aboutsummaryrefslogtreecommitdiffstats
path: root/app/assets/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/application.js2
-rw-r--r--app/assets/javascripts/es6_browserified/actions/index.js42
-rw-r--r--app/assets/javascripts/es6_browserified/components/App.js12
-rw-r--r--app/assets/javascripts/es6_browserified/components/BSelect2.js128
-rw-r--r--app/assets/javascripts/es6_browserified/components/Todo.js75
-rw-r--r--app/assets/javascripts/es6_browserified/components/TodoList.js36
-rw-r--r--app/assets/javascripts/es6_browserified/containers/AddTodo.js22
-rw-r--r--app/assets/javascripts/es6_browserified/containers/VisibleTodoList.js36
-rw-r--r--app/assets/javascripts/es6_browserified/form_helper.js10
-rw-r--r--app/assets/javascripts/es6_browserified/reducers/index.js8
-rw-r--r--app/assets/javascripts/es6_browserified/reducers/todos.js85
-rw-r--r--app/assets/javascripts/es6_browserified/stop_points.js65
-rw-r--r--app/assets/javascripts/select2.coffee11
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