diff options
| author | Alban Peignier | 2016-11-20 22:38:47 +0100 |
|---|---|---|
| committer | Alban Peignier | 2016-11-20 22:38:47 +0100 |
| commit | 85fd6480daebe50e423ba27bce772c7b7f86fbf6 (patch) | |
| tree | 04285d132e00fa82cb4786f946a605ac9f549795 /app/assets/javascripts | |
| parent | 7b05ae21fc9421b81fc071976f3bb98ed7c87f43 (diff) | |
| parent | 65c8a96a00f8d3afbd02cfb019b34f39ad44bc3e (diff) | |
| download | chouette-core-85fd6480daebe50e423ba27bce772c7b7f86fbf6.tar.bz2 | |
Merge branch 'master' into staging
Diffstat (limited to 'app/assets/javascripts')
13 files changed, 532 insertions, 0 deletions
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 7193d0d21..b0e100684 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,6 +12,8 @@ //= require raphael //= require morrisjs //= require bootstrap-sass-official +//= require select2-full +//= require select2_locale_fr //= require typeahead.js //= require jquery-tokeninput //= require moment diff --git a/app/assets/javascripts/es6_browserified/actions/index.js b/app/assets/javascripts/es6_browserified/actions/index.js new file mode 100644 index 000000000..7d225f2f6 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/actions/index.js @@ -0,0 +1,42 @@ +const actions = { + addStop : () => { + return { + type: 'ADD_STOP' + } + }, + moveStopUp : (index) => { + return { + type: 'MOVE_STOP_UP', + index + } + }, + moveStopDown : (index) => { + return { + type: 'MOVE_STOP_DOWN', + index + } + }, + deleteStop : (index) => { + return { + type: 'DELETE_STOP', + index + } + }, + updateInputValue : (index, text) => { + return { + type : 'UPDATE_INPUT_VALUE', + index, + text + } + }, + updateSelectValue: (e, index) => { + return { + type :'UPDATE_SELECT_VALUE', + select_id: e.currentTarget.id, + select_value: e.currentTarget.value, + index + } + } +} + +module.exports = actions diff --git a/app/assets/javascripts/es6_browserified/components/App.js b/app/assets/javascripts/es6_browserified/components/App.js new file mode 100644 index 000000000..7488b0b39 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/components/App.js @@ -0,0 +1,12 @@ +var React = require('react') +var AddTodo = require('../containers/AddTodo') +var VisibleTodoList = require('../containers/VisibleTodoList') + +const App = () => ( + <div> + <AddTodo /> + <VisibleTodoList /> + </div> +) + +module.exports = App diff --git a/app/assets/javascripts/es6_browserified/components/BSelect2.js b/app/assets/javascripts/es6_browserified/components/BSelect2.js new file mode 100644 index 000000000..ec0d130d2 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/components/BSelect2.js @@ -0,0 +1,128 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +var Select2 = require('react-select2') + + +// get JSON full path +var origin = window.location.origin +var path = window.location.pathname.split('/', 3).join('/') + + +class BSelect3 extends React.Component{ + constructor(props) { + super(props) + this.state = { + edit: false + } + } + onToggleEdit(e) { + e.preventDefault() + this.setState({edit: !this.state.edit}) + } + onChange(e) { + this.props.onChange(this.props.index, { + text: e.currentTarget.textContent, stoparea_id: e.currentTarget.value + }) + this.setState({edit: false}) + } + + render() { + if(this.state.edit) + return ( + <div className='input-group select2-bootstrap-append'> + <BSelect2 {...this.props} onSelect={ this.onChange.bind(this) }/> + + <span className='input-group-btn'> + <button type='button' className='btn btn-default' onClick={this.onToggleEdit.bind(this)}> + <span className='fa fa-undo'></span> + </button> + </span> + </div> + ) + else + if(!this.props.value.stoparea_id) + return ( + <div> + <BSelect2 {...this.props} onSelect={ this.onChange.bind(this) }/> + </div> + ) + else + return ( + <div className='input-group'> + <a + className='form-control form-control-link' + href={origin + path + '/stop_areas/' + this.props.value.stoparea_id} + title={"Voir l'arrêt '" + this.props.value.text + "'"} + style={{lineHeight: '22px', overflow: 'hidden'}} + > + {this.props.value.text} + </a> + <span className='input-group-btn'> + <button type='button' className='btn btn-default' onClick={this.onToggleEdit.bind(this)}> + <span className='fa fa-pencil'></span> + </button> + </span> + </div> + ) + } +} + +class BSelect2 extends React.Component{ + componentDidMount() { + this.refs.newSelect.el.select2('open') + } + + render() { + return ( + <Select2 + value={ this.props.value.stoparea_id } + onSelect={ this.props.onSelect } + ref='newSelect' + options={{ + placeholder: 'Sélectionnez un arrêt existant...', + allowClear: true, + language: 'fr', /* Doesn't seem to work... :( */ + theme: 'bootstrap', + width: '100%', + ajax: { + url: origin + path + '/autocomplete_stop_areas.json', + dataType: 'json', + delay: '500', + data: function(params) { + return { + q: params.term + }; + }, + processResults: function(data, params) { + return { + results: data.map( + item => Object.assign( + {}, + item, + { text: item.name + ", " + item.zip_code + " " + item.short_city_name } + ) + ) + }; + }, + cache: true + }, + minimumInputLength: 3, + templateResult: formatRepo + }} + /> + ) + } +} + +const formatRepo = (props) => { + if(props.text) return props.text + // console.log(props) + // return ( + // <div> + // {props.short_name} + // <small><em>{props.zip_code} {props.short_city_name}</em></small> + // </div> + // ) +} + +module.exports = BSelect3 diff --git a/app/assets/javascripts/es6_browserified/components/Todo.js b/app/assets/javascripts/es6_browserified/components/Todo.js new file mode 100644 index 000000000..2a670370f --- /dev/null +++ b/app/assets/javascripts/es6_browserified/components/Todo.js @@ -0,0 +1,75 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +var BSelect2 = require('./BSelect2') + +const Todo = (props) => { + return ( + <div className='list-group-item'> + <div className='row'> + <div className='col-lg-5 col-md-5 col-sm-4 col-xs-5'> + <div style={{display: 'inline-block', width: '20%', verticalAlign: 'middle', textAlign: 'right'}}> + <span className='label label-default' style={{marginRight: 10}}>{props.value.stoparea_id}</span> + </div> + + <div style={{display: 'inline-block', width: '80%', verticalAlign: 'middle'}}> + <BSelect2 id={'route_stop_points_' + props.id} value={props.value} onChange={props.onChange} index={props.index} /> + </div> + </div> + + <div className='col-lg-2 col-md-2 col-sm-2 col-xs-2'> + <div style={{display: 'inline-block', width: '100%', verticalAlign: 'middle'}}> + <select className='form-control' value={props.value.for_boarding} id="for_boarding" onChange={props.onSelectChange}> + <option value="forbidden">interdit</option> + <option value="normal">normal</option> + </select> + </div> + </div> + <div className='col-lg-2 col-md-2 col-sm-2 col-xs-2'> + <div style={{display: 'inline-block', width: '100%', verticalAlign: 'middle'}}> + <select className='form-control' value={props.value.for_alighting} id="for_alighting" onChange={props.onSelectChange}> + <option value="forbidden">interdit</option> + <option value="normal">normal</option> + </select> + </div> + </div> + + <div className='col-lg-3 col-md-3 col-sm-4 col-xs-3' style={{textAlign: 'right'}}> + <div className='btn-group btn-group-sm'> + <div + className={'btn btn-primary' + (props.first ? ' disabled' : '')} + onClick={props.onMoveUpClick} + > + <span className='fa fa-arrow-up'></span> + </div> + <div + className={'btn btn-primary' + (props.last ? ' disabled' : '')} + onClick={props.onMoveDownClick} + > + <span className='fa fa-arrow-down'></span> + </div> + <div + className='btn btn-danger' + onClick={props.onDeleteClick} + > + <span className='fa fa-trash'></span> + </div> + </div> + </div> + </div> + </div> + ) +} + +Todo.propTypes = { + onDeleteClick: PropTypes.func.isRequired, + onMoveUpClick: PropTypes.func.isRequired, + onMoveDownClick: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + onSelectChange: PropTypes.func.isRequired, + first: PropTypes.bool, + last: PropTypes.bool, + index: PropTypes.number, + value: PropTypes.object +} + +module.exports = Todo diff --git a/app/assets/javascripts/es6_browserified/components/TodoList.js b/app/assets/javascripts/es6_browserified/components/TodoList.js new file mode 100644 index 000000000..3ea2c90e1 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/components/TodoList.js @@ -0,0 +1,36 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +var Todo = require('./Todo') + +const TodoList = ({ todos, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange }) => { + return ( + <div className='list-group'> + {todos.map((todo, index) => + <Todo + key={'item-' + index} + onDeleteClick={() => onDeleteClick(index)} + onMoveUpClick={() => { + onMoveUpClick(index) + }} + onMoveDownClick={() => onMoveDownClick(index)} + onChange={ onChange } + onSelectChange={ (e) => onSelectChange(e, index) } + first={ index === 0 } + last={ index === (todos.length - 1) } + index={ index } + value={ todo } + /> + )} + </div> + ) +} + +TodoList.propTypes = { + todos: PropTypes.array.isRequired, + onDeleteClick: PropTypes.func.isRequired, + onMoveUpClick: PropTypes.func.isRequired, + onMoveDownClick: PropTypes.func.isRequired, + onSelectChange: PropTypes.func.isRequired +} + +module.exports = TodoList diff --git a/app/assets/javascripts/es6_browserified/containers/AddTodo.js b/app/assets/javascripts/es6_browserified/containers/AddTodo.js new file mode 100644 index 000000000..d0128f16d --- /dev/null +++ b/app/assets/javascripts/es6_browserified/containers/AddTodo.js @@ -0,0 +1,22 @@ +var React = require('react') +var connect = require('react-redux').connect +var actions = require('../actions') + +let AddTodo = ({ dispatch }) => { + return ( + <div className="clearfix" style={{marginBottom: 10}}> + <form onSubmit={e => { + e.preventDefault() + dispatch(actions.addStop()) + }}> + <label>Séquence d'arrêts</label> + <button type="submit" className="btn btn-primary btn-xs pull-right"> + <span className="fa fa-plus"></span> Ajouter un arrêt + </button> + </form> + </div> + ) +} +AddTodo = connect()(AddTodo) + +module.exports = AddTodo diff --git a/app/assets/javascripts/es6_browserified/containers/VisibleTodoList.js b/app/assets/javascripts/es6_browserified/containers/VisibleTodoList.js new file mode 100644 index 000000000..464d6e482 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/containers/VisibleTodoList.js @@ -0,0 +1,36 @@ +var actions = require('../actions') +var connect = require('react-redux').connect +var TodoList = require('../components/TodoList') + +const mapStateToProps = (state) => { + return { + todos: state.todos + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onDeleteClick: (index) =>{ + dispatch(actions.deleteStop(index)) + }, + onMoveUpClick: (index) =>{ + dispatch(actions.moveStopUp(index)) + }, + onMoveDownClick: (index) =>{ + dispatch(actions.moveStopDown(index)) + }, + onChange: (index, text) =>{ + dispatch(actions.updateInputValue(index, text)) + }, + onSelectChange: (e, index) =>{ + dispatch(actions.updateSelectValue(e, index)) + } + } +} + +const VisibleTodoList = connect( + mapStateToProps, + mapDispatchToProps +)(TodoList) + +module.exports = VisibleTodoList diff --git a/app/assets/javascripts/es6_browserified/form_helper.js b/app/assets/javascripts/es6_browserified/form_helper.js new file mode 100644 index 000000000..d48718841 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/form_helper.js @@ -0,0 +1,10 @@ +const addInput = (name, value, index) => { + let form = document.querySelector('form') + let input = document.createElement('input') + input.setAttribute('type', 'hidden') + input.setAttribute('name', `route[stop_points_attributes][${index}][${name}]`) + input.setAttribute('value', value) + form.appendChild(input) +} + +module.exports = addInput diff --git a/app/assets/javascripts/es6_browserified/reducers/index.js b/app/assets/javascripts/es6_browserified/reducers/index.js new file mode 100644 index 000000000..381b32d8b --- /dev/null +++ b/app/assets/javascripts/es6_browserified/reducers/index.js @@ -0,0 +1,8 @@ +var combineReducers = require('redux').combineReducers +var todos = require('./todos') + +const todoApp = combineReducers({ + todos +}) + +module.exports = todoApp diff --git a/app/assets/javascripts/es6_browserified/reducers/todos.js b/app/assets/javascripts/es6_browserified/reducers/todos.js new file mode 100644 index 000000000..916cd4704 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/reducers/todos.js @@ -0,0 +1,85 @@ +var addInput = require('../form_helper') + +const todo = (state = {}, action, length) => { + switch (action.type) { + case 'ADD_STOP': + return { + text: '', + index: length, + for_boarding: 'normal', + for_alighting: 'normal' + } + default: + return state + } +} +const updateFormForDeletion = (stop) =>{ + if (stop.stoppoint_id !== undefined){ + let now = Date.now() + addInput('id', stop.stoppoint_id, now) + addInput('_destroy', 'true', now) + } +} + +const todos = (state = [], action) => { + switch (action.type) { + case 'ADD_STOP': + return [ + ...state, + todo(undefined, action, state.length) + ] + case 'MOVE_STOP_UP': + return [ + ...state.slice(0, action.index - 1), + state[action.index], + state[action.index - 1], + ...state.slice(action.index + 1) + ] + case 'MOVE_STOP_DOWN': + return [ + ...state.slice(0, action.index), + state[action.index + 1], + state[action.index], + ...state.slice(action.index + 2) + ] + case 'DELETE_STOP': + updateFormForDeletion(state[action.index]) + return [ + ...state.slice(0, action.index), + ...state.slice(action.index + 1).map((todo)=>{ + todo.index-- + return todo + }) + ] + case 'UPDATE_INPUT_VALUE': + return state.map( (t, i) => { + if (i === action.index) { + updateFormForDeletion(t) + return Object.assign( + {}, + t, + {text: action.text.text, stoparea_id: action.text.stoparea_id} + ) + } else { + return t + } + }) + // return state.map(t => + // todo(t, action) + // ) + case 'UPDATE_SELECT_VALUE': + return state.map( (t,i) => { + if (i === action.index) { + let stopState = Object.assign({}, t) + stopState[action.select_id] = action.select_value + return stopState + } else { + return t + } + }) + default: + return state + } +} + +module.exports = todos diff --git a/app/assets/javascripts/es6_browserified/stop_points.js b/app/assets/javascripts/es6_browserified/stop_points.js new file mode 100644 index 000000000..f594c0da4 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/stop_points.js @@ -0,0 +1,65 @@ +var React = require('react') +var render = require('react-dom').render +var Provider = require('react-redux').Provider +var createStore = require('redux').createStore +var todoApp = require('./reducers') +var App = require('./components/App') +var addInput = require('./form_helper') + +// logger, DO NOT REMOVE +// var applyMiddleware = require('redux').applyMiddleware +// var createLogger = require('redux-logger') +// var thunkMiddleware = require('redux-thunk').default +// var promise = require('redux-promise') + +const getInitialState = () => { + let state = [] + let datas = JSON.parse(decodeURIComponent(window.itinerary_stop)) + for (let [index, value] of datas.entries()){ + + let fancyText = value.name + if(value.zip_code && value.city_name) + fancyText += ", " + value.zip_code + " " + value.city_name + + state.push({ + stoppoint_id: value.stoppoint_id, + stoparea_id: value.stoparea_id, + index: index, + city_name: value.city_name, + zip_code: value.zip_code, + text: fancyText, + for_boarding: value.for_boarding || "normal", + for_alighting: value.for_alighting || "normal" + }) + } + return state +} + +var initialState = {todos: getInitialState()} +// const loggerMiddleware = createLogger() +let store = createStore( + todoApp, + initialState + // applyMiddleware(thunkMiddleware, promise, loggerMiddleware) +) + +render( + <Provider store={store}> + <App /> + </Provider>, + document.getElementById('stop_points') +) + +document.querySelector('input[name=commit]').addEventListener('click', (event)=>{ + let state = store.getState() + for (let [i, todo] of state.todos.entries()){ + if (todo.stoppoint_id == undefined){ + todo.stoppoint_id = "" + } + addInput('id',todo.stoppoint_id, i) + addInput('stop_area_id',todo.stoparea_id, i) + addInput('position',i, i) + addInput('for_boarding',todo.for_boarding, i) + addInput('for_alighting',todo.for_alighting, i) + } +}) diff --git a/app/assets/javascripts/select2.coffee b/app/assets/javascripts/select2.coffee new file mode 100644 index 000000000..edd4c476d --- /dev/null +++ b/app/assets/javascripts/select2.coffee @@ -0,0 +1,11 @@ +@select_2 = -> + $("[data-select2ed='true']").each -> + target = $(this) + target.select2 + theme: 'bootstrap' + language: 'fr' + placeholder: target.data('select2ed-placeholder') + allowClear: true + + +$(document).on 'ready page:load', select_2 |
