<commit_before> 'use strict';

 import {
     q
 }
 from '../controllers/queue.server.controller';
 import * as GameRoomManager from '../controllers/game_room_manager.server.controller';

 var setSocket = false;

 // Create the game socket.io configuration
 export default function(io, socket) {

     if (!setSocket) {
         setSocket = true;
         q.setIO(io);
     }

     console.log(socket.request.user.username, 'connected');
     GameRoomManager.ConnectedPlayers.set(socket.request.user.username, {
         in_queue: false,
         in_game: false,
         in_lobby: false,
         socket_id: socket.id
     });

     socket.on('join public game', function() {
         var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);

         if (ConnectedPlayer.in_queue) {
            socket.emit('already in queue');
         } else if (ConnectedPlayer.in_game) {
            socket.emit('already in game');
         } else {
             q.addPlayer(socket);

             ConnectedPlayer.in_queue = true;
             GameRoomManager.ConnectedPlayers.set(socket.request.user.username, ConnectedPlayer);
         }
     });

     socket.on('join private lobby', function(msg) {
	console.log('join private jobby');
	console.log(msg);
	//ADDING THE PLAYER ISNT WORKING I DONT KNOW WHY
	GameRoomManager.getGameRoom(msg[0]).addPlayer(msg[1]);
	console.log('added player');
	console.log(GameRoomManager.getGameRoom(msg[0]).players);
	io.to(msg[1]).emit('joined private lobby');

     });

     socket.on('create private game', function() {
         var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);
	 console.log('creating private game');
         if (ConnectedPlayer.in_queue) {
            socket.emit('already in queue');
	    //remove from queue?
         } else if (ConnectedPlayer.in_game) {
            socket.emit('already in game');
	    //remove from game?
         } else {
	     GameRoomManager.createGameRoom([socket], false);
	     ConnectedPlayer.in_game = true;
         }
     });

     socket.on('get all avaliable players', function(){
	 var avaliablePlayers = {};
	 GameRoomManager.ConnectedPlayers.forEach(function(val, key){if( !val.in_game && !val.in_queue){avaliablePlayers[key]=val;}});
	 console.log(avaliablePlayers);
	 socket.emit('avaliable players responding', avaliablePlayers);
     });

     socket.on('invite player', function(msg){
	 console.log(socket.game_room_id);
	 io.to(msg).emit('invite notification', [socket.game_room_id, socket.request.user.username, msg]);
     });

     socket.on('get game info', function() {
	 console.log(socket.game_room_id);
         var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
	 console.log('1');
	 console.log(GameRoom);
	 console.log('2');
         socket.emit('game info responding', {
             _id: GameRoom._id,
             players: GameRoom.getPlayerUserNames(),
             waiting_players: GameRoom.getWaitingPlayerUserNames(),
             state: GameRoom.getStateName(),
             judge: GameRoom.getJudgeUserName(),
             phrases: GameRoom.getPhrases()
         });

         for (let username of GameRoom.getPlayerUserNames()) {
             var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);
             ConnectedPlayer.in_queue = false;
             ConnectedPlayer.in_game = true;
             GameRoomManager.ConnectedPlayers.set(socket.request.user.username, ConnectedPlayer);
         }
     });

     socket.on('get lobby info', function(){
	  console.log('hellolobby');
	//THIS IS FAILING, HE ISNT PUT INTO THE GAME ROOM????
          var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
	  console.log(GameRoom);
          socket.emit('lobby info responding', {
	       _id: GameRoom._id,
	       players: GameRoom.getPlayerUserNames(),
	       state: GameRoom.getStateName()
          });
     });

     socket.on('set phrase', function(msg) {
         var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
         GameRoom.setPhrase(msg);
     });

     socket.on('set winner', function(msg) {
         var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
         GameRoom.setWinner(msg);
         GameRoom.setState('Ending');
     });

     socket.on('leave room', function() {
         if (socket.game_room_id) {
             var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
             GameRoom.removePlayer(socket);

             var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);
             ConnectedPlayer.in_game = false;
             GameRoomManager.ConnectedPlayers.set(socket.request.user.username, ConnectedPlayer);
         }
     });

     socket.on('admin updates subscribe', function() {
         socket.join('admin_updates');
         socket.emit('initial queue info', q.getInfo());
         socket.emit('initial rooms info', GameRoomManager.getInfo());
     });

     socket.on('disconnect', function() {
         if (socket.request.user.username) {
             console.log(socket.request.user.username, 'has disconnected');
             if (socket.game_room_id) {
                 var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
                 GameRoom.removePlayer(socket);
             }

             GameRoomManager.ConnectedPlayers.delete(socket.request.user.username);
         }
     });
 }
<commit_msg>hello<commit_after> 'use strict';

 import {
     q
 }
 from '../controllers/queue.server.controller';
 import * as GameRoomManager from '../controllers/game_room_manager.server.controller';

 var setSocket = false;

 // Create the game socket.io configuration
 export default function(io, socket) {

     if (!setSocket) {
         setSocket = true;
         q.setIO(io);
     }

     console.log(socket.request.user.username, 'connected');
     GameRoomManager.ConnectedPlayers.set(socket.request.user.username, {
         in_queue: false,
         in_game: false,
         in_lobby: false,
         socket_id: socket.id
     });

     socket.on('join public game', function() {
         var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);

         if (ConnectedPlayer.in_queue) {
            socket.emit('already in queue');
         } else if (ConnectedPlayer.in_game) {
            socket.emit('already in game');
         } else {
             q.addPlayer(socket);

             ConnectedPlayer.in_queue = true;
             GameRoomManager.ConnectedPlayers.set(socket.request.user.username, ConnectedPlayer);
         }
     });

    socket.on('join private lobby', function(msg) {
	   console.log('join private jobby');
	   console.log(msg);
	   //ADDING THE PLAYER ISNT WORKING I DONT KNOW WHY
	   GameRoomManager.getGameRoom(msg[0]).addPlayer(socket);
	   console.log('added player');
	   console.log(GameRoomManager.getGameRoom(msg[0]).players);
	   io.to(msg[1]).emit('joined private lobby');
	});

     socket.on('create private game', function() {
         var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);
	 console.log('creating private game');
         if (ConnectedPlayer.in_queue) {
            socket.emit('already in queue');
	    //remove from queue?
         } else if (ConnectedPlayer.in_game) {
            socket.emit('already in game');
	    //remove from game?
         } else {
	     GameRoomManager.createGameRoom([socket], false);
	     ConnectedPlayer.in_game = true;
         }
     });

     socket.on('get all avaliable players', function(){
	 var avaliablePlayers = {};
	 GameRoomManager.ConnectedPlayers.forEach(function(val, key){if( !val.in_game && !val.in_queue){avaliablePlayers[key]=val;}});
	 console.log(avaliablePlayers);
	 socket.emit('avaliable players responding', avaliablePlayers);
     });

     socket.on('invite player', function(msg){
	 console.log(socket.game_room_id);
     var invite_socket_id = msg;
	 io.to(msg).emit('invite notification', [socket.game_room_id, socket.request.user.username, invite_socket_id]);
     });

     socket.on('get game info', function() {
	 console.log(socket.game_room_id);
         var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
	 console.log('1');
	 console.log(GameRoom);
	 console.log('2');
         socket.emit('game info responding', {
             _id: GameRoom._id,
             players: GameRoom.getPlayerUserNames(),
             waiting_players: GameRoom.getWaitingPlayerUserNames(),
             state: GameRoom.getStateName(),
             judge: GameRoom.getJudgeUserName(),
             phrases: GameRoom.getPhrases()
         });

         for (let username of GameRoom.getPlayerUserNames()) {
             var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);
             ConnectedPlayer.in_queue = false;
             ConnectedPlayer.in_game = true;
             GameRoomManager.ConnectedPlayers.set(socket.request.user.username, ConnectedPlayer);
         }
     });

     socket.on('get lobby info', function(){
	  console.log('hellolobby');
	//THIS IS FAILING, HE ISNT PUT INTO THE GAME ROOM????
          var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
	  console.log(GameRoom);
          socket.emit('lobby info responding', {
	       _id: GameRoom._id,
	       players: GameRoom.getPlayerUserNames(),
	       state: GameRoom.getStateName()
          });
     });

     socket.on('set phrase', function(msg) {
         var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
         GameRoom.setPhrase(msg);
     });

     socket.on('set winner', function(msg) {
         var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
         GameRoom.setWinner(msg);
         GameRoom.setState('Ending');
     });

     socket.on('leave room', function() {
         if (socket.game_room_id) {
             var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
             GameRoom.removePlayer(socket);

             var ConnectedPlayer = GameRoomManager.ConnectedPlayers.get(socket.request.user.username);
             ConnectedPlayer.in_game = false;
             GameRoomManager.ConnectedPlayers.set(socket.request.user.username, ConnectedPlayer);
         }
     });

     socket.on('admin updates subscribe', function() {
         socket.join('admin_updates');
         socket.emit('initial queue info', q.getInfo());
         socket.emit('initial rooms info', GameRoomManager.getInfo());
     });

     socket.on('disconnect', function() {
         if (socket.request.user.username) {
             console.log(socket.request.user.username, 'has disconnected');
             if (socket.game_room_id) {
                 var GameRoom = GameRoomManager.getGameRoom(socket.game_room_id);
                 GameRoom.removePlayer(socket);
             }

             GameRoomManager.ConnectedPlayers.delete(socket.request.user.username);
         }
     });
 }
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { PropTypes } from 'react'
import Immutable, { List } from 'immutable'

import { connect } from 'react-redux'
// REDUX: actions/dispatch/func
import { pushWindowPath, replaceWindowPath, updateWindowPath } from 'providers/redux/reducers/windowPath'
import { changeTheme, setRouteParams } from 'providers/redux/reducers/navigation'

import selectn from 'selectn'

import classNames from 'classnames'

import ConfGlobal from 'conf/local.js'
import ConfRoutes, { matchPath } from 'conf/routes'
import { WORKSPACES } from 'common/Constants'

import ProviderHelpers from 'common/ProviderHelpers'
import { getSearchObject } from 'common/NavigationHelpers'
import { Redirector } from './Redirector'
// import UIHelpers from 'common/UIHelpers'
import StringHelpers from 'common/StringHelpers'
// import AnalyticsHelpers from 'common/AnalyticsHelpers'

import FlatButton from 'material-ui/lib/flat-button'
import Navigation from 'views/components/Navigation'
import WorkspaceSwitcher from 'views/components/Navigation/WorkspaceSwitcher'
import KidsNavigation from 'views/components/Kids/navigation'
import Footer from 'views/components/Navigation/Footer'
import Breadcrumb from 'views/components/Breadcrumb'

import IntlService from 'views/services/intl'

import { PageError } from 'views/pages'

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

const { any, array, func, object, string } = PropTypes

const intl = IntlService.instance

const PAGE_NOT_FOUND_TITLE =
  '404 - ' +
  intl.translate({
    key: 'errors.page_not_found',
    default: 'Page Not Found',
    case: 'first',
  })

const PAGE_NOT_FOUND_BODY = (

      {intl.translate({
        key: 'errors.report_via_feedback',
        default: 'Please report this error so that we can fix it',
        case: 'first',
      })}
      .

      {intl.translate({
        key: 'errors.feedback_include_link',
        default: 'Include what link or action you took to get to this page',
      })}
      .

      {intl.translate({
        key: 'thank_you!',
        default: 'Thank You!',
        case: 'words',
      })}

)

export class AppFrontController extends Component {
  static propTypes = {
    warnings: object.isRequired,

    // loadGuide: func.isRequired,
    // loadNavigation: func.isRequired

    // REDUX: reducers/state
    computeDialect2: object.isRequired,
    computeLogin: object.isRequired,
    properties: object.isRequired,
    routeParams: object.isRequired,
    search: object.isRequired,
    matchedPage: any,
    splitWindowPath: array.isRequired,
    windowPath: string.isRequired,
    // REDUX: actions/dispatch/func
    updateWindowPath: func.isRequired,
    setRouteParams: func.isRequired,
    changeTheme: func.isRequired,
    pushWindowPath: func.isRequired,
    replaceWindowPath: func.isRequired,
  }

  static defaultProps = {
    matchedPage: undefined,
  }

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

    this.state = this._getInitialState()
  }

  componentDidMount() {
    // NOTE: added to respond to `window.history.back()` calls
    window.addEventListener('popstate', this._handleHistoryEvent)
    // NOTE: this used to be called in `componentWillMount`
    this._route(this.props)
  }

  componentDidUpdate(prevProps) {
    this._updateTitle()

    if (prevProps.windowPath !== this.props.windowPath) {
      // Track page view
      if (window.snowplow) {
        window.snowplow('trackPageView')
      }
    }

    // Re-route when:
    // - window path changes
    // - logged in
    const pathChanged = prevProps.windowPath !== this.props.windowPath
    // const loggedIn = prevProps.computeLogin != this.props.computeLogin
    const prevCl = prevProps.computeLogin
    const curCl = this.props.computeLogin
    const loggedIn = prevCl.isFetching !== curCl.isFetching || prevCl.success !== curCl.success

    const { sortOrder: newSortOrder, sortBy: newSortBy } = this.props.search
    const { sortOrder: prevSortOrder, sortBy: prevSortBy } = prevProps.search
    const windowLocationSearch = getSearchObject()
    const windowLocationSearchSortOrder = windowLocationSearch.sortOrder
    const windowLocationSearchSortBy = windowLocationSearch.sortBy

    const sortOrderChanged = newSortOrder !== prevSortOrder || windowLocationSearchSortOrder != newSortOrder
    const sortByChanged = newSortBy !== prevSortBy || windowLocationSearchSortBy != newSortBy

    if (pathChanged || loggedIn || sortOrderChanged || sortByChanged) {
      this._route(this.props)
    }
  }

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

    // NOTE: Due to the switch from `componentWillMount` to `componentDidMount`
    // `render` runs before we are ready, hence the empty div being returned
    if (matchedPage === undefined) {
      return

    }

    const isFrontPage = !matchedPage ? false : matchedPage.get('frontpage')
    const hideNavigation = matchedPage && matchedPage.has('navigation') && matchedPage.get('navigation') === false

    let page

    let navigation = <Navigation frontpage={isFrontPage} routeParams={routeParams} />
    const theme = routeParams.hasOwnProperty('theme') ? routeParams.theme : 'default'
    // prettier-ignore
    const print = matchedPage
      ? matchedPage
        .get('page')
        .get('props')
        .get('print') === true
      : false

    let footer =

    const clonedElement = React.cloneElement(matchedPage.get('page').toJS(), { routeParams: routeParams })

    // For print view return page only
    if (print) {
      return
{clonedElement}

    }

    // Remove breadcrumbs for Kids portal
    // TODO: Make more generic if additional themes are added in the future.
    if (theme === 'kids') {
      page = clonedElement
      navigation = <KidsNavigation frontpage={isFrontPage} routeParams={routeParams} />
    } else {
      // Without breadcrumbs
      if (matchedPage.get('breadcrumbs') === false) {
        page = clonedElement
      } else {
        // With breadcrumbs
        page = this._renderWithBreadcrumb(clonedElement, matchedPage, this.props, theme)
      }
    }

    // Hide navigation
    if (hideNavigation) {
      navigation = footer = ''
    }

    return (

        {(matchedPage && matchedPage.hasOwnProperty('warnings') ? matchedPage.get('warnings') : []).map((warning) => {
          if (this.props.warnings.hasOwnProperty(warning) && !this.state.warningsDismissed) {
            return (

                {selectn(warning, this.props.warnings)}
                <FlatButton
                  label={intl.translate({
                    key: 'dismiss',
                    default: 'Dismiss',
                    case: 'words',
                  })}
                  onClick={() => this.setState({ warningsDismissed: true })}
                />

            )
          }
        })}

            {navigation}

            {page}

            {footer}

    )
  }

  _getInitialState() {
    let routes = Immutable.fromJS(ConfRoutes)
    const contextPath = ConfGlobal.contextPath.split('/').filter((v) => v !== '')

    // Add context path to PATH and ALIAS properties if it is set (usually applies in DEV environment)
    if (contextPath && contextPath.length > 0) {
      routes = routes.map((route) => {
        let newRoute = route.set('path', List(contextPath).concat(route.get('path')))
        newRoute = newRoute.set('alias', List(contextPath).concat(route.get('alias')))
        return newRoute
      })
    }

    return {
      routes,
      warningsDismissed: false,
    }
  }

  _handleHistoryEvent = (postStateEvent) => {
    const { state: postStateEventState } = postStateEvent
    if (postStateEventState) {
      const { windowPath } = postStateEventState
      // NOTE: windowPath === postStateEvent.state.windowPath
      this.props.updateWindowPath(windowPath)
    } else {
      this.props.updateWindowPath(window.location.pathname)
    }
  }

  _renderWithBreadcrumb = (reactElement, matchedPage, props, theme) => {
    const themePalette = props.properties.theme.palette.rawTheme.palette
    const { routeParams } = reactElement.props
    const { /*splitWindowPath, */ computeLogin } = props
    const { routes } = this.state
    let _workspaceSwitcher = null
    const area = selectn('routeParams.area', reactElement.props)
    if (
      area &&
      selectn('isConnected', computeLogin) &&
      matchedPage.get('disableWorkspaceSectionNav') !== true &&
      !ProviderHelpers.isSiteMember(selectn('response.properties.groups', computeLogin))
    ) {
      _workspaceSwitcher = <WorkspaceSwitcher className="AppFrontController__workspaceSwitcher" area={area} />
    }
    const overrideBreadcrumbs = selectn('props.properties.breadcrumbs', this)
    const findReplace = overrideBreadcrumbs
      ? { find: overrideBreadcrumbs.find, replace: selectn(overrideBreadcrumbs.replace, this.props.properties) }
      : undefined
    return (

            <Breadcrumb
              className="AppFrontController__breadcrumb"
              matchedPage={matchedPage}
              routes={routes}
              routeParams={routeParams}
              // splitWindowPath={splitWindowPath}
              findReplace={findReplace}
            />
            {_workspaceSwitcher}

{reactElement}

    )
  }

  /**
   * Conditionally route the parameters.
   * This could normally go into the render method to keep things simple,
   * however redirecting (i.e. updating state), cannot be done inside render.
   */
  _route = (props, routesOverride = null) => {
    let matchedPage = null
    let _routeParams = {}
    const pathArray = props.splitWindowPath

    const routes = routesOverride || this.state.routes
    routes.forEach((value) => {
      const matchTest = matchPath(value.get('path'), pathArray)
      const matchAlias = matchPath(value.get('alias'), pathArray)

      if (matchTest.matched || matchAlias.matched) {
        const routeParams = matchTest.routeParams

        // Extract common paths from URL
        if (value.has('extractPaths') && value.get('extractPaths')) {
          const domainPathLocation = pathArray.indexOf(ConfGlobal.domain)
          const dialectPathLocation = 5
          const languagePathLocation = 4
          const languageFamilyPathLocation = 3

          // If domain is specified in the URL, these are Nuxeo paths that can be extracted
          if (domainPathLocation !== -1) {
            // Path from domain to end of path (e.g. /FV/Workspaces/Data/family/language/dialect)
            const nuxeoPath = pathArray.slice(domainPathLocation, pathArray.length)

            if (nuxeoPath.length >= dialectPathLocation) {
              routeParams.dialect_name = decodeURI(nuxeoPath[dialectPathLocation])
              routeParams.dialect_path = decodeURI('/' + nuxeoPath.slice(0, dialectPathLocation + 1).join('/'))
            }

            if (nuxeoPath.length >= languagePathLocation) {
              routeParams.language_name = decodeURI(nuxeoPath[languagePathLocation])
              routeParams.language_path = decodeURI('/' + nuxeoPath.slice(0, languagePathLocation + 1).join('/'))
            }

            if (nuxeoPath.length >= languageFamilyPathLocation) {
              routeParams.language_family_name = decodeURI(nuxeoPath[languageFamilyPathLocation])
              routeParams.language_family_path = decodeURI(
                '/' + nuxeoPath.slice(0, languageFamilyPathLocation + 1).join('/')
              )
            }
          }
        }

        matchedPage = value
        _routeParams = routeParams

        // Break out of forEach
        return false
      }
    })

    // Match found
    if (matchedPage !== null) {
      // Redirect if required
      if (matchedPage.has('redirects')) {
        matchedPage.get('redirects').forEach((value) => {
          if (value.get('condition')({ props: props })) {
            // Avoid invariant violations during rendering by setting temporary placeholder component as matched page, and 'redirecting' after mount.
            matchedPage = matchedPage.set(
              'page',
              Immutable.fromJS(
                React.createElement(
                  Redirector,
                  {
                    redirect: () => {
                      return props.replaceWindowPath(value.get('target')({ props: props }))
                    },
                  },
                  matchedPage.get('page')
                )
              )
            )

            return false
          }
        })
      }

      // Switch themes based on route params
      if (_routeParams.hasOwnProperty('theme')) {
        let newTheme = _routeParams.theme

        // Switch to workspace theme if available
        if (
          ((_routeParams.hasOwnProperty('area') && _routeParams.area === WORKSPACES) ||
            matchedPage.get('path').indexOf(WORKSPACES) !== -1) &&
          _routeParams.theme === 'explore'
        ) {
          newTheme = 'workspace'
          // Note: Also updating routeParams.area
          _routeParams.area = WORKSPACES
        }

        if (props.properties.theme.id !== newTheme) {
          props.changeTheme(newTheme)
        }
      } else {
        // NOTE: Initial theme state is now set in a redux reducer located at:
        //   app/assets/javascripts/providers/redux/reducers/navigation/reducer.js
        // props.changeTheme('default')
      }
      const matchReturn = {
        matchedPage,
        matchedRouteParams: _routeParams,
      }
      // Load help
      //props.loadGuide(props.windowPath, matchReturn);

      // Load Navigation
      //props.loadNavigation();

      // this.setState(matchReturn)
      this.props.setRouteParams({
        ...matchReturn,
        search: getSearchObject(),
      })
      return
    }
    // No match found (i.e. 404)
    const notFoundPage = Immutable.fromJS({
      title: PAGE_NOT_FOUND_TITLE,
      page: <PageError title={PAGE_NOT_FOUND_TITLE} body={PAGE_NOT_FOUND_BODY} />,
    })

    const matchReturn = {
      matchedPage: notFoundPage,
      matchedRouteParams: _routeParams,
    }

    // this.setState(matchReturn)
    this.props.setRouteParams({
      ...matchReturn,
      search: getSearchObject(),
    })
  }

  /**
   * Dynamically update title
   */
  _updateTitle = () => {
    // Title provided from within a component
    const pageTitleParams = this.props.properties.pageTitleParams

    let title = this.props.properties.title

    if (
      this.props.matchedPage &&
      this.props.matchedPage.has('title') &&
      this.props.matchedPage.get('title') &&
      this.props.matchedPage.get('title') !== document.title
    ) {
      const combinedRouteParams = Object.assign({}, this.props.routeParams, pageTitleParams)

      title = this.props.matchedPage.get('title')
      Object.keys(combinedRouteParams).forEach((route) => {
        title = title.replace('{$' + route + '}', StringHelpers.toTitleCase(combinedRouteParams[route]))
      })

      title = title + ' | ' + this.props.properties.title
    }

    if (title.search(' | ') >= 0) {
      const newTitle = []

      const parts = title.split('|')

      let i
      for (i in parts) {
        newTitle.push(intl.searchAndReplace(parts[i].trim()))
      }
      title = newTitle.join(' | ')
    }

    document.title = title
  }
}
// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvDialect, navigation, nuxeo, windowPath } = state

  const { properties, route } = navigation
  const { computeLogin } = nuxeo
  const { computeDialect2 } = fvDialect
  const { splitWindowPath, _windowPath } = windowPath
  return {
    computeDialect2,
    computeLogin,
    properties,
    routeParams: route.routeParams,
    matchedPage: route.matchedPage,
    search: route.search,
    splitWindowPath,
    windowPath: _windowPath,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  pushWindowPath,
  replaceWindowPath,
  changeTheme,
  setRouteParams,
  updateWindowPath,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(AppFrontController)
<commit_msg>FW-279<commit_after>import React, { Component } from 'react'
import { PropTypes } from 'react'
import Immutable, { List } from 'immutable'

import { connect } from 'react-redux'
// REDUX: actions/dispatch/func
import { pushWindowPath, replaceWindowPath, updateWindowPath } from 'providers/redux/reducers/windowPath'
import { changeTheme, setRouteParams } from 'providers/redux/reducers/navigation'

import selectn from 'selectn'

import classNames from 'classnames'

import ConfGlobal from 'conf/local.js'
import ConfRoutes, { matchPath } from 'conf/routes'
import { WORKSPACES } from 'common/Constants'

import ProviderHelpers from 'common/ProviderHelpers'
import { routeHasChanged, getSearchObject } from 'common/NavigationHelpers'
import { Redirector } from './Redirector'
// import UIHelpers from 'common/UIHelpers'
import StringHelpers from 'common/StringHelpers'
// import AnalyticsHelpers from 'common/AnalyticsHelpers'

import FlatButton from 'material-ui/lib/flat-button'
import Navigation from 'views/components/Navigation'
import WorkspaceSwitcher from 'views/components/Navigation/WorkspaceSwitcher'
import KidsNavigation from 'views/components/Kids/navigation'
import Footer from 'views/components/Navigation/Footer'
import Breadcrumb from 'views/components/Breadcrumb'

import IntlService from 'views/services/intl'

import { PageError } from 'views/pages'

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

const { any, array, func, object, string } = PropTypes

const intl = IntlService.instance

const PAGE_NOT_FOUND_TITLE =
  '404 - ' +
  intl.translate({
    key: 'errors.page_not_found',
    default: 'Page Not Found',
    case: 'first',
  })

const PAGE_NOT_FOUND_BODY = (

      {intl.translate({
        key: 'errors.report_via_feedback',
        default: 'Please report this error so that we can fix it',
        case: 'first',
      })}
      .

      {intl.translate({
        key: 'errors.feedback_include_link',
        default: 'Include what link or action you took to get to this page',
      })}
      .

      {intl.translate({
        key: 'thank_you!',
        default: 'Thank You!',
        case: 'words',
      })}

)

export class AppFrontController extends Component {
  static propTypes = {
    warnings: object.isRequired,

    // loadGuide: func.isRequired,
    // loadNavigation: func.isRequired

    // REDUX: reducers/state
    computeDialect2: object.isRequired,
    computeLogin: object.isRequired,
    properties: object.isRequired,
    routeParams: object.isRequired,
    search: object.isRequired,
    matchedPage: any,
    splitWindowPath: array.isRequired,
    windowPath: string.isRequired,
    // REDUX: actions/dispatch/func
    updateWindowPath: func.isRequired,
    setRouteParams: func.isRequired,
    changeTheme: func.isRequired,
    pushWindowPath: func.isRequired,
    replaceWindowPath: func.isRequired,
  }

  static defaultProps = {
    matchedPage: undefined,
  }

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

    this.state = this._getInitialState()
  }

  componentDidMount() {
    // NOTE: added to respond to `window.history.back()` calls
    window.addEventListener('popstate', this._handleHistoryEvent)
    // NOTE: this used to be called in `componentWillMount`
    this._route(this.props)
  }

  componentDidUpdate(prevProps) {
    this._updateTitle()
    const _routeHasChanged = routeHasChanged({
      prevWindowPath: prevProps.windowPath,
      curWindowPath: this.props.windowPath,
      prevRouteParams: prevProps.routeParams,
      curRouteParams: this.props.routeParams,
    })
    if (_routeHasChanged) {
      // Track page view
      if (window.snowplow) {
        window.snowplow('trackPageView')
      }
    }

    // Re-route if needed:
    const prevCl = prevProps.computeLogin
    const curCl = this.props.computeLogin
    const loggedIn = prevCl.isConnected !== curCl.isConnected && curCl.isConnected === true

    const { sortOrder: newSortOrder, sortBy: newSortBy } = this.props.search
    const { sortOrder: prevSortOrder, sortBy: prevSortBy } = prevProps.search
    const windowLocationSearch = getSearchObject()
    const windowLocationSearchSortOrder = windowLocationSearch.sortOrder
    const windowLocationSearchSortBy = windowLocationSearch.sortBy

    const sortOrderChanged = newSortOrder !== prevSortOrder || windowLocationSearchSortOrder != newSortOrder
    const sortByChanged = newSortBy !== prevSortBy || windowLocationSearchSortBy != newSortBy

    if (_routeHasChanged || loggedIn || sortOrderChanged || sortByChanged) {
      this._route(this.props)
    }
  }

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

    // NOTE: Due to the switch from `componentWillMount` to `componentDidMount`
    // `render` runs before we are ready, hence the empty div being returned
    if (matchedPage === undefined) {
      return

    }

    const isFrontPage = !matchedPage ? false : matchedPage.get('frontpage')
    const hideNavigation = matchedPage && matchedPage.has('navigation') && matchedPage.get('navigation') === false

    let page

    let navigation = <Navigation frontpage={isFrontPage} routeParams={routeParams} />
    const theme = routeParams.hasOwnProperty('theme') ? routeParams.theme : 'default'
    // prettier-ignore
    const print = matchedPage
      ? matchedPage
        .get('page')
        .get('props')
        .get('print') === true
      : false

    let footer =

    const clonedElement = React.cloneElement(matchedPage.get('page').toJS(), { routeParams: routeParams })

    // For print view return page only
    if (print) {
      return
{clonedElement}

    }

    // Remove breadcrumbs for Kids portal
    // TODO: Make more generic if additional themes are added in the future.
    if (theme === 'kids') {
      page = clonedElement
      navigation = <KidsNavigation frontpage={isFrontPage} routeParams={routeParams} />
    } else {
      // Without breadcrumbs
      if (matchedPage.get('breadcrumbs') === false) {
        page = clonedElement
      } else {
        // With breadcrumbs
        page = this._renderWithBreadcrumb(clonedElement, matchedPage, this.props, theme)
      }
    }

    // Hide navigation
    if (hideNavigation) {
      navigation = footer = ''
    }

    return (

        {(matchedPage && matchedPage.hasOwnProperty('warnings') ? matchedPage.get('warnings') : []).map((warning) => {
          if (this.props.warnings.hasOwnProperty(warning) && !this.state.warningsDismissed) {
            return (

                {selectn(warning, this.props.warnings)}
                <FlatButton
                  label={intl.translate({
                    key: 'dismiss',
                    default: 'Dismiss',
                    case: 'words',
                  })}
                  onClick={() => this.setState({ warningsDismissed: true })}
                />

            )
          }
        })}

            {navigation}

            {page}

            {footer}

    )
  }

  _getInitialState() {
    let routes = Immutable.fromJS(ConfRoutes)
    const contextPath = ConfGlobal.contextPath.split('/').filter((v) => v !== '')

    // Add context path to PATH and ALIAS properties if it is set (usually applies in DEV environment)
    if (contextPath && contextPath.length > 0) {
      routes = routes.map((route) => {
        let newRoute = route.set('path', List(contextPath).concat(route.get('path')))
        newRoute = newRoute.set('alias', List(contextPath).concat(route.get('alias')))
        return newRoute
      })
    }

    return {
      routes,
      warningsDismissed: false,
    }
  }

  _handleHistoryEvent = (postStateEvent) => {
    const { state: postStateEventState } = postStateEvent
    if (postStateEventState) {
      const { windowPath } = postStateEventState
      // NOTE: windowPath === postStateEvent.state.windowPath
      this.props.updateWindowPath(windowPath)
    } else {
      this.props.updateWindowPath(window.location.pathname)
    }
  }

  _renderWithBreadcrumb = (reactElement, matchedPage, props, theme) => {
    const themePalette = props.properties.theme.palette.rawTheme.palette
    const { routeParams } = reactElement.props
    const { /*splitWindowPath, */ computeLogin } = props
    const { routes } = this.state
    let _workspaceSwitcher = null
    const area = selectn('routeParams.area', reactElement.props)
    if (
      area &&
      selectn('isConnected', computeLogin) &&
      matchedPage.get('disableWorkspaceSectionNav') !== true &&
      !ProviderHelpers.isSiteMember(selectn('response.properties.groups', computeLogin))
    ) {
      _workspaceSwitcher = <WorkspaceSwitcher className="AppFrontController__workspaceSwitcher" area={area} />
    }
    const overrideBreadcrumbs = selectn('props.properties.breadcrumbs', this)
    const findReplace = overrideBreadcrumbs
      ? { find: overrideBreadcrumbs.find, replace: selectn(overrideBreadcrumbs.replace, this.props.properties) }
      : undefined
    return (

            <Breadcrumb
              className="AppFrontController__breadcrumb"
              matchedPage={matchedPage}
              routes={routes}
              routeParams={routeParams}
              // splitWindowPath={splitWindowPath}
              findReplace={findReplace}
            />
            {_workspaceSwitcher}

{reactElement}

    )
  }

  /**
   * Conditionally route the parameters.
   * This could normally go into the render method to keep things simple,
   * however redirecting (i.e. updating state), cannot be done inside render.
   */
  _route = (props, routesOverride = null) => {
    let matchedPage = null
    let _routeParams = {}
    const pathArray = props.splitWindowPath

    const routes = routesOverride || this.state.routes
    routes.forEach((value) => {
      const matchTest = matchPath(value.get('path'), pathArray)
      const matchAlias = matchPath(value.get('alias'), pathArray)

      if (matchTest.matched || matchAlias.matched) {
        const routeParams = matchTest.routeParams

        // Extract common paths from URL
        if (value.has('extractPaths') && value.get('extractPaths')) {
          const domainPathLocation = pathArray.indexOf(ConfGlobal.domain)
          const dialectPathLocation = 5
          const languagePathLocation = 4
          const languageFamilyPathLocation = 3

          // If domain is specified in the URL, these are Nuxeo paths that can be extracted
          if (domainPathLocation !== -1) {
            // Path from domain to end of path (e.g. /FV/Workspaces/Data/family/language/dialect)
            const nuxeoPath = pathArray.slice(domainPathLocation, pathArray.length)

            if (nuxeoPath.length >= dialectPathLocation) {
              routeParams.dialect_name = decodeURI(nuxeoPath[dialectPathLocation])
              routeParams.dialect_path = decodeURI('/' + nuxeoPath.slice(0, dialectPathLocation + 1).join('/'))
            }

            if (nuxeoPath.length >= languagePathLocation) {
              routeParams.language_name = decodeURI(nuxeoPath[languagePathLocation])
              routeParams.language_path = decodeURI('/' + nuxeoPath.slice(0, languagePathLocation + 1).join('/'))
            }

            if (nuxeoPath.length >= languageFamilyPathLocation) {
              routeParams.language_family_name = decodeURI(nuxeoPath[languageFamilyPathLocation])
              routeParams.language_family_path = decodeURI(
                '/' + nuxeoPath.slice(0, languageFamilyPathLocation + 1).join('/')
              )
            }
          }
        }

        matchedPage = value
        _routeParams = routeParams

        // Break out of forEach
        return false
      }
    })

    // Match found
    if (matchedPage !== null) {
      // Redirect if required
      if (matchedPage.has('redirects')) {
        matchedPage.get('redirects').forEach((value) => {
          if (value.get('condition')({ props: props })) {
            // Avoid invariant violations during rendering by setting temporary placeholder component as matched page, and 'redirecting' after mount.
            matchedPage = matchedPage.set(
              'page',
              Immutable.fromJS(
                React.createElement(
                  Redirector,
                  {
                    redirect: () => {
                      return props.replaceWindowPath(value.get('target')({ props: props }))
                    },
                  },
                  matchedPage.get('page')
                )
              )
            )

            return false
          }
        })
      }

      // Switch themes based on route params
      if (_routeParams.hasOwnProperty('theme')) {
        let newTheme = _routeParams.theme

        // Switch to workspace theme if available
        if (
          ((_routeParams.hasOwnProperty('area') && _routeParams.area === WORKSPACES) ||
            matchedPage.get('path').indexOf(WORKSPACES) !== -1) &&
          _routeParams.theme === 'explore'
        ) {
          newTheme = 'workspace'
          // Note: Also updating routeParams.area
          _routeParams.area = WORKSPACES
        }

        if (props.properties.theme.id !== newTheme) {
          props.changeTheme(newTheme)
        }
      } else {
        // NOTE: Initial theme state is now set in a redux reducer located at:
        //   app/assets/javascripts/providers/redux/reducers/navigation/reducer.js
        // props.changeTheme('default')
      }
      const matchReturn = {
        matchedPage,
        matchedRouteParams: _routeParams,
      }
      // Load help
      //props.loadGuide(props.windowPath, matchReturn);

      // Load Navigation
      //props.loadNavigation();

      // this.setState(matchReturn)
      this.props.setRouteParams({
        ...matchReturn,
        search: getSearchObject(),
      })
      return
    }
    // No match found (i.e. 404)
    const notFoundPage = Immutable.fromJS({
      title: PAGE_NOT_FOUND_TITLE,
      page: <PageError title={PAGE_NOT_FOUND_TITLE} body={PAGE_NOT_FOUND_BODY} />,
    })

    const matchReturn = {
      matchedPage: notFoundPage,
      matchedRouteParams: _routeParams,
    }

    // this.setState(matchReturn)
    this.props.setRouteParams({
      ...matchReturn,
      search: getSearchObject(),
    })
  }

  /**
   * Dynamically update title
   */
  _updateTitle = () => {
    // Title provided from within a component
    const pageTitleParams = this.props.properties.pageTitleParams

    let title = this.props.properties.title

    if (
      this.props.matchedPage &&
      this.props.matchedPage.has('title') &&
      this.props.matchedPage.get('title') &&
      this.props.matchedPage.get('title') !== document.title
    ) {
      const combinedRouteParams = Object.assign({}, this.props.routeParams, pageTitleParams)

      title = this.props.matchedPage.get('title')
      Object.keys(combinedRouteParams).forEach((route) => {
        title = title.replace('{$' + route + '}', StringHelpers.toTitleCase(combinedRouteParams[route]))
      })

      title = title + ' | ' + this.props.properties.title
    }

    if (title.search(' | ') >= 0) {
      const newTitle = []

      const parts = title.split('|')

      let i
      for (i in parts) {
        newTitle.push(intl.searchAndReplace(parts[i].trim()))
      }
      title = newTitle.join(' | ')
    }

    document.title = title
  }
}
// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvDialect, navigation, nuxeo, windowPath } = state

  const { properties, route } = navigation
  const { computeLogin } = nuxeo
  const { computeDialect2 } = fvDialect
  const { splitWindowPath, _windowPath } = windowPath
  return {
    computeDialect2,
    computeLogin,
    properties,
    routeParams: route.routeParams,
    matchedPage: route.matchedPage,
    search: route.search,
    splitWindowPath,
    windowPath: _windowPath,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  pushWindowPath,
  replaceWindowPath,
  changeTheme,
  setRouteParams,
  updateWindowPath,
}

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


<commit_before>'use strict';
var generators = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var mkdirp = require('mkdirp');

function createImageStackLayer(self, templatePath, destinationPath) {
  self.fs.copy(
    self.templatePath(templatePath + '/Content.imageset/Contents.json'),
    self.destinationPath(destinationPath + '/Content.imageset/Contents.json')
  );
  self.fs.copy(
    self.templatePath(templatePath + '/Contents.json'),
    self.destinationPath(destinationPath + '/Contents.json')
  );
}

function createImageStack(self, templatePath, destinationPath) {
  createImageStackLayer(self, templatePath + '/Back.imagestacklayer', destinationPath + '/Back.imagestacklayer');
  createImageStackLayer(self, templatePath + '/Front.imagestacklayer', destinationPath + '/Front.imagestacklayer');
  createImageStackLayer(self, templatePath + '/Middle.imagestacklayer', destinationPath + '/Middle.imagestacklayer');
  self.fs.copy(
    self.templatePath(templatePath + '/Contents.json'),
    self.destinationPath(destinationPath + '/Contents.json')
  );
}

function createBrandAssets(self, templatePath, destinationPath) {
  createImageStack(self, templatePath + '/App\ Icon\ -\ Large.imagestack', destinationPath + '/App\ Icon\ -\ Large.imagestack');
  createImageStack(self, templatePath + '/App\ Icon\ -\ Small.imagestack', destinationPath + '/App\ Icon\ -\ Small.imagestack');
  self.fs.copy(
    self.templatePath(templatePath + '/Top\ Shelf\ Image.imageset/Contents.json'),
    self.destinationPath(destinationPath + '/Top\ Shelf\ Image.imageset/Contents.json')
  );
  self.fs.copy(
    self.templatePath(templatePath + '/Contents.json'),
    self.destinationPath(destinationPath + '/Contents.json')
  );
}

function createAssets(self) {
  createBrandAssets(self, self.templatePath('TvmlApp/Assets.xcassets/App\ Icon\ \&\ Top\ Shelf\ Image.brandassets'), self.appname + '/Assets.xcassets/App\ Icon\ \&\ Top\ Shelf\ Image.brandassets');
  self.fs.copy(
    self.templatePath('TvmlApp/Assets.xcassets/LaunchImage.launchimage/Contents.json'),
    self.destinationPath(self.appname + '/Assets.xcassets/LaunchImage.launchimage/Contents.json')
  );
  self.fs.copy(
    self.templatePath('TvmlApp/Assets.xcassets/Contents.json'),
    self.destinationPath(self.appname + '/Assets.xcassets/Contents.json')
  );
}

module.exports = generators.Base.extend({
  constructor: function () {

    generators.Base.apply(this, arguments);

    this.option('skip-welcome-message', {
      desc: 'Skips the welcome message',
      type: Boolean
    });

    this.option('skip-install-message', {
      desc: 'Skips the message after the installation of dependencies',
      type: Boolean
    });

    this.option('appname', {
      desc: 'Name of the app',
      type: String,
      defaults: this.appname
    });

    this.option('appid', {
      desc: 'Id of the app',
      type: String
    });
  },

  prompting: function () {
    var done = this.async();

    if (!this.options['skip-welcome-message']) {
      this.log(yosay('I create a scaffold for creating JavasScript-based TVML tvOS Apps.  '));
    }

    if (this.options.appname && this.options.appid) {
      this.appname = this.options.appname;
      this.appid = this.options.appid;
      done();
    } else {

      var prompts = [{
        type: 'input',
        name: 'name',
        message: 'Your App name',
        default: this.appname
      }, {
        type: 'input',
        name: 'id',
        message: 'Your App ID',
        default: 'org.sample.tvml-app'
      }];

      this.prompt(prompts, function (answers) {
        this.appname = answers.name;
        this.appid = answers.id;
        done();
      }.bind(this));
    }

  },

  writing: {

    xcode: function () {
      mkdirp(this.appname + '/dist');

      // Xcode
      this.fs.copyTpl(
        this.templatePath('TvmlApp.xcodeproj/project.pbxproj'),
        this.destinationPath(this.appname + '.xcodeproj/project.pbxproj'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata'),
        this.destinationPath(this.appname + '.xcodeproj/project.xcworkspace/contents.xcworkspacedata'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      createAssets(this);

      // App
      this.fs.copyTpl(
        this.templatePath('TvmlApp/AppDelegate.swift'),
        this.destinationPath(this.appname + '/AppDelegate.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlApp/ResourceLoader.swift'),
        this.destinationPath(this.appname + '/ResourceLoader.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlApp/Info.plist'),
        this.destinationPath(this.appname + '/Info.plist'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      // Tests
      this.fs.copyTpl(
        this.templatePath('TvmlAppTests/TvmlAppTests.swift'),
        this.destinationPath(this.appname + 'Tests/' + this.appname + 'Tests.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlAppTests/Info.plist'),
        this.destinationPath(this.appname + 'Tests/Info.plist'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      // UITests
      this.fs.copyTpl(
        this.templatePath('TvmlAppUITests/TvmlAppUITests.swift'),
        this.destinationPath(this.appname + 'UITests/' + this.appname + 'UITests.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlAppUITests/Info.plist'),
        this.destinationPath(this.appname + 'UITests/Info.plist'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    gruntfile: function () {
      this.fs.copyTpl(
        this.templatePath('TvmlApp/Gruntfile.js'),
        this.destinationPath(this.appname + '/Gruntfile.js'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    webpack: function () {
      this.fs.copyTpl(
        this.templatePath('TvmlApp/webpack.config.js'),
        this.destinationPath(this.appname + '/webpack.config.js'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    packageJSON: function () {
      this.fs.copyTpl(
        this.templatePath('TvmlApp/_package.json'),
        this.destinationPath(this.appname + '/package.json'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    git: function () {
      this.fs.copyTpl(
        this.templatePath('gitignore'),
        this.destinationPath('.gitignore'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );

      this.fs.copy(
        this.templatePath('gitattributes'),
        this.destinationPath('.gitattributes')
      );
    },

    editorConfig: function () {
      this.fs.copy(
        this.templatePath('editorconfig'),
        this.destinationPath('.editorconfig')
      );
    },

    scripts: function () {
      this.fs.copy(
        this.templatePath('TvmlApp/src/application.js'),
        this.destinationPath(this.appname + '/src/application.js')
      );
    },

    templates: function () {
      this.fs.copy(
        this.templatePath('TvmlApp/src/templates/loading.jade'),
        this.destinationPath(this.appname + '/src/templates/loading.jade')
      );
      this.fs.copy(
        this.templatePath('TvmlApp/src/templates/list.jade'),
        this.destinationPath(this.appname + '/src/templates/list.jade')
      );
    }
  },

  install: function () {
    var elementDir = process.cwd() + '/' + this.appname;
    process.chdir(elementDir);
    this.installDependencies({
      bower: false,
      npm: true,
      skipMessage: this.options['skip-install-message'],
      skipInstall: this.options['skip-install']
    });
  },

  end: function () {
    var howToInstall =
      '\nPlease run ' +
      chalk.yellow.bold('npm install') +
      '.';

    if (this.options['skip-install']) {
      this.log(howToInstall);
      return;
    }
    this.log(yosay('Run ' + chalk.yellow.bold('cd ' + this.appname + ' && npm start') + ' to start local dev server with reload. Then Start the app from Xcode.'));
  }
});
<commit_msg>Fix small typo<commit_after>'use strict';
var generators = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var mkdirp = require('mkdirp');

function createImageStackLayer(self, templatePath, destinationPath) {
  self.fs.copy(
    self.templatePath(templatePath + '/Content.imageset/Contents.json'),
    self.destinationPath(destinationPath + '/Content.imageset/Contents.json')
  );
  self.fs.copy(
    self.templatePath(templatePath + '/Contents.json'),
    self.destinationPath(destinationPath + '/Contents.json')
  );
}

function createImageStack(self, templatePath, destinationPath) {
  createImageStackLayer(self, templatePath + '/Back.imagestacklayer', destinationPath + '/Back.imagestacklayer');
  createImageStackLayer(self, templatePath + '/Front.imagestacklayer', destinationPath + '/Front.imagestacklayer');
  createImageStackLayer(self, templatePath + '/Middle.imagestacklayer', destinationPath + '/Middle.imagestacklayer');
  self.fs.copy(
    self.templatePath(templatePath + '/Contents.json'),
    self.destinationPath(destinationPath + '/Contents.json')
  );
}

function createBrandAssets(self, templatePath, destinationPath) {
  createImageStack(self, templatePath + '/App\ Icon\ -\ Large.imagestack', destinationPath + '/App\ Icon\ -\ Large.imagestack');
  createImageStack(self, templatePath + '/App\ Icon\ -\ Small.imagestack', destinationPath + '/App\ Icon\ -\ Small.imagestack');
  self.fs.copy(
    self.templatePath(templatePath + '/Top\ Shelf\ Image.imageset/Contents.json'),
    self.destinationPath(destinationPath + '/Top\ Shelf\ Image.imageset/Contents.json')
  );
  self.fs.copy(
    self.templatePath(templatePath + '/Contents.json'),
    self.destinationPath(destinationPath + '/Contents.json')
  );
}

function createAssets(self) {
  createBrandAssets(self, self.templatePath('TvmlApp/Assets.xcassets/App\ Icon\ \&\ Top\ Shelf\ Image.brandassets'), self.appname + '/Assets.xcassets/App\ Icon\ \&\ Top\ Shelf\ Image.brandassets');
  self.fs.copy(
    self.templatePath('TvmlApp/Assets.xcassets/LaunchImage.launchimage/Contents.json'),
    self.destinationPath(self.appname + '/Assets.xcassets/LaunchImage.launchimage/Contents.json')
  );
  self.fs.copy(
    self.templatePath('TvmlApp/Assets.xcassets/Contents.json'),
    self.destinationPath(self.appname + '/Assets.xcassets/Contents.json')
  );
}

module.exports = generators.Base.extend({
  constructor: function () {

    generators.Base.apply(this, arguments);

    this.option('skip-welcome-message', {
      desc: 'Skips the welcome message',
      type: Boolean
    });

    this.option('skip-install-message', {
      desc: 'Skips the message after the installation of dependencies',
      type: Boolean
    });

    this.option('appname', {
      desc: 'Name of the app',
      type: String,
      defaults: this.appname
    });

    this.option('appid', {
      desc: 'Id of the app',
      type: String
    });
  },

  prompting: function () {
    var done = this.async();

    if (!this.options['skip-welcome-message']) {
      this.log(yosay('I create a scaffold for JavasScript-based TVML tvOS Apps.'));
    }

    if (this.options.appname && this.options.appid) {
      this.appname = this.options.appname;
      this.appid = this.options.appid;
      done();
    } else {

      var prompts = [{
        type: 'input',
        name: 'name',
        message: 'Your App name',
        default: this.appname
      }, {
        type: 'input',
        name: 'id',
        message: 'Your App ID',
        default: 'org.sample.tvml-app'
      }];

      this.prompt(prompts, function (answers) {
        this.appname = answers.name;
        this.appid = answers.id;
        done();
      }.bind(this));
    }

  },

  writing: {

    xcode: function () {
      mkdirp(this.appname + '/dist');

      // Xcode
      this.fs.copyTpl(
        this.templatePath('TvmlApp.xcodeproj/project.pbxproj'),
        this.destinationPath(this.appname + '.xcodeproj/project.pbxproj'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata'),
        this.destinationPath(this.appname + '.xcodeproj/project.xcworkspace/contents.xcworkspacedata'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      createAssets(this);

      // App
      this.fs.copyTpl(
        this.templatePath('TvmlApp/AppDelegate.swift'),
        this.destinationPath(this.appname + '/AppDelegate.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlApp/ResourceLoader.swift'),
        this.destinationPath(this.appname + '/ResourceLoader.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlApp/Info.plist'),
        this.destinationPath(this.appname + '/Info.plist'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      // Tests
      this.fs.copyTpl(
        this.templatePath('TvmlAppTests/TvmlAppTests.swift'),
        this.destinationPath(this.appname + 'Tests/' + this.appname + 'Tests.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlAppTests/Info.plist'),
        this.destinationPath(this.appname + 'Tests/Info.plist'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      // UITests
      this.fs.copyTpl(
        this.templatePath('TvmlAppUITests/TvmlAppUITests.swift'),
        this.destinationPath(this.appname + 'UITests/' + this.appname + 'UITests.swift'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
      this.fs.copyTpl(
        this.templatePath('TvmlAppUITests/Info.plist'),
        this.destinationPath(this.appname + 'UITests/Info.plist'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    gruntfile: function () {
      this.fs.copyTpl(
        this.templatePath('TvmlApp/Gruntfile.js'),
        this.destinationPath(this.appname + '/Gruntfile.js'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    webpack: function () {
      this.fs.copyTpl(
        this.templatePath('TvmlApp/webpack.config.js'),
        this.destinationPath(this.appname + '/webpack.config.js'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    packageJSON: function () {
      this.fs.copyTpl(
        this.templatePath('TvmlApp/_package.json'),
        this.destinationPath(this.appname + '/package.json'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );
    },

    git: function () {
      this.fs.copyTpl(
        this.templatePath('gitignore'),
        this.destinationPath('.gitignore'),
        {
          appname: this.appname,
          appid: this.appid
        }
      );

      this.fs.copy(
        this.templatePath('gitattributes'),
        this.destinationPath('.gitattributes')
      );
    },

    editorConfig: function () {
      this.fs.copy(
        this.templatePath('editorconfig'),
        this.destinationPath('.editorconfig')
      );
    },

    scripts: function () {
      this.fs.copy(
        this.templatePath('TvmlApp/src/application.js'),
        this.destinationPath(this.appname + '/src/application.js')
      );
    },

    templates: function () {
      this.fs.copy(
        this.templatePath('TvmlApp/src/templates/loading.jade'),
        this.destinationPath(this.appname + '/src/templates/loading.jade')
      );
      this.fs.copy(
        this.templatePath('TvmlApp/src/templates/list.jade'),
        this.destinationPath(this.appname + '/src/templates/list.jade')
      );
    }
  },

  install: function () {
    var elementDir = process.cwd() + '/' + this.appname;
    process.chdir(elementDir);
    this.installDependencies({
      bower: false,
      npm: true,
      skipMessage: this.options['skip-install-message'],
      skipInstall: this.options['skip-install']
    });
  },

  end: function () {
    var howToInstall =
      '\nPlease run ' +
      chalk.yellow.bold('npm install') +
      '.';

    if (this.options['skip-install']) {
      this.log(howToInstall);
      return;
    }
    this.log(yosay('Run ' + chalk.yellow.bold('cd ' + this.appname + ' && npm start') + ' to start local dev server with reload. Then Start the app from Xcode.'));
  }
});
<|endoftext|>


<commit_before>/**
 * @file MaterialTextField component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import TextField from '../TextField';
import MaterialFieldSeparator from '../_MaterialFieldSeparator';
import Theme from '../Theme';

import Util from '../_vendors/Util';

class MaterialTextField extends Component {

    static Type = TextField.Type;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: '',
            isFocus: false,
            isHover: false
        };

        this.triggerFocusHandler = ::this.triggerFocusHandler;
        this.triggerBlurHandler = ::this.triggerBlurHandler;
        this.triggerChangeHandler = ::this.triggerChangeHandler;
        this.triggerMouseOverHandler = ::this.triggerMouseOverHandler;
        this.triggerMouseOutHandler = ::this.triggerMouseOutHandler;

    }

    triggerFocusHandler(...args) {
        this.setState({
            isFocus: true
        }, () => {
            const {onFocus} = this.props;
            onFocus && onFocus(...args);
        });
    }

    triggerBlurHandler(...args) {
        this.setState({
            isFocus: false
        }, () => {
            const {onBlur} = this.props;
            onBlur && onBlur(...args);
        });
    }

    triggerChangeHandler(value) {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    }

    triggerMouseOverHandler(...args) {
        this.setState({
            isHover: true
        }, () => {
            const {onMouseOver} = this.props;
            onMouseOver && onMouseOver(...args);
        });
    }

    triggerMouseOutHandler(...args) {
        this.setState({
            isHover: false
        }, () => {
            const {onMouseOut} = this.props;
            onMouseOut && onMouseOut(...args);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value) {
            this.setState({
                value: nextProps.value
            });
        }
    }

    componentDidMount() {
        this.setState({
            value: this.props.value
        });
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate,
                ...restProps
            } = this.props,
            {isFocus, isHover, value} = this.state,

            wrapperClassName = (isLabelAnimate ? ' animated' : '') + (label ? ' has-label' : '')
                + (isFocus ? ' focused' : '') + (value ? ' has-value' : '') + (className ? ' ' + className : '');

        return (

                {
                    label ?

                            {label}

                        :
                        null
                }

                <TextField {...restProps}
                           theme={theme}
                           value={value}
                           onFocus={this.triggerFocusHandler}
                           onBlur={this.triggerBlurHandler}
                           onMouseOver={this.triggerMouseOverHandler}
                           onMouseOut={this.triggerMouseOutHandler}
                           onChange={this.triggerChangeHandler}/>

                <MaterialFieldSeparator theme={theme}
                                        isHover={isHover}
                                        isFocus={isFocus}/>

        );

    }
};

MaterialTextField.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The TextField theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Specifies the type of input to display such as "password" or "text".
     */
    type: PropTypes.oneOf(Util.enumerateValue(TextField.Type)),

    /**
     * The name of the text field.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.any,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The placeholder of the text field.
     */
    placeholder: PropTypes.string,

    /**
     * The value of the text field.Type can be string or number.
     */
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

    /**
     * Use this property to display an icon.
     */
    iconCls: PropTypes.string,

    /**
     * Disables the textField if set to true.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the textField will can't editable.
     */
    readOnly: PropTypes.bool,

    /**
     * If true,the textField will autoFocus.
     */
    autoFocus: PropTypes.bool,

    /**
     * The message of the textField.
     */
    infoMsg: PropTypes.string,

    /**
     * If true,clearButton will display when the textField is not empty.
     */
    clearButtonVisible: PropTypes.bool,

    /**
     * Use this property to display an icon.
     */
    rightIconCls: PropTypes.string,

    /**
     * If true,passwordButton will display.
     */
    passwordButtonVisible: PropTypes.bool,

    // valid
    /**
     * If true,the textField must be required.
     */
    required: PropTypes.bool,

    /**
     * The maximum length of textField to enter.
     */
    maxLength: PropTypes.number,

    /**
     * Maximum number of textField that can be entered.
     */
    max: PropTypes.number,

    /**
     * Minimum number of textField that can be entered.
     */
    min: PropTypes.number,

    /**
     * The matching rule of textField.
     */
    pattern: PropTypes.object,

    /**
     * The invalid message of textField.
     */
    patternInvalidMsg: PropTypes.string,

    /**
     *
     */
    autoComplete: PropTypes.string,

    /**
     *
     */
    autoCorrect: PropTypes.string,

    /**
     *
     */
    autoCapitalize: PropTypes.string,

    /**
     *
     */
    spellCheck: PropTypes.string,

    /**
     * Callback function fired when the textField is changed.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when the press enter.
     */
    onPressEnter: PropTypes.func,

    /**
     * Callback function fired when textField valid.
     */
    onValid: PropTypes.func,

    /**
     * Callback function fired when textField invalid.
     */
    onInvalid: PropTypes.func,

    /**
     * Callback function fired when textField focus.
     */
    onFocus: PropTypes.func,

    /**
     * Callback function fired when textField blur.
     */
    onBlur: PropTypes.func,

    /**
     * Callback function fired when textField clear.
     */
    onClear: PropTypes.func,

    /**
     * Callback function fired when password visible.
     */
    onPasswordVisible: PropTypes.func,

    /**
     * Callback function fired when password invisible.
     */
    onPasswordInvisible: PropTypes.func,

    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

MaterialTextField.defaultProps = {

    className: '',
    style: null,
    theme: Theme.DEFAULT,

    type: 'text',
    name: '',
    label: '',
    isLabelAnimate: true,
    placeholder: '',
    value: '',
    iconCls: '',
    disabled: false,
    readOnly: false,
    autoFocus: false,
    infoMsg: '',

    clearButtonVisible: true,
    passwordButtonVisible: true,

    // valid
    required: false,
    patternInvalidMsg: '',
    preventInvalidInput: false,

    autoComplete: 'off',
    autoCorrect: 'off',
    autoCapitalize: 'off',
    spellCheck: 'false',

    fieldMsgVisible: true

};

export default MaterialTextField;<commit_msg>update MaterialTextField<commit_after>/**
 * @file MaterialTextField component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import TextField from '../TextField';
import MaterialFieldSeparator from '../_MaterialFieldSeparator';
import Theme from '../Theme';

import Util from '../_vendors/Util';

class MaterialTextField extends Component {

    static Type = TextField.Type;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: '',
            isFocus: false,
            isHover: false
        };

        this.triggerFocusHandler = ::this.triggerFocusHandler;
        this.triggerBlurHandler = ::this.triggerBlurHandler;
        this.triggerChangeHandler = ::this.triggerChangeHandler;
        this.triggerMouseOverHandler = ::this.triggerMouseOverHandler;
        this.triggerMouseOutHandler = ::this.triggerMouseOutHandler;

    }

    triggerFocusHandler(...args) {
        this.setState({
            isFocus: true
        }, () => {
            const {onFocus} = this.props;
            onFocus && onFocus(...args);
        });
    }

    triggerBlurHandler(...args) {
        this.setState({
            isFocus: false
        }, () => {
            const {onBlur} = this.props;
            onBlur && onBlur(...args);
        });
    }

    triggerChangeHandler(value) {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    }

    triggerMouseOverHandler(...args) {
        this.setState({
            isHover: true
        }, () => {
            const {onMouseOver} = this.props;
            onMouseOver && onMouseOver(...args);
        });
    }

    triggerMouseOutHandler(...args) {
        this.setState({
            isHover: false
        }, () => {
            const {onMouseOut} = this.props;
            onMouseOut && onMouseOut(...args);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value) {
            this.setState({
                value: nextProps.value
            });
        }
    }

    componentDidMount() {
        this.setState({
            value: this.props.value
        });
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate,
                ...restProps
            } = this.props,
            {isFocus, isHover, value} = this.state,

            fieldClassName = classNames('material-text-field', {
                animated: isLabelAnimate,
                'has-label': label,
                focused: isFocus,
                'has-value': value,
                [className]: className
            });

        return (

                {
                    label ?

                            {label}

                        :
                        null
                }

                <TextField {...restProps}
                           theme={theme}
                           value={value}
                           onFocus={this.triggerFocusHandler}
                           onBlur={this.triggerBlurHandler}
                           onMouseOver={this.triggerMouseOverHandler}
                           onMouseOut={this.triggerMouseOutHandler}
                           onChange={this.triggerChangeHandler}/>

                <MaterialFieldSeparator theme={theme}
                                        isHover={isHover}
                                        isFocus={isFocus}/>

        );

    }
};

MaterialTextField.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The TextField theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Specifies the type of input to display such as "password" or "text".
     */
    type: PropTypes.oneOf(Util.enumerateValue(TextField.Type)),

    /**
     * The name of the text field.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.any,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The placeholder of the text field.
     */
    placeholder: PropTypes.string,

    /**
     * The value of the text field.Type can be string or number.
     */
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

    /**
     * Use this property to display an icon.
     */
    iconCls: PropTypes.string,

    /**
     * Disables the textField if set to true.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the textField will can't editable.
     */
    readOnly: PropTypes.bool,

    /**
     * If true,the textField will autoFocus.
     */
    autoFocus: PropTypes.bool,

    /**
     * The message of the textField.
     */
    infoMsg: PropTypes.string,

    /**
     * If true,clearButton will display when the textField is not empty.
     */
    clearButtonVisible: PropTypes.bool,

    /**
     * Use this property to display an icon.
     */
    rightIconCls: PropTypes.string,

    /**
     * If true,passwordButton will display.
     */
    passwordButtonVisible: PropTypes.bool,

    // valid
    /**
     * If true,the textField must be required.
     */
    required: PropTypes.bool,

    /**
     * The maximum length of textField to enter.
     */
    maxLength: PropTypes.number,

    /**
     * Maximum number of textField that can be entered.
     */
    max: PropTypes.number,

    /**
     * Minimum number of textField that can be entered.
     */
    min: PropTypes.number,

    /**
     * The matching rule of textField.
     */
    pattern: PropTypes.object,

    /**
     * The invalid message of textField.
     */
    patternInvalidMsg: PropTypes.string,

    /**
     *
     */
    autoComplete: PropTypes.string,

    /**
     *
     */
    autoCorrect: PropTypes.string,

    /**
     *
     */
    autoCapitalize: PropTypes.string,

    /**
     *
     */
    spellCheck: PropTypes.string,

    /**
     * Callback function fired when the textField is changed.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when the press enter.
     */
    onPressEnter: PropTypes.func,

    /**
     * Callback function fired when textField valid.
     */
    onValid: PropTypes.func,

    /**
     * Callback function fired when textField invalid.
     */
    onInvalid: PropTypes.func,

    /**
     * Callback function fired when textField focus.
     */
    onFocus: PropTypes.func,

    /**
     * Callback function fired when textField blur.
     */
    onBlur: PropTypes.func,

    /**
     * Callback function fired when textField clear.
     */
    onClear: PropTypes.func,

    /**
     * Callback function fired when password visible.
     */
    onPasswordVisible: PropTypes.func,

    /**
     * Callback function fired when password invisible.
     */
    onPasswordInvisible: PropTypes.func,

    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

MaterialTextField.defaultProps = {

    className: '',
    style: null,
    theme: Theme.DEFAULT,

    type: 'text',
    name: '',
    label: '',
    isLabelAnimate: true,
    placeholder: '',
    value: '',
    iconCls: '',
    disabled: false,
    readOnly: false,
    autoFocus: false,
    infoMsg: '',

    clearButtonVisible: true,
    passwordButtonVisible: true,

    // valid
    required: false,
    patternInvalidMsg: '',
    preventInvalidInput: false,

    autoComplete: 'off',
    autoCorrect: 'off',
    autoCapitalize: 'off',
    spellCheck: 'false',

    fieldMsgVisible: true

};

export default MaterialTextField;<|endoftext|>


<commit_before>import React from 'react';

import UserCard from '../../components/UserCard';
import Markdown from '../../components/Markdown';
import { displayUrl } from '../../components/DisplayUrl';

export default class PublicGroupWhoWeAre extends React.Component {
  render() {
    const { group } = this.props;
    let logoElement = null;
    let noLogoClassName = '';

    if (group.logo) {
      logoElement = ;
    } else {
      noLogoClassName = 'PublicGroupIntro--no-logo bg-no-repeat';
    }

    return (

        <div className={`PublicGroupIntro-container container center relative ${noLogoClassName}`}>
          {logoElement}

We are {group.name}

{group.description}

            {group.longDescription && (
              <Markdown className='PublicGroup-quoteText left-align' value={group.longDescription} />
            )}

          {group.website && (

              {displayUrl(group.website)}

          )}

          {group.members.length ? (

Core Contributors

                {group.members.map((user, index) => <UserCard user={user} key={index} className='m1' />)}

          ) : null}

    );
  }
};
<commit_msg>PublicGroup subtitle width matches that of long description (#151)<commit_after>import React from 'react';

import UserCard from '../../components/UserCard';
import Markdown from '../../components/Markdown';
import { displayUrl } from '../../components/DisplayUrl';

export default class PublicGroupWhoWeAre extends React.Component {
  render() {
    const { group } = this.props;
    let logoElement = null;
    let noLogoClassName = '';

    if (group.logo) {
      logoElement = ;
    } else {
      noLogoClassName = 'PublicGroupIntro--no-logo bg-no-repeat';
    }

    return (

        <div className={`PublicGroupIntro-container container center relative ${noLogoClassName}`}>
          {logoElement}

We are {group.name}

{group.description}

            {group.longDescription && (
              <Markdown className='PublicGroup-quoteText left-align' value={group.longDescription} />
            )}

          {group.website && (

              {displayUrl(group.website)}

          )}

          {group.members.length ? (

Core Contributors

                {group.members.map((user, index) => <UserCard user={user} key={index} className='m1' />)}

          ) : null}

    );
  }
};
<|endoftext|>


<commit_before>const generators = require('yeoman-generator')
const fs = require('fs')

module.exports = generators.Base.extend({
  constructor: function () {
    generators.Base.apply(this, arguments)
    this.sourceRoot(__dirname + '/../kit')
    this.option('install')
  },
  prompting: function () {
    var done = this.async()

    const prompts = [
      {
        type: 'input',
        name: 'name',
        message: 'Project name',
        default: this.appname,
        filter: function (input) {
          return input.replace(' ', '').toLowerCase()
        }
      },
      {
        type: 'input',
        name: 'author',
        message: 'Author'
      },
      {
        type: 'input',
        name: 'db_host',
        message: 'DB host',
        default: 'localhost'
      },
      {
        type: 'input',
        name: 'db_name',
        message: 'DB name',
        default: 'muffin'
      },
      {
        type: 'input',
        name: 'db_user',
        message: 'DB user'
      },
      {
        type: 'input',
        name: 'db_password',
        message: 'DB password'
      }
    ]

    this.prompt(prompts, function (answers) {
      this.fields = {
        year: new Date().getFullYear(),
        secret: (Math.random() + 1).toString(36).substring(2)
      }

      Object.assign(this.fields, answers)
      done()
    }.bind(this))
  },
  writing: function () {
    const details = this.fields

    fs.readdir(this.templatePath(), function (err, files) {
      if (err) {
        throw err
      }

      for (var file of files) {
        if (file === 'node_modules') {
          continue
        }

        var source = this.templatePath(file)
        this.fs.copyTpl(source, this.destinationPath(file), details)
      }
    }.bind(this))

    if (!this.options.install) {
      return
    }

    this.installDependencies({
      bower: false
    })
  }
})
<commit_msg>Allow end user to specify destination path<commit_after>const generators = require('yeoman-generator')
const fs = require('fs')
const path = require('path')

module.exports = generators.Base.extend({
  constructor: function () {
    generators.Base.apply(this, arguments)
    this.sourceRoot(__dirname + '/../kit')
    this.option('install')

    const dest = path.resolve(this.destinationRoot())

    this.argument('path', {
      type: String,
      desc: 'The path in which the new site should be generated',
      default: dest
    })

    this.destinationRoot(this.path)
  },
  prompting: function () {
    const done = this.async()
    const destPath = path.resolve(this.path)

    const prompts = [
      {
        type: 'input',
        name: 'name',
        message: 'Project name',
        default: path.basename(destPath),
        filter: function (input) {
          return input.replace(' ', '').toLowerCase()
        }
      },
      {
        type: 'input',
        name: 'author',
        message: 'Author'
      },
      {
        type: 'input',
        name: 'db_host',
        message: 'DB host',
        default: 'localhost'
      },
      {
        type: 'input',
        name: 'db_name',
        message: 'DB name',
        default: 'muffin'
      },
      {
        type: 'input',
        name: 'db_user',
        message: 'DB user'
      },
      {
        type: 'input',
        name: 'db_password',
        message: 'DB password'
      }
    ]

    this.prompt(prompts, function (answers) {
      this.fields = {
        year: new Date().getFullYear(),
        secret: (Math.random() + 1).toString(36).substring(2)
      }

      Object.assign(this.fields, answers)
      done()
    }.bind(this))
  },
  writing: function () {
    const details = this.fields

    fs.readdir(this.templatePath(), function (err, files) {
      if (err) {
        throw err
      }

      for (var file of files) {
        if (file === 'node_modules') {
          continue
        }

        var source = this.templatePath(file)
        this.template(source, this.destinationPath(file), details)
      }
    }.bind(this))

    if (!this.options.install) {
      return
    }

    this.installDependencies({
      bower: false
    })
  }
})
<|endoftext|>


<commit_before>$(function(){
	$(".dropdown-menu > li > a.trigger").on("click",function(e){
		var current=$(this).next();
		var grandparent=$(this).parent().parent();
		if($(this).hasClass('left-caret')||$(this).hasClass('right-caret'))
			$(this).toggleClass('right-caret left-caret');
		grandparent.find('.left-caret').not(this).toggleClass('right-caret left-caret');
		grandparent.find(".sub-menu:visible").not(current).hide();
		current.toggle();
		e.stopPropagation();
	});
	$(".dropdown-menu > li > a:not(.trigger)").on("click",function(){
		var root=$(this).closest('.dropdown');
		root.find('.left-caret').toggleClass('right-caret left-caret');
		root.find('.sub-menu:visible').hide();
	});
});<commit_msg>modal com ajax<commit_after>$(function(){
	$(".dropdown-menu > li > a.trigger").on("click",function(e){
		var current=$(this).next();
		var grandparent=$(this).parent().parent();
		if($(this).hasClass('left-caret')||$(this).hasClass('right-caret'))
			$(this).toggleClass('right-caret left-caret');
		grandparent.find('.left-caret').not(this).toggleClass('right-caret left-caret');
		grandparent.find(".sub-menu:visible").not(current).hide();
		current.toggle();
		e.stopPropagation();
	});
	$(".dropdown-menu > li > a:not(.trigger)").on("click",function(){
		var root=$(this).closest('.dropdown');
		root.find('.left-caret').toggleClass('right-caret left-caret');
		root.find('.sub-menu:visible').hide();
	});
	$('.modalButton').click(function(){
	  	$('#modal-content').load($(this).attr('href'),function(result){
		    $('.modalWindow').modal({show:true});
		});
		return false;
	});
});<|endoftext|>


<commit_before>
var lightBoxShown=false;
$(document).ready(function() {
	if(typeof FileActions!=='undefined'){
		images={};//image cache
		var overlay=$('
');
		$( 'body' ).append(overlay);
		var container=$('
');
		$( 'body' ).append(container);
		FileActions.register('image','View',function(filename){
			var location='ajax/download.php?files='+filename+'&dir='+$('#dir').val();
			overlay.show();
			if(!images[location]){
				var img = new Image();
				img.onload = function(){
					images[location]=img;
					showLightbox(container,img);
				}
				img.src = location;
			}else{
				showLightbox(container,images[location]);
			}
		});
		$( 'body' ).click(hideLightbox);
		FileActions.setDefault('image','View');
	}
});

function showLightbox(container,img){
	var maxWidth = $( window ).width() - 50;
	var maxHeight = $( window ).height() - 50;
	if( img.width > maxWidth || img.height > maxHeight ) { // One of these is larger than the window
		var ratio = img.width / img.height;
		if( img.height >= maxHeight ) {
			img.height = maxHeight;
			img.width = maxHeight * ratio;
		} else {
			img.width = maxWidth;
			img.height = maxWidth * ratio;
		}
	}
	container.empty();
	container.append(img);
	container.css('top',Math.round( ($( window ).height() - img.height)/2));
	container.css('left',Math.round( ($( window ).width() - img.width)/2));
	$('#lightbox').show();
	setTimeout(function(){
		lightBoxShown=true;
	},100);
}

function hideLightbox(){
	if(lightBoxShown){
		$('#lightbox_overlay').hide();
		$('#lightbox').hide();
		lightBoxShown=false;
	}
}<commit_msg>fix resizing images in image viewer<commit_after>
var lightBoxShown=false;
$(document).ready(function() {
	if(typeof FileActions!=='undefined'){
		images={};//image cache
		var overlay=$('
');
		$( 'body' ).append(overlay);
		var container=$('
');
		$( 'body' ).append(container);
		FileActions.register('image','View',function(filename){
			var location='ajax/download.php?files='+filename+'&dir='+$('#dir').val();
			overlay.show();
			if(!images[location]){
				var img = new Image();
				img.onload = function(){
					images[location]=img;
					showLightbox(container,img);
				}
				img.src = location;
			}else{
				showLightbox(container,images[location]);
			}
		});
		$( 'body' ).click(hideLightbox);
		FileActions.setDefault('image','View');
	}
});

function showLightbox(container,img){
	var maxWidth = $( window ).width() - 50;
	var maxHeight = $( window ).height() - 50;
	if( img.width > maxWidth || img.height > maxHeight ) { // One of these is larger than the window
		var ratio = img.width / img.height;
		if( img.height >= maxHeight ) {
			img.height = maxHeight;
			img.width = maxHeight * ratio;
		} else {
			img.width = maxWidth;
			img.height = maxWidth / ratio;
		}
	}
	container.empty();
	container.append(img);
	container.css('top',Math.round( ($( window ).height() - img.height)/2));
	container.css('left',Math.round( ($( window ).width() - img.width)/2));
	$('#lightbox').show();
	setTimeout(function(){
		lightBoxShown=true;
	},100);
}

function hideLightbox(){
	if(lightBoxShown){
		$('#lightbox_overlay').hide();
		$('#lightbox').hide();
		lightBoxShown=false;
	}
}
<|endoftext|>