<commit_before>// @flow
import React from 'react'
import {
  Alert,
  Keyboard,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  ScrollView,
  View
} from 'react-native'
import SegmentedControlTab from 'react-native-segmented-control-tab'
import expect from 'expect'
import moment from 'moment'
import PropTypes from 'prop-types'

import { capitalizeFirstLetter } from './utilities/String+Capitalize'
import { SRDarkColor, SRYellowColor, SRBrightColor, SRRedColor } from './utilities/SRColors'

const studyTaskString = 'Study Task'
const notesString = 'Notes'
const dateString = 'Starting Date'

const SRPlaceholderTextColor = 'rgba(251, 251, 253, 0.5)'

const inactiveColor = SRBrightColor
const buttonHeight = 46
const buttonCornerRadius = buttonHeight/2
const cancelButtonTint = SRDarkColor
const tintColor = SRRedColor

const dateSegmentedControlCornerRadius = 4

export default class SRStudyTaskEditor extends React.Component {

  static navigationOptions = (props) => {
    const { readonly } = props

    return {
      headerTintColor: SRDarkColor,
      headerStyle: {
        backgroundColor: SRBrightColor
      },
      title: readonly ? 'Details' : 'Add a task',
    }
  }

  state: {
    editMode: bool,
    hasChanges: bool,

    taskName: string,
    notes: string,
    date: string,

    studyTaskLabelString: string,
    notesLabelString: string,
    pickedDate: string,
    selectedDateIndex: number,
    selectedIntensityIndex: number,
  }

  _initialState = (props: Object) => {
    const { item } = props

    return {
      editMode: false,
      hasChanges: false,

      taskName: item != null && item.taskName != null ? item.taskName : '',
      notes: item != null && item.notes != null ? item.notes : '',
      date: new Date().toString(),

      studyTaskLabelString: item != null && item.taskName != null ? studyTaskString : ' ',
      notesLabelString: item != null && item.notes != null ? notesString : ' ',
      pickedDate: 'Other', // TODO: implement
      selectedDateIndex: 0,
      selectedIntensityIndex: 0,
    }
  }
  constructor(props: Object) {
    super(props)
    this.state = this._initialState(props)
  }

  componentWillMount() {
    const { notes, taskName } = this.props

    const taskNameTextFieldIsEmpty = taskName == null || taskName == ''
    this.hideStudyTaskLabel(taskNameTextFieldIsEmpty)

    const notesTextFieldIsEmpty = notes == null || notes == ''
    this.hideNotesLabel(notesTextFieldIsEmpty)
  }

  componentDidMount() {
  }

  componentWillReceiveProps() {
  }

  render() {
    const { readonly } = this.props
    const {
      editMode,
      taskName,
      notes,
      studyTaskLabelString
    } = this.state

    const actionButtonTitle = (readonly && editMode == false) ? 'Edit' : 'Save'
    const destructiveButtonTitle = (readonly && editMode == false) ? 'Delete' : 'Cancel'

    const disableActionButton = taskName == null || taskName == ''
    const editingOrAddingNewTask = editMode || !readonly
    const viewingOnly = readonly && !editMode
    const notesExistOrEditingOrAddingTask = !readonly || editMode || (notes != null && notes != '')
    const NOT_IMPLEMENTED = false

    return (
      <ScrollView
        style={styles.scrollView}
        keyboardDismissMode={'on-drag'}
        keyboardShouldPersistTaps={'handled'}
        >
        <View style={styles.edgePadding}>

          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{studyTaskLabelString}</Text>
            <TextInput
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={studyTaskString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={(event) => {
                this.refs.notesTextInput.focus()
              }}
              onChangeText={(taskName) => this.studyTextFieldOnChangeText(taskName)}
              value={taskName}
              editable={editingOrAddingNewTask}
              multiline={viewingOnly}
              autoFocus={!readonly}
              returnKeyType={'next'}
            />
            {this._renderSeparator(editingOrAddingNewTask)}
          </View>

          {this._renderNotes(notesExistOrEditingOrAddingTask)}
          {this._renderDateSelection(!readonly)}
          {this._renderRatingHistory(NOT_IMPLEMENTED)}

          <View name='dataSeparator' style={[styles.sectionSeparator, styles.lastSectionSeparator]}/>

          <View style={[styles.sections, styles.bottomButtonsView]}>
            <TouchableOpacity
              style={this.disabledButtonStyle(disableActionButton)}
              disabled={disableActionButton}
              onPress={this.actionButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.actionButtonText]}>{actionButtonTitle}</Text>
            </TouchableOpacity>

            <TouchableOpacity
              style={[styles.dataInputItemPadding, styles.bottomButtons, styles.cancelButton]}
              onPress={this.destructiveButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.destructiveButtonText]}>{destructiveButtonTitle}</Text>
            </TouchableOpacity>
          </View>

        </View>
      </ScrollView>
    )
  }

  // Data input

  studyTextFieldOnChangeText = (taskName: string) => {
    const taskNameExists = taskName == null || taskName == ''
    this.hideStudyTaskLabel(taskNameExists)
    this.setState({
      taskName,
      hasChanges: true
    })
  }

  notesTextFieldOnChangeText = (notes: string) => {
    const notesExist = notes == null || notes == ''
    this.hideNotesLabel(notesExist)
    this.setState({
      notes,
      hasChanges: true
    })
  }

  handleDateSelection = (index: number) => {
    var selectedDate = new Date()
    switch(index) {
      case 0:
        selectedDate = new Date()
        break
      case 1:
        selectedDate = new Date(moment().subtract(1, 'days'))
        break
      case 2:
        this.openDatePicker()
        break
      default:
      throw 'handleDateSelection()'
    }

    this.setState({
      date: selectedDate.toString(),
      selectedDateIndex: index,
      hasChanges: true
    })
  }

  handleIntensitySelection = (index: number) => {
    this.setState({
      selectedIntensityIndex: index,
      hasChanges: true
    })
  }

  // Actions

  actionButtonAction = () => {
    const { readonly, item } = this.props
    const { editMode } = this.state
    const wantsEdit = readonly && !editMode

    if(wantsEdit) {
      this.setState({editMode: true})
    } else { // Save data input
      const { readonly, saveAction } = this.props
      const { taskName, notes, date } = this.state

      expect(taskName).toExist('No taskName')
      expect(taskName).toNotEqual('','taskName is empty string')

      const newItemChanges = {
        taskName: taskName,
        notes: notes,
        date: date,
      }

      saveAction(newItemChanges, item)
      if(readonly) {
        this.setState({editMode: false})
      }
    }

  }

  destructiveButtonAction = () => {
    const { readonly, deleteAction, cancelAction, item } = this.props
    const { editMode, hasChanges } = this.state
    const deleteWhenReadonly = readonly && !editMode
    const cancelEditing = readonly && editMode
    const dismissAddingNewTask = !readonly

    if (deleteWhenReadonly) {
      deleteAction(item)
    } else if(cancelEditing) {
      if (hasChanges) {
        Alert.alert(
          'Discard Changes',
          'Are you sure you want to discard your changes?',
          [
            {text: 'Keep Editing', onPress: () => {}, style: 'cancel'},
            {text: 'Discard Changes', onPress: () => {
              this.resetFields()
              this.setState({editMode: false})
            }},
          ],
          { cancelable: true }
        )
      } else {
        this.resetFields()
        this.setState({editMode: false})
      }
    } else if (dismissAddingNewTask) {
      cancelAction()
    } else {
      expect(0).toBe(1, 'destructiveButtonAction() else')
    }
  }

  resetFields = () => {
    this.setState({
      ...this.state,
      ...this._initialState(this.props),
    })
  }

  // UI changes

  hideStudyTaskLabel = (flag: bool = true) => {
    this.setState({
      studyTaskLabelString: flag ? ' ' : studyTaskString.toUpperCase()
    })
  }

  hideNotesLabel = (flag: bool = true) => {
    this.setState({
      notesLabelString: flag ? ' ' : notesString.toUpperCase()
    })
  }

  openDatePicker = () => {
    // TODO: missing implementation
    // pickedDate = '' // set this to a nicely formatted date
  }

  _renderSeparator = (flag) => {
    if(flag) {
      return <View name='separator' style={styles.sectionSeparator}/>
    } else {
      return null
    }
  }

  _renderNotes = (flag) => {
      if(flag) {
        const { readonly } = this.props
        const { notes, notesLabelString, editMode } = this.state
        const editingOrAddingNewTask = editMode || !readonly
        const viewingOnly = readonly && !editMode
        return(
          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{notesLabelString}</Text>
            <TextInput
              ref='notesTextInput'
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={notesString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={Keyboard.dismiss}
              onChangeText={(notes) => this.notesTextFieldOnChangeText(notes)}
              value={notes}
              editable={editingOrAddingNewTask}
              multiline={viewingOnly}
              returnKeyType={'done'}
            />
            {this._renderSeparator(!readonly)}
          </View>
        )
      } else {
        return null
      }
  }

  _renderDateSelection = (flag) => {
    if(flag) {
      const { pickedDate } = this.state
      const formattedPickedDate = pickedDate // TODO:
      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>{dateString.toUpperCase()}</Text>
          <SegmentedControlTab
            borderRadius={dateSegmentedControlCornerRadius}
            tabsContainerStyle={styles.tabsContainerStyle}
            tabStyle={styles.tabStyle}
            tabTextStyle={styles.tabTextStyle}
            activeTabStyle={styles.activeTabStyle}
            activeTabTextStyle={styles.activeTabTextStyle}
            values={['Today', 'Yesterday', formattedPickedDate]}
            selectedIndex={this.state.selectedDateIndex}
            onTabPress={this.handleDateSelection}
          />
        </View>
      )
    } else {
      return null
    }
  }

  _renderRatingHistory = (flag) => {
    if(flag) {
      // TODO: missing implementation
      // if made changes then set hasChanges: true
      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>Rating History</Text>

        </View>
      )
    } else {
      return null
    }
  }

  disabledButtonStyle = (flag: bool) => {
    const defaultStyle = [styles.dataInputItemPadding, styles.bottomButtons, styles.actionButton]
    if(flag) {
      return [...defaultStyle, styles.actionButtonDisabled]
    } else {
      return defaultStyle
    }
  }

}

SRStudyTaskEditor.propTypes = {
  item: PropTypes.shape({
    title: PropTypes.string,
    notes: PropTypes.string,
  }),

  saveAction: PropTypes.func.isRequired,
  deleteAction: PropTypes.func,
  cancelAction: PropTypes.func,

  readonly: PropTypes.bool.isRequired,
}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
    backgroundColor: SRDarkColor,
  },
  edgePadding: {
    padding: 15,
    flex:1,
  },
  dataInputItemPadding: {
    padding: 4,
  },
  textInput: {
    fontSize: 48,
    color: SRBrightColor,
  },
  sectionLabel: {
    fontSize: 20,
    color: SRRedColor,
    fontWeight: 'bold'
  },
  sectionSeparator: {
    backgroundColor: SRBrightColor,
    height: 1,
  },
  lastSectionSeparator: {
    marginTop: 8,
  },
  sections: {
    padding: 8,
  },
  bottomButtonsView: {
    flexDirection: 'column',
    paddingTop: 20,
  },
  bottomButtons: {
    alignItems: 'center',
    height: buttonHeight,
    justifyContent: 'center',
  },
  actionButton: {
    backgroundColor: SRYellowColor,
    borderRadius: buttonCornerRadius,
    flex: 1,
  },
  actionButtonDisabled: {
    backgroundColor: 'rgba(255, 252, 49, 0.5)'
  },
  cancelButton: {
    borderColor: SRYellowColor,
    borderWidth: 1,
    borderRadius: buttonCornerRadius,
    flex: 1,
    marginTop: 10,
  },
  bottomButtonsText: {
    color: SRDarkColor,
    fontSize: 16,
    fontWeight: 'bold',
  },
  actionButtonText: {
    paddingTop: 1,
  },
  destructiveButtonText: {
    color: SRYellowColor,
  },
  tabsContainerStyle: {
    paddingTop: 15,
    paddingBottom: 5,
    height: buttonHeight+14,
  },
  tabStyle: {
    backgroundColor: SRBrightColor,
    borderColor: SRBrightColor,
    borderRadius: dateSegmentedControlCornerRadius,
    marginLeft: 2,
    marginRight: 2,
  },
  tabTextStyle: {
    fontWeight: 'bold',
    color: SRDarkColor,
  },
  activeTabStyle: {
    backgroundColor: SRYellowColor,
    borderColor: SRYellowColor,
  },
  activeTabTextStyle: {
    color: SRDarkColor
  },
})
<commit_msg>Fixed input labels not being shown.<commit_after>// @flow
import React from 'react'
import {
  Alert,
  Keyboard,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  ScrollView,
  View
} from 'react-native'
import SegmentedControlTab from 'react-native-segmented-control-tab'
import expect from 'expect'
import moment from 'moment'
import PropTypes from 'prop-types'

import { capitalizeFirstLetter } from './utilities/String+Capitalize'
import { SRDarkColor, SRYellowColor, SRBrightColor, SRRedColor } from './utilities/SRColors'

const studyTaskString = 'Study Task'
const notesString = 'Notes'
const dateString = 'Starting Date'

const SRPlaceholderTextColor = 'rgba(251, 251, 253, 0.5)'

const inactiveColor = SRBrightColor
const buttonHeight = 46
const buttonCornerRadius = buttonHeight/2
const cancelButtonTint = SRDarkColor
const tintColor = SRRedColor

const dateSegmentedControlCornerRadius = 4

export default class SRStudyTaskEditor extends React.Component {

  static navigationOptions = (props) => {
    const { readonly } = props

    return {
      headerTintColor: SRDarkColor,
      headerStyle: {
        backgroundColor: SRBrightColor
      },
      title: readonly ? 'Details' : 'Add a task',
    }
  }

  state: {
    editMode: bool,
    hasChanges: bool,

    taskName: string,
    notes: string,
    date: string,

    studyTaskLabelString: string,
    notesLabelString: string,
    pickedDate: string,
    selectedDateIndex: number,
    selectedIntensityIndex: number,
  }

  _initialState = (props: Object) => {
    const { item } = props

    return {
      editMode: false,
      hasChanges: false,

      taskName: item != null && item.taskName != null ? item.taskName : '',
      notes: item != null && item.notes != null ? item.notes : '',
      date: new Date().toString(),

      studyTaskLabelString: item != null && item.taskName != null ? studyTaskString : ' ',
      notesLabelString: item != null && item.notes != null ? notesString : ' ',
      pickedDate: 'Other', // TODO: implement
      selectedDateIndex: 0,
      selectedIntensityIndex: 0,
    }
  }

  constructor(props: Object) {
    super(props)
    this.state = this._initialState(props)
  }

  componentWillMount() {
    this.updateUIStates(this.props)
  }

  componentWillReceiveProps(newProps: Object) {
    this.updateUIStates(newProps)
  }

  render() {
    const { readonly } = this.props
    const {
      editMode,
      taskName,
      notes,
      studyTaskLabelString
    } = this.state

    const actionButtonTitle = (readonly && editMode == false) ? 'Edit' : 'Save'
    const destructiveButtonTitle = (readonly && editMode == false) ? 'Delete' : 'Cancel'

    const disableActionButton = taskName == null || taskName == ''
    const editingOrAddingNewTask = editMode || !readonly
    const viewingOnly = readonly && !editMode
    const notesExistOrEditingOrAddingTask = !readonly || editMode || (notes != null && notes != '')
    const NOT_IMPLEMENTED = false

    return (
      <ScrollView
        style={styles.scrollView}
        keyboardDismissMode={'on-drag'}
        keyboardShouldPersistTaps={'handled'}
        >
        <View style={styles.edgePadding}>

          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{studyTaskLabelString}</Text>
            <TextInput
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={studyTaskString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={(event) => {
                this.refs.notesTextInput.focus()
              }}
              onChangeText={(taskName) => this.studyTextFieldOnChangeText(taskName)}
              value={taskName}
              editable={editingOrAddingNewTask}
              multiline={viewingOnly}
              autoFocus={!readonly}
              returnKeyType={'next'}
            />
            {this._renderSeparator(editingOrAddingNewTask)}
          </View>

          {this._renderNotes(notesExistOrEditingOrAddingTask)}
          {this._renderDateSelection(!readonly)}
          {this._renderRatingHistory(NOT_IMPLEMENTED)}

          <View name='dataSeparator' style={[styles.sectionSeparator, styles.lastSectionSeparator]}/>

          <View style={[styles.sections, styles.bottomButtonsView]}>
            <TouchableOpacity
              style={this.disabledButtonStyle(disableActionButton)}
              disabled={disableActionButton}
              onPress={this.actionButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.actionButtonText]}>{actionButtonTitle}</Text>
            </TouchableOpacity>

            <TouchableOpacity
              style={[styles.dataInputItemPadding, styles.bottomButtons, styles.cancelButton]}
              onPress={this.destructiveButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.destructiveButtonText]}>{destructiveButtonTitle}</Text>
            </TouchableOpacity>
          </View>

        </View>
      </ScrollView>
    )
  }

  // Data input

  studyTextFieldOnChangeText = (taskName: string) => {
    const taskNameExists = taskName == null || taskName == ''
    this.hideStudyTaskLabel(taskNameExists)
    this.setState({
      taskName,
      hasChanges: true
    })
  }

  notesTextFieldOnChangeText = (notes: string) => {
    const notesExist = notes == null || notes == ''
    this.hideNotesLabel(notesExist)
    this.setState({
      notes,
      hasChanges: true
    })
  }

  handleDateSelection = (index: number) => {
    var selectedDate = new Date()
    switch(index) {
      case 0:
        selectedDate = new Date()
        break
      case 1:
        selectedDate = new Date(moment().subtract(1, 'days'))
        break
      case 2:
        this.openDatePicker()
        break
      default:
      throw 'handleDateSelection()'
    }

    this.setState({
      date: selectedDate.toString(),
      selectedDateIndex: index,
      hasChanges: true
    })
  }

  handleIntensitySelection = (index: number) => {
    this.setState({
      selectedIntensityIndex: index,
      hasChanges: true
    })
  }

  // Actions

  actionButtonAction = () => {
    const { readonly, item } = this.props
    const { editMode } = this.state
    const wantsEdit = readonly && !editMode

    if(wantsEdit) {
      this.setState({editMode: true})
    } else { // Save data input
      const { readonly, saveAction } = this.props
      const { taskName, notes, date } = this.state

      expect(taskName).toExist('No taskName')
      expect(taskName).toNotEqual('','taskName is empty string')

      const newItemChanges = {
        taskName: taskName,
        notes: notes,
        date: date,
      }

      saveAction(newItemChanges, item)
      if(readonly) {
        this.setState({editMode: false})
      }
    }

  }

  destructiveButtonAction = () => {
    const { readonly, deleteAction, cancelAction, item } = this.props
    const { editMode, hasChanges } = this.state
    const deleteWhenReadonly = readonly && !editMode
    const cancelEditing = readonly && editMode
    const dismissAddingNewTask = !readonly

    if (deleteWhenReadonly) {
      deleteAction(item)
    } else if(cancelEditing) {
      if (hasChanges) {
        Alert.alert(
          'Discard Changes',
          'Are you sure you want to discard your changes?',
          [
            {text: 'Keep Editing', onPress: () => {}, style: 'cancel'},
            {text: 'Discard Changes', onPress: () => {
              this.resetFields()
              this.setState({editMode: false})
            }},
          ],
          { cancelable: true }
        )
      } else {
        this.resetFields()
        this.setState({editMode: false})
      }
    } else if (dismissAddingNewTask) {
      cancelAction()
    } else {
      expect(0).toBe(1, 'destructiveButtonAction() else')
    }
  }

  resetFields = () => {
    this.setState({
      ...this.state,
      ...this._initialState(this.props),
    })
  }

  // UI changes

  updateUIStates = (props: Object) => {
    const { notes, taskName } = props.item
    const taskNameTextFieldIsEmpty = taskName == null || taskName == ''
    this.hideStudyTaskLabel(taskNameTextFieldIsEmpty)

    const notesTextFieldIsEmpty = notes == null || notes == ''
    this.hideNotesLabel(notesTextFieldIsEmpty)
  }

  hideStudyTaskLabel = (flag: bool = true) => {
    this.setState({
      studyTaskLabelString: flag ? ' ' : studyTaskString.toUpperCase()
    })
  }

  hideNotesLabel = (flag: bool = true) => {
    this.setState({
      notesLabelString: flag ? ' ' : notesString.toUpperCase()
    })
  }

  openDatePicker = () => {
    // TODO: missing implementation
    // pickedDate = '' // set this to a nicely formatted date
  }

  _renderSeparator = (flag) => {
    if(flag) {
      return <View name='separator' style={styles.sectionSeparator}/>
    } else {
      return null
    }
  }

  _renderNotes = (flag) => {
      if(flag) {
        const { readonly } = this.props
        const { notes, notesLabelString, editMode } = this.state
        const editingOrAddingNewTask = editMode || !readonly
        const viewingOnly = readonly && !editMode
        return(
          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{notesLabelString}</Text>
            <TextInput
              ref='notesTextInput'
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={notesString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={Keyboard.dismiss}
              onChangeText={(notes) => this.notesTextFieldOnChangeText(notes)}
              value={notes}
              editable={editingOrAddingNewTask}
              multiline={viewingOnly}
              returnKeyType={'done'}
            />
            {this._renderSeparator(!readonly)}
          </View>
        )
      } else {
        return null
      }
  }

  _renderDateSelection = (flag) => {
    if(flag) {
      const { pickedDate } = this.state
      const formattedPickedDate = pickedDate // TODO:
      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>{dateString.toUpperCase()}</Text>
          <SegmentedControlTab
            borderRadius={dateSegmentedControlCornerRadius}
            tabsContainerStyle={styles.tabsContainerStyle}
            tabStyle={styles.tabStyle}
            tabTextStyle={styles.tabTextStyle}
            activeTabStyle={styles.activeTabStyle}
            activeTabTextStyle={styles.activeTabTextStyle}
            values={['Today', 'Yesterday', formattedPickedDate]}
            selectedIndex={this.state.selectedDateIndex}
            onTabPress={this.handleDateSelection}
          />
        </View>
      )
    } else {
      return null
    }
  }

  _renderRatingHistory = (flag) => {
    if(flag) {
      // TODO: missing implementation
      // if made changes then set hasChanges: true
      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>Rating History</Text>

        </View>
      )
    } else {
      return null
    }
  }

  disabledButtonStyle = (flag: bool) => {
    const defaultStyle = [styles.dataInputItemPadding, styles.bottomButtons, styles.actionButton]
    if(flag) {
      return [...defaultStyle, styles.actionButtonDisabled]
    } else {
      return defaultStyle
    }
  }

}

SRStudyTaskEditor.propTypes = {
  item: PropTypes.shape({
    title: PropTypes.string,
    notes: PropTypes.string,
  }),

  saveAction: PropTypes.func.isRequired,
  deleteAction: PropTypes.func,
  cancelAction: PropTypes.func,

  readonly: PropTypes.bool.isRequired,
}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
    backgroundColor: SRDarkColor,
  },
  edgePadding: {
    padding: 15,
    flex:1,
  },
  dataInputItemPadding: {
    padding: 4,
  },
  textInput: {
    fontSize: 48,
    color: SRBrightColor,
  },
  sectionLabel: {
    fontSize: 20,
    color: SRRedColor,
    fontWeight: 'bold'
  },
  sectionSeparator: {
    backgroundColor: SRBrightColor,
    height: 1,
  },
  lastSectionSeparator: {
    marginTop: 8,
  },
  sections: {
    padding: 8,
  },
  bottomButtonsView: {
    flexDirection: 'column',
    paddingTop: 20,
  },
  bottomButtons: {
    alignItems: 'center',
    height: buttonHeight,
    justifyContent: 'center',
  },
  actionButton: {
    backgroundColor: SRYellowColor,
    borderRadius: buttonCornerRadius,
    flex: 1,
  },
  actionButtonDisabled: {
    backgroundColor: 'rgba(255, 252, 49, 0.5)'
  },
  cancelButton: {
    borderColor: SRYellowColor,
    borderWidth: 1,
    borderRadius: buttonCornerRadius,
    flex: 1,
    marginTop: 10,
  },
  bottomButtonsText: {
    color: SRDarkColor,
    fontSize: 16,
    fontWeight: 'bold',
  },
  actionButtonText: {
    paddingTop: 1,
  },
  destructiveButtonText: {
    color: SRYellowColor,
  },
  tabsContainerStyle: {
    paddingTop: 15,
    paddingBottom: 5,
    height: buttonHeight+14,
  },
  tabStyle: {
    backgroundColor: SRBrightColor,
    borderColor: SRBrightColor,
    borderRadius: dateSegmentedControlCornerRadius,
    marginLeft: 2,
    marginRight: 2,
  },
  tabTextStyle: {
    fontWeight: 'bold',
    color: SRDarkColor,
  },
  activeTabStyle: {
    backgroundColor: SRYellowColor,
    borderColor: SRYellowColor,
  },
  activeTabTextStyle: {
    color: SRDarkColor
  },
})
<|endoftext|>


<commit_before>import jetpack from 'fs-jetpack'
import path from 'path'
import _ from 'lodash'

const DEFAULT_PANEL_CONF = getConfig(__dirname, '..', 'config', 'defaultPanelConfig.json')
const CONFIG = getConfig(__dirname, '..', 'config', 'config.json')

/**
 * getConfigPaths - Evaluates the panel config locations defined in the config.json
 * and returns valid OS dependent path
 *
 * @return {array}  An array of paths to the panel configurations
 */
function getConfigPaths() {
  let userHome = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']

  return CONFIG.panelConfigDirectories.map((_dirParts) => {
    _dirParts = _dirParts.map((__dirPart) => __dirPart.replace(/\%USERHOME\%/i, userHome))
    return path.join(..._dirParts)
  }).reduce((_configPaths, _configPath) => {

    if(jetpack.exists(_configPath) == 'dir') {
      _configPaths.push(_configPath)
    }

    return _configPaths

  }, [])
}

/**
 * validatePath - Joins the multiple path parts and validates if they match the
 * specified type (i.e. dir, file)
 *
 * @param  {string} _type         The type to check the path against (dir, file)
 * @param  {string} ..._pathParts Path parts to be joined an evaluated
 * @return {string}               Returns the joined version of the given path parts if they match the given type else false
 */
function validatePath(_type, ..._pathParts) {
  let _path = path.join(..._pathParts)
  return jetpack.exists(_path) == _type ? _path : false
}

/**
 * getItems - Extracts "items" from the given path parts and stores them in an
 * handy object. An item can either be a panel or one of the defined custom
 * elements. Therefore they are de facto HTML files which should be loaded.
 *
 * Returns only valid items
 *
 * @param  {string} ..._pathParts The path parts pointing to a directory of items
 * @return {array}                An array of "item" objects which contain the item name and resolved path
 */
function getItems(..._pathParts) {

  let _items = []
  let _itemsPath = validatePath('dir', ..._pathParts)

  if(!_itemsPath) return _items

  jetpack.list(_itemsPath).reduce((__items, __cItemName) => {
    let __itemPath = validatePath('file', _itemsPath, __cItemName, 'index.html')
    let __itemNodeModules = validatePath('dir', _itemsPath, __cItemName, 'node_modules')

    if(__itemPath) {
      __items.push({
        name: __cItemName,
        path: __itemPath,
        modulesPath: __itemNodeModules,
      })
    }

    return __items
  }, _items)

  return _items
}

/**
 * getConfig - Reads the config file of the given path parts if the path is valid
 *
 * @param  {string} ..._pathParts The path parts pointing to the json config file
 * @return {object}               Either empty if the path does not point to a valid json file or the config from the json file
 */
function getConfig(..._pathParts) {

  let _config = {}
  let _configPath = validatePath('file', ..._pathParts)

  if(!_configPath) return _config

  return jetpack.read(_configPath, 'json')
}

/**
 * getPanelsFromPath - Returns an array of panel objects from a given path.
 * All valid panels in the provided path will be returned. Each panel is
 * described in an object and contains all source files (including local and global
 * custom elements) and the panel specific configuration which consists of the
 * local panel config file, the global panels config file and the default panel
 * config.
 *
 * @param  {string} _panelsPath Path to panel configuration location
 * @return {array}              Array of panel objects each containing all relevant information in order to build the panel
 */
function getPanelsFromPath(_panelsPath) {
  let _globalConfig = getConfig(_panelsPath, 'panels', `${CONFIG.panelConfigFileName}.json`)
  let _globalElements = getItems(_panelsPath, 'elements')
  let _panels = getItems(_panelsPath, 'panels')

  _panels.map((__panel) => {
    let __panelConfig = getConfig(__panel.path, '..', `${CONFIG.panelConfigFileName}.json`)
    let __panelElements = getItems(__panel.path, '..', 'elements')

    __panel.elements = _.uniq(__panelElements.concat(_globalElements), 'name')
    __panel.config = _.merge({}, DEFAULT_PANEL_CONF, _globalConfig, __panelConfig)

    return __panel
  })

  return _panels
}

/**
 * export - Default export for all panels of all configuration locations
 *
 * @return {array}  array of panel objects each containing all relevant information in order to build the panel
 */
export default function() {
  let _panels = []

  getConfigPaths().forEach((__configPath) => {
    _panels = _panels.concat(getPanelsFromPath(__configPath))
  })

  return _panels
}
<commit_msg>single params for arrow functions without ()<commit_after>import jetpack from 'fs-jetpack'
import path from 'path'
import _ from 'lodash'

const DEFAULT_PANEL_CONF = getConfig(__dirname, '..', 'config', 'defaultPanelConfig.json')
const CONFIG = getConfig(__dirname, '..', 'config', 'config.json')

/**
 * getConfigPaths - Evaluates the panel config locations defined in the config.json
 * and returns valid OS dependent path
 *
 * @return {array}  An array of paths to the panel configurations
 */
function getConfigPaths() {
  let userHome = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']

  return CONFIG.panelConfigDirectories.map(_dirParts => {
    _dirParts = _dirParts.map(__dirPart => __dirPart.replace(/\%USERHOME\%/i, userHome))
    return path.join(..._dirParts)
  }).reduce((_configPaths, _configPath) => {

    if(jetpack.exists(_configPath) == 'dir') {
      _configPaths.push(_configPath)
    }

    return _configPaths

  }, [])
}

/**
 * validatePath - Joins the multiple path parts and validates if they match the
 * specified type (i.e. dir, file)
 *
 * @param  {string} _type         The type to check the path against (dir, file)
 * @param  {string} ..._pathParts Path parts to be joined an evaluated
 * @return {string}               Returns the joined version of the given path parts if they match the given type else false
 */
function validatePath(_type, ..._pathParts) {
  let _path = path.join(..._pathParts)
  return jetpack.exists(_path) == _type ? _path : false
}

/**
 * getItems - Extracts "items" from the given path parts and stores them in an
 * handy object. An item can either be a panel or one of the defined custom
 * elements. Therefore they are de facto HTML files which should be loaded.
 *
 * Returns only valid items
 *
 * @param  {string} ..._pathParts The path parts pointing to a directory of items
 * @return {array}                An array of "item" objects which contain the item name and resolved path
 */
function getItems(..._pathParts) {

  let _items = []
  let _itemsPath = validatePath('dir', ..._pathParts)

  if(!_itemsPath) return _items

  jetpack.list(_itemsPath).reduce((__items, __cItemName) => {
    let __itemPath = validatePath('file', _itemsPath, __cItemName, 'index.html')
    let __itemNodeModules = validatePath('dir', _itemsPath, __cItemName, 'node_modules')

    if(__itemPath) {
      __items.push({
        name: __cItemName,
        path: __itemPath,
        modulesPath: __itemNodeModules,
      })
    }

    return __items
  }, _items)

  return _items
}

/**
 * getConfig - Reads the config file of the given path parts if the path is valid
 *
 * @param  {string} ..._pathParts The path parts pointing to the json config file
 * @return {object}               Either empty if the path does not point to a valid json file or the config from the json file
 */
function getConfig(..._pathParts) {

  let _config = {}
  let _configPath = validatePath('file', ..._pathParts)

  if(!_configPath) return _config

  return jetpack.read(_configPath, 'json')
}

/**
 * getPanelsFromPath - Returns an array of panel objects from a given path.
 * All valid panels in the provided path will be returned. Each panel is
 * described in an object and contains all source files (including local and global
 * custom elements) and the panel specific configuration which consists of the
 * local panel config file, the global panels config file and the default panel
 * config.
 *
 * @param  {string} _panelsPath Path to panel configuration location
 * @return {array}              Array of panel objects each containing all relevant information in order to build the panel
 */
function getPanelsFromPath(_panelsPath) {
  let _globalConfig = getConfig(_panelsPath, 'panels', `${CONFIG.panelConfigFileName}.json`)
  let _globalElements = getItems(_panelsPath, 'elements')
  let _panels = getItems(_panelsPath, 'panels')

  _panels.map(__panel => {
    let __panelConfig = getConfig(__panel.path, '..', `${CONFIG.panelConfigFileName}.json`)
    let __panelElements = getItems(__panel.path, '..', 'elements')

    __panel.elements = _.uniq(__panelElements.concat(_globalElements), 'name')
    __panel.config = _.merge({}, DEFAULT_PANEL_CONF, _globalConfig, __panelConfig)

    return __panel
  })

  return _panels
}

/**
 * export - Default export for all panels of all configuration locations
 *
 * @return {array}  array of panel objects each containing all relevant information in order to build the panel
 */
export default function() {
  let _panels = []

  getConfigPaths().forEach(__configPath => {
    _panels = _panels.concat(getPanelsFromPath(__configPath))
  })

  return _panels
}
<|endoftext|>


<commit_before>var express = require('express')
var debug = require('debug')
var validate = require('../validate')
var middlewares = require('../middlewares')
var api = require('../db-api')

var log = debug('democracyos:api:comments')

var app = module.exports = express()

app.get('/comments', validate({
  query: Object.assign({}, validate.schemas.pagination, {
    topicId: {
      type: 'string',
      required: true,
      format: 'mongo-object-id',
      description: 'id of the Topic to fetch comments from'
    },
    sort: {
      enum: ['score', '-score', 'createdAt', '-createdAt'],
      default: '-score'
    }
  })
}),
middlewares.topics.findByTopicId,
middlewares.forums.findFromTopic,
middlewares.forums.privileges('canView'),
function getComments (req, res, next) {
  log('GET /api/comments')

  Promise.all([
    api.comments.list(req.query),
    api.comments.listCount(req.query)
  ]).catch((err) => {
    log('GET /api/comments ERROR', err)
    next(new Error('Server error.'))
  }).then((results) => {
    res.json({
      status: 200,
      count: results[1],
      page: req.query.page,
      limit: req.query.limit,
      comments: results[0]
    })
  })
})
<commit_msg>add results scope on api response<commit_after>var express = require('express')
var debug = require('debug')
var validate = require('../validate')
var middlewares = require('../middlewares')
var api = require('../db-api')

var log = debug('democracyos:api:comments')

var app = module.exports = express()

app.get('/comments', validate({
  query: Object.assign({}, validate.schemas.pagination, {
    topicId: {
      type: 'string',
      required: true,
      format: 'mongo-object-id',
      description: 'id of the Topic to fetch comments from'
    },
    sort: {
      enum: ['score', '-score', 'createdAt', '-createdAt'],
      default: '-score'
    }
  })
}),
middlewares.topics.findByTopicId,
middlewares.forums.findFromTopic,
middlewares.forums.privileges('canView'),
function getComments (req, res, next) {
  log('GET /api/comments')

  Promise.all([
    api.comments.list(req.query),
    api.comments.listCount(req.query)
  ]).catch((err) => {
    log('GET /api/comments ERROR', err)
    next(new Error('Server error.'))
  }).then((results) => {
    res.json({
      status: 200,
      count: results[1],
      page: req.query.page,
      limit: req.query.limit,
      results: {
        comments: results[0]
      }
    })
  })
})
<|endoftext|>


<commit_before>var st7735 = require('jsupm_st7735');
var lcd = new st7735.ST7735(7, 1, 9, 8);

lcd.fillScreen(st7735.ST7735_RED);
lcd.refresh();
lcd.fillScreen(st7735.ST7735_CYAN);
lcd.refresh();

lcd.fillScreen(st7735.ST7735_BLACK);
lcd.refresh();
//128 x 160 display
//lcd.Circle(64,80,50,st7735.ST7735_RED);
lcd.refresh();
function fillrectangle(x0, y0, x1, y1, color){
 var width = x1 - x0 +1;
 var height = y1 - y0 +1;

while (y0<= y1){
    lcd.drawLine(x0,y0,x1,y0,color);
    y0+=1;

}
    lcd.refresh();
    lcd.sdCSOn();

}

//fillrectangle(0,0,100,100,st7735.ST7735_RED);
var width = 128;
var height = 160;

function FillCircle (xPos, yPos, radius, color)
// draws filled circle at x,y with given radius & color
{
 var r2 = radius * radius;
 for (var x=0; x<=radius; x++)
 {
 var y = Math.sqrt(r2-x*x);
 var y0 = yPos-y;
 var y1 = yPos+y;
 lcd.drawLine(xPos+x,y0,xPos+x,y1,color);
 lcd.drawLine(xPos - x,y0,xPos-x, y1,color);
 }
     lcd.refresh();
   //s lcd.sdCSOn();
}
//lcd.drawCircle(100, 110, 10, st7735.ST7735_BLUE);
//lcd.drawCircle((width/2)-1,(height/2)-1,60,st7735.ST7735_RED);
lcd.refresh();
FillCircle((width/2)-1,(height/2)-1,60,st7735.ST7735_GREEN);
FillCircle((width/2)-1,(height/2)-1,52,st7735.ST7735_BLACK);
lcd.refresh();

for (var i = 0; i < 360; i += 30) {
    var sx = Math.cos((i - 90) * 0.0174532925);
    var sy = Math.sin((i - 90) * 0.0174532925);
    var x0 = sx * 56 + (width/2)-1;
    var yy0 = sy * 56 + (height/2)-1;
    var x1 = sx * 42 + (width/2)-1;
    var yy1 = sy * 42 + (height/2)-2;

    tft.drawLine(x0, yy0, x1, yy1, TFT_YELLOW);//garis penanda angka jam
  }
lcd.refresh();
/*
lcd.refresh();

lcd.drawPixel(20, 20, st7735.ST7735_GREEN);
lcd.refresh();

lcd.drawTriangle(50, 50, 80, 80, 60, 90, st7735.ST7735_GREEN);
lcd.refresh();

lcd.drawCircle(100, 110, 10, st7735.ST7735_BLUE);
lcd.refresh();

lcd.setTextWrap(0x0);

lcd.setCursor(0, 30);
lcd.setTextColor(st7735.ST7735_RED, st7735.ST7735_RED);
lcd.setTextSize(1);
lcd.print('Hello World!');

lcd.setCursor(10, 50);
lcd.setTextColor(st7735.ST7735_RED, st7735.ST7735_RED);
lcd.setTextSize(2);
lcd.print('BIG');

lcd.refresh();*/
<commit_msg>fixsynta<commit_after>var st7735 = require('jsupm_st7735');
var lcd = new st7735.ST7735(7, 1, 9, 8);

lcd.fillScreen(st7735.ST7735_RED);
lcd.refresh();
lcd.fillScreen(st7735.ST7735_CYAN);
lcd.refresh();

lcd.fillScreen(st7735.ST7735_BLACK);
lcd.refresh();
//128 x 160 display
//lcd.Circle(64,80,50,st7735.ST7735_RED);
lcd.refresh();
function fillrectangle(x0, y0, x1, y1, color){
 var width = x1 - x0 +1;
 var height = y1 - y0 +1;

while (y0<= y1){
    lcd.drawLine(x0,y0,x1,y0,color);
    y0+=1;

}
    lcd.refresh();
    lcd.sdCSOn();

}

//fillrectangle(0,0,100,100,st7735.ST7735_RED);
var width = 128;
var height = 160;

function FillCircle (xPos, yPos, radius, color)
// draws filled circle at x,y with given radius & color
{
 var r2 = radius * radius;
 for (var x=0; x<=radius; x++)
 {
 var y = Math.sqrt(r2-x*x);
 var y0 = yPos-y;
 var y1 = yPos+y;
 lcd.drawLine(xPos+x,y0,xPos+x,y1,color);
 lcd.drawLine(xPos - x,y0,xPos-x, y1,color);
 }
     lcd.refresh();
   //s lcd.sdCSOn();
}
//lcd.drawCircle(100, 110, 10, st7735.ST7735_BLUE);
//lcd.drawCircle((width/2)-1,(height/2)-1,60,st7735.ST7735_RED);
lcd.refresh();
FillCircle((width/2)-1,(height/2)-1,60,st7735.ST7735_GREEN);
FillCircle((width/2)-1,(height/2)-1,52,st7735.ST7735_BLACK);
lcd.refresh();

for (var i = 0; i < 360; i += 30) {
    var sx = Math.cos((i - 90) * 0.0174532925);
    var sy = Math.sin((i - 90) * 0.0174532925);
    var x0 = sx * 56 + (width/2)-1;
    var yy0 = sy * 56 + (height/2)-1;
    var x1 = sx * 42 + (width/2)-1;
    var yy1 = sy * 42 + (height/2)-2;

    lcd.drawLine(x0, yy0, x1, yy1, TFT_YELLOW);//garis penanda angka jam
  }
lcd.refresh();
/*
lcd.refresh();

lcd.drawPixel(20, 20, st7735.ST7735_GREEN);
lcd.refresh();

lcd.drawTriangle(50, 50, 80, 80, 60, 90, st7735.ST7735_GREEN);
lcd.refresh();

lcd.drawCircle(100, 110, 10, st7735.ST7735_BLUE);
lcd.refresh();

lcd.setTextWrap(0x0);

lcd.setCursor(0, 30);
lcd.setTextColor(st7735.ST7735_RED, st7735.ST7735_RED);
lcd.setTextSize(1);
lcd.print('Hello World!');

lcd.setCursor(10, 50);
lcd.setTextColor(st7735.ST7735_RED, st7735.ST7735_RED);
lcd.setTextSize(2);
lcd.print('BIG');

lcd.refresh();*/
<|endoftext|>


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

'use strict'

const program = require('commander')
const pkgJson = require('../package.json')
const Bumper = require('../lib/bumper')
const Cli = require('../lib/cli')
const cli = new Cli()

program
  .version(pkgJson.version)
  .option('-s, --skip-comments', 'disable PR comments even if enabled via .pr-bumper.json')
  .arguments('<cmd>')
  .action((cmd, program) => {
    cli
      .run(cmd, program.skipComments)
      .catch((error) => {
        const msg = (error.message) ? error.message : error
        console.log(`${pkgJson.name}: ERROR: ${msg}`)
        if (error instanceof Bumper.Cancel) {
          process.exit(0)
        }
        process.exit(1)
      })
  })
  .on('--help', () => {
    console.log('  Options:')
    console.log('')
    console.log(
      '    --skip-comments - disable PR comments even if enabled via .pr-bumper.json\n' +
      '                      Useful particularly when running check-coverage manually'
    )
    console.log('')
    console.log('  Commands:')
    console.log('')
    console.log('    check - verify an open PR has a version-bump comment')
    console.log('    check-coverage - compare current code coverage against baseline from package.json')
    console.log('    bump - actually bump the version based on the merged PR')
    console.log('')
  })
  .parse(process.argv)
<commit_msg>Log the result of the operation<commit_after>#!/usr/bin/env node

'use strict'

const program = require('commander')
const pkgJson = require('../package.json')
const Bumper = require('../lib/bumper')
const Cli = require('../lib/cli')
const cli = new Cli()

program
  .version(pkgJson.version)
  .option('-s, --skip-comments', 'disable PR comments even if enabled via .pr-bumper.json')
  .arguments('<cmd>')
  .action((cmd, program) => {
    cli
      .run(cmd, program.skipComments)
      .then(result => {
        console.log(result)
      })
      .catch((error) => {
        const msg = (error.message) ? error.message : error
        console.log(`${pkgJson.name}: ERROR: ${msg}`)
        if (error instanceof Bumper.Cancel) {
          process.exit(0)
        }
        process.exit(1)
      })
  })
  .on('--help', () => {
    console.log('  Options:')
    console.log('')
    console.log(
      '    --skip-comments - disable PR comments even if enabled via .pr-bumper.json\n' +
      '                      Useful particularly when running check-coverage manually'
    )
    console.log('')
    console.log('  Commands:')
    console.log('')
    console.log('    check - verify an open PR has a version-bump comment')
    console.log('    check-coverage - compare current code coverage against baseline from package.json')
    console.log('    bump - actually bump the version based on the merged PR')
    console.log('')
  })
  .parse(process.argv)
<|endoftext|>


<commit_before>/**
 * TreeWalker.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * TreeWalker class enables you to walk the DOM in a linear manner.
 *
 * @class tinymce.dom.TreeWalker
 * @example
 * var walker = new tinymce.dom.TreeWalker(startNode);
 *
 * do {
 *     console.log(walker.current());
 * } while (walker.next());
 */
define("tinymce/dom/TreeWalker", [], function() {
	/**
	 * Constructs a new TreeWalker instance.
	 *
	 * @constructor
	 * @method TreeWalker
	 * @param {Node} startNode Node to start walking from.
	 * @param {node} rootNode Optional root node to never walk out of.
	 */
	return function(startNode, rootNode) {
		var node = startNode;

		function findSibling(node, startName, siblingName, shallow) {
			var sibling, parent;

			if (node) {
				// Walk into nodes if it has a start
				if (!shallow && node[startName]) {
					return node[startName];
				}

				// Return the sibling if it has one
				if (node != rootNode) {
					sibling = node[siblingName];
					if (sibling) {
						return sibling;
					}

					// Walk up the parents to look for siblings
					for (parent = node.parentNode; parent && parent != rootNode; parent = parent.parentNode) {
						sibling = parent[siblingName];
						if (sibling) {
							return sibling;
						}
					}
				}
			}
		}

		function findPreviousNode(node, startName, siblingName, shallow) {
			var sibling, parent, child;

			if (node) {
				sibling = node[siblingName];
				if (sibling == rootNode) {
					return;
				}

				if (sibling) {
					if (!shallow) {
						// Walk up the parents to look for siblings
						for (child = sibling[startName]; child; child = child[startName]) {
							if (!child[startName]) {
								return child;
							}
						}
					}

					return sibling;
				}

				parent = node.parentNode;
				if (parent != rootNode) {
					return parent;
				}
			}
		}

		/**
		 * Returns the current node.
		 *
		 * @method current
		 * @return {Node} Current node where the walker is.
		 */
		this.current = function() {
			return node;
		};

		/**
		 * Walks to the next node in tree.
		 *
		 * @method next
		 * @return {Node} Current node where the walker is after moving to the next node.
		 */
		this.next = function(shallow) {
			node = findSibling(node, 'firstChild', 'nextSibling', shallow);
			return node;
		};

		/**
		 * Walks to the previous node in tree.
		 *
		 * @method prev
		 * @return {Node} Current node where the walker is after moving to the previous node.
		 */
		this.prev = function(shallow) {
			node = findSibling(node, 'lastChild', 'previousSibling', shallow);
			return node;
		};

		this.prev2 = function(shallow) {
			node = findPreviousNode(node, 'lastChild', 'previousSibling', shallow);
			return node;
		};
	};
});
<commit_msg>Fixed rootNode checking for new prev node<commit_after>/**
 * TreeWalker.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * TreeWalker class enables you to walk the DOM in a linear manner.
 *
 * @class tinymce.dom.TreeWalker
 * @example
 * var walker = new tinymce.dom.TreeWalker(startNode);
 *
 * do {
 *     console.log(walker.current());
 * } while (walker.next());
 */
define("tinymce/dom/TreeWalker", [], function() {
	/**
	 * Constructs a new TreeWalker instance.
	 *
	 * @constructor
	 * @method TreeWalker
	 * @param {Node} startNode Node to start walking from.
	 * @param {node} rootNode Optional root node to never walk out of.
	 */
	return function(startNode, rootNode) {
		var node = startNode;

		function findSibling(node, startName, siblingName, shallow) {
			var sibling, parent;

			if (node) {
				// Walk into nodes if it has a start
				if (!shallow && node[startName]) {
					return node[startName];
				}

				// Return the sibling if it has one
				if (node != rootNode) {
					sibling = node[siblingName];
					if (sibling) {
						return sibling;
					}

					// Walk up the parents to look for siblings
					for (parent = node.parentNode; parent && parent != rootNode; parent = parent.parentNode) {
						sibling = parent[siblingName];
						if (sibling) {
							return sibling;
						}
					}
				}
			}
		}

		function findPreviousNode(node, startName, siblingName, shallow) {
			var sibling, parent, child;

			if (node) {
				sibling = node[siblingName];
				if (rootNode && sibling === rootNode) {
					return;
				}

				if (sibling) {
					if (!shallow) {
						// Walk up the parents to look for siblings
						for (child = sibling[startName]; child; child = child[startName]) {
							if (!child[startName]) {
								return child;
							}
						}
					}

					return sibling;
				}

				parent = node.parentNode;
				if (parent && parent !== rootNode) {
					return parent;
				}
			}
		}

		/**
		 * Returns the current node.
		 *
		 * @method current
		 * @return {Node} Current node where the walker is.
		 */
		this.current = function() {
			return node;
		};

		/**
		 * Walks to the next node in tree.
		 *
		 * @method next
		 * @return {Node} Current node where the walker is after moving to the next node.
		 */
		this.next = function(shallow) {
			node = findSibling(node, 'firstChild', 'nextSibling', shallow);
			return node;
		};

		/**
		 * Walks to the previous node in tree.
		 *
		 * @method prev
		 * @return {Node} Current node where the walker is after moving to the previous node.
		 */
		this.prev = function(shallow) {
			node = findSibling(node, 'lastChild', 'previousSibling', shallow);
			return node;
		};

		this.prev2 = function(shallow) {
			node = findPreviousNode(node, 'lastChild', 'previousSibling', shallow);
			return node;
		};
	};
});
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import {
  Alert,
  Keyboard,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  ScrollView,
  View
} from 'react-native'
import SegmentedControlTab from 'react-native-segmented-control-tab'
import expect, { createSpy, spyOn, isSpy } from 'expect'
import moment from 'moment'
import { actionCreators, SRStudyTask, SRStudyTaskIntensity } from './dataModel/SRSimpleDataModel'
import { SRSpacedRepetition } from './SRSpacedRepetition'
import { uuid } from './utilities/UUID'
import { capitalizeFirstLetter } from './utilities/String+Capitalize'
import {SRDarkColor, SRYellowColor, SRBrightColor, SRRedColor} from './utilities/SRColors'

const studyTaskString = 'STUDY TASK'
const notesString = 'NOTES'
const dateString = 'STARTING DATE'

const SRPlaceholderTextColor = 'rgba(251, 251, 253, 0.5)'

const inactiveColor = SRBrightColor
const buttonHeight = 46
const buttonCornerRadius = buttonHeight/2
const cancelButtonTint = SRDarkColor
const tintColor = SRRedColor

const dateSegmentedControlCornerRadius = 4

export default class SRStudyTaskEditor extends React.Component {

  static navigationOptions = ({navigation}) => {
    const { params = {} } = navigation.state

    return {
      headerTintColor: SRDarkColor,
      headerStyle: {
        backgroundColor: SRBrightColor
      },
      title: (params.readonly) ? 'Details' : 'Add a task',
    }
  }

  constructor(props) {
    super(props)

    const { params } = props.navigation.state

    this.state = {
      id:             params != null ? params.item.id            : uuid(),
      taskName:       params != null ? params.item.taskName      : null,
      notes:          params != null ? params.item.notes         : null,
      dates:          params != null ? params.item.dates         : [new Date()],
      ratingHistory:  params != null ? params.item.ratingHistory : [],
      srs:            params != null ? params.item.srs           : new SRSpacedRepetition(),
      intensity:      params != null ? params.item.intensity     : SRStudyTaskIntensity.NORMAL,

      readonly: params != null ? params.readonly : false,
      editMode: false,

      studyTaskLabelString: params != null ? studyTaskString : ' ',
      notesLabelString: params != null ? notesString : ' ',
      pickedDate: 'Other',
      selectedDateIndex: 0,
      selectedIntensityIndex: 0,
    }
  }

  props: {
    saveAction: (studyTask) => any,
  }

  componentWillReceiveProps() {
    const { notes, taskName } = this.state
    this.hideStudyTaskLabel(taskName == null || taskName == '')
    this.hideNotesLabel(notes == null || notes == '')
  }

  render() {
    const { dates, intensity, notes, editMode, readonly, studyTaskLabelString, taskName } = this.state

    const actionButtonTitle = (readonly && editMode == false) ? 'Edit' : 'Save'
    const destructiveButtonTitle = (readonly && editMode == false) ? 'Delete' : 'Cancel'

    const NOT_IMPLEMENTED = false

    return (
      <ScrollView style={styles.scrollView}>
        <View style={styles.edgePadding}>

          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{studyTaskLabelString}</Text>
            <TextInput
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={studyTaskString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={Keyboard.dismiss}
              onChangeText={(taskName) => this.studyTextFieldOnChangeText(taskName)}
              value={taskName}
              editable={this.state.editMode}
              multiline={this.state.readonly && !this.state.editMode}
            />
            {this._renderSeparator(editMode)}
          </View>

          {this._renderNotes(!readonly || editMode || (notes != null && notes != ''))}
          {this._renderDateSelection(!readonly)}
          {this._renderRatingHistory(NOT_IMPLEMENTED)}

          <View name='dataSeparator' style={[styles.sectionSeparator, styles.lastSectionSeparator]}/>

          <View style={[styles.sections, styles.bottomButtonsView]}>
            <TouchableOpacity
              style={[styles.dataInputItemPadding, styles.bottomButtons, styles.actionButton]}
              onPress={this.actionButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.actionButtonText]}>{actionButtonTitle}</Text>
            </TouchableOpacity>

            <TouchableOpacity
              style={[styles.dataInputItemPadding, styles.bottomButtons, styles.cancelButton]}
              onPress={this.destructiveButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.destructiveButtonText]}>{destructiveButtonTitle}</Text>
            </TouchableOpacity>
          </View>

        </View>
      </ScrollView>
    )
  }

  studyTextFieldOnChangeText = (taskName) => {
    this.hideStudyTaskLabel(taskName == null || taskName == '')
    this.setState({taskName})
  }

  notesTextFieldOnChangeText = (notes) => {
    this.hideNotesLabel(notes == null || notes == '')
    this.setState({notes})
  }

  hideStudyTaskLabel = (flag = true) => {
    this.setState({
      studyTaskLabelString: flag ? ' ' : studyTaskString
    })
  }

  hideNotesLabel = (flag = true) => {
    this.setState({
      notesLabelString: flag ? ' ' : notesString
    })
  }

  handleDateSelection = (index) => {
    this.setState({...this.state, selectedDateIndex: index})
  }

  handleIntensitySelection = (index) => {
    this.setState({...this.state, selectedIntensityIndex: index})
  }

  openDatePicker = () => {

  }

  changeIntensity = () => {

  }

  actionButtonAction = () => {
    if(this.state.readonly && !this.state.editMode) {
      this.setState({editMode: true})
    } else {
      const { store } = this.props.screenProps

      const studyTask = new SRStudyTask(
        this.state.id,
        this.state.taskName,
        this.state.notes,
        this.state.dates,
        this.state.ratingHistory,
        this.state.srs,
        this.state.intensity
      )

      if(this.state.readonly) {
        store.dispatch(actionCreators.replace(studyTask))
        this.setState({editMode: false})
      } else {
        store.dispatch(actionCreators.add(studyTask))
        this.dismissView()
      }
    }

  }

  destructiveButtonAction = () => {
    if (this.state.readonly && !this.state.editMode) {
      Alert.alert(
        'Delete Study Task',
        'Are you sure you want to delete the study task?',
        [
          {text: 'Cancel', onPress: () => {}, style: 'cancel'},
          {text: 'Delete', onPress: () => {
            // expect(this.state.id).toEqual('ada', `this.state.id: ${this.state.id}`)
            this.props.screenProps.store.dispatch(actionCreators.remove({id: this.state.id}))
            this.dismissView()
          }},
        ],
        { cancelable: true }
      )
    } else {
      this.dismissView()
    }
  }

  _renderSeparator = (flag) => {
    if(flag) {
      return <View name='separator' style={styles.sectionSeparator}/>
    } else {
      return null
    }
  }

  _renderNotes = (flag) => {
      if(flag) {
        const { notes, notesLabelString, readonly } = this.state
        return(
          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{notesLabelString}</Text>
            <TextInput
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={notesString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={Keyboard.dismiss}
              onChangeText={(notes) => this.notesTextFieldOnChangeText(notes)}
              value={notes}
              editable={this.state.editMode}
              multiline={this.state.readonly && !this.state.editMode}
            />
            {this._renderSeparator(!readonly)}
          </View>
        )
      } else {
        return null
      }
  }

  _renderDateSelection = (flag) => {
    if(flag) {
      const { pickedDate } = this.state
      const formattedPickedDate = pickedDate // TODO:
      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>{dateString}</Text>
          <SegmentedControlTab
            borderRadius={dateSegmentedControlCornerRadius}
            tabsContainerStyle={styles.tabsContainerStyle}
            tabStyle={styles.tabStyle}
            tabTextStyle={styles.tabTextStyle}
            activeTabStyle={styles.activeTabStyle}
            activeTabTextStyle={styles.activeTabTextStyle}
            values={['Today', 'Yesterday', formattedPickedDate]}
            selectedIndex={this.state.selectedDateIndex}
            onTabPress={this.handleDateSelection}
          />
        </View>
      )
    } else {
      return null
    }
  }

  _renderRatingHistory = (flag) => {
    if(flag) {

      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>Rating History</Text>

        </View>
      )
    } else {
      return null
    }
  }

  dismissView = () => {
    const { modalDismissAction } = this.props.screenProps
    modalDismissAction()
  }

}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
    backgroundColor: SRDarkColor,
  },
  edgePadding: {
    padding: 15,
    flex:1,
  },
  dataInputItemPadding: {
    padding: 4,
  },
  textInput: {
    fontSize: 48,
    color: SRBrightColor,
  },
  sectionLabel: {
    fontSize: 20,
    color: SRRedColor,
    fontWeight: 'bold'
  },
  sectionSeparator: {
    backgroundColor: SRBrightColor,
    height: 1,
  },
  lastSectionSeparator: {
    marginTop: 8,
  },
  sections: {
    padding: 8,
  },
  bottomButtonsView: {
    flexDirection: 'column',
    paddingTop: 20,
  },
  bottomButtons: {
    alignItems: 'center',
    height: buttonHeight,
    justifyContent: 'center',
  },
  actionButton: {
    backgroundColor: SRYellowColor,
    borderRadius: buttonCornerRadius,
    flex: 1,
  },
  cancelButton: {
    borderColor: SRYellowColor,
    borderWidth: 1,
    borderRadius: buttonCornerRadius,
    flex: 1,
    marginTop: 10,
  },
  bottomButtonsText: {
    color: SRDarkColor,
    fontSize: 16,
    fontWeight: 'bold',
  },
  actionButtonText: {
    paddingTop: 1,
  },
  destructiveButtonText: {
    color: SRYellowColor,
  },
  tabsContainerStyle: {
    paddingTop: 15,
    paddingBottom: 5,
    height: buttonHeight+14,
  },
  tabStyle: {
    backgroundColor: SRBrightColor,
    borderColor: SRBrightColor,
    borderRadius: dateSegmentedControlCornerRadius,
    marginLeft: 2,
    marginRight: 2,
  },
  tabTextStyle: {
    fontWeight: 'bold',
    color: SRDarkColor,
  },
  activeTabStyle: {
    backgroundColor: SRYellowColor,
    borderColor: SRYellowColor,
  },
  activeTabTextStyle: {
    color: SRDarkColor
  },
})
<commit_msg>Fixed unable to add tasks. Keyboard appears automatically when adding new task.<commit_after>// @flow
import React from 'react'
import {
  Alert,
  Keyboard,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  ScrollView,
  View
} from 'react-native'
import SegmentedControlTab from 'react-native-segmented-control-tab'
import expect, { createSpy, spyOn, isSpy } from 'expect'
import moment from 'moment'
import { actionCreators, SRStudyTask, SRStudyTaskIntensity } from './dataModel/SRSimpleDataModel'
import { SRSpacedRepetition } from './SRSpacedRepetition'
import { uuid } from './utilities/UUID'
import { capitalizeFirstLetter } from './utilities/String+Capitalize'
import {SRDarkColor, SRYellowColor, SRBrightColor, SRRedColor} from './utilities/SRColors'

const studyTaskString = 'STUDY TASK'
const notesString = 'NOTES'
const dateString = 'STARTING DATE'

const SRPlaceholderTextColor = 'rgba(251, 251, 253, 0.5)'

const inactiveColor = SRBrightColor
const buttonHeight = 46
const buttonCornerRadius = buttonHeight/2
const cancelButtonTint = SRDarkColor
const tintColor = SRRedColor

const dateSegmentedControlCornerRadius = 4

export default class SRStudyTaskEditor extends React.Component {

  static navigationOptions = ({navigation}) => {
    const { params = {} } = navigation.state

    return {
      headerTintColor: SRDarkColor,
      headerStyle: {
        backgroundColor: SRBrightColor
      },
      title: (params.readonly) ? 'Details' : 'Add a task',
    }
  }

  constructor(props) {
    super(props)

    const { params } = props.navigation.state

    this.state = {
      id:             params != null ? params.item.id            : uuid(),
      taskName:       params != null ? params.item.taskName      : null,
      notes:          params != null ? params.item.notes         : null,
      dates:          params != null ? params.item.dates         : [new Date()],
      ratingHistory:  params != null ? params.item.ratingHistory : [],
      srs:            params != null ? params.item.srs           : new SRSpacedRepetition(),
      intensity:      params != null ? params.item.intensity     : SRStudyTaskIntensity.NORMAL,

      readonly: params != null ? params.readonly : false,
      editMode: false,

      studyTaskLabelString: params != null ? studyTaskString : ' ',
      notesLabelString: params != null ? notesString : ' ',
      pickedDate: 'Other',
      selectedDateIndex: 0,
      selectedIntensityIndex: 0,
    }
  }

  props: {
    saveAction: (studyTask) => any,
  }

  componentWillReceiveProps() {
    const { notes, taskName } = this.state
    this.hideStudyTaskLabel(taskName == null || taskName == '')
    this.hideNotesLabel(notes == null || notes == '')
  }

  componentDidMount() {

  }

  render() {
    const { dates, intensity, notes, editMode, readonly, studyTaskLabelString, taskName } = this.state

    const actionButtonTitle = (readonly && editMode == false) ? 'Edit' : 'Save'
    const destructiveButtonTitle = (readonly && editMode == false) ? 'Delete' : 'Cancel'

    const NOT_IMPLEMENTED = false

    return (
      <ScrollView style={styles.scrollView}>
        <View style={styles.edgePadding}>

          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{studyTaskLabelString}</Text>
            <TextInput
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={studyTaskString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={Keyboard.dismiss}
              onChangeText={(taskName) => this.studyTextFieldOnChangeText(taskName)}
              value={taskName}
              editable={this.state.editMode || !readonly}
              multiline={this.state.readonly && !this.state.editMode}
              autoFocus={!readonly}
            />
            {this._renderSeparator(editMode)}
          </View>

          {this._renderNotes(!readonly || editMode || (notes != null && notes != ''))}
          {this._renderDateSelection(!readonly)}
          {this._renderRatingHistory(NOT_IMPLEMENTED)}

          <View name='dataSeparator' style={[styles.sectionSeparator, styles.lastSectionSeparator]}/>

          <View style={[styles.sections, styles.bottomButtonsView]}>
            <TouchableOpacity
              style={[styles.dataInputItemPadding, styles.bottomButtons, styles.actionButton]}
              onPress={this.actionButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.actionButtonText]}>{actionButtonTitle}</Text>
            </TouchableOpacity>

            <TouchableOpacity
              style={[styles.dataInputItemPadding, styles.bottomButtons, styles.cancelButton]}
              onPress={this.destructiveButtonAction}>
              <Text style={[styles.bottomButtonsText, styles.destructiveButtonText]}>{destructiveButtonTitle}</Text>
            </TouchableOpacity>
          </View>

        </View>
      </ScrollView>
    )
  }

  studyTextFieldOnChangeText = (taskName) => {
    this.hideStudyTaskLabel(taskName == null || taskName == '')
    this.setState({taskName})
  }

  notesTextFieldOnChangeText = (notes) => {
    this.hideNotesLabel(notes == null || notes == '')
    this.setState({notes})
  }

  hideStudyTaskLabel = (flag = true) => {
    this.setState({
      studyTaskLabelString: flag ? ' ' : studyTaskString
    })
  }

  hideNotesLabel = (flag = true) => {
    this.setState({
      notesLabelString: flag ? ' ' : notesString
    })
  }

  handleDateSelection = (index) => {
    this.setState({...this.state, selectedDateIndex: index})
  }

  handleIntensitySelection = (index) => {
    this.setState({...this.state, selectedIntensityIndex: index})
  }

  openDatePicker = () => {

  }

  changeIntensity = () => {

  }

  actionButtonAction = () => {
    if(this.state.readonly && !this.state.editMode) {
      this.setState({editMode: true})
    } else {
      const { store } = this.props.screenProps

      const studyTask = new SRStudyTask(
        this.state.id,
        this.state.taskName,
        this.state.notes,
        this.state.dates,
        this.state.ratingHistory,
        this.state.srs,
        this.state.intensity
      )

      if(this.state.readonly) {
        store.dispatch(actionCreators.replace(studyTask))
        this.setState({editMode: false})
      } else {
        store.dispatch(actionCreators.add(studyTask))
        this.dismissView()
      }
    }

  }

  destructiveButtonAction = () => {
    if (this.state.readonly && !this.state.editMode) {
      Alert.alert(
        'Delete Study Task',
        'Are you sure you want to delete the study task?',
        [
          {text: 'Cancel', onPress: () => {}, style: 'cancel'},
          {text: 'Delete', onPress: () => {
            // expect(this.state.id).toEqual('ada', `this.state.id: ${this.state.id}`)
            this.props.screenProps.store.dispatch(actionCreators.remove({id: this.state.id}))
            this.dismissView()
          }},
        ],
        { cancelable: true }
      )
    } else {
      this.dismissView()
    }
  }

  _renderSeparator = (flag) => {
    if(flag) {
      return <View name='separator' style={styles.sectionSeparator}/>
    } else {
      return null
    }
  }

  _renderNotes = (flag) => {
      if(flag) {
        const { notes, notesLabelString, readonly } = this.state
        return(
          <View style={styles.sections}>
            <Text style={styles.sectionLabel}>{notesLabelString}</Text>
            <TextInput
              style={[styles.dataInputItemPadding, styles.textInput]}
              placeholder={notesString}
              placeholderTextColor={SRPlaceholderTextColor}
              onSubmitEditing={Keyboard.dismiss}
              onChangeText={(notes) => this.notesTextFieldOnChangeText(notes)}
              value={notes}
              editable={this.state.editMode || !readonly}
              multiline={this.state.readonly && !this.state.editMode}
            />
            {this._renderSeparator(!readonly)}
          </View>
        )
      } else {
        return null
      }
  }

  _renderDateSelection = (flag) => {
    if(flag) {
      const { pickedDate } = this.state
      const formattedPickedDate = pickedDate // TODO:
      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>{dateString}</Text>
          <SegmentedControlTab
            borderRadius={dateSegmentedControlCornerRadius}
            tabsContainerStyle={styles.tabsContainerStyle}
            tabStyle={styles.tabStyle}
            tabTextStyle={styles.tabTextStyle}
            activeTabStyle={styles.activeTabStyle}
            activeTabTextStyle={styles.activeTabTextStyle}
            values={['Today', 'Yesterday', formattedPickedDate]}
            selectedIndex={this.state.selectedDateIndex}
            onTabPress={this.handleDateSelection}
          />
        </View>
      )
    } else {
      return null
    }
  }

  _renderRatingHistory = (flag) => {
    if(flag) {

      return (
        <View style={styles.sections}>
          <Text style={styles.sectionLabel}>Rating History</Text>

        </View>
      )
    } else {
      return null
    }
  }

  dismissView = () => {
    const { modalDismissAction } = this.props.screenProps
    modalDismissAction()
  }

}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
    backgroundColor: SRDarkColor,
  },
  edgePadding: {
    padding: 15,
    flex:1,
  },
  dataInputItemPadding: {
    padding: 4,
  },
  textInput: {
    fontSize: 48,
    color: SRBrightColor,
  },
  sectionLabel: {
    fontSize: 20,
    color: SRRedColor,
    fontWeight: 'bold'
  },
  sectionSeparator: {
    backgroundColor: SRBrightColor,
    height: 1,
  },
  lastSectionSeparator: {
    marginTop: 8,
  },
  sections: {
    padding: 8,
  },
  bottomButtonsView: {
    flexDirection: 'column',
    paddingTop: 20,
  },
  bottomButtons: {
    alignItems: 'center',
    height: buttonHeight,
    justifyContent: 'center',
  },
  actionButton: {
    backgroundColor: SRYellowColor,
    borderRadius: buttonCornerRadius,
    flex: 1,
  },
  cancelButton: {
    borderColor: SRYellowColor,
    borderWidth: 1,
    borderRadius: buttonCornerRadius,
    flex: 1,
    marginTop: 10,
  },
  bottomButtonsText: {
    color: SRDarkColor,
    fontSize: 16,
    fontWeight: 'bold',
  },
  actionButtonText: {
    paddingTop: 1,
  },
  destructiveButtonText: {
    color: SRYellowColor,
  },
  tabsContainerStyle: {
    paddingTop: 15,
    paddingBottom: 5,
    height: buttonHeight+14,
  },
  tabStyle: {
    backgroundColor: SRBrightColor,
    borderColor: SRBrightColor,
    borderRadius: dateSegmentedControlCornerRadius,
    marginLeft: 2,
    marginRight: 2,
  },
  tabTextStyle: {
    fontWeight: 'bold',
    color: SRDarkColor,
  },
  activeTabStyle: {
    backgroundColor: SRYellowColor,
    borderColor: SRYellowColor,
  },
  activeTabTextStyle: {
    color: SRDarkColor
  },
})
<|endoftext|>


<commit_before>var subarg = require('subarg');

function Prorogram(opts) {

    Object.defineProperty(this, opts, {
        enumerable: false,
        value: opts || {}
    });

    this.options = {};
    this.commands = {};

    this.raw_arguments = {};
    this.parsed = {};

    this.selected = {};
}

// Prototype Setter/Getter Properties

Object.defineProperty(Prorogram.prototype, "action", {
    enumerable: true,
    get: function() {
        return this.opts.action;
    },
    set: function(fn) {
        this.opts.action = fn;
    }
});

Object.defineProperty(Prorogram.prototype, "required", {
    enumerable: true,
    get: function() {
        return this.opts.required;
    },
    set: function(reqd) {
        this.opts.required = reqd;
    }
});

Object.defineProperty(Prorogram.prototype, "description", {
    enumerable: true,
    get: function() {
        return this.opts.description;
    },
    set: function(desc) {
        this.opts.description = desc;
    }
});

// Main API Methods

Prorogram.prototype.create = function create(opts) {
    return new Prorogram(opts);
};

Prorogram.prototype.option = function(flag_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof flag_name !== 'string') {
        throw new Error("Missing Flag Name");
    }

    opts.flag_name = flag_name = clearLeadingDashes(flag_name);
    opts.shortcut = createShortcut(opts.shortcut, flag_name, this.options);
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.options[flag_name] = opts;

    return this;
};

Prorogram.prototype.command = function(command_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof command_name !== 'string') {
        throw new Error("Missing Command Name");
    }

    opts.command_name = command_name;
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.commands[command_name] = this.create(opts);

    return this.commands[command_name];
};

Prorogram.prototype.parse = function(argv) {

    if (!Array.isArray(argv) && typeof argv === 'object') {
        argv = this.rebuildArgArray(argv);
    }

    this.parsed = subarg(argv);
    this.raw_arguments = {
        _: argv
    };

    if (!evalCmd(this, this.parsed, argv, this.commands)) {
        evalFlags(this, this.parsed, this.options);
    }
};

// Core Functional Evaluation Methods

function evalFlags(program, args, options) {

    var value = null,
        err = null,
        flag = null;

    for (var flag_name in options) {

        flag = options[flag_name];
        value = args[flag_name] || args[flag.shortcut];

        if (value) {
            if (flag.required && value === true) {
                err = new Error('Required argument <' + flag.required + '> missing for flag: \'--' + flag_name + '\'');
            } else {
                err = null;
            }

            program.selected[flag_name] = value;

            if (typeof flag.action === 'function') {
                flag.action(err, value, program);
            }
        }
    }
}

function evalCmd(program, parse_args, argv, commands) {

    var possible_commands = parse_args._,
        command,
        possible,
        remaining_args,
        err;

    for (var i = 0; i < possible_commands.length; i++) {

        possible = possible_commands[i];

        for (var command_name in commands) {

            if (possible === command_name || possible === commands[command_name].alias) {

                command = commands[command_name];

                if (command.required && possible_commands[i + 1] === undefined) {
                    err = new Error('Required argument <' + command.required + '> missing for command: \'' + command_name + '\'');
                } else {
                    err = null;
                }

                remaining_args = argv.slice(i);
                command.parse(remaining_args);

                if (typeof command.action === 'function') {
                    command.action(err, remaining_args, program);
                }
                return true;
            }
        }
    }
    return false;
}

// Extra Sauce API Methods

Prorogram.prototype.rebuildArgString = function(parsed_args) {
    return unparse(parsed_args).command_string;
};

Prorogram.prototype.rebuildArgArray = function(parsed_args) {
    return unparse(parsed_args);
};

function createShortcut(shortcut, flag_name, options) {

    var exists;

    if (!shortcut) {
        for (var i = 0; i < flag_name.length; i++) {
            exists = false;
            shortcut = flag_name[i];
            for (var flag in options) {
                if (options[flag].shortcut === shortcut) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                break;
            }
        }
    } else {
        shortcut = clearLeadingDashes(shortcut);
    }
    return shortcut;
}

function clearLeadingDashes(str) {
    for (var i = 0; i < str.length; i++) {
        if (str[i] !== '-')
            break;
    }
    return str.slice(i);
}

function mergeOpts(opts, fn) {
    opts = opts || {};

    if (typeof opts === 'function' && fn === undefined) {
        fn = opts;
        opts = {};
    }
    if (typeof fn === 'function' && typeof opts.action !== 'function') {
        opts.action = fn;
    }

    return opts;
}

module.exports = exports = new Prorogram();
<commit_msg>bug in defininung opts property<commit_after>var subarg = require('subarg');

function Prorogram(opts) {

    Object.defineProperty(this, 'opts', {
        enumerable: false,
        value: opts || {}
    });

    this.options = {};
    this.commands = {};

    this.raw_arguments = {};
    this.parsed = {};

    this.selected = {};
}

// Prototype Setter/Getter Properties

Object.defineProperty(Prorogram.prototype, "action", {
    enumerable: true,
    get: function() {
        return this.opts.action;
    },
    set: function(fn) {
        this.opts.action = fn;
    }
});

Object.defineProperty(Prorogram.prototype, "required", {
    enumerable: true,
    get: function() {
        return this.opts.required;
    },
    set: function(reqd) {
        this.opts.required = reqd;
    }
});

Object.defineProperty(Prorogram.prototype, "description", {
    enumerable: true,
    get: function() {
        return this.opts.description;
    },
    set: function(desc) {
        this.opts.description = desc;
    }
});

// Main API Methods

Prorogram.prototype.create = function create(opts) {
    return new Prorogram(opts);
};

Prorogram.prototype.option = function(flag_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof flag_name !== 'string') {
        throw new Error("Missing Flag Name");
    }

    opts.flag_name = flag_name = clearLeadingDashes(flag_name);
    opts.shortcut = createShortcut(opts.shortcut, flag_name, this.options);
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.options[flag_name] = opts;

    return this;
};

Prorogram.prototype.command = function(command_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof command_name !== 'string') {
        throw new Error("Missing Command Name");
    }

    opts.command_name = command_name;
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.commands[command_name] = this.create(opts);

    return this.commands[command_name];
};

Prorogram.prototype.parse = function(argv) {

    if (!Array.isArray(argv) && typeof argv === 'object') {
        argv = this.rebuildArgArray(argv);
    }

    this.parsed = subarg(argv);
    this.raw_arguments = {
        _: argv
    };

    if (!evalCmd(this, this.parsed, argv, this.commands)) {
        evalFlags(this, this.parsed, this.options);
    }
};

// Core Functional Evaluation Methods

function evalFlags(program, args, options) {

    var value = null,
        err = null,
        flag = null;

    for (var flag_name in options) {

        flag = options[flag_name];
        value = args[flag_name] || args[flag.shortcut];

        if (value) {
            if (flag.required && value === true) {
                err = new Error('Required argument <' + flag.required + '> missing for flag: \'--' + flag_name + '\'');
            } else {
                err = null;
            }

            program.selected[flag_name] = value;

            if (typeof flag.action === 'function') {
                flag.action(err, value, program);
            }
        }
    }
}

function evalCmd(program, parse_args, argv, commands) {

    var possible_commands = parse_args._,
        command,
        possible,
        remaining_args,
        err;

    for (var i = 0; i < possible_commands.length; i++) {

        possible = possible_commands[i];

        for (var command_name in commands) {

            if (possible === command_name || possible === commands[command_name].alias) {

                command = commands[command_name];

                if (command.required && possible_commands[i + 1] === undefined) {
                    err = new Error('Required argument <' + command.required + '> missing for command: \'' + command_name + '\'');
                } else {
                    err = null;
                }

                remaining_args = argv.slice(i);
                command.parse(remaining_args);

                if (typeof command.action === 'function') {
                    command.action(err, remaining_args, program);
                }
                return true;
            }
        }
    }
    return false;
}

// Extra Sauce API Methods

Prorogram.prototype.rebuildArgString = function(parsed_args) {
    return unparse(parsed_args).command_string;
};

Prorogram.prototype.rebuildArgArray = function(parsed_args) {
    return unparse(parsed_args);
};

function createShortcut(shortcut, flag_name, options) {

    var exists;

    if (!shortcut) {
        for (var i = 0; i < flag_name.length; i++) {
            exists = false;
            shortcut = flag_name[i];
            for (var flag in options) {
                if (options[flag].shortcut === shortcut) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                break;
            }
        }
    } else {
        shortcut = clearLeadingDashes(shortcut);
    }
    return shortcut;
}

function clearLeadingDashes(str) {
    for (var i = 0; i < str.length; i++) {
        if (str[i] !== '-')
            break;
    }
    return str.slice(i);
}

function mergeOpts(opts, fn) {
    opts = opts || {};

    if (typeof opts === 'function' && fn === undefined) {
        fn = opts;
        opts = {};
    }
    if (typeof fn === 'function' && typeof opts.action !== 'function') {
        opts.action = fn;
    }

    return opts;
}

module.exports = exports = new Prorogram();
<|endoftext|>


<commit_before>/*
  Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
  (c) 2012-2013, Lennard Voogdt

  http://leafletjs.com
  https://github.com/lvoogdt
*/

/*global L*/

(function (window, document, undefined) {
    "use strict";
    /*
     * Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library.
     */

    L.AwesomeMarkers = {};

    L.AwesomeMarkers.version = '2.0.1';

    L.AwesomeMarkers.Icon = L.Icon.extend({
        options: {
            iconSize: [35, 45],
            iconAnchor:   [17, 42],
            popupAnchor: [1, -32],
            shadowAnchor: [10, 12],
            shadowSize: [36, 16],
            className: 'awesome-marker',
            prefix: 'glyphicon',
            spinClass: 'fa-spin',
            extraClasses: '',
            icon: 'home',
            markerColor: 'blue',
            iconColor: 'white',
			html: ""
        },

        initialize: function (options) {
            options = L.Util.setOptions(this, options);
        },

        createIcon: function () {
            var div = document.createElement('div'),
                options = this.options;

            //if (options.icon) {
                div.innerHTML = this._createInner();
            //}

            if (options.bgPos) {
                div.style.backgroundPosition =
                    (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px';
            }

            this._setIconStyles(div, 'icon-' + options.markerColor);
            return div;
        },

        _createInner: function() {
            var iconClass, iconSpinClass = "", iconColorClass = "", iconColorStyle = "", options = this.options;

            if(options.icon.slice(0,options.prefix.length+1) === options.prefix + "-") {
                iconClass = options.icon;
            } else {
                iconClass = options.prefix + "-" + options.icon;
            }

            if(options.spin && typeof options.spinClass === "string") {
                iconSpinClass = options.spinClass;
            }

            if(options.iconColor) {
                if(options.iconColor === 'white' || options.iconColor === 'black') {
                    iconColorClass = "icon-" + options.iconColor;
                } else {
                    iconColorStyle = "style='color: " + options.iconColor + "' ";
                }
            }

            return "<i " + iconColorStyle + "class='" + options.extraClasses + " " + options.prefix + " " + iconClass + " " + iconSpinClass + " " + iconColorClass + "'> + options.html + </i>";
        },

        _setIconStyles: function (img, name) {
            var options = this.options,
                size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']),
                anchor;

            if (name === 'shadow') {
                anchor = L.point(options.shadowAnchor || options.iconAnchor);
            } else {
                anchor = L.point(options.iconAnchor);
            }

            if (!anchor && size) {
                anchor = size.divideBy(2, true);
            }

            img.className = 'awesome-marker-' + name + ' ' + options.className;

            if (anchor) {
                img.style.marginLeft = (-anchor.x) + 'px';
                img.style.marginTop  = (-anchor.y) + 'px';
            }

            if (size) {
                img.style.width  = size.x + 'px';
                img.style.height = size.y + 'px';
            }
        },

        createShadow: function () {
            var div = document.createElement('div');

            this._setIconStyles(div, 'shadow');
            return div;
      },
    });

    L.AwesomeMarkers.icon = function (options) {
        return new L.AwesomeMarkers.Icon(options);
    };

}(this, document));

<commit_msg>include html option to marker<commit_after>/*
  Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
  (c) 2012-2013, Lennard Voogdt

  http://leafletjs.com
  https://github.com/lvoogdt
*/

/*global L*/

(function (window, document, undefined) {
    "use strict";
    /*
     * Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library.
     */

    L.AwesomeMarkers = {};

    L.AwesomeMarkers.version = '2.0.1';

    L.AwesomeMarkers.Icon = L.Icon.extend({
        options: {
            iconSize: [35, 45],
            iconAnchor:   [17, 42],
            popupAnchor: [1, -32],
            shadowAnchor: [10, 12],
            shadowSize: [36, 16],
            className: 'awesome-marker',
            prefix: 'glyphicon',
            spinClass: 'fa-spin',
            extraClasses: '',
            icon: 'home',
            markerColor: 'blue',
            iconColor: 'white',
			html: ""
        },

        initialize: function (options) {
            options = L.Util.setOptions(this, options);
        },

        createIcon: function () {
            var div = document.createElement('div'),
                options = this.options;

            //if (options.icon) {
                div.innerHTML = this._createInner();
            //}

            if (options.bgPos) {
                div.style.backgroundPosition =
                    (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px';
            }

            this._setIconStyles(div, 'icon-' + options.markerColor);
            return div;
        },

        _createInner: function() {
            var iconClass, iconSpinClass = "", iconColorClass = "", iconColorStyle = "", options = this.options;

            if(options.icon.slice(0,options.prefix.length+1) === options.prefix + "-") {
                iconClass = options.icon;
            } else {
                iconClass = options.prefix + "-" + options.icon;
            }

            if(options.spin && typeof options.spinClass === "string") {
                iconSpinClass = options.spinClass;
            }

            if(options.iconColor) {
                if(options.iconColor === 'white' || options.iconColor === 'black') {
                    iconColorClass = "icon-" + options.iconColor;
                } else {
                    iconColorStyle = "style='color: " + options.iconColor + "' ";
                }
            }

            return "<i " + iconColorStyle + "class='" + options.extraClasses + " " + options.prefix + " " + iconClass + " " + iconSpinClass + " " + iconColorClass + "'>" + options.html + </i>";
        },

        _setIconStyles: function (img, name) {
            var options = this.options,
                size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']),
                anchor;

            if (name === 'shadow') {
                anchor = L.point(options.shadowAnchor || options.iconAnchor);
            } else {
                anchor = L.point(options.iconAnchor);
            }

            if (!anchor && size) {
                anchor = size.divideBy(2, true);
            }

            img.className = 'awesome-marker-' + name + ' ' + options.className;

            if (anchor) {
                img.style.marginLeft = (-anchor.x) + 'px';
                img.style.marginTop  = (-anchor.y) + 'px';
            }

            if (size) {
                img.style.width  = size.x + 'px';
                img.style.height = size.y + 'px';
            }
        },

        createShadow: function () {
            var div = document.createElement('div');

            this._setIconStyles(div, 'shadow');
            return div;
      },
    });

    L.AwesomeMarkers.icon = function (options) {
        return new L.AwesomeMarkers.Icon(options);
    };

}(this, document));

<|endoftext|>


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

'use strict';

var _ = require('underscore');
var fs = require('fs');
var chalk = require('chalk');
var program = require('commander');

var StyleStats = require('../lib/stylestats');
var Format = require('../lib/format');
var specs = require('../lib/specs');
var util = require('../lib/util');

program
  .version(require('../package.json').version)
  .usage('[options] <file ...>')
  .option('-c, --config [path]', 'set configurations')
  .option('-f, --format [format]', 'set the output format <json|html|md|csv>')
  .option('-t, --template [path]', 'set the template path for output formant')
  .option('-s, --specs [path]', 'run test with your test specs file')
  .option('-g, --gzip', 'show gzipped file size')
  .option('-n, --number', 'show only numeral metrics')
  .option('-u, --ua [OS]', 'set the user agent <ios|android>')
  .parse(process.argv);

if (!program.args.length) {
  console.log(chalk.red('\n No input file specified.'));
  program.help();
}

// Config
var config = {
  requestOptions: {
    headers: {}
  }
};

if (program.gzip) {
  config.gzippedSize = true;
}

if (program.ua) {
  var iOS = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A365 Safari/600.1.4';
  var Android = 'Mozilla/5.0 (Linux; Android 5.0; Nexus 5 Build/LPX13D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36';
  switch (program.ua) {
    case 'ios':
      config.requestOptions.headers['User-Agent'] = iOS;
      break;
    case 'android':
      config.requestOptions.headers['User-Agent'] = Android;
      break;
    default:
      console.error(chalk.yellow(' [WARN] User agent should be `ios` or `android`.'));
      break;
  }
}

if (program.number) {
  var numberConfig = {
    "published": false,
    "paths": false,
    "mostIdentifierSelector": false,
    "lowestCohesionSelector": false,
    "uniqueFontSizes": false,
    "uniqueColors": false,
    "propertiesCount": false
  };
  _.extend(config, numberConfig);
}

var userConfig = {};
if (program.config && util.isFile(program.config)) {
  var configString = fs.readFileSync(program.config, {
    encoding: 'utf8'
  });
  try {
    userConfig = JSON.parse(configString);
  } catch (e) {
    throw e;
  }
} else if (_.isObject(program.config)) {
  userConfig = config;
}

_.extend(config, userConfig);

// Parse
var stats = new StyleStats(program.args, config);
stats.parse(function (error, result) {
  if (error) {
    console.log(chalk.red(' [ERROR] ' + error.message));
  }

  var format = new Format(result);
  if (fs.existsSync(program.template)) {

    format.setTemplate(fs.readFileSync(program.template, {
      encoding: 'utf8'
    }));

    format.toTemplate(function (text) {
      console.log(text);
    });

  } else if(!program.specs) {
    switch (program.format) {
      case 'json':
        format.toJSON(function (json) {
          console.log(json);
        });
        break;
      case 'csv':
        format.toCSV(function (csv) {
          console.log(csv);
        });
        break;
      case 'html':
        format.toHTML(function (html) {
          console.log(html);
        });
        break;
      case 'md':
        format.toMarkdown(function (md) {
          console.log(md);
        });
        break;
      default:
        format.toTable(function (table) {
          console.log(' StyleStats!\n' + table);
        });
        break;
    }
  } else {
    specs(result, program.specs);
  }
});
<commit_msg>Fix --number option<commit_after>#!/usr/bin/env node

'use strict';

var _ = require('underscore');
var fs = require('fs');
var chalk = require('chalk');
var program = require('commander');

var StyleStats = require('../lib/stylestats');
var Format = require('../lib/format');
var specs = require('../lib/specs');
var util = require('../lib/util');

program
  .version(require('../package.json').version)
  .usage('[options] <file ...>')
  .option('-c, --config [path]', 'set configurations')
  .option('-f, --format [format]', 'set the output format <json|html|md|csv>')
  .option('-t, --template [path]', 'set the template path for output formant')
  .option('-s, --specs [path]', 'run test with your test specs file')
  .option('-g, --gzip', 'show gzipped file size')
  .option('-n, --number', 'show only numeral metrics')
  .option('-u, --ua [OS]', 'set the user agent <ios|android>')
  .parse(process.argv);

if (!program.args.length) {
  console.log(chalk.red('\n No input file specified.'));
  program.help();
}

// Config
var config = {
  requestOptions: {
    headers: {}
  }
};

if (program.gzip) {
  config.gzippedSize = true;
}

if (program.ua) {
  var iOS = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A365 Safari/600.1.4';
  var Android = 'Mozilla/5.0 (Linux; Android 5.0; Nexus 5 Build/LPX13D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36';
  switch (program.ua) {
    case 'ios':
      config.requestOptions.headers['User-Agent'] = iOS;
      break;
    case 'android':
      config.requestOptions.headers['User-Agent'] = Android;
      break;
    default:
      console.error(chalk.yellow(' [WARN] User agent should be `ios` or `android`.'));
      break;
  }
}

if (program.number) {
  var numberConfig = {
    "published": false,
    "paths": false,
    "mostIdentifierSelector": false,
    "lowestCohesionSelector": false,
    "uniqueFontFamilies": false,
    "uniqueFontSizes": false,
    "uniqueColors": false,
    "propertiesCount": false
  };
  _.extend(config, numberConfig);
}

var userConfig = {};
if (program.config && util.isFile(program.config)) {
  var configString = fs.readFileSync(program.config, {
    encoding: 'utf8'
  });
  try {
    userConfig = JSON.parse(configString);
  } catch (e) {
    throw e;
  }
} else if (_.isObject(program.config)) {
  userConfig = config;
}

_.extend(config, userConfig);

// Parse
var stats = new StyleStats(program.args, config);
stats.parse(function (error, result) {
  if (error) {
    console.log(chalk.red(' [ERROR] ' + error.message));
  }

  var format = new Format(result);
  if (fs.existsSync(program.template)) {

    format.setTemplate(fs.readFileSync(program.template, {
      encoding: 'utf8'
    }));

    format.toTemplate(function (text) {
      console.log(text);
    });

  } else if(!program.specs) {
    switch (program.format) {
      case 'json':
        format.toJSON(function (json) {
          console.log(json);
        });
        break;
      case 'csv':
        format.toCSV(function (csv) {
          console.log(csv);
        });
        break;
      case 'html':
        format.toHTML(function (html) {
          console.log(html);
        });
        break;
      case 'md':
        format.toMarkdown(function (md) {
          console.log(md);
        });
        break;
      default:
        format.toTable(function (table) {
          console.log(' StyleStats!\n' + table);
        });
        break;
    }
  } else {
    specs(result, program.specs);
  }
});
<|endoftext|>