<commit_before>/*
Copyright 2016 First People's Cultural Council

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.
*/
import React, { Component, PropTypes } from 'react'
// import classNames from 'classnames'
import selectn from 'selectn'

// REDUX
import { connect } from 'react-redux'
// REDUX: actions/dispatch/func
import { deleteContributor, fetchContributors } from 'providers/redux/reducers/fvContributor'
import { pushWindowPath } from 'providers/redux/reducers/windowPath'

import NavigationHelpers from 'common/NavigationHelpers'

import ProviderHelpers from 'common/ProviderHelpers'
import DocumentListView from 'views/components/Document/DocumentListView'
import { STATE_UNAVAILABLE } from 'common/Constants'
import ContributorDelete from 'views/components/Confirmation'

import ContributorsSelected from './ContributorsSelected'
import Checkbox from 'views/components/Form/Common/Checkbox'

import '!style-loader!css-loader!./Contributors.css'

let contributorsPath = undefined
let _computeContributors = undefined
let _computeDialect2 = undefined
const { array, func, number, object, string } = PropTypes

const iconUnsorted = (
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
    <path d="M0 0h24v24H0z" fill="none" />
    <path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z" />
  </svg>
)
const iconSortAsc = (
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
    <path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </svg>
)
const iconSortDesc = (
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
    <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </svg>
)
export class Contributors extends Component {
  static propTypes = {
    DEFAULT_PAGE: number,
    DEFAULT_PAGE_SIZE: number,
    DEFAULT_SORT_COL: string,
    DEFAULT_SORT_TYPE: string,
    editUrl: string,
    copy: object,
    // REDUX: reducers/state
    routeParams: object.isRequired,
    computeContributors: object.isRequired,
    computeDialect: object.isRequired,
    computeDialect2: object.isRequired,
    search: object.isRequired,
    splitWindowPath: array.isRequired,
    windowPath: string.isRequired,
    // REDUX: actions/dispatch/func
    fetchContributors: func.isRequired,
    createContributor: func.isRequired,
    fetchDialect: func.isRequired,
    pushWindowPath: func.isRequired,
  }

  static defaultProps = {
    DEFAULT_PAGE: 1,
    DEFAULT_PAGE_SIZE: 100,
    DEFAULT_LANGUAGE: 'english',
    DEFAULT_SORT_COL: 'dc:title',
    DEFAULT_SORT_TYPE: 'asc',
  }
  state = {
    componentState: STATE_UNAVAILABLE,
    copy: {
      actions: {
        th: '',
        edit: '',
        delete: '',
      },
      batch: {
        select: '',
        deselect: '',
      },
      title: {
        th: '',
      },
      description: {
        th: '',
      },
    },
    deletedUids: [],
    selected: [],
  }

  //   fetchData(newProps) {
  //     const dialectPath = ProviderHelpers.getDialectPathFromURLArray(newProps.splitWindowPath)
  //     this.setState({ dialectPath: dialectPath })

  //     if (!this.props.computeDialect.success) {
  //       newProps.fetchDialect('/' + dialectPath)
  //     }
  //   }

  async componentDidMount() {
    const copy = this.props.copy
      ? this.props.copy
      : await import(/* webpackChunkName: "ContributorsInternationalization" */ './internationalization').then(
          (_copy) => {
            return _copy.default
          }
        )

    this._getData({ copy })
  }
  async componentDidUpdate(prevProps) {
    const { computeContributors, computeDialect2, routeParams } = this.props

    if (this._paginationHasUpdated(prevProps)) {
      await this._getData()
    }
    _computeContributors = ProviderHelpers.getEntry(computeContributors, contributorsPath)
    _computeDialect2 = ProviderHelpers.getEntry(computeDialect2, routeParams.dialect_path)
  }

  render() {
    const { routeParams } = this.props
    const { pageSize, page } = routeParams

    return (
      <DocumentListView
        cssModifier="DictionaryList--contributors"
        sortInfo={this.sortInfo.uiSortOrder} // TODO: NOT USED?
        className="browseDataGrid"
        columns={this._getColumns()}
        data={this._filterDeletedData()}
        dialect={selectn('response', _computeDialect2)}
        gridCols={4}
        gridListView={false}
        page={Number(page)}
        pageSize={Number(pageSize)}
        refetcher={this.handleRefetch}
        type="FVContributor"
      />
    )
  }
  sortInfo = {
    uiSortOrder: [],
    currentSortCols: this.props.DEFAULT_SORT_COL,
    currentSortType: this.props.DEFAULT_SORT_TYPE,
  }
  _getColumns = () => {
    const { copy } = this.state
    const { routeParams, editUrl } = this.props
    const { theme, dialect_path } = routeParams

    return [
      {
        name: 'batch',
        title: () => {
          const allItems = this._getAllItems()
          // All items selected, show deselect
          if (allItems.length === this.state.selected.length && allItems.length !== 0) {
            return (
              <button className="_btn _btn--compact" type="button" onClick={this._selectNone}>
                {copy.batch.deselect}
              </button>
            )
          }
          // show select
          return (
            <button className="_btn _btn--compact" type="button" onClick={this._selectAll}>
              {copy.batch.select}
            </button>
          )
        },
        footer: () => {
          return {
            colSpan: 4,
            element: (
              <ContributorsSelected
                confirmationAction={this._deleteSelected}
                selected={this.state.selected}
                copy={copy.contributorsSelected}
              />
            ),
          }
        },
        render: (value, data) => {
          const uid = data.uid
          const isSelected = this._isSelected(uid)
          return (
            <Checkbox
              selected={isSelected}
              id={uid}
              value={uid}
              name="batch"
              labelText=""
              handleChange={this._toggleCheckbox}
            />
          )
        },
      },
      {
        name: 'title',
        title: () => {
          return (
            <button
              type="button"
              className="Contributors__colSort"
              onClick={() => {
                this._sortCol({
                  sortBy: 'dc:title',
                })
              }}
            >
              {this._getIcon('dc:title')}
              {copy.title.th}
            </button>
          )
        },
        render: (value, data) => {
          const uid = data.uid
          const url = editUrl ? `${editUrl}/${uid}` : `/${theme}${dialect_path}/contributor/${uid}`

          return (
             {
                e.preventDefault()
                NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
              }}
            >
              {value}

          )
        },
      },
      {
        name: 'dc:description',
        title: () => {
          return (
            <button
              className="Contributors__colSort"
              onClick={() => {
                this._sortCol({
                  sortBy: 'dc:description',
                })
              }}
            >
              {this._getIcon('dc:description')}
              {copy.description.th}
            </button>
          )
        },
        render: (v, data /*, cellProps*/) => {
          const bio = selectn('properties.dc:description', data) || '-'
          return

        },
      },
      {
        name: 'actions',
        title: copy.actions.th,
        render: (v, data) => {
          const uid = data.uid
          const url = editUrl ? `${editUrl}/${uid}` : `/${theme}${dialect_path}/edit/contributor/${uid}`

          return (

                <ContributorDelete
                  reverse
                  compact
                  copy={{
                    isConfirmOrDenyTitle: copy.isConfirmOrDenyTitle,
                    btnInitiate: copy.btnInitiate,
                    btnDeny: copy.btnDeny,
                    btnConfirm: copy.btnConfirm,
                  }}
                  confirmationAction={() => {
                    this._deleteItem(uid)
                  }}
                />

                 {
                    e.preventDefault()
                    NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
                  }}
                >
                  {copy.actions.edit}

          )
        },
      },
    ]
  }
  _deleteSelected = async () => {
    const { selected } = this.state
    this.setState(
      {
        deletedUids: [...this.state.deletedUids, ...selected],
      },
      () => {
        selected.forEach(async (uid) => {
          await this.props.deleteContributor(uid)
        })
        this.setState({
          selected: [],
        })
      }
    )
  }
  _deleteItem = async (uid) => {
    /* NOTE: save uid to state */
    this.setState(
      {
        deletedUids: [...this.state.deletedUids, uid],
      },
      () => {
        this.props.deleteContributor(uid)
        this._toggleCheckbox(false, uid)
      }
    )
  }

  _filterDeletedUids = () => {
    const { deletedUids } = this.state
    if (_computeContributors && _computeContributors.isFetching === false && _computeContributors.success) {
      const _entries = _computeContributors.response.entries
      const filtered = _entries.reduce((accumulator, entry) => {
        const isDeleted = deletedUids.find((uid) => {
          return uid === entry.uid
        })
        if (isDeleted === undefined) {
          return [...accumulator, entry]
        }
        return accumulator
      }, [])
      return filtered
    }
    return []
  }
  _filterDeletedData = () => {
    const { deletedUids } = this.state
    if (_computeContributors && _computeContributors.isFetching === false && _computeContributors.success) {
      const _entries = _computeContributors.response.entries
      const filtered = _entries.reduce((accumulator, entry) => {
        const isDeleted = deletedUids.find((uid) => {
          return uid === entry.uid
        })
        if (isDeleted === undefined) {
          return [...accumulator, entry]
        }
        return accumulator
      }, [])
      const filteredComputeContributors = Object.assign({}, _computeContributors)
      filteredComputeContributors.response.entries = filtered
      return filteredComputeContributors
    }
    return _computeContributors
  }
  _getIcon = (field) => {
    const { search } = this.props
    const { sortOrder, sortBy } = search

    if (sortBy === field) {
      return sortOrder === 'asc' ? iconSortAsc : iconSortDesc
    }
    return iconUnsorted
  }
  _getData = async (addToState) => {
    const { routeParams, search } = this.props
    const { pageSize, page } = routeParams
    const { sortBy, sortOrder } = search

    let currentAppliedFilter = '' // eslint-disable-line
    // if (filter.has('currentAppliedFilter')) {
    //   currentAppliedFilter = Object.values(filter.get('currentAppliedFilter').toJS()).join('')
    // }
    // Get contrinbutors
    contributorsPath = `${routeParams.dialect_path}/Contributors`
    await this.props.fetchContributors(
      contributorsPath,
      `${currentAppliedFilter}&currentPageIndex=${page -
        1}&pageSize=${pageSize}&sortOrder=${sortOrder}&sortBy=${sortBy}`
    )
    // NOTE: redux doesn't update on changes to deeply nested data, hence the manual re-render
    this.setState({
      rerender: Date.now(),
      ...addToState,
    })
  }
  handleRefetch = (componentProps, page, pageSize) => {
    const { routeParams } = this.props
    const { theme, dialect_path } = routeParams
    const url = `/${theme}${dialect_path}/contributors/${pageSize}/${page}${window.location.search}`
    NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
  }
  _paginationHasUpdated = (prevProps) => {
    const { routeParams, search } = this.props
    const { pageSize, page } = routeParams
    const { sortBy, sortOrder } = search

    const { routeParams: prevRouteParams, search: prevSearch } = prevProps
    const { pageSize: prevPageSize, page: prevPage } = prevRouteParams
    const { sortBy: prevSortBy, sortOrder: prevSortOrder } = prevSearch

    if (pageSize !== prevPageSize || page !== prevPage || sortBy !== prevSortBy || sortOrder !== prevSortOrder) {
      return true
    }
    return false
  }
  _getAllItems = () => {
    const filteredData = this._filterDeletedUids()
    const uids = filteredData.reduce((accumulator, item) => {
      return [...accumulator, item.uid]
    }, [])
    return uids
  }
  _selectAll = () => {
    const uids = this._getAllItems()

    this.setState({
      selected: uids,
    })
  }
  _selectNone = () => {
    this.setState({
      selected: [],
    })
  }
  _sortCol = (arg) => {
    const { routeParams, search } = this.props
    const { theme, dialect_path, pageSize } = routeParams
    const { sortOrder } = search

    const url = `/${theme}${dialect_path}/contributors/${pageSize}/1?sortBy=${arg.sortBy}&sortOrder=${
      sortOrder === 'asc' ? 'desc' : 'asc'
    }`
    NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
  }
  _isSelected = (uid) => {
    const exists = this.state.selected.find((selectedUid) => {
      return selectedUid === uid
    })
    return exists ? true : false
  }
  _toggleCheckbox = (checked, uid) => {
    let selected = [...this.state.selected]

    const exists = this._isSelected(uid)
    if (checked && !exists) {
      selected.push(uid)
    }
    // remove if exists
    if (!checked && exists) {
      selected = selected.filter((selectedUid) => {
        return selectedUid !== uid
      })
    }

    this.setState({
      selected,
    })
  }
}

// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvContributor, fvDialect, navigation, windowPath } = state

  const { computeContributors } = fvContributor
  const { computeDialect, computeDialect2 } = fvDialect
  const { splitWindowPath, _windowPath } = windowPath

  const { route } = navigation

  return {
    computeContributors,
    routeParams: route.routeParams,
    search: route.search,
    computeDialect,
    computeDialect2,
    splitWindowPath,
    windowPath: _windowPath,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  deleteContributor,
  fetchContributors,
  pushWindowPath,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Contributors)
<commit_msg>defaultProps fixes undef err, fn()s alphabetized<commit_after>/*
Copyright 2016 First People's Cultural Council

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.
*/
import React, { Component, PropTypes } from 'react'
// import classNames from 'classnames'
import selectn from 'selectn'

// REDUX
import { connect } from 'react-redux'
// REDUX: actions/dispatch/func
import { deleteContributor, fetchContributors } from 'providers/redux/reducers/fvContributor'
import { pushWindowPath } from 'providers/redux/reducers/windowPath'

import NavigationHelpers from 'common/NavigationHelpers'

import ProviderHelpers from 'common/ProviderHelpers'
import DocumentListView from 'views/components/Document/DocumentListView'
import { STATE_UNAVAILABLE } from 'common/Constants'
import ContributorDelete from 'views/components/Confirmation'

import ContributorsSelected from './ContributorsSelected'
import Checkbox from 'views/components/Form/Common/Checkbox'

import '!style-loader!css-loader!./Contributors.css'

let contributorsPath = undefined
let _computeContributors = undefined
let _computeDialect2 = undefined
const { array, func, number, object, string } = PropTypes

const iconUnsorted = (
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
    <path d="M0 0h24v24H0z" fill="none" />
    <path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z" />
  </svg>
)
const iconSortAsc = (
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
    <path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </svg>
)
const iconSortDesc = (
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
    <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" />
    <path d="M0 0h24v24H0z" fill="none" />
  </svg>
)
export class Contributors extends Component {
  static propTypes = {
    DEFAULT_PAGE: number,
    DEFAULT_PAGE_SIZE: number,
    DEFAULT_SORT_COL: string,
    DEFAULT_SORT_TYPE: string,
    editUrl: string,
    copy: object,
    // REDUX: reducers/state
    routeParams: object.isRequired,
    computeContributors: object.isRequired,
    computeDialect: object.isRequired,
    computeDialect2: object.isRequired,
    search: object.isRequired,
    splitWindowPath: array.isRequired,
    windowPath: string.isRequired,
    // REDUX: actions/dispatch/func
    fetchContributors: func.isRequired,
    createContributor: func.isRequired,
    fetchDialect: func.isRequired,
    pushWindowPath: func.isRequired,
  }

  static defaultProps = {
    DEFAULT_PAGE: 1,
    DEFAULT_PAGE_SIZE: 100,
    DEFAULT_LANGUAGE: 'english',
    DEFAULT_SORT_COL: 'dc:title',
    DEFAULT_SORT_TYPE: 'asc',
    fetchContributors: () => {},
    createContributor: () => {},
    fetchDialect: () => {},
    pushWindowPath: () => {},
  }
  state = {
    componentState: STATE_UNAVAILABLE,
    copy: {
      actions: {
        th: '',
        edit: '',
        delete: '',
      },
      batch: {
        select: '',
        deselect: '',
      },
      title: {
        th: '',
      },
      description: {
        th: '',
      },
    },
    deletedUids: [],
    selected: [],
  }

  async componentDidMount() {
    const copy = this.props.copy
      ? this.props.copy
      : await import(/* webpackChunkName: "ContributorsInternationalization" */ './internationalization').then(
          (_copy) => {
            return _copy.default
          }
        )

    await this._getData({ copy })
  }

  async componentDidUpdate(prevProps) {
    const { computeContributors, computeDialect2, routeParams } = this.props

    if (this._paginationHasUpdated(prevProps)) {
      await this._getData()
    }
    _computeContributors = ProviderHelpers.getEntry(computeContributors, contributorsPath)
    _computeDialect2 = ProviderHelpers.getEntry(computeDialect2, routeParams.dialect_path)
  }

  render() {
    const { routeParams } = this.props
    const { pageSize, page } = routeParams

    return (
      <DocumentListView
        cssModifier="DictionaryList--contributors"
        sortInfo={this.sortInfo.uiSortOrder} // TODO: NOT USED?
        className="browseDataGrid"
        columns={this._getColumns()}
        data={this._filterDeletedData()}
        dialect={selectn('response', _computeDialect2)}
        gridCols={4}
        gridListView={false}
        page={Number(page)}
        pageSize={Number(pageSize)}
        refetcher={this.handleRefetch}
        type="FVContributor"
      />
    )
  }

  handleRefetch = (componentProps, page, pageSize) => {
    const { routeParams } = this.props
    const { theme, dialect_path } = routeParams
    const url = `/${theme}${dialect_path}/contributors/${pageSize}/${page}${window.location.search}`
    NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
  }

  sortInfo = {
    uiSortOrder: [],
    currentSortCols: this.props.DEFAULT_SORT_COL,
    currentSortType: this.props.DEFAULT_SORT_TYPE,
  }

  _deleteItem = async (uid) => {
    /* NOTE: save uid to state */
    this.setState(
      {
        deletedUids: [...this.state.deletedUids, uid],
      },
      () => {
        this.props.deleteContributor(uid)
        this._toggleCheckbox(false, uid)
      }
    )
  }

  _deleteSelected = async () => {
    const { selected } = this.state
    this.setState(
      {
        deletedUids: [...this.state.deletedUids, ...selected],
      },
      () => {
        selected.forEach(async (uid) => {
          await this.props.deleteContributor(uid)
        })
        this.setState({
          selected: [],
        })
      }
    )
  }

  _filterDeletedData = () => {
    const { deletedUids } = this.state
    if (_computeContributors && _computeContributors.isFetching === false && _computeContributors.success) {
      const _entries = _computeContributors.response.entries
      const filtered = _entries.reduce((accumulator, entry) => {
        const isDeleted = deletedUids.find((uid) => {
          return uid === entry.uid
        })
        if (isDeleted === undefined) {
          return [...accumulator, entry]
        }
        return accumulator
      }, [])
      const filteredComputeContributors = Object.assign({}, _computeContributors)
      filteredComputeContributors.response.entries = filtered
      return filteredComputeContributors
    }
    return _computeContributors
  }

  _filterDeletedUids = () => {
    const { deletedUids } = this.state
    if (_computeContributors && _computeContributors.isFetching === false && _computeContributors.success) {
      const _entries = _computeContributors.response.entries
      const filtered = _entries.reduce((accumulator, entry) => {
        const isDeleted = deletedUids.find((uid) => {
          return uid === entry.uid
        })
        if (isDeleted === undefined) {
          return [...accumulator, entry]
        }
        return accumulator
      }, [])
      return filtered
    }
    return []
  }

  _getAllItems = () => {
    const filteredData = this._filterDeletedUids()
    const uids = filteredData.reduce((accumulator, item) => {
      return [...accumulator, item.uid]
    }, [])
    return uids
  }

  _getColumns = () => {
    const { copy } = this.state
    const { routeParams, editUrl } = this.props
    const { theme, dialect_path } = routeParams

    return [
      {
        name: 'batch',
        title: () => {
          const allItems = this._getAllItems()
          // All items selected, show deselect
          if (allItems.length === this.state.selected.length && allItems.length !== 0) {
            return (
              <button className="_btn _btn--compact" type="button" onClick={this._selectNone}>
                {copy.batch.deselect}
              </button>
            )
          }
          // show select
          return (
            <button className="_btn _btn--compact" type="button" onClick={this._selectAll}>
              {copy.batch.select}
            </button>
          )
        },
        footer: () => {
          return {
            colSpan: 4,
            element: (
              <ContributorsSelected
                confirmationAction={this._deleteSelected}
                selected={this.state.selected}
                copy={copy.itemsSelected}
              />
            ),
          }
        },
        render: (value, data) => {
          const uid = data.uid
          const isSelected = this._isSelected(uid)
          return (
            <Checkbox
              selected={isSelected}
              id={uid}
              value={uid}
              name="batch"
              labelText=""
              handleChange={this._toggleCheckbox}
            />
          )
        },
      },
      {
        name: 'title',
        title: () => {
          return (
            <button
              type="button"
              className="Contributors__colSort"
              onClick={() => {
                this._sortCol({
                  sortBy: 'dc:title',
                })
              }}
            >
              {this._getIcon('dc:title')}
              {copy.title.th}
            </button>
          )
        },
        render: (value, data) => {
          const uid = data.uid
          const url = editUrl ? `${editUrl}/${uid}` : `/${theme}${dialect_path}/contributor/${uid}`

          return (
             {
                e.preventDefault()
                NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
              }}
            >
              {value}

          )
        },
      },
      {
        name: 'dc:description',
        title: () => {
          return (
            <button
              className="Contributors__colSort"
              onClick={() => {
                this._sortCol({
                  sortBy: 'dc:description',
                })
              }}
            >
              {this._getIcon('dc:description')}
              {copy.description.th}
            </button>
          )
        },
        render: (v, data /*, cellProps*/) => {
          const bio = selectn('properties.dc:description', data) || '-'
          return

        },
      },
      {
        name: 'actions',
        title: copy.actions.th,
        render: (v, data) => {
          const uid = data.uid
          const url = editUrl ? `${editUrl}/${uid}` : `/${theme}${dialect_path}/edit/contributor/${uid}`

          return (

                <ContributorDelete
                  reverse
                  compact
                  copy={{
                    isConfirmOrDenyTitle: copy.isConfirmOrDenyTitle,
                    btnInitiate: copy.btnInitiate,
                    btnDeny: copy.btnDeny,
                    btnConfirm: copy.btnConfirm,
                  }}
                  confirmationAction={() => {
                    this._deleteItem(uid)
                  }}
                />

                 {
                    e.preventDefault()
                    NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
                  }}
                >
                  {copy.actions.edit}

          )
        },
      },
    ]
  }

  _getData = async (addToState) => {
    const { routeParams, search } = this.props
    const { pageSize, page } = routeParams
    const { sortBy, sortOrder } = search

    let currentAppliedFilter = '' // eslint-disable-line
    // if (filter.has('currentAppliedFilter')) {
    //   currentAppliedFilter = Object.values(filter.get('currentAppliedFilter').toJS()).join('')
    // }
    // Get contrinbutors
    contributorsPath = `${routeParams.dialect_path}/Contributors`
    await this.props.fetchContributors(
      contributorsPath,
      `${currentAppliedFilter}&currentPageIndex=${page -
        1}&pageSize=${pageSize}&sortOrder=${sortOrder}&sortBy=${sortBy}`
    )
    // NOTE: redux doesn't update on changes to deeply nested data, hence the manual re-render
    this.setState({
      rerender: Date.now(),
      ...addToState,
    })
  }

  _getIcon = (field) => {
    const { search } = this.props
    const { sortOrder, sortBy } = search

    if (sortBy === field) {
      return sortOrder === 'asc' ? iconSortAsc : iconSortDesc
    }
    return iconUnsorted
  }

  _isSelected = (uid) => {
    const exists = this.state.selected.find((selectedUid) => {
      return selectedUid === uid
    })
    return exists ? true : false
  }

  _paginationHasUpdated = (prevProps) => {
    const { routeParams, search } = this.props
    const { pageSize, page } = routeParams
    const { sortBy, sortOrder } = search

    const { routeParams: prevRouteParams, search: prevSearch } = prevProps
    const { pageSize: prevPageSize, page: prevPage } = prevRouteParams
    const { sortBy: prevSortBy, sortOrder: prevSortOrder } = prevSearch

    if (pageSize !== prevPageSize || page !== prevPage || sortBy !== prevSortBy || sortOrder !== prevSortOrder) {
      return true
    }
    return false
  }

  _selectAll = () => {
    const uids = this._getAllItems()

    this.setState({
      selected: uids,
    })
  }

  _selectNone = () => {
    this.setState({
      selected: [],
    })
  }

  _sortCol = (arg) => {
    const { routeParams, search } = this.props
    const { theme, dialect_path, pageSize } = routeParams
    const { sortOrder } = search

    const url = `/${theme}${dialect_path}/contributors/${pageSize}/1?sortBy=${arg.sortBy}&sortOrder=${
      sortOrder === 'asc' ? 'desc' : 'asc'
    }`
    NavigationHelpers.navigate(url, this.props.pushWindowPath, false)
  }

  _toggleCheckbox = (checked, uid) => {
    let selected = [...this.state.selected]

    const exists = this._isSelected(uid)
    if (checked && !exists) {
      selected.push(uid)
    }
    // remove if exists
    if (!checked && exists) {
      selected = selected.filter((selectedUid) => {
        return selectedUid !== uid
      })
    }

    this.setState({
      selected,
    })
  }
}

// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvContributor, fvDialect, navigation, windowPath } = state

  const { computeContributors } = fvContributor
  const { computeDialect, computeDialect2 } = fvDialect
  const { splitWindowPath, _windowPath } = windowPath

  const { route } = navigation

  return {
    computeContributors,
    routeParams: route.routeParams,
    search: route.search,
    computeDialect,
    computeDialect2,
    splitWindowPath,
    windowPath: _windowPath,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  deleteContributor,
  fetchContributors,
  pushWindowPath,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Contributors)
<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import Snippets from './Snippets'

class Form extends React.Component {

  constructor(props) {
    super(props);
  }

  render() {
    var form = {
      color: "white",

    }

    var input = {
        marginRight: "10px",
        marginLeft: "20px",
        position: "relative",
        right: "20px"
    }

    var inputSpan = {
      position: "relative",
      right: "20px"
    }

    var submitBtn = {
      color: "black",
      margin: "50px"
    }

    var box = {
      width: "300px",
      height: "300px",
      background: "gray",
      display: "inline-flex",
      margin: "10px"
    }

    return (

Box for snippet 1

Box for snippet 2

        <Snippets snippets={this.props.snippets}/>

    );
  }

}

export default Form;<commit_msg>deleted old style variables from form comp<commit_after>'use strict';

import React from 'react';
import Snippets from './Snippets'

class Form extends React.Component {

  constructor(props) {
    super(props);
  }

  render() {

    var box = {
      width: "300px",
      height: "300px",
      background: "gray",
      display: "inline-flex",
      margin: "10px"
    }

    return (

Box for snippet 1

Box for snippet 2

        <Snippets snippets={this.props.snippets}/>

    );
  }

}

export default Form;<|endoftext|>


<commit_before>$(function(){

  // NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT
  // IT'S ALL JUST JUNK FOR OUR DOCS!
  // ++++++++++++++++++++++++++++++++++++++++++

  // Hide the Mobile Safari address bar once loaded
  // ==============================================

  // Set a timeout...
  setTimeout(function(){
    // Hide the address bar!
    window.scrollTo(0, 1);
  }, 0);

  // table sort example
  // ==================

  // make code pretty
  prettyPrint && prettyPrint()

  // table sort example
  if ($.fn.tableSorter) {
    $("#sortTableExample").tablesorter( { sortList: [[ 1, 0 ]] } )
  }

  // add on logic
  $('.add-on :checkbox').on('click', function () {
    var $this = $(this)
      , method = $this.attr('checked') ? 'addClass' : 'removeClass'
    $(this).parents('.add-on')[method]('active')
  })

  // Disable certain links in docs
  // Please do not carry these styles over to your projects
  // it's merely here to prevent button clicks form taking you
  // away from your spot on page!!

  $('[href^=#]').click(function (e) {
    e.preventDefault()
  })

  // Copy code blocks in docs
  $(".copy-code").on('focus', function () {
    var el = this
    setTimeout(function () { $(el).select() }, 0)
  })

  if ($.fn.twipsy) {

    // position static twipsies for components page
    if ($(".twipsies a").length) {
      $(window).on('load resize', function () {
        $(".twipsies a").each(function () {
          $(this)
            .twipsy({
              placement: $(this).attr('title')
            , trigger: 'manual'
            })
            .twipsy('show')
          })
      })
    }

    // add tipsies to grid for scaffolding
    if ($('#grid-system').length) {

      $('#grid-system').twipsy({
          selector: '.show-grid > div'
        , title: function () { return $(this).width() + 'px' }
      })

    }
  }

})
<commit_msg>check for prettyprint on window<commit_after>$(function(){

  // NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT
  // IT'S ALL JUST JUNK FOR OUR DOCS!
  // ++++++++++++++++++++++++++++++++++++++++++

  // Hide the Mobile Safari address bar once loaded
  // ==============================================

  // Set a timeout...
  setTimeout(function(){
    // Hide the address bar!
    window.scrollTo(0, 1);
  }, 0);

  // table sort example
  // ==================

  // make code pretty
  window.prettyPrint && prettyPrint()

  // table sort example
  if ($.fn.tableSorter) {
    $("#sortTableExample").tablesorter( { sortList: [[ 1, 0 ]] } )
  }

  // add on logic
  $('.add-on :checkbox').on('click', function () {
    var $this = $(this)
      , method = $this.attr('checked') ? 'addClass' : 'removeClass'
    $(this).parents('.add-on')[method]('active')
  })

  // Disable certain links in docs
  // Please do not carry these styles over to your projects
  // it's merely here to prevent button clicks form taking you
  // away from your spot on page!!

  $('[href^=#]').click(function (e) {
    e.preventDefault()
  })

  // Copy code blocks in docs
  $(".copy-code").on('focus', function () {
    var el = this
    setTimeout(function () { $(el).select() }, 0)
  })

  if ($.fn.twipsy) {

    // position static twipsies for components page
    if ($(".twipsies a").length) {
      $(window).on('load resize', function () {
        $(".twipsies a").each(function () {
          $(this)
            .twipsy({
              placement: $(this).attr('title')
            , trigger: 'manual'
            })
            .twipsy('show')
          })
      })
    }

    // add tipsies to grid for scaffolding
    if ($('#grid-system').length) {

      $('#grid-system').twipsy({
          selector: '.show-grid > div'
        , title: function () { return $(this).width() + 'px' }
      })

    }
  }

})
<|endoftext|>


<commit_before>import QUnit from "qunitjs";

QUnit.module("dom/manipulate/remove()",
    {
        beforeEach: function ()
        {
            document.getElementById("qunit-fixture").innerHTML =
                '

' +
                '
'+
                '

' +
                '
' +
                'Some text' +
                '

';
        }
    }
);

QUnit.test(
    "remove() on existent element",
    function (assert)
    {
        const find = mojave.dom.traverse.find;
        const element = document.querySelector(".element2");
        const remove = mojave.dom.manipulate.remove;

        remove(element);

        const result = find(".element2");

        assert.equal(result.length, 0, ".element2 successfully removed");
    }
);

QUnit.test(
    "remove() on non-existent element (fails)",
    function (assert)
    {
        const find = mojave.dom.traverse.find;
        const element = document.querySelector(".missing");
        const remove = mojave.dom.manipulate.remove;

        remove(element);

        const result = find(".missing");

        assert.equal(result.length, 0, ".missing not found");
    }
);
<commit_msg>add import line for {remove}<commit_after>import QUnit from "qunitjs";
import {remove} from "../../../../dom/manipulate";

QUnit.module("dom/manipulate/remove()",
    {
        beforeEach: function ()
        {
            document.getElementById("qunit-fixture").innerHTML =
                '

' +
                '
'+
                '

' +
                '
' +
                'Some text' +
                '

';
        }
    }
);

QUnit.test(
    "remove() on existent element",
    function (assert)
    {
        const find = mojave.dom.traverse.find;
        const element = document.querySelector(".element2");
        const remove = mojave.dom.manipulate.remove;

        remove(element);

        const result = find(".element2");

        assert.equal(result.length, 0, ".element2 successfully removed");
    }
);

QUnit.test(
    "remove() on non-existent element (fails)",
    function (assert)
    {
        const find = mojave.dom.traverse.find;
        const element = document.querySelector(".missing");
        const remove = mojave.dom.manipulate.remove;

        remove(element);

        const result = find(".missing");

        assert.equal(result.length, 0, ".missing not found");
    }
);
<|endoftext|>


<commit_before>
  command: 'curl -s "http://legacy.cafebonappetit.com/api/2/menus?cafe=261"',
  refreshFrequency: 6000000,

  render: function(output) {
    return [
        '

',
        '

',
        '

',
        '

',
    ].join('')
  },

  update: function(output, domEl) {

    function createOutputString(okItems){
        var str = "";
        for(var i = 0; i < okItems.length; i++){
            str+= okItems[i]+"

";
        }
        return str;
    }

    function parseDate(x){
        var m,d,y;
        y=x.substr(0,4);
        m=x.substr(5,2);
        d=x.substr(8,2);

        var rawToday = new Date(y+"-"+m+"-"+d);
        var offsetDate = Date(rawToday - rawToday.getTimezoneOffset());
        var todayDate = new Date(offsetDate).toString();
        var today = todayDate.substr(0,10);

        return today.toString();
    }

    function parseMenu(menu){
        console.log ("menu: ")
        console.log(arguments);

        var okItems=[];
        for(var prop in menu){
            if(menu.hasOwnProperty(prop)){
                if(menu[prop].cor_icon.hasOwnProperty(7)){
                    okItems.push(menu[prop].label);
                }
            }
        }
        // Handle update on Mondays and 0 results
        if(okItems.length === 0) {
            // Body
            okItems.push("0 menu items found...");

            // Footer
            var theDay = new Date().getDay();
            if(theDay === 1) {
                var footer = document.getElementById("footer");
                footer.innerHTML = "*Note: the menu usually updates on Mondays";
            }
        }

        return okItems;
    }

    var dom,
     theDate,
     theMenu,
     title,
     jstringObj,
     outputString;

    dom = $(domEl);
    jstringObj = JSON.parse(output);
    theDate= parseDate(jstringObj.days[0].date);
    theMenu= jstringObj.items;
    var friendly= parseMenu(theMenu);
    outputString= createOutputString(friendly);

    title = "Stav Hall Menu";

    //Output
    dom.find(widgetTitle).html(title);
    dom.find(date).html(theDate);
    dom.find(food).html(outputString);
  },
  style: "top: 20px\nleft: 440px\nwidth:400px\nmargin:0px\npadding:0px\nbackground:rgba(#FFF, 0.5)\nborder:2px solid rgba(#000, 0.5)\nborder-radius:10px\noverflow:hidden\n#date\n  margin:12pt\n  margin-bottom:12pt\n  font-family: Helvetica\n  font-size: 25pt\n  font-weight:bold\n  color: rgba(black, 0.75)\n\n#title\n  margin-left:50pt\n  margin-right:12pt\n  font-family: American Typewriter\n  font-size: 20pt\n  font-weight:bold\n#description\n  margin-left:12pt\n  margin-right:12pt\n  font-family: American Typewriter\n  font-size: 12pt\n  line-height:18pt\n  max-height:10pt\n  overflow:hidden\n  hyphens: auto\n\n\#food\n  height: 350px\n\n#footer\n  font-family: Helvetica\n  font-size: 9pt\n  margin:12pt\n  color: rgba(#000, 0.5)\n\np\n  margin: 0 0 0 20px\n\n.e\n  height: 60pt\n\n.event\n  font-size: 17pt\n  font-weight: bold\n"
<commit_msg>Cleaned up the style display so that it is easy to modify and read<commit_after>
  command: 'curl -s "http://legacy.cafebonappetit.com/api/2/menus?cafe=261"',
  refreshFrequency: 6000000,

  render: function(output) {
    return [
        '

',
        '

',
        '

',
        '

',
    ].join('')
  },

  update: function(output, domEl) {

    function createOutputString(okItems){
        var str = "";
        for(var i = 0; i < okItems.length; i++){
            str+= okItems[i]+"

";
        }
        return str;
    }

    function parseDate(x){
        var m,d,y;
        y=x.substr(0,4);
        m=x.substr(5,2);
        d=x.substr(8,2);

        var rawToday = new Date(y+"-"+m+"-"+d);
        var offsetDate = Date(rawToday - rawToday.getTimezoneOffset());
        var todayDate = new Date(offsetDate).toString();
        var today = todayDate.substr(0,10);

        return today.toString();
    }

    function parseMenu(menu){
        console.log ("menu: ")
        console.log(arguments);

        var okItems=[];
        for(var prop in menu){
            if(menu.hasOwnProperty(prop)){
                if(menu[prop].cor_icon.hasOwnProperty(7)){
                    okItems.push(menu[prop].label);
                }
            }
        }
        // Handle update on Mondays and 0 results
        if(okItems.length === 0) {
            // Body
            okItems.push("0 menu items found...");

            // Footer
            var theDay = new Date().getDay();
            if(theDay === 1) {
                var footer = document.getElementById("footer");
                footer.innerHTML = "*Note: the menu usually updates on Mondays";
            }
        }

        return okItems;
    }

    var dom,
     theDate,
     theMenu,
     title,
     jstringObj,
     outputString;

    dom = $(domEl);
    jstringObj = JSON.parse(output);
    theDate= parseDate(jstringObj.days[0].date);
    theMenu= jstringObj.items;
    var friendly= parseMenu(theMenu);
    outputString= createOutputString(friendly);

    title = "Stav Hall Menu";

    //Output
    dom.find(widgetTitle).html(title);
    dom.find(date).html(theDate);
    dom.find(food).html(outputString);
  },

  style: [
    "top: 20px",
    "left: 40px",
    "width:400px",
    "margin:0px",
    "padding:0px",
    "background:rgba(#FFF, 0.5)",
    "border:2px solid rgba(#000, 0.5)",
    "border-radius:10px",
    "overflow:hidden",

    "#date",
    "  margin:12pt",
    "  margin-bottom:12pt",
    "  font-family: Helvetica",
    "  font-size: 25pt",
    "  font-weight:bold",
    "  color: rgba(128,0,0,0.75)",

    "#title",
    "  margin-left:50pt",
    "  margin-right:12pt",
    "  font-family: American Typewriter",
    "  font-size: 20pt",
    "  font-weight:bold",

    "#description",
    "  margin-left:12pt",
    "  margin-right:12pt",
    "  font-family: American Typewriter",
    "  font-size: 12pt",
    "  line-height:18pt",
    "  max-height:10pt",
    "  overflow:hidden",
    "  hyphens: auto",

    "#food",
    "  height: 350px",

    "#footer",
    "  font-family: Helvetica",
    "  font-size: 9pt",
    "  margin:12pt",
    "  color: rgba(#000, 0.5)",

    "p",
    "  margin: 0 0 0 20px",

    ".e",
    "  margin-top: -40px",
    "  margin-left: 20px",
    "  height: 60pt",

    ".event",
    "  font-size: 17pt",
    "  font-weight: bold",
    ].join('\n')
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var util = require('util')
  , OAuth2Strategy = require('passport-oauth').OAuth2Strategy
  , InternalOAuthError = require('passport-oauth').InternalOAuthError;

/**
 * `Strategy` constructor.
 *
 * The Google authentication strategy authenticates requests by delegating to
 * Google using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      your Google application's client id
 *   - `clientSecret`  your Google application's client secret
 *   - `callbackURL`   URL to which Google will redirect the user after granting authorization
 *
 * Examples:
 *
 *     passport.use(new GoogleStrategy({
 *         clientID: '123-456-789',
 *         clientSecret: 'shhh-its-a-secret'
 *         callbackURL: 'https://www.example.net/auth/google/callback'
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://accounts.google.com/o/oauth2/auth';
  options.tokenURL = options.tokenURL || 'https://accounts.google.com/o/oauth2/token';

  OAuth2Strategy.call(this, options, verify);
  this.name = 'google';
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from Google.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `google`
 *   - `id`
 *   - `username`
 *   - `displayName`
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
Strategy.prototype.userProfile = function(accessToken, done) {
  this._oauth2.get('https://www.googleapis.com/oauth2/v1/userinfo', accessToken, function (err, body, res) {
    if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }

    try {
      var json = JSON.parse(body);

      var profile = { provider: 'google' };
      profile.id = json.id;
      profile.displayName = json.name;
      profile.name = { familyName: json.family_name,
                       givenName: json.given_name };
      profile.emails = [{ value: json.email }];

      profile._raw = body;
      profile._json = json;

      done(null, profile);
    } catch(e) {
      done(e);
    }
  });
}

/**
 * Return extra Google-specific parameters to be included in the authorization
 * request.
 *
 * @param {Object} options
 * @return {Object}
 * @api protected
 */
Strategy.prototype.authorizationParams = function(options) {
  var params = {};
  if (options.accessType) {
    params['access_type'] = options.accessType;
  }
  if (options.approvalPrompt) {
    params['approval_prompt'] = options.approvalPrompt;
  }
  if (options.prompt) {
    // This parameter is undocumented in Google's official documentation.
    // However, it was detailed by Breno de Medeiros (who works at Google) in
    // this Stack Overflow answer:
    //  http://stackoverflow.com/questions/14384354/force-google-account-chooser/14393492#14393492
    params['prompt'] = options.prompt;
  }
  if (options.loginHint) {
    // This parameter is derived from OpenID Connect, and supported by Google's
    // OAuth 2.0 endpoint.
    //   https://github.com/jaredhanson/passport-google-oauth/pull/8
    //   https://bitbucket.org/openid/connect/commits/970a95b83add
    params['login_hint'] = options.loginHint;
  }
  if (options.userID) {
    // Undocumented, but supported by Google's OAuth 2.0 endpoint.  Appears to
    // be equivalent to `login_hint`.
    params['user_id'] = options.userID;
  }
  if (options.hostedDomain || options.hd) {
    // This parameter is derived from Google's OAuth 1.0 endpoint, and (although
    // undocumented) is supported by Google's OAuth 2.0 endpoint was well.
    //   https://developers.google.com/accounts/docs/OAuth_ref
    params['hd'] = options.hostedDomain || options.hd;
  }
  if (options.display) {
    // Specify what kind of display consent screen to display to users.
    //   https://developers.google.com/accounts/docs/OpenIDConnect#authenticationuriparameters
    params['display'] = options.display;
  }
  return params;
}

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
<commit_msg>Fix merge conflict.<commit_after>/**
 * Module dependencies.
 */
var util = require('util')
  , OAuth2Strategy = require('passport-oauth').OAuth2Strategy
  , InternalOAuthError = require('passport-oauth').InternalOAuthError;

/**
 * `Strategy` constructor.
 *
 * The Google authentication strategy authenticates requests by delegating to
 * Google using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      your Google application's client id
 *   - `clientSecret`  your Google application's client secret
 *   - `callbackURL`   URL to which Google will redirect the user after granting authorization
 *
 * Examples:
 *
 *     passport.use(new GoogleStrategy({
 *         clientID: '123-456-789',
 *         clientSecret: 'shhh-its-a-secret'
 *         callbackURL: 'https://www.example.net/auth/google/callback'
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://accounts.google.com/o/oauth2/auth';
  options.tokenURL = options.tokenURL || 'https://accounts.google.com/o/oauth2/token';

  OAuth2Strategy.call(this, options, verify);
  this.name = 'google';
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from Google.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `google`
 *   - `id`
 *   - `username`
 *   - `displayName`
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
Strategy.prototype.userProfile = function(accessToken, done) {
  this._oauth2.get('https://www.googleapis.com/oauth2/v1/userinfo', accessToken, function (err, body, res) {
    if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }

    try {
      var json = JSON.parse(body);

      var profile = { provider: 'google' };
      profile.id = json.id;
      profile.displayName = json.name;
      profile.name = { familyName: json.family_name,
                       givenName: json.given_name };
      profile.emails = [{ value: json.email }];

      profile._raw = body;
      profile._json = json;

      done(null, profile);
    } catch(e) {
      done(e);
    }
  });
}

/**
 * Return extra Google-specific parameters to be included in the authorization
 * request.
 *
 * @param {Object} options
 * @return {Object}
 * @api protected
 */
Strategy.prototype.authorizationParams = function(options) {
  var params = {};
  if (options.accessType) {
    params['access_type'] = options.accessType;
  }
  if (options.approvalPrompt) {
    params['approval_prompt'] = options.approvalPrompt;
  }
  if (options.prompt) {
    // This parameter is undocumented in Google's official documentation.
    // However, it was detailed by Breno de Medeiros (who works at Google) in
    // this Stack Overflow answer:
    //  http://stackoverflow.com/questions/14384354/force-google-account-chooser/14393492#14393492
    params['prompt'] = options.prompt;
  }
  if (options.loginHint) {
    // This parameter is derived from OpenID Connect, and supported by Google's
    // OAuth 2.0 endpoint.
    //   https://github.com/jaredhanson/passport-google-oauth/pull/8
    //   https://bitbucket.org/openid/connect/commits/970a95b83add
    params['login_hint'] = options.loginHint;
  }
  if (options.userID) {
    // Undocumented, but supported by Google's OAuth 2.0 endpoint.  Appears to
    // be equivalent to `login_hint`.
    params['user_id'] = options.userID;
  }
  if (options.hostedDomain || options.hd) {
    // This parameter is derived from Google's OAuth 1.0 endpoint, and (although
    // undocumented) is supported by Google's OAuth 2.0 endpoint was well.
    //   https://developers.google.com/accounts/docs/OAuth_ref
    params['hd'] = options.hostedDomain || options.hd;
  }
  if (options.display) {
    // Specify what kind of display consent screen to display to users.
    //   https://developers.google.com/accounts/docs/OpenIDConnect#authenticationuriparameters
    params['display'] = options.display;
  }
  if (options.requestVisibleActions) {
    // Space separated list of allowed app actions
    // as documented at:
    //  https://developers.google.com/+/web/app-activities/#writing_an_app_activity_using_the_google_apis_client_libraries
    //  https://developers.google.com/+/api/moment-types/
    params['request_visible_actions'] = options.requestVisibleActions;
  }
  return params;
}

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
<|endoftext|>


<commit_before>const hbs = require('express-hbs');
const _ = require('lodash');
const debug = require('@tryghost/debug')('error-handler');
const errors = require('@tryghost/errors');
const config = require('../../../../shared/config');
const i18n = require('../../../../shared/i18n');
const helpers = require('../../../../frontend/services/routing/helpers');
const sentry = require('../../../../shared/sentry');

const escapeExpression = hbs.Utils.escapeExpression;
const _private = {};
const errorHandler = {};

/**
 * This is a bare minimum setup, which allows us to render the error page
 * It uses the {{asset}} helper, and nothing more
 */
_private.createHbsEngine = () => {
    const engine = hbs.create();
    engine.registerHelper('asset', require('../../../../frontend/helpers/asset'));

    return engine.express4();
};

/**
 * Get an error ready to be shown the the user
 *
 * @TODO: support multiple errors within one single error, see https://github.com/TryGhost/Ghost/issues/7116#issuecomment-252231809
 */
_private.prepareError = (err, req, res, next) => {
    debug(err);

    if (Array.isArray(err)) {
        err = err[0];
    }

    if (!errors.utils.isIgnitionError(err)) {
        // We need a special case for 404 errors
        // @TODO look at adding this to the GhostError class
        if (err.statusCode && err.statusCode === 404) {
            err = new errors.NotFoundError({
                err: err
            });
        } else if (err.stack.match(/node_modules\/handlebars\//)) {
            // Temporary handling of theme errors from handlebars
            // @TODO remove this when #10496 is solved properly
            err = new errors.IncorrectUsageError({
                err: err,
                message: err.message,
                statusCode: err.statusCode
            });
        } else {
            err = new errors.GhostError({
                err: err,
                message: err.message,
                statusCode: err.statusCode
            });
        }
    }

    // used for express logging middleware see core/server/app.js
    req.err = err;

    // alternative for res.status();
    res.statusCode = err.statusCode;

    // never cache errors
    res.set({
        'Cache-Control': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
    });

    next(err);
};

_private.JSONErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    res.json({
        errors: [{
            message: err.message,
            context: err.context,
            errorType: err.errorType,
            errorDetails: err.errorDetails
        }]
    });
};

_private.prepareUserMessage = (err, res) => {
    const userError = {
        message: err.message,
        context: err.context
    };

    const docName = _.get(res, 'frameOptions.docName');
    const method = _.get(res, 'frameOptions.method');

    if (docName && method) {
        let action;

        const actionMap = {
            browse: 'list',
            read: 'read',
            add: 'save',
            edit: 'edit',
            destroy: 'delete'
        };

        if (i18n.doesTranslationKeyExist(`common.api.actions.${docName}.${method}`)) {
            action = i18n.t(`common.api.actions.${docName}.${method}`);
        } else if (Object.keys(actionMap).includes(method)) {
            let resource = docName;

            if (method !== 'browse') {
                resource = resource.replace(/s$/, '');
            }

            action = `${actionMap[method]} ${resource}`;
        }

        if (action) {
            if (err.context) {
                userError.context = `${err.message} ${err.context}`;
            } else {
                userError.context = err.message;
            }

            userError.message = i18n.t(`errors.api.userMessages.${err.name}`, {action: action});
        }
    }

    return userError;
};

_private.JSONErrorRendererV2 = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    const userError = _private.prepareUserMessage(err, req);

    res.json({
        errors: [{
            message: userError.message || null,
            context: userError.context || null,
            type: err.errorType || null,
            details: err.errorDetails || null,
            property: err.property || null,
            help: err.help || null,
            code: err.code || null,
            id: err.id || null
        }]
    });
};

_private.ErrorFallbackMessage = err => `
${i18n.t('errors.errors.oopsErrorTemplateHasError')}

${i18n.t('errors.errors.encounteredError')}

${escapeExpression(err.message || err)}

${i18n.t('errors.errors.whilstTryingToRender')}

     ${err.statusCode}
${escapeExpression(err.message || err)}
`;

_private.ThemeErrorRenderer = (err, req, res, next) => {
    // If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
    // Skip trying to render an HTML error, and move on to the basic error renderer
    // We do this because customised 404 templates could reference the image that's missing
    // A better long term solution might be to do this based on extension
    if (err.code === 'STATIC_FILE_NOT_FOUND') {
        return next(err);
    }

    // Renderer begin
    // Format Data
    const data = {
        message: err.message,
        // @deprecated Remove in Ghost 4.0
        code: err.statusCode,
        statusCode: err.statusCode,
        errorDetails: err.errorDetails || []
    };

    // Template
    // @TODO: very dirty !!!!!!
    helpers.templates.setTemplate(req, res);

    // It can be that something went wrong with the theme or otherwise loading handlebars
    // This ensures that no matter what res.render will work here
    // @TODO: split the error handler for assets, admin & theme to refactor this away
    if (_.isEmpty(req.app.engines)) {
        res._template = 'error';
        req.app.engine('hbs', _private.createHbsEngine());
        req.app.set('view engine', 'hbs');
        req.app.set('views', config.get('paths').defaultViews);
    }

    // @TODO use renderer here?!
    // Render Call - featuring an error handler for what happens if rendering fails
    res.render(res._template, data, (_err, html) => {
        if (!_err) {
            return res.send(html);
        }

        // re-attach new error e.g. error template has syntax error or misusage
        req.err = _err;

        // And then try to explain things to the user...
        // Cheat and output the error using handlebars escapeExpression
        return res.status(500).send(_private.ErrorFallbackMessage(_err));
    });
};

_private.HTMLErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    const data = {
        message: err.message,
        statusCode: err.statusCode,
        errorDetails: err.errorDetails || []
    };

    // e.g. if you serve the admin /ghost and Ghost returns a 503 because it generates the urls at the moment.
    // This ensures that no matter what res.render will work here
    // @TODO: put to prepare error function?
    if (_.isEmpty(req.app.engines)) {
        res._template = 'error';
        req.app.engine('hbs', _private.createHbsEngine());
        req.app.set('view engine', 'hbs');
        req.app.set('views', config.get('paths').defaultViews);
    }

    res.render('error', data, (_err, html) => {
        if (!_err) {
            return res.send(html);
        }

        // re-attach new error e.g. error template has syntax error or misusage
        req.err = _err;

        // And then try to explain things to the user...
        // Cheat and output the error using handlebars escapeExpression
        return res.status(500).send(_private.ErrorFallbackMessage(_err));
    });
};

_private.BasicErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    return res.send(res.statusCode + ' ' + err.message);
};

errorHandler.resourceNotFound = (req, res, next) => {
    // TODO, handle unknown resources & methods differently, so that we can also produce
    // 405 Method Not Allowed
    next(new errors.NotFoundError({message: i18n.t('errors.errors.resourceNotFound')}));
};

errorHandler.pageNotFound = (req, res, next) => {
    next(new errors.NotFoundError({message: i18n.t('errors.errors.pageNotFound')}));
};

errorHandler.handleJSONResponse = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using JSON format
    _private.JSONErrorRenderer
];

errorHandler.handleJSONResponseV2 = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using JSON format
    _private.JSONErrorRendererV2
];

errorHandler.handleHTMLResponse = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using HTML format
    _private.HTMLErrorRenderer,
    // Fall back to basic if HTML is not explicitly accepted
    _private.BasicErrorRenderer
];

errorHandler.handleThemeResponse = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using theme template
    _private.ThemeErrorRenderer,
    // Fall back to basic if HTML is not explicitly accepted
    _private.BasicErrorRenderer
];

module.exports = errorHandler;
<commit_msg>Corrected deprecation comment<commit_after>const hbs = require('express-hbs');
const _ = require('lodash');
const debug = require('@tryghost/debug')('error-handler');
const errors = require('@tryghost/errors');
const config = require('../../../../shared/config');
const i18n = require('../../../../shared/i18n');
const helpers = require('../../../../frontend/services/routing/helpers');
const sentry = require('../../../../shared/sentry');

const escapeExpression = hbs.Utils.escapeExpression;
const _private = {};
const errorHandler = {};

/**
 * This is a bare minimum setup, which allows us to render the error page
 * It uses the {{asset}} helper, and nothing more
 */
_private.createHbsEngine = () => {
    const engine = hbs.create();
    engine.registerHelper('asset', require('../../../../frontend/helpers/asset'));

    return engine.express4();
};

/**
 * Get an error ready to be shown the the user
 *
 * @TODO: support multiple errors within one single error, see https://github.com/TryGhost/Ghost/issues/7116#issuecomment-252231809
 */
_private.prepareError = (err, req, res, next) => {
    debug(err);

    if (Array.isArray(err)) {
        err = err[0];
    }

    if (!errors.utils.isIgnitionError(err)) {
        // We need a special case for 404 errors
        // @TODO look at adding this to the GhostError class
        if (err.statusCode && err.statusCode === 404) {
            err = new errors.NotFoundError({
                err: err
            });
        } else if (err.stack.match(/node_modules\/handlebars\//)) {
            // Temporary handling of theme errors from handlebars
            // @TODO remove this when #10496 is solved properly
            err = new errors.IncorrectUsageError({
                err: err,
                message: err.message,
                statusCode: err.statusCode
            });
        } else {
            err = new errors.GhostError({
                err: err,
                message: err.message,
                statusCode: err.statusCode
            });
        }
    }

    // used for express logging middleware see core/server/app.js
    req.err = err;

    // alternative for res.status();
    res.statusCode = err.statusCode;

    // never cache errors
    res.set({
        'Cache-Control': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
    });

    next(err);
};

_private.JSONErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    res.json({
        errors: [{
            message: err.message,
            context: err.context,
            errorType: err.errorType,
            errorDetails: err.errorDetails
        }]
    });
};

_private.prepareUserMessage = (err, res) => {
    const userError = {
        message: err.message,
        context: err.context
    };

    const docName = _.get(res, 'frameOptions.docName');
    const method = _.get(res, 'frameOptions.method');

    if (docName && method) {
        let action;

        const actionMap = {
            browse: 'list',
            read: 'read',
            add: 'save',
            edit: 'edit',
            destroy: 'delete'
        };

        if (i18n.doesTranslationKeyExist(`common.api.actions.${docName}.${method}`)) {
            action = i18n.t(`common.api.actions.${docName}.${method}`);
        } else if (Object.keys(actionMap).includes(method)) {
            let resource = docName;

            if (method !== 'browse') {
                resource = resource.replace(/s$/, '');
            }

            action = `${actionMap[method]} ${resource}`;
        }

        if (action) {
            if (err.context) {
                userError.context = `${err.message} ${err.context}`;
            } else {
                userError.context = err.message;
            }

            userError.message = i18n.t(`errors.api.userMessages.${err.name}`, {action: action});
        }
    }

    return userError;
};

_private.JSONErrorRendererV2 = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    const userError = _private.prepareUserMessage(err, req);

    res.json({
        errors: [{
            message: userError.message || null,
            context: userError.context || null,
            type: err.errorType || null,
            details: err.errorDetails || null,
            property: err.property || null,
            help: err.help || null,
            code: err.code || null,
            id: err.id || null
        }]
    });
};

_private.ErrorFallbackMessage = err => `
${i18n.t('errors.errors.oopsErrorTemplateHasError')}

${i18n.t('errors.errors.encounteredError')}

${escapeExpression(err.message || err)}

${i18n.t('errors.errors.whilstTryingToRender')}

     ${err.statusCode}
${escapeExpression(err.message || err)}
`;

_private.ThemeErrorRenderer = (err, req, res, next) => {
    // If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
    // Skip trying to render an HTML error, and move on to the basic error renderer
    // We do this because customised 404 templates could reference the image that's missing
    // A better long term solution might be to do this based on extension
    if (err.code === 'STATIC_FILE_NOT_FOUND') {
        return next(err);
    }

    // Renderer begin
    // Format Data
    const data = {
        message: err.message,
        // @deprecated Remove in Ghost 5.0
        code: err.statusCode,
        statusCode: err.statusCode,
        errorDetails: err.errorDetails || []
    };

    // Template
    // @TODO: very dirty !!!!!!
    helpers.templates.setTemplate(req, res);

    // It can be that something went wrong with the theme or otherwise loading handlebars
    // This ensures that no matter what res.render will work here
    // @TODO: split the error handler for assets, admin & theme to refactor this away
    if (_.isEmpty(req.app.engines)) {
        res._template = 'error';
        req.app.engine('hbs', _private.createHbsEngine());
        req.app.set('view engine', 'hbs');
        req.app.set('views', config.get('paths').defaultViews);
    }

    // @TODO use renderer here?!
    // Render Call - featuring an error handler for what happens if rendering fails
    res.render(res._template, data, (_err, html) => {
        if (!_err) {
            return res.send(html);
        }

        // re-attach new error e.g. error template has syntax error or misusage
        req.err = _err;

        // And then try to explain things to the user...
        // Cheat and output the error using handlebars escapeExpression
        return res.status(500).send(_private.ErrorFallbackMessage(_err));
    });
};

_private.HTMLErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    const data = {
        message: err.message,
        statusCode: err.statusCode,
        errorDetails: err.errorDetails || []
    };

    // e.g. if you serve the admin /ghost and Ghost returns a 503 because it generates the urls at the moment.
    // This ensures that no matter what res.render will work here
    // @TODO: put to prepare error function?
    if (_.isEmpty(req.app.engines)) {
        res._template = 'error';
        req.app.engine('hbs', _private.createHbsEngine());
        req.app.set('view engine', 'hbs');
        req.app.set('views', config.get('paths').defaultViews);
    }

    res.render('error', data, (_err, html) => {
        if (!_err) {
            return res.send(html);
        }

        // re-attach new error e.g. error template has syntax error or misusage
        req.err = _err;

        // And then try to explain things to the user...
        // Cheat and output the error using handlebars escapeExpression
        return res.status(500).send(_private.ErrorFallbackMessage(_err));
    });
};

_private.BasicErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
    return res.send(res.statusCode + ' ' + err.message);
};

errorHandler.resourceNotFound = (req, res, next) => {
    // TODO, handle unknown resources & methods differently, so that we can also produce
    // 405 Method Not Allowed
    next(new errors.NotFoundError({message: i18n.t('errors.errors.resourceNotFound')}));
};

errorHandler.pageNotFound = (req, res, next) => {
    next(new errors.NotFoundError({message: i18n.t('errors.errors.pageNotFound')}));
};

errorHandler.handleJSONResponse = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using JSON format
    _private.JSONErrorRenderer
];

errorHandler.handleJSONResponseV2 = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using JSON format
    _private.JSONErrorRendererV2
];

errorHandler.handleHTMLResponse = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using HTML format
    _private.HTMLErrorRenderer,
    // Fall back to basic if HTML is not explicitly accepted
    _private.BasicErrorRenderer
];

errorHandler.handleThemeResponse = [
    // Make sure the error can be served
    _private.prepareError,
    // Handle the error in Sentry
    sentry.errorHandler,
    // Render the error using theme template
    _private.ThemeErrorRenderer,
    // Fall back to basic if HTML is not explicitly accepted
    _private.BasicErrorRenderer
];

module.exports = errorHandler;
<|endoftext|>


<commit_before>/*****************************************************************************/
/* EmployeeEmploymentDetailsDataEntry: Event Handlers */
/*****************************************************************************/
Template.EmployeeEmploymentDetailsDataEntry.events({
  'click #save-close': (e, tmpl) => {
    Modal.hide('EmployeeEditEmploymentPayrollModal');
  },
  'click #save': (e, tmpl) => {
    let user = Template.instance().getEditUser();
    console.log("User to update on server: \n" + JSON.stringify(user));

    Meteor.call('account/updateEmploymentData', user, user._id, (err, res) => {
        if (res){
            Session.set('employeesList_selectedEmployee', user);
            swal({
                title: "Success",
                text: `Employee employment data updated`,
                confirmButtonClass: "btn-success",
                type: "success",
                confirmButtonText: "OK"
            });
            Modal.hide('EmployeeEditEmploymentPayrollModal');
        } else {
            console.log(err);
        }
    });
  },
  'blur [name=employmentPosition]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.position = value;

      console.log("user employment position changed to: " + value);
    }
    Template.instance().setEditUser(user);
    Template.instance().setSelectedPosition(value);
  },
  'blur [name=employmentPayGrade]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.paygrade = value;

      console.log("user employment position changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentPayGrade]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.paygrade = value;

      console.log("user employment paygrade changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentHireDate]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.hireDate = value;

      console.log("user employment hireDate changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentConfirmationDate]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.confirmationDate = value;

      console.log("user employment confirmationDate changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentStatus]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.status = value;

      console.log("user employment status changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentTerminationDate]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.terminationDate = value;

      console.log("user employment terminationDate changed to: " + value);
    }
    Template.instance().setEditUser(user);
  }
});

/*****************************************************************************/
/* EmployeeEmploymentDetailsDataEntry: Helpers */
/*****************************************************************************/
Template.registerHelper('formatDate', function(date) {
  return moment(date).format('MM-DD-YYYY');
});

Template.EmployeeEmploymentDetailsDataEntry.helpers({
    'employees': function(){
        return Meteor.users.find({"employee": true});
    },
    "selectedEmployee": function() {
        let selectedEmployee = Session.get('employeesList_selectedEmployee');
        return [selectedEmployee];
    },
    positions: () => {
        return EntityObjects.find();
    },
    'selectedPosition': () => {
        let editUser = Template.instance().getEditUser();
        if(editUser) {
          return editUser.employeeProfile.employment.position;
        } else {
          return null;
        }
    },
    'grades': () => {
        return PayGrades.find();
    },
});

/*****************************************************************************/
/* EmployeeEmploymentDetailsDataEntry: Lifecycle Hooks */
/*****************************************************************************/
Template.EmployeeEmploymentDetailsDataEntry.onCreated(function () {
  let self = this;

  self.getEditUser = () => {
    return Session.get('employeeNextOfKinData');
  }

  self.setEditUser = (editUser) => {
    console.log("Inside setEditUser");
    Session.set('employeeNextOfKinData', editUser);
  }

  let selectedEmployee = Session.get('employeesList_selectedEmployee')
  self.setEditUser(selectedEmployee);

  // var self = this;
  //
  // self.selectedPosition = new ReactiveVar();
  // self.selectedGrade = new ReactiveVar();
  // self.assignedTypes = new ReactiveVar();
  // // self.subscribe("getPositions", Session.get('context'));
  self.subscribe("getbuconstants", selectedEmployee._id);
  //
  self.autorun(function(){
      // let position = self.getSelectedPosition();
      let position = Session.get("selectedEmployee_employmentDetails_selectedPosition");
      if(position)
          self.subscribe("assignedGrades", position);
  });

  self.getSelectedPosition = () => {
    return Session.get("selectedEmployee_employmentDetails_selectedPosition");
  }

  self.setSelectedPosition = (selectedPosition) => {
    Session.set("selectedEmployee_employmentDetails_selectedPosition", selectedPosition);
  }
  //--
  self.getSelectedPayGrade = () => {
    return Session.get("selectedEmployee_employmentDetails_selectedPayGrade");
  }

  self.setSelectedPayGrade = (selectedPayGrade) => {
    Session.set("selectedEmployee_employmentDetails_selectedPayGrade", selectedPayGrade);
  }
  //--
  self.getAssignedPayTypes = () => {
    return Session.get("selectedEmployee_employmentDetails_assignedPayTypes");
  }

  self.setAssignedPayTypes = (selectedPosition) => {
    Session.set("selectedEmployee_employmentDetails_assignedPayTypes", selectedPosition);
  }

  self.autorun(function(){
      let selectedGrade = Template.instance().getSelectedPayGrade();
      if(selectedGrade){
          let grade = PayGrades.findOne({_id: selectedGrade});
          if (grade){
              let paytypes = grade.payTypes.map(x => {
                  return x.paytype;
              });
              self.subscribe("getpositionGrades", paytypes);
          }
          //
          let pgObj = PayGrades.findOne({_id: selectedGrade});
          let paytypes = pgObj.payTypes;
          paytypes.forEach(x => {
              pt = PayTypes.findOne({_id: x.paytype});
              if (pt)
                  _.extend(x, pt);
              return x
          });
          Template.instance().setAssignedPayTypes(paytypes);
      }
  });
});

Template.EmployeeEmploymentDetailsDataEntry.onRendered(function () {
  let selectedEmployee = Session.get('employeesList_selectedEmployee');
  console.log("Positon: " + selectedEmployee.employeeProfile.employment.position);

  $('[name="employmentPosition"]').val(selectedEmployee.employeeProfile.employment.position);
});

Template.EmployeeEmploymentDetailsDataEntry.onDestroyed(function () {
});

//----
<commit_msg>fix bug on employment details modal for showing the active or inactive<commit_after>/*****************************************************************************/
/* EmployeeEmploymentDetailsDataEntry: Event Handlers */
/*****************************************************************************/
Template.EmployeeEmploymentDetailsDataEntry.events({
  'click #save-close': (e, tmpl) => {
    Modal.hide('EmployeeEditEmploymentPayrollModal');
  },
  'click #save': (e, tmpl) => {
    let user = Template.instance().getEditUser();
    console.log("User to update on server: \n" + JSON.stringify(user));

    Meteor.call('account/updateEmploymentData', user, user._id, (err, res) => {
        if (res){
            Session.set('employeesList_selectedEmployee', user);
            swal({
                title: "Success",
                text: `Employee employment data updated`,
                confirmButtonClass: "btn-success",
                type: "success",
                confirmButtonText: "OK"
            });
            Modal.hide('EmployeeEditEmploymentPayrollModal');
        } else {
            console.log(err);
        }
    });
  },
  'blur [name=employmentPosition]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.position = value;

      console.log("user employment position changed to: " + value);
    }
    Template.instance().setEditUser(user);
    Template.instance().setSelectedPosition(value);
  },
  'blur [name=employmentPayGrade]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.paygrade = value;

      console.log("user employment position changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentPayGrade]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.paygrade = value;

      console.log("user employment paygrade changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentHireDate]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.hireDate = value;

      console.log("user employment hireDate changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentConfirmationDate]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.confirmationDate = value;

      console.log("user employment confirmationDate changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentStatus]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.status = value;

      console.log("user employment status changed to: " + value);
    }
    Template.instance().setEditUser(user);
  },
  'blur [name=employmentTerminationDate]': function (e, tmpl) {
    let user = Template.instance().getEditUser();
    let value = e.currentTarget.value;
    if (value && value.trim().length > 0) {
      user.employeeProfile = user.employeeProfile || {};
      user.employeeProfile.employment = user.employeeProfile.employment || {};
      user.employeeProfile.employment.terminationDate = value;

      console.log("user employment terminationDate changed to: " + value);
    }
    Template.instance().setEditUser(user);
  }
});

/*****************************************************************************/
/* EmployeeEmploymentDetailsDataEntry: Helpers */
/*****************************************************************************/
Template.registerHelper('formatDate', function(date) {
  return moment(date).format('MM-DD-YYYY');
});

Template.EmployeeEmploymentDetailsDataEntry.helpers({
    'employees': function(){
        return Meteor.users.find({"employee": true});
    },
    "selectedEmployee": function() {
        let selectedEmployee = Session.get('employeesList_selectedEmployee');
        return [selectedEmployee];
    },
    positions: () => {
        return EntityObjects.find();
    },
    'selectedPosition': () => {
        let editUser = Template.instance().getEditUser();
        if(editUser) {
          return editUser.employeeProfile.employment.position;
        } else {
          return null;
        }
    },
    'grades': () => {
        return PayGrades.find();
    },
});

/*****************************************************************************/
/* EmployeeEmploymentDetailsDataEntry: Lifecycle Hooks */
/*****************************************************************************/
Template.EmployeeEmploymentDetailsDataEntry.onCreated(function () {
  let self = this;

  self.getEditUser = () => {
    return Session.get('employeeNextOfKinData');
  }

  self.setEditUser = (editUser) => {
    console.log("Inside setEditUser");
    Session.set('employeeNextOfKinData', editUser);
  }

  let selectedEmployee = Session.get('employeesList_selectedEmployee')
  self.setEditUser(selectedEmployee);

  // var self = this;
  //
  // self.selectedPosition = new ReactiveVar();
  // self.selectedGrade = new ReactiveVar();
  // self.assignedTypes = new ReactiveVar();
  // // self.subscribe("getPositions", Session.get('context'));
  self.subscribe("getbuconstants", selectedEmployee._id);
  //
  self.autorun(function(){
      // let position = self.getSelectedPosition();
      let position = Session.get("selectedEmployee_employmentDetails_selectedPosition");
      if(position)
          self.subscribe("assignedGrades", position);
  });

  self.getSelectedPosition = () => {
    return Session.get("selectedEmployee_employmentDetails_selectedPosition");
  }

  self.setSelectedPosition = (selectedPosition) => {
    Session.set("selectedEmployee_employmentDetails_selectedPosition", selectedPosition);
  }
  //--
  self.getSelectedPayGrade = () => {
    return Session.get("selectedEmployee_employmentDetails_selectedPayGrade");
  }

  self.setSelectedPayGrade = (selectedPayGrade) => {
    Session.set("selectedEmployee_employmentDetails_selectedPayGrade", selectedPayGrade);
  }
  //--
  self.getAssignedPayTypes = () => {
    return Session.get("selectedEmployee_employmentDetails_assignedPayTypes");
  }

  self.setAssignedPayTypes = (selectedPosition) => {
    Session.set("selectedEmployee_employmentDetails_assignedPayTypes", selectedPosition);
  }

  self.autorun(function(){
      let selectedGrade = Template.instance().getSelectedPayGrade();
      if(selectedGrade){
          let grade = PayGrades.findOne({_id: selectedGrade});
          if (grade){
              let paytypes = grade.payTypes.map(x => {
                  return x.paytype;
              });
              self.subscribe("getpositionGrades", paytypes);
          }
          //
          let pgObj = PayGrades.findOne({_id: selectedGrade});
          let paytypes = pgObj.payTypes;
          paytypes.forEach(x => {
              pt = PayTypes.findOne({_id: x.paytype});
              if (pt)
                  _.extend(x, pt);
              return x
          });
          Template.instance().setAssignedPayTypes(paytypes);
      }
  });
});

Template.EmployeeEmploymentDetailsDataEntry.onRendered(function () {
  let selectedEmployee = Session.get('employeesList_selectedEmployee');
  console.log("Positon: " + selectedEmployee.employeeProfile.employment.position);

  $('[name="employmentPosition"]').val(selectedEmployee.employeeProfile.employment.position);
  $('[name="employmentStatus"]').val(selectedEmployee.employeeProfile.employment.status);
});

Template.EmployeeEmploymentDetailsDataEntry.onDestroyed(function () {
});

//----
<|endoftext|>


<commit_before>const http = require('http')
const request = require('request')

exports.name = "🔮 Wikipedia"

var regexes = [
	/Qu[' ]est[- ]ce qu(?:e|') ?(?:la|le|les|une?|l')? ?(.+)(?: \?)?/i,
	/Qui est (.+)(?: \?)?/i
]

exports.regexes = regexes

exports.help = [
	{example: "Qui est Barrack Obama ?"},
	{example: "Qu'est ce qu'un tabouret ?", description: "Je cherche la signification sur wikipedia"},
]

//Repris et adapté du projet Alfred
exports.onMessage = function(message,matching){
	message.channel.sendMessage(message.author+" Je cherche sur Wikipedia...")
	var wikiSerachOptions = "http://fr.wikipedia.org/w/api.php?action=opensearch&search="+matching.regexResult[1]+"&format=json&utf8"
	request(wikiSerachOptions,(err,res,result) => {
		try{
			result = JSON.parse(result)
			if(result[2].length > 0){
				if(result[2][0] == "" && result[2][1]){
					message.channel.sendMessage(message.author+" "+result[2][1])
				} else if(result[2][0] != "") {
					message.channel.sendMessage(message.author+" "+result[2][0])
				} else {
					message.channel.sendMessage(message.author+" Je ne trouve rien à propos de "+matching.regexResult[1])
				}
			} else {
				message.channel.sendMessage(message.author+" Je ne trouve rien à propos de "+matching.regexResult[1])
			}
		} catch(e) {
			console.error(e)
			message.channel.sendMessage(message.author+" Whoops, j'ai une érreur... proposez autre chose peut être...")
		}
	})
}<commit_msg>Recherch ddg si pas wikipedia<commit_after>const http = require('http')
const request = require('request')

exports.name = "🔮 Wikipedia"

var regexes = [
	/Qu[' ]est[- ]ce qu(?:e|') ?(?:la|le|les|une?|l')? ?(.+)(?: \?)?/i,
	/Qui est (.+)(?: \?)?/i
]

exports.regexes = regexes

exports.help = [
	{example: "Qui est Barrack Obama ?"},
	{example: "Qu'est ce qu'un tabouret ?", description: "Je cherche la signification sur wikipedia"},
]

//Repris et adapté du projet Alfred
exports.onMessage = function(message,matching){
	message.channel.sendMessage(message.author+" Je cherche sur Wikipedia...")
	var wikiSerachOptions = "http://fr.wikipedia.org/w/api.php?action=opensearch&search="+matching.regexResult[1]+"&format=json&utf8"
	request(wikiSerachOptions,(err,res,result) => {
		try{
			result = JSON.parse(result)
			if(result[2].length > 0){
				if(result[2][0] == "" && result[2][1]){
					message.channel.sendMessage(message.author+" "+result[2][1])
				} else if(result[2][0] != "") {
					message.channel.sendMessage(message.author+" "+result[2][0])
				} else {
					message.channel.sendMessage(message.author+" Je ne trouve rien à propos de "+matching.regexResult[1]+". Essayez https://duckduckgo.com/?q="+matching.regexResult[1])
				}
			} else {
				message.channel.sendMessage(message.author+" Je ne trouve rien à propos de "+matching.regexResult[1]+". Essayez https://duckduckgo.com/?q="+matching.regexResult[1])
			}
		} catch(e) {
			console.error(e)
			message.channel.sendMessage(message.author+" Whoops, j'ai une érreur... proposez autre chose peut être...")
		}
	})
}<|endoftext|>