<commit_before>/*
 * A smart button for react-native apps
 * https://github.com/react-native-component/react-native-smart-button/
 * Released under the MIT license
 * Copyright (c) 2016 react-native-component <moonsunfall@aliyun.com>
 */

import React, {
  Component,
  PropTypes,
} from 'react'
import {
  View,
  Text,
  TouchableHighlight,
  TouchableOpacity,
  TouchableWithoutFeedback,
  StyleSheet,
} from 'react-native'

import Blur from './blur'

const SYSTEM_OPACITY = 0.2
const TOUCH_TYPE = 'opacity'

export default class Button extends Component {

  static defaultProps = {
    touchableType: TOUCH_TYPE,
    activeOpacity: SYSTEM_OPACITY,
    onPress: () => {},
    onPressIn: () => {},
    onPressOut: () => {},
  }

  static PropTypes = {
      testID: PropTypes.string,
      touchableType: PropTypes.string,
      activeOpacity: PropTypes.number,
      underlayColor: PropTypes.color,
      style: PropTypes.style,
      textStyle: PropTypes.style,
      onPressIn: PropTypes.func,
      onPressOut: PropTypes.func,
      onPress: PropTypes.func,
      disabled: PropTypes.bool,
      icon: PropTypes.element,
      badge: PropTypes.element,
      shadowOpacity: PropTypes.number,
      shadowColor: PropTypes.color,
  }

    // 构造
    constructor(props, context) {
      super(props);
      // 初始状态
      this.state = {
         pressIn: false,
      };
    }

  render() {
      let touchableProps = {},
          touchableType = this.props.touchableType
      if(!this.props.disabled) {
        touchableProps.onPress = this.props.onPress
        touchableProps.onPressIn = this.props.onPressIn
        touchableProps.onPressOut = this.props.onPressOut
      }
      switch (touchableType) {
          case 'highlight':
              touchableProps.activeOpacity = 1
              touchableProps.underlayColor = this.props.underlayColor
              return (
                <TouchableHighlight
                  style={[this.props.style]}
                  {...touchableProps}
                  testID={this.props.testID}>
                  <View>
                    {this.props.icon}
                    <Text style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}>
                      {this.props.children}
                    </Text>
                    {this.props.badge}
                  </View>
                </TouchableHighlight>
              )
           case 'opacityContent':
             touchableProps.activeOpacity = this.props.activeOpacity
             return (
               <View style={this.props.style}>
                 <TouchableOpacity
                   style={[styles.touchContainer]}
                   {...touchableProps}
                   testID={this.props.testID}>
                   {this.props.icon}
                   <Text style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}>
                     {this.props.children}
                   </Text>
                   {this.props.badge}
                 </TouchableOpacity>
               </View>
             )
           case 'blur': //experimental feature
             touchableProps.activeOpacity = this.props.activeOpacity
             touchableProps.onPressIn = this._onBlurPressIn
             touchableProps.onPressOut = this._onBlurPressOut
             return (
               <View onLayout={this._onButtonLayout} style={[this.props.style, {position: 'relative', overflow: 'hidden',}]}>
                 <TouchableOpacity
                   style={styles.touchContainer}
                   {...touchableProps}
                   testID={this.props.testID}>
                   {this.props.icon}
                   <Text
                     onLayout={this._onTextLayout}
                     style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}
                   >
                     {this.props.children}
                   </Text>
                   {this.props.badge}
                 </TouchableOpacity>
                 {this._renderBlur()}
               </View>
             )
           case 'opacity':
           default:
             touchableProps.activeOpacity = this.props.activeOpacity
             return (
                 <TouchableOpacity
                   style={[this.props.style]}
                   {...touchableProps}
                   testID={this.props.testID}>
                   {this.props.icon}
                   <Text style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}>
                     {this.props.children}
                   </Text>
                   {this.props.badge}
                 </TouchableOpacity>
               )
      }
  }

  _renderBlur() {
      return  (
          <Blur
            show={this.state.pressIn}
            textDimension={this.textDimension}
            containerDimension={this.boxDimension}
            shadowOpacity={this.props.shadowOpacity}
            shadowColor={this.props.shadowColor}
          />
      )
  }

  _onBlurPressIn = (e) => {
      this.setState({
        pressIn: true,
      })
      this.props.onPressIn.call(this, e)
  }

  _onBlurPressOut = (e) => {
    this.setState({
      pressIn: false,
    })
    this.props.onPressOut.call(this, e)
  }

  _onButtonLayout = (e) => {
    this.boxDimension = {
      width: e.nativeEvent.layout.width,
      height: e.nativeEvent.layout.height,
    }
  }

  _onTextLayout = (e) => {
     this.textDimension = {
       width: e.nativeEvent.layout.width,
       height: e.nativeEvent.layout.height,
     }
  }

}

const styles = StyleSheet.create({
  text: {
    color: '#007aff',
    fontFamily: '.HelveticaNeueInterface-MediumP4',
    fontSize: 17,
    fontWeight: 'bold',
    textAlign: 'center',
  },
  disabledText: {
    color: '#dcdcdc',
  },
  touchContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
})<commit_msg>fixed proptypes defination<commit_after>/*
 * A smart button for react-native apps
 * https://github.com/react-native-component/react-native-smart-button/
 * Released under the MIT license
 * Copyright (c) 2016 react-native-component <moonsunfall@aliyun.com>
 */

import React, {
  Component,
  PropTypes,
} from 'react'
import {
  View,
  Text,
  TouchableHighlight,
  TouchableOpacity,
  TouchableWithoutFeedback,
  StyleSheet,
} from 'react-native'

import Blur from './blur'

const SYSTEM_OPACITY = 0.2
const TOUCH_TYPE = 'opacity'

export default class Button extends Component {

  static defaultProps = {
    touchableType: TOUCH_TYPE,
    activeOpacity: SYSTEM_OPACITY,
    onPress: () => {},
    onPressIn: () => {},
    onPressOut: () => {},
  }

  static PropTypes = {
      testID: PropTypes.string,
      touchableType: PropTypes.string,
      activeOpacity: PropTypes.number,
      underlayColor: PropTypes.color,
      style: View.propTypes.style,
      textStyle: Text.propTypes.style,
      onPressIn: PropTypes.func,
      onPressOut: PropTypes.func,
      onPress: PropTypes.func,
      disabled: PropTypes.bool,
      icon: PropTypes.element,
      badge: PropTypes.element,
      shadowOpacity: PropTypes.number,
      shadowColor: PropTypes.color,
  }

    // 构造
    constructor(props, context) {
      super(props);
      // 初始状态
      this.state = {
         pressIn: false,
      };
    }

  render() {
      let touchableProps = {},
          touchableType = this.props.touchableType
      if(!this.props.disabled) {
        touchableProps.onPress = this.props.onPress
        touchableProps.onPressIn = this.props.onPressIn
        touchableProps.onPressOut = this.props.onPressOut
      }
      switch (touchableType) {
          case 'highlight':
              touchableProps.activeOpacity = 1
              touchableProps.underlayColor = this.props.underlayColor
              return (
                <TouchableHighlight
                  style={[this.props.style]}
                  {...touchableProps}
                  testID={this.props.testID}>
                  <View>
                    {this.props.icon}
                    <Text style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}>
                      {this.props.children}
                    </Text>
                    {this.props.badge}
                  </View>
                </TouchableHighlight>
              )
           case 'opacityContent':
             touchableProps.activeOpacity = this.props.activeOpacity
             return (
               <View style={this.props.style}>
                 <TouchableOpacity
                   style={[styles.touchContainer]}
                   {...touchableProps}
                   testID={this.props.testID}>
                   {this.props.icon}
                   <Text style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}>
                     {this.props.children}
                   </Text>
                   {this.props.badge}
                 </TouchableOpacity>
               </View>
             )
           case 'blur': //experimental feature
             touchableProps.activeOpacity = this.props.activeOpacity
             touchableProps.onPressIn = this._onBlurPressIn
             touchableProps.onPressOut = this._onBlurPressOut
             return (
               <View onLayout={this._onButtonLayout} style={[this.props.style, {position: 'relative', overflow: 'hidden',}]}>
                 <TouchableOpacity
                   style={styles.touchContainer}
                   {...touchableProps}
                   testID={this.props.testID}>
                   {this.props.icon}
                   <Text
                     onLayout={this._onTextLayout}
                     style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}
                   >
                     {this.props.children}
                   </Text>
                   {this.props.badge}
                 </TouchableOpacity>
                 {this._renderBlur()}
               </View>
             )
           case 'opacity':
           default:
             touchableProps.activeOpacity = this.props.activeOpacity
             return (
                 <TouchableOpacity
                   style={[this.props.style]}
                   {...touchableProps}
                   testID={this.props.testID}>
                   {this.props.icon}
                   <Text style={[styles.text, this.props.disabled ? styles.disabledText : null, this.props.textStyle]}>
                     {this.props.children}
                   </Text>
                   {this.props.badge}
                 </TouchableOpacity>
               )
      }
  }

  _renderBlur() {
      return  (
          <Blur
            show={this.state.pressIn}
            textDimension={this.textDimension}
            containerDimension={this.boxDimension}
            shadowOpacity={this.props.shadowOpacity}
            shadowColor={this.props.shadowColor}
          />
      )
  }

  _onBlurPressIn = (e) => {
      this.setState({
        pressIn: true,
      })
      this.props.onPressIn.call(this, e)
  }

  _onBlurPressOut = (e) => {
    this.setState({
      pressIn: false,
    })
    this.props.onPressOut.call(this, e)
  }

  _onButtonLayout = (e) => {
    this.boxDimension = {
      width: e.nativeEvent.layout.width,
      height: e.nativeEvent.layout.height,
    }
  }

  _onTextLayout = (e) => {
     this.textDimension = {
       width: e.nativeEvent.layout.width,
       height: e.nativeEvent.layout.height,
     }
  }

}

const styles = StyleSheet.create({
  text: {
    color: '#007aff',
    fontFamily: '.HelveticaNeueInterface-MediumP4',
    fontSize: 17,
    fontWeight: 'bold',
    textAlign: 'center',
  },
  disabledText: {
    color: '#dcdcdc',
  },
  touchContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
})<|endoftext|>


<commit_before><commit_msg>Adding my JS for exercise 02<commit_after><|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { isElloAndroid } from '../../lib/jello'
import { trackEvent } from '../../actions/analytics'
import {
  BoltIcon,
  CircleIcon,
  GridIcon,
  ListIcon,
  SearchIcon,
  SparklesIcon,
} from '../assets/Icons'
import {
  NavbarLayoutTool,
  NavbarLink,
  NavbarMark,
  NavbarMorePostsButton,
  NavbarOmniButton,
  NavbarProfile,
} from './NavbarParts'
import { CategoryTabBar } from '../tabs/CategoryTabBar'
import NotificationsContainer from '../../containers/NotificationsContainer'
import { css, media, modifier, parent, select } from '../../styles/jss'
import * as s from '../../styles/jso'

const navbarStyle = css(
  s.fixed,
  s.fullWidth,
  { height: 80, top: -80, right: 0, left: 0 },
  s.zNavbar,
  s.bgcWhite,
  modifier('isPaginatoring', select('.navbar-content', { transform: 'translate3d(0, 100%, 0)' })),
  select('.isNavbarHidden ~ &:hover .navbar-content',
    {
      transitionDelay: '350ms',
      transform: 'translate3d(0, 100%, 0)',
    }),
  select('&.hide:hover .navbar-content',
    {
      transitionDelay: '350ms',
      transform: 'translate3d(0, 100%, 0)',
    }),
  parent('.isOmnibarActive', s.overflowHidden, s.pointerNone, s.bgcTransparent, s.opacity0),
  select('.isOnboardingView ~ &', s.displayNone),
  media(s.minBreak3,
    select('.no-touch .isNavbarHidden ~ .Discover + &:hover .navbar-content', { transitionDelay: '1.5s' }),
  ),
)

const grabberStyle = css(
  s.relative,
  s.block,
  s.fullWidth,
  s.p0,
  {
    height: 0,
    margin: 0,
    overflow: 'hidden',
  },
  select(
    '&:hover',
    { cursor: 'pointer' },
  ),
  select(
    '.isNavbarHidden ~ .Navbar &',
    { height: 15, marginTop: 0 },
  ),
  select(
    '.Navbar.hide &',
    { height: 15, marginTop: 0 },
    media(s.maxBreak3,
      { display: 'none' },
    ),
  ),
)

const wrapperStyle = css(
  s.relative,
  s.p10,
  s.fullWidth,
  s.bgcWhite,
  { transition: 'transform 350ms ease', transform: 'translate3d(0, calc(100%), 0)' },
  { height: 80, margin: 0 },
  select('.isNavbarHidden ~ .Navbar &', { transform: 'translate3d(0, 0, 0)' }),
  select('.Navbar.hide &', { transform: 'translate3d(0, 0, 0)' }),
  media(s.minBreak3,
    s.p20,
    { borderBottom: '1px solid #f2f2f2' },
  ),
)

const containerStyle = css(
  s.relative,
  s.block,
  s.maxSiteWidth,
  s.fullWidth,
  { margin: '0 auto' },
)

const mainStyle = css(
  s.maxSiteWidth,
  s.mxAuto,
  s.relative,
)

const linksStyle = css(
  s.absolute,
  { top: 0, left: 0 },
  s.nowrap,
  media(s.minBreak3,
    parent('.isLoggedIn', { top: 'calc(50% + 5px)', right: 200, left: 'auto', marginTop: -20 }),
    parent('.isLoggedOut', { top: 'calc(50% + 5px)', right: 175, left: 'auto', marginTop: -20 }),
    parent('.isOmnibarActive .Navbar >', s.absolute, { transform: 'translate3d(400px, 0, 0)' }),
  ),
)

export const NavbarLoggedOut = ({
  categoryTabs,
  areCategoriesSubscribed,
  deviceSize,
  dispatch,
  isLightBoxActive,
  hasLoadMoreButton,
  onClickLoadMorePosts,
  onClickNavbarMark,
  pathname,
}, { onClickArtistInvites, onClickLogin, onClickSignup }) => {
  const isTruncatedHeader = deviceSize === 'mobile' || deviceSize === 'tablet'
  const elloBlogPath = '/elloblog'
  const trackBlogLink = () => {
    dispatch(trackEvent('elloblog-nav-link-clicked'))
  }
  return (
    <nav className={`Navbar ${navbarStyle}`} >
      <div className={`navbar-content ${wrapperStyle}`}>
        <div className={`navbar-container ${containerStyle}`}>
          <div className={`NavbarMain ${mainStyle}`}>
            <NavbarMark onClick={onClickNavbarMark} />
            {hasLoadMoreButton ? <NavbarMorePostsButton onClick={onClickLoadMorePosts} /> : null}
            <div className={`NavbarLinks ${linksStyle}`}>
              {isTruncatedHeader &&
                <NavbarLink
                  className="LabelOnly"
                  label="Editorial"
                  pathname={pathname}
                  to="/"
                />
              }
              <NavbarLink
                className="LabelOnly"
                label="Creative Briefs"
                onClick={onClickArtistInvites}
                pathname={pathname}
                to="/creative-briefs"
              />
              {innerWidth > 700
                  ? <NavbarLink
                    className="LabelOnly"
                    label="Blog"
                    pathname={pathname}
                    to={elloBlogPath}
                    onClick={trackBlogLink}
                  /> : null }
              <NavbarLink
                className="LabelOnly"
                icon={<SparklesIcon />}
                label="Discover"
                pathname={pathname}
                to="/discover"
              />
              <NavbarLink
                className="IconOnly"
                icon={<SearchIcon />}
                label="Search"
                pathname={pathname}
                to="/search"
              />

            <NavbarLink
              className="LabelOnly isLogin"
              label="Login"
              onClick={onClickLogin}
              pathname={pathname}
              to="/enter"
            />
            <NavbarLink
              className="LabelOnly isSignUp"
              label="Sign Up"
              onClick={onClickSignup}
              pathname={pathname}
              to="/join"
            />

        {categoryTabs && !isLightBoxActive &&
          <CategoryTabBar
            pathname={pathname}
            tabs={categoryTabs}
            areCategoriesSubscribed={areCategoriesSubscribed}
            subscribed={false}
            deviceSize={deviceSize}
          />
        }

  )
}

NavbarLoggedOut.propTypes = {
  categoryTabs: PropTypes.array,
  areCategoriesSubscribed: PropTypes.bool,
  deviceSize: PropTypes.string.isRequired,
  dispatch: PropTypes.func.isRequired,
  isLightBoxActive: PropTypes.bool,
  hasLoadMoreButton: PropTypes.bool.isRequired,
  onClickLoadMorePosts: PropTypes.func.isRequired,
  onClickNavbarMark: PropTypes.func.isRequired,
  pathname: PropTypes.string.isRequired,
}
NavbarLoggedOut.defaultProps = {
  categoryTabs: null,
  isLightBoxActive: false,
  areCategoriesSubscribed: false,
}
NavbarLoggedOut.contextTypes = {
  onClickArtistInvites: PropTypes.func.isRequired,
  onClickLogin: PropTypes.func.isRequired,
  onClickSignup: PropTypes.func.isRequired,
}

export const NavbarLoggedIn = ({
  artistInvitesInProfileMenu,
  avatar,
  categoryTabs,
  areCategoriesSubscribed,
  deviceSize,
  dispatch,
  hasLoadMoreButton,
  isBrand,
  isGridMode,
  isLightBoxActive,
  isLayoutToolHidden,
  isNotificationsActive,
  isNotificationsUnread,
  isProfileMenuActive,
  isStaff,
  notificationCategory,
  onClickAvatar,
  onClickLoadMorePosts,
  onClickNavbarMark,
  onClickNotification,
  onClickOmniButton,
  onClickToggleLayoutMode,
  onDragLeaveStreamLink,
  onDragOverOmniButton,
  onDragOverStreamLink,
  onDropStreamLink,
  onLogOut,
  pathname,
  username,
  innerWidth,
}, { onClickArtistInvites }) => {
  const isTruncatedHeader = deviceSize === 'mobile' || deviceSize === 'tablet'
  const elloBlogPath = '/elloblog'
  const trackBlogLink = () => {
    dispatch(trackEvent('elloblog-nav-link-clicked'))
  }
  return (
    <nav className={`Navbar ${navbarStyle}`}>
      <div className={`navbar-content ${wrapperStyle}`}>
        <div className={`navbar-container ${containerStyle}`}>
          <div className={`NavbarMain ${mainStyle}`}>
            <NavbarMark onClick={onClickNavbarMark} />
            {hasLoadMoreButton ? <NavbarMorePostsButton onClick={onClickLoadMorePosts} /> : null}
            <div className={`NavbarLinks ${linksStyle}`}>
              {isTruncatedHeader &&
                <NavbarLink
                  className="LabelOnly"
                  label="Editorial"
                  pathname={pathname}
                  to="/"
                />
              }
              {!artistInvitesInProfileMenu &&
                <NavbarLink
                  className="LabelOnly"
                  label="Creative Briefs"
                  onClick={onClickArtistInvites}
                  pathname={pathname}
                  to="/creative-briefs"
                />
              }
              {innerWidth > 700
                  ? <NavbarLink
                    className="LabelOnly"
                    label="Blog"
                    pathname={pathname}
                    to={elloBlogPath}
                    onClick={trackBlogLink}
                  /> : null }
              <NavbarLink
                className="LabelOnly"
                icon={<SparklesIcon />}
                label="Discover"
                pathname={pathname}
                to="/discover/subscribed"
              />
              <NavbarLink
                className="LabelOnly"
                icon={<CircleIcon />}
                label="Following"
                onDragLeave={onDragLeaveStreamLink}
                onDragOver={onDragOverStreamLink}
                onDrop={onDropStreamLink}
                pathname={pathname}
                to="/following"
              />
              <NavbarLink
                className={classNames('IconOnly', { isNotificationsUnread })}
                icon={<BoltIcon />}
                label="Notifications"
                onClick={isElloAndroid() || isTruncatedHeader ? null : onClickNotification}
                pathname={pathname}
                to={`/notifications${notificationCategory}`}
              />
              <NavbarLink
                className="IconOnly"
                icon={<SearchIcon />}
                label="Search"
                pathname={pathname}
                to="/search"
              />

            <NavbarProfile
              artistInvitesInProfileMenu={artistInvitesInProfileMenu}
              avatar={avatar}
              isBrand={isBrand}
              isProfileMenuActive={isProfileMenuActive}
              isStaff={isStaff}
              onClickAvatar={onClickAvatar}
              onLogOut={onLogOut}
              username={username}
              innerWidth={innerWidth}
            />
            {isTruncatedHeader && !isLayoutToolHidden ?
              <NavbarLayoutTool
                icon={isGridMode ? <ListIcon /> : <GridIcon />}
                onClick={onClickToggleLayoutMode}
              /> : null
            }
            <NavbarOmniButton
              onClick={onClickOmniButton}
              onDragOver={onDragOverOmniButton}
            />
            {!isTruncatedHeader && isNotificationsActive ?
              <NotificationsContainer isModal /> : null
            }

        {categoryTabs && !isLightBoxActive &&
          <CategoryTabBar
            pathname={pathname}
            tabs={categoryTabs}
            areCategoriesSubscribed={areCategoriesSubscribed}
            subscribed
            deviceSize={deviceSize}
          />
        }

      <div className={`grabber ${grabberStyle}`} />

  )
}

NavbarLoggedIn.propTypes = {
  artistInvitesInProfileMenu: PropTypes.bool.isRequired,
  avatar: PropTypes.object,
  categoryTabs: PropTypes.array,
  areCategoriesSubscribed: PropTypes.bool,
  deviceSize: PropTypes.string.isRequired,
  dispatch: PropTypes.func.isRequired,
  hasLoadMoreButton: PropTypes.bool.isRequired,
  isBrand: PropTypes.bool.isRequired,
  isGridMode: PropTypes.bool,
  isLightBoxActive: PropTypes.bool,
  isLayoutToolHidden: PropTypes.bool.isRequired,
  isNotificationsActive: PropTypes.bool.isRequired,
  isNotificationsUnread: PropTypes.bool.isRequired,
  isProfileMenuActive: PropTypes.bool.isRequired,
  isStaff: PropTypes.bool.isRequired,
  notificationCategory: PropTypes.string.isRequired,
  onClickAvatar: PropTypes.func.isRequired,
  onClickLoadMorePosts: PropTypes.func.isRequired,
  onClickNavbarMark: PropTypes.func.isRequired,
  onClickNotification: PropTypes.func.isRequired,
  onClickOmniButton: PropTypes.func.isRequired,
  onClickToggleLayoutMode: PropTypes.func.isRequired,
  onDragLeaveStreamLink: PropTypes.func.isRequired,
  onDragOverOmniButton: PropTypes.func.isRequired,
  onDragOverStreamLink: PropTypes.func.isRequired,
  onDropStreamLink: PropTypes.func.isRequired,
  onLogOut: PropTypes.func.isRequired,
  pathname: PropTypes.string.isRequired,
  username: PropTypes.string,
  innerWidth: PropTypes.number,
}
NavbarLoggedIn.defaultProps = {
  avatar: null,
  categoryTabs: null,
  areCategoriesSubscribed: false,
  isGridMode: false,
  isLightBoxActive: false,
  username: null,
  innerWidth: null,
}
NavbarLoggedIn.contextTypes = {
  onClickArtistInvites: PropTypes.func.isRequired,
}
<commit_msg>Add ElloU link to navigation bar<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { isElloAndroid } from '../../lib/jello'
import { trackEvent } from '../../actions/analytics'
import {
  BoltIcon,
  CircleIcon,
  GridIcon,
  ListIcon,
  MoneyIcon,
  SearchIcon,
  SparklesIcon,
} from '../assets/Icons'
import {
  NavbarLayoutTool,
  NavbarLink,
  NavbarMark,
  NavbarMorePostsButton,
  NavbarOmniButton,
  NavbarProfile,
} from './NavbarParts'
import { CategoryTabBar } from '../tabs/CategoryTabBar'
import NotificationsContainer from '../../containers/NotificationsContainer'
import { css, media, modifier, parent, select } from '../../styles/jss'
import * as s from '../../styles/jso'

const navbarStyle = css(
  s.fixed,
  s.fullWidth,
  { height: 80, top: -80, right: 0, left: 0 },
  s.zNavbar,
  s.bgcWhite,
  modifier('isPaginatoring', select('.navbar-content', { transform: 'translate3d(0, 100%, 0)' })),
  select('.isNavbarHidden ~ &:hover .navbar-content',
    {
      transitionDelay: '350ms',
      transform: 'translate3d(0, 100%, 0)',
    }),
  select('&.hide:hover .navbar-content',
    {
      transitionDelay: '350ms',
      transform: 'translate3d(0, 100%, 0)',
    }),
  parent('.isOmnibarActive', s.overflowHidden, s.pointerNone, s.bgcTransparent, s.opacity0),
  select('.isOnboardingView ~ &', s.displayNone),
  media(s.minBreak3,
    select('.no-touch .isNavbarHidden ~ .Discover + &:hover .navbar-content', { transitionDelay: '1.5s' }),
  ),
)

const grabberStyle = css(
  s.relative,
  s.block,
  s.fullWidth,
  s.p0,
  {
    height: 0,
    margin: 0,
    overflow: 'hidden',
  },
  select(
    '&:hover',
    { cursor: 'pointer' },
  ),
  select(
    '.isNavbarHidden ~ .Navbar &',
    { height: 15, marginTop: 0 },
  ),
  select(
    '.Navbar.hide &',
    { height: 15, marginTop: 0 },
    media(s.maxBreak3,
      { display: 'none' },
    ),
  ),
)

const wrapperStyle = css(
  s.relative,
  s.p10,
  s.fullWidth,
  s.bgcWhite,
  { transition: 'transform 350ms ease', transform: 'translate3d(0, calc(100%), 0)' },
  { height: 80, margin: 0 },
  select('.isNavbarHidden ~ .Navbar &', { transform: 'translate3d(0, 0, 0)' }),
  select('.Navbar.hide &', { transform: 'translate3d(0, 0, 0)' }),
  media(s.minBreak3,
    s.p20,
    { borderBottom: '1px solid #f2f2f2' },
  ),
)

const containerStyle = css(
  s.relative,
  s.block,
  s.maxSiteWidth,
  s.fullWidth,
  { margin: '0 auto' },
)

const mainStyle = css(
  s.maxSiteWidth,
  s.mxAuto,
  s.relative,
)

const linksStyle = css(
  s.absolute,
  { top: 0, left: 0 },
  s.nowrap,
  media(s.minBreak3,
    parent('.isLoggedIn', { top: 'calc(50% + 5px)', right: 200, left: 'auto', marginTop: -20 }),
    parent('.isLoggedOut', { top: 'calc(50% + 5px)', right: 175, left: 'auto', marginTop: -20 }),
    parent('.isOmnibarActive .Navbar >', s.absolute, { transform: 'translate3d(400px, 0, 0)' }),
  ),
)

export const NavbarLoggedOut = ({
  categoryTabs,
  areCategoriesSubscribed,
  deviceSize,
  dispatch,
  isLightBoxActive,
  hasLoadMoreButton,
  onClickLoadMorePosts,
  onClickNavbarMark,
  pathname,
}, { onClickArtistInvites, onClickLogin, onClickSignup }) => {
  const isTruncatedHeader = deviceSize === 'mobile' || deviceSize === 'tablet'
  const elloBlogPath = '/elloblog'
  const trackBlogLink = () => {
    dispatch(trackEvent('elloblog-nav-link-clicked'))
  }
  return (
    <nav className={`Navbar ${navbarStyle}`} >
      <div className={`navbar-content ${wrapperStyle}`}>
        <div className={`navbar-container ${containerStyle}`}>
          <div className={`NavbarMain ${mainStyle}`}>
            <NavbarMark onClick={onClickNavbarMark} />
            {hasLoadMoreButton ? <NavbarMorePostsButton onClick={onClickLoadMorePosts} /> : null}
            <div className={`NavbarLinks ${linksStyle}`}>
              {isTruncatedHeader &&
                <NavbarLink
                  className="LabelOnly"
                  label="Editorial"
                  pathname={pathname}
                  to="/"
                />
              }
              <NavbarLink
                className="LabelOnly"
                label="Creative Briefs"
                onClick={onClickArtistInvites}
                pathname={pathname}
                to="/creative-briefs"
              />
              {innerWidth > 700
                  ? <NavbarLink
                    className="LabelOnly"
                    label="Blog"
                    pathname={pathname}
                    to={elloBlogPath}
                    onClick={trackBlogLink}
                  /> : null }
              <NavbarLink
                className="LabelOnly"
                icon={<SparklesIcon />}
                label="Discover"
                pathname={pathname}
                to="/discover"
              />
              <NavbarLink
                className="LabelOnly"
                icon={<MoneyIcon />}
                label="ElloU"
                to="https://ellou.com/"
                external
              />
              <NavbarLink
                className="IconOnly"
                icon={<SearchIcon />}
                label="Search"
                pathname={pathname}
                to="/search"
              />

            <NavbarLink
              className="LabelOnly isLogin"
              label="Login"
              onClick={onClickLogin}
              pathname={pathname}
              to="/enter"
            />
            <NavbarLink
              className="LabelOnly isSignUp"
              label="Sign Up"
              onClick={onClickSignup}
              pathname={pathname}
              to="/join"
            />

        {categoryTabs && !isLightBoxActive &&
          <CategoryTabBar
            pathname={pathname}
            tabs={categoryTabs}
            areCategoriesSubscribed={areCategoriesSubscribed}
            subscribed={false}
            deviceSize={deviceSize}
          />
        }

  )
}

NavbarLoggedOut.propTypes = {
  categoryTabs: PropTypes.array,
  areCategoriesSubscribed: PropTypes.bool,
  deviceSize: PropTypes.string.isRequired,
  dispatch: PropTypes.func.isRequired,
  isLightBoxActive: PropTypes.bool,
  hasLoadMoreButton: PropTypes.bool.isRequired,
  onClickLoadMorePosts: PropTypes.func.isRequired,
  onClickNavbarMark: PropTypes.func.isRequired,
  pathname: PropTypes.string.isRequired,
}
NavbarLoggedOut.defaultProps = {
  categoryTabs: null,
  isLightBoxActive: false,
  areCategoriesSubscribed: false,
}
NavbarLoggedOut.contextTypes = {
  onClickArtistInvites: PropTypes.func.isRequired,
  onClickLogin: PropTypes.func.isRequired,
  onClickSignup: PropTypes.func.isRequired,
}

export const NavbarLoggedIn = ({
  artistInvitesInProfileMenu,
  avatar,
  categoryTabs,
  areCategoriesSubscribed,
  deviceSize,
  dispatch,
  hasLoadMoreButton,
  isBrand,
  isGridMode,
  isLightBoxActive,
  isLayoutToolHidden,
  isNotificationsActive,
  isNotificationsUnread,
  isProfileMenuActive,
  isStaff,
  notificationCategory,
  onClickAvatar,
  onClickLoadMorePosts,
  onClickNavbarMark,
  onClickNotification,
  onClickOmniButton,
  onClickToggleLayoutMode,
  onDragLeaveStreamLink,
  onDragOverOmniButton,
  onDragOverStreamLink,
  onDropStreamLink,
  onLogOut,
  pathname,
  username,
  innerWidth,
}, { onClickArtistInvites }) => {
  const isTruncatedHeader = deviceSize === 'mobile' || deviceSize === 'tablet'
  const elloBlogPath = '/elloblog'
  const trackBlogLink = () => {
    dispatch(trackEvent('elloblog-nav-link-clicked'))
  }
  return (
    <nav className={`Navbar ${navbarStyle}`}>
      <div className={`navbar-content ${wrapperStyle}`}>
        <div className={`navbar-container ${containerStyle}`}>
          <div className={`NavbarMain ${mainStyle}`}>
            <NavbarMark onClick={onClickNavbarMark} />
            {hasLoadMoreButton ? <NavbarMorePostsButton onClick={onClickLoadMorePosts} /> : null}
            <div className={`NavbarLinks ${linksStyle}`}>
              {isTruncatedHeader &&
                <NavbarLink
                  className="LabelOnly"
                  label="Editorial"
                  pathname={pathname}
                  to="/"
                />
              }
              {!artistInvitesInProfileMenu &&
                <NavbarLink
                  className="LabelOnly"
                  label="Creative Briefs"
                  onClick={onClickArtistInvites}
                  pathname={pathname}
                  to="/creative-briefs"
                />
              }
              {innerWidth > 700
                  ? <NavbarLink
                    className="LabelOnly"
                    label="Blog"
                    pathname={pathname}
                    to={elloBlogPath}
                    onClick={trackBlogLink}
                  /> : null }
              <NavbarLink
                className="LabelOnly"
                icon={<SparklesIcon />}
                label="Discover"
                pathname={pathname}
                to="/discover/subscribed"
              />
              <NavbarLink
                className="LabelOnly"
                icon={<CircleIcon />}
                label="Following"
                onDragLeave={onDragLeaveStreamLink}
                onDragOver={onDragOverStreamLink}
                onDrop={onDropStreamLink}
                pathname={pathname}
                to="/following"
              />
              <NavbarLink
                className={classNames('IconOnly', { isNotificationsUnread })}
                icon={<BoltIcon />}
                label="Notifications"
                onClick={isElloAndroid() || isTruncatedHeader ? null : onClickNotification}
                pathname={pathname}
                to={`/notifications${notificationCategory}`}
              />
              <NavbarLink
                className="IconOnly"
                icon={<SearchIcon />}
                label="Search"
                pathname={pathname}
                to="/search"
              />

            <NavbarProfile
              artistInvitesInProfileMenu={artistInvitesInProfileMenu}
              avatar={avatar}
              isBrand={isBrand}
              isProfileMenuActive={isProfileMenuActive}
              isStaff={isStaff}
              onClickAvatar={onClickAvatar}
              onLogOut={onLogOut}
              username={username}
              innerWidth={innerWidth}
            />
            {isTruncatedHeader && !isLayoutToolHidden ?
              <NavbarLayoutTool
                icon={isGridMode ? <ListIcon /> : <GridIcon />}
                onClick={onClickToggleLayoutMode}
              /> : null
            }
            <NavbarOmniButton
              onClick={onClickOmniButton}
              onDragOver={onDragOverOmniButton}
            />
            {!isTruncatedHeader && isNotificationsActive ?
              <NotificationsContainer isModal /> : null
            }

        {categoryTabs && !isLightBoxActive &&
          <CategoryTabBar
            pathname={pathname}
            tabs={categoryTabs}
            areCategoriesSubscribed={areCategoriesSubscribed}
            subscribed
            deviceSize={deviceSize}
          />
        }

      <div className={`grabber ${grabberStyle}`} />

  )
}

NavbarLoggedIn.propTypes = {
  artistInvitesInProfileMenu: PropTypes.bool.isRequired,
  avatar: PropTypes.object,
  categoryTabs: PropTypes.array,
  areCategoriesSubscribed: PropTypes.bool,
  deviceSize: PropTypes.string.isRequired,
  dispatch: PropTypes.func.isRequired,
  hasLoadMoreButton: PropTypes.bool.isRequired,
  isBrand: PropTypes.bool.isRequired,
  isGridMode: PropTypes.bool,
  isLightBoxActive: PropTypes.bool,
  isLayoutToolHidden: PropTypes.bool.isRequired,
  isNotificationsActive: PropTypes.bool.isRequired,
  isNotificationsUnread: PropTypes.bool.isRequired,
  isProfileMenuActive: PropTypes.bool.isRequired,
  isStaff: PropTypes.bool.isRequired,
  notificationCategory: PropTypes.string.isRequired,
  onClickAvatar: PropTypes.func.isRequired,
  onClickLoadMorePosts: PropTypes.func.isRequired,
  onClickNavbarMark: PropTypes.func.isRequired,
  onClickNotification: PropTypes.func.isRequired,
  onClickOmniButton: PropTypes.func.isRequired,
  onClickToggleLayoutMode: PropTypes.func.isRequired,
  onDragLeaveStreamLink: PropTypes.func.isRequired,
  onDragOverOmniButton: PropTypes.func.isRequired,
  onDragOverStreamLink: PropTypes.func.isRequired,
  onDropStreamLink: PropTypes.func.isRequired,
  onLogOut: PropTypes.func.isRequired,
  pathname: PropTypes.string.isRequired,
  username: PropTypes.string,
  innerWidth: PropTypes.number,
}
NavbarLoggedIn.defaultProps = {
  avatar: null,
  categoryTabs: null,
  areCategoriesSubscribed: false,
  isGridMode: false,
  isLightBoxActive: false,
  username: null,
  innerWidth: null,
}
NavbarLoggedIn.contextTypes = {
  onClickArtistInvites: PropTypes.func.isRequired,
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {autobind} from 'core-decorators';
import cx from 'classnames';
import {CompositeDisposable} from 'atom';

import StagingView from './staging-view';
import GitLogo from './git-logo';
import CommitViewController from '../controllers/commit-view-controller';
import EtchWrapper from './etch-wrapper';
import {isValidWorkdir} from '../helpers';

export default class GitTabView extends React.Component {
  static focus = {
    ...StagingView.focus,
    ...CommitViewController.focus,
  };

  static propTypes = {
    repository: PropTypes.object.isRequired,
    isLoading: PropTypes.bool.isRequired,

    lastCommit: PropTypes.object.isRequired,
    isMerging: PropTypes.bool,
    isRebasing: PropTypes.bool,
    isAmending: PropTypes.bool,
    hasUndoHistory: PropTypes.bool,
    currentBranch: PropTypes.object,
    unstagedChanges: PropTypes.arrayOf(PropTypes.object),
    stagedChanges: PropTypes.arrayOf(PropTypes.object),
    mergeConflicts: PropTypes.arrayOf(PropTypes.object),
    workingDirectoryPath: PropTypes.string,
    mergeMessage: PropTypes.string,
    fetchInProgress: PropTypes.bool,

    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    grammars: PropTypes.object.isRequired,
    resolutionProgress: PropTypes.object.isRequired,
    notificationManager: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    project: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,

    initializeRepo: PropTypes.func.isRequired,
    abortMerge: PropTypes.func.isRequired,
    commit: PropTypes.func.isRequired,
    prepareToCommit: PropTypes.func.isRequired,
    resolveAsOurs: PropTypes.func.isRequired,
    resolveAsTheirs: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    attemptStageAllOperation: PropTypes.func.isRequired,
    attemptFileStageOperation: PropTypes.func.isRequired,
    discardWorkDirChangesForPaths: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.subscriptions = new CompositeDisposable();

    this.refRoot = null;
    this.refStagingView = null;
    this.refCommitViewComponent = null;
  }

  componentDidMount() {
    this.subscriptions.add(
      this.props.commandRegistry.add(this.refRoot, {
        'tool-panel:unfocus': this.blur,
        'core:focus-next': this.advanceFocus,
        'core:focus-previous': this.retreatFocus,
      }),
    );
  }

  render() {
    if (this.props.repository.isTooLarge()) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Too many changes

              The repository at {this.props.workingDirectoryPath} has too many changed files
              to display in Atom. Ensure that you have set up an appropriate .gitignore file.

      );
    } else if (this.props.repository.hasDirectory() &&
               !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Unsupported directory

              Atom does not support managing Git repositories in your home or root directories.

      );
    } else if (this.props.repository.showGitTabInit()) {
      const inProgress = this.props.repository.showGitTabInitInProgress();
      const message = this.props.repository.hasDirectory() ?
        (
          Initialize {this.props.workingDirectoryPath} with a
          Git repository
        ) :
          Initialize a new project directory with a Git repository;

      return (

 { this.refRoot = c; }}>

              <GitLogo />

{message}

            <button onClick={this.initializeRepo} disabled={inProgress} className="btn btn-primary">
              {inProgress ? 'Creating repository...' : 'Create repository'}
            </button>

      );
    } else {
      const isLoading = this.props.fetchInProgress || this.props.repository.showGitTabLoading();

      return (

 { this.refRoot = c; }}>
          <EtchWrapper ref={c => { this.refStagingView = c; }}>
            <StagingView
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              workspace={this.props.workspace}
              stagedChanges={this.props.stagedChanges}
              unstagedChanges={this.props.unstagedChanges}
              mergeConflicts={this.props.mergeConflicts}
              workingDirectoryPath={this.props.workingDirectoryPath}
              resolutionProgress={this.props.resolutionProgress}
              openFiles={this.props.openFiles}
              discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
              attemptFileStageOperation={this.props.attemptFileStageOperation}
              attemptStageAllOperation={this.props.attemptStageAllOperation}
              undoLastDiscard={this.props.undoLastDiscard}
              abortMerge={this.props.abortMerge}
              resolveAsOurs={this.props.resolveAsOurs}
              resolveAsTheirs={this.props.resolveAsTheirs}
              lastCommit={this.props.lastCommit}
              isLoading={this.props.isLoading}
              isAmending={this.props.isAmending}
              hasUndoHistory={this.props.hasUndoHistory}
              isMerging={this.props.isMerging}
            />
          </EtchWrapper>
          <EtchWrapper ref={c => { this.refCommitViewController = c; }}>
            <CommitViewController
              tooltips={this.props.tooltips}
              config={this.props.config}
              stagedChangesExist={this.props.stagedChanges.length > 0}
              mergeConflictsExist={this.props.mergeConflicts.length > 0}
              prepareToCommit={this.props.prepareToCommit}
              commit={this.props.commit}
              abortMerge={this.props.abortMerge}
              branchName={''}
              workspace={this.props.workspace}
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              grammars={this.props.grammars}
              mergeMessage={this.props.mergeMessage}
              isMerging={this.props.isMerging}
              isAmending={this.props.isAmending}
              isLoading={this.props.isLoading}
              lastCommit={this.props.lastCommit}
              repository={this.props.repository}
            />
          </EtchWrapper>

      );
    }
  }

  componentWillUnmount() {
    this.subscriptions.dispose();
  }

  @autobind
  initializeRepo(event) {
    event.preventDefault();
    let initPath = null;
    const activeEditor = this.props.workspace.getActiveTextEditor();
    if (activeEditor) {
      const [projectPath] = this.props.project.relativizePath(activeEditor.getPath());
      if (projectPath) {
        initPath = projectPath;
      }
    }
    this.props.initializeRepo(initPath);
  }

  rememberFocus(event) {
    let currentFocus = null;

    if (this.refs.stagingView) {
      currentFocus = this.refStagingView.rememberFocus(event);
    }

    if (!currentFocus && this.refCommitViewController) {
      currentFocus = this.refCommitViewController.rememberFocus(event);
    }

    return currentFocus;
  }

  setFocus(focus) {
    if (this.refStagingView) {
      if (this.refStagingView.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    if (this.refCommitViewController) {
      if (this.refCommitViewController.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    return false;
  }

  @autobind
  blur() {
    this.props.workspace.getActivePane().activate();
  }

  @autobind
  advanceFocus(evt) {
    if (!this.refStagingView.getWrappedComponent().activateNextList()) {
      if (this.refCommitViewController.getWrappedComponent().setFocus(GitTabView.focus.EDITOR)) {
        evt.stopPropagation();
      }
    } else {
      evt.stopPropagation();
    }
  }

  @autobind
  retreatFocus(evt) {
    const stagingView = this.refStagingView.getWrappedComponent();
    const commitViewController = this.refCommitViewController.getWrappedComponent();

    if (commitViewController.hasFocus()) {
      if (stagingView.activateLastList()) {
        this.setFocus(GitTabView.focus.STAGING);
        evt.stopPropagation();
      }
    } else {
      stagingView.activatePreviousList();
      evt.stopPropagation();
    }
  }

  async focusAndSelectStagingItem(filePath, stagingStatus) {
    await this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
    this.setFocus(GitTabView.focus.STAGING);
  }

  hasFocus() {
    return this.refRoot.contains(document.activeElement);
  }

  @autobind
  quietlySelectItem(filePath, stagingStatus) {
    return this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
  }
}
<commit_msg>Restore missing .getWrappedComponent() calls<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {autobind} from 'core-decorators';
import cx from 'classnames';
import {CompositeDisposable} from 'atom';

import StagingView from './staging-view';
import GitLogo from './git-logo';
import CommitViewController from '../controllers/commit-view-controller';
import EtchWrapper from './etch-wrapper';
import {isValidWorkdir} from '../helpers';

export default class GitTabView extends React.Component {
  static focus = {
    ...StagingView.focus,
    ...CommitViewController.focus,
  };

  static propTypes = {
    repository: PropTypes.object.isRequired,
    isLoading: PropTypes.bool.isRequired,

    lastCommit: PropTypes.object.isRequired,
    isMerging: PropTypes.bool,
    isRebasing: PropTypes.bool,
    isAmending: PropTypes.bool,
    hasUndoHistory: PropTypes.bool,
    currentBranch: PropTypes.object,
    unstagedChanges: PropTypes.arrayOf(PropTypes.object),
    stagedChanges: PropTypes.arrayOf(PropTypes.object),
    mergeConflicts: PropTypes.arrayOf(PropTypes.object),
    workingDirectoryPath: PropTypes.string,
    mergeMessage: PropTypes.string,
    fetchInProgress: PropTypes.bool,

    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    grammars: PropTypes.object.isRequired,
    resolutionProgress: PropTypes.object.isRequired,
    notificationManager: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    project: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,

    initializeRepo: PropTypes.func.isRequired,
    abortMerge: PropTypes.func.isRequired,
    commit: PropTypes.func.isRequired,
    prepareToCommit: PropTypes.func.isRequired,
    resolveAsOurs: PropTypes.func.isRequired,
    resolveAsTheirs: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    attemptStageAllOperation: PropTypes.func.isRequired,
    attemptFileStageOperation: PropTypes.func.isRequired,
    discardWorkDirChangesForPaths: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.subscriptions = new CompositeDisposable();

    this.refRoot = null;
    this.refStagingView = null;
    this.refCommitViewComponent = null;
  }

  componentDidMount() {
    this.subscriptions.add(
      this.props.commandRegistry.add(this.refRoot, {
        'tool-panel:unfocus': this.blur,
        'core:focus-next': this.advanceFocus,
        'core:focus-previous': this.retreatFocus,
      }),
    );
  }

  render() {
    if (this.props.repository.isTooLarge()) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Too many changes

              The repository at {this.props.workingDirectoryPath} has too many changed files
              to display in Atom. Ensure that you have set up an appropriate .gitignore file.

      );
    } else if (this.props.repository.hasDirectory() &&
               !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Unsupported directory

              Atom does not support managing Git repositories in your home or root directories.

      );
    } else if (this.props.repository.showGitTabInit()) {
      const inProgress = this.props.repository.showGitTabInitInProgress();
      const message = this.props.repository.hasDirectory() ?
        (
          Initialize {this.props.workingDirectoryPath} with a
          Git repository
        ) :
          Initialize a new project directory with a Git repository;

      return (

 { this.refRoot = c; }}>

              <GitLogo />

{message}

            <button onClick={this.initializeRepo} disabled={inProgress} className="btn btn-primary">
              {inProgress ? 'Creating repository...' : 'Create repository'}
            </button>

      );
    } else {
      const isLoading = this.props.fetchInProgress || this.props.repository.showGitTabLoading();

      return (

 { this.refRoot = c; }}>
          <EtchWrapper ref={c => { this.refStagingView = c; }}>
            <StagingView
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              workspace={this.props.workspace}
              stagedChanges={this.props.stagedChanges}
              unstagedChanges={this.props.unstagedChanges}
              mergeConflicts={this.props.mergeConflicts}
              workingDirectoryPath={this.props.workingDirectoryPath}
              resolutionProgress={this.props.resolutionProgress}
              openFiles={this.props.openFiles}
              discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
              attemptFileStageOperation={this.props.attemptFileStageOperation}
              attemptStageAllOperation={this.props.attemptStageAllOperation}
              undoLastDiscard={this.props.undoLastDiscard}
              abortMerge={this.props.abortMerge}
              resolveAsOurs={this.props.resolveAsOurs}
              resolveAsTheirs={this.props.resolveAsTheirs}
              lastCommit={this.props.lastCommit}
              isLoading={this.props.isLoading}
              isAmending={this.props.isAmending}
              hasUndoHistory={this.props.hasUndoHistory}
              isMerging={this.props.isMerging}
            />
          </EtchWrapper>
          <EtchWrapper ref={c => { this.refCommitViewController = c; }}>
            <CommitViewController
              tooltips={this.props.tooltips}
              config={this.props.config}
              stagedChangesExist={this.props.stagedChanges.length > 0}
              mergeConflictsExist={this.props.mergeConflicts.length > 0}
              prepareToCommit={this.props.prepareToCommit}
              commit={this.props.commit}
              abortMerge={this.props.abortMerge}
              branchName={''}
              workspace={this.props.workspace}
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              grammars={this.props.grammars}
              mergeMessage={this.props.mergeMessage}
              isMerging={this.props.isMerging}
              isAmending={this.props.isAmending}
              isLoading={this.props.isLoading}
              lastCommit={this.props.lastCommit}
              repository={this.props.repository}
            />
          </EtchWrapper>

      );
    }
  }

  componentWillUnmount() {
    this.subscriptions.dispose();
  }

  @autobind
  initializeRepo(event) {
    event.preventDefault();
    let initPath = null;
    const activeEditor = this.props.workspace.getActiveTextEditor();
    if (activeEditor) {
      const [projectPath] = this.props.project.relativizePath(activeEditor.getPath());
      if (projectPath) {
        initPath = projectPath;
      }
    }
    this.props.initializeRepo(initPath);
  }

  rememberFocus(event) {
    let currentFocus = null;

    if (this.refs.stagingView) {
      currentFocus = this.refStagingView.getWrappedComponent().rememberFocus(event);
    }

    if (!currentFocus && this.refCommitViewController) {
      currentFocus = this.refCommitViewController.getWrappedComponent().rememberFocus(event);
    }

    return currentFocus;
  }

  setFocus(focus) {
    if (this.refStagingView) {
      if (this.refStagingView.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    if (this.refCommitViewController) {
      if (this.refCommitViewController.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    return false;
  }

  @autobind
  blur() {
    this.props.workspace.getActivePane().activate();
  }

  @autobind
  advanceFocus(evt) {
    if (!this.refStagingView.getWrappedComponent().activateNextList()) {
      if (this.refCommitViewController.getWrappedComponent().setFocus(GitTabView.focus.EDITOR)) {
        evt.stopPropagation();
      }
    } else {
      evt.stopPropagation();
    }
  }

  @autobind
  retreatFocus(evt) {
    const stagingView = this.refStagingView.getWrappedComponent();
    const commitViewController = this.refCommitViewController.getWrappedComponent();

    if (commitViewController.hasFocus()) {
      if (stagingView.activateLastList()) {
        this.setFocus(GitTabView.focus.STAGING);
        evt.stopPropagation();
      }
    } else {
      stagingView.activatePreviousList();
      evt.stopPropagation();
    }
  }

  async focusAndSelectStagingItem(filePath, stagingStatus) {
    await this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
    this.setFocus(GitTabView.focus.STAGING);
  }

  hasFocus() {
    return this.refRoot.contains(document.activeElement);
  }

  @autobind
  quietlySelectItem(filePath, stagingStatus) {
    return this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
  }
}
<|endoftext|>


<commit_before>import React from "react";
import { Link } from "react-router";
import Loader from "../../core/Loader";
import DataComponent from "./../base/DataComponent";
import ResourceAction from "./../base/ResourceAction";
import history from "../../history";

class TemplateDetail extends DataComponent {
    getDataUri() {
        return "templates/" + this.props.params.id;
    }

    componentWillReceiveProps(next) {
        let oldId = this.props.params.id;
        let newId = next.params.id;

        if (oldId !== newId) {
            this.fetchData();
        }
    }

    render() {
        let content = null;

        if (this.state.loaded) {
            if (this.state.failed) {
                content = (

Error while loading…

Content couldn't be loaded.

                );
            } else {
                let type;

                if ("answerType" in this.state.data) {
                    type = (

                            Image

                    );
                } else {
                    type = (

                            Text

                    );
                }

                content = (

                            <Link to={this.props.location.pathname + "/edit"} className="action">

                                Edit
                            </Link>

                            <ResourceAction icon="trash" method="DELETE" uri={"templates/" + this.props.params.id}
                                            onClick={() => window.confirm("Do you really want to delete this template?")}
                                            onSuccess={() => history.replaceState(null, "/templates")}
                                            onError={() => window.alert("Deletion failed.")}
                                            backend={this.props.backend}>
                                Delete
                            </ResourceAction>

Template: {this.state.data.name}

                        Content

{this.state.data.content}

                        Answer Type

{type}

                );
            }
        }

        return (
            <Loader loaded={this.state.loaded} className="loader">
                {content}
            </Loader>
        );
    }
}

export default TemplateDetail;<commit_msg>Add 'Use' Button to TemplateDetail<commit_after>import React from "react";
import { Link } from "react-router";
import Loader from "../../core/Loader";
import DataComponent from "./../base/DataComponent";
import ResourceAction from "./../base/ResourceAction";
import history from "../../history";

class TemplateDetail extends DataComponent {
    getDataUri() {
        return "templates/" + this.props.params.id;
    }

    componentWillReceiveProps(next) {
        let oldId = this.props.params.id;
        let newId = next.params.id;

        if (oldId !== newId) {
            this.fetchData();
        }
    }

    render() {
        let content = null;

        if (this.state.loaded) {
            if (this.state.failed) {
                content = (

Error while loading…

Content couldn't be loaded.

                );
            } else {
                let type;

                if ("answerType" in this.state.data) {
                    type = (

                            Image

                    );
                } else {
                    type = (

                            Text

                    );
                }

                content = (

                            <button type="button" className="action" onClick={this._onUseClick.bind(this)}>

                                Use
                            </button>

                            <Link to={this.props.location.pathname + "/edit"} className="action">

                                Edit
                            </Link>

                            <ResourceAction icon="trash" method="DELETE" uri={"templates/" + this.props.params.id}
                                            onClick={() => window.confirm("Do you really want to delete this template?")}
                                            onSuccess={() => history.replaceState(null, "/templates")}
                                            onError={() => window.alert("Deletion failed.")}
                                            backend={this.props.backend}>
                                Delete
                            </ResourceAction>

Template: {this.state.data.name}

                        Content

{this.state.data.content}

                        Answer Type

{type}

                );
            }
        }

        return (
            <Loader loaded={this.state.loaded} className="loader">
                {content}
            </Loader>
        );
    }

    _onUseClick() {
        history.replaceState({
            template: this.state.data
        }, "/experiments/new");
    }
}

export default TemplateDetail;<|endoftext|>


<commit_before>
/* This script is for balancing player actor classes. */

require('babel-register');
const RG = require('../client/src/battles');
const Actors = require('../client/data/actors.js');
const ActorBattles = require('../tests/actor-battles');

const brainMap = {
    Cryomancer: 'SpellCaster',
    Marksman: 'GoalOriented'
};

const createPlayer = function(playerConf) {
    const {actorClass, playerLevel} = playerConf;
    const fact = new RG.Factory.Game();
    const race = 'goblin';
    const conf = {
        playerName: 'hero',
        playerClass: actorClass,
        playerRace: race,
        playerLevel: 'Medium'
    };
    const playerActor = fact.createPlayerUnlessLoaded(conf);
    playerActor.remove('Player');
    RG.levelUpActor(playerActor, playerLevel);

    let brainType = brainMap[actorClass];
    if (!brainType) {brainType = 'GoalOriented';}

    const brain = new RG.Brain[brainType](playerActor);
    playerActor.setBrain(brain);
    return playerActor;
};

const monitorActor = 'hero';
const matchLimit = 2000;
const shells = Actors.filter(a => !((/spirit/i).test(a.name)));

// Classes to be tested
const classes = ['Cryomancer', 'Marksman'];
// const classes = ['Cryomancer'];
const levels = [4, 8, 12, 16, 20, 24, 28, 32];
// const levels = [8, 16, 24, 32];

classes.forEach(className => {
    levels.forEach(playerLevel => {
        const conf = {
            actorClass: className, playerLevel
        };
        const ab = new ActorBattles({monitorActor, matchLimit, shells});
        ab.runWithActor(createPlayer.bind(null, conf), 3);
        // ab.printOutputs(className);
        //
        const tag = `${className}_L${playerLevel}`;
        ab.printMonitored(tag);

        const durationMs = ab.getDuration();
        console.log('Total duration ' + (durationMs / 1000) + ' s');

        console.log('Player stats:');
        const player = createPlayer(conf);
        console.log(JSON.stringify(player, null, 1));
        console.log(`#### FINISHED: ${tag} ####`);
    });
});
<commit_msg>Added more actor classes for testing.<commit_after>
/* This script is for balancing player actor classes. */

require('babel-register');
const RG = require('../client/src/battles');
const Actors = require('../client/data/actors.js');
const ActorBattles = require('../tests/actor-battles');

const brainMap = {
    Cryomancer: 'SpellCaster',
    Marksman: 'GoalOriented'
};

const createPlayer = function(playerConf) {
    const {actorClass, playerLevel} = playerConf;
    const fact = new RG.Factory.Game();
    const race = 'goblin';
    const conf = {
        playerName: 'hero',
        playerClass: actorClass,
        playerRace: race,
        playerLevel: 'Medium'
    };
    const playerActor = fact.createPlayerUnlessLoaded(conf);
    playerActor.remove('Player');
    RG.levelUpActor(playerActor, playerLevel);

    let brainType = brainMap[actorClass];
    if (!brainType) {brainType = 'GoalOriented';}

    const brain = new RG.Brain[brainType](playerActor);
    playerActor.setBrain(brain);
    return playerActor;
};

const monitorActor = 'hero';
const matchLimit = 2000;
const shells = Actors.filter(a => !((/spirit/i).test(a.name)));

// Classes to be tested
const classes = ['Adventurer', 'Blademaster', 'Cryomancer', 'Marksman'];
// const classes = ['Cryomancer'];
const levels = [4, 8, 12, 16, 20, 24, 28, 32];
// const levels = [4];
// const levels = [8, 16, 24, 32];

let summary = '';
classes.forEach(className => {
    levels.forEach(playerLevel => {
        const tag = `${className}_L${playerLevel}`;
        console.log(`#### STARTED: ${tag} {{{`);
        const conf = {
            actorClass: className, playerLevel
        };
        const ab = new ActorBattles({monitorActor, matchLimit, shells});
        ab.runWithActor(createPlayer.bind(null, conf), 3);
        // ab.printOutputs(className);

        ab.printMonitored(tag);

        const durationMs = ab.getDuration();
        console.log('Total duration ' + (durationMs / 1000) + ' s');

        console.log('Player stats:');
        const player = createPlayer(conf);
        console.log(JSON.stringify(player, null, 1));
        console.log(`#### FINISHED: ${tag} }}}`);

        const monitor = ab.monitor;
        const {won, lost, tied} = monitor;
        summary += `${tag},${won.sum},${tied.sum},${lost.sum}\n`;
    });
});

console.log('tag,won,tied,lost');
console.log(summary);
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved.
 */

/**
 * Handlers for commands related to file handling (opening, saving, etc.)
 */
var FileCommandHandlers = (function() {
    // TODO: remove this and use the real exports variable when we switch to modules.
    var exports = {};

    var _editor, _title, _currentFilePath, _currentTitlePath,
        _isDirty = false,
        _savedUndoPosition = 0;

    exports.init = function init(editor, title) {
        _editor = editor;
        _title = title;

        _editor.setOption("onChange", function() {
            updateDirty();
        });

        // Register global commands
        CommandManager.register(Commands.FILE_OPEN, handleFileOpen);
        CommandManager.register(Commands.FILE_SAVE, handleFileSave);
        CommandManager.register(Commands.FILE_CLOSE, handleFileClose);
    };

    function updateDirty() {
        // If we've undone past the undo position at the last save, and there is no redo stack,
        // then we can never get back to a non-dirty state.
        var historySize = _editor.historySize();
        if (historySize.undo < _savedUndoPosition && historySize.redo == 0) {
            _savedUndoPosition = -1;
        }
        var newIsDirty = (_editor.historySize().undo != _savedUndoPosition);
        if (_isDirty != newIsDirty) {
            _isDirty = newIsDirty;
            updateTitle();
        }
    }

    function updateTitle() {
        _title.text(
            _currentTitlePath
                ? (_currentTitlePath + (_isDirty ? " \u2022" : ""))
                : "Untitled"
        );
    }

    function handleFileOpen(fullPath) {
        // TODO: In the future, when we implement multiple open files, we won't close the previous file when opening
        // a new one. However, for now, since we only support a single open document, I'm pretending as if we're
        // closing the existing file first. This is so that I can put the code that checks for an unsaved file and
        // prompts the user to save it in the close command, where it belongs. When we implement multiple open files,
        // we can remove this here.
        var result;
        if (_currentFilePath) {
            result = new $.Deferred();
            CommandManager
                .execute(Commands.FILE_CLOSE)
                .done(function() {
                    doOpenWithOptionalPath(fullPath)
                        .done(function() {
                            result.resolve();
                        })
                        .fail(function() {
                            result.reject();
                        });
                })
                .fail(function() {
                    result.reject();
                });
        }
        else {
            result = doOpenWithOptionalPath(fullPath);
        }
        result.always(function() {
            _editor.focus();
        });
        return result;
    }

    function doOpenWithOptionalPath(fullPath) {
        var result;
        if (!fullPath) {
            // Prompt the user with a dialog
            // TODO: we're relying on this to not be asynchronous--is that safe?
            NativeFileSystem.showOpenDialog(false, false, brackets.strings.OPEN_FILE, ProjectManager.getProjectRoot().fullPath,
                ["htm", "html", "js", "css"], function(files) {
                    if (files.length > 0) {
                        result = doOpen(files[0]);
                        return;
                    }
                });
        }
        else {
            result = doOpen(fullPath);
        }
        if (!result)
            result = (new $.Deferred()).reject();
        return result;
    }

    function doOpen(fullPath) {
        var result = new $.Deferred();
        if (fullPath) {
            var reader = new NativeFileSystem.FileReader();

            // TODO: we should implement something like NativeFileSystem.resolveNativeFileSystemURL() (similar
            // to what's in the standard file API) to get a FileEntry, rather than manually constructing it
            var fileEntry = new NativeFileSystem.FileEntry(fullPath);

            // TODO: it's weird to have to construct a FileEntry just to get a File.
            fileEntry.file(function(file) {
                reader.onload = function(event) {
                    _currentFilePath = _currentTitlePath = fullPath;

                    // In the main toolbar, show the project-relative path (if the file is inside the current project)
                    // or the full absolute path (if it's not in the project).
                    var projectRootPath = ProjectManager.getProjectRoot().fullPath;
                    if (projectRootPath.length > 0 && projectRootPath.charAt(projectRootPath.length - 1) != "/") {
                        projectRootPath += "/";
                    }
                    if (fullPath.indexOf(projectRootPath) == 0) {
                        _currentTitlePath = fullPath.slice(projectRootPath.length);
                        if (_currentTitlePath.charAt(0) == '/') {
                            _currentTitlePath = _currentTitlePath.slice(1);
                        }
                    }

                    // TODO: have a real controller object for the editor
                    _editor.setValue(event.target.result);

                    // Make sure we can't undo back to the previous content.
                    _editor.clearHistory();

                    // This should be 0, but just to be safe...
                    _savedUndoPosition = _editor.historySize().undo;
                    updateDirty();

                    result.resolve();
                };

                reader.onerror = function(event) {
                    showFileOpenError(event.target.error.code, fullPath);
                    result.reject();
                }

                reader.readAsText(file, "utf8");
            },
            function (error) {
                showFileOpenError(event.target.error.code, fullPath);
                result.reject();
            });
        }
        return result;
    }

    function handleFileSave() {
        var result = new $.Deferred();
        if (_currentFilePath && _isDirty) {
            // TODO: we should implement something like NativeFileSystem.resolveNativeFileSystemURL() (similar
            // to what's in the standard file API) to get a FileEntry, rather than manually constructing it
            var fileEntry = new NativeFileSystem.FileEntry(_currentFilePath);

            fileEntry.createWriter(
                function(writer) {
                    writer.onwrite = function() {
                        _savedUndoPosition = _editor.historySize().undo;
                        updateDirty();
                        result.resolve();
                    }
                    writer.onerror = function(event) {
                        showSaveFileError(event.target.error.code, _currentFilePath);
                        result.reject();
                    }
                    writer.write(_editor.getValue());
                },
                function(event) {
                    showSaveFileError(event.target.error.code, _currentFilePath);
                    result.reject();
                }
            );
        }
        else {
            result.resolve();
        }
        result.always(function() {
            _editor.focus();
        });
        return result;
    }

    function handleFileClose() {
        var result = new $.Deferred();
        if (_currentFilePath && _isDirty) {
            brackets.showModalDialog(
                  brackets.DIALOG_ID_SAVE_CLOSE
                , brackets.strings.SAVE_CLOSE_TITLE
                , brackets.strings.format(brackets.strings.SAVE_CLOSE_MESSAGE, _currentTitlePath)
            ).done(function(id) {
                if (id === brackets.DIALOG_BTN_CANCEL) {
                    result.reject();
                }
                else {
                    if (id === brackets.DIALOG_BTN_OK) {
                        CommandManager
                            .execute(Commands.FILE_SAVE)
                            .done(function() {
                                doClose();
                                result.resolve();
                            })
                            .fail(function() {
                                result.reject();
                            });
                    }
                    else {
                        // This is the "Don't Save" case--we can just go ahead and close the file.
                        doClose();
                        result.resolve();
                    }
                }
            });
            result.always(function() {
                _editor.focus();
            });
        }
        else {
            doClose();
            _editor.focus();
            result.resolve();
        }
        return result;
    }

    function doClose() {
        // TODO: When we implement multiple files being open, this will probably change to just
        // dispose of the editor for the current file (and will later change again if we choose to
        // limit the number of open editors).
        _editor.setValue("");
        _editor.clearHistory();
        _currentFilePath = _currentTitlePath = null;
        _savedUndoPosition = 0;
        _isDirty = false;
        updateTitle();
        _editor.focus();
    }

    function showFileOpenError(code, path) {
        brackets.showModalDialog(
              brackets.DIALOG_ID_ERROR
            , brackets.strings.ERROR_OPENING_FILE_TITLE
            , brackets.strings.format(
                    brackets.strings.ERROR_OPENING_FILE
                  , path
                  , getErrorString(code))
        );
    }

    function showSaveFileError(code, path) {
        brackets.showModalDialog(
              brackets.DIALOG_ID_ERROR
            , brackets.strings.ERROR_SAVING_FILE_TITLE
            , brackets.strings.format(
                    brackets.strings.ERROR_SAVING_FILE
                  , path
                  , getErrorString(code))
        );
    }

    function getErrorString(code) {
        // There are a few error codes that we have specific error messages for. The rest are
        // displayed with a generic "(error N)" message.
        var result;

        if (code == FileError.NOT_FOUND_ERR)
            result = brackets.strings.NOT_FOUND_ERR;
        else if (code == FileError.NOT_READABLE_ERR)
            result = brackets.strings.NOT_READABLE_ERR;
        else if (code == FileError.NO_MODIFICATION_ALLOWED_ERR)
            result = brackets.strings.NO_MODIFICATION_ALLOWED_ERR;
        else
            result = brackets.strings.format(brackets.strings.GENERIC_ERROR, code);

        return result;
    }

    return exports;
})();

<commit_msg>Code cleanup.<commit_after>/*
 * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved.
 */

/**
 * Handlers for commands related to file handling (opening, saving, etc.)
 */
var FileCommandHandlers = (function() {
    // TODO: remove this and use the real exports variable when we switch to modules.
    var exports = {};

    var _editor, _title, _currentFilePath, _currentTitlePath,
        _isDirty = false,
        _savedUndoPosition = 0;

    exports.init = function init(editor, title) {
        _editor = editor;
        _title = title;

        _editor.setOption("onChange", function() {
            updateDirty();
        });

        // Register global commands
        CommandManager.register(Commands.FILE_OPEN, handleFileOpen);
        CommandManager.register(Commands.FILE_SAVE, handleFileSave);
        CommandManager.register(Commands.FILE_CLOSE, handleFileClose);
    };

    function updateDirty() {
        // If we've undone past the undo position at the last save, and there is no redo stack,
        // then we can never get back to a non-dirty state.
        var historySize = _editor.historySize();
        if (historySize.undo < _savedUndoPosition && historySize.redo == 0) {
            _savedUndoPosition = -1;
        }
        var newIsDirty = (_editor.historySize().undo != _savedUndoPosition);
        if (_isDirty != newIsDirty) {
            _isDirty = newIsDirty;
            updateTitle();
        }
    }

    function updateTitle() {
        _title.text(
            _currentTitlePath
                ? (_currentTitlePath + (_isDirty ? " \u2022" : ""))
                : "Untitled"
        );
    }

    function handleFileOpen(fullPath) {
        // TODO: In the future, when we implement multiple open files, we won't close the previous file when opening
        // a new one. However, for now, since we only support a single open document, I'm pretending as if we're
        // closing the existing file first. This is so that I can put the code that checks for an unsaved file and
        // prompts the user to save it in the close command, where it belongs. When we implement multiple open files,
        // we can remove this here.
        var result;
        if (_currentFilePath) {
            result = new $.Deferred();
            CommandManager
                .execute(Commands.FILE_CLOSE)
                .done(function() {
                    doOpenWithOptionalPath(fullPath)
                        .done(function() {
                            result.resolve();
                        })
                        .fail(function() {
                            result.reject();
                        });
                })
                .fail(function() {
                    result.reject();
                });
        }
        else {
            result = doOpenWithOptionalPath(fullPath);
        }
        result.always(function() {
            _editor.focus();
        });
        return result;
    }

    function doOpenWithOptionalPath(fullPath) {
        var result;
        if (!fullPath) {
            // Prompt the user with a dialog
            // TODO: we're relying on this to not be asynchronous--is that safe?
            NativeFileSystem.showOpenDialog(false, false, brackets.strings.OPEN_FILE, ProjectManager.getProjectRoot().fullPath,
                ["htm", "html", "js", "css"], function(files) {
                    if (files.length > 0) {
                        result = doOpen(files[0]);
                        return;
                    }
                });
        }
        else {
            result = doOpen(fullPath);
        }
        if (!result)
            result = (new $.Deferred()).reject();
        return result;
    }

    function doOpen(fullPath) {
        var result = new $.Deferred();
        if (!fullPath) {
            console.log("doOpen() called without fullPath");
            result.reject();
            return result;

        }

        var reader = new NativeFileSystem.FileReader();

        // TODO: we should implement something like NativeFileSystem.resolveNativeFileSystemURL() (similar
        // to what's in the standard file API) to get a FileEntry, rather than manually constructing it
        var fileEntry = new NativeFileSystem.FileEntry(fullPath);

        // TODO: it's weird to have to construct a FileEntry just to get a File.
        fileEntry.file(function(file) {
            reader.onload = function(event) {
                _currentFilePath = _currentTitlePath = fullPath;

                // In the main toolbar, show the project-relative path (if the file is inside the current project)
                // or the full absolute path (if it's not in the project).
                var projectRootPath = ProjectManager.getProjectRoot().fullPath;
                if (projectRootPath.length > 0 && projectRootPath.charAt(projectRootPath.length - 1) != "/") {
                    projectRootPath += "/";
                }
                if (fullPath.indexOf(projectRootPath) == 0) {
                    _currentTitlePath = fullPath.slice(projectRootPath.length);
                    if (_currentTitlePath.charAt(0) == '/') {
                        _currentTitlePath = _currentTitlePath.slice(1);
                    }
                }

                // TODO: have a real controller object for the editor
                _editor.setValue(event.target.result);

                // Make sure we can't undo back to the previous content.
                _editor.clearHistory();

                // This should be 0, but just to be safe...
                _savedUndoPosition = _editor.historySize().undo;
                updateDirty();

                result.resolve();
            };

            reader.onerror = function(event) {
                showFileOpenError(event.target.error.code, fullPath);
                result.reject();
            }

            reader.readAsText(file, "utf8");
        },
        function (error) {
            showFileOpenError(event.target.error.code, fullPath);
            result.reject();
        });

        return result;
    }

    function handleFileSave() {
        var result = new $.Deferred();
        if (_currentFilePath && _isDirty) {
            // TODO: we should implement something like NativeFileSystem.resolveNativeFileSystemURL() (similar
            // to what's in the standard file API) to get a FileEntry, rather than manually constructing it
            var fileEntry = new NativeFileSystem.FileEntry(_currentFilePath);

            fileEntry.createWriter(
                function(writer) {
                    writer.onwrite = function() {
                        _savedUndoPosition = _editor.historySize().undo;
                        updateDirty();
                        result.resolve();
                    }
                    writer.onerror = function(event) {
                        showSaveFileError(event.target.error.code, _currentFilePath);
                        result.reject();
                    }
                    writer.write(_editor.getValue());
                },
                function(event) {
                    showSaveFileError(event.target.error.code, _currentFilePath);
                    result.reject();
                }
            );
        }
        else {
            result.resolve();
        }
        result.always(function() {
            _editor.focus();
        });
        return result;
    }

    function handleFileClose() {
        var result = new $.Deferred();
        if (_currentFilePath && _isDirty) {
            brackets.showModalDialog(
                  brackets.DIALOG_ID_SAVE_CLOSE
                , brackets.strings.SAVE_CLOSE_TITLE
                , brackets.strings.format(brackets.strings.SAVE_CLOSE_MESSAGE, _currentTitlePath)
            ).done(function(id) {
                if (id === brackets.DIALOG_BTN_CANCEL) {
                    result.reject();
                }
                else {
                    if (id === brackets.DIALOG_BTN_OK) {
                        CommandManager
                            .execute(Commands.FILE_SAVE)
                            .done(function() {
                                doClose();
                                result.resolve();
                            })
                            .fail(function() {
                                result.reject();
                            });
                    }
                    else {
                        // This is the "Don't Save" case--we can just go ahead and close the file.
                        doClose();
                        result.resolve();
                    }
                }
            });
            result.always(function() {
                _editor.focus();
            });
        }
        else {
            doClose();
            _editor.focus();
            result.resolve();
        }
        return result;
    }

    function doClose() {
        // TODO: When we implement multiple files being open, this will probably change to just
        // dispose of the editor for the current file (and will later change again if we choose to
        // limit the number of open editors).
        _editor.setValue("");
        _editor.clearHistory();
        _currentFilePath = _currentTitlePath = null;
        _savedUndoPosition = 0;
        _isDirty = false;
        updateTitle();
        _editor.focus();
    }

    function showFileOpenError(code, path) {
        brackets.showModalDialog(
              brackets.DIALOG_ID_ERROR
            , brackets.strings.ERROR_OPENING_FILE_TITLE
            , brackets.strings.format(
                    brackets.strings.ERROR_OPENING_FILE
                  , path
                  , getErrorString(code))
        );
    }

    function showSaveFileError(code, path) {
        brackets.showModalDialog(
              brackets.DIALOG_ID_ERROR
            , brackets.strings.ERROR_SAVING_FILE_TITLE
            , brackets.strings.format(
                    brackets.strings.ERROR_SAVING_FILE
                  , path
                  , getErrorString(code))
        );
    }

    function getErrorString(code) {
        // There are a few error codes that we have specific error messages for. The rest are
        // displayed with a generic "(error N)" message.
        var result;

        if (code == FileError.NOT_FOUND_ERR)
            result = brackets.strings.NOT_FOUND_ERR;
        else if (code == FileError.NOT_READABLE_ERR)
            result = brackets.strings.NOT_READABLE_ERR;
        else if (code == FileError.NO_MODIFICATION_ALLOWED_ERR)
            result = brackets.strings.NO_MODIFICATION_ALLOWED_ERR;
        else
            result = brackets.strings.format(brackets.strings.GENERIC_ERROR, code);

        return result;
    }

    return exports;
})();

<|endoftext|>


<commit_before><commit_msg>Get rid of unnecessary methods<commit_after><|endoftext|>


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

var camOptions = {
  verbose: false,
  device : '/dev/video0',
  resolution : '590x440',
  png : '1',
  greyscale : false,
  controls : {
    focus : 'auto',
    brightness : 130,
    contrast : 50,
    saturation : 50,
    hue : 100,
    gamma : 130,
    sharpness : 50
  }
};
var camelot = new Camelot(camOptions);
var imageDir = path.resolve('images/');
var latestFile = '0';

exports.getFile = function(error,fileBuffer){
	fs.readDir(imageDir,function(err,files){
		if(err)
			error(err);
		filename(path.basename(files[files.length-1]));
		fs.readFile(filename,function(err,data){
			if (err)
				error(err);
			fileBuffer(data);
		})
	});
}

function getLastFile(error,filename){
	fs.readdir(imageDir,function(err,files){
		if(err)
			error(err);
		filename(path.basename(files[files.length-1]));
	});
}

function getImage(errCb,imageCb){
	camelot.grab({},function(image){
		imageCb(image);
	});
	camelot.on('error',function(error){
		errCb(error);
	});
};

exports.saveImage = function(error,success){
	getImage(function(imgErr){
		if (imgErr)
			error(imgErr);
	},function(image){
		getLastFile(function(err){
			if(err)
				error(err);
		},function(latest){
			latest++;
			filename = latest + '.png';
			fd.writeFile(filename,image,function(err){
				if(err)
					error(err);
				success(filename);
			});
		});
	});
};<commit_msg>omg what have I done?<commit_after>var Camelot = require('camelot');
var fs = require('fs');
var path = require('path');

var camOptions = {
  verbose: false,
  device : '/dev/video0',
  resolution : '590x440',
  png : '1',
  greyscale : false,
  controls : {
    focus : 'auto',
    brightness : 130,
    contrast : 50,
    saturation : 50,
    hue : 100,
    gamma : 130,
    sharpness : 50
  }
};
var camelot = new Camelot(camOptions);
var imageDir = path.resolve('images/');
var latestFile = '0';

exports.getFile = function(error,fileBuffer){
	fs.readDir(imageDir,function(err,files){
		if(err)
			error(err);
		filename(path.basename(files[files.length-1]));
		fs.readFile(filename,function(err,data){
			if (err)
				error(err);
			fileBuffer(data);
		})
	});
}

function getLastFile(error,filename){
	fs.readdir(imageDir,function(err,files){
		if(err)
			error(err);
		if(!files)
			filename('0');
		filename(path.basename(files[files.length-1]));
	});
}

function getImage(errCb,imageCb){
	camelot.grab({},function(image){
		imageCb(image);
	});
	camelot.on('error',function(error){
		errCb(error);
	});
};

exports.saveImage = function(error,success){
	getImage(function(imgErr){
		if (imgErr)
			error(imgErr);
	},function(image){
		getLastFile(function(err){
			if(err)
				error(err);
		},function(latest){
			latest++;
			filename = latest + '.png';
			fd.writeFile(filename,image,function(err){
				if(err)
					error(err);
				success(filename);
			});
		});
	});
};<|endoftext|>