<commit_before>/* eslint-disable max-len */

import React, { Component, PropTypes } from 'react'
import moment from 'moment'
import $ from 'jquery'
import styled from 'styled-components'
import { observer, inject } from 'mobx-react'
import compose from 'recompose/compose'

import isDateField from '../../src/isDateField'
import validateDate from '../../src/validateDate'
import AreaGeschaeft from './AreaGeschaeft'
import AreaNummern from './AreaNummern'
import AreaFristen from './AreaFristen'
import AreaParlVorstoss from './AreaParlVorstoss'
import AreaRechtsmittel from './AreaRechtsmittel'
import AreaPersonen from './AreaPersonen'
import AreaHistory from './AreaHistory'
import AreaLinks from './AreaLinks'
import AreaZuletztMutiert from './AreaZuletztMutiert'

moment.locale('de')

const ScrollContainerRegular = styled.div`
  height: calc(100vh - 52px);
  overflow-y: auto;
  overflow-x: hidden;
`
const ScrollContainerPdf = styled.div`
  overflow: visible;
  height: 26cm;
`
const WrapperNarrow = styled.div`
  display: grid;
  grid-template-columns: repeat(1, 100%);
  grid-template-rows: auto;
  grid-template-areas:
    "areaNummern"
    "areaGeschaeft"
    "areaForGeschaeftsart"
    "areaFristen"
    "areaPersonen"
    "areaLinks"
    "areaHistory"
    "areaZuletztMutiert";
`
const WrapperNarrowNoAreaForGeschaeftsart = styled(WrapperNarrow)`
  grid-template-areas:
    "areaNummern"
    "areaGeschaeft"
    "areaFristen"
    "areaPersonen"
    "areaLinks"
    "areaHistory"
    "areaZuletztMutiert";
`
const WrapperWide = styled.div`
  display: grid;
  grid-template-columns: repeat(12, 8.33333%);
  grid-template-rows: auto;
  grid-template-areas:
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart"
    "areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
    "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
    "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
    "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`
const WrapperPdf = styled(WrapperWide)`
  max-height: 26cm;
  overflow: hidden;
  max-width: 180mm;
  grid-template-columns: repeat(12, 15mm);
`
const WrapperWidePdf = styled(WrapperPdf)`
  grid-template-areas:
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart"
    "areaFristen areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
    "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
    "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
    "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`
const WrapperWideNoAreaForGeschaeftsart = styled(WrapperWide)`
  grid-template-areas:
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
    "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
    "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
    "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`
const WrapperWideNoAreaForGeschaeftsartPdf = styled(WrapperPdf)`
    grid-template-areas:
      "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
      "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
      "areaFristen areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
      "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
      "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
      "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`

const enhance = compose(
  inject('store'),
  observer
)

class Geschaeft extends Component {
  static propTypes = {
    store: PropTypes.object.isRequired,
  }

  onChangeDatePicker = (name, e, picker) => {
    const rVal = {
      target: {
        type: 'text',
        name,
        value: picker.startDate,
      }
    }
    this.blur(rVal)
  }

  change = (e) => {
    const { store } = this.props
    const { changeGeschaeftInDb, geschaefteChangeState } = store
    const {
      activeId,
      geschaeftePlusFilteredAndSorted: geschaefte,
    } = store.geschaefte
    const geschaeft = geschaefte.find(g =>
      g.idGeschaeft === activeId
    )
    const {
      type,
      name,
      dataset,
    } = e.target
    let { value } = e.target
    if (type === 'radio') {
      // need to set null if existing value was clicked
      if (geschaeft[name] === dataset.value) {
        value = ''
      } else {
        value = dataset.value
      }
      // blur does not occur in radio
      changeGeschaeftInDb(activeId, name, value)
    }
    if (type === 'select-one') {
      changeGeschaeftInDb(activeId, name, value)
    }
    geschaefteChangeState(activeId, name, value)
  }

  blur = (e) => {
    const { store } = this.props
    const { changeGeschaeftInDb, geschaefteChangeState } = store
    const { activeId } = store.geschaefte
    const {
      type,
      name,
    } = e.target
    const { value } = e.target
    if (type !== 'radio' && type !== 'select-one') {
      if (isDateField(name)) {
        if (validateDate(value)) {
          // if correct date, save to db
          changeGeschaeftInDb(activeId, name, value)
        }
        // else: give user hint
        let value2 = ''
        if (value) value2 = moment(value, 'DD.MM.YYYY').format('DD.MM.YYYY')
        if (value2.includes('Invalid date')) {
          value2 = value2.replace('Invalid date', 'Format: DD.MM.YYYY')
        }
        geschaefteChangeState(activeId, name, value2)
      } else {
        changeGeschaeftInDb(activeId, name, value)
      }
    }
  }

  render = () => {
    const { store } = this.props
    const {
      activeId,
      geschaeftePlusFilteredAndSorted: geschaefte,
    } = store.geschaefte
    const path = store.history.location.pathname
    const { config } = store.app
    const isPrintPreview = path === '/geschaeftPdf'
    const geschaeft = geschaefte.find(g =>
      g.idGeschaeft === activeId
    )

    // return immediately if no geschaeft
    const showGeschaeft = geschaeft && geschaeft.idGeschaeft
    if (!showGeschaeft) return null

    const showAreaParlVorstoss = (
      geschaeft.geschaeftsart === 'Parlament. Vorstoss' &&
      !(
        isPrintPreview &&
        !geschaeft.parlVorstossStufe &&
        !geschaeft.parlVorstossZustaendigkeitAwel &&
        !geschaeft.parlVorstossTyp
      )
    )
    const showAreaRechtsmittel = (
      geschaeft.geschaeftsart === 'Rekurs/Beschwerde' &&
      !(
        isPrintPreview &&
        !geschaeft.rechtsmittelInstanz &&
        !geschaeft.rechtsmittelEntscheidNr &&
        !geschaeft.rechtsmittelEntscheidDatum &&
        !geschaeft.rechtsmittelErledigung &&
        !geschaeft.rechtsmittelTxt
      )
    )
    const showAreaForGeschaeftsart = (
      showAreaParlVorstoss ||
      showAreaRechtsmittel
    )

    // need width to adapt layout to differing widths
    const windowWidth = $(window).width()
    const areaGeschaefteWidth = windowWidth - config.geschaefteColumnWidth

    // prepare tab indexes
    const nrOfGFields = 10
    const nrOfNrFields = 13
    const nrOfFieldsBeforePv = nrOfGFields + nrOfNrFields
    const nrOfPvFields = 9
    const nrOfFieldsBeforeFristen = nrOfFieldsBeforePv + nrOfPvFields
    const nrOfFieldsBeforePersonen = nrOfFieldsBeforeFristen + 7
    const viewIsNarrow = areaGeschaefteWidth < 860
    let ScrollContainer = ScrollContainerRegular
    if (isPrintPreview) ScrollContainer = ScrollContainerPdf
    let Wrapper
    if (isPrintPreview) {
      if (showAreaForGeschaeftsart) {
        Wrapper = WrapperWidePdf
      } else {
        Wrapper = WrapperWideNoAreaForGeschaeftsartPdf
      }
    } else if (viewIsNarrow) {
      if (showAreaForGeschaeftsart) {
        Wrapper = WrapperNarrow
      } else {
        Wrapper = WrapperNarrowNoAreaForGeschaeftsart
      }
    } else if (showAreaForGeschaeftsart) {
      Wrapper = WrapperWide
    } else {
      Wrapper = WrapperWideNoAreaForGeschaeftsart
    }

    const showLinks = !(isPrintPreview && geschaeft.links.length === 0)

    return (
      <ScrollContainer>
        <Wrapper isPrintPreview={isPrintPreview}>
          <AreaGeschaeft
            viewIsNarrow={viewIsNarrow}
            nrOfGFields={nrOfGFields}
            change={this.change}
            blur={this.blur}
          />
          <AreaNummern
            viewIsNarrow={viewIsNarrow}
            nrOfGFields={nrOfGFields}
            change={this.change}
            blur={this.blur}
          />
          {
            showAreaParlVorstoss &&
            <AreaParlVorstoss
              nrOfFieldsBeforePv={nrOfFieldsBeforePv}
              change={this.change}
            />
          }
          {
            showAreaRechtsmittel &&
            <AreaRechtsmittel
              nrOfFieldsBeforePv={nrOfFieldsBeforePv}
              change={this.change}
              blur={this.blur}
              onChangeDatePicker={this.onChangeDatePicker}
            />
          }
          <AreaFristen
            nrOfFieldsBeforeFristen={nrOfFieldsBeforeFristen}
            change={this.change}
            blur={this.blur}
            onChangeDatePicker={this.onChangeDatePicker}
          />
          <AreaPersonen
            nrOfFieldsBeforePersonen={nrOfFieldsBeforePersonen}
            change={this.change}
          />
          {
            showLinks &&
            <AreaLinks
              links={geschaeft.links}
            />
          }
          <AreaHistory
            blur={this.blur}
            change={this.change}
          />
          <AreaZuletztMutiert />
        </Wrapper>
      </ScrollContainer>
    )
  }
}

export default enhance(Geschaeft)
<commit_msg>Repair<commit_after>/* eslint-disable max-len */

import React, { Component, PropTypes } from 'react'
import moment from 'moment'
import $ from 'jquery'
import styled from 'styled-components'
import { observer, inject } from 'mobx-react'
import compose from 'recompose/compose'

import isDateField from '../../src/isDateField'
import validateDate from '../../src/validateDate'
import AreaGeschaeft from './AreaGeschaeft'
import AreaNummern from './AreaNummern'
import AreaFristen from './AreaFristen'
import AreaParlVorstoss from './AreaParlVorstoss'
import AreaRechtsmittel from './AreaRechtsmittel'
import AreaPersonen from './AreaPersonen'
import AreaHistory from './AreaHistory'
import AreaLinks from './AreaLinks'
import AreaZuletztMutiert from './AreaZuletztMutiert'

moment.locale('de')

const ScrollContainerRegular = styled.div`
  height: calc(100vh - 52px);
  overflow-y: auto;
  overflow-x: hidden;
`
const ScrollContainerPdf = styled.div`
  overflow: visible;
  height: 26cm;
`
const WrapperNarrow = styled.div`
  display: grid;
  grid-template-columns: repeat(1, 100%);
  grid-template-rows: auto;
  grid-template-areas:
    "areaNummern"
    "areaGeschaeft"
    "areaForGeschaeftsart"
    "areaFristen"
    "areaPersonen"
    "areaLinks"
    "areaHistory"
    "areaZuletztMutiert";
`
const WrapperNarrowNoAreaForGeschaeftsart = styled(WrapperNarrow)`
  grid-template-areas:
    "areaNummern"
    "areaGeschaeft"
    "areaFristen"
    "areaPersonen"
    "areaLinks"
    "areaHistory"
    "areaZuletztMutiert";
`
const WrapperWide = styled.div`
  display: grid;
  grid-template-columns: repeat(12, 8.33333%);
  grid-template-rows: auto;
  grid-template-areas:
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart"
    "areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
    "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
    "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
    "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`
const WrapperPdf = styled(WrapperWide)`
  max-height: 26cm;
  overflow: hidden;
  max-width: 180mm;
  grid-template-columns: repeat(12, 15mm);
`
const WrapperWidePdf = styled(WrapperPdf)`
  grid-template-areas:
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart areaForGeschaeftsart"
    "areaFristen areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
    "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
    "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
    "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`
const WrapperWideNoAreaForGeschaeftsart = styled(WrapperWide)`
  grid-template-areas:
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
    "areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
    "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
    "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
    "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`
const WrapperWideNoAreaForGeschaeftsartPdf = styled(WrapperPdf)`
    grid-template-areas:
      "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
      "areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaGeschaeft areaNummern areaNummern areaNummern areaNummern"
      "areaFristen areaFristen areaFristen areaFristen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen areaPersonen"
      "areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks areaLinks"
      "areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory areaHistory"
      "areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert areaZuletztMutiert";
`

const enhance = compose(
  inject('store'),
  observer
)

class Geschaeft extends Component {
  static propTypes = {
    store: PropTypes.object.isRequired,
  }

  onChangeDatePicker = (name, e, picker) => {
    const rVal = {
      target: {
        type: 'text',
        name,
        value: picker.startDate,
      }
    }
    this.blur(rVal)
  }

  change = (e) => {
    const { store } = this.props
    const { changeGeschaeftInDb, geschaefteChangeState } = store
    const {
      activeId,
      geschaeftePlusFilteredAndSorted: geschaefte,
    } = store.geschaefte
    const geschaeft = geschaefte.find(g =>
      g.idGeschaeft === activeId
    )
    const {
      type,
      name,
      dataset,
    } = e.target
    let { value } = e.target
    if (type === 'radio') {
      // need to set null if existing value was clicked
      if (geschaeft[name] === dataset.value) {
        value = ''
      } else {
        value = dataset.value
      }
      // blur does not occur in radio
      changeGeschaeftInDb(activeId, name, value)
    }
    if (type === 'select-one') {
      changeGeschaeftInDb(activeId, name, value)
    }
    geschaefteChangeState(activeId, name, value)
  }

  blur = (e) => {
    const { store } = this.props
    const { changeGeschaeftInDb, geschaefteChangeState } = store
    const { activeId } = store.geschaefte
    const { type, name, value } = e.target
    if (type !== 'radio' && type !== 'select-one') {
      if (isDateField(name)) {
        if (validateDate(value)) {
          // if correct date, save to db
          changeGeschaeftInDb(activeId, name, value)
        }
        // else: give user hint
        let value2 = ''
        if (value) value2 = moment(value, 'DD.MM.YYYY').format('DD.MM.YYYY')
        if (value2.includes('Invalid date')) {
          value2 = value2.replace('Invalid date', 'Format: DD.MM.YYYY')
        }
        geschaefteChangeState(activeId, name, value2)
      } else {
        changeGeschaeftInDb(activeId, name, value)
      }
    }
  }

  render() {
    const { store } = this.props
    const {
      activeId,
      geschaeftePlusFilteredAndSorted: geschaefte,
    } = store.geschaefte
    const { config } = store.app
    const path = store.history.location.pathname
    const isPrintPreview = path === '/geschaeftPdf'
    const geschaeft = geschaefte.find(g =>
      g.idGeschaeft === activeId
    )

    // return immediately if no geschaeft
    const showGeschaeft = geschaeft && geschaeft.idGeschaeft
    if (!showGeschaeft) return null

    const showAreaParlVorstoss = (
      geschaeft.geschaeftsart === 'Parlament. Vorstoss' &&
      !(
        isPrintPreview &&
        !geschaeft.parlVorstossStufe &&
        !geschaeft.parlVorstossZustaendigkeitAwel &&
        !geschaeft.parlVorstossTyp
      )
    )
    const showAreaRechtsmittel = (
      geschaeft.geschaeftsart === 'Rekurs/Beschwerde' &&
      !(
        isPrintPreview &&
        !geschaeft.rechtsmittelInstanz &&
        !geschaeft.rechtsmittelEntscheidNr &&
        !geschaeft.rechtsmittelEntscheidDatum &&
        !geschaeft.rechtsmittelErledigung &&
        !geschaeft.rechtsmittelTxt
      )
    )
    const showAreaForGeschaeftsart = (
      showAreaParlVorstoss ||
      showAreaRechtsmittel
    )

    // need width to adapt layout to differing widths
    const windowWidth = $(window).width()
    const areaGeschaefteWidth = windowWidth - config.geschaefteColumnWidth

    // prepare tab indexes
    const nrOfGFields = 10
    const nrOfNrFields = 13
    const nrOfFieldsBeforePv = nrOfGFields + nrOfNrFields
    const nrOfPvFields = 9
    const nrOfFieldsBeforeFristen = nrOfFieldsBeforePv + nrOfPvFields
    const nrOfFieldsBeforePersonen = nrOfFieldsBeforeFristen + 7
    const viewIsNarrow = areaGeschaefteWidth < 860
    let ScrollContainer = ScrollContainerRegular
    if (isPrintPreview) ScrollContainer = ScrollContainerPdf
    let Wrapper
    if (isPrintPreview) {
      if (showAreaForGeschaeftsart) {
        Wrapper = WrapperWidePdf
      } else {
        Wrapper = WrapperWideNoAreaForGeschaeftsartPdf
      }
    } else if (viewIsNarrow) {
      if (showAreaForGeschaeftsart) {
        Wrapper = WrapperNarrow
      } else {
        Wrapper = WrapperNarrowNoAreaForGeschaeftsart
      }
    } else if (showAreaForGeschaeftsart) {
      Wrapper = WrapperWide
    } else {
      Wrapper = WrapperWideNoAreaForGeschaeftsart
    }

    const showLinks = !(isPrintPreview && geschaeft.links.length === 0)

    return (
      <ScrollContainer>
        <Wrapper isPrintPreview={isPrintPreview}>
          <AreaGeschaeft
            viewIsNarrow={viewIsNarrow}
            nrOfGFields={nrOfGFields}
            change={this.change}
            blur={this.blur}
          />
          <AreaNummern
            viewIsNarrow={viewIsNarrow}
            nrOfGFields={nrOfGFields}
            change={this.change}
            blur={this.blur}
          />
          {
            showAreaParlVorstoss &&
            <AreaParlVorstoss
              nrOfFieldsBeforePv={nrOfFieldsBeforePv}
              change={this.change}
            />
          }
          {
            showAreaRechtsmittel &&
            <AreaRechtsmittel
              nrOfFieldsBeforePv={nrOfFieldsBeforePv}
              change={this.change}
              blur={this.blur}
              onChangeDatePicker={this.onChangeDatePicker}
            />
          }
          <AreaFristen
            nrOfFieldsBeforeFristen={nrOfFieldsBeforeFristen}
            change={this.change}
            blur={this.blur}
            onChangeDatePicker={this.onChangeDatePicker}
          />
          <AreaPersonen
            nrOfFieldsBeforePersonen={nrOfFieldsBeforePersonen}
            change={this.change}
          />
          {
            showLinks &&
            <AreaLinks
              links={geschaeft.links}
            />
          }
          <AreaHistory
            blur={this.blur}
            change={this.change}
          />
          <AreaZuletztMutiert />
        </Wrapper>
      </ScrollContainer>
    )
  }
}

export default enhance(Geschaeft)
<|endoftext|>


<commit_before>/*
 *  Copyright 2014 TWO SIGMA OPEN SOURCE, LLC
 *
 *  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.
 */

var BeakerPageObject = require('../../beaker.po.js');
var beakerPO;

describe('Progress Reporting API', function () {

    beforeAll(function(done){
        beakerPO = new BeakerPageObject();
        browser.get(beakerPO.baseURL + "beaker/#/open?uri=file:config%2Ftutorials%2FprogressUpdate.bkr&readOnly=true").then(done);
        beakerPO.waitUntilLoadingCellOutput();
    });

    afterAll(function(done){
        beakerPO.createScreenshot('progressAPITutorial');
        done();
    });

    function checkProgressBar(idCell, label){
        return browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('div.progress-bar', label))), 15000).then(
            function(result){return true;},
            function(error){
                expect(error).toBe('progress bar should display ' + label);
            });
    };

    function checkProgressMessage(idCell, label){
        return browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('div[ng-if="hasMessage()"]', label))), 15000).then(
            function(result){return true;},
            function(error){
                expect(error).toBe('progress message should display ' + label);
            });
    };

    function checkProgressTopBar(idCell, label){
        return browser.wait(beakerPO.EC.presenceOf(element(by.cssContainingText('div.navbar-text', label))), 15000).then(
            function(result){return true;},
            function(error){
                expect(error).toBe('progress top Beaker bar should display ' + label);
            });
    };

    it('Display progress by Groovy', function () {
        var idCell = "codeXnQmyX";
        beakerPO.scrollToBkCellByIdCell(idCell);
        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Progress');
        checkProgressMessage(idCell, 'starting')
        .then(checkProgressBar.bind(this, idCell, '20 %'))
        .then(checkProgressMessage.bind(this, idCell, 'started'))
        .then(checkProgressBar.bind(this, idCell, '40 %'))
        .then(checkProgressMessage.bind(this, idCell, 'begin'))
        .then(checkProgressBar.bind(this, idCell, '60 %'))
        .then(checkProgressMessage.bind(this, idCell, 'middle'))
        .then(checkProgressBar.bind(this, idCell, '80 %'));
        browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('pre', 'finished'))), 10000);
    });

    it('Display progress by JavaScript', function () {
        var idCell = "codeOw6722";
        beakerPO.scrollToBkCellByIdCell(idCell);
        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Text');
        /*
         Skip check because protractor waiting for the end of progress bar. (The check works well with code 'setTimeout(operation,1500)')
        checkProgressMessage(idCell, 'working');
        checkProgressBar(idCell, '20 %');
        checkProgressMessage(idCell, 'working');
        checkProgressBar(idCell, '40 %');
        checkProgressMessage(idCell, 'still working');
        checkProgressBar(idCell, '60 %');
        checkProgressMessage(idCell, 'still working');
        checkProgressBar(idCell, '80 %');
        */
        browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('pre', 'FINISHED (finally)'))), 25000);
    });

    it('Display progress by Java', function () {
        var idCell = "codefgkSlJ";
        beakerPO.scrollToBkCellByIdCell(idCell);
        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Progress');
        checkProgressMessage(idCell, 'starting')
        .then(checkProgressBar.bind(this, idCell, '20 %'))
        .then(checkProgressMessage.bind(this, idCell, 'started'))
        .then(checkProgressBar.bind(this, idCell, '40 %'))
        .then(checkProgressMessage.bind(this, idCell, 'begin'))
        .then(checkProgressBar.bind(this, idCell, '60 %'))
        .then(checkProgressMessage.bind(this, idCell, 'middle'))
        .then(checkProgressBar.bind(this, idCell, '80 %'));
    });

    it('Display progress on top Beaker bar', function () {
        var idCell = "codeJg1qDx";
        beakerPO.scrollToBkCellByIdCell(idCell);

        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Text');
        /*
         Skip check because protractor waiting for the end of progress bar. (The check works well with code 'setTimeout(operation,1500)')
         checkProgressTopBar(idCell, 'working at 20');
         checkProgressTopBar(idCell, 'working at 40');
         checkProgressTopBar(idCell, 'still working at 60');
         checkProgressTopBar(idCell, 'still working at 80');
         */
        browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('pre', 'FINISHED (finally)'))), 25000);
    });

});<commit_msg>fix test<commit_after>/*
 *  Copyright 2014 TWO SIGMA OPEN SOURCE, LLC
 *
 *  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.
 */

var BeakerPageObject = require('../../beaker.po.js');
var beakerPO;

describe('Progress Reporting API', function () {

    beforeAll(function(done){
        beakerPO = new BeakerPageObject();
        browser.get(beakerPO.baseURL + "beaker/#/open?uri=file:config%2Ftutorials%2FprogressUpdate.bkr&readOnly=true").then(done);
        beakerPO.waitUntilLoadingCellOutput();
    });

    afterAll(function(done){
        beakerPO.createScreenshot('progressAPITutorial');
        done();
    });

    function checkProgressBar(idCell, label){
        return browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('div.progress-bar', label))), 15000).then(
            function(result){return true;},
            function(error){
                expect(error).toBe('progress bar should display ' + label);
            });
    };

    function checkProgressMessage(idCell, label){
        return browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('div[ng-if="hasMessage()"]', label))), 15000).then(
            function(result){return true;},
            function(error){
                expect(error).toBe('progress message should display ' + label);
            });
    };

    function checkProgressTopBar(idCell, label){
        return browser.wait(beakerPO.EC.presenceOf(element(by.cssContainingText('div.navbar-text', label))), 15000).then(
            function(result){return true;},
            function(error){
                expect(error).toBe('progress top Beaker bar should display ' + label);
            });
    };

    it('Display progress by Groovy', function () {
        var idCell = "codeXnQmyX";
        beakerPO.scrollToBkCellByIdCell(idCell);
        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Progress');
        checkProgressMessage(idCell, 'starting')
            .then(checkProgressBar.bind(this, idCell, '20 %'))
            .then(checkProgressMessage.bind(this, idCell, 'about to finish'));
        browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('pre', 'finished'))), 10000);
    });

    it('Display progress by Java', function () {
        var idCell = "codefgkSlJ";
        beakerPO.scrollToBkCellByIdCell(idCell);
        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Progress');
        checkProgressMessage(idCell, 'starting')
            .then(checkProgressBar.bind(this, idCell, '20 %'))
            .then(checkProgressMessage.bind(this, idCell, 'about to finish'));
    });

    it('Display progress by JavaScript', function () {
        var idCell = "codeOw6722";
        beakerPO.scrollToBkCellByIdCell(idCell);
        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Text');
        /*
         Skip check because protractor waiting for the end of progress bar. (The check works well with code 'setTimeout(operation,1500)')
        checkProgressMessage(idCell, 'working');
        checkProgressBar(idCell, '20 %');
        checkProgressMessage(idCell, 'working');
        checkProgressBar(idCell, '40 %');
        checkProgressMessage(idCell, 'still working');
        checkProgressBar(idCell, '60 %');
        checkProgressMessage(idCell, 'still working');
        checkProgressBar(idCell, '80 %');
        */
        browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('pre', 'FINISHED (finally)'))), 25000);
    });

    it('Display progress on top Beaker bar', function () {
        var idCell = "codeJg1qDx";
        beakerPO.scrollToBkCellByIdCell(idCell);

        beakerPO.clickCodeCellInputButtonByIdCell(idCell, 'Text');
        /*
         Skip check because protractor waiting for the end of progress bar. (The check works well with code 'setTimeout(operation,1500)')
         checkProgressTopBar(idCell, 'working at 20');
         checkProgressTopBar(idCell, 'working at 40');
         checkProgressTopBar(idCell, 'still working at 60');
         checkProgressTopBar(idCell, 'still working at 80');
         */
        browser.wait(beakerPO.EC.presenceOf(beakerPO.getCodeCellOutputByIdCell(idCell).element(by.cssContainingText('pre', 'FINISHED (finally)'))), 25000);
    });

});<|endoftext|>


<commit_before>/**
 * @fileOverview In charge of dealing with the editable target.
 * This module detects the resize of the target element and provides
 * interface for getting and setting the content of the target
 * element. It also provides inserting link (by emulating text input)
 * interface for other seamless posting modules.
 *
 * This module will handle and make respond to the following Privly messages:
 *    posting/contentScript/getTargetContent
 *      Get the content of the editable element.
 *      Returns value for textareas and innerHTML for contentEditable elements.
 *    posting/contentScript/getTargetText
 *      Get the text content of the editable element.
 *      Returns value for textareas and innerText for contentEditable elements.
 *    posting/contentScript/setTargetText
 *      Set the text content of the editable element.
 *      Set value for textareas and innerText for contentEditable elements.
 *    posting/contentScript/emitEnterEvent
 *      Emulate a key enter event on the target element with the given modify key.
 *    posting/contentScript/insertLink
 *      Insert link by emulating text input events to the target element.
 *
 * This module will broadcast the following internal
 * messages to other modules:
 *
 *    posting/internal/targetPositionChanged
 *        when the size or the position of the target element has changed
 */
/*global SeamlessPosting */
// If Privly namespace is not initialized, initialize it
var SeamlessPosting;
if (SeamlessPosting === undefined) {
  SeamlessPosting = {};
}
(function () {

  // If this file is already loaded, don't do it again
  if (SeamlessPosting.Target !== undefined) {
    return;
  }

  /**
   * SeamlessPosting.Target receives the DOM of an editable element
   * and provide manipulation interface for the element.
   *
   * @class
   * @augments NodeResourceItem
   *
   * @param {Element} target The editable element
   */
  var Target = function (target) {
    this.setNode(target);
    this.addMessageListeners();
  };

  Target.prototype = Object.create(SeamlessPosting.NodeResourceItem.prototype);
  Target.super = SeamlessPosting.NodeResourceItem.prototype;

  /**
   * Override default destroy method behaviour of NodeResourceItem because
   * our target element should not be destroyed and we also want to
   * stop the resize monitor.
   *
   * @override
   */
  Target.prototype.destroy = function () {
    this.stopResizeMonitor();
  };

  /**
   * Add message listeners
   *
   * @override
   */
  Target.prototype.addMessageListeners = function () {
    Target.super.addMessageListeners.call(this);
    this.addMessageListener('posting/internal/stateChanged', this.onStateChanged.bind(this));
    this.addMessageListener('posting/internal/targetActivated', this.onTargetActivated.bind(this));
    this.addMessageListener('posting/internal/targetDeactivated', this.onTargetDeactivated.bind(this));
    this.addMessageListener('posting/contentScript/getTargetContent', this.onGetTargetContent.bind(this));
    this.addMessageListener('posting/contentScript/getTargetText', this.onGetTargetText.bind(this));
    this.addMessageListener('posting/contentScript/setTargetText', this.onSetTargetText.bind(this));
    this.addMessageListener('posting/contentScript/emitEnterEvent', this.onEmitEnterEvent.bind(this));
    this.addMessageListener('posting/contentScript/insertLink', this.onInsertLink.bind(this));
  };

  /**
   * If the seamless-posting App is closed, we need to re-focus
   * the target element.
   */
  Target.prototype.onStateChanged = function (message) {
    this.state = message.state;
    switch (message.state) {
    case 'OPEN':
      this.detectResize();
      break;
    case 'CLOSE':
      this.getNode().focus();
      break;
    }
    this.updateResizeMonitor();
  };

  /**
   * When target element is activated
   */
  Target.prototype.onTargetActivated = function () {
    this.activated = true;
    this.updateResizeMonitor();
  };

  /**
   * When target element is deactivated
   */
  Target.prototype.onTargetDeactivated = function () {
    this.activated = false;
    this.updateResizeMonitor();
  };

  /**
   * Determine whether the resize monitor timer should be started or stoped
   * according to the state (open or not) and activate state (focused or not)
   */
  Target.prototype.updateResizeMonitor = function () {
    if (this.activated || this.state === 'OPEN') {
      this.startResizeMonitor();
    } else if (!this.activated && this.state === 'CLOSE') {
      this.stopResizeMonitor();
    }
  };

  /**
   * Respond to getTargetContent message
   */
  Target.prototype.onGetTargetContent = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        sendResponse(this.getNode().value);
      } else {
        sendResponse(this.getNode().innerHTML);
      }
    }
  };

  /**
   * Respond to getTargetText message
   */
  Target.prototype.onGetTargetText = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        sendResponse(this.getNode().value);
      } else {
        sendResponse(this.getNode().innerText);
      }
    }
  };

  /**
   * Respond to setTargetText message
   */
  Target.prototype.onSetTargetText = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        this.getNode().value = message.text;
      } else {
        this.getNode().innerText = message.text;
      }
    }
  };

  /**
   * Respond to emitEnterEvent message
   */
  Target.prototype.onEmitEnterEvent = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keydown', 13, message.keys);
      SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keypress', 13, message.keys);
      SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keyup', 13, message.keys);
      sendResponse(true);
    }
  };

  /**
   * Respond to insertLink message
   */
  Target.prototype.onInsertLink = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        this.getNode().value = '';
      } else {
        this.getNode().innerHTML = '';
      }
      this.receiveURL(message.link);
      sendResponse(true);
    }
  };

  /**
   * Create an event if the target is resized or re-positioned.
   */
  Target.prototype.detectResize = function () {
    if (!this.isValid()) {
      this.stopResizeMonitor();
      return;
    }
    // only available when it is attached to a resource
    if (!this.resource) {
      return;
    }
    var node = this.getNode();
    var position = SeamlessPosting.util.position(node);
    var box = node.getClientRects()[0];
    if (
      box.width !== this._width || box.height !== this._height ||
        position.left !== this._left || position.top !== this._top
    ) {
      this.resource.broadcastInternal({
        action: 'posting/internal/targetPositionChanged'
      });
    }
  };

  /**
   * Start monitoring target resizing
   */
  Target.prototype.startResizeMonitor = function () {
    if (this.resizeMonitor) {
      return;
    }
    this.resizeMonitor = setInterval(this.detectResize.bind(this), 300);
  };

  /**
   * Stop monitoring target resizing
   */
  Target.prototype.stopResizeMonitor = function () {
    if (!this.resizeMonitor) {
      return;
    }
    clearInterval(this.resizeMonitor);
    this.resizeMonitor = null;
  };

  /**
   * Place the URL into the host page and fire
   * the appropriate events to get the host page
   * to process the link.
   *
   * @param  {String} url The URL to insert into the editable element
   */
  Target.prototype.receiveURL = function (url) {
    // For efficiency, we directly insert all characters at once.
    SeamlessPosting.util.dispatchTextEvent(this.getNode(), 'textInput', url);

    // Then we emulate inputing a space
    var ch = ' ';
    var chCode = ch.charCodeAt(0);
    SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keydown', chCode);
    SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keypress', chCode);
    SeamlessPosting.util.dispatchTextEvent(this.getNode(), 'textInput', ch);
    SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keyup', chCode);
  };

  SeamlessPosting.Target = Target;

}());
<commit_msg>fix bug<commit_after>/**
 * @fileOverview In charge of dealing with the editable target.
 * This module detects the resize of the target element and provides
 * interface for getting and setting the content of the target
 * element. It also provides inserting link (by emulating text input)
 * interface for other seamless posting modules.
 *
 * This module will handle and make respond to the following Privly messages:
 *    posting/contentScript/getTargetContent
 *      Get the content of the editable element.
 *      Returns value for textareas and innerHTML for contentEditable elements.
 *    posting/contentScript/getTargetText
 *      Get the text content of the editable element.
 *      Returns value for textareas and innerText for contentEditable elements.
 *    posting/contentScript/setTargetText
 *      Set the text content of the editable element.
 *      Set value for textareas and innerText for contentEditable elements.
 *    posting/contentScript/emitEnterEvent
 *      Emulate a key enter event on the target element with the given modify key.
 *    posting/contentScript/insertLink
 *      Insert link by emulating text input events to the target element.
 *
 * This module will broadcast the following internal
 * messages to other modules:
 *
 *    posting/internal/targetPositionChanged
 *        when the size or the position of the target element has changed
 */
/*global SeamlessPosting */
// If Privly namespace is not initialized, initialize it
var SeamlessPosting;
if (SeamlessPosting === undefined) {
  SeamlessPosting = {};
}
(function () {

  // If this file is already loaded, don't do it again
  if (SeamlessPosting.Target !== undefined) {
    return;
  }

  /**
   * SeamlessPosting.Target receives the DOM of an editable element
   * and provide manipulation interface for the element.
   *
   * @class
   * @augments NodeResourceItem
   *
   * @param {Element} target The editable element
   */
  var Target = function (target) {
    this.setNode(target);
    this.addMessageListeners();
  };

  Target.prototype = Object.create(SeamlessPosting.NodeResourceItem.prototype);
  Target.super = SeamlessPosting.NodeResourceItem.prototype;

  /**
   * Override default destroy method behaviour of NodeResourceItem because
   * our target element should not be destroyed and we also want to
   * stop the resize monitor.
   *
   * @override
   */
  Target.prototype.destroy = function () {
    this.stopResizeMonitor();
  };

  /**
   * Add message listeners
   *
   * @override
   */
  Target.prototype.addMessageListeners = function () {
    Target.super.addMessageListeners.call(this);
    this.addMessageListener('posting/internal/stateChanged', this.onStateChanged.bind(this));
    this.addMessageListener('posting/internal/targetActivated', this.onTargetActivated.bind(this));
    this.addMessageListener('posting/internal/targetDeactivated', this.onTargetDeactivated.bind(this));
    this.addMessageListener('posting/contentScript/getTargetContent', this.onGetTargetContent.bind(this));
    this.addMessageListener('posting/contentScript/getTargetText', this.onGetTargetText.bind(this));
    this.addMessageListener('posting/contentScript/setTargetText', this.onSetTargetText.bind(this));
    this.addMessageListener('posting/contentScript/emitEnterEvent', this.onEmitEnterEvent.bind(this));
    this.addMessageListener('posting/contentScript/insertLink', this.onInsertLink.bind(this));
  };

  /**
   * If the seamless-posting App is closed, we need to re-focus
   * the target element.
   */
  Target.prototype.onStateChanged = function (message) {
    this.state = message.state;
    switch (message.state) {
    case 'OPEN':
      this.detectResize();
      break;
    case 'CLOSE':
      this.getNode().focus();
      break;
    }
    this.updateResizeMonitor();
  };

  /**
   * When target element is activated
   */
  Target.prototype.onTargetActivated = function () {
    this.activated = true;
    this.updateResizeMonitor();
  };

  /**
   * When target element is deactivated
   */
  Target.prototype.onTargetDeactivated = function () {
    this.activated = false;
    this.updateResizeMonitor();
  };

  /**
   * Determine whether the resize monitor timer should be started or stoped
   * according to the state (open or not) and activate state (focused or not)
   */
  Target.prototype.updateResizeMonitor = function () {
    if (this.activated || this.state === 'OPEN') {
      this.startResizeMonitor();
    } else if (!this.activated && this.state === 'CLOSE') {
      this.stopResizeMonitor();
    }
  };

  /**
   * Respond to getTargetContent message
   */
  Target.prototype.onGetTargetContent = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        sendResponse(this.getNode().value);
      } else {
        sendResponse(this.getNode().innerHTML);
      }
    }
  };

  /**
   * Respond to getTargetText message
   */
  Target.prototype.onGetTargetText = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        sendResponse(this.getNode().value);
      } else {
        sendResponse(this.getNode().innerText);
      }
    }
  };

  /**
   * Respond to setTargetText message
   */
  Target.prototype.onSetTargetText = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        this.getNode().value = message.text;
      } else {
        this.getNode().innerText = message.text;
      }
    }
  };

  /**
   * Respond to emitEnterEvent message
   */
  Target.prototype.onEmitEnterEvent = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keydown', 13, message.keys);
      SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keypress', 13, message.keys);
      SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keyup', 13, message.keys);
      sendResponse(true);
    }
  };

  /**
   * Respond to insertLink message
   */
  Target.prototype.onInsertLink = function (message, sendResponse) {
    if (!this.isValid()) {
      sendResponse(false);
    } else {
      if (this.getNode().nodeName === 'TEXTAREA') {
        this.getNode().value = '';
      } else {
        this.getNode().innerHTML = '';
      }
      this.receiveURL(message.link);
      sendResponse(true);
    }
  };

  /**
   * Create an event if the target is resized or re-positioned.
   */
  Target.prototype.detectResize = function () {
    if (!this.isValid()) {
      this.stopResizeMonitor();
      return;
    }
    // only available when it is attached to a resource
    if (!this.resource) {
      this.stopResizeMonitor();
      return;
    }
    var node = this.getNode();
    var position = SeamlessPosting.util.position(node);
    var box = node.getClientRects()[0];
    if (box == undefined) {
      this.stopResizeMonitor();
      return;
    }
    if (
      box.width !== this._width || box.height !== this._height ||
        position.left !== this._left || position.top !== this._top
    ) {
      this.resource.broadcastInternal({
        action: 'posting/internal/targetPositionChanged'
      });
    }
  };

  /**
   * Start monitoring target resizing
   */
  Target.prototype.startResizeMonitor = function () {
    if (this.resizeMonitor) {
      return;
    }
    this.resizeMonitor = setInterval(this.detectResize.bind(this), 300);
  };

  /**
   * Stop monitoring target resizing
   */
  Target.prototype.stopResizeMonitor = function () {
    if (!this.resizeMonitor) {
      return;
    }
    clearInterval(this.resizeMonitor);
    this.resizeMonitor = null;
  };

  /**
   * Place the URL into the host page and fire
   * the appropriate events to get the host page
   * to process the link.
   *
   * @param  {String} url The URL to insert into the editable element
   */
  Target.prototype.receiveURL = function (url) {
    // For efficiency, we directly insert all characters at once.
    SeamlessPosting.util.dispatchTextEvent(this.getNode(), 'textInput', url);

    // Then we emulate inputing a space
    var ch = ' ';
    var chCode = ch.charCodeAt(0);
    SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keydown', chCode);
    SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keypress', chCode);
    SeamlessPosting.util.dispatchTextEvent(this.getNode(), 'textInput', ch);
    SeamlessPosting.util.dispatchInjectedKeyboardEvent(this.getNode(), 'keyup', chCode);
  };

  SeamlessPosting.Target = Target;

}());
<|endoftext|>


<commit_before>/* eslint no-console:0 */

import algoliasearch from 'algoliasearch';
import autocomplete from 'autocomplete.js';

import createHitFormatter from './createHitFormatter.js';
import formatInputValue from './formatInputValue.js';
import formatAutocompleteSuggestion from './formatAutocompleteSuggestion.js';
import './places.scss';
import EventEmitter from 'events';
import clearIcon from './icons/clear.svg';
import pinIcon from './icons/address.svg';

const hitFormatter = createHitFormatter({
  formatAutocompleteSuggestion,
  formatInputValue
});

export default function places({
  countries,
  language = navigator.language.split('-')[0],
  container
}) {
  const placesInstance = new EventEmitter();
  const client = algoliasearch.initPlaces(
    '6TZ2RYGYRQ',
    '20b9e128b7e37ff38a4e86b08477980b',
    {hosts: ['places-de-1.algolia.net']} // use staging for now, FIXME
  );
  client.as.setExtraHeader('targetIndexingIndexes', true);

  // https://github.com/algolia/autocomplete.js#options
  const options = {
    autoselect: true,
    hint: true,
    cssClasses: {
      root: 'algolia-places',
      prefix: 'ap'
    }
  };

  if (process.env.NODE_ENV === 'development') {
    options.debug = true;
  }

  // https://github.com/algolia/autocomplete.js#options
  const templates = {
    suggestion: hit => hit._dropdownHTMLFormatted
  };

  const autocompleteInstance = autocomplete(
    container,
    options, {
      // https://github.com/algolia/autocomplete.js#sources
      source: (query, cb) => client
        .search({query, language, countries})
        .then(({hits}) => hits.slice(0, 5).map(hitFormatter))
        .then(suggestions => {
          placesInstance.emit('suggestions', {suggestions, query: autocompleteInstance.val()});
          return suggestions;
        })
        .then(cb)
        .catch(err => console.error(err)),
      templates,
      displayKey: '_inputValue'
    }
  );

  const autocompleteContainer = container.parentNode;

  const autocompleteChangeEvents = ['selected', 'autocompleted'];
  autocompleteChangeEvents.forEach(eventName => {
    autocompleteInstance.on(`autocomplete:${eventName}`, (_, suggestion) => {
      placesInstance.emit('change', {suggestion, query: autocompleteInstance.val()});
    });
  });
  autocompleteInstance.on('autocomplete:cursorchanged', (_, suggestion) => {
    placesInstance.emit('cursorchanged', {suggestion, query: autocompleteInstance.val()});
  });

  const clear = document.createElement('button');
  clear.classList.add('ap-input-icon');
  clear.innerHTML = clearIcon;
  autocompleteContainer.appendChild(clear);
  clear.style.display = 'none';

  const pin = document.createElement('button');
  pin.classList.add('ap-input-icon');
  pin.innerHTML = pinIcon;
  autocompleteContainer.appendChild(pin);

  pin.addEventListener('click', () => autocompleteInstance.focus());
  clear.addEventListener('click', () => {
    autocompleteInstance.autocomplete.setVal('');
    autocompleteInstance.focus();
  });

  let previousQuery = '';
  autocompleteContainer.querySelector('.ap-input').addEventListener('input', () => {
    const query = autocompleteInstance.val();
    if (query === '') {
      pin.style.display = '';
      clear.style.display = 'none';
      if (previousQuery !== query) {
        placesInstance.emit('change', {query});
      }
    } else {
      clear.style.display = '';
      pin.style.display = 'none';
    }
    previousQuery = query;
  });

  return placesInstance;
}
<commit_msg>fix(buttons): avoid submit on click (#103)<commit_after>/* eslint no-console:0 */

import algoliasearch from 'algoliasearch';
import autocomplete from 'autocomplete.js';

import createHitFormatter from './createHitFormatter.js';
import formatInputValue from './formatInputValue.js';
import formatAutocompleteSuggestion from './formatAutocompleteSuggestion.js';
import './places.scss';
import EventEmitter from 'events';
import clearIcon from './icons/clear.svg';
import pinIcon from './icons/address.svg';

const hitFormatter = createHitFormatter({
  formatAutocompleteSuggestion,
  formatInputValue
});

export default function places({
  countries,
  language = navigator.language.split('-')[0],
  container
}) {
  const placesInstance = new EventEmitter();
  const client = algoliasearch.initPlaces(
    '6TZ2RYGYRQ',
    '20b9e128b7e37ff38a4e86b08477980b',
    {hosts: ['places-de-1.algolia.net']} // use staging for now, FIXME
  );
  client.as.setExtraHeader('targetIndexingIndexes', true);

  // https://github.com/algolia/autocomplete.js#options
  const options = {
    autoselect: true,
    hint: true,
    cssClasses: {
      root: 'algolia-places',
      prefix: 'ap'
    }
  };

  if (process.env.NODE_ENV === 'development') {
    options.debug = true;
  }

  // https://github.com/algolia/autocomplete.js#options
  const templates = {
    suggestion: hit => hit._dropdownHTMLFormatted
  };

  const autocompleteInstance = autocomplete(
    container,
    options, {
      // https://github.com/algolia/autocomplete.js#sources
      source: (query, cb) => client
        .search({query, language, countries})
        .then(({hits}) => hits.slice(0, 5).map(hitFormatter))
        .then(suggestions => {
          placesInstance.emit('suggestions', {suggestions, query: autocompleteInstance.val()});
          return suggestions;
        })
        .then(cb)
        .catch(err => console.error(err)),
      templates,
      displayKey: '_inputValue'
    }
  );

  const autocompleteContainer = container.parentNode;

  const autocompleteChangeEvents = ['selected', 'autocompleted'];
  autocompleteChangeEvents.forEach(eventName => {
    autocompleteInstance.on(`autocomplete:${eventName}`, (_, suggestion) => {
      placesInstance.emit('change', {suggestion, query: autocompleteInstance.val()});
    });
  });
  autocompleteInstance.on('autocomplete:cursorchanged', (_, suggestion) => {
    placesInstance.emit('cursorchanged', {suggestion, query: autocompleteInstance.val()});
  });

  const clear = document.createElement('button');
  clear.setAttribute('type', 'button');
  clear.classList.add('ap-input-icon');
  clear.innerHTML = clearIcon;
  autocompleteContainer.appendChild(clear);
  clear.style.display = 'none';

  const pin = document.createElement('button');
  pin.setAttribute('type', 'button');
  pin.classList.add('ap-input-icon');
  pin.innerHTML = pinIcon;
  autocompleteContainer.appendChild(pin);

  pin.addEventListener('click', () => autocompleteInstance.focus());
  clear.addEventListener('click', () => {
    autocompleteInstance.autocomplete.setVal('');
    autocompleteInstance.focus();
  });

  let previousQuery = '';
  autocompleteContainer.querySelector('.ap-input').addEventListener('input', () => {
    const query = autocompleteInstance.val();
    if (query === '') {
      pin.style.display = '';
      clear.style.display = 'none';
      if (previousQuery !== query) {
        placesInstance.emit('change', {query});
      }
    } else {
      clear.style.display = '';
      pin.style.display = 'none';
    }
    previousQuery = query;
  });

  return placesInstance;
}
<|endoftext|>


<commit_before>import container from './container'

let pid = 0

export default {
  props: {
    playerHeight: {
      type: [String, Number],
      default: '390'
    },
    playerWidth: {
      type: [String, Number],
      default: '640'
    },
    playerVars: {
      type: Object,
      default: () => ({ autoplay: 0, time: 0 })
    },
    videoId: {
      type: String
    },
    mute: {
      type: Boolean,
      default: false
    }
  },
  render (h) {
    return h('div', [
      h('div', { attrs: { id: this.elementId }})
    ])
  },
  template: '

',
  watch: {
    playerWidth: 'setSize',
    playerHeight: 'setSize',
    videoId: 'update',
    mute: 'setMute'
  },
  data () {
    pid += 1
    return {
      elementId: `youtube-player-${pid}`,
      player: {}
    }
  },
  methods: {
    setSize () {
      this.player.setSize(this.playerWidth, this.playerHeight)
    },
    setMute (value) {
      if (value) {
        this.player.mute()
      } else {
        this.player.unMute()
      }
    },
    update (videoId) {
      const name = `${this.playerVars.autoplay ? 'load' : 'cue'}VideoById`
      if (this.player.hasOwnProperty(name)) {
        this.player[name](videoId)
      } else {
        setTimeout(function () {
          this.update(videoId)
        }.bind(this), 100)
      }
    }
  },
  mounted () {
    container.register((YouTube) => {
      const { playerHeight, playerWidth, playerVars, videoId } = this

      this.player = new YouTube.Player(this.elementId, {
        height: playerHeight,
        width: playerWidth,
        playerVars,
        videoId,
        host: 'https://www.youtube.com',
        events: {
          onReady: (event) => {
            this.setMute(this.mute)
            this.$emit('ready', event)
          },
          onStateChange: (event) => {
            if (event.data !== -1) {
              this.$emit(container.events[event.data], event)
            }
          },
          onError: (event) => {
            this.$emit('error', event)
          }
        }
      })
    })
  },
  beforeDestroy () {
    if (this.player !== null && this.player.destroy) {
      this.player.destroy()
    }
    delete this.player
  }
}
<commit_msg>Revert "fix postMessage related error"<commit_after>import container from './container'

let pid = 0

export default {
  props: {
    playerHeight: {
      type: [String, Number],
      default: '390'
    },
    playerWidth: {
      type: [String, Number],
      default: '640'
    },
    playerVars: {
      type: Object,
      default: () => ({ autoplay: 0, time: 0 })
    },
    videoId: {
      type: String
    },
    mute: {
      type: Boolean,
      default: false
    }
  },
  render (h) {
    return h('div', [
      h('div', { attrs: { id: this.elementId }})
    ])
  },
  template: '

',
  watch: {
    playerWidth: 'setSize',
    playerHeight: 'setSize',
    videoId: 'update',
    mute: 'setMute'
  },
  data () {
    pid += 1
    return {
      elementId: `youtube-player-${pid}`,
      player: {}
    }
  },
  methods: {
    setSize () {
      this.player.setSize(this.playerWidth, this.playerHeight)
    },
    setMute (value) {
      if (value) {
        this.player.mute()
      } else {
        this.player.unMute()
      }
    },
    update (videoId) {
      const name = `${this.playerVars.autoplay ? 'load' : 'cue'}VideoById`
      if (this.player.hasOwnProperty(name)) {
        this.player[name](videoId)
      } else {
        setTimeout(function () {
          this.update(videoId)
        }.bind(this), 100)
      }
    }
  },
  mounted () {
    container.register((YouTube) => {
      const { playerHeight, playerWidth, playerVars, videoId } = this

      this.player = new YouTube.Player(this.elementId, {
        height: playerHeight,
        width: playerWidth,
        playerVars,
        videoId,
        events: {
          onReady: (event) => {
            this.setMute(this.mute)
            this.$emit('ready', event)
          },
          onStateChange: (event) => {
            if (event.data !== -1) {
              this.$emit(container.events[event.data], event)
            }
          },
          onError: (event) => {
            this.$emit('error', event)
          }
        }
      })
    })
  },
  beforeDestroy () {
    if (this.player !== null && this.player.destroy) {
      this.player.destroy()
    }
    delete this.player
  }
}
<|endoftext|>


<commit_before>  'use strict';

  var pluginName = 'insight',
      defaults = {
        fn: null,
        classIn:      'insight',
        classAbove:   'insight-above',
        classBelow:   'insight-below',
        classLeft:    'insight-left',
        classRight:   'insight-right',
        container:    $(window),
      };

  function InSight(element, options) {
    this.el = element;
    this.$el = $(this.el);
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._name = pluginName;
    this.init();
  }

  InSight.prototype = {

    init: function() {
      this.handler = this._handler.bind(this);
      $(window)
        .off('DOMContentLoaded load resize', this.handler)
        .on('DOMContentLoaded load resize', this.handler);
      this.options.container
        .off('scroll', this.handler)
        .on('scroll', this.handler)
        .trigger('scroll');
    },
    destroy: function() {
      $(window)
        .off('DOMContentLoaded load resize', this.handler);
      this.options.container
        .off('scroll', this.handler);
      this.$el.removeData(pluginName);
    },
    _handler: function(e, rect, wWidth, wHeight, insight, position) {
      try {
        rect = this.el.getBoundingClientRect();
        wWidth = this.options.container.width();
        wHeight = this.options.container.height();
        insight = rect.top < wHeight &&
                  rect.bottom > 0 &&
                  rect.left < wWidth &&
                  rect.right > 0;
        position = {
          above: rect.top < 0 && rect.bottom <= 0,
          left: rect.left < 0 && rect.right <= 0,
          right: rect.left >= wWidth && rect.right > wWidth,
          below: rect.top >= wHeight && rect.bottom > wHeight,
        };

        if (insight) {
          this.$el.addClass(this.options.classIn);
        }

        if (position.above) {
          this.$el.addClass(this.options.classAbove);
        }
        else {
          this.$el.removeClass(this.options.classAbove);
        }

        if (position.below) {
          this.$el.addClass(this.options.classBelow);
        }
        else {
          this.$el.removeClass(this.options.classBelow);
        }

        if (position.left) {
          this.$el.addClass(this.options.classLeft);
        }
        else {
          this.$el.removeClass(this.options.classLeft);
        }

        if (position.right) {
          this.$el.addClass(this.options.classRight);
        }
        else {
          this.$el.removeClass(this.options.classRight);
        }
      }
      catch(e) {}
      this.options.fn && this.options.fn.apply(this.el, [{
        target: this.el,
        insight: insight,
        position: position,
        rect: rect,
      }]);
    }
  };

  $.fn[pluginName] = function(options) {
    return this.each(function() {

      var $el = $(this);
      var inst = $el.data(pluginName);

      if(!inst) {
        inst = new InSight(this, options);
        $el.data(pluginName, inst);
      }

      else if (options === 'destroy') {
        inst.destroy();
      }

    });
  };
<commit_msg>add option to specify a fraction that must be visible before adding insight class<commit_after>  'use strict';

  var pluginName = 'insight',
      defaults = {
        fraction: 0,
        fn: null,
        classIn:      'insight',
        classAbove:   'insight-above',
        classBelow:   'insight-below',
        classLeft:    'insight-left',
        classRight:   'insight-right',
        container:    $(window),
      };

  function InSight(element, options) {
    this.el = element;
    this.$el = $(this.el);
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._name = pluginName;
    this.init();
  }

  InSight.prototype = {

    init: function() {
      this.handler = this._handler.bind(this);
      this.options.fraction = Math.max(Math.min(+this.options.fraction, 1), 0);
      $(window)
        .off('DOMContentLoaded load resize', this.handler)
        .on('DOMContentLoaded load resize', this.handler);
      this.options.container
        .off('scroll', this.handler)
        .on('scroll', this.handler)
        .trigger('scroll');
    },
    destroy: function() {
      $(window)
        .off('DOMContentLoaded load resize', this.handler);
      this.options.container
        .off('scroll', this.handler);
      this.$el.removeData(pluginName);
    },
    _handler: function(e, rect, wWidth, wHeight, insight, position) {
      try {
        rect = this.el.getBoundingClientRect();
        wWidth = this.options.container.width();
        wHeight = this.options.container.height();
        position = {
          above: rect.top < 0 && rect.bottom <= 0,
          left: rect.left < 0 && rect.right <= 0,
          right: rect.left >= wWidth && rect.right > wWidth,
          below: rect.top >= wHeight && rect.bottom > wHeight,
        };

        if (this.options.fraction) {
          var heightFraction = Math.min(rect.height, wHeight) * this.options.fraction;
          var widthFraction = Math.min(rect.width, wWidth) * this.options.fraction;
          insight = (
                      (rect.top <= wHeight - heightFraction && rect.bottom > 0) ||
                      (rect.top < wHeight && rect.bottom >= heightFraction && rect.bottom <= wHeight)
                    ) &&
                    (
                      (rect.left <= wWidth - widthFraction && rect.right > 0) ||
                      (rect.left < wWidth && rect.right >= widthFraction && rect.right <= wWidth)
                    );
        }
        else {
          insight = rect.top < wHeight &&
                    rect.bottom > 0 &&
                    rect.left < wWidth &&
                    rect.right > 0;
        }

        if (insight) {
          this.$el.addClass(this.options.classIn);
        }

        if (position.above) {
          this.$el.addClass(this.options.classAbove);
        }
        else {
          this.$el.removeClass(this.options.classAbove);
        }

        if (position.below) {
          this.$el.addClass(this.options.classBelow);
        }
        else {
          this.$el.removeClass(this.options.classBelow);
        }

        if (position.left) {
          this.$el.addClass(this.options.classLeft);
        }
        else {
          this.$el.removeClass(this.options.classLeft);
        }

        if (position.right) {
          this.$el.addClass(this.options.classRight);
        }
        else {
          this.$el.removeClass(this.options.classRight);
        }
      }
      catch(e) {}
      this.options.fn && this.options.fn.apply(this.el, [{
        target: this.el,
        insight: insight,
        position: position,
        rect: rect,
      }]);
    }
  };

  $.fn[pluginName] = function(options) {
    return this.each(function() {

      var $el = $(this);
      var inst = $el.data(pluginName);

      if(!inst) {
        inst = new InSight(this, options);
        $el.data(pluginName, inst);
      }

      else if (options === 'destroy') {
        inst.destroy();
      }

    });
  };
<|endoftext|>


<commit_before>var pollerFactory = function (window, jQuery, statusChecker, cursorFetcher) {
        "use strict";
        var defaults = {
            // jQuery.ajax options
                dataType: "json",
                type: "POST",
                global: false,
                timeout: 5 * 60 * 1000,
                data: { 'cursor': null },
            // poller options
                errorSleepTime: 500,
                pollInterval: 1 // miliseconds between consecutive polls
            },
            options = {},
            errorSleepTime = {},
            listeners = {},
            deferreds = {},
            i = 0,

            // checks status for response
            checkStatus = statusChecker || function (response) {
                try {
                    return parseInt(response.status, 10);
                } catch (e) {
                }
                return 0;
            },

            // fetches last message ID (cursor)
            fetchCursor = cursorFetcher || function (response) {
                if (response !== (void 0) && 1 === parseInt(response.status, 10)) {
                    return response.messages[response.messages.length - 1].id;
                }
            },

            // placeholder/declaration (implementation/definition put below - JSLint compliance)
            doSendRequest = null,

            // sends request according to given timeout
            sendRequest = function (url, timeout) {
                if (timeout !== (void 0) && timeout > 0) {
                    window.setTimeout(
                        function () {
                            doSendRequest(url);
                        },
                        timeout
                    );
                    return;
                }
                doSendRequest(url);
            },

            // called on erroneous response
            onError = function (response, url) {
                // when response does not contain "status" field it means that "timeout" occured,
                // so wo don`t increase error sleep time
                if (checkStatus(response) !== 1) {
                    errorSleepTime[url] *= 2;
                }
                sendRequest(url, errorSleepTime[url]);
            },

            // called on succeeded response
            onSuccess = function (response, url) {
                // fetch last message ID (cursor)
                options[url].data.cursor = fetchCursor(response);
                errorSleepTime[url] = options[url].errorSleepTime;
                sendRequest(url, options[url].pollInterval);
            };

        // sends request
        doSendRequest = function (url) {
            // send request
            deferreds[url] = jQuery.ajax(options[url]);
            // append listeners
            for (i = 0; i < listeners[url].length; i = i + 1) {
                deferreds[url].success(listeners[url][i]);
            }
            // append "onError" action
            deferreds[url].error(function (response) {
                onError(response, url);
            });
        };

        return function (url, success, params) {
            // for each new URL define standard structure
            if (!listeners.hasOwnProperty(url)) {
                // merge options
                options[url] = jQuery.extend(defaults, {url: url}, params);
                // add listeners (at least one - internal listener that updates cursor)
                listeners[url] = [function (response) { onSuccess(response, url); }];
                // set default errorSleepTime
                errorSleepTime[url] = options[url].errorSleepTime;
                // force request send right now (not after timeout)
                // it sets deferreds[url]
                doSendRequest(url);
            }
            // append callback to listeners
            listeners[url].push(success);
            // append callback to current deferred instance
            deferreds[url].success(success);
        };
    },
    poller = null;

try {
    poller = pollerFactory(window, jQuery);
} catch (e) {
}
<commit_msg>Fixed preparing options so defaults will not be overriden<commit_after>var pollerFactory = function (window, jQuery, statusChecker, cursorFetcher) {
        "use strict";
        var defaults = {
            // jQuery.ajax options
                dataType: "json",
                type: "POST",
                global: false,
                timeout: 5 * 60 * 1000,
                data: { 'cursor': null },
            // poller options
                errorSleepTime: 500,
                pollInterval: 1 // miliseconds between consecutive polls
            },
            options = {},
            errorSleepTime = {},
            listeners = {},
            deferreds = {},
            i = 0,

            // checks status for response
            checkStatus = statusChecker || function (response) {
                try {
                    return parseInt(response.status, 10);
                } catch (e) {
                }
                return 0;
            },

            // fetches last message ID (cursor)
            fetchCursor = cursorFetcher || function (response) {
                if (response !== (void 0) && 1 === parseInt(response.status, 10)) {
                    return response.messages[response.messages.length - 1].id;
                }
            },

            // placeholder/declaration (implementation/definition put below - JSLint compliance)
            doSendRequest = null,

            // sends request according to given timeout
            sendRequest = function (url, timeout) {
                if (timeout !== (void 0) && timeout > 0) {
                    window.setTimeout(
                        function () {
                            doSendRequest(url);
                        },
                        timeout
                    );
                    return;
                }
                doSendRequest(url);
            },

            // called on erroneous response
            onError = function (response, url) {
                // when response does not contain "status" field it means that "timeout" occured,
                // so wo don`t increase error sleep time
                if (checkStatus(response) !== 1) {
                    errorSleepTime[url] *= 2;
                }
                sendRequest(url, errorSleepTime[url]);
            },

            // called on succeeded response
            onSuccess = function (response, url) {
                // fetch last message ID (cursor)
                options[url].data.cursor = fetchCursor(response);
                errorSleepTime[url] = options[url].errorSleepTime;
                sendRequest(url, options[url].pollInterval);
            };

        // sends request
        doSendRequest = function (url) {
            // send request
            deferreds[url] = jQuery.ajax(options[url]);
            // append listeners
            for (i = 0; i < listeners[url].length; i = i + 1) {
                deferreds[url].success(listeners[url][i]);
            }
            // append "onError" action
            deferreds[url].error(function (response) {
                onError(response, url);
            });
        };

        return function (url, success, params) {
            // for each new URL define standard structure
            if (!listeners.hasOwnProperty(url)) {
                // merge options
                options[url] = jQuery.extend(true, {}, defaults, params, {url: url});
                // add listeners (at least one - internal listener that updates cursor)
                listeners[url] = [function (response) { onSuccess(response, url); }];
                // set default errorSleepTime
                errorSleepTime[url] = options[url].errorSleepTime;
                // force request send right now (not after timeout)
                // it sets deferreds[url]
                doSendRequest(url);
            }
            // append callback to listeners
            listeners[url].push(success);
            // append callback to current deferred instance
            deferreds[url].success(success);
        };
    },
    poller = null;

try {
    poller = pollerFactory(window, jQuery);
} catch (e) {
}
<|endoftext|>


<commit_before>/*!
 *
 * Copyright (c) 2013 Manfred Bork
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

/**
 * @constructor
 */

var Random = function () {
};

/**
 * Seedable random number generator
 *
 * @module Random
 * @class Random
 * @api
 */

Random.prototype = {

    /**
     * Sets initial seed
     *
     * @method initialSeed
     * @param {String|Number} seed Initial seed
     */

    initialSeed: function (seed) {
        if (typeof seed === 'number') {
            seed = '' + seed;
        }
        this.i = 0;
        this.j = 0;
        this.keystream = this._keystream(seed);
    },

    /**
     * Generates random number
     *
     * @method random
     * @return {Number} Number between 0 and 1
     */

    random: function () {
        if (!this.keystream) {
            this.initialSeed('seed');
        }
        return (this._randomByte() + this._randomByte() * 256 + this._randomByte() * 65536 +
                this._randomByte() * 16777216 + this._randomByte() * 4294967296 +
                this._randomByte() * 1099511627776 + this._randomByte() * 281474976710656 +
                this._randomByte() * 72057594037927940) / 18446744073709551616;
    },

//////////////////////////////// Private Random methods ////////////////////////////////

    /**
     * The key-scheduling algorithm
     *
     * @method _keystream
     * @param {String} key Key
     * @return {Array} Keystream
     * @private
     */

    _keystream: function (key) {
        var S = [];
        var j = 0;
        for(var i = 0; i < 256; i++) {
            S[i] = i;
        }
        for(var k = 0; k < 256; k++) {
            var swap = S[k];
            j = (j + swap + key[k % key.length].charCodeAt(0)) % 256;
            S[k] = S[j];
            S[j] = swap;
        }
        return S;
    },

    /**
     * Generates random byte
     *
     * @method _randomByte
     * @return {Number} Random byte
     * @private
     */

    _randomByte: function () {
        var swap = this.keystream[this.i];
        this.i = (this.i + 1) % 256;
        this.j = (this.j + swap) % 256;
        this.keystream[this.i] = this.keystream[this.j];
        this.keystream[this.j] = swap;
        return this.keystream[(this.keystream[this.i] + this.keystream[this.j]) % 256];
    }
};

// export the module
module.exports = Random;
<commit_msg>Refactored version<commit_after>/*!
 *
 * Copyright (c) 2013 Manfred Bork
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

/**
 * @constructor
 */

var Random = function () {
};

/**
 * Seedable random number generator
 *
 * @module Random
 * @class Random
 * @api
 */

Random.prototype = {

    /**
     * Sets initial seed
     *
     * @method initialSeed
     * @param {String|Number} seed Initial seed
     */

    initialSeed: function (seed) {
        if (typeof seed === 'number') {
            seed = this._longToHex(seed);
        }
        this.i = 0;
        this.j = 0;
        this.keystream = this._keystream(seed);
    },

    /**
     * Generates random number
     *
     * @method random
     * @return {Number} Number between 0 and 1
     */

    random: function () {
        if (!this.keystream) {
            this.initialSeed('seed');
        }
        return (this._randomByte() + this._randomByte() * 256 + this._randomByte() * 65536 +
                this._randomByte() * 16777216 + this._randomByte() * 4294967296 +
                this._randomByte() * 1099511627776 + this._randomByte() * 281474976710656 +
                this._randomByte() * 72057594037927940) / 18446744073709551616;
    },

//////////////////////////////// Private Random methods ////////////////////////////////

    /**
     * Converts 64-bit unsigned long to hexadecimal
     *
     * @method _longToHex
     * @param {Number} n 64-bit unsigned long
     * @return {String} Hexadecimal
     * @private
     */

    _longToHex: function (n) {
        var key = '';
        var hex = '0123456789ABCDEF';
        for (var i = 0; i < 8; i++) {
            var ch = n & 0xf;
            key = hex.charAt(ch) + key;
            n = (n - ch) / 16;
        }
        return key;
    },

    /**
     * The key-scheduling algorithm
     *
     * @method _keystream
     * @param {String} key Key
     * @return {Array} Keystream
     * @private
     */

    _keystream: function (key) {
        var S = [];
        var j = 0;
        for(var i = 0; i < 256; i++) {
            S[i] = i;
        }
        for(var k = 0; k < 256; k++) {
            var swap = S[k];
            j = (j + swap + key[k % key.length].charCodeAt(0)) % 256;
            S[k] = S[j];
            S[j] = swap;
        }
        return S;
    },

    /**
     * Generates random byte
     *
     * @method _randomByte
     * @return {Number} Random byte
     * @private
     */

    _randomByte: function () {
        var swap = this.keystream[this.i];
        this.i = (this.i + 1) % 256;
        this.j = (this.j + swap) % 256;
        this.keystream[this.i] = this.keystream[this.j];
        this.keystream[this.j] = swap;
        return this.keystream[(this.keystream[this.i] + this.keystream[this.j]) % 256];
    }
};

// export the module
module.exports = Random;
<|endoftext|>