<commit_before>import _ from 'lodash';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import Callout from '@folio/stripes-components/lib/Callout';
import Modal from '@folio/stripes-components/lib/Modal';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';
import Popover from '@folio/stripes-components/lib/Popover';
import Button from '@folio/stripes-components/lib/Button';
import IconButton from '@folio/stripes-components/lib/IconButton';
import { UncontrolledDropdown } from '@folio/stripes-components/lib/Dropdown';
import MenuItem from '@folio/stripes-components/lib/MenuItem';
import DropdownMenu from '@folio/stripes-components/lib/DropdownMenu';
import Label from '../../Label';
import css from './OpenLoans.css';
import ActionsBar from '../components/ActionsBar';

import withRenew from '../../../withRenew';

class OpenLoans extends React.Component {
  static propTypes = {
    stripes: PropTypes.shape({
      intl: PropTypes.object.isRequired,
      formatDate: PropTypes.func.isRequired,
      formatDateTime: PropTypes.func.isRequired,
    }),
    onClickViewLoanActionsHistory: PropTypes.func.isRequired,
    loans: PropTypes.arrayOf(PropTypes.object).isRequired,
    renew: PropTypes.func,
    mutator: PropTypes.shape({
      query: PropTypes.object.isRequired,
    }),
    resources: PropTypes.shape({
      query: PropTypes.object,
    }),
  };

  static manifest = {
    query: {},
  }

  constructor(props) {
    super(props);

    this.onRowClick = this.onRowClick.bind(this);
    this.onSort = this.onSort.bind(this);
    this.getLoansFormatter = this.getLoansFormatter.bind(this);
    this.toggleItem = this.toggleItem.bind(this);
    this.toggleAll = this.toggleAll.bind(this);
    this.handleOptionsChange = this.handleOptionsChange.bind(this);
    this.renewSelected = this.renewSelected.bind(this);
    this.formatDate = this.props.stripes.formatDate;
    this.formatDateTime = this.props.stripes.formatDateTime;
    this.hideLoansModal = this.hideLoansModal.bind(this);
    this.callout = null;

    const { stripes } = props;

    this.sortMap = {
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.title' })]: loan => _.get(loan, ['item', 'title']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.barcode' })]: loan => _.get(loan, ['item', 'barcode']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.itemStatus' })]: loan => _.get(loan, ['item', 'status', 'name'], ''),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.loanDate' })]: loan => loan.loanDate,
      [stripes.intl.formatMessage({ id: 'ui-users.loans.details.callNumber' })]: loan => _.get(loan, ['item', 'callNumber']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.contributors' })]: loan => _.get(loan, ['item', 'contributors']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.dueDate' })]: loan => loan.dueDate,
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.renewals' })]: loan => loan.renewalCount,
    };

    this.state = {
      checkedLoans: {},
      allChecked: false,
      sortOrder: ['title', 'barcode'],
      sortDirection: ['asc', 'asc'],
      loanModalOpen: false,
      loanItems: [],
    };
  }

  onRowClick(e, row) {
    if (e.target.type !== 'button') {
      this.props.onClickViewLoanActionsHistory(e, row);
    }
  }

  onSort(e, meta) {
    if (!this.sortMap[meta.alias]) return;

    let { sortOrder, sortDirection } = this.state;

    if (sortOrder[0] !== meta.alias) {
      sortOrder = [meta.alias, sortOrder[0]];
      sortDirection = ['asc', sortDirection[0]];
    } else {
      const direction = (sortDirection[0] === 'desc') ? 'asc' : 'desc';
      sortDirection = [direction, sortDirection[1]];
    }

    this.setState({ ...this.state, sortOrder, sortDirection });
  }

  getContributorslist = (loan) => {
    const contributors = _.get(loan, ['item', 'contributors']);
    const contributorsList = [];
    if (typeof contributors !== 'undefined') {
      Object.keys(contributors).forEach(contributor => contributorsList.push(`${contributors[contributor].name}, `));
    } else {
      contributorsList.push('-');
    }
    return contributorsList;
  }

  getLoansFormatter() {
    const checkedLoans = this.state.checkedLoans;
    return {
      '  ': loan => (
        <input
          checked={!!(checkedLoans[loan.id])}
          onClick={e => this.toggleItem(e, loan)}
          type="checkbox"
        />
      ),
      'title': loan => {
        const title = _.get(loan, ['item', 'title'], '');
        if (title) {
          const titleTodisplay = (title.length >= 77) ? `${title.substring(0, 77)}...` : title;
          return `${titleTodisplay}(${_.get(loan, ['item', 'materialType', 'name'])})`;
        }
        return '-';
      },
      'barcode': loan => _.get(loan, ['item', 'barcode'], ''),
      'itemStatus': loan => `${_.get(loan, ['item', 'status', 'name'], '')}`,
      'Call number': loan => _.get(loan, ['item', 'callNumber'], '-'),
      'Contributors': (loan) => {
        const contributorsList = this.getContributorslist(loan);
        const contributorsListString = contributorsList.join(' ');
        // Truncate if no of contributors > 2
        const listTodisplay = (contributorsList === '-') ? '-' : (contributorsList.length > 2) ? `${contributorsList[0]}, ${contributorsList[1]}...` : `${contributorsListString.substring(0, contributorsListString.length - 2)}`;
        return (contributorsList.length > 2) ?
          (
            <Popover>

{listTodisplay}

                {
                  contributorsList.map(contributor =>
{contributor}
)
                }

            </Popover>
          ) :
          (

              {listTodisplay}

          );
      },
      'loanDate': loan => this.formatDate(loan.loanDate),
      'dueDate': loan => this.formatDateTime(loan.dueDate),
      'renewals': loan => loan.renewalCount || 0,
      ' ': loan => this.renderActions(loan),
    };
  }

  toggleItem(e, loan) {
    e.stopPropagation();

    const id = loan.id;
    const loans = this.state.checkedLoans;
    const checkedLoans = (loans[id])
      ? _.omit(loans, id)
      : { ...loans, [id]: loan };
    const allChecked = _.size(checkedLoans) === this.props.loans.length;
    this.setState({ ...this.state, checkedLoans, allChecked });
  }

  toggleAll(e) {
    const loans = this.props.loans;
    const checkedLoans = (e.target.checked)
      ? loans.reduce((memo, loan) => (Object.assign(memo, { [loan.id]: loan })), {})
      : {};

    const allChecked = !this.state.allChecked;
    this.setState({ ...this.state, checkedLoans, allChecked });
  }

  details(loan, e) {
    this.props.onClickViewLoanActionsHistory(e, loan);
  }

  itemDetails(loan, e) {
    if (e) e.preventDefault();

    // none of the query params relevent to finding a user
    // are relevent to finding instances so we purge them all.
    const q = {};
    Object.keys(this.props.resources.query).forEach((k) => { q[k] = null; });

    this.props.mutator.query.update({
      _path: `/inventory/view/${loan.item.instanceId}/${loan.item.holdingsRecordId}/${loan.itemId}`,
      ...q,
    });
  }

  showLoansModal() {
    this.setState({ loanModalOpen: true });
  }

  hideLoansModal() {
    this.setState({ loanModalOpen: false });
  }

  showSingleRenewCallout(loan) {
    const verb = {this.props.stripes.intl.formatMessage({ id: 'ui-users.loans.item.renewed.callout.verb' })};
    const message = (

        <FormattedMessage
          id="ui-users.loans.item.renewed.callout"
          values={{
            title: {loan.item.title},
            verb: {verb},
          }}
        />

    );

    this.callout.sendCallout({ message });
  }

  showMultiRenewCallout(loanItems) {
    const message = (

        <FormattedMessage
          id="ui-users.loans.items.renewed.callout"
          values={{
            strongCount: {loanItems.length},
            count: loanItems.length,
          }}
        />
        <Button buttonStyle="link marginBottom0" onClick={() => this.showLoansModal()}>
          - <FormattedMessage id="ui-users.loans.items.renewed.callout.details" />
        </Button>

    );

    this.callout.sendCallout({ message });
  }

  renew(loan, skipCallout) {
    const promise = this.props.renew(loan);
    if (skipCallout) return promise;

    promise
      .then(() => this.showSingleRenewCallout(loan));

    return promise;
  }

  renewSelected() {
    const selectedLoans = Object.values(this.state.checkedLoans);
    const renewedLoans = selectedLoans.map(loan => this.renew(loan, true));

    Promise.all(renewedLoans)
      .then(() => this.afterRenewSelected(selectedLoans));
    this.setState({ checkedLoans: {}, allChecked: false });
  }

  afterRenewSelected(loanItems) {
    if (loanItems.length > 1) {
      this.showMultiRenewCallout(loanItems);
      this.setState({ loanItems });
    } else {
      this.showSingleRenewCallout(loanItems[0]);
    }
  }

  /**
   * change handler for the options-menu prevents the event from bubbling
   * up to the event handler attached to the row.
   */
  handleOptionsChange(itemMeta, e) {
    e.preventDefault();
    e.stopPropagation();

    const { loan, action } = itemMeta;

    if (action && this[action]) {
      this[action](loan);
    }
  }

  renderActions(loan) {
    return (
      <UncontrolledDropdown
        onSelectItem={this.handleOptionsChange}
      >
        <IconButton data-role="toggle" icon="ellipsis" size="small" iconSize="medium" />
        <DropdownMenu data-role="menu" overrideStyle={{ padding: '7px 3px' }}>
          <MenuItem itemMeta={{ loan, action: 'itemDetails' }}>
            <Button buttonStyle="dropdownItem" href={`/inventory/view/${loan.item.instanceId}/${loan.item.holdingsRecordId}/${loan.itemId}`}><FormattedMessage id="ui-users.itemDetails" /></Button>
          </MenuItem>
          <MenuItem itemMeta={{ loan, action: 'details' }}>
            <Button buttonStyle="dropdownItem" href={`/users/view/${loan.userId}?layer=loan&loan=${loan.id}`}><FormattedMessage id="ui-users.loanDetails" /></Button>
          </MenuItem>
          <MenuItem itemMeta={{ loan, action: 'renew' }}>
            <Button buttonStyle="dropdownItem"><FormattedMessage id="ui-users.renew" /></Button>
          </MenuItem>
        </DropdownMenu>
      </UncontrolledDropdown>
    );
  }

  renderSubHeader() {
    const checkedLoans = this.state.checkedLoans;

    let stringToolTip = this.props.stripes.intl.formatMessage({ id: 'ui-users.renew' });
    const isDisabled = _.size(checkedLoans) === 0;

    if (isDisabled) {
      stringToolTip = this.props.stripes.intl.formatMessage({ id: 'ui-users.renew.toolTip' });
    }

    return (
      <ActionsBar
        contentStart={{this.props.stripes.intl.formatMessage({ id: 'ui-users.resultCount' }, { count: this.props.loans.length })}}
        contentEnd={<Button marginBottom0 id="renew-all" disabled={isDisabled} title={stringToolTip} onClick={this.renewSelected}><FormattedMessage id="ui-users.renew" /></Button>}
      />
    );
  }

  render() {
    const { sortOrder, sortDirection, allChecked, loanItems } = this.state;
    const visibleColumns = ['  ', 'title', 'itemStatus', 'barcode', 'loanDate', 'Call number', 'Contributors', 'dueDate', 'renewals', ' '];
    const columnMapping = {
      '  ': (<input type="checkbox" checked={allChecked} name="check-all" onChange={this.toggleAll} />),
      'title': <FormattedMessage id="ui-users.loans.columns.title" />,
      'itemStatus': <FormattedMessage id="ui-users.loans.columns.itemStatus" />,
      'barcode': <FormattedMessage id="ui-users.loans.columns.barcode" />,
      'loanDate': <FormattedMessage id="ui-users.loans.columns.loanDate" />,
      'Call number': <FormattedMessage id="ui-users.loans.details.callNumber" />,
      'Contributors': <FormattedMessage id="ui-users.loans.columns.contributors" />,
      'dueDate': <FormattedMessage id="ui-users.loans.columns.dueDate" />,
      'renewals': <FormattedMessage id="ui-users.loans.columns.renewals" />,
    };

    const loans = _.orderBy(this.props.loans,
      [this.sortMap[sortOrder[0]], this.sortMap[sortOrder[1]]], sortDirection);
    const subHeading = (

        <FormattedMessage
          id="ui-users.loans.items.renewed.subheading"
          values={{
            strongCount: {loanItems.length},
            count: loanItems.length,
            verb: {this.props.stripes.intl.formatMessage({ id: 'ui-users.loans.item.renewed.callout.verb' })},
          }}
        />

    );

    const label = this.props.stripes.intl.formatMessage({ id: 'ui-users.loans.items.renewed.label' });
    return (

        {this.props.loans.length > 0 && this.renderSubHeader()}
        <MultiColumnList
          id="list-loanshistory"
          fullWidth
          formatter={this.getLoansFormatter()}
          columnWidths={{ '  ': 28, 'barcode': 150, 'loanDate': 120, 'title': 250, 'Call number': 150, 'Contributors': 150, 'dueDate': 160, 'renewals': 70, ' ': 50 }}
          visibleColumns={visibleColumns}
          columnMapping={columnMapping}
          columnOverflow={{ ' ': true }}
          onHeaderClick={this.onSort}
          onRowClick={this.props.onClickViewLoanActionsHistory}
          sortOrder={sortOrder[0]}
          sortDirection={`${sortDirection[0]}ending`}
          contentData={loans}
          interactive={false}
        />
        <Modal dismissible closeOnBackgroundClick onClose={this.hideLoansModal} open={this.state.loanModalOpen} label={label}>
          {subHeading}
          {
              loanItems.map((loanItem, index) => (

                  {loanItem.item.title}

))
          }
        </Modal>
        <Callout ref={(ref) => { this.callout = ref; }} />

    );
  }
}

export default withRenew(OpenLoans);
<commit_msg>Removed arrow function for getContributorslist method and re-binded in constructor. Added an eslint-disable-line comment because it triggered the 'class-methods-use-this' linting error.<commit_after>import _ from 'lodash';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import Callout from '@folio/stripes-components/lib/Callout';
import Modal from '@folio/stripes-components/lib/Modal';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';
import Popover from '@folio/stripes-components/lib/Popover';
import Button from '@folio/stripes-components/lib/Button';
import IconButton from '@folio/stripes-components/lib/IconButton';
import { UncontrolledDropdown } from '@folio/stripes-components/lib/Dropdown';
import MenuItem from '@folio/stripes-components/lib/MenuItem';
import DropdownMenu from '@folio/stripes-components/lib/DropdownMenu';
import Label from '../../Label';
import css from './OpenLoans.css';
import ActionsBar from '../components/ActionsBar';

import withRenew from '../../../withRenew';

class OpenLoans extends React.Component {
  static propTypes = {
    stripes: PropTypes.shape({
      intl: PropTypes.object.isRequired,
      formatDate: PropTypes.func.isRequired,
      formatDateTime: PropTypes.func.isRequired,
    }),
    onClickViewLoanActionsHistory: PropTypes.func.isRequired,
    loans: PropTypes.arrayOf(PropTypes.object).isRequired,
    renew: PropTypes.func,
    mutator: PropTypes.shape({
      query: PropTypes.object.isRequired,
    }),
    resources: PropTypes.shape({
      query: PropTypes.object,
    }),
  };

  static manifest = {
    query: {},
  }

  constructor(props) {
    super(props);

    this.onRowClick = this.onRowClick.bind(this);
    this.onSort = this.onSort.bind(this);
    this.getLoansFormatter = this.getLoansFormatter.bind(this);
    this.toggleItem = this.toggleItem.bind(this);
    this.toggleAll = this.toggleAll.bind(this);
    this.handleOptionsChange = this.handleOptionsChange.bind(this);
    this.renewSelected = this.renewSelected.bind(this);
    this.formatDate = this.props.stripes.formatDate;
    this.formatDateTime = this.props.stripes.formatDateTime;
    this.hideLoansModal = this.hideLoansModal.bind(this);
    this.getContributorslist = this.getContributorslist.bind(this);
    this.callout = null;

    const { stripes } = props;

    this.sortMap = {
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.title' })]: loan => _.get(loan, ['item', 'title']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.barcode' })]: loan => _.get(loan, ['item', 'barcode']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.itemStatus' })]: loan => _.get(loan, ['item', 'status', 'name'], ''),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.loanDate' })]: loan => loan.loanDate,
      [stripes.intl.formatMessage({ id: 'ui-users.loans.details.callNumber' })]: loan => _.get(loan, ['item', 'callNumber']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.contributors' })]: loan => _.get(loan, ['item', 'contributors']),
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.dueDate' })]: loan => loan.dueDate,
      [stripes.intl.formatMessage({ id: 'ui-users.loans.columns.renewals' })]: loan => loan.renewalCount,
    };

    this.state = {
      checkedLoans: {},
      allChecked: false,
      sortOrder: ['title', 'barcode'],
      sortDirection: ['asc', 'asc'],
      loanModalOpen: false,
      loanItems: [],
    };
  }

  onRowClick(e, row) {
    if (e.target.type !== 'button') {
      this.props.onClickViewLoanActionsHistory(e, row);
    }
  }

  onSort(e, meta) {
    if (!this.sortMap[meta.alias]) return;

    let { sortOrder, sortDirection } = this.state;

    if (sortOrder[0] !== meta.alias) {
      sortOrder = [meta.alias, sortOrder[0]];
      sortDirection = ['asc', sortDirection[0]];
    } else {
      const direction = (sortDirection[0] === 'desc') ? 'asc' : 'desc';
      sortDirection = [direction, sortDirection[1]];
    }

    this.setState({ ...this.state, sortOrder, sortDirection });
  }

  getContributorslist(loan) { // eslint-disable-line class-methods-use-this
    const contributors = _.get(loan, ['item', 'contributors']);
    const contributorsList = [];
    if (typeof contributors !== 'undefined') {
      Object.keys(contributors).forEach(contributor => contributorsList.push(`${contributors[contributor].name}, `));
    } else {
      contributorsList.push('-');
    }
    return contributorsList;
  }

  getLoansFormatter() {
    const checkedLoans = this.state.checkedLoans;
    return {
      '  ': loan => (
        <input
          checked={!!(checkedLoans[loan.id])}
          onClick={e => this.toggleItem(e, loan)}
          type="checkbox"
        />
      ),
      'title': loan => {
        const title = _.get(loan, ['item', 'title'], '');
        if (title) {
          const titleTodisplay = (title.length >= 77) ? `${title.substring(0, 77)}...` : title;
          return `${titleTodisplay}(${_.get(loan, ['item', 'materialType', 'name'])})`;
        }
        return '-';
      },
      'barcode': loan => _.get(loan, ['item', 'barcode'], ''),
      'itemStatus': loan => `${_.get(loan, ['item', 'status', 'name'], '')}`,
      'Call number': loan => _.get(loan, ['item', 'callNumber'], '-'),
      'Contributors': (loan) => {
        const contributorsList = this.getContributorslist(loan);
        const contributorsListString = contributorsList.join(' ');
        // Truncate if no of contributors > 2
        const listTodisplay = (contributorsList === '-') ? '-' : (contributorsList.length > 2) ? `${contributorsList[0]}, ${contributorsList[1]}...` : `${contributorsListString.substring(0, contributorsListString.length - 2)}`;
        return (contributorsList.length > 2) ?
          (
            <Popover>

{listTodisplay}

                {
                  contributorsList.map(contributor =>
{contributor}
)
                }

            </Popover>
          ) :
          (

              {listTodisplay}

          );
      },
      'loanDate': loan => this.formatDate(loan.loanDate),
      'dueDate': loan => this.formatDateTime(loan.dueDate),
      'renewals': loan => loan.renewalCount || 0,
      ' ': loan => this.renderActions(loan),
    };
  }

  toggleItem(e, loan) {
    e.stopPropagation();

    const id = loan.id;
    const loans = this.state.checkedLoans;
    const checkedLoans = (loans[id])
      ? _.omit(loans, id)
      : { ...loans, [id]: loan };
    const allChecked = _.size(checkedLoans) === this.props.loans.length;
    this.setState({ ...this.state, checkedLoans, allChecked });
  }

  toggleAll(e) {
    const loans = this.props.loans;
    const checkedLoans = (e.target.checked)
      ? loans.reduce((memo, loan) => (Object.assign(memo, { [loan.id]: loan })), {})
      : {};

    const allChecked = !this.state.allChecked;
    this.setState({ ...this.state, checkedLoans, allChecked });
  }

  details(loan, e) {
    this.props.onClickViewLoanActionsHistory(e, loan);
  }

  itemDetails(loan, e) {
    if (e) e.preventDefault();

    // none of the query params relevent to finding a user
    // are relevent to finding instances so we purge them all.
    const q = {};
    Object.keys(this.props.resources.query).forEach((k) => { q[k] = null; });

    this.props.mutator.query.update({
      _path: `/inventory/view/${loan.item.instanceId}/${loan.item.holdingsRecordId}/${loan.itemId}`,
      ...q,
    });
  }

  showLoansModal() {
    this.setState({ loanModalOpen: true });
  }

  hideLoansModal() {
    this.setState({ loanModalOpen: false });
  }

  showSingleRenewCallout(loan) {
    const verb = {this.props.stripes.intl.formatMessage({ id: 'ui-users.loans.item.renewed.callout.verb' })};
    const message = (

        <FormattedMessage
          id="ui-users.loans.item.renewed.callout"
          values={{
            title: {loan.item.title},
            verb: {verb},
          }}
        />

    );

    this.callout.sendCallout({ message });
  }

  showMultiRenewCallout(loanItems) {
    const message = (

        <FormattedMessage
          id="ui-users.loans.items.renewed.callout"
          values={{
            strongCount: {loanItems.length},
            count: loanItems.length,
          }}
        />
        <Button buttonStyle="link marginBottom0" onClick={() => this.showLoansModal()}>
          - <FormattedMessage id="ui-users.loans.items.renewed.callout.details" />
        </Button>

    );

    this.callout.sendCallout({ message });
  }

  renew(loan, skipCallout) {
    const promise = this.props.renew(loan);
    if (skipCallout) return promise;

    promise
      .then(() => this.showSingleRenewCallout(loan));

    return promise;
  }

  renewSelected() {
    const selectedLoans = Object.values(this.state.checkedLoans);
    const renewedLoans = selectedLoans.map(loan => this.renew(loan, true));

    Promise.all(renewedLoans)
      .then(() => this.afterRenewSelected(selectedLoans));
    this.setState({ checkedLoans: {}, allChecked: false });
  }

  afterRenewSelected(loanItems) {
    if (loanItems.length > 1) {
      this.showMultiRenewCallout(loanItems);
      this.setState({ loanItems });
    } else {
      this.showSingleRenewCallout(loanItems[0]);
    }
  }

  /**
   * change handler for the options-menu prevents the event from bubbling
   * up to the event handler attached to the row.
   */
  handleOptionsChange(itemMeta, e) {
    e.preventDefault();
    e.stopPropagation();

    const { loan, action } = itemMeta;

    if (action && this[action]) {
      this[action](loan);
    }
  }

  renderActions(loan) {
    return (
      <UncontrolledDropdown
        onSelectItem={this.handleOptionsChange}
      >
        <IconButton data-role="toggle" icon="ellipsis" size="small" iconSize="medium" />
        <DropdownMenu data-role="menu" overrideStyle={{ padding: '7px 3px' }}>
          <MenuItem itemMeta={{ loan, action: 'itemDetails' }}>
            <Button buttonStyle="dropdownItem" href={`/inventory/view/${loan.item.instanceId}/${loan.item.holdingsRecordId}/${loan.itemId}`}><FormattedMessage id="ui-users.itemDetails" /></Button>
          </MenuItem>
          <MenuItem itemMeta={{ loan, action: 'details' }}>
            <Button buttonStyle="dropdownItem" href={`/users/view/${loan.userId}?layer=loan&loan=${loan.id}`}><FormattedMessage id="ui-users.loanDetails" /></Button>
          </MenuItem>
          <MenuItem itemMeta={{ loan, action: 'renew' }}>
            <Button buttonStyle="dropdownItem"><FormattedMessage id="ui-users.renew" /></Button>
          </MenuItem>
        </DropdownMenu>
      </UncontrolledDropdown>
    );
  }

  renderSubHeader() {
    const checkedLoans = this.state.checkedLoans;

    let stringToolTip = this.props.stripes.intl.formatMessage({ id: 'ui-users.renew' });
    const isDisabled = _.size(checkedLoans) === 0;

    if (isDisabled) {
      stringToolTip = this.props.stripes.intl.formatMessage({ id: 'ui-users.renew.toolTip' });
    }

    return (
      <ActionsBar
        contentStart={{this.props.stripes.intl.formatMessage({ id: 'ui-users.resultCount' }, { count: this.props.loans.length })}}
        contentEnd={<Button marginBottom0 id="renew-all" disabled={isDisabled} title={stringToolTip} onClick={this.renewSelected}><FormattedMessage id="ui-users.renew" /></Button>}
      />
    );
  }

  render() {
    const { sortOrder, sortDirection, allChecked, loanItems } = this.state;
    const visibleColumns = ['  ', 'title', 'itemStatus', 'barcode', 'loanDate', 'Call number', 'Contributors', 'dueDate', 'renewals', ' '];
    const columnMapping = {
      '  ': (<input type="checkbox" checked={allChecked} name="check-all" onChange={this.toggleAll} />),
      'title': <FormattedMessage id="ui-users.loans.columns.title" />,
      'itemStatus': <FormattedMessage id="ui-users.loans.columns.itemStatus" />,
      'barcode': <FormattedMessage id="ui-users.loans.columns.barcode" />,
      'loanDate': <FormattedMessage id="ui-users.loans.columns.loanDate" />,
      'Call number': <FormattedMessage id="ui-users.loans.details.callNumber" />,
      'Contributors': <FormattedMessage id="ui-users.loans.columns.contributors" />,
      'dueDate': <FormattedMessage id="ui-users.loans.columns.dueDate" />,
      'renewals': <FormattedMessage id="ui-users.loans.columns.renewals" />,
    };

    const loans = _.orderBy(this.props.loans,
      [this.sortMap[sortOrder[0]], this.sortMap[sortOrder[1]]], sortDirection);
    const subHeading = (

        <FormattedMessage
          id="ui-users.loans.items.renewed.subheading"
          values={{
            strongCount: {loanItems.length},
            count: loanItems.length,
            verb: {this.props.stripes.intl.formatMessage({ id: 'ui-users.loans.item.renewed.callout.verb' })},
          }}
        />

    );

    const label = this.props.stripes.intl.formatMessage({ id: 'ui-users.loans.items.renewed.label' });
    return (

        {this.props.loans.length > 0 && this.renderSubHeader()}
        <MultiColumnList
          id="list-loanshistory"
          fullWidth
          formatter={this.getLoansFormatter()}
          columnWidths={{ '  ': 28, 'barcode': 150, 'loanDate': 120, 'title': 250, 'Call number': 150, 'Contributors': 150, 'dueDate': 160, 'renewals': 70, ' ': 50 }}
          visibleColumns={visibleColumns}
          columnMapping={columnMapping}
          columnOverflow={{ ' ': true }}
          onHeaderClick={this.onSort}
          onRowClick={this.props.onClickViewLoanActionsHistory}
          sortOrder={sortOrder[0]}
          sortDirection={`${sortDirection[0]}ending`}
          contentData={loans}
          interactive={false}
        />
        <Modal dismissible closeOnBackgroundClick onClose={this.hideLoansModal} open={this.state.loanModalOpen} label={label}>
          {subHeading}
          {
              loanItems.map((loanItem, index) => (

                  {loanItem.item.title}

))
          }
        </Modal>
        <Callout ref={(ref) => { this.callout = ref; }} />

    );
  }
}

export default withRenew(OpenLoans);
<|endoftext|>


<commit_before>var fs = require('fs'),
    zlib = require('zlib'),
    vow = require('vow'),
    vowNode = require('vow-node'),
    inherit = require('inherit'),
    tar = require('tar'),
    fstream = require('fstream'),
    fsExtra = require('fs-extra'),

    Logger = require('bem-site-logger'),
    Pather = require('../pather');

module.exports = inherit({
    _logger: undefined,
    _pather: undefined,

    __constructor: function (options) {
        this._pather = Pather.create(options.path);
        this._logger = Logger.setOptions(options['logger']).createLogger(module);
    },

    /**
     * Executes current task
     * @param {Object} data object with fields:
     * - {Object} buildResult - result of data building. Have methods for retrieving changes model
     * - {String} snapshotName - name of snapshot
     * @returns {*}
     */
    execute: function (data) {
        this._logger.info('_sendSnapshot: %s', data.snapshotName);
        return vow.resolve(data)
            .then(this._createDbArchive.bind(this))
            .then(this._removeDbFolder.bind(this));
    },

    /**
     * Returns name of current task
     * @returns {String}
     */
    getName: function () {
        return 'simple';
    },

    /**
     * Creates archive from snapshot database folder
     * @param {Object} data object with fields:
     * - {Object} buildResult - result of data building. Have methods for retrieving changes model
     * - {String} snapshotName - name of snapshot
     * @returns {*}
     * @private
     */
    _createDbArchive: function (data) {
        var _this = this,
            def = vow.defer(),
            dbDir = this._pather.getSnapshotDbDir(data.snapshotName);

        this._logger.debug('_createDbArchive: for folder %s', dbDir);

        fstream.Reader({ path: dbDir, type: 'Directory' })
            .pipe(tar.Pack())
            .pipe(zlib.Gzip())
            .pipe(fs.createWriteStream(dbDir + '.tar.gz'))
            .on('error', function (err) {
                _this._logger.error('_createDbArchive: Error %s', err.message);
                def.reject(err);
            })
            .on('close', function () {
                _this._logger.debug('_createDbArchive: Success');
                def.resolve(data);
            })
            .on('end', function () {
                _this._logger.debug('_createDbArchive: Success');
                def.resolve(data);
            });
        return def.promise();
    },

    /**
     * Removes database folder
     * @param {Object} data object with fields:
     * - {Object} buildResult - result of data building. Have methods for retrieving changes model
     * - {String} snapshotName - name of snapshot
     * @returns {*}
     * @private
     */
    _removeDbFolder: function (data) {
        var dbDir = this._pather.getSnapshotDbDir(data.snapshotName);
        this._logger.debug('_removeDbFolder: %s', dbDir);
        return vowNode.promisify(fsExtra.remove)(dbDir).then(function () {
            this._logger.debug('_removeDbFolder: Success');
            return data;
        }, this);
    }
});
<commit_msg>Make small code refactoring in lib/send/simple.js module<commit_after>var fs = require('fs'),
    zlib = require('zlib'),
    vow = require('vow'),
    vowNode = require('vow-node'),
    inherit = require('inherit'),
    tar = require('tar'),
    fstream = require('fstream'),
    fsExtra = require('fs-extra'),

    Logger = require('bem-site-logger'),
    Pather = require('../pather');

module.exports = inherit({
    _logger: undefined,
    _pather: undefined,

    __constructor: function (options) {
        this._pather = Pather.create(options.path);
        this._logger = Logger.setOptions(options['logger']).createLogger(module);
    },

    /**
     * Executes current task
     * @param {Object} data object with fields:
     * - {Object} buildResult - result of data building. Have methods for retrieving changes model
     * - {String} snapshotName - name of snapshot
     * @returns {*}
     */
    execute: function (data) {
        this._logger.info('_sendSnapshot: %s', data.snapshotName);
        return vow.resolve(data)
            .then(this._createDbArchive.bind(this))
            .then(this._removeDbFolder.bind(this));
    },

    /**
     * Returns name of current task
     * @returns {String}
     */
    getName: function () {
        return 'simple';
    },

    /**
     * Creates archive from snapshot database folder
     * @param {Object} data object with fields:
     * - {Object} buildResult - result of data building. Have methods for retrieving changes model
     * - {String} snapshotName - name of snapshot
     * @returns {*}
     * @private
     */
    _createDbArchive: function (data) {
        var _this = this,
            def = vow.defer(),
            dbDir = this._pather.getSnapshotDbDir(data.snapshotName),
            onSuccess = function () {
                _this._logger.debug('_createDbArchive: Success');
                def.resolve(data);
            },
            onError = function (err) {
                _this._logger.error('_createDbArchive: Error %s', err.message);
                def.reject(err);
            };

        this._logger.debug('_createDbArchive: for folder %s', dbDir);
        fstream.Reader({ path: dbDir, type: 'Directory' })
            .pipe(tar.Pack())
            .pipe(zlib.Gzip())
            .pipe(fs.createWriteStream(dbDir + '.tar.gz'))
            .on('error', onError)
            .on('close', onSuccess)
            .on('end', onSuccess);
        return def.promise();
    },

    /**
     * Removes database folder
     * @param {Object} data object with fields:
     * - {Object} buildResult - result of data building. Have methods for retrieving changes model
     * - {String} snapshotName - name of snapshot
     * @returns {*}
     * @private
     */
    _removeDbFolder: function (data) {
        var dbDir = this._pather.getSnapshotDbDir(data.snapshotName);
        this._logger.debug('_removeDbFolder: %s', dbDir);
        return vowNode.promisify(fsExtra.remove)(dbDir).then(function () {
            this._logger.debug('_removeDbFolder: Success');
            return data;
        }, this);
    }
});
<|endoftext|>


<commit_before>(function () {
    'use strict';

    if (!global.cloudcmd)
        return console.log(
             '# pipe.js'                                        + '\n'  +
             '# -----------'                                    + '\n'  +
             '# Module is part of Cloud Commander,'             + '\n'  +
             '# used for work with stream.'                     + '\n'  +
             '# If you wont to see at work call'                + '\n'  +
             '# stream.createPipe'                              + '\n'  +
             '# http://cloudcmd.io'                             + '\n');

    var main        = global.cloudcmd.main,
        fs          = main.fs,
        Util        = main.util,
        zlib        = main.zlib;

    exports.getBody = getBody;

    exports.create  = function(pParams) {
        var lZlib, lError, lMsg, lRead, lWrite, lIsFsWrite,
            p               = pParams;

        if (p) {
            lRead           = p.read    || fs.createReadStream(p.from, {
                bufferSize: 4 * 1024
            });

            if (p.write)
                lWrite      = p.write;
            else {
                lWrite      = fs.createWriteStream(p.to);
                lIsFsWrite  = true;
            }

            lError  = function(pError) {
                Util.exec(p.callback, pError);
            };

            if (p.gzip) {
                lZlib       = zlib.createGzip();
                lRead.on('error', lError);
                lRead       = lRead.pipe(lZlib);
            }

            lWrite.on('error', lError);
            lRead.on('error', lError);

            Util.ifExec(!lIsFsWrite, function() {
                lRead.on('data', function(data) {
                    lWrite.write(data);
                });

                lRead.on('end', function() {
                    if (!p.notEnd)
                        lWrite.end();

                    Util.exec(p.callback);
                });
            }, function(pCallBack) {
                lWrite.on('open', pCallBack);
            });
        }
    };

    /**
     * get body of readStream
     *
     * @param readStream
     * @param callback
     */
    function getBody(readStream, callback) {
        var body = '';

        readStream.on('data', function(chunk) {
            body += chunk;
        });

        readStream.on('end', function() {
            Util.exec(callback, body);
        });
    }
})();
<commit_msg>refactor(pipe) lRead -> read<commit_after>(function () {
    'use strict';

    if (!global.cloudcmd)
        return console.log(
             '# pipe.js'                                        + '\n'  +
             '# -----------'                                    + '\n'  +
             '# Module is part of Cloud Commander,'             + '\n'  +
             '# used for work with stream.'                     + '\n'  +
             '# If you wont to see at work call'                + '\n'  +
             '# stream.createPipe'                              + '\n'  +
             '# http://cloudcmd.io'                             + '\n');

    var main        = global.cloudcmd.main,
        fs          = main.fs,
        Util        = main.util,
        zlib        = main.zlib;

    exports.getBody = getBody;

    exports.create  = function(params) {
        var gzip, onError, read, write, isFsWrite,
            p               = params;

        if (p) {
            read           = p.read    || fs.createReadStream(p.from, {
                bufferSize: 4 * 1024
            });

            if (p.write)
                write      = p.write;
            else {
                write      = fs.createWriteStream(p.to);
                isFsWrite  = true;
            }

            onError  = function(error) {
                Util.exec(p.callback, error);
            };

            if (p.gzip) {
                gzip       = zlib.createGzip();
                read.on('error', onError);
                read       = read.pipe(gzip);
            }

            write.on('error', onError);
            read.on('error', onError);

            Util.ifExec(!isFsWrite, function() {
                read.on('data', function(data) {
                    write.write(data);
                });

                read.on('end', function() {
                    if (!p.notEnd)
                        write.end();

                    Util.exec(p.callback);
                });
            }, function(callback) {
                write.on('open', callback);
            });
        }
    };

    /**
     * get body of readStream
     *
     * @param readStream
     * @param callback
     */
    function getBody(readStream, callback) {
        var body = '';

        readStream.on('data', function(chunk) {
            body += chunk;
        });

        readStream.on('end', function() {
            Util.exec(callback, body);
        });
    }
})();
<|endoftext|>


<commit_before>/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
 * for the full text of the license. */

// TRASH THIS
OpenLayers.State = {
    /** states */
    UNKNOWN: 'Unknown',
    INSERT: 'Insert',
    UPDATE: 'Update',
    DELETE: 'Delete'
}

/**
 * @class
 *
 * @requires OpenLayers/Feature.js
 * @requires OpenLayers/Util.js
 */
OpenLayers.Feature.Vector = OpenLayers.Class.create();
OpenLayers.Feature.Vector.prototype =
  OpenLayers.Class.inherit( OpenLayers.Feature, {

    /** @type String */
    fid: null,

    /** @type OpenLayers.Geometry */
    geometry:null,

    /** @type array */
    attributes: {},

    /** @type strinng */
    state: null,

    /** @type Object */
    style: null,

    /**
     * Create a vector feature.
     * @constructor
     *
     * @param {OpenLayers.Geometry} geometry
     * @param {Object} data
     */
    initialize: function(geometry, data, style) {
        OpenLayers.Feature.prototype.initialize.apply(this, [null, null, data]);
        this.lonlat = null;
        this.setGeometry(geometry);
        this.state = null;
        if (data) {
            OpenLayers.Util.extend(this.attributes, data);
        }
        this.style = style ? style : null;
    },

   /**
    * @returns An exact clone of this OpenLayers.Feature
    * @type OpenLayers.Feature
    */
    clone: function (obj) {
        if (obj == null) {
            obj = new OpenLayers.Feature(null, this.geometry.clone(), this.data);
        }

        // catch any randomly tagged-on properties
        OpenLayers.Util.applyDefaults(obj, this);

        return obj;
    },

    /**
     *
     */
    destroy: function() {
        this.geometry = null;
        OpenLayers.Feature.prototype.destroy.apply(this, arguments);
    },

    /**
     * HACK - we need to rewrite this for non-point geometry
     * @returns null - we need to rewrite this for non-point geometry
     * @type Boolean
     */
    onScreen:function() {
        return null;
    },

    /**
     *
     * HACK - we need to decide if all vector features should be able to
     * create markers
     *
     * @returns null
     *
     * @type OpenLayers.Marker
     */
    createMarker: function() {
        return null;
    },

    /**
     * HACK - we need to decide if all vector features should be able to
     * delete markers
     *
     * If user overrides the createMarker() function, s/he should be able
     *   to also specify an alternative function for destroying it
     */
    destroyMarker: function() {
        // pass
    },

    /**
     * HACK - we need to decide if all vector features should be able to
     * create popups
     *
     * @returns null
     */
    createPopup: function() {
        return null;
    },

    /**
     * Set a feature id to the feature
     *
     * @param {String} feature id to set
     */
    setFid: function(fid) {
        this.fid = fid;
    },

    /**
     * Set a geometry to the feature
     *
     * @param {OpenLayers.Geometry} geometry to set
     * @param {Boolean} recurse Recursively set feature (for components)
     */
    setGeometry: function(geometry, recurse) {
        if(geometry) {
            this.geometry = geometry;
            this.geometry.feature = this;
            if (recurse != false) {
                this._setGeometryFeatureReference(this.geometry, this);
            }
        }
    },

    /**
     * Sets recursively the reference to the feature in the geometry
     *
     * @param {OpenLayers.Geometry}
     * @param {OpenLayers.Feature}
     */
    _setGeometryFeatureReference: function(geometry, feature) {
        geometry.feature = feature;
        if (geometry.components) {
            for (var i = 0; i < geometry.components.length; i++) {
                this._setGeometryFeatureReference(geometry.components[i], feature);
            }
        }
    },

    /**
     * Adds attributes an attributes object to the feature.
     * (should not be in geometry but in feature class)
     *
     * @param {Attributes} attributes
     */
    setAttributes: function(attributes) {
        this.attributes=attributes;
    },

    /**
     * @param {OpenLayers.LonLat} lonlat
     * @param {float} toleranceLon Optional tolerance in Geometric Coords
     * @param {float} toleranceLat Optional tolerance in Geographic Coords
     *
     * @returns Whether or not the feature is at the specified location
     * @type Boolean
     */
    atPoint: function(lonlat, toleranceLon, toleranceLat) {
        var atPoint = false;
        if(this.geometry) {
            atPoint = this.geometry.atPoint(lonlat, toleranceLon,
                                                    toleranceLat);
        }
        return atPoint;
    },

    /**
     *
     * HACK - we need to decide if all vector features should be able to
     * delete popups
     */
    destroyPopup: function() {
        // pass
    },

    /**
     * Sets the new state
     * @param {String} state
     */
    toState: function(state) {
        if (state == OpenLayers.State.UPDATE) {
            switch (this.state) {
                case OpenLayers.State.UNKNOWN:
                case OpenLayers.State.DELETE:
                    this.state = state;
                    break;
                case OpenLayers.State.UPDATE:
                case OpenLayers.State.INSERT:
                    break;
            }
        } else if (state == OpenLayers.State.INSERT) {
            switch (this.state) {
                case OpenLayers.State.UNKNOWN:
                    break;
                default:
                    this.state = state;
                    break;
            }
        } else if (state == OpenLayers.State.DELETE) {
            switch (this.state) {
                case OpenLayers.State.INSERT:
                    // the feature should be destroyed
                    break;
                case OpenLayers.State.DELETE:
                    break;
                case OpenLayers.State.UNKNOWN:
                case OpenLayers.State.UPDATE:
                    this.state = state;
                    break;
            }
        } else if (state == OpenLayers.State.UNKNOWN) {
            this.state = state;
        }
    },

    destroy: function() {

    },

    CLASS_NAME: "OpenLayers.Feature.Vector"
});

// styles for feature rendering
OpenLayers.Feature.Vector.style = {
    'default': {
        fillColor: "#ee9900",
        fillOpacity: 0.4,
        hoverFillColor: "white",
        hoverFillOpacity: 0.8,
        strokeColor: "#ee9900",
        strokeOpacity: 1,
        strokeWidth: 1,
        hoverStrokeColor: "red",
        hoverStrokeOpacity: 1,
        hoverStrokeWidth: 0.2,
        pointRadius: 6,
        hoverPointRadius: 1,
        hoverPointUnit: "%",
        pointerEvents: "visiblePainted"
    },
    'select': {
        fillColor: "blue",
        fillOpacity: 0.4,
        hoverFillColor: "white",
        hoverFillOpacity: 0.8,
        strokeColor: "blue",
        strokeOpacity: 1,
        strokeWidth: 2,
        hoverStrokeColor: "red",
        hoverStrokeOpacity: 1,
        hoverStrokeWidth: 0.2,
        pointRadius: 6,
        hoverPointRadius: 1,
        hoverPointUnit: "%",
        pointerEvents: "visiblePainted"
    },
    'temporary': {
        fillColor: "yellow",
        fillOpacity: 0.2,
        hoverFillColor: "white",
        hoverFillOpacity: 0.8,
        strokeColor: "yellow",
        strokeOpacity: 1,
        strokeWidth: 4,
        hoverStrokeColor: "red",
        hoverStrokeOpacity: 1,
        hoverStrokeWidth: 0.2,
        pointRadius: 6,
        hoverPointRadius: 1,
        hoverPointUnit: "%",
        pointerEvents: "visiblePainted"
    }
};
<commit_msg>#605 "OpenLayers.Feature.Vector: destroy() is defined twice" by fredj, patch by euzuro. thx euz, fredj.<commit_after>/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
 * for the full text of the license. */

// TRASH THIS
OpenLayers.State = {
    /** states */
    UNKNOWN: 'Unknown',
    INSERT: 'Insert',
    UPDATE: 'Update',
    DELETE: 'Delete'
}

/**
 * @class
 *
 * @requires OpenLayers/Feature.js
 * @requires OpenLayers/Util.js
 */
OpenLayers.Feature.Vector = OpenLayers.Class.create();
OpenLayers.Feature.Vector.prototype =
  OpenLayers.Class.inherit( OpenLayers.Feature, {

    /** @type String */
    fid: null,

    /** @type OpenLayers.Geometry */
    geometry:null,

    /** @type array */
    attributes: {},

    /** @type strinng */
    state: null,

    /** @type Object */
    style: null,

    /**
     * Create a vector feature.
     * @constructor
     *
     * @param {OpenLayers.Geometry} geometry
     * @param {Object} data
     */
    initialize: function(geometry, data, style) {
        OpenLayers.Feature.prototype.initialize.apply(this, [null, null, data]);
        this.lonlat = null;
        this.setGeometry(geometry);
        this.state = null;
        if (data) {
            OpenLayers.Util.extend(this.attributes, data);
        }
        this.style = style ? style : null;
    },

    /**
     *
     */
    destroy: function() {
        this.geometry = null;
        OpenLayers.Feature.prototype.destroy.apply(this, arguments);
    },

   /**
    * @returns An exact clone of this OpenLayers.Feature
    * @type OpenLayers.Feature
    */
    clone: function (obj) {
        if (obj == null) {
            obj = new OpenLayers.Feature(null, this.geometry.clone(), this.data);
        }

        // catch any randomly tagged-on properties
        OpenLayers.Util.applyDefaults(obj, this);

        return obj;
    },

    /**
     * HACK - we need to rewrite this for non-point geometry
     * @returns null - we need to rewrite this for non-point geometry
     * @type Boolean
     */
    onScreen:function() {
        return null;
    },

    /**
     *
     * HACK - we need to decide if all vector features should be able to
     * create markers
     *
     * @returns null
     *
     * @type OpenLayers.Marker
     */
    createMarker: function() {
        return null;
    },

    /**
     * HACK - we need to decide if all vector features should be able to
     * delete markers
     *
     * If user overrides the createMarker() function, s/he should be able
     *   to also specify an alternative function for destroying it
     */
    destroyMarker: function() {
        // pass
    },

    /**
     * HACK - we need to decide if all vector features should be able to
     * create popups
     *
     * @returns null
     */
    createPopup: function() {
        return null;
    },

    /**
     * Set a feature id to the feature
     *
     * @param {String} feature id to set
     */
    setFid: function(fid) {
        this.fid = fid;
    },

    /**
     * Set a geometry to the feature
     *
     * @param {OpenLayers.Geometry} geometry to set
     * @param {Boolean} recurse Recursively set feature (for components)
     */
    setGeometry: function(geometry, recurse) {
        if(geometry) {
            this.geometry = geometry;
            this.geometry.feature = this;
            if (recurse != false) {
                this._setGeometryFeatureReference(this.geometry, this);
            }
        }
    },

    /**
     * Sets recursively the reference to the feature in the geometry
     *
     * @param {OpenLayers.Geometry}
     * @param {OpenLayers.Feature}
     */
    _setGeometryFeatureReference: function(geometry, feature) {
        geometry.feature = feature;
        if (geometry.components) {
            for (var i = 0; i < geometry.components.length; i++) {
                this._setGeometryFeatureReference(geometry.components[i], feature);
            }
        }
    },

    /**
     * Adds attributes an attributes object to the feature.
     * (should not be in geometry but in feature class)
     *
     * @param {Attributes} attributes
     */
    setAttributes: function(attributes) {
        this.attributes=attributes;
    },

    /**
     * @param {OpenLayers.LonLat} lonlat
     * @param {float} toleranceLon Optional tolerance in Geometric Coords
     * @param {float} toleranceLat Optional tolerance in Geographic Coords
     *
     * @returns Whether or not the feature is at the specified location
     * @type Boolean
     */
    atPoint: function(lonlat, toleranceLon, toleranceLat) {
        var atPoint = false;
        if(this.geometry) {
            atPoint = this.geometry.atPoint(lonlat, toleranceLon,
                                                    toleranceLat);
        }
        return atPoint;
    },

    /**
     *
     * HACK - we need to decide if all vector features should be able to
     * delete popups
     */
    destroyPopup: function() {
        // pass
    },

    /**
     * Sets the new state
     * @param {String} state
     */
    toState: function(state) {
        if (state == OpenLayers.State.UPDATE) {
            switch (this.state) {
                case OpenLayers.State.UNKNOWN:
                case OpenLayers.State.DELETE:
                    this.state = state;
                    break;
                case OpenLayers.State.UPDATE:
                case OpenLayers.State.INSERT:
                    break;
            }
        } else if (state == OpenLayers.State.INSERT) {
            switch (this.state) {
                case OpenLayers.State.UNKNOWN:
                    break;
                default:
                    this.state = state;
                    break;
            }
        } else if (state == OpenLayers.State.DELETE) {
            switch (this.state) {
                case OpenLayers.State.INSERT:
                    // the feature should be destroyed
                    break;
                case OpenLayers.State.DELETE:
                    break;
                case OpenLayers.State.UNKNOWN:
                case OpenLayers.State.UPDATE:
                    this.state = state;
                    break;
            }
        } else if (state == OpenLayers.State.UNKNOWN) {
            this.state = state;
        }
    },

    CLASS_NAME: "OpenLayers.Feature.Vector"
});

// styles for feature rendering
OpenLayers.Feature.Vector.style = {
    'default': {
        fillColor: "#ee9900",
        fillOpacity: 0.4,
        hoverFillColor: "white",
        hoverFillOpacity: 0.8,
        strokeColor: "#ee9900",
        strokeOpacity: 1,
        strokeWidth: 1,
        hoverStrokeColor: "red",
        hoverStrokeOpacity: 1,
        hoverStrokeWidth: 0.2,
        pointRadius: 6,
        hoverPointRadius: 1,
        hoverPointUnit: "%",
        pointerEvents: "visiblePainted"
    },
    'select': {
        fillColor: "blue",
        fillOpacity: 0.4,
        hoverFillColor: "white",
        hoverFillOpacity: 0.8,
        strokeColor: "blue",
        strokeOpacity: 1,
        strokeWidth: 2,
        hoverStrokeColor: "red",
        hoverStrokeOpacity: 1,
        hoverStrokeWidth: 0.2,
        pointRadius: 6,
        hoverPointRadius: 1,
        hoverPointUnit: "%",
        pointerEvents: "visiblePainted"
    },
    'temporary': {
        fillColor: "yellow",
        fillOpacity: 0.2,
        hoverFillColor: "white",
        hoverFillOpacity: 0.8,
        strokeColor: "yellow",
        strokeOpacity: 1,
        strokeWidth: 4,
        hoverStrokeColor: "red",
        hoverStrokeOpacity: 1,
        hoverStrokeWidth: 0.2,
        pointRadius: 6,
        hoverPointRadius: 1,
        hoverPointUnit: "%",
        pointerEvents: "visiblePainted"
    }
};
<|endoftext|>


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

var instances = {};

function where(fn)
{
    var result = [];

    for (var n in this)
    {
        var item = this[n];

        if (fn(item))
            result.push(item);
    }

    return result;
}

function getByName(name)
{
    for (var n in this)
    {
        var item = this[n];

        if (item.name == name)
            return item;
    }

    return null;
}

function getById(id)
{
    for (var n in this)
    {
        var item = this[n];

        if (item.id == id)
            return item;
    }

    return null;
}

function getMaxId()
{
    var maxid = 0;

    for (var n in this)
    {
        var item = this[n];

        if (item.id > maxid)
            maxid = item.id;
    }

    return maxid;
}

function getInstances()
{
    return instances[this.name];
}

function addInstance(data)
{
    var newinstance = {};

    for (var n in this.properties)
        newinstance[n.name] = data[n.name];

    newinstance.id = this.instances().maxId() + 1;
    this.instances().push(newinstance);

    return newinstance;
}

function removeInstance(id)
{
    var instances = this.instances();

    for (var n in instances)
        if (instances[n].id == id)
        {
            var instance = instances[n];
            instances.splice(n,1);
            return instance;
        }

    return null;
}

function loadInstances(filename)
{
    var data = JSON.parse(fs.readFileSync(filename).toString());

    data.id = getById;
    data.name = getByName;
    data.where = where;
    data.maxId = getMaxId;

    instances[this.name] = data;
}

function loadModelInstances(dirname)
{
    this.entities.forEach(function(entity)
    {
        entity.loadInstances(path.join(dirname, entity.setName + '.json'));
    });
}

function enhanceModel(model)
{
    model.loadInstances = loadModelInstances;

    for (var n in model)
    {
        var item = model[n];

        if (Array.isArray(item))
        {
            item.name = getByName;
            item.id = getById;
            item.where = where;

            if (n == 'entities')
                for (var m in item)
                {
                    var entity = item[m];
                    entity.loadInstances = loadInstances;
                    entity.instances = getInstances;
                    entity.addInstance = addInstance;
                    entity.removeInstance = removeInstance;
                }
        }
    }
}

exports.loadModel = function(filename)
{
    var model = JSON.parse(fs.readFileSync(filename).toString());
    enhanceModel(model);
    return model;
}

<commit_msg>path.existsSync in model loadInstances<commit_after>
var fs = require('fs'),
    path = require('path');

var instances = {};

function where(fn)
{
    var result = [];

    for (var n in this)
    {
        var item = this[n];

        if (fn(item))
            result.push(item);
    }

    return result;
}

function getByName(name)
{
    for (var n in this)
    {
        var item = this[n];

        if (item.name == name)
            return item;
    }

    return null;
}

function getById(id)
{
    for (var n in this)
    {
        var item = this[n];

        if (item.id == id)
            return item;
    }

    return null;
}

function getMaxId()
{
    var maxid = 0;

    for (var n in this)
    {
        var item = this[n];

        if (item.id > maxid)
            maxid = item.id;
    }

    return maxid;
}

function getInstances()
{
    return instances[this.name];
}

function addInstance(data)
{
    var newinstance = {};

    for (var n in this.properties)
        newinstance[n.name] = data[n.name];

    newinstance.id = this.instances().maxId() + 1;
    this.instances().push(newinstance);

    return newinstance;
}

function removeInstance(id)
{
    var instances = this.instances();

    for (var n in instances)
        if (instances[n].id == id)
        {
            var instance = instances[n];
            instances.splice(n,1);
            return instance;
        }

    return null;
}

function loadInstances(filename)
{
    var data = JSON.parse(fs.readFileSync(filename).toString());

    data.id = getById;
    data.name = getByName;
    data.where = where;
    data.maxId = getMaxId;

    instances[this.name] = data;
}

function loadModelInstances(dirname)
{
    this.entities.forEach(function(entity)
    {
        var filename = path.join(dirname, entity.setName + '.json');

        if (path.existsSync(filename))
            entity.loadInstances(filename);
    });
}

function enhanceModel(model)
{
    model.loadInstances = loadModelInstances;

    for (var n in model)
    {
        var item = model[n];

        if (Array.isArray(item))
        {
            item.name = getByName;
            item.id = getById;
            item.where = where;

            if (n == 'entities')
                for (var m in item)
                {
                    var entity = item[m];
                    entity.loadInstances = loadInstances;
                    entity.instances = getInstances;
                    entity.addInstance = addInstance;
                    entity.removeInstance = removeInstance;
                }
        }
    }
}

exports.loadModel = function(filename)
{
    var model = JSON.parse(fs.readFileSync(filename).toString());
    enhanceModel(model);
    return model;
}

<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'

const pkg = require('./package.json')
const MongoClient = require('mongodb').MongoClient
const program = require('commander')
const insert = require('./lib/insert')
const makeOptions = require('./lib/makeOptions')
const readline = require('readline')

program
  .version(pkg.version)
  .description(pkg.description)
  .option('-H, --host <address>', 'set database host (localhost)', 'localhost')
  .option('-P, --port <number>', 'set database port (27017)', 27017)
  .option('-d, --db <name>', 'set database name (logs)', 'logs')
  .option('-c, --collection <name>', 'set database collection (logs)', 'logs')
  .option('-u, --user <username>', 'set database username', undefined)
  .option('-p, --pass <password>', 'set database password', undefined)
  .option('-q, --quiet', 'suppress stdin to stdout output (false)', false)
  .option('--show-insert-errors', 'show errors from inserting documents into mongodb (true)', true)
  .parse(process.argv)

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: !program.quiet
})

MongoClient.connect(makeOptions(program), function onConnection (e, db) {
  if (e) {
    throw e
  }

  process.on('SIGINT', function () {
    db.close(function () {
      process.exit()
    })
  })

  rl.on('line', insert.bind({
    collection: db.collection(program.collection),
    program: program
  }))
})
<commit_msg>Remove undefined as a default var in commander under user and pass<commit_after>#!/usr/bin/env node
'use strict'

const pkg = require('./package.json')
const MongoClient = require('mongodb').MongoClient
const program = require('commander')
const insert = require('./lib/insert')
const makeOptions = require('./lib/makeOptions')
const readline = require('readline')

program
  .version(pkg.version)
  .description(pkg.description)
  .option('-H, --host <address>', 'set database host (localhost)', 'localhost')
  .option('-P, --port <number>', 'set database port (27017)', 27017)
  .option('-d, --db <name>', 'set database name (logs)', 'logs')
  .option('-c, --collection <name>', 'set database collection (logs)', 'logs')
  .option('-u, --user <username>', 'set database username')
  .option('-p, --pass <password>', 'set database password')
  .option('-q, --quiet', 'suppress stdin to stdout output (false)', false)
  .option('--show-insert-errors', 'show errors from inserting documents into mongodb (true)', true)
  .parse(process.argv)

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: !program.quiet
})

MongoClient.connect(makeOptions(program), function onConnection (e, db) {
  if (e) {
    throw e
  }

  process.on('SIGINT', function () {
    db.close(function () {
      process.exit()
    })
  })

  rl.on('line', insert.bind({
    collection: db.collection(program.collection),
    program: program
  }))
})
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');

function Command() {
  this.actions = [];
  this.token;

  mixin(this, EventEmitter.prototype, false);
}

Command.prototype.setToken = function (token) {
  this.token = token;
}

Command.prototype._checkToken = function(data) {
  if(!this.token) {
    console.warn('Without a validation token anyone can execute your command.');
  } else {
    if(data.token !== this.token) throw 'Invalid token';
  }
}

Command.prototype._findAction = function (text) {
  var action;

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

    console.log(action, action.pattern.test(text));
    if(action.pattern.test(text)) {
      return action;
    }
  }
};

Command.prototype.action = function (pattern, callback) {
  if(typeof pattern !== RegExp) pattern = new RegExp(pattern);
  this.actions.push({pattern: pattern, callback: callback});
};

Command.prototype.execute = function (data) {
  try {
    this._checkToken(data);

    var text = data.text.trim();
    var action = this._findAction(text);

    if(action) {
      this.emit('success', action.callback(data, action.pattern.exec(text)));
    } else {
      this.emit('error', 'No matching action found to handle ' + text);
    }
  } catch(e) {
    this.emit('error', e);
  }
};

exports.Command = Command;<commit_msg>Remove console.<commit_after>'use strict';

var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');

function Command() {
  this.actions = [];
  this.token;

  mixin(this, EventEmitter.prototype, false);
}

Command.prototype.setToken = function (token) {
  this.token = token;
}

Command.prototype._checkToken = function(data) {
  if(!this.token) {
    console.warn('Without a validation token anyone can execute your command.');
  } else {
    if(data.token !== this.token) throw 'Invalid token';
  }
}

Command.prototype._findAction = function (text) {
  var action;

  for(var i = 0; i < this.actions.length; i++) {
    action = this.actions[i];
    if(action.pattern.test(text)) {
      return action;
    }
  }
};

Command.prototype.action = function (pattern, callback) {
  if(typeof pattern !== RegExp) pattern = new RegExp(pattern);
  this.actions.push({pattern: pattern, callback: callback});
};

Command.prototype.execute = function (data) {
  try {
    this._checkToken(data);

    var text = data.text.trim();
    var action = this._findAction(text);

    if(action) {
      this.emit('success', action.callback(data, action.pattern.exec(text)));
    } else {
      this.emit('error', 'No matching action found to handle ' + text);
    }
  } catch(e) {
    this.emit('error', e);
  }
};

exports.Command = Command;<|endoftext|>


<commit_before>var request = require('request');
var async = require('async');

function SuperMaster(masters){
    this.cache = {};
    this.masters = masters;

    // Initialize cache with empty list for each master
    masters.forEach((master) => { this.cache[master.name] = [] });
}

SuperMaster.prototype.getJobs = function(callback){
  var self = this;

  async.map(self.masters, (master, callback) => {
    // Issue request against each master
    request.get(master.endpoint + "/api/json", (err, res, body) => {
      var jobs;
      if(err || res.statusCode != 200 ){
        if(res && res.statusCode != 200)
          err = new Error(res.statusMessage);
        console.warn("Request to", master.name, "failed.\nMessage:", err.message);
        jobs = self.cache[master.name]; // Set jobs from cache

        jobs.forEach((job) => {
          job.cached = true;
        });
      }else{
        jobs = JSON.parse(body).jobs;

        jobs.forEach((job) => {
          job.master = master.name;
          job.icon = master.icon || "";
        });

        // Update cached job list for master
        self.cache[master.name] = jobs;
      }

      callback(null, jobs);
    });

  }, (err, jobs) => {
    callback(err, [].concat.apply([], jobs) || []);
  });
}

module.exports = SuperMaster;
<commit_msg>Add timeout for requests to jenkins masters<commit_after>var request = require('request').defaults({ timeout: 1000 });
var async = require('async');

function SuperMaster(masters){
    this.cache = {};
    this.masters = masters;

    // Initialize cache with empty list for each master
    masters.forEach((master) => { this.cache[master.name] = [] });
}

SuperMaster.prototype.getJobs = function(callback){
  var self = this;

  async.map(self.masters, (master, callback) => {
    // Issue request against each master
    request.get(master.endpoint + "/api/json", (err, res, body) => {
      var jobs;
      if(err || res.statusCode != 200 ){
        if(res && res.statusCode != 200)
          err = new Error(res.statusMessage);

        console.warn("Request to", master.name, "failed.\nMessage:", err.message);
        jobs = self.cache[master.name]; // Set jobs from cache

        jobs.forEach((job) => {
          job.cached = true;
        });
      }else{
        jobs = JSON.parse(body).jobs;

        jobs.forEach((job) => {
          job.master = master.name;
          job.icon = master.icon || "";
        });

        // Update cached job list for master
        self.cache[master.name] = jobs;
      }

      callback(null, jobs);
    });

  }, (err, jobs) => {
    callback(err, [].concat.apply([], jobs) || []);
  });
}

module.exports = SuperMaster;
<|endoftext|>


<commit_before>'use strict';

var FS = require('fs');
var yaml = require('js-yaml');

var EXTEND = require('whet.extend');

/**
 * Read and/or extend/replace default config file,
 * prepare and optimize plugins array.
 *
 * @param {Object} [config] input config
 * @return {Object} output config
 */
module.exports = function(config) {

    var defaults;
    config = config || {};

    if (config.full) {
        defaults = config;

        if (Array.isArray(defaults.plugins)) {
            defaults.plugins = preparePluginsArray(defaults.plugins);
        }
    } else {
        defaults = EXTEND({}, yaml.safeLoad(FS.readFileSync(__dirname + '/../../.svgo.yml', 'utf8')));
        defaults.plugins = preparePluginsArray(defaults.plugins);
        defaults = extendConfig(defaults, config);
    }

    if ('floatPrecision' in config && Array.isArray(defaults.plugins)) {
        defaults.plugins.forEach(function(plugin) {
            if (plugin.params && ('floatPrecision' in plugin.params)) {
                // Don't touch default plugin params
                plugin.params = EXTEND({}, plugin.params, { floatPrecision: config.floatPrecision });
            }
        });
    }

    if (Array.isArray(defaults.plugins)) {
        defaults.plugins = optimizePluginsArray(defaults.plugins);
    }

    return defaults;

};

/**
 * Require() all plugins in array.
 *
 * @param {Array} plugins input plugins array
 * @return {Array} input plugins array of arrays
 */
function preparePluginsArray(plugins) {

    var plugin,
        key;

    return plugins.map(function(item) {

        // {}
        if (typeof item === 'object') {

            key = Object.keys(item)[0];

            // custom
            if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
                plugin = setupCustomPlugin(key, item[key]);

            } else {

              plugin = EXTEND({}, require('../../plugins/' + key));

              // name: {}
              if (typeof item[key] === 'object') {
                  plugin.params = EXTEND({}, plugin.params || {}, item[key]);
                  plugin.active = true;

              // name: false
              } else if (item[key] === false) {
                 plugin.active = false;

              // name: true
              } else if (item[key] === true) {
                 plugin.active = true;
              }

              plugin.name = key;
            }

        // name
        } else {

            plugin = EXTEND({}, require('../../plugins/' + item));
            plugin.name = item;

        }

        return plugin;

    });

}

/**
 * Extend plugins with the custom config object.
 *
 * @param {Array} plugins input plugins
 * @param {Object} config config
 * @return {Array} output plugins
 */
function extendConfig(defaults, config) {

    var key;

    // plugins
    if (config.plugins) {

        config.plugins.forEach(function(item) {

            // {}
            if (typeof item === 'object') {

                key = Object.keys(item)[0];

                // custom
                if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
                    defaults.plugins.push(setupCustomPlugin(key, item[key]));

                } else {
                    defaults.plugins.forEach(function(plugin) {

                        if (plugin.name === key) {
                            // name: {}
                            if (typeof item[key] === 'object') {
                                plugin.params = EXTEND({}, plugin.params || {}, item[key]);
                                plugin.active = true;

                            // name: false
                            } else if (item[key] === false) {
                               plugin.active = false;

                            // name: true
                            } else if (item[key] === true) {
                               plugin.active = true;
                            }
                        }
                    });
                }

            }

        });

    }

    defaults.multipass = config.multipass;

    // svg2js
    if (config.svg2js) {
        defaults.svg2js = config.svg2js;
    }

    // js2svg
    if (config.js2svg) {
        defaults.js2svg = config.js2svg;
    }

    return defaults;

}

/**
 * Setup and enable a custom plugin
 *
 * @param {String} plugin name
 * @param {Object} custom plugin
 * @return {Array} enabled plugin
 */
function setupCustomPlugin(name, plugin) {
    plugin.active = true;
    plugin.params = EXTEND({}, plugin.params || {});
    plugin.name = name;

    return plugin;
}

/**
 * Try to group sequential elements of plugins array.
 *
 * @param {Object} plugins input plugins
 * @return {Array} output plugins
 */
function optimizePluginsArray(plugins) {

    var prev;

    return plugins.reduce(function(plugins, item) {
        if (prev && item.type == prev[0].type) {
            prev.push(item);
        } else {
            plugins.push(prev = [item]);
        }
        return plugins;
    }, []);

}
<commit_msg>SystemJS meta information.<commit_after>'use strict';

// Plugins meta for SystemJS;
"deps ../plugins/removeDoctype";

var FS = require('fs');
var yaml = require('js-yaml');

var EXTEND = require('whet.extend');

/**
 * Read and/or extend/replace default config file,
 * prepare and optimize plugins array.
 *
 * @param {Object} [config] input config
 * @return {Object} output config
 */
module.exports = function(config) {

    var defaults;
    config = config || {};

    if (config.full) {
        defaults = config;

        if (Array.isArray(defaults.plugins)) {
            defaults.plugins = preparePluginsArray(defaults.plugins);
        }
    } else {
        defaults = EXTEND({}, yaml.safeLoad(FS.readFileSync(__dirname + '/../../.svgo.yml', 'utf8')));
        defaults.plugins = preparePluginsArray(defaults.plugins);
        defaults = extendConfig(defaults, config);
    }

    if ('floatPrecision' in config && Array.isArray(defaults.plugins)) {
        defaults.plugins.forEach(function(plugin) {
            if (plugin.params && ('floatPrecision' in plugin.params)) {
                // Don't touch default plugin params
                plugin.params = EXTEND({}, plugin.params, { floatPrecision: config.floatPrecision });
            }
        });
    }

    if (Array.isArray(defaults.plugins)) {
        defaults.plugins = optimizePluginsArray(defaults.plugins);
    }

    return defaults;

};

/**
 * Require() all plugins in array.
 *
 * @param {Array} plugins input plugins array
 * @return {Array} input plugins array of arrays
 */
function preparePluginsArray(plugins) {

    var plugin,
        key;

    return plugins.map(function(item) {

        // {}
        if (typeof item === 'object') {

            key = Object.keys(item)[0];

            // custom
            if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
                plugin = setupCustomPlugin(key, item[key]);

            } else {

              plugin = EXTEND({}, require('../../plugins/' + key));

              // name: {}
              if (typeof item[key] === 'object') {
                  plugin.params = EXTEND({}, plugin.params || {}, item[key]);
                  plugin.active = true;

              // name: false
              } else if (item[key] === false) {
                 plugin.active = false;

              // name: true
              } else if (item[key] === true) {
                 plugin.active = true;
              }

              plugin.name = key;
            }

        // name
        } else {

            plugin = EXTEND({}, require('../../plugins/' + item));
            plugin.name = item;

        }

        return plugin;

    });

}

/**
 * Extend plugins with the custom config object.
 *
 * @param {Array} plugins input plugins
 * @param {Object} config config
 * @return {Array} output plugins
 */
function extendConfig(defaults, config) {

    var key;

    // plugins
    if (config.plugins) {

        config.plugins.forEach(function(item) {

            // {}
            if (typeof item === 'object') {

                key = Object.keys(item)[0];

                // custom
                if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
                    defaults.plugins.push(setupCustomPlugin(key, item[key]));

                } else {
                    defaults.plugins.forEach(function(plugin) {

                        if (plugin.name === key) {
                            // name: {}
                            if (typeof item[key] === 'object') {
                                plugin.params = EXTEND({}, plugin.params || {}, item[key]);
                                plugin.active = true;

                            // name: false
                            } else if (item[key] === false) {
                               plugin.active = false;

                            // name: true
                            } else if (item[key] === true) {
                               plugin.active = true;
                            }
                        }
                    });
                }

            }

        });

    }

    defaults.multipass = config.multipass;

    // svg2js
    if (config.svg2js) {
        defaults.svg2js = config.svg2js;
    }

    // js2svg
    if (config.js2svg) {
        defaults.js2svg = config.js2svg;
    }

    return defaults;

}

/**
 * Setup and enable a custom plugin
 *
 * @param {String} plugin name
 * @param {Object} custom plugin
 * @return {Array} enabled plugin
 */
function setupCustomPlugin(name, plugin) {
    plugin.active = true;
    plugin.params = EXTEND({}, plugin.params || {});
    plugin.name = name;

    return plugin;
}

/**
 * Try to group sequential elements of plugins array.
 *
 * @param {Object} plugins input plugins
 * @return {Array} output plugins
 */
function optimizePluginsArray(plugins) {

    var prev;

    return plugins.reduce(function(plugins, item) {
        if (prev && item.type == prev[0].type) {
            prev.push(item);
        } else {
            plugins.push(prev = [item]);
        }
        return plugins;
    }, []);

}
<|endoftext|>