<commit_before>import React, {Component, PropTypes} from 'react'
import { Checkbox, FormControl, FormGroup, ControlLabel, Tooltip, OverlayTrigger } from 'react-bootstrap'
import Select from 'react-select'
import reactCSS from 'reactcss'
import moment from 'moment'
import DateTimeField from 'react-bootstrap-datetimepicker'
import { sentence as toSentenceCase } from 'change-case'

import { getEntityName } from '../util/gtfs'
import VirtualizedEntitySelect from './VirtualizedEntitySelect'
import GtfsSearch from '../../gtfs/components/gtfssearch'
import TimezoneSelect from '../../common/components/TimezoneSelect'
import LanguageSelect from '../../common/components/LanguageSelect'
import { SketchPicker } from 'react-color'
import Dropzone from 'react-dropzone'

export default class EditorInput extends Component {
  static propTypes = {
    entities: PropTypes.array
  }
  constructor (props) {
    super(props)
    this.state = {
      color: {
        r: '241',
        g: '112',
        b: '19',
        a: '1'
      }
    }
  }
  handleClick (field) {
    this.setState({ [field]: !this.state[field] })
  }
  handleClose (field) {
    this.setState({ [field]: !this.state[field] })
  }
  render () {
    const {
      activeEntity,
      updateActiveEntity,
      activeComponent,
      uploadBrandingAsset,
      feedSource,
      getGtfsEntity,
      fieldEdited,
      gtfsEntitySelected,
      tableData,
      row,
      field,
      currentValue,
      approveGtfsDisabled,
      zoneOptions,
      table,
      isNotValid
    } = this.props
    const formProps = {
      controlId: `${editorField}`,
      className: `col-xs-${field.columnWidth}`,
      validationState: isNotValid
        ? 'error'
        : field.required
        ? 'success'
        : ''
    }
    const simpleFormProps = {
      controlId: `${editorField}`,
      className: `col-xs-${field.columnWidth}`
    }
    const styles = reactCSS({
      'default': {
        swatch: {
          padding: '5px',
          marginRight: '30px',
          background: '#fff',
          zIndex: 1,
          borderRadius: '1px',
          boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
          display: 'inline-block',
          cursor: 'pointer'
        },
        popover: {
          position: 'absolute',
          zIndex: '200'
        },
        cover: {
          position: 'fixed',
          top: '0',
          right: '0',
          bottom: '0',
          left: '0'
        }
      }
    })
    const editorField = field.displayName || field.name
    const basicLabel = field.helpContent
        ? <OverlayTrigger placement='right' overlay={<Tooltip id='tooltip'>{field.helpContent}</Tooltip>}>
          <ControlLabel>{editorField}{field.required ? ' *' : ''}</ControlLabel>
        </OverlayTrigger>
        : <ControlLabel>{editorField}{field.required ? ' *' : ''}</ControlLabel>
    switch (field.inputType) {
      case 'GTFS_ID':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        )
      case 'TEXT':
      case 'GTFS_TRIP':
      case 'GTFS_SHAPE':
      case 'GTFS_BLOCK':
      case 'GTFS_FARE':
      case 'GTFS_SERVICE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue || ''}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        )
      case 'URL':
        let elements = [
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        ]
        if (field.name === 'agency_branding_url' || field.name === 'route_branding_url') {
          elements.push(
            <FormGroup
              className='col-xs-12'
              key={`${editorField}-upload`}>
              <ControlLabel>Upload {activeComponent} branding asset</ControlLabel>
              <Dropzone
                accept='image/*'
                multiple={false}
                onDrop={(files) => {
                  uploadBrandingAsset(feedSource.id, activeEntity.id, activeComponent, files[0])
                  this.setState({file: files[0]})
                }}>

Drop {activeComponent} image here, or click to select image to upload.

                {activeEntity && activeEntity[field.name]
                  ?
                  : null
                }
              </Dropzone>
            </FormGroup>
          )
        }
        return {elements}
      case 'EMAIL':
        return (
          <FormGroup {...formProps}
          >
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        )
      case 'GTFS_ZONE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <Select
              placeholder='Select zone ID...'
              clearable
              noResultsText={`No zones found. Specify zones in stop.`}
              key={Math.random()}
              value={currentValue}
              onChange={(input) => {
                let props = {}
                let val = input ? input.value : null
                props[field.name] = val
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
              filterOptions={(options, filter, values) => {
                // Filter already selected values
                let valueKeys = values && values.map(i => i.value)
                let filteredOptions = options.filter(option => {
                  return valueKeys ? valueKeys.indexOf(option.value) === -1 : []
                })

                // Filter by label
                if (filter !== undefined && filter != null && filter.length > 0) {
                  filteredOptions = filteredOptions.filter(option => {
                    return RegExp(filter, 'ig').test(option.label)
                  })
                }

                // Append Addition option
                if (filteredOptions.length === 0) {
                  filteredOptions.push({
                    label: Create new zone: {filter},
                    value: filter,
                    create: true
                  })
                }

                return filteredOptions
              }}
              options={zoneOptions} />
          </FormGroup>
        )
      case 'TIMEZONE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <TimezoneSelect
              value={currentValue}
              clearable={!field.required}
              onChange={(option) => {
                let props = {}
                props[field.name] = option.value
                this.setState({[editorField]: option.value})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'LANGUAGE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <LanguageSelect
              value={currentValue}
              clearable={false}
              onChange={(option) => {
                let props = {}
                props[field.name] = option.value
                this.setState({[editorField]: option.value})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'TIME':
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder='HH:MM:SS'
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'LATITUDE':
      case 'LONGITUDE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              // readOnly
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
              //   this.setState({[editorField]: evt.target.value})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'NUMBER':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'DATE':
        let defaultValue = /end/.test(editorField) ? +moment().startOf('day').add(3, 'months') : +moment().startOf('day')
        let dateTimeProps = {
          mode: 'date',
          dateTime: currentValue ? +moment(currentValue) : defaultValue,
          onChange: (millis) => {
            let props = {}
            props[field.name] = +millis
            updateActiveEntity(activeEntity, activeComponent, props)
          }
        }
        if (!currentValue) {
          dateTimeProps.defaultText = 'Please select a date'
        }
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <DateTimeField {...dateTimeProps} />
          </FormGroup>
        )
      case 'COLOR':
        const hexColor = currentValue !== null ? `#${currentValue}` : '#000000'
        const colorStyle = {
          width: '36px',
          height: '20px',
          borderRadius: '2px',
          background: hexColor
        }
        const wrapper = {
          position: 'inherit',
          zIndex: '100'
        }
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            {

 this.handleClick(editorField)}>

            }
            {this.state[editorField]
              ?

 this.handleClose(editorField)} />

                  <SketchPicker
                    color={hexColor}
                    onChange={(color) => {
                      let props = {}
                      props[field.name] = color.hex.split('#')[1]
                      updateActiveEntity(activeEntity, activeComponent, props)
                    }} />

              : null
            }
          </FormGroup>
        )
      case 'POSITIVE_INT':
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              min={0}
              step={1}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'POSITIVE_NUM':
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              min={0}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'DAY_OF_WEEK_BOOLEAN':
        return (

            <span key={`dow-label`}>
              {editorField === 'monday'
                ?
<ControlLabel>Days of service</ControlLabel>
 : null
              }

            <span key={`${editorField}`} className='col-xs-3'>
              <Checkbox
                inline
                checked={this.state[editorField] === 1 || currentValue === 1}
                onChange={(evt) => {
                  let props = {}
                  props[field.name] = evt.target.checked ? 1 : 0
                  updateActiveEntity(activeEntity, activeComponent, props)
                }}>
                {toSentenceCase(editorField.substr(0, 3))}
              </Checkbox>
              {'     '}

        )
      case 'DROPDOWN':
        return (
          <FormGroup
            controlId={`${editorField}`}
            className={field.columnWidth ? `col-xs-${field.columnWidth}` : 'col-xs-12'}>
            {basicLabel}
            <FormControl componentClass='select'
              value={currentValue}
              disabled={approveGtfsDisabled && field.adminOnly}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}>
              {field.options.map(option => {
                return <option value={option.value} key={option.value}>
                  {option.text || option.value}
                </option>
              })}
            </FormControl>
          </FormGroup>
        )
      case 'GTFS_ROUTE':
        const routeEntity = getGtfsEntity('route', currentValue)
        const routeValue = routeEntity
          ? {
            'value': routeEntity.route_id,
            'label': routeEntity.route_short_name
              ? `${routeEntity.route_short_name} - ${routeEntity.route_long_name}`
              : routeEntity.route_long_name
          }
          : ''
        return (
          <GtfsSearch
            feeds={[feedSource]}
            limit={100}
            entities={['routes']}
            minimumInput={1}
            clearable={false}
            onChange={(evt) => {
              fieldEdited(table.id, row, editorField, evt.route.route_id)
              gtfsEntitySelected('route', evt.route)
            }}
            value={routeValue} />
        )
      case 'GTFS_AGENCY':
        const agency = tableData.agency && tableData.agency.find(a => a.id === currentValue)
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <Select
              placeholder='Select agency...'
              clearable
              value={agency ? {value: currentValue, label: agency.agency_name} : {value: currentValue}}
              onChange={(input) => {
                console.log(input)
                let props = {}
                let val = input ? input.value : null
                props[field.name] = val
                this.setState({[editorField]: val})
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
              options={tableData.agency
                ? tableData.agency.map(agency => {
                  return {
                    value: agency.id,
                    label: agency.agency_name,
                    agency
                  }
                })
                : []
            } />
          </FormGroup>
        )
      case 'GTFS_STOP':
        const stopIndex = tableData.stop && tableData.stop.findIndex(s => s.id === activeEntity.id)
        const stop = tableData.stop.find(s => s.id === currentValue)
        let stops = [...tableData.stop]
        // remove current entity from list of stops
        if (stopIndex !== -1) {
          stops.splice(stopIndex, 1)
        }
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <VirtualizedEntitySelect
              value={stop ? {value: stop.id, label: getEntityName(activeComponent, stop), entity: stop} : null}
              component={'stop'}
              entities={stops}
              onChange={(input) => {
                console.log(input)
                let props = {}
                let val = input ? input.value : null
                props[field.name] = val
                this.setState({[editorField]: val})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      default:
        return null
    }
  }
}
<commit_msg>add keys where missing<commit_after>import React, {Component, PropTypes} from 'react'
import { Checkbox, FormControl, FormGroup, ControlLabel, Tooltip, OverlayTrigger } from 'react-bootstrap'
import Select from 'react-select'
import reactCSS from 'reactcss'
import moment from 'moment'
import DateTimeField from 'react-bootstrap-datetimepicker'
import { sentence as toSentenceCase } from 'change-case'

import { getEntityName } from '../util/gtfs'
import VirtualizedEntitySelect from './VirtualizedEntitySelect'
import GtfsSearch from '../../gtfs/components/gtfssearch'
import TimezoneSelect from '../../common/components/TimezoneSelect'
import LanguageSelect from '../../common/components/LanguageSelect'
import { SketchPicker } from 'react-color'
import Dropzone from 'react-dropzone'

export default class EditorInput extends Component {
  static propTypes = {
    entities: PropTypes.array
  }
  constructor (props) {
    super(props)
    this.state = {
      color: {
        r: '241',
        g: '112',
        b: '19',
        a: '1'
      }
    }
  }
  handleClick (field) {
    this.setState({ [field]: !this.state[field] })
  }
  handleClose (field) {
    this.setState({ [field]: !this.state[field] })
  }
  render () {
    const {
      activeEntity,
      updateActiveEntity,
      activeComponent,
      uploadBrandingAsset,
      feedSource,
      getGtfsEntity,
      key,
      fieldEdited,
      gtfsEntitySelected,
      tableData,
      row,
      field,
      currentValue,
      approveGtfsDisabled,
      zoneOptions,
      table,
      isNotValid
    } = this.props
    const formProps = {
      controlId: `${editorField}`,
      key: key,
      className: `col-xs-${field.columnWidth}`
    }
    if (isNotValid) {
      formProps.validationState = 'error'
    } else if (field.required) {
      formProps.validationState = 'success'
    }
    const simpleFormProps = {
      controlId: `${editorField}`,
      key: key,
      className: `col-xs-${field.columnWidth}`
    }
    const styles = reactCSS({
      'default': {
        swatch: {
          padding: '5px',
          marginRight: '30px',
          background: '#fff',
          zIndex: 1,
          borderRadius: '1px',
          boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
          display: 'inline-block',
          cursor: 'pointer'
        },
        popover: {
          position: 'absolute',
          zIndex: '200'
        },
        cover: {
          position: 'fixed',
          top: '0',
          right: '0',
          bottom: '0',
          left: '0'
        }
      }
    })
    const editorField = field.displayName || field.name
    const basicLabel = field.helpContent
        ? <OverlayTrigger placement='right' overlay={<Tooltip id='tooltip'>{field.helpContent}</Tooltip>}>
          <ControlLabel>{editorField}{field.required ? ' *' : ''}</ControlLabel>
        </OverlayTrigger>
        : <ControlLabel>{editorField}{field.required ? ' *' : ''}</ControlLabel>
    switch (field.inputType) {
      case 'GTFS_ID':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        )
      case 'TEXT':
      case 'GTFS_TRIP':
      case 'GTFS_SHAPE':
      case 'GTFS_BLOCK':
      case 'GTFS_FARE':
      case 'GTFS_SERVICE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue || ''}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        )
      case 'URL':
        let elements = [
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        ]
        if (field.name === 'agency_branding_url' || field.name === 'route_branding_url') {
          elements.push(
            <FormGroup
              className='col-xs-12'
              key={`${editorField}-upload`}>
              <ControlLabel>Upload {activeComponent} branding asset</ControlLabel>
              <Dropzone
                accept='image/*'
                multiple={false}
                onDrop={(files) => {
                  uploadBrandingAsset(feedSource.id, activeEntity.id, activeComponent, files[0])
                  this.setState({file: files[0]})
                }}>

Drop {activeComponent} image here, or click to select image to upload.

                {activeEntity && activeEntity[field.name]
                  ?
                  : null
                }
              </Dropzone>
            </FormGroup>
          )
        }
        return {elements}
      case 'EMAIL':
        return (
          <FormGroup {...formProps}
          >
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder={field.placeholder ? field.placeholder : ''}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
            />
          </FormGroup>
        )
      case 'GTFS_ZONE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <Select
              placeholder='Select zone ID...'
              clearable
              noResultsText={`No zones found. Specify zones in stop.`}
              key={Math.random()}
              value={currentValue}
              onChange={(input) => {
                let props = {}
                let val = input ? input.value : null
                props[field.name] = val
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
              filterOptions={(options, filter, values) => {
                // Filter already selected values
                let valueKeys = values && values.map(i => i.value)
                let filteredOptions = options.filter(option => {
                  return valueKeys ? valueKeys.indexOf(option.value) === -1 : []
                })

                // Filter by label
                if (filter !== undefined && filter != null && filter.length > 0) {
                  filteredOptions = filteredOptions.filter(option => {
                    return RegExp(filter, 'ig').test(option.label)
                  })
                }

                // Append Addition option
                if (filteredOptions.length === 0) {
                  filteredOptions.push({
                    label: Create new zone: {filter},
                    value: filter,
                    create: true
                  })
                }

                return filteredOptions
              }}
              options={zoneOptions} />
          </FormGroup>
        )
      case 'TIMEZONE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <TimezoneSelect
              value={currentValue}
              clearable={!field.required}
              onChange={(option) => {
                let props = {}
                props[field.name] = option.value
                this.setState({[editorField]: option.value})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'LANGUAGE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <LanguageSelect
              value={currentValue}
              clearable={false}
              onChange={(option) => {
                let props = {}
                props[field.name] = option.value
                this.setState({[editorField]: option.value})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'TIME':
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              placeholder='HH:MM:SS'
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'LATITUDE':
      case 'LONGITUDE':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              // readOnly
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
              //   this.setState({[editorField]: evt.target.value})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'NUMBER':
        return (
          <FormGroup {...formProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'DATE':
        let defaultValue = /end/.test(editorField) ? +moment().startOf('day').add(3, 'months') : +moment().startOf('day')
        let dateTimeProps = {
          mode: 'date',
          dateTime: currentValue ? +moment(currentValue) : defaultValue,
          onChange: (millis) => {
            let props = {}
            props[field.name] = +millis
            updateActiveEntity(activeEntity, activeComponent, props)
          }
        }
        if (!currentValue) {
          dateTimeProps.defaultText = 'Please select a date'
        }
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <DateTimeField {...dateTimeProps} />
          </FormGroup>
        )
      case 'COLOR':
        const hexColor = currentValue !== null ? `#${currentValue}` : '#000000'
        const colorStyle = {
          width: '36px',
          height: '20px',
          borderRadius: '2px',
          background: hexColor
        }
        const wrapper = {
          position: 'inherit',
          zIndex: '100'
        }
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            {

 this.handleClick(editorField)}>

            }
            {this.state[editorField]
              ?

 this.handleClose(editorField)} />

                  <SketchPicker
                    color={hexColor}
                    onChange={(color) => {
                      let props = {}
                      props[field.name] = color.hex.split('#')[1]
                      updateActiveEntity(activeEntity, activeComponent, props)
                    }} />

              : null
            }
          </FormGroup>
        )
      case 'POSITIVE_INT':
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              min={0}
              step={1}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'POSITIVE_NUM':
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <FormControl
              value={currentValue}
              type='number'
              min={0}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      case 'DAY_OF_WEEK_BOOLEAN':
        return (

            <span key={`dow-label`}>
              {editorField === 'monday'
                ?
<ControlLabel>Days of service</ControlLabel>
 : null
              }

            <span key={`${editorField}`} className='col-xs-3'>
              <Checkbox
                inline
                checked={this.state[editorField] === 1 || currentValue === 1}
                onChange={(evt) => {
                  let props = {}
                  props[field.name] = evt.target.checked ? 1 : 0
                  updateActiveEntity(activeEntity, activeComponent, props)
                }}>
                {toSentenceCase(editorField.substr(0, 3))}
              </Checkbox>
              {'     '}

        )
      case 'DROPDOWN':
        return (
          <FormGroup
            key={key}
            controlId={`${editorField}`}
            className={field.columnWidth ? `col-xs-${field.columnWidth}` : 'col-xs-12'}>
            {basicLabel}
            <FormControl componentClass='select'
              value={currentValue !== null ? currentValue : false}
              disabled={approveGtfsDisabled && field.adminOnly}
              onChange={(evt) => {
                let props = {}
                props[field.name] = evt.target.value
                updateActiveEntity(activeEntity, activeComponent, props)
              }}>
              {field.options.map(option => {
                return <option value={option.value} key={option.value}>
                  {option.text || option.value}
                </option>
              })}
            </FormControl>
          </FormGroup>
        )
      case 'GTFS_ROUTE':
        const routeEntity = getGtfsEntity('route', currentValue)
        const routeValue = routeEntity
          ? {
            'value': routeEntity.route_id,
            'label': routeEntity.route_short_name
              ? `${routeEntity.route_short_name} - ${routeEntity.route_long_name}`
              : routeEntity.route_long_name
          }
          : ''
        return (
          <GtfsSearch
            feeds={[feedSource]}
            limit={100}
            key={key}
            entities={['routes']}
            minimumInput={1}
            clearable={false}
            onChange={(evt) => {
              fieldEdited(table.id, row, editorField, evt.route.route_id)
              gtfsEntitySelected('route', evt.route)
            }}
            value={routeValue} />
        )
      case 'GTFS_AGENCY':
        const agency = tableData.agency && tableData.agency.find(a => a.id === currentValue)
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <Select
              placeholder='Select agency...'
              clearable
              value={agency ? {value: currentValue, label: agency.agency_name} : {value: currentValue}}
              onChange={(input) => {
                console.log(input)
                let props = {}
                let val = input ? input.value : null
                props[field.name] = val
                this.setState({[editorField]: val})
                updateActiveEntity(activeEntity, activeComponent, props)
              }}
              options={tableData.agency
                ? tableData.agency.map(agency => {
                  return {
                    value: agency.id,
                    label: agency.agency_name,
                    agency
                  }
                })
                : []
            } />
          </FormGroup>
        )
      case 'GTFS_STOP':
        const stopIndex = tableData.stop && tableData.stop.findIndex(s => s.id === activeEntity.id)
        const stop = tableData.stop.find(s => s.id === currentValue)
        let stops = [...tableData.stop]
        // remove current entity from list of stops
        if (stopIndex !== -1) {
          stops.splice(stopIndex, 1)
        }
        return (
          <FormGroup {...simpleFormProps}>
            {basicLabel}
            <VirtualizedEntitySelect
              value={stop ? {value: stop.id, label: getEntityName(activeComponent, stop), entity: stop} : null}
              component={'stop'}
              entities={stops}
              onChange={(input) => {
                console.log(input)
                let props = {}
                let val = input ? input.value : null
                props[field.name] = val
                this.setState({[editorField]: val})
                updateActiveEntity(activeEntity, activeComponent, props)
              }} />
          </FormGroup>
        )
      default:
        return null
    }
  }
}
<|endoftext|>


<commit_before>describe('Unit: youtubePlugin widget app', function () {
    describe('Unit: app routes', function () {
        beforeEach(module('youtubePluginWidget'));
        var location, route, rootScope;
        beforeEach(inject(
            function (_$location_, _$route_, _$rootScope_) {
                location = _$location_;
                route = _$route_;
                rootScope = _$rootScope_;
            }));

        describe('Unit test for resolve in path /', function () {
            beforeEach(inject(
                function ($httpBackend) {
                    $httpBackend.expectGET('/')
                        .respond(200);
                }));
            it('should resolve initial values for my Controller', function () {
                expect(route.routes['/'].resolve.videoData).toBeDefined(); //or whatever test you want
            });
        });
        describe('feed route', function () {
            beforeEach(inject(
                function ($httpBackend) {
                    $httpBackend.expectGET('templates/home.html')
                        .respond(200);
                    $httpBackend.expectGET('/feed/:playlistId')
                        .respond(200);
                }));

            it('should load the home page on successful load of location path /feed/:playlistId', function () {
                location.path('/feed/:playlistId');
                rootScope.$digest();
                expect(route.current.controller).toBe('WidgetFeedCtrl')
            });
        });
        describe('video route', function () {
            beforeEach(inject(
                function ($httpBackend) {
                    $httpBackend.expectGET('templates/Item_Details.html')
                        .respond(200);
                    $httpBackend.expectGET('/video/:videoId')
                        .respond(200);
                }));

            it('should load the home page on successful load of location path /video/:videoId', function () {
                location.path('/video/:videoId');
                rootScope.$digest();
                expect(route.current.controller).toBe('WidgetSingleCtrl')
            });
        });
    });
    describe('Unit: getImageUrl filter', function () {
        beforeEach(module('youtubePluginWidget'));
        var filter;
        beforeEach(inject(function (_$filter_) {
            filter = _$filter_;
        }));

        it('it should pass if "getImageUrl" filter returns resized image url', function () {
            var result;
            result = filter('getImageUrl')('https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg', 88, 124, 'resize');
            expect(result).toEqual("http://s7obnu.cloudimage.io/s/resizenp/88x124/https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg");
        });
        it('it should pass if "getImageUrl" filter returns cropped image url', function () {
            var result;
            result = filter('getImageUrl')('https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg', 88, 124, 'crop');
            expect(result).toEqual('http://s7obnu.cloudimage.io/s/crop/88x124/https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg');
        });
    });
});<commit_msg>Fixed the test cases according to code refactor<commit_after>describe('Unit: youtubePlugin widget app', function () {
    describe('Unit: app routes', function () {
        beforeEach(module('youtubePluginWidget'));
        var location, route, rootScope;
        beforeEach(inject(
            function (_$location_, _$route_, _$rootScope_) {
                location = _$location_;
                route = _$route_;
                rootScope = _$rootScope_;
            }));

        describe('Unit test for resolve in path /', function () {
            beforeEach(inject(
                function ($httpBackend) {
                    $httpBackend.expectGET('/')
                        .respond(200);
                }));
        });
        describe('video route', function () {
            beforeEach(inject(
                function ($httpBackend) {
                    $httpBackend.expectGET('templates/Item_Details.html')
                        .respond(200);
                    $httpBackend.expectGET('/video/:videoId')
                        .respond(200);
                }));

            it('should load the home page on successful load of location path /video/:videoId', function () {
                location.path('/video/:videoId');
                rootScope.$digest();
                expect(route.current.controller).toBe('WidgetSingleCtrl')
            });
        });
    });
    describe('Unit: getImageUrl filter', function () {
        beforeEach(module('youtubePluginWidget'));
        var filter;
        beforeEach(inject(function (_$filter_) {
            filter = _$filter_;
        }));

        it('it should pass if "getImageUrl" filter returns resized image url', function () {
            var result;
            result = filter('getImageUrl')('https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg', 88, 124, 'resize');
            expect(result).toEqual("http://s7obnu.cloudimage.io/s/resizenp/88x124/https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg");
        });
        it('it should pass if "getImageUrl" filter returns cropped image url', function () {
            var result;
            result = filter('getImageUrl')('https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg', 88, 124, 'crop');
            expect(result).toEqual('http://s7obnu.cloudimage.io/s/crop/88x124/https://imagelibserver.s3.amazonaws.com/25935164-2add-11e5-9d04-02f7ca55c361/950a50c0-400a-11e5-9af5-3f5e0d725ccb.jpg');
        });
    });
});<|endoftext|>


<commit_before>/*global describe, it, expect, example, before, after, beforeEach, afterEach, mocha, sinon*/
'use strict';
var assert = require('chai').assert;
var donateBanner = require('js/home-page/donateBannerPlugin');

describe('donateBanner', () => {
    describe('pickBanner', () => {
        it('check picks correct data on startDate', () => {

            var bannerOptions = [
                {
                    startDate: new Date('August 16, 2017'),
                    endDate: new Date('August 23, 2017')
                }, {
                    startDate: new Date('August 9, 2017'),
                    endDate: new Date('August 16, 2017')
                }, {
                    startDate: new Date('August 23, 2017'),
                    endtDate: new Date('August 30, 2017')
                },
            ];

           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 9, 2017')), 0);
           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 16, 2017')), 1);
           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 26, 2017')), 2);
           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 6, 2017')), -1);

        });
    });
});<commit_msg>Fix donate button test thanks Lauren R!<commit_after>/*global describe, it, expect, example, before, after, beforeEach, afterEach, mocha, sinon*/
'use strict';
var assert = require('chai').assert;
var donateBanner = require('js/home-page/donateBannerPlugin');

describe('donateBanner', () => {
    describe('pickBanner', () => {
        it('check picks correct data on startDate', () => {

            var bannerOptions = [
                {
                    startDate: new Date('August 16, 2017'),
                    endDate: new Date('August 23, 2017')
                }, {
                    startDate: new Date('August 9, 2017'),
                    endDate: new Date('August 16, 2017')
                }, {
                    startDate: new Date('August 23, 2017'),
                    endDate: new Date('August 30, 2017')
                },
            ];

           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 9, 2017')), 0);
           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 16, 2017')), 1);
           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 26, 2017')), 2);
           assert.equal(donateBanner.pickBanner(bannerOptions, new Date('August 6, 2017')), -1);

        });
    });
});<|endoftext|>


<commit_before>(function (angular) {
    angular
        .module('mediaCenterWidget')
        .controller('WidgetHomeCtrl', ['$scope', '$window', 'DB', 'COLLECTIONS', '$rootScope', 'Buildfire', 'Messaging', 'EVENTS', 'PATHS', 'Location', 'Orders', '$location',
            function ($scope, $window, DB, COLLECTIONS, $rootScope, Buildfire, Messaging, EVENTS, PATHS, Location, Orders, $location) {
                $rootScope.showFeed = true;
                var WidgetHome = this;
                var _infoData = {
                    data: {
                        content: {
                            images: [],
                            descriptionHTML: '

',
                            description: '',
                            sortBy: Orders.ordersMap.Newest,
                            rankOfLastItem: 0
                        },
                        design: {
                            listLayout: "list-1",
                            itemLayout: "item-1",
                            backgroundImage: ""
                        }
                    }
                };
                var view = null;

                /**
                 * Create instance of MediaContent, MediaCenter db collection
                 * @type {DB}
                 */
                var MediaContent = new DB(COLLECTIONS.MediaContent),
                    MediaCenter = new DB(COLLECTIONS.MediaCenter);

                /**
                 * WidgetHome.media contains MediaCenterInfo.
                 * @type {MediaCenterInfo|*}
                 */
                var MediaCenterInfo = null;
                MediaCenter.get().then(function success(result) {
                        if (result && result.data && result.id) {
                            MediaCenterInfo = result;
                        }
                        else {
                            MediaCenterInfo = _infoData;
                        }
                        WidgetHome.media = MediaCenterInfo;
                        $rootScope.backgroundImage = MediaCenterInfo.data.design.backgroundImage;

                    },
                    function fail() {
                        MediaCenterInfo = _infoData;
                        WidgetHome.media = MediaCenterInfo;
                    }
                );
                var _skip = 0,
                    _limit = 10,
                    searchOptions = {
                        filter: {"$json.title": {"$regex": '/*'}},
                        skip: _skip,
                        limit: _limit + 1 // the plus one is to check if there are any more
                    };
                /**
                 * WidgetHome.isBusy is used for infinite scroll.
                 * @type {boolean}
                 */
                WidgetHome.isBusy = false;

                /*declare the device width heights*/
                $rootScope.deviceHeight = WidgetHome.deviceHeight = window.innerHeight;
                $rootScope.deviceWidth = WidgetHome.deviceWidth = window.innerWidth || 320;

                /*initialize the device width heights*/
                var initDeviceSize = function (callback) {
                    WidgetHome.deviceHeight = window.innerHeight;
                    WidgetHome.deviceWidth = window.innerWidth;
                    if (callback) {
                        if (WidgetHome.deviceWidth == 0 || WidgetHome.deviceHeight == 0) {
                            setTimeout(function () {
                                initDeviceSize(callback);
                            }, 500);
                        } else {
                            callback();
                            if (!$scope.$$phase && !$scope.$root.$$phase) {
                                $scope.$apply();
                            }
                        }
                    }
                };
                /**
                 * Messaging.onReceivedMessage is called when any event is fire from Content/design section.
                 * @param event
                 */
                Messaging.onReceivedMessage = function (event) {
                    if (event) {
                        switch (event.name) {
                            case EVENTS.ROUTE_CHANGE:
                                if((event.message && event.message.path == PATHS.MEDIA && $location.$$path.indexOf('/media') == -1) || (event.message && event.message.path != PATHS.MEDIA)) {
                                    var path = event.message.path,
                                        id = event.message.id;
                                    var url = "#/";
                                    switch (path) {
                                        case PATHS.MEDIA:
                                            url = url + "media/";
                                            if (id) {
                                                url = url + id + "/";
                                            }
                                            break;
                                    }
                                    Location.go(url);
                                    if (path == PATHS.MEDIA) {
                                        $rootScope.showFeed = false;
                                    }
                                    else {
                                        $rootScope.showFeed = true;
                                    }
                                    $scope.$apply();
                                }
                                break;
                            case EVENTS.ITEMS_CHANGE:
                                WidgetHome.refreshItems();
                                break;
                        }
                    }
                };

                var onUpdateCallback = function (event) {
                    if (event.tag == "MediaCenter") {
                        if (event.data) {
                            WidgetHome.media.data = event.data;
                            $rootScope.backgroundImage = WidgetHome.media.data.design.backgroundImage;
                            console.log(WidgetHome.media);
                            $scope.$apply();
                            if (view && event.data.content && event.data.content.images) {
                                view.loadItems(event.data.content.images);
                            }
                            WidgetHome.refreshItems();
                        }
                    }
                    else {
                        WidgetHome.refreshItems();
                    }
                };

                /**
                 * Buildfire.datastore.onUpdate method calls when Data is changed.
                 */
                var listener = Buildfire.datastore.onUpdate(onUpdateCallback);

                /**
                 * updateGetOptions method checks whether sort options changed or not.
                 * @returns {boolean}
                 */
                var updateGetOptions = function () {
                    var order = Orders.getOrder(WidgetHome.media.data.content.sortBy || Orders.ordersMap.Default);
                    if (order) {
                        var sort = {};
                        sort[order.key] = order.order;
                        searchOptions.sort = sort;
                        return true;
                    }
                    else {
                        return false;
                    }
                };

                // ShowDescription only when it have content
                WidgetHome.showDescription = function () {
                    if (WidgetHome.media.data.content.descriptionHTML == '

' || WidgetHome.media.data.content.descriptionHTML == '

'|| WidgetHome.media.data.content.descriptionHTML == '')
                        return false;
                    else
                        return true;
                };

                /**
                 * WidgetHome.items holds the array of items.
                 * @type {Array}
                 */
                WidgetHome.items = [];
                /**
                 * WidgetHome.noMore checks for further data
                 * @type {boolean}
                 */
                WidgetHome.noMore = false;

                /**
                 * loadMore method loads the items in list page.
                 */
                WidgetHome.loadMore = function () {

                    if (WidgetHome.isBusy || WidgetHome.noMore) {
                        return;
                    }
                    updateGetOptions();
                    WidgetHome.isBusy = true;

                    MediaContent.find(searchOptions).then(function success(result) {
                        if (WidgetHome.noMore)
                            return;

                        if (result.length <= _limit) {// to indicate there are more

                            WidgetHome.noMore = true;
                        }
                        else {
                            result.pop();
                            searchOptions.skip = searchOptions.skip + _limit;
                            WidgetHome.noMore = false;
                        }
                        WidgetHome.items = WidgetHome.items ? WidgetHome.items.concat(result) : result;
                        WidgetHome.isBusy = false;
                    }, function fail() {
                        WidgetHome.isBusy = false;
                        console.error('error');
                    });
                };

                WidgetHome.openLinks = function (actionItems, $event) {
                    if (actionItems && actionItems.length) {
                        var options = {};
                        var callback = function (error, result) {
                            if (error) {
                                console.error('Error:', error);
                            }
                        };

                        $event.preventDefault();
                        $timeout(function() {
                            Buildfire.actionItems.list(actionItems, options, callback);
                        });
                    }
                };

                WidgetHome.refreshItems = function () {
                    searchOptions.skip = 0;
                    WidgetHome.items = [];
                    WidgetHome.noMore = false;
                    WidgetHome.loadMore();
                };

                WidgetHome.goToMedia = function (ind) {
                    $rootScope.showFeed = false;
                    Location.go('#/media/' + WidgetHome.items[ind].id);
                };

                $rootScope.$on("Carousel:LOADED", function () {
                    if (WidgetHome.media.data.content && WidgetHome.media.data.content.images) {
                        view = new Buildfire.components.carousel.view("#carousel", WidgetHome.media.data.content.images);
                        //view.loadItems(WidgetHome.media.data.content.images, false);
                    } else {
                        view.loadItems([]);
                    }
                });

                Messaging.sendMessageToControl({
                    name: EVENTS.ROUTE_CHANGE,
                    message: {
                        path: PATHS.HOME
                    }
                });

                $rootScope.$watch('showFeed', function () {
                    if ($rootScope.showFeed) {
                        listener.clear();
                        listener = Buildfire.datastore.onUpdate(onUpdateCallback);

                        MediaCenter.get().then(function success(result) {
                                WidgetHome.media = result;
                            },
                            function fail() {
                                WidgetHome.media = _infoData;
                            }
                        );
                    }
                });
                /**
                 * Implementation of pull down to refresh
                 */
                var onRefresh=Buildfire.datastore.onRefresh(function(){
                    Location.goToHome();
                });

            }]);
})(window.angular);<commit_msg>Bring limit up to support all device sizes<commit_after>(function (angular) {
    angular
        .module('mediaCenterWidget')
        .controller('WidgetHomeCtrl', ['$scope', '$window', 'DB', 'COLLECTIONS', '$rootScope', 'Buildfire', 'Messaging', 'EVENTS', 'PATHS', 'Location', 'Orders', '$location',
            function ($scope, $window, DB, COLLECTIONS, $rootScope, Buildfire, Messaging, EVENTS, PATHS, Location, Orders, $location) {
                $rootScope.showFeed = true;
                var WidgetHome = this;
                var _infoData = {
                    data: {
                        content: {
                            images: [],
                            descriptionHTML: '

',
                            description: '',
                            sortBy: Orders.ordersMap.Newest,
                            rankOfLastItem: 0
                        },
                        design: {
                            listLayout: "list-1",
                            itemLayout: "item-1",
                            backgroundImage: ""
                        }
                    }
                };
                var view = null;

                /**
                 * Create instance of MediaContent, MediaCenter db collection
                 * @type {DB}
                 */
                var MediaContent = new DB(COLLECTIONS.MediaContent),
                    MediaCenter = new DB(COLLECTIONS.MediaCenter);

                /**
                 * WidgetHome.media contains MediaCenterInfo.
                 * @type {MediaCenterInfo|*}
                 */
                var MediaCenterInfo = null;
                MediaCenter.get().then(function success(result) {
                        if (result && result.data && result.id) {
                            MediaCenterInfo = result;
                        }
                        else {
                            MediaCenterInfo = _infoData;
                        }
                        WidgetHome.media = MediaCenterInfo;
                        $rootScope.backgroundImage = MediaCenterInfo.data.design.backgroundImage;

                    },
                    function fail() {
                        MediaCenterInfo = _infoData;
                        WidgetHome.media = MediaCenterInfo;
                    }
                );
                var _skip = 0,
                    _limit = 15,
                    searchOptions = {
                        filter: {"$json.title": {"$regex": '/*'}},
                        skip: _skip,
                        limit: _limit + 1 // the plus one is to check if there are any more
                    };
                /**
                 * WidgetHome.isBusy is used for infinite scroll.
                 * @type {boolean}
                 */
                WidgetHome.isBusy = false;

                /*declare the device width heights*/
                $rootScope.deviceHeight = WidgetHome.deviceHeight = window.innerHeight;
                $rootScope.deviceWidth = WidgetHome.deviceWidth = window.innerWidth || 320;

                /*initialize the device width heights*/
                var initDeviceSize = function (callback) {
                    WidgetHome.deviceHeight = window.innerHeight;
                    WidgetHome.deviceWidth = window.innerWidth;
                    if (callback) {
                        if (WidgetHome.deviceWidth == 0 || WidgetHome.deviceHeight == 0) {
                            setTimeout(function () {
                                initDeviceSize(callback);
                            }, 500);
                        } else {
                            callback();
                            if (!$scope.$$phase && !$scope.$root.$$phase) {
                                $scope.$apply();
                            }
                        }
                    }
                };
                /**
                 * Messaging.onReceivedMessage is called when any event is fire from Content/design section.
                 * @param event
                 */
                Messaging.onReceivedMessage = function (event) {
                    if (event) {
                        switch (event.name) {
                            case EVENTS.ROUTE_CHANGE:
                                if((event.message && event.message.path == PATHS.MEDIA && $location.$$path.indexOf('/media') == -1) || (event.message && event.message.path != PATHS.MEDIA)) {
                                    var path = event.message.path,
                                        id = event.message.id;
                                    var url = "#/";
                                    switch (path) {
                                        case PATHS.MEDIA:
                                            url = url + "media/";
                                            if (id) {
                                                url = url + id + "/";
                                            }
                                            break;
                                    }
                                    Location.go(url);
                                    if (path == PATHS.MEDIA) {
                                        $rootScope.showFeed = false;
                                    }
                                    else {
                                        $rootScope.showFeed = true;
                                    }
                                    $scope.$apply();
                                }
                                break;
                            case EVENTS.ITEMS_CHANGE:
                                WidgetHome.refreshItems();
                                break;
                        }
                    }
                };

                var onUpdateCallback = function (event) {
                    if (event.tag == "MediaCenter") {
                        if (event.data) {
                            WidgetHome.media.data = event.data;
                            $rootScope.backgroundImage = WidgetHome.media.data.design.backgroundImage;
                            console.log(WidgetHome.media);
                            $scope.$apply();
                            if (view && event.data.content && event.data.content.images) {
                                view.loadItems(event.data.content.images);
                            }
                            WidgetHome.refreshItems();
                        }
                    }
                    else {
                        WidgetHome.refreshItems();
                    }
                };

                /**
                 * Buildfire.datastore.onUpdate method calls when Data is changed.
                 */
                var listener = Buildfire.datastore.onUpdate(onUpdateCallback);

                /**
                 * updateGetOptions method checks whether sort options changed or not.
                 * @returns {boolean}
                 */
                var updateGetOptions = function () {
                    var order = Orders.getOrder(WidgetHome.media.data.content.sortBy || Orders.ordersMap.Default);
                    if (order) {
                        var sort = {};
                        sort[order.key] = order.order;
                        searchOptions.sort = sort;
                        return true;
                    }
                    else {
                        return false;
                    }
                };

                // ShowDescription only when it have content
                WidgetHome.showDescription = function () {
                    if (WidgetHome.media.data.content.descriptionHTML == '

' || WidgetHome.media.data.content.descriptionHTML == '

'|| WidgetHome.media.data.content.descriptionHTML == '')
                        return false;
                    else
                        return true;
                };

                /**
                 * WidgetHome.items holds the array of items.
                 * @type {Array}
                 */
                WidgetHome.items = [];
                /**
                 * WidgetHome.noMore checks for further data
                 * @type {boolean}
                 */
                WidgetHome.noMore = false;

                /**
                 * loadMore method loads the items in list page.
                 */
                WidgetHome.loadMore = function () {

                    if (WidgetHome.isBusy || WidgetHome.noMore) {
                        return;
                    }
                    updateGetOptions();
                    WidgetHome.isBusy = true;

                    MediaContent.find(searchOptions).then(function success(result) {
                        if (WidgetHome.noMore)
                            return;

                        if (result.length <= _limit) {// to indicate there are more

                            WidgetHome.noMore = true;
                        }
                        else {
                            result.pop();
                            searchOptions.skip = searchOptions.skip + _limit;
                            WidgetHome.noMore = false;
                        }
                        WidgetHome.items = WidgetHome.items ? WidgetHome.items.concat(result) : result;
                        WidgetHome.isBusy = false;
                    }, function fail() {
                        WidgetHome.isBusy = false;
                        console.error('error');
                    });
                };

                WidgetHome.openLinks = function (actionItems, $event) {
                    if (actionItems && actionItems.length) {
                        var options = {};
                        var callback = function (error, result) {
                            if (error) {
                                console.error('Error:', error);
                            }
                        };

                        $event.preventDefault();
                        $timeout(function() {
                            Buildfire.actionItems.list(actionItems, options, callback);
                        });
                    }
                };

                WidgetHome.refreshItems = function () {
                    searchOptions.skip = 0;
                    WidgetHome.items = [];
                    WidgetHome.noMore = false;
                    WidgetHome.loadMore();
                };

                WidgetHome.goToMedia = function (ind) {
                    $rootScope.showFeed = false;
                    Location.go('#/media/' + WidgetHome.items[ind].id);
                };

                $rootScope.$on("Carousel:LOADED", function () {
                    if (WidgetHome.media.data.content && WidgetHome.media.data.content.images) {
                        view = new Buildfire.components.carousel.view("#carousel", WidgetHome.media.data.content.images);
                        //view.loadItems(WidgetHome.media.data.content.images, false);
                    } else {
                        view.loadItems([]);
                    }
                });

                Messaging.sendMessageToControl({
                    name: EVENTS.ROUTE_CHANGE,
                    message: {
                        path: PATHS.HOME
                    }
                });

                $rootScope.$watch('showFeed', function () {
                    if ($rootScope.showFeed) {
                        listener.clear();
                        listener = Buildfire.datastore.onUpdate(onUpdateCallback);

                        MediaCenter.get().then(function success(result) {
                                WidgetHome.media = result;
                            },
                            function fail() {
                                WidgetHome.media = _infoData;
                            }
                        );
                    }
                });
                /**
                 * Implementation of pull down to refresh
                 */
                var onRefresh=Buildfire.datastore.onRefresh(function(){
                    Location.goToHome();
                });

            }]);
})(window.angular);
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
 * (C) Copyright 2013-2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License (LGPL)
 * version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

/**
 * {@link MediaPipeline} basic test suite.
 *
 *

 * Methods tested:
 *

 *
{@link HttpEndpoint#getUrl()}
 *

 *

 * Events tested:
 *

 *
{@link HttpEndpoint#addMediaSessionStartListener(MediaEventListener)}
 *

 * {@link HttpEndpoint#addMediaSessionTerminatedListener(MediaEventListener)}
 *

 *
 * @author Jesús Leganés Combarro "piranna" (piranna@gmail.com)
 * @version 1.0.0
 */

var spawn = require('child_process').spawn;

var QUnit = require('qunit-cli');
QUnit.load();

var kurentoClient = require('..');

// Get ws_port
var ws_port = ""
if (process.argv.length == 3) {
  ws_port = process.argv[2];
}

if (ws_port == "") {
  QUnit.pushFailure("The test needs a ws_port");
}

const ARGV = ['-f', './kurento.conf.json'];
const ws_uri = 'ws://127.0.0.1:' + ws_port + '/kurento'

/**
 * Manage timeouts in an object-oriented style
 */
function Timeout(id, delay, ontimeout) {
  if (!(this instanceof Timeout))
    return new Timeout(id, delay, ontimeout);

  var timeout;

  function _ontimeout(message) {
    this.stop();

    ontimeout(message);
  };

  this.start = function () {
    var delay_factor = delay * Timeout.factor;

    timeout = setTimeout(_ontimeout.bind(this), delay_factor,
      'Time out ' + id + ' (' + delay_factor + 'ms)');
  };

  this.stop = function () {
    clearTimeout(timeout);
  };
};

function getOnError(done) {
  return function onerror(error) {
    QUnit.pushFailure(error.message || error, error.stack);

    done();
  };
}

function sleep(seconds) {
  var e = new Date().getTime() + (seconds * 1000);

  while (new Date().getTime() <= e) {;
  }
}

Timeout.factor = parseFloat(QUnit.config.timeout_factor) || 1;

QUnit.config.testTimeout = 30000 * Timeout.factor;

QUnit.module('reconnect', {
  beforeEach: function () {
    var self = this;

    var options = {
      request_timeout: 5000 * Timeout.factor
    };

    this.server = spawn('kurento-media-server', ARGV)
      .on('error', onerror)

    console.log("Waiting KMS is started...")
    sleep(3)

    this.client = kurentoClient(ws_uri, options)
    this.client.create('MediaPipeline', function (error, pipeline) {
      if (error) return onerror(error);

      self.pipeline = pipeline;

      QUnit.start();
    });

    QUnit.stop();
  },

  afterEach: function () {
    this.client.close();
    this.server.kill()
  }
});

/**
 * restart the MediaServer and keep the session
 */
QUnit.test('MediaServer restarted', function (assert) {
  var self = this;

  QUnit.expect(4);

  var done = assert.async()
  var onerror = getOnError(done)

  var client = self.client
  var pipeline = self.pipeline

  var sessionId = client.sessionId;

  // restart MediaServer
  self.server.kill();
  self.server.on('exit', function (code, signal) {
    assert.equal(code, undefined, 'MediaServer killed');

    client._resetCache()

    self.server = spawn('kurento-media-server', ARGV)
      .on('error', onerror)

    console.log("Waiting KMS is started again...")
    sleep(3)

    client.getMediaobjectById(pipeline.id, function (error, mediaObject) {
      assert.notEqual(error, undefined);
      assert.strictEqual(error.code, 40101);

      assert.strictEqual(client.sessionId, sessionId);

      done();
    })
  })
});

/**
 * All objects are Invalid after the MediaServer got down
 */
QUnit.test('MediaServer closed, client disconnected', function (assert) {
  var self = this;

  QUnit.expect(2);

  var done = assert.async()
  var onerror = getOnError(done)

  var client = self.client
  var pipeline = self.pipeline

  // stop MediaServer
  self.server.kill();
  self.server.on('exit', function (code, signal) {
    client.once('disconnect', function (error) {
      assert.notEqual(error, undefined);

      assert.throws(function () {
          client.sessionId
        },
        new SyntaxError('Client has been disconnected'));

      done();
    });
  })
});
<commit_msg>Add support for showing kms logs on the test<commit_after>#!/usr/bin/env node

/*
 * (C) Copyright 2013-2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License (LGPL)
 * version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

/**
 * {@link MediaPipeline} basic test suite.
 *
 *

 * Methods tested:
 *

 *
{@link HttpEndpoint#getUrl()}
 *

 *

 * Events tested:
 *

 *
{@link HttpEndpoint#addMediaSessionStartListener(MediaEventListener)}
 *

 * {@link HttpEndpoint#addMediaSessionTerminatedListener(MediaEventListener)}
 *

 *
 * @author Jesús Leganés Combarro "piranna" (piranna@gmail.com)
 * @version 1.0.0
 */

var spawn = require('child_process').spawn;

var QUnit = require('qunit-cli');
QUnit.load();

var kurentoClient = require('..');

// Get ws_port
var ws_port = ""
if (process.argv.length == 3) {
  ws_port = process.argv[2];
}

if (ws_port == "") {
  QUnit.pushFailure("The test needs a ws_port");
}

const ARGV = ['-f', './kurento.conf.json', '--gst-debug=Kurento*:5', '2>&1'];
const ws_uri = 'ws://127.0.0.1:' + ws_port + '/kurento'

/**
 * Manage timeouts in an object-oriented style
 */
function Timeout(id, delay, ontimeout) {
  if (!(this instanceof Timeout))
    return new Timeout(id, delay, ontimeout);

  var timeout;

  function _ontimeout(message) {
    this.stop();

    ontimeout(message);
  };

  this.start = function () {
    var delay_factor = delay * Timeout.factor;

    timeout = setTimeout(_ontimeout.bind(this), delay_factor,
      'Time out ' + id + ' (' + delay_factor + 'ms)');
  };

  this.stop = function () {
    clearTimeout(timeout);
  };
};

function getOnError(done) {
  return function onerror(error) {
    QUnit.pushFailure(error.message || error, error.stack);

    done();
  };
}

function sleep(seconds) {
  var e = new Date().getTime() + (seconds * 1000);

  while (new Date().getTime() <= e) {;
  }
}

Timeout.factor = parseFloat(QUnit.config.timeout_factor) || 1;

QUnit.config.testTimeout = 30000 * Timeout.factor;

QUnit.module('reconnect', {
  beforeEach: function () {
    var self = this;

    var options = {
      request_timeout: 5000 * Timeout.factor
    };

    this.server = spawn('kurento-media-server', ARGV)
      .on('error', onerror)

    this.server.stdout.on('data', function (data) {
      console.log('stdout: ' + data);
    });

    this.server.stderr.on('data', function (data) {
      console.log('stderr: ' + data);
    });

    console.log("Waiting KMS is started... KMS pid:", this.server.pid)

    this.client = kurentoClient(ws_uri, options)
    this.client.create('MediaPipeline', function (error, pipeline) {
      if (error) return onerror(error);

      self.pipeline = pipeline;

      QUnit.start();
    });

    QUnit.stop();
  },

  afterEach: function () {
    this.client.close();
    this.server.kill()
  }
});

/**
 * restart the MediaServer and keep the session
 */
QUnit.test('MediaServer restarted', function (assert) {
  var self = this;

  QUnit.expect(4);

  var done = assert.async()
  var onerror = getOnError(done)

  var client = self.client
  var pipeline = self.pipeline

  var sessionId = client.sessionId;

  // restart MediaServer
  self.server.kill();
  self.server.on('exit', function (code, signal) {
    assert.equal(code, undefined, 'MediaServer killed');

    client._resetCache()

    self.server = spawn('kurento-media-server', ARGV)
      .on('error', onerror)

    self.server.stdout.on('data', function (data) {
      console.log('stdout: ' + data);
    });

    self.server.stderr.on('data', function (data) {
      console.log('stderr: ' + data);
    });

    console.log("Waiting KMS is started again... KMS pid:", self.server
      .pid)

    client.getMediaobjectById(pipeline.id, function (error, mediaObject) {
      assert.notEqual(error, undefined);
      assert.strictEqual(error.code, 40101);

      assert.strictEqual(client.sessionId, sessionId);

      done();
    })
  })
});

/**
 * All objects are Invalid after the MediaServer got down
 */
QUnit.test('MediaServer closed, client disconnected', function (assert) {
  var self = this;

  QUnit.expect(2);

  var done = assert.async()
  var onerror = getOnError(done)

  var client = self.client
  var pipeline = self.pipeline

  // stop MediaServer
  self.server.kill();
  self.server.on('exit', function (code, signal) {
    client.once('disconnect', function (error) {
      assert.notEqual(error, undefined);

      assert.throws(function () {
          client.sessionId
        },
        new SyntaxError('Client has been disconnected'));

      done();
    });
  })
});
<|endoftext|>


<commit_before>var addressPoints = [
  [
    "Berkeley CA, USA",
    37.8708393,
    -122.2728638
  ],
  [
    "London, UK",
    51.5073219,
    -0.1276473
  ],
  [
    "San Francisco, California",
    37.7792808,
    -122.4192362
  ],
  [
    "Los Angeles, CA",
    34.0543942,
    -118.2439408
  ]
];<commit_msg>Delete org-locations.js<commit_after><|endoftext|>


<commit_before>/*
 * grunt-angular-service
 * https://github.com/obibring/grunt-angular-service
 *
 * Copyright (c) 2013 Orr Bibring
 * Licensed under the MIT license.
 */

/* Jshint directives below */
/*global module:true */
/*global require:true */

"use strict";
var _ = require('underscore');
var beautify = require('js-beautify').js_beautify;

var quoteWrap = function (dep) {
  // Wrap dependency in quotes.
  return "'" + dep + "'";
};

var VALID_EXPORT_STRATEGIES = ['window', 'context', 'node'];
var VALID_PROVIDERS = ['service', 'factory'];
var DEFAULT_PROVIDER = 'factory';

function isValidExportStrategy (strategy) {
  return VALID_EXPORT_STRATEGIES.indexOf(strategy) > -1;
}

function isValidProvider (provider) {
  return VALID_PROVIDERS.indexOf(provider) > -1;
}

// Template that wraps JavaScript in angular factory definition.
//
// @param exportStrategy {String} There are many ways in which a JavaScript can
//   expose its API. By default, grunt-angular-service tries to make an educated
//   guess as to how the target library does so. If the default strategy
// @param defineModule {Boolean} Whether to define a new module when creating
//   the service.
// @param modDeps {Array} A list of dependencies to be passed as the second
//   argument to the module definition. `defineModule` must be set to `true`
//   for this to take effect.
// @param deps {Array} A list of dependencies that will be made available to
//   the target library as properties on `this`.
// @param choose {String} If `exportStrategy` is 'this', then
//
var makeTemplate = function(exportStrategy, defineModule, modDeps, deps, choose) {

  var defineStr = defineModule ? ', [' + modDeps.map(quoteWrap).join(', ') + ']' : '';
  var srvcStr = deps.length ? deps.map(quoteWrap).join(', ') + ', ' : '';

  // Create the content for the service provider function. This is the code passed to
  // one of angular's provider methods ('service', 'factory', etc). Each exportStrategy
  // will set a different value for this body.
  var funcBody = "";

  if (exportStrategy === 'window') {
    funcBody +=
      "   var window = {};" +
      "   var injected = {};";

      // Loop through each dependency, and assign it as a property on the
    // context that the target library will execute in.
    deps.forEach(function(dep){
      funcBody +=
        " window['" + dep + "'] = " + dep + ";" +
        " injected['" + dep + "'] = true;";
    });

    funcBody +=
      "   <%= targetLibrarySourceCode %>";

    if (choose) {
      funcBody +=
        " return window['" + choose + "']; ";
    } else {
      // Check if the target library only exported a single value onto window.
      // If so, return that single value, otherwise return the entire mock
      // window object.
      funcBody +=
        " var propsAddedByTargetLib = [];" +
        " angular.forEach(window, function (val, prop) { " +
        "   if (angular.isUndefined(injected[prop])) { " +
        "     propsAddedByTargetLib.push(val); " +
        "   }" +
        " });" +
        " if (propsAddedByTargetLib.length === 1) {" +
        "   return propsAddedByTargetLib.pop();" +
        " } else { " +
        "   return window;" +
        " } ";
    }
  } // "window" exportStrategy

  // Export Strategy #1: `this`
  if (exportStrategy === 'context') {
    funcBody +=
      "   var temp = function() {" +
      "     <%= targetLibrarySourceCode %>" +
      "   };" +
      "   var context = {}; " + // Create the context we call our temporary function with.
      "   var injected = {}; "; // Keep track of dependencies injected into `context`.

    // Loop through each dependency, and assign it as a property on the
    // context that the target library will execute in.
    deps.forEach(function(dep){
      funcBody +=
        " context['" + dep + "'] = " + dep + ";" +
        " injected['" + dep + "'] = true;";
    });

    funcBody +=
      "   temp.call(context);";

    if (choose) {
      funcBody +=
        " return context['" + choose + "']; ";
    } else {
      // Check if the target library only exported a single value onto context.
      // If so, return that single value, otherwise return the entire context
      // object.
      funcBody +=
        " var propsAddedByTargetLib = [];" +
        " angular.forEach(context, function (val, prop) { " +
        "   if (angular.isUndefined(injected[prop])) { " +
        "     propsAddedByTargetLib.push(val);" +
        "   }" +
        " });" +
        " if (propsAddedByTargetLib.length === 1) {" +
        "   return propsAddedByTargetLib.pop();" +
        " } else { " +
        "   return context;" +
        " } ";
    }
  } // end `context` exportStrategy

  // Export Strategy #2: node
  if (exportStrategy === 'node') {
    funcBody +=
      "   var injected = {};";

    // Loop through each dependency, and assign it as a property on the
    // inject object to be used by our mock `require()` function.
    deps.forEach(function(dep){
      funcBody +=
        " injected['" + dep + "'] = " + dep + ";";
    });

    funcBody +=
      // Mock the require() function for providing dependencies to the target lib.
      "   var require = function (dependency) { " +
      "     return injected[dependency]; " +
      "   }" +
      // Create a variable that mocks the global `module` provided by node.
      // Later, we inspect this shadowed object to see if the target library added
      // properties onto it.
      "   var module = {exports: {}}, exports = module.exports; " +
      "   <%= targetLibrarySourceCode %>" +
      // If module.exports was set to something else, return it.
      "   if (!angular.isObject(module.exports)) { " +
      "     return module.exports;" +
      "   }";

    if (choose) {
      funcBody +=
        " return module.exports['" + choose + "']; ";
    } else {
      // Check if the target library only exported a single value onto context.
      // If so, return that single value, otherwise return the entire context
      // object.
      funcBody +=
        " var propsAddedByTargetLib = [];" +
        " angular.forEach(module.exports, function (val, prop) { " +
        "   if (angular.isUndefined(injected[prop])) { " +
        "     propsAddedByTargetLib.push(val);" +
        "   }" +
        " });" +
        " if (propsAddedByTargetLib.length === 1) {" +
        "   return propsAddedByTargetLib.pop();" +
        " } else { " +
        "   return module.exports;" +
        " } ";
    }
  } // end `exports` exportStrategy

  // Export strategy #3: `value`
  if (exportStrategy === 'value') {
    funcBody +=
      "   var returnValue = <%= targetLibrarySourceCode %>;";

    if (choose) {
      funcBody +=
        " return returnValue['" + choose + "']; ";
    } else {
      funcBody +=
        " return returnValue;";
    }
  } // end `value` exportStrategy

  var template =
    "(function(angular) {"+
    "  angular.module('<%= module %>'" + defineStr +  ")" +
    "    .<%= provider %>('<%= name %>', [" + srvcStr + "function("+ deps.join(', ') +") {" +
    "      " + funcBody +
    "    }]);" +
    "})(window.angular);";

  return template;
};

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('ngservice',
    'Generate AngularJS services from JavaScript libraries', function() {

        var warn = function (message) {
          grunt.log.warn(this.name + ": " + message);
        }.bind(this);

        var log = function (message) {
          grunt.log.writeln(this.name + ": " + message);
        }.bind(this);

        var fatal = function (message) {
          grunt.fatal(this.name + ": " + message);
        }.bind(this);

      var data = this.data;

      if (!_.has(data, 'exportStrategy')) {
        fatal('`exportStrategy` setting not provided.');
      }

      // Determine validity of `module` option.
      if (!_.has(data, 'module') || !_.isString(data.module)) {
        fatal('Invalid `module` setting.');
      }

      // Determine validity of `name` option.
      if (!_.has(data, 'name') || !_.isString(data.name)) {
        fatal('Invalid `name` setting.');
      }

      // Determine validity of `defineModule` option.
      if (_.has(data, 'defineModule') && !_.isBoolean(data.defineModule)) {
        fatal('Invalid `defineModule` option.');
      }

      var exportStrategy = data.exportStrategy;
      var provider = data.provider || DEFAULT_PROVIDER;   // Type of Angular provider to declare.
      var module = data.module;                           // Name of module.
      var defineModule = data.defineModule || false;      // Define the module?
      var modDeps = data.moduleDependencies || [];        // Service dependencies.
      var deps = data.inject || [];                       // Service dependencies.
      var name = data.name;                               // Name of service.
      var choose = data.choose;
      var pretty = data.pretty || true;

      // If pretty is `true`, set it to default beautifier settings.
      if (pretty === true) {
        pretty = {indent_size: 2, indent_char: ' '};
      }

      if (!isValidExportStrategy(exportStrategy)) {
        fatal("Invalid export strategy. Must be one of: " + VALID_EXPORT_STRATEGIES.join(', '));
      }

      if (!isValidProvider(provider)) {
        fatal("Invalid provider. Must be one of: " + VALID_PROVIDERS.join(', '));
      }

      if (_.isString(deps)) {
        deps = [deps];
      }

      if (_.isString(modDeps)) {
        modDeps = [modDeps];
      }

      var sources = [];

      // Iterate over all specified file groups.
      this.files.forEach(function(f) {
        f.src.filter(function(filepath) {
          // Warn on and remove invalid source files (if nonull was set).
          if (!grunt.file.exists(filepath)) {
            warn('Source file "' + filepath + '" not found.');
            return false;
          } else {
            return true;
          }
        }).map(function(filepath) {
          // Read file source.
          return grunt.file.read(filepath);
        }).forEach(function(srcString) {
          sources.push(srcString);
        });

        // If sources is empty, die.
        if (sources.length < 1) {
          fatal('No source files provided.');
        }

        var template = makeTemplate(exportStrategy, defineModule, modDeps, deps, choose);
        var formatter = pretty ? beautify : function(src) { return src; };

        // Write the destination file.
        grunt.file.write(f.dest, formatter(_.template(template, {
          provider: provider,
          targetLibrarySourceCode: sources.join("\n"),
          module: module,
          name: name
        }), pretty));

        // Print a success message.
        log('File "' + f.dest + '" created.');

    });
  });

};
<commit_msg>Fix comment typo<commit_after>/*
 * grunt-angular-service
 * https://github.com/obibring/grunt-angular-service
 *
 * Copyright (c) 2013 Orr Bibring
 * Licensed under the MIT license.
 */

/* Jshint directives below */
/*global module:true */
/*global require:true */

"use strict";
var _ = require('underscore');
var beautify = require('js-beautify').js_beautify;

var quoteWrap = function (dep) {
  // Wrap dependency in quotes.
  return "'" + dep + "'";
};

var VALID_EXPORT_STRATEGIES = ['window', 'context', 'node'];
var VALID_PROVIDERS = ['service', 'factory'];
var DEFAULT_PROVIDER = 'factory';

function isValidExportStrategy (strategy) {
  return VALID_EXPORT_STRATEGIES.indexOf(strategy) > -1;
}

function isValidProvider (provider) {
  return VALID_PROVIDERS.indexOf(provider) > -1;
}

// Template that wraps JavaScript in angular factory definition.
//
// @param exportStrategy {String} There are many ways in which a JavaScript can
//   expose its API. By default, grunt-angular-service tries to make an educated
//   guess as to how the target library does so. If the default strategy
// @param defineModule {Boolean} Whether to define a new module when creating
//   the service.
// @param modDeps {Array} A list of dependencies to be passed as the second
//   argument to the module definition. `defineModule` must be set to `true`
//   for this to take effect.
// @param deps {Array} A list of dependencies that will be made available to
//   the target library as properties on `this`.
// @param choose {String} If `exportStrategy` is 'this', then
//
var makeTemplate = function(exportStrategy, defineModule, modDeps, deps, choose) {

  var defineStr = defineModule ? ', [' + modDeps.map(quoteWrap).join(', ') + ']' : '';
  var srvcStr = deps.length ? deps.map(quoteWrap).join(', ') + ', ' : '';

  // Create the content for the service provider function. This is the code passed to
  // one of angular's provider methods ('service', 'factory', etc). Each exportStrategy
  // will set a different value for this body.
  var funcBody = "";

  if (exportStrategy === 'window') {
    funcBody +=
      "   var window = {};" +
      "   var injected = {};";

      // Loop through each dependency, and assign it as a property on the
    // context that the target library will execute in.
    deps.forEach(function(dep){
      funcBody +=
        " window['" + dep + "'] = " + dep + ";" +
        " injected['" + dep + "'] = true;";
    });

    funcBody +=
      "   <%= targetLibrarySourceCode %>";

    if (choose) {
      funcBody +=
        " return window['" + choose + "']; ";
    } else {
      // Check if the target library only exported a single value onto window.
      // If so, return that single value, otherwise return the entire mock
      // window object.
      funcBody +=
        " var propsAddedByTargetLib = [];" +
        " angular.forEach(window, function (val, prop) { " +
        "   if (angular.isUndefined(injected[prop])) { " +
        "     propsAddedByTargetLib.push(val); " +
        "   }" +
        " });" +
        " if (propsAddedByTargetLib.length === 1) {" +
        "   return propsAddedByTargetLib.pop();" +
        " } else { " +
        "   return window;" +
        " } ";
    }
  } // "window" exportStrategy

  // Export Strategy #1: `this`
  if (exportStrategy === 'context') {
    funcBody +=
      "   var temp = function() {" +
      "     <%= targetLibrarySourceCode %>" +
      "   };" +
      "   var context = {}; " + // Create the context we call our temporary function with.
      "   var injected = {}; "; // Keep track of dependencies injected into `context`.

    // Loop through each dependency, and assign it as a property on the
    // context that the target library will execute in.
    deps.forEach(function(dep){
      funcBody +=
        " context['" + dep + "'] = " + dep + ";" +
        " injected['" + dep + "'] = true;";
    });

    funcBody +=
      "   temp.call(context);";

    if (choose) {
      funcBody +=
        " return context['" + choose + "']; ";
    } else {
      // Check if the target library only exported a single value onto context.
      // If so, return that single value, otherwise return the entire context
      // object.
      funcBody +=
        " var propsAddedByTargetLib = [];" +
        " angular.forEach(context, function (val, prop) { " +
        "   if (angular.isUndefined(injected[prop])) { " +
        "     propsAddedByTargetLib.push(val);" +
        "   }" +
        " });" +
        " if (propsAddedByTargetLib.length === 1) {" +
        "   return propsAddedByTargetLib.pop();" +
        " } else { " +
        "   return context;" +
        " } ";
    }
  } // end `context` exportStrategy

  // Export Strategy #2: node
  if (exportStrategy === 'node') {
    funcBody +=
      "   var injected = {};";

    // Loop through each dependency, and assign it as a property on the
    // inject object to be used by our mock `require()` function.
    deps.forEach(function(dep){
      funcBody +=
        " injected['" + dep + "'] = " + dep + ";";
    });

    funcBody +=
      // Mock the require() function for providing dependencies to the target lib.
      "   var require = function (dependency) { " +
      "     return injected[dependency]; " +
      "   }" +
      // Create a variable that mocks the global `module` provided by node.
      // Later, we inspect this shadowed object to see if the target library added
      // properties onto it.
      "   var module = {exports: {}}, exports = module.exports; " +
      "   <%= targetLibrarySourceCode %>" +
      // If module.exports was set to something else, return it.
      "   if (!angular.isObject(module.exports)) { " +
      "     return module.exports;" +
      "   }";

    if (choose) {
      funcBody +=
        " return module.exports['" + choose + "']; ";
    } else {
      // Check if the target library only exported a single value onto context.
      // If so, return that single value, otherwise return the entire context
      // object.
      funcBody +=
        " var propsAddedByTargetLib = [];" +
        " angular.forEach(module.exports, function (val, prop) { " +
        "   if (angular.isUndefined(injected[prop])) { " +
        "     propsAddedByTargetLib.push(val);" +
        "   }" +
        " });" +
        " if (propsAddedByTargetLib.length === 1) {" +
        "   return propsAddedByTargetLib.pop();" +
        " } else { " +
        "   return module.exports;" +
        " } ";
    }
  } // end `exports` exportStrategy

  // Export strategy #3: `value`
  if (exportStrategy === 'value') {
    funcBody +=
      "   var returnValue = <%= targetLibrarySourceCode %>;";

    if (choose) {
      funcBody +=
        " return returnValue['" + choose + "']; ";
    } else {
      funcBody +=
        " return returnValue;";
    }
  } // end `value` exportStrategy

  var template =
    "(function(angular) {"+
    "  angular.module('<%= module %>'" + defineStr +  ")" +
    "    .<%= provider %>('<%= name %>', [" + srvcStr + "function("+ deps.join(', ') +") {" +
    "      " + funcBody +
    "    }]);" +
    "})(window.angular);";

  return template;
};

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('ngservice',
    'Generate AngularJS services from JavaScript libraries', function() {

        var warn = function (message) {
          grunt.log.warn(this.name + ": " + message);
        }.bind(this);

        var log = function (message) {
          grunt.log.writeln(this.name + ": " + message);
        }.bind(this);

        var fatal = function (message) {
          grunt.fatal(this.name + ": " + message);
        }.bind(this);

      var data = this.data;

      if (!_.has(data, 'exportStrategy')) {
        fatal('`exportStrategy` setting not provided.');
      }

      // Determine validity of `module` option.
      if (!_.has(data, 'module') || !_.isString(data.module)) {
        fatal('Invalid `module` setting.');
      }

      // Determine validity of `name` option.
      if (!_.has(data, 'name') || !_.isString(data.name)) {
        fatal('Invalid `name` setting.');
      }

      // Determine validity of `defineModule` option.
      if (_.has(data, 'defineModule') && !_.isBoolean(data.defineModule)) {
        fatal('Invalid `defineModule` option.');
      }

      var exportStrategy = data.exportStrategy;
      var provider = data.provider || DEFAULT_PROVIDER;   // Type of Angular provider to declare.
      var module = data.module;                           // Name of module.
      var defineModule = data.defineModule || false;      // Define the module?
      var modDeps = data.moduleDependencies || [];        // Module dependencies.
      var deps = data.inject || [];                       // Service dependencies.
      var name = data.name;                               // Name of service.
      var choose = data.choose;
      var pretty = data.pretty || true;

      // If pretty is `true`, set it to default beautifier settings.
      if (pretty === true) {
        pretty = {indent_size: 2, indent_char: ' '};
      }

      if (!isValidExportStrategy(exportStrategy)) {
        fatal("Invalid export strategy. Must be one of: " + VALID_EXPORT_STRATEGIES.join(', '));
      }

      if (!isValidProvider(provider)) {
        fatal("Invalid provider. Must be one of: " + VALID_PROVIDERS.join(', '));
      }

      if (_.isString(deps)) {
        deps = [deps];
      }

      if (_.isString(modDeps)) {
        modDeps = [modDeps];
      }

      var sources = [];

      // Iterate over all specified file groups.
      this.files.forEach(function(f) {
        f.src.filter(function(filepath) {
          // Warn on and remove invalid source files (if nonull was set).
          if (!grunt.file.exists(filepath)) {
            warn('Source file "' + filepath + '" not found.');
            return false;
          } else {
            return true;
          }
        }).map(function(filepath) {
          // Read file source.
          return grunt.file.read(filepath);
        }).forEach(function(srcString) {
          sources.push(srcString);
        });

        // If sources is empty, die.
        if (sources.length < 1) {
          fatal('No source files provided.');
        }

        var template = makeTemplate(exportStrategy, defineModule, modDeps, deps, choose);
        var formatter = pretty ? beautify : function(src) { return src; };

        // Write the destination file.
        grunt.file.write(f.dest, formatter(_.template(template, {
          provider: provider,
          targetLibrarySourceCode: sources.join("\n"),
          module: module,
          name: name
        }), pretty));

        // Print a success message.
        log('File "' + f.dest + '" created.');

    });
  });

};
<|endoftext|>