<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { Autobind } from 'es-decorators';
import debounce from 'lodash/debounce';
import isEqual from 'lodash/isEqual';
import MediaQuery from 'react-responsive';
import 'isomorphic-fetch';
import ReactDOM from 'react-dom';
import DropdownTreeSelect from 'react-dropdown-tree-select';

// Redux
import withRedux from 'next-redux-wrapper';
import { initStore } from 'store';
import {
  toggleLayerGroupVisibility,
  toggleLayerGroup,
  setLayerGroupsOrder,
  setLayerGroupActiveLayer,
  setLayerGroups,
  getDatasets,
  setDatasetsPage,
  setDatasetsSearchFilter,
  setDatasetsTopicsFilter,
  setDatasetsGeographiesFilter,
  setDatasetsDataTypeFilter,
  setDatasetsFilteredByConcepts
} from 'redactions/explore';
import { redirectTo } from 'redactions/common';
import { toggleModal, setModalOptions } from 'redactions/modal';

// Selectors
import getpaginatedDatasets from 'selectors/explore/datasetsPaginatedExplore';
import getFilteredDatasets from 'selectors/explore/filterDatasets';
import getLayerGroups from 'selectors/explore/layersExplore';

// Components
import Sidebar from 'components/app/layout/Sidebar';
import DatasetListHeader from 'components/app/explore/DatasetListHeader';
import DatasetList from 'components/app/explore/DatasetList';
import Paginator from 'components/ui/Paginator';
import Map from 'components/vis/Map';
import ShareModalExplore from 'components/modal/ShareModalExplore';
import Legend from 'components/ui/Legend';
import Spinner from 'components/ui/Spinner';
import Icon from 'components/ui/Icon';
import SearchInput from 'components/ui/SearchInput';

// Layout
import Page from 'components/app/layout/Page';
import Layout from 'components/app/layout/Layout';

// Utils
import LayerManager from 'utils/layers/LayerManager';

// Services
import DatasetService from 'services/DatasetService';

const mapConfig = {
  zoom: 3,
  latLng: {
    lat: 0,
    lng: 0
  }
};

class Explore extends Page {
  constructor(props) {
    super(props);

    this.state = {
      topicsTree: null,
      geographiesTree: null,
      dataTypesTree: null
    };

    // Services
    this.datasetService = new DatasetService(null, { apiURL: process.env.WRI_API_URL });

    // BINDINGS
    this.handleFilterDatasetsSearch = debounce(this.handleFilterDatasetsSearch.bind(this), 500);
  }

  componentWillMount() {
    const query = this.props.url.query;
    if (query.page) {
      this.props.setDatasetsPage(+query.page);
    }

    if (query.layers) {
      try {
        const layerGroups = JSON.parse(decodeURIComponent(query.layers));
        this.props.setLayerGroups(layerGroups);
      } catch (e) {
        this.props.setLayerGroups([]);
      }
    }

    if (query.search) {
      this.props.setDatasetsSearchFilter({ value: query.search, key: 'name' });
    }

    if (query.topics) {
      this.props.setDatasetsTopicsFilter(JSON.parse(query.topics));
    }

    if (query.geographies) {
      this.props.setDatasetsGeographiesFilter(JSON.parse(query.geographies));
    }

    if (query.dataType) {
      this.props.setDatasetsDataTypeFilter(JSON.parse(query.dataType));
    }

    this.props.getDatasets();
  }

  componentDidMount() {
    this.loadKnowledgeGraph();
  }

  componentWillReceiveProps(nextProps) {
    const oldFilters = this.props.explore.filters;
    const { topics, geographies, dataType } = oldFilters;
    const newFilters = nextProps.explore.filters;

    const conceptsUpdated = topics !== newFilters.topics ||
      geographies !== newFilters.geographies ||
      dataType !== newFilters.dataType;

    const newFiltersHaveData = (newFilters.topics && newFilters.topics.length > 0) ||
      (newFilters.dataType && newFilters.dataType.length > 0) ||
      (newFilters.geographies && newFilters.geographies.length > 0);

    if (conceptsUpdated && newFiltersHaveData) {
      this.datasetService.searchDatasetsByConcepts(
        newFilters.topics, newFilters.geographies, newFilters.dataType)
        .then((datasetList) => {
          console.log('datasetList', datasetList);
          this.props.setDatasetsFilteredByConcepts(datasetList);
        });
    } else if (conceptsUpdated && !newFiltersHaveData) {
      this.props.setDatasetsFilteredByConcepts(null);
    }

    // this.setState({
    //   vocabularies: nextProps.explore.vocabularies.list
    // });
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !isEqual(nextProps.explore, this.props.explore)
      || !isEqual(nextState, this.state);
  }

  loadKnowledgeGraph() {
    // Topics selector
    fetch(new Request('/static/data/TopicsTreeLite.json'))
      .then(response => response.json())
      .then((response) => {
        this.setState({ topicsTree: response });
        const element = document.getElementsByClassName('topics-selector')[0];

        const onChange = (currentNode, selectedNodes) => {
          const topics = selectedNodes.map(val => val.value);
          this.props.setDatasetsTopicsFilter(topics);
        };
        ReactDOM.render(
          <DropdownTreeSelect
            placeholderText="Topics"
            data={response}
            onChange={onChange}
          />,
          element);
      });

    // Data types selector
    fetch(new Request('/static/data/DataTypesTreeLite.json'))
      .then(response => response.json())
      .then((response) => {
        this.setState({ dataTypesTree: response });
        const element = document.getElementsByClassName('data-types-selector')[0];

        const onChange = (currentNode, selectedNodes) => {
          const dataTypes = selectedNodes.map(val => val.value);
          this.props.setDatasetsDataTypeFilter(dataTypes);
        };
        ReactDOM.render(
          <DropdownTreeSelect
            data={response}
            placeholderText="Data types"
            onChange={onChange}
          />,
          element);
      });

    // Data types selector
    fetch(new Request('/static/data/GeographiesTreeLite.json'))
      .then(response => response.json())
      .then((response) => {
        this.setState({ geographiesTree: response });
        const element = document.getElementsByClassName('geographies-selector')[0];

        const onChange = (currentNode, selectedNodes) => {
          const geographies = selectedNodes.map(val => val.value);
          this.props.setDatasetsGeographiesFilter(geographies);
        };
        ReactDOM.render(
          <DropdownTreeSelect
            data={response}
            placeholderText="Geographies"
            onChange={onChange}
          />,
          element);
      });
  }

  @Autobind
  handleRedirect(item) {
    if (item && item.value) {
      this.props.redirectTo(`explore/${item.value}`);
    }
  }

  handleFilterDatasetsSearch(value) {
    const filter = { value: value || '', key: 'name' };
    this.props.setDatasetsSearchFilter(filter);

    // We move the user to the first page
    this.props.setDatasetsPage(1);
  }

  handleShareModal() {
    const options = {
      children: ShareModalExplore,
      childrenProps: {
        url: window.location.href,
        layerGroups: this.props.rawLayerGroups,
        toggleModal: this.props.toggleModal
      }
    };
    this.props.toggleModal(true);
    this.props.setModalOptions(options);
  }

  /**
   * Event handler executed when the user toggles the visibility
   * of a layer group in the legend
   * @param {LayerGroup} layerGroup
   */
  @Autobind
  onToggleLayerGroupVisibility(layerGroup) {
    this.props.toggleLayerGroupVisibility(layerGroup.dataset, !layerGroup.visible);
  }

  /**
   * Event handler executed when the user removes a layer
   * group from the map
   * @param {LayerGroup} layerGroup
   */
  @Autobind
  onRemoveLayerGroup(layerGroup) {
    this.props.removeLayerGroup(layerGroup.dataset);
  }

  /**
   * Event handler executed when the user re-orders the
   * layer groups
   * @param {string[]} datasets - List of datasets IDs
   */
  @Autobind
  onSetLayerGroupsOrder(datasets) {
    this.props.setLayerGroupsOrder(datasets);
  }

  /**
   * Event handler executed when the user change the active
   * layer of a layer group
   * @param {string} dataset - Dataset ID
   * @param {string} layer - Layer ID
   */
  @Autobind
  onSetLayerGroupActiveLayer(dataset, layer) {
    this.props.setLayerGroupActiveLayer(dataset, layer);
  }

  /**
   * Return the current value of the vocabulary filter
   * @returns {string}
   */
  getCurrentVocabularyFilter() {
    const filters = this.props.explore.filters;
    if (!filters.length) return null;

    const filter = filters.find(f => f.key === 'vocabulary');

    return filter && filter.value;
  }

  /**
   * Return the current search made on the name of the
   * datasets
   * @returns {string}
   */
  getCurrentNameFilter() {
    const filters = this.props.explore.filters;
    if (!filters.length) return null;

    const filter = filters.find(f => f.key === 'name');

    return filter && filter.value;
  }

  render() {
    const { explore, paginatedDatasets } = this.props;
    const { search } = explore.filters;

    return (
      <Layout
        title="Explore"
        description="Explore description"
        url={this.props.url}
        user={this.props.user}
      >

            <Sidebar>

Explore

                <SearchInput
                  onSearch={this.handleFilterDatasetsSearch}
                  input={{
                    value: search && search.value,
                    placeholder: 'Search dataset'
                  }}
                />

              <DatasetListHeader
                list={explore.datasets.list}
                mode={explore.datasets.mode}
              />
              <Spinner
                isLoading={explore.datasets.loading}
                className="-light"
              />

                  <DatasetList
                    list={paginatedDatasets}
                    mode={explore.datasets.mode}
                    showActions
                  />

              <Paginator
                options={{
                  page: explore.datasets.page,
                  limit: explore.datasets.limit,
                  size: explore.datasets.list.length
                }}
                onChange={(page) => {
                  this.props.setDatasetsPage(page);
                  // Scroll to the top of the list
                  document.getElementsByClassName('sidebar-content')[0].scrollTop = 0;
                }}
              />
            </Sidebar>
            <MediaQuery minDeviceWidth={720} values={{ deviceWidth: 720 }}>

                <Map
                  LayerManager={LayerManager}
                  mapConfig={mapConfig}
                  layerGroups={this.props.layerGroups}
                />

                <button className="share-button" onClick={() => this.handleShareModal()}>
                  <Icon name="icon-share" className="-small" />
                </button>

                {this.props.layerGroups && this.props.layerGroups.length &&
                  <Legend
                    layerGroups={this.props.layerGroups}
                    className={{ color: '-dark' }}
                    toggleLayerGroupVisibility={this.onToggleLayerGroupVisibility}
                    setLayerGroupsOrder={this.onSetLayerGroupsOrder}
                    removeLayerGroup={this.onRemoveLayerGroup}
                    setLayerGroupActiveLayer={this.onSetLayerGroupActiveLayer}
                  />
                }

            </MediaQuery>

      </Layout>
    );
  }
}

Explore.propTypes = {
  // ROUTER
  url: PropTypes.object,

  // STORE
  explore: PropTypes.object,
  paginatedDatasets: PropTypes.array,
  layerGroups: PropTypes.array,
  toggledDataset: PropTypes.string,

  // ACTIONS

  getDatasets: PropTypes.func,
  setDatasetsPage: PropTypes.func,
  redirectTo: PropTypes.func,
  setDatasetsFilters: PropTypes.func,
  toggleModal: PropTypes.func,
  setModalOptions: PropTypes.func,

  // Toggle the visibility of a layer group based on the layer passed as argument
  toggleLayerGroupVisibility: PropTypes.func.isRequired,
  // Remove the layer group
  removeLayerGroup: PropTypes.func.isRequired,
  // Set the active layer of a layer group
  setLayerGroupActiveLayer: PropTypes.func.isRequired,
  // Set the layer groups
  setLayerGroups: PropTypes.func.isRequired
};

const mapStateToProps = (state) => {
  const filters = state.explore.filters;
  const datasets = (filters.search || filters.topcis || filters.geographies || filters.dataType)
    ? Object.assign({}, state.explore.datasets, { list: getFilteredDatasets(state) })
    : state.explore.datasets;

  const explore = Object.assign({}, state.explore, { datasets });

  return {
    explore,
    paginatedDatasets: getpaginatedDatasets(explore),
    allDatasets: state.explore.datasets.list,
    layerGroups: getLayerGroups(state),
    rawLayerGroups: state.explore.layers
  };
};

const mapDispatchToProps = dispatch => ({
  getDatasets: () => { dispatch(getDatasets()); },
  setDatasetsSearchFilter: search => dispatch(setDatasetsSearchFilter(search)),
  setDatasetsTopicsFilter: topics => dispatch(setDatasetsTopicsFilter(topics)),
  setDatasetsDataTypeFilter: dataType => dispatch(setDatasetsDataTypeFilter(dataType)),
  setDatasetsGeographiesFilter: geographies => dispatch(setDatasetsGeographiesFilter(geographies)),
  setDatasetsFilteredByConcepts: datasetList =>
    dispatch(setDatasetsFilteredByConcepts(datasetList)),
  redirectTo: (url) => { dispatch(redirectTo(url)); },
  toggleModal: (open, options) => dispatch(toggleModal(open, options)),
  setModalOptions: (options) => { dispatch(setModalOptions(options)); },
  setDatasetsPage: page => dispatch(setDatasetsPage(page)),
  toggleLayerGroupVisibility: (dataset, visible) => {
    dispatch(toggleLayerGroupVisibility(dataset, visible));
  },
  removeLayerGroup: dataset => dispatch(toggleLayerGroup(dataset, false)),
  setLayerGroupsOrder: datasets => dispatch(setLayerGroupsOrder(datasets)),
  setLayerGroupActiveLayer: (dataset, layer) => dispatch(setLayerGroupActiveLayer(dataset, layer)),
  setLayerGroups: layerGroups => dispatch(setLayerGroups(layerGroups))
});

export default withRedux(initStore, mapStateToProps, mapDispatchToProps)(Explore);
<commit_msg>set selectors value from url<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { Autobind } from 'es-decorators';
import debounce from 'lodash/debounce';
import isEqual from 'lodash/isEqual';
import MediaQuery from 'react-responsive';
import 'isomorphic-fetch';
import ReactDOM from 'react-dom';
import DropdownTreeSelect from 'react-dropdown-tree-select';

// Redux
import withRedux from 'next-redux-wrapper';
import { initStore } from 'store';
import {
  toggleLayerGroupVisibility,
  toggleLayerGroup,
  setLayerGroupsOrder,
  setLayerGroupActiveLayer,
  setLayerGroups,
  getDatasets,
  setDatasetsPage,
  setDatasetsSearchFilter,
  setDatasetsTopicsFilter,
  setDatasetsGeographiesFilter,
  setDatasetsDataTypeFilter,
  setDatasetsFilteredByConcepts
} from 'redactions/explore';
import { redirectTo } from 'redactions/common';
import { toggleModal, setModalOptions } from 'redactions/modal';

// Selectors
import getpaginatedDatasets from 'selectors/explore/datasetsPaginatedExplore';
import getFilteredDatasets from 'selectors/explore/filterDatasets';
import getLayerGroups from 'selectors/explore/layersExplore';

// Components
import Sidebar from 'components/app/layout/Sidebar';
import DatasetListHeader from 'components/app/explore/DatasetListHeader';
import DatasetList from 'components/app/explore/DatasetList';
import Paginator from 'components/ui/Paginator';
import Map from 'components/vis/Map';
import ShareModalExplore from 'components/modal/ShareModalExplore';
import Legend from 'components/ui/Legend';
import Spinner from 'components/ui/Spinner';
import Icon from 'components/ui/Icon';
import SearchInput from 'components/ui/SearchInput';

// Layout
import Page from 'components/app/layout/Page';
import Layout from 'components/app/layout/Layout';

// Utils
import LayerManager from 'utils/layers/LayerManager';

// Services
import DatasetService from 'services/DatasetService';

const mapConfig = {
  zoom: 3,
  latLng: {
    lat: 0,
    lng: 0
  }
};

class Explore extends Page {
  constructor(props) {
    super(props);

    this.state = {
      topicsTree: null,
      geographiesTree: null,
      dataTypesTree: null
    };

    // Services
    this.datasetService = new DatasetService(null, { apiURL: process.env.WRI_API_URL });

    // BINDINGS
    this.handleFilterDatasetsSearch = debounce(this.handleFilterDatasetsSearch.bind(this), 500);
  }

  componentWillMount() {
    const query = this.props.url.query;
    if (query.page) {
      this.props.setDatasetsPage(+query.page);
    }

    if (query.layers) {
      try {
        const layerGroups = JSON.parse(decodeURIComponent(query.layers));
        this.props.setLayerGroups(layerGroups);
      } catch (e) {
        this.props.setLayerGroups([]);
      }
    }

    if (query.search) {
      this.props.setDatasetsSearchFilter({ value: query.search, key: 'name' });
    }

    if (query.topics) {
      this.props.setDatasetsTopicsFilter(JSON.parse(query.topics));
    }

    if (query.geographies) {
      this.props.setDatasetsGeographiesFilter(JSON.parse(query.geographies));
    }

    if (query.dataType) {
      this.props.setDatasetsDataTypeFilter(JSON.parse(query.dataType));
    }

    this.props.getDatasets();
  }

  componentDidMount() {
    this.loadKnowledgeGraph();
  }

  componentWillReceiveProps(nextProps) {
    const oldFilters = this.props.explore.filters;
    const { topics, geographies, dataType } = oldFilters;
    const newFilters = nextProps.explore.filters;

    const conceptsUpdated = topics !== newFilters.topics ||
      geographies !== newFilters.geographies ||
      dataType !== newFilters.dataType;

    const newFiltersHaveData = (newFilters.topics && newFilters.topics.length > 0) ||
      (newFilters.dataType && newFilters.dataType.length > 0) ||
      (newFilters.geographies && newFilters.geographies.length > 0);

    if (conceptsUpdated && newFiltersHaveData) {
      this.datasetService.searchDatasetsByConcepts(
        newFilters.topics, newFilters.geographies, newFilters.dataType)
        .then((datasetList) => {
          this.props.setDatasetsFilteredByConcepts(datasetList);
        });
    } else if (conceptsUpdated && !newFiltersHaveData) {
      this.props.setDatasetsFilteredByConcepts(null);
    }

    // this.setState({
    //   vocabularies: nextProps.explore.vocabularies.list
    // });
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !isEqual(nextProps.explore, this.props.explore)
      || !isEqual(nextState, this.state);
  }

  loadKnowledgeGraph() {
    const query = this.props.url.query;
    const { topics, dataType, geographies } = query;

    // Topics selector
    fetch(new Request('/static/data/TopicsTreeLite.json'))
      .then(response => response.json())
      .then((response) => {
        const data = response;
        this.setState({ topicsTree: data });
        const element = document.getElementsByClassName('topics-selector')[0];

        const onChange = (currentNode, selectedNodes) => {
          const topicsVal = selectedNodes.map(val => val.value);
          this.props.setDatasetsTopicsFilter(topicsVal);
        };

        if (topics) {
          data.forEach(child => this.selectElementsFromTree(child, topics));
        }

        ReactDOM.render(
          <DropdownTreeSelect
            placeholderText="Topics"
            data={data}
            onChange={onChange}
          />,
          element);
      });

    // Data types selector
    fetch(new Request('/static/data/DataTypesTreeLite.json'))
      .then(response => response.json())
      .then((response) => {
        const data = response;
        this.setState({ dataTypesTree: data });
        const element = document.getElementsByClassName('data-types-selector')[0];

        const onChange = (currentNode, selectedNodes) => {
          const dataTypesVal = selectedNodes.map(val => val.value);
          this.props.setDatasetsDataTypeFilter(dataTypesVal);
        };

        if (dataType) {
          data.forEach(child => this.selectElementsFromTree(child, dataType));
        }

        ReactDOM.render(
          <DropdownTreeSelect
            data={response}
            placeholderText="Data types"
            onChange={onChange}
          />,
          element);
      });

    // Data types selector
    fetch(new Request('/static/data/GeographiesTreeLite.json'))
      .then(response => response.json())
      .then((response) => {
        const data = response;
        this.setState({ geographiesTree: data });
        const element = document.getElementsByClassName('geographies-selector')[0];

        const onChange = (currentNode, selectedNodes) => {
          const geographiesVal = selectedNodes.map(val => val.value);
          this.props.setDatasetsGeographiesFilter(geographiesVal);
        };

        if (dataType) {
          data.forEach(child => this.selectElementsFromTree(child, geographies));
        }

        ReactDOM.render(
          <DropdownTreeSelect
            data={response}
            placeholderText="Geographies"
            onChange={onChange}
          />,
          element);
      });
  }

  selectElementsFromTree(tree, elements) {
    if (elements.includes(tree.value)) {
      tree.checked = true;
    }
    if (tree.children) {
      tree.children.forEach(val => this.selectElementsFromTree(val, elements));
    }
  }

  @Autobind
  handleRedirect(item) {
    if (item && item.value) {
      this.props.redirectTo(`explore/${item.value}`);
    }
  }

  handleFilterDatasetsSearch(value) {
    const filter = { value: value || '', key: 'name' };
    this.props.setDatasetsSearchFilter(filter);

    // We move the user to the first page
    this.props.setDatasetsPage(1);
  }

  handleShareModal() {
    const options = {
      children: ShareModalExplore,
      childrenProps: {
        url: window.location.href,
        layerGroups: this.props.rawLayerGroups,
        toggleModal: this.props.toggleModal
      }
    };
    this.props.toggleModal(true);
    this.props.setModalOptions(options);
  }

  /**
   * Event handler executed when the user toggles the visibility
   * of a layer group in the legend
   * @param {LayerGroup} layerGroup
   */
  @Autobind
  onToggleLayerGroupVisibility(layerGroup) {
    this.props.toggleLayerGroupVisibility(layerGroup.dataset, !layerGroup.visible);
  }

  /**
   * Event handler executed when the user removes a layer
   * group from the map
   * @param {LayerGroup} layerGroup
   */
  @Autobind
  onRemoveLayerGroup(layerGroup) {
    this.props.removeLayerGroup(layerGroup.dataset);
  }

  /**
   * Event handler executed when the user re-orders the
   * layer groups
   * @param {string[]} datasets - List of datasets IDs
   */
  @Autobind
  onSetLayerGroupsOrder(datasets) {
    this.props.setLayerGroupsOrder(datasets);
  }

  /**
   * Event handler executed when the user change the active
   * layer of a layer group
   * @param {string} dataset - Dataset ID
   * @param {string} layer - Layer ID
   */
  @Autobind
  onSetLayerGroupActiveLayer(dataset, layer) {
    this.props.setLayerGroupActiveLayer(dataset, layer);
  }

  /**
   * Return the current value of the vocabulary filter
   * @returns {string}
   */
  getCurrentVocabularyFilter() {
    const filters = this.props.explore.filters;
    if (!filters.length) return null;

    const filter = filters.find(f => f.key === 'vocabulary');

    return filter && filter.value;
  }

  /**
   * Return the current search made on the name of the
   * datasets
   * @returns {string}
   */
  getCurrentNameFilter() {
    const filters = this.props.explore.filters;
    if (!filters.length) return null;

    const filter = filters.find(f => f.key === 'name');

    return filter && filter.value;
  }

  render() {
    const { explore, paginatedDatasets } = this.props;
    const { search } = explore.filters;

    return (
      <Layout
        title="Explore"
        description="Explore description"
        url={this.props.url}
        user={this.props.user}
      >

            <Sidebar>

Explore

                <SearchInput
                  onSearch={this.handleFilterDatasetsSearch}
                  input={{
                    value: search && search.value,
                    placeholder: 'Search dataset'
                  }}
                />

              <DatasetListHeader
                list={explore.datasets.list}
                mode={explore.datasets.mode}
              />
              <Spinner
                isLoading={explore.datasets.loading}
                className="-light"
              />

                  <DatasetList
                    list={paginatedDatasets}
                    mode={explore.datasets.mode}
                    showActions
                  />

              <Paginator
                options={{
                  page: explore.datasets.page,
                  limit: explore.datasets.limit,
                  size: explore.datasets.list.length
                }}
                onChange={(page) => {
                  this.props.setDatasetsPage(page);
                  // Scroll to the top of the list
                  document.getElementsByClassName('sidebar-content')[0].scrollTop = 0;
                }}
              />
            </Sidebar>
            <MediaQuery minDeviceWidth={720} values={{ deviceWidth: 720 }}>

                <Map
                  LayerManager={LayerManager}
                  mapConfig={mapConfig}
                  layerGroups={this.props.layerGroups}
                />

                <button className="share-button" onClick={() => this.handleShareModal()}>
                  <Icon name="icon-share" className="-small" />
                </button>

                {this.props.layerGroups && this.props.layerGroups.length &&
                  <Legend
                    layerGroups={this.props.layerGroups}
                    className={{ color: '-dark' }}
                    toggleLayerGroupVisibility={this.onToggleLayerGroupVisibility}
                    setLayerGroupsOrder={this.onSetLayerGroupsOrder}
                    removeLayerGroup={this.onRemoveLayerGroup}
                    setLayerGroupActiveLayer={this.onSetLayerGroupActiveLayer}
                  />
                }

            </MediaQuery>

      </Layout>
    );
  }
}

Explore.propTypes = {
  // ROUTER
  url: PropTypes.object,

  // STORE
  explore: PropTypes.object,
  paginatedDatasets: PropTypes.array,
  layerGroups: PropTypes.array,
  toggledDataset: PropTypes.string,

  // ACTIONS

  getDatasets: PropTypes.func,
  setDatasetsPage: PropTypes.func,
  redirectTo: PropTypes.func,
  setDatasetsFilters: PropTypes.func,
  toggleModal: PropTypes.func,
  setModalOptions: PropTypes.func,

  // Toggle the visibility of a layer group based on the layer passed as argument
  toggleLayerGroupVisibility: PropTypes.func.isRequired,
  // Remove the layer group
  removeLayerGroup: PropTypes.func.isRequired,
  // Set the active layer of a layer group
  setLayerGroupActiveLayer: PropTypes.func.isRequired,
  // Set the layer groups
  setLayerGroups: PropTypes.func.isRequired
};

const mapStateToProps = (state) => {
  const filters = state.explore.filters;
  const datasets = (filters.search || filters.topcis || filters.geographies || filters.dataType)
    ? Object.assign({}, state.explore.datasets, { list: getFilteredDatasets(state) })
    : state.explore.datasets;

  const explore = Object.assign({}, state.explore, { datasets });

  return {
    explore,
    paginatedDatasets: getpaginatedDatasets(explore),
    allDatasets: state.explore.datasets.list,
    layerGroups: getLayerGroups(state),
    rawLayerGroups: state.explore.layers
  };
};

const mapDispatchToProps = dispatch => ({
  getDatasets: () => { dispatch(getDatasets()); },
  setDatasetsSearchFilter: search => dispatch(setDatasetsSearchFilter(search)),
  setDatasetsTopicsFilter: topics => dispatch(setDatasetsTopicsFilter(topics)),
  setDatasetsDataTypeFilter: dataType => dispatch(setDatasetsDataTypeFilter(dataType)),
  setDatasetsGeographiesFilter: geographies => dispatch(setDatasetsGeographiesFilter(geographies)),
  setDatasetsFilteredByConcepts: datasetList =>
    dispatch(setDatasetsFilteredByConcepts(datasetList)),
  redirectTo: (url) => { dispatch(redirectTo(url)); },
  toggleModal: (open, options) => dispatch(toggleModal(open, options)),
  setModalOptions: (options) => { dispatch(setModalOptions(options)); },
  setDatasetsPage: page => dispatch(setDatasetsPage(page)),
  toggleLayerGroupVisibility: (dataset, visible) => {
    dispatch(toggleLayerGroupVisibility(dataset, visible));
  },
  removeLayerGroup: dataset => dispatch(toggleLayerGroup(dataset, false)),
  setLayerGroupsOrder: datasets => dispatch(setLayerGroupsOrder(datasets)),
  setLayerGroupActiveLayer: (dataset, layer) => dispatch(setLayerGroupActiveLayer(dataset, layer)),
  setLayerGroups: layerGroups => dispatch(setLayerGroups(layerGroups))
});

export default withRedux(initStore, mapStateToProps, mapDispatchToProps)(Explore);
<|endoftext|>


<commit_before>var qcloud = require('../../bower_components/qcloud-weapp-client-sdk/index');
var config = require('../../config');

Page({
    data: {
        loginUrl: config.service.loginUrl,
        requestUrl: config.service.requestUrl,
        tunnelUrl: config.service.tunnelUrl,
    },

    doLogin: function () {
        qcloud.setLoginUrl(this.data.loginUrl);
        qcloud.login({
            success: function () {
                console.log('login success', arguments);
            },

            fail: function () {
                console.log('login fail', arguments);
            }
        });
    },

    clearSession: function () {
        wx.clearStorageSync();
    },

    doRequest: function () {
        qcloud.setLoginUrl(this.data.loginUrl);
        qcloud.request({
            url: this.data.requestUrl,

            success: function () {
                console.log('request success', arguments);
            },

            fail: function () {
                console.log('request fail', arguments);
            },

            complete: function () {
                console.log('request complete');
            }
        });
    },

    openTunnel: function () {
        qcloud.setLoginUrl(this.data.loginUrl);

        var tunnel = this.tunnel = new qcloud.Tunnel(this.data.tunnelUrl);
        tunnel.open();
        tunnel.on('*', function (type, args) {
            switch(type) {
            case 'connect':
                console.log('连接已建立');
                break;
            case 'close':
                console.log('连接已断开');
                break;
            case 'reconnecting':
                console.log('正在重连');
                break;
            case 'reconnect':
                console.log('重连成功');
                break;
            case 'error':
                console.error(args);
                break;
            default:
                console.log(type, args);
                break;
            }
        });
    },

    closeTunnel: function () {
        if (this.tunnel) {
            this.tunnel.close();
        }
    },

    sendMessage: function () {
        if (this.tunnel) {
            this.tunnel.emit('speak', {
                'word': Math.random().toString(32).slice(2),
            });
        }
    },

    openChat: function () {
        wx.navigateTo({ url: '../chat/chat' });
    },
});
<commit_msg>请求测试添加 `login: true` 传参<commit_after>var qcloud = require('../../bower_components/qcloud-weapp-client-sdk/index');
var config = require('../../config');

Page({
    data: {
        loginUrl: config.service.loginUrl,
        requestUrl: config.service.requestUrl,
        tunnelUrl: config.service.tunnelUrl,
    },

    doLogin: function () {
        qcloud.setLoginUrl(this.data.loginUrl);
        qcloud.login({
            success: function () {
                console.log('login success', arguments);
            },

            fail: function () {
                console.log('login fail', arguments);
            }
        });
    },

    clearSession: function () {
        wx.clearStorageSync();
    },

    doRequest: function () {
        qcloud.setLoginUrl(this.data.loginUrl);
        qcloud.request({
            url: this.data.requestUrl,
            login: true,

            success: function () {
                console.log('request success', arguments);
            },

            fail: function () {
                console.log('request fail', arguments);
            },

            complete: function () {
                console.log('request complete');
            }
        });
    },

    openTunnel: function () {
        qcloud.setLoginUrl(this.data.loginUrl);

        var tunnel = this.tunnel = new qcloud.Tunnel(this.data.tunnelUrl);
        tunnel.open();
        tunnel.on('*', function (type, args) {
            switch(type) {
            case 'connect':
                console.log('连接已建立');
                break;
            case 'close':
                console.log('连接已断开');
                break;
            case 'reconnecting':
                console.log('正在重连');
                break;
            case 'reconnect':
                console.log('重连成功');
                break;
            case 'error':
                console.error(args);
                break;
            default:
                console.log(type, args);
                break;
            }
        });
    },

    closeTunnel: function () {
        if (this.tunnel) {
            this.tunnel.close();
        }
    },

    sendMessage: function () {
        if (this.tunnel) {
            this.tunnel.emit('speak', {
                'word': Math.random().toString(32).slice(2),
            });
        }
    },

    openChat: function () {
        wx.navigateTo({ url: '../chat/chat' });
    },
});
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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.
*/
/* global angular d3 */

/**
 * @module QDR
 * @main QDR
 *
 * The main entry point for the QDR module
 *
 */

//import angular from 'angular';
import { QDRLogger, QDRTemplatePath, QDR_LAST_LOCATION } from './plugin/js/qdrGlobals.js';
import { QDRService } from './plugin/js/qdrService.js';
import { QDRChartService } from './plugin/js/qdrChartService.js';
import { NavBarController } from './plugin/js/navbar.js';
import { OverviewController } from './plugin/js/qdrOverview.js';
import { OverviewChartsController } from './plugin/js/qdrOverviewChartsController.js';
import { OverviewLogsController } from './plugin/js/qdrOverviewLogsController.js';
import { TopologyController } from './plugin/js/topology/qdrTopology.js';
import { ChordController } from './plugin/js/chord/qdrChord.js';
import { ListController } from './plugin/js/qdrList.js';
import { TopAddressesController } from './plugin/js/qdrTopAddressesController.js';
import { ChartDialogController } from './plugin/js/dlgChartController.js';
import { DetailDialogController, SubTable } from './plugin/js/dlgDetailController.js';
import { SettingsController } from './plugin/js/qdrSettings.js';
import { SchemaController } from './plugin/js/qdrSchema.js';
import { ChartsController } from './plugin/js/qdrCharts.js';
import { AboutController } from './plugin/js/qdrAbout.js';
import { posint } from './plugin/js/posintDirective.js';

(function (QDR) {

  /**
   * This plugin's angularjs module instance
   */
  QDR.module = angular.module('QDR', ['ngRoute', 'ngSanitize', 'ngResource', 'ui.bootstrap',
    'ui.grid', 'ui.grid.selection', 'ui.grid.autoResize', 'ui.grid.resizeColumns', 'ui.grid.saveState',
    'ui.slider', 'ui.checkbox', 'patternfly.charts', 'patternfly.card', 'patternfly.modals']);

  // set up the routing for this plugin
  QDR.module.config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: QDRTemplatePath + 'qdrOverview.html'
      })
      .when('/overview', {
        templateUrl: QDRTemplatePath + 'qdrOverview.html'
      })
      .when('/topology', {
        templateUrl: QDRTemplatePath + 'qdrTopology.html'
      })
      .when('/list', {
        templateUrl: QDRTemplatePath + 'qdrList.html'
      })
      .when('/schema', {
        templateUrl: QDRTemplatePath + 'qdrSchema.html'
      })
      .when('/charts', {
        templateUrl: QDRTemplatePath + 'qdrCharts.html'
      })
      .when('/chord', {
        templateUrl: QDRTemplatePath + 'qdrChord.html'
      })
      .when('/connect', {
        templateUrl: QDRTemplatePath + 'qdrConnect.html'
      });
  });

  QDR.module.config(function ($compileProvider) {
    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension|file|blob):/);
    $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension):/);
  });

  QDR.module.filter('to_trusted', ['$sce', function ($sce) {
    return function (text) {
      return $sce.trustAsHtml(text + '');
    };
  }]);

  QDR.module.filter('humanify', ['QDRService', function (QDRService) {
    return function (input) {
      return QDRService.utilities.humanify(input);
    };
  }]);

  QDR.module.filter('Pascalcase', function () {
    return function (str) {
      if (!str)
        return '';
      return str.replace(/(\w)(\w*)/g,
        function (g0, g1, g2) { return g1.toUpperCase() + g2.toLowerCase(); });
    };
  });

  QDR.module.filter('safePlural', function () {
    return function (str) {
      var es = ['x', 'ch', 'ss', 'sh'];
      for (var i = 0; i < es.length; ++i) {
        if (str.endsWith(es[i]))
          return str + 'es';
      }
      if (str.endsWith('y'))
        return str.substr(0, str.length - 2) + 'ies';
      if (str.endsWith('s'))
        return str;
      return str + 's';
    };
  });

  QDR.module.filter('pretty', function () {
    return function (str) {
      var formatComma = d3.format(',');
      if (!isNaN(parseFloat(str)) && isFinite(str))
        return formatComma(str);
      return str;
    };
  });

  QDR.module.filter('truncate', function () {
    return function (str) {
      if (!isNaN(parseFloat(str)) && isFinite(str))
        return Math.round(str);
      return str;
    };
  });
  // one-time initialization happens in the run function
  // of our module
  QDR.module.run(['$rootScope', '$route', '$timeout', '$location', '$log', 'QDRService', 'QDRChartService', function ($rootScope, $route, $timeout, $location, $log, QDRService, QDRChartService) {
    let QDRLog = new QDRLogger($log, 'main');
    QDRLog.info('************* creating Dispatch Console ************');

    var curPath = $location.path();
    var org = curPath.substr(1);
    if (org && org.length > 0 && org !== 'connect') {
      $location.search('org', org);
    } else {
      $location.search('org', null);
    }
    QDR.queue = d3.queue;

    if (!QDRService.management.connection.is_connected()) {
      // attempt to connect to the host:port that served this page
      var host = $location.host();
      var port = $location.port();
      var search = $location.search();
      if (search.org) {
        if (search.org === 'connect')
          $location.search('org', 'overview');
      }
      var connectOptions = { address: host, port: port };
      QDRLog.info('Attempting AMQP over websockets connection using address:port of browser (' + host + ':' + port + ')');
      QDRService.management.connection.testConnect(connectOptions)
        .then(function () {
          // We didn't connect with reconnect: true flag.
          // The reason being that if we used reconnect:true and the connection failed, rhea would keep trying. There
          // doesn't appear to be a way to tell it to stop trying to reconnect.
          QDRService.disconnect();
          QDRLog.info('Connect succeeded. Using address:port of browser');
          connectOptions.reconnect = true;
          // complete the connection (create the sender/receiver)
          QDRService.connect(connectOptions)
            .then(function () {
              // register a callback for when the node list is available (needed for loading saved charts)
              QDRService.management.topology.addUpdatedAction('initChartService', function () {
                QDRService.management.topology.delUpdatedAction('initChartService');
                QDRChartService.init(); // initialize charting service after we are connected
              });
              // get the list of nodes
              QDRService.management.topology.startUpdating(false);
            });
        }, function () {
          QDRLog.info('failed to auto-connect to ' + host + ':' + port);
          QDRLog.info('redirecting to connect page');
          $timeout(function () {
            $location.path('/connect');
            $location.search('org', org);
            $location.replace();
          });
        });
    }

    $rootScope.$on('$routeChangeSuccess', function () {
      var path = $location.path();
      if (path !== '/connect') {
        localStorage[QDR_LAST_LOCATION] = path;
      }
    });
  }]);

  QDR.module.controller('QDR.MainController', ['$scope', '$log', '$location', function ($scope, $log, $location) {
    let QDRLog = new QDRLogger($log, 'MainController');
    QDRLog.debug('started QDR.MainController with location.url: ' + $location.url());
    QDRLog.debug('started QDR.MainController with window.location.pathname : ' + window.location.pathname);
    $scope.topLevelTabs = [];
    $scope.topLevelTabs.push({
      id: 'qdr',
      content: 'Qpid Dispatch Router Console',
      title: 'Dispatch Router Console',
      isValid: function () { return true; },
      href: function () { return '#connect'; },
      isActive: function () { return true; }
    });
  }]);

  QDR.module.controller('QDR.Core', function ($scope, $rootScope, $timeout, QDRService) {
    $scope.alerts = [];
    $scope.breadcrumb = {};
    $scope.closeAlert = function (index) {
      $scope.alerts.splice(index, 1);
    };
    $scope.$on('setCrumb', function (event, data) {
      $scope.breadcrumb = data;
    });
    $scope.$on('newAlert', function (event, data) {
      $scope.alerts.push(data);
      $scope.$apply();
    });
    $scope.$on('clearAlerts', function () {
      $scope.alerts = [];
      $scope.$apply();
    });
    $scope.pageMenuClicked = function () {
      $rootScope.$broadcast('pageMenuClicked');
    };
    $scope.logout = function () {
      QDRService.management.connection.disconnect();
      location.href = "#/connect";
    };
    $scope.user = '';
    let onConnected = function () {
      if (!QDRService.management.connection.is_connected()) {
        setTimeout(onConnected, 1000);
        return;
      }
      QDRService.management.connection.addDisconnectAction(onDisconnect);
      let parts = QDRService.management.connection.getReceiverAddress().split("/");
      parts[parts.length - 1] = "$management";
      let router = parts.join('/');
      QDRService.management.topology.fetchEntity(router, "connection", [], function (nodeId, entity, response) {
        $timeout(function () {
          response.results.some(result => {
            let c = QDRService.utilities.flatten(response.attributeNames, result);
            if (QDRService.utilities.isConsole(c)) {
              $scope.user = c.user;
              return true;
            }
            return false;
          });
        });
      });
    };

    let onDisconnect = function () {
      QDRService.management.connection.addConnectAction(onConnected);
      $timeout(() => {
        $scope.user = '';
      });
    };
    onDisconnect();
  });

  QDR.module.controller('QDR.NavBarController', NavBarController);
  QDR.module.controller('QDR.OverviewController', OverviewController);
  QDR.module.controller('QDR.OverviewChartsController', OverviewChartsController);
  QDR.module.controller('QDR.OverviewLogsController', OverviewLogsController);
  QDR.module.controller('QDR.TopAddressesController', TopAddressesController);
  QDR.module.controller('QDR.ChartDialogController', ChartDialogController);
  QDR.module.controller('QDR.DetailDialogController', DetailDialogController);
  QDR.module.controller('QDR.SettingsController', SettingsController);
  QDR.module.controller('QDR.TopologyController', TopologyController);
  QDR.module.controller('QDR.ChordController', ChordController);
  QDR.module.controller('QDR.ListController', ListController);
  QDR.module.controller('QDR.SchemaController', SchemaController);
  QDR.module.controller('QDR.ChartsController', ChartsController);
  QDR.module.controller('QDR.AboutController', AboutController);

  QDR.module.service('QDRService', QDRService);
  QDR.module.service('QDRChartService', QDRChartService);
  QDR.module.directive('posint', posint);
  QDR.module.directive('subTable', SubTable.create);
  //  .directive('exampleDirective', () => new ExampleDirective);
}({}));

<commit_msg>DISPATCH-1284 Call correct disconnect when logout menu item is clicked<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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.
*/
/* global angular d3 */

/**
 * @module QDR
 * @main QDR
 *
 * The main entry point for the QDR module
 *
 */

//import angular from 'angular';
import { QDRLogger, QDRTemplatePath, QDR_LAST_LOCATION } from './plugin/js/qdrGlobals.js';
import { QDRService } from './plugin/js/qdrService.js';
import { QDRChartService } from './plugin/js/qdrChartService.js';
import { NavBarController } from './plugin/js/navbar.js';
import { OverviewController } from './plugin/js/qdrOverview.js';
import { OverviewChartsController } from './plugin/js/qdrOverviewChartsController.js';
import { OverviewLogsController } from './plugin/js/qdrOverviewLogsController.js';
import { TopologyController } from './plugin/js/topology/qdrTopology.js';
import { ChordController } from './plugin/js/chord/qdrChord.js';
import { ListController } from './plugin/js/qdrList.js';
import { TopAddressesController } from './plugin/js/qdrTopAddressesController.js';
import { ChartDialogController } from './plugin/js/dlgChartController.js';
import { DetailDialogController, SubTable } from './plugin/js/dlgDetailController.js';
import { SettingsController } from './plugin/js/qdrSettings.js';
import { SchemaController } from './plugin/js/qdrSchema.js';
import { ChartsController } from './plugin/js/qdrCharts.js';
import { AboutController } from './plugin/js/qdrAbout.js';
import { posint } from './plugin/js/posintDirective.js';

(function (QDR) {

  /**
   * This plugin's angularjs module instance
   */
  QDR.module = angular.module('QDR', ['ngRoute', 'ngSanitize', 'ngResource', 'ui.bootstrap',
    'ui.grid', 'ui.grid.selection', 'ui.grid.autoResize', 'ui.grid.resizeColumns', 'ui.grid.saveState',
    'ui.slider', 'ui.checkbox', 'patternfly.charts', 'patternfly.card', 'patternfly.modals']);

  // set up the routing for this plugin
  QDR.module.config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: QDRTemplatePath + 'qdrOverview.html'
      })
      .when('/overview', {
        templateUrl: QDRTemplatePath + 'qdrOverview.html'
      })
      .when('/topology', {
        templateUrl: QDRTemplatePath + 'qdrTopology.html'
      })
      .when('/list', {
        templateUrl: QDRTemplatePath + 'qdrList.html'
      })
      .when('/schema', {
        templateUrl: QDRTemplatePath + 'qdrSchema.html'
      })
      .when('/charts', {
        templateUrl: QDRTemplatePath + 'qdrCharts.html'
      })
      .when('/chord', {
        templateUrl: QDRTemplatePath + 'qdrChord.html'
      })
      .when('/connect', {
        templateUrl: QDRTemplatePath + 'qdrConnect.html'
      });
  });

  QDR.module.config(function ($compileProvider) {
    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension|file|blob):/);
    $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension):/);
  });

  QDR.module.filter('to_trusted', ['$sce', function ($sce) {
    return function (text) {
      return $sce.trustAsHtml(text + '');
    };
  }]);

  QDR.module.filter('humanify', ['QDRService', function (QDRService) {
    return function (input) {
      return QDRService.utilities.humanify(input);
    };
  }]);

  QDR.module.filter('Pascalcase', function () {
    return function (str) {
      if (!str)
        return '';
      return str.replace(/(\w)(\w*)/g,
        function (g0, g1, g2) { return g1.toUpperCase() + g2.toLowerCase(); });
    };
  });

  QDR.module.filter('safePlural', function () {
    return function (str) {
      var es = ['x', 'ch', 'ss', 'sh'];
      for (var i = 0; i < es.length; ++i) {
        if (str.endsWith(es[i]))
          return str + 'es';
      }
      if (str.endsWith('y'))
        return str.substr(0, str.length - 2) + 'ies';
      if (str.endsWith('s'))
        return str;
      return str + 's';
    };
  });

  QDR.module.filter('pretty', function () {
    return function (str) {
      var formatComma = d3.format(',');
      if (!isNaN(parseFloat(str)) && isFinite(str))
        return formatComma(str);
      return str;
    };
  });

  QDR.module.filter('truncate', function () {
    return function (str) {
      if (!isNaN(parseFloat(str)) && isFinite(str))
        return Math.round(str);
      return str;
    };
  });
  // one-time initialization happens in the run function
  // of our module
  QDR.module.run(['$rootScope', '$route', '$timeout', '$location', '$log', 'QDRService', 'QDRChartService', function ($rootScope, $route, $timeout, $location, $log, QDRService, QDRChartService) {
    let QDRLog = new QDRLogger($log, 'main');
    QDRLog.info('************* creating Dispatch Console ************');

    var curPath = $location.path();
    var org = curPath.substr(1);
    if (org && org.length > 0 && org !== 'connect') {
      $location.search('org', org);
    } else {
      $location.search('org', null);
    }
    QDR.queue = d3.queue;

    if (!QDRService.management.connection.is_connected()) {
      // attempt to connect to the host:port that served this page
      var host = $location.host();
      var port = $location.port();
      var search = $location.search();
      if (search.org) {
        if (search.org === 'connect')
          $location.search('org', 'overview');
      }
      var connectOptions = { address: host, port: port };
      QDRLog.info('Attempting AMQP over websockets connection using address:port of browser (' + host + ':' + port + ')');
      QDRService.management.connection.testConnect(connectOptions)
        .then(function () {
          // We didn't connect with reconnect: true flag.
          // The reason being that if we used reconnect:true and the connection failed, rhea would keep trying. There
          // doesn't appear to be a way to tell it to stop trying to reconnect.
          QDRService.disconnect();
          QDRLog.info('Connect succeeded. Using address:port of browser');
          connectOptions.reconnect = true;
          // complete the connection (create the sender/receiver)
          QDRService.connect(connectOptions)
            .then(function () {
              // register a callback for when the node list is available (needed for loading saved charts)
              QDRService.management.topology.addUpdatedAction('initChartService', function () {
                QDRService.management.topology.delUpdatedAction('initChartService');
                QDRChartService.init(); // initialize charting service after we are connected
              });
              // get the list of nodes
              QDRService.management.topology.startUpdating(false);
            });
        }, function () {
          QDRLog.info('failed to auto-connect to ' + host + ':' + port);
          QDRLog.info('redirecting to connect page');
          $timeout(function () {
            $location.path('/connect');
            $location.search('org', org);
            $location.replace();
          });
        });
    }

    $rootScope.$on('$routeChangeSuccess', function () {
      var path = $location.path();
      if (path !== '/connect') {
        localStorage[QDR_LAST_LOCATION] = path;
      }
    });
  }]);

  QDR.module.controller('QDR.MainController', ['$scope', '$log', '$location', function ($scope, $log, $location) {
    let QDRLog = new QDRLogger($log, 'MainController');
    QDRLog.debug('started QDR.MainController with location.url: ' + $location.url());
    QDRLog.debug('started QDR.MainController with window.location.pathname : ' + window.location.pathname);
    $scope.topLevelTabs = [];
    $scope.topLevelTabs.push({
      id: 'qdr',
      content: 'Qpid Dispatch Router Console',
      title: 'Dispatch Router Console',
      isValid: function () { return true; },
      href: function () { return '#connect'; },
      isActive: function () { return true; }
    });
  }]);

  QDR.module.controller('QDR.Core', function ($scope, $rootScope, $timeout, QDRService) {
    $scope.alerts = [];
    $scope.breadcrumb = {};
    $scope.closeAlert = function (index) {
      $scope.alerts.splice(index, 1);
    };
    $scope.$on('setCrumb', function (event, data) {
      $scope.breadcrumb = data;
    });
    $scope.$on('newAlert', function (event, data) {
      $scope.alerts.push(data);
      $scope.$apply();
    });
    $scope.$on('clearAlerts', function () {
      $scope.alerts = [];
      $scope.$apply();
    });
    $scope.pageMenuClicked = function () {
      $rootScope.$broadcast('pageMenuClicked');
    };
    $scope.logout = function () {
      QDRService.disconnect();
      location.href = "#/connect";
    };
    $scope.user = '';
    let onConnected = function () {
      if (!QDRService.management.connection.is_connected()) {
        setTimeout(onConnected, 1000);
        return;
      }
      QDRService.management.connection.addDisconnectAction(onDisconnect);
      let parts = QDRService.management.connection.getReceiverAddress().split("/");
      parts[parts.length - 1] = "$management";
      let router = parts.join('/');
      QDRService.management.topology.fetchEntity(router, "connection", [], function (nodeId, entity, response) {
        $timeout(function () {
          response.results.some(result => {
            let c = QDRService.utilities.flatten(response.attributeNames, result);
            if (QDRService.utilities.isConsole(c)) {
              $scope.user = c.user;
              return true;
            }
            return false;
          });
        });
      });
    };

    let onDisconnect = function () {
      QDRService.management.connection.addConnectAction(onConnected);
      $timeout(() => {
        $scope.user = '';
      });
    };
    onDisconnect();
  });

  QDR.module.controller('QDR.NavBarController', NavBarController);
  QDR.module.controller('QDR.OverviewController', OverviewController);
  QDR.module.controller('QDR.OverviewChartsController', OverviewChartsController);
  QDR.module.controller('QDR.OverviewLogsController', OverviewLogsController);
  QDR.module.controller('QDR.TopAddressesController', TopAddressesController);
  QDR.module.controller('QDR.ChartDialogController', ChartDialogController);
  QDR.module.controller('QDR.DetailDialogController', DetailDialogController);
  QDR.module.controller('QDR.SettingsController', SettingsController);
  QDR.module.controller('QDR.TopologyController', TopologyController);
  QDR.module.controller('QDR.ChordController', ChordController);
  QDR.module.controller('QDR.ListController', ListController);
  QDR.module.controller('QDR.SchemaController', SchemaController);
  QDR.module.controller('QDR.ChartsController', ChartsController);
  QDR.module.controller('QDR.AboutController', AboutController);

  QDR.module.service('QDRService', QDRService);
  QDR.module.service('QDRChartService', QDRChartService);
  QDR.module.directive('posint', posint);
  QDR.module.directive('subTable', SubTable.create);
  //  .directive('exampleDirective', () => new ExampleDirective);
}({}));

<|endoftext|>


<commit_before>import { invoke, defer } from 'lodash';
import { observable, action, computed } from 'mobx';
import cn from 'classnames';
import Analytics from '../../helpers/analytics';

export class OverlayRegistry {

  @observable activeOverlay = {};
  @observable page;
  @observable detached;
  @observable isOverlayExpanded = false;
  @observable isOverlayHidden = true;
  @observable isPageHidden = false;

  @computed get pageClassName() {
    return cn('page', {
      hidden: this.isPageHidden,
    });
  }

  @computed get overlayClassName() {
    return cn('overlay', this.activeOverlay.id);
  }

  @action.bound onOverlayAnimated() {
    this.isPageHidden = this.isOverlayExpanded;
    if (!this.isOverlayExpanded) {
      this.isOverlayHidden = true;
    }
  }

  @action hideOverlay() {
    if (this.isOverlayExpanded) {
      this.onHide();
    }
    this.isPageHidden = false;
    this.isOverlayExpanded = false;
  }

  @action.bound onEscKey() {
    this.hideOverlay();
  }

  @action onHide() {
    invoke(this.activeOverlay, 'onHide');
  }

  @action expandOverlay() {
    this.isOverlayHidden = false;
    defer(() => this.isOverlayExpanded = true);
  }

  @action setOverlay({ visible, id, renderer, onHide }) {
    if (visible) {
      if (id !== this.activeOverlay.id) {
        this.onHide();
      }
      this.activeOverlay = { id, renderer, onHide };
      this.expandOverlay();
      Analytics.sendPageView(`/overlay/${id}`);
    } else if (id == this.activeOverlay.id) {
      this.hideOverlay();
    }
  }

  get overlay() {
    if (this.activeOverlay.renderer) {
      return this.activeOverlay.renderer();
    }
    return null;
  }

}

const DefaultRegistry = new OverlayRegistry();

export { DefaultRegistry };
<commit_msg>remember and restore page scroll position<commit_after>import { invoke, defer } from 'lodash';
import { observable, action, computed } from 'mobx';
import cn from 'classnames';
import Analytics from '../../helpers/analytics';

export class OverlayRegistry {

  @observable activeOverlay = {};
  @observable page;
  @observable detached;
  @observable isOverlayExpanded = false;
  @observable isOverlayHidden = true;
  @observable isPageHidden = false;
  @observable pageScrollPosition;

  @computed get pageClassName() {
    return cn('page', {
      hidden: this.isPageHidden,
    });
  }

  @computed get overlayClassName() {
    return cn('overlay', this.activeOverlay.id);
  }

  @action.bound onOverlayAnimated() {
    if (this.isOverlayExpanded) {
      this.pageScrollPosition = { x: window.pageXOffset, y: window.pageYOffset };
    }
    this.isPageHidden = this.isOverlayExpanded;
    if (!this.isOverlayExpanded) {
      this.isOverlayHidden = true;
    }
  }

  @action hideOverlay() {
    if (this.isOverlayExpanded) {
      this.onHide();
    }
    this.isPageHidden = false;
    if (this.pageScrollPosition) {
      defer(() => { // schedule a scroll to take place after the page is re-displayed
        window.scroll(this.pageScrollPosition.x, this.pageScrollPosition.y);
        this.pageScrollPosition = null;
      });
    }
    this.isOverlayExpanded = false;
  }

  @action.bound onEscKey() {
    this.hideOverlay();
  }

  @action onHide() {
    invoke(this.activeOverlay, 'onHide');
  }

  @action expandOverlay() {
    this.isOverlayHidden = false;
    defer(() => this.isOverlayExpanded = true);
  }

  @action setOverlay({ visible, id, renderer, onHide }) {
    if (visible) {
      if (id !== this.activeOverlay.id) {
        this.onHide();
      }
      this.activeOverlay = { id, renderer, onHide };
      this.expandOverlay();
      Analytics.sendPageView(`/overlay/${id}`);
    } else if (id == this.activeOverlay.id) {
      this.hideOverlay();
    }
  }

  get overlay() {
    if (this.activeOverlay.renderer) {
      return this.activeOverlay.renderer();
    }
    return null;
  }

}

const DefaultRegistry = new OverlayRegistry();

export { DefaultRegistry };
<|endoftext|>


<commit_before>function GM_xmlhttpRequester(unsafeContentWin, chromeWindow, originUrl) {
  this.unsafeContentWin = unsafeContentWin;
  this.chromeWindow = chromeWindow;
  this.originUrl = originUrl;
}

// this function gets called by user scripts in content security scope to
// start a cross-domain xmlhttp request.
//
// details should look like:
// {method,url,onload,onerror,onreadystatechange,headers,data}
// headers should be in the form {name:value,name:value,etc}
// can't support mimetype because i think it's only used for forcing
// text/xml and we can't support that
GM_xmlhttpRequester.prototype.contentStartRequest = function(details) {
  if (!GM_apiLeakCheck("GM_xmlhttpRequest")) {
    return;
  }

  GM_log("> GM_xmlhttpRequest.contentStartRequest");

  try {
    // Validate and parse the (possibly relative) given URL.
    var uri = GM_uriFromUrl(details.url, this.originUrl);
    var url = uri.spec;
  } catch (e) {
    // A malformed URL won't be parsed properly.
    throw new Error("Invalid URL: " + details.url);
  }

  // This is important - without it, GM_xmlhttpRequest can be used to get
  // access to things like files and chrome. Careful.
  switch (uri.scheme) {
    case "http":
    case "https":
    case "ftp":
        var req = new this.chromeWindow.XMLHttpRequest();
        GM_hitch(this, "chromeStartRequest", url, details, req)();
      break;
    default:
      throw new Error("Disallowed scheme in URL: " + details.url);
  }

  GM_log("< GM_xmlhttpRequest.contentStartRequest");

  return {
    abort: function() {
      req.abort();
    }
  };
};

// this function is intended to be called in chrome's security context, so
// that it can access other domains without security warning
GM_xmlhttpRequester.prototype.chromeStartRequest =
function(safeUrl, details, req) {
  GM_log("> GM_xmlhttpRequest.chromeStartRequest");

  this.setupRequestEvent(this.unsafeContentWin, req, "onload", details);
  this.setupRequestEvent(this.unsafeContentWin, req, "onerror", details);
  this.setupRequestEvent(this.unsafeContentWin, req, "onreadystatechange",
                         details);

  req.open(details.method, safeUrl, true, details.user || "", details.password || "");

  if (details.overrideMimeType) {
    req.overrideMimeType(details.overrideMimeType);
  }

  if (details.headers) {
    var headers = details.headers;

    for (var prop in headers) {
      if (Object.prototype.hasOwnProperty.call(headers, prop)) {
        req.setRequestHeader(prop, headers[prop]);
      }
    }
  }

  var body = details.data ? details.data : null;
  if (details.binary) {
    // xhr supports binary?
    if (!req.sendAsBinary) {
      var err = new Error("Unavailable feature: " +
              "This version of Firefox does not support sending binary data " +
              "(you should consider upgrading to version 3 or newer.)");
      GM_logError(err);
      throw err;
    }
    req.sendAsBinary(body);
  } else {
    req.send(body);
  }

  GM_log("< GM_xmlhttpRequest.chromeStartRequest");
};

// arranges for the specified 'event' on xmlhttprequest 'req' to call the
// method by the same name which is a property of 'details' in the content
// window's security context.
GM_xmlhttpRequester.prototype.setupRequestEvent =
function(unsafeContentWin, req, event, details) {
  GM_log("> GM_xmlhttpRequester.setupRequestEvent");

  if (details[event]) {
    req[event] = function() {
      GM_log("> GM_xmlhttpRequester -- callback for " + event);

      var responseState = {
        // can't support responseXML because security won't
        // let the browser call properties on it
        responseText: req.responseText,
        readyState: req.readyState,
        responseHeaders: null,
        status: null,
        statusText: null,
        finalUrl: null
      };
      if (4 == req.readyState && 'onerror' != event) {
        responseState.responseHeaders = req.getAllResponseHeaders();
        responseState.status = req.status;
        responseState.statusText = req.statusText;
        responseState.finalUrl = req.channel.URI.spec;
      }

      // Pop back onto browser thread and call event handler.
      // Have to use nested function here instead of GM_hitch because
      // otherwise details[event].apply can point to window.setTimeout, which
      // can be abused to get increased priveledges.
      new XPCNativeWrapper(unsafeContentWin, "setTimeout()")
        .setTimeout(function(){details[event](responseState);}, 0);

      GM_log("< GM_xmlhttpRequester -- callback for " + event);
    };
  }

  GM_log("< GM_xmlhttpRequester.setupRequestEvent");
};
<commit_msg>Add pass-through for mozBackgroundRequest on GM_XHR<commit_after>function GM_xmlhttpRequester(unsafeContentWin, chromeWindow, originUrl) {
  this.unsafeContentWin = unsafeContentWin;
  this.chromeWindow = chromeWindow;
  this.originUrl = originUrl;
}

// this function gets called by user scripts in content security scope to
// start a cross-domain xmlhttp request.
//
// details should look like:
// {method,url,onload,onerror,onreadystatechange,headers,data}
// headers should be in the form {name:value,name:value,etc}
// can't support mimetype because i think it's only used for forcing
// text/xml and we can't support that
GM_xmlhttpRequester.prototype.contentStartRequest = function(details) {
  if (!GM_apiLeakCheck("GM_xmlhttpRequest")) {
    return;
  }

  GM_log("> GM_xmlhttpRequest.contentStartRequest");

  try {
    // Validate and parse the (possibly relative) given URL.
    var uri = GM_uriFromUrl(details.url, this.originUrl);
    var url = uri.spec;
  } catch (e) {
    // A malformed URL won't be parsed properly.
    throw new Error("Invalid URL: " + details.url);
  }

  // This is important - without it, GM_xmlhttpRequest can be used to get
  // access to things like files and chrome. Careful.
  switch (uri.scheme) {
    case "http":
    case "https":
    case "ftp":
        var req = new this.chromeWindow.XMLHttpRequest();
        GM_hitch(this, "chromeStartRequest", url, details, req)();
      break;
    default:
      throw new Error("Disallowed scheme in URL: " + details.url);
  }

  GM_log("< GM_xmlhttpRequest.contentStartRequest");

  return {
    abort: function() {
      req.abort();
    }
  };
};

// this function is intended to be called in chrome's security context, so
// that it can access other domains without security warning
GM_xmlhttpRequester.prototype.chromeStartRequest =
function(safeUrl, details, req) {
  GM_log("> GM_xmlhttpRequest.chromeStartRequest");

  this.setupRequestEvent(this.unsafeContentWin, req, "onload", details);
  this.setupRequestEvent(this.unsafeContentWin, req, "onerror", details);
  this.setupRequestEvent(this.unsafeContentWin, req, "onreadystatechange",
                         details);

  if (details.mozBackgroundRequest) {
      req.mozBackgroundRequest = true;
  }

  req.open(details.method, safeUrl, true, details.user || "", details.password || "");

  if (details.overrideMimeType) {
    req.overrideMimeType(details.overrideMimeType);
  }

  if (details.headers) {
    var headers = details.headers;

    for (var prop in headers) {
      if (Object.prototype.hasOwnProperty.call(headers, prop)) {
        req.setRequestHeader(prop, headers[prop]);
      }
    }
  }

  var body = details.data ? details.data : null;
  if (details.binary) {
    // xhr supports binary?
    if (!req.sendAsBinary) {
      var err = new Error("Unavailable feature: " +
              "This version of Firefox does not support sending binary data " +
              "(you should consider upgrading to version 3 or newer.)");
      GM_logError(err);
      throw err;
    }
    req.sendAsBinary(body);
  } else {
    req.send(body);
  }

  GM_log("< GM_xmlhttpRequest.chromeStartRequest");
};

// arranges for the specified 'event' on xmlhttprequest 'req' to call the
// method by the same name which is a property of 'details' in the content
// window's security context.
GM_xmlhttpRequester.prototype.setupRequestEvent =
function(unsafeContentWin, req, event, details) {
  GM_log("> GM_xmlhttpRequester.setupRequestEvent");

  if (details[event]) {
    req[event] = function() {
      GM_log("> GM_xmlhttpRequester -- callback for " + event);

      var responseState = {
        // can't support responseXML because security won't
        // let the browser call properties on it
        responseText: req.responseText,
        readyState: req.readyState,
        responseHeaders: null,
        status: null,
        statusText: null,
        finalUrl: null
      };
      if (4 == req.readyState && 'onerror' != event) {
        responseState.responseHeaders = req.getAllResponseHeaders();
        responseState.status = req.status;
        responseState.statusText = req.statusText;
        responseState.finalUrl = req.channel.URI.spec;
      }

      // Pop back onto browser thread and call event handler.
      // Have to use nested function here instead of GM_hitch because
      // otherwise details[event].apply can point to window.setTimeout, which
      // can be abused to get increased priveledges.
      new XPCNativeWrapper(unsafeContentWin, "setTimeout()")
        .setTimeout(function(){details[event](responseState);}, 0);

      GM_log("< GM_xmlhttpRequester -- callback for " + event);
    };
  }

  GM_log("< GM_xmlhttpRequester.setupRequestEvent");
};
<|endoftext|>


<commit_before>/*
 * Copyright 2016 The Closure Compiler Authors.
 *
 * 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.
 */

/**
 * @fileoverview Externs definitions for Chai, 3.5 branch.
 *
 * This file defines both the BDD and TDD APIs. The BDD API should be complete.
 *
 * This file defines some virtual types for the chained methods, please don't
 * use these types directly, but follow the official API guidelines.
 *
 * @externs
 * @see http://chaijs.com/
 */

// Below are the externs for the BDD expect API: http://chaijs.com/api/bdd/

/**
 * @param {*} subject
 * @param {string=} opt_description
 * @return {!ExpectChain}
 */
var expect = function(subject, opt_description) {};

/**
 * Represents the chainable return type of `expect()`.
 * @constructor
 */
var ExpectChain = function() {};

/**
 * Represent a non-chainable terminal part in an `expect()` chain. These are
 * effectively assertions.
 * @constructor
 */
var ExpectChainTerminal = function() {};

/** @type {!ExpectChain} */ ExpectChain.prototype.to;
/** @type {!ExpectChain} */ ExpectChain.prototype.be;
/** @type {!ExpectChain} */ ExpectChain.prototype.been;
/** @type {!ExpectChain} */ ExpectChain.prototype.is;
/** @type {!ExpectChain} */ ExpectChain.prototype.that;
/** @type {!ExpectChain} */ ExpectChain.prototype.which;
/** @type {!ExpectChain} */ ExpectChain.prototype.and;
/** @type {!ExpectChain} */ ExpectChain.prototype.has;
/** @type {!ExpectChain} */ ExpectChain.prototype.have;
/** @type {!ExpectChain} */ ExpectChain.prototype.with;
/** @type {!ExpectChain} */ ExpectChain.prototype.at;
/** @type {!ExpectChain} */ ExpectChain.prototype.of;
/** @type {!ExpectChain} */ ExpectChain.prototype.same;
/** @type {!ExpectChain} */ ExpectChain.prototype.not;
/** @type {!ExpectChain} */ ExpectChain.prototype.deep;
/** @type {!ExpectChain} */ ExpectChain.prototype.any;
/** @type {!ExpectChain} */ ExpectChain.prototype.all;
/** @type {!ExpectChain} */ ExpectChain.prototype.length;
/** @type {!ExpectChain} */ ExpectChain.prototype.itself;

/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.ok;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.true;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.false;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.null;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.undefined;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.NaN;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.exist;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.empty;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.arguments;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.extensible;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.sealed;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.frozen;

/**
 * @param {string} type
 * @param {string=} opt_message
 */
ExpectChain.prototype.a = function(type, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.include = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.equal = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.eql = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.above = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.least = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.below = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.most = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.within = function(value, opt_message) {};

/**
 * @param {function(new: Object)} constructor
 * @param {string=} opt_message
 */
ExpectChain.prototype.instanceof = function(constructor, opt_message) {};

/**
 * @param {string} name
 * @param {*=} opt_value
 * @param {string=} opt_message
 */
ExpectChain.prototype.property = function(name, opt_value, opt_message) {};

/**
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.ownProperty = function(name, opt_message) {};

/**
 * @param {string} name
 * @param {!Object=} opt_descriptor
 * @param {string=} opt_message
 */
ExpectChain.prototype.ownPropertyDescriptor =
    function(name, opt_descriptor, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.lengthOf = function(value, opt_message) {};

/**
 * @param {!RegExp} re
 * @param {string=} opt_message
 */
ExpectChain.prototype.match = function(re, opt_message) {};

/**
 * @param {string} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.string = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.keys = function(value, opt_message) {};

/**
 * Note: incomplete definition because it is tricky.
 * @param {...*} var_args
 */
ExpectChain.prototype.throw = function(var_args) {};

/**
 * @param {string} method
 * @param {string=} opt_message
 */
ExpectChain.prototype.respondTo = function(method, opt_message) {};

/**
 * @param {function(*): boolean} matcher
 * @param {string=} opt_message
 */
ExpectChain.prototype.satisfy = function(matcher, opt_message) {};

/**
 * @param {!Array<*>} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.members = function(value, opt_message) {};

/**
 * @param {!Array<*>} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.oneOf = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.change = function(value, name, opt_message) {};

/**
 * @param {*} value
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.increase = function(value, name, opt_message) {};

/**
 * @param {*} value
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.decrease = function(value, name, opt_message) {};

// Below are the externs for the TDD expect API: http://chaijs.com/api/assert/

/** @const */
var assert = {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 * @param {string=} opt_operator
 */
assert.fail = function(actual, expected, opt_message, opt_operator) {};

/**
 * @param {*} object
 * @param {string=} opt_message
 */
assert.isOk = function(object, opt_message) {};

/**
 * @param {*} object
 * @param {string=} opt_message
 */
assert.isNotOk = function(object, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.equal = function(actual, expected, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.strictEqual = function(actual, expected, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.notEqual = function(actual, expected, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.deepEqual = function(actual, expected, opt_message) {};

/**
 * @param {*} valueToCheck
 * @param {*} valueToBeAbove
 * @param {string=} opt_message
 */
assert.isAbove = function(valueToCheck, valueToBeAbove, opt_message) {};

/**
 * @param {*} valueToCheck
 * @param {*} valueToBeBelow
 * @param {string=} opt_message
 */
assert.isBelow = function(valueToCheck, valueToBeBelow, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isTrue = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isFalse = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isUndefined = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isDefined = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} message
 */
assert.isNotNull = function(value, message) {}

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isNull = function(value, opt_message) {};

/**
 * @param {*} object
 * @param {function(new: Object)} constructor
 * @param {string=} opt_message
 */
assert.instanceOf = function(object, constructor, opt_message) {};

/**
 * @param {!Array<*>|string} haystack
 * @param {*} needle
 * @param {string=} opt_message
 */
assert.include = function(haystack, needle, opt_message) {};

/**
 * @param {*} collection
 * @param {number} length
 * @param {string=} message
 */
assert.lengthOf = function(collection, length, message) {};

/**
 * @param {!Array<*>|string} haystack
 * @param {*} needle
 * @param {string=} opt_message
 */
assert.notInclude = function(haystack, needle, opt_message) {};

/**
 * @param {*} object
 * @param {!RegExp} re
 * @param {string=} opt_message
 */
assert.match = function(object, re, opt_message) {};

/**
 * @param {?Object|undefined} object
 * @param {string} property
 * @param {*} value
 * @param {string=} opt_message
 */
assert.propertyVal = function(object, property, value, opt_message) {};

/**
 * @param {function()} fn
 * @param {function(new: Object)|string|!RegExp} constructor
 * @param {string|!RegExp=} opt_regexp
 * @param {string=} opt_message
 */
assert.throws = function(fn, constructor, opt_regexp, opt_message) {};

/**
 * @param {!Array<*>} set1
 * @param {!Array<*>} set2
 * @param {string=} opt_message
 */
assert.sameMembers = function(set1, set2, opt_message) {};
<commit_msg>Fix support for Chai's BDD within.<commit_after>/*
 * Copyright 2016 The Closure Compiler Authors.
 *
 * 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.
 */

/**
 * @fileoverview Externs definitions for Chai, 3.5 branch.
 *
 * This file defines both the BDD and TDD APIs. The BDD API should be complete.
 *
 * This file defines some virtual types for the chained methods, please don't
 * use these types directly, but follow the official API guidelines.
 *
 * @externs
 * @see http://chaijs.com/
 */

// Below are the externs for the BDD expect API: http://chaijs.com/api/bdd/

/**
 * @param {*} subject
 * @param {string=} opt_description
 * @return {!ExpectChain}
 */
var expect = function(subject, opt_description) {};

/**
 * Represents the chainable return type of `expect()`.
 * @constructor
 */
var ExpectChain = function() {};

/**
 * Represent a non-chainable terminal part in an `expect()` chain. These are
 * effectively assertions.
 * @constructor
 */
var ExpectChainTerminal = function() {};

/** @type {!ExpectChain} */ ExpectChain.prototype.to;
/** @type {!ExpectChain} */ ExpectChain.prototype.be;
/** @type {!ExpectChain} */ ExpectChain.prototype.been;
/** @type {!ExpectChain} */ ExpectChain.prototype.is;
/** @type {!ExpectChain} */ ExpectChain.prototype.that;
/** @type {!ExpectChain} */ ExpectChain.prototype.which;
/** @type {!ExpectChain} */ ExpectChain.prototype.and;
/** @type {!ExpectChain} */ ExpectChain.prototype.has;
/** @type {!ExpectChain} */ ExpectChain.prototype.have;
/** @type {!ExpectChain} */ ExpectChain.prototype.with;
/** @type {!ExpectChain} */ ExpectChain.prototype.at;
/** @type {!ExpectChain} */ ExpectChain.prototype.of;
/** @type {!ExpectChain} */ ExpectChain.prototype.same;
/** @type {!ExpectChain} */ ExpectChain.prototype.not;
/** @type {!ExpectChain} */ ExpectChain.prototype.deep;
/** @type {!ExpectChain} */ ExpectChain.prototype.any;
/** @type {!ExpectChain} */ ExpectChain.prototype.all;
/** @type {!ExpectChain} */ ExpectChain.prototype.length;
/** @type {!ExpectChain} */ ExpectChain.prototype.itself;

/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.ok;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.true;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.false;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.null;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.undefined;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.NaN;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.exist;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.empty;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.arguments;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.extensible;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.sealed;
/** @type {!ExpectChainTerminal} */ ExpectChain.prototype.frozen;

/**
 * @param {string} type
 * @param {string=} opt_message
 */
ExpectChain.prototype.a = function(type, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.include = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.equal = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.eql = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.above = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.least = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.below = function(value, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.most = function(value, opt_message) {};

/**
 * @param {number} start
 * @param {number} finish
 * @param {string=} opt_message
 */
ExpectChain.prototype.within = function(start, finish, opt_message) {};

/**
 * @param {function(new: Object)} constructor
 * @param {string=} opt_message
 */
ExpectChain.prototype.instanceof = function(constructor, opt_message) {};

/**
 * @param {string} name
 * @param {*=} opt_value
 * @param {string=} opt_message
 */
ExpectChain.prototype.property = function(name, opt_value, opt_message) {};

/**
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.ownProperty = function(name, opt_message) {};

/**
 * @param {string} name
 * @param {!Object=} opt_descriptor
 * @param {string=} opt_message
 */
ExpectChain.prototype.ownPropertyDescriptor =
    function(name, opt_descriptor, opt_message) {};

/**
 * @param {number} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.lengthOf = function(value, opt_message) {};

/**
 * @param {!RegExp} re
 * @param {string=} opt_message
 */
ExpectChain.prototype.match = function(re, opt_message) {};

/**
 * @param {string} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.string = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.keys = function(value, opt_message) {};

/**
 * Note: incomplete definition because it is tricky.
 * @param {...*} var_args
 */
ExpectChain.prototype.throw = function(var_args) {};

/**
 * @param {string} method
 * @param {string=} opt_message
 */
ExpectChain.prototype.respondTo = function(method, opt_message) {};

/**
 * @param {function(*): boolean} matcher
 * @param {string=} opt_message
 */
ExpectChain.prototype.satisfy = function(matcher, opt_message) {};

/**
 * @param {!Array<*>} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.members = function(value, opt_message) {};

/**
 * @param {!Array<*>} value
 * @param {string=} opt_message
 */
ExpectChain.prototype.oneOf = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.change = function(value, name, opt_message) {};

/**
 * @param {*} value
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.increase = function(value, name, opt_message) {};

/**
 * @param {*} value
 * @param {string} name
 * @param {string=} opt_message
 */
ExpectChain.prototype.decrease = function(value, name, opt_message) {};

// Below are the externs for the TDD expect API: http://chaijs.com/api/assert/

/** @const */
var assert = {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 * @param {string=} opt_operator
 */
assert.fail = function(actual, expected, opt_message, opt_operator) {};

/**
 * @param {*} object
 * @param {string=} opt_message
 */
assert.isOk = function(object, opt_message) {};

/**
 * @param {*} object
 * @param {string=} opt_message
 */
assert.isNotOk = function(object, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.equal = function(actual, expected, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.strictEqual = function(actual, expected, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.notEqual = function(actual, expected, opt_message) {};

/**
 * @param {*} actual
 * @param {*} expected
 * @param {string=} opt_message
 */
assert.deepEqual = function(actual, expected, opt_message) {};

/**
 * @param {*} valueToCheck
 * @param {*} valueToBeAbove
 * @param {string=} opt_message
 */
assert.isAbove = function(valueToCheck, valueToBeAbove, opt_message) {};

/**
 * @param {*} valueToCheck
 * @param {*} valueToBeBelow
 * @param {string=} opt_message
 */
assert.isBelow = function(valueToCheck, valueToBeBelow, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isTrue = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isFalse = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isUndefined = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isDefined = function(value, opt_message) {};

/**
 * @param {*} value
 * @param {string=} message
 */
assert.isNotNull = function(value, message) {}

/**
 * @param {*} value
 * @param {string=} opt_message
 */
assert.isNull = function(value, opt_message) {};

/**
 * @param {*} object
 * @param {function(new: Object)} constructor
 * @param {string=} opt_message
 */
assert.instanceOf = function(object, constructor, opt_message) {};

/**
 * @param {!Array<*>|string} haystack
 * @param {*} needle
 * @param {string=} opt_message
 */
assert.include = function(haystack, needle, opt_message) {};

/**
 * @param {*} collection
 * @param {number} length
 * @param {string=} message
 */
assert.lengthOf = function(collection, length, message) {};

/**
 * @param {!Array<*>|string} haystack
 * @param {*} needle
 * @param {string=} opt_message
 */
assert.notInclude = function(haystack, needle, opt_message) {};

/**
 * @param {*} object
 * @param {!RegExp} re
 * @param {string=} opt_message
 */
assert.match = function(object, re, opt_message) {};

/**
 * @param {?Object|undefined} object
 * @param {string} property
 * @param {*} value
 * @param {string=} opt_message
 */
assert.propertyVal = function(object, property, value, opt_message) {};

/**
 * @param {function()} fn
 * @param {function(new: Object)|string|!RegExp} constructor
 * @param {string|!RegExp=} opt_regexp
 * @param {string=} opt_message
 */
assert.throws = function(fn, constructor, opt_regexp, opt_message) {};

/**
 * @param {!Array<*>} set1
 * @param {!Array<*>} set2
 * @param {string=} opt_message
 */
assert.sameMembers = function(set1, set2, opt_message) {};
<|endoftext|>