aboutsummaryrefslogtreecommitdiffstats
path: root/app/javascript/routes/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/routes/components')
-rw-r--r--app/javascript/routes/components/App.js25
-rw-r--r--app/javascript/routes/components/BSelect2.js125
-rw-r--r--app/javascript/routes/components/OlMap.js169
-rw-r--r--app/javascript/routes/components/StopPoint.js94
-rw-r--r--app/javascript/routes/components/StopPointList.js69
5 files changed, 482 insertions, 0 deletions
diff --git a/app/javascript/routes/components/App.js b/app/javascript/routes/components/App.js
new file mode 100644
index 000000000..0f5786407
--- /dev/null
+++ b/app/javascript/routes/components/App.js
@@ -0,0 +1,25 @@
+import React, { Component, PropTypes } from 'react'
+import AddStopPoint from '../containers/AddStopPoint'
+import VisibleStopPoints from'../containers/VisibleStopPoints'
+import clone from '../../helpers/clone'
+const I18n = clone(window , "I18n", true)
+
+export default class App extends Component {
+
+ getChildContext() {
+ return { I18n }
+ }
+
+ render() {
+ return (
+ <div>
+ <VisibleStopPoints />
+ <AddStopPoint />
+ </div>
+ )
+ }
+}
+
+App.childContextTypes = {
+ I18n: PropTypes.object
+}
diff --git a/app/javascript/routes/components/BSelect2.js b/app/javascript/routes/components/BSelect2.js
new file mode 100644
index 000000000..340d9df95
--- /dev/null
+++ b/app/javascript/routes/components/BSelect2.js
@@ -0,0 +1,125 @@
+import _ from'lodash'
+import React, { Component, PropTypes } from 'react'
+import Select2 from 'react-select2'
+
+
+// get JSON full path
+var origin = window.location.origin
+var path = window.location.pathname.split('/', 3).join('/')
+
+
+export default class BSelect3 extends Component {
+ constructor(props, context) {
+ super(props, context)
+ }
+ onChange(e) {
+ this.props.onChange(this.props.index, {
+ text: e.currentTarget.textContent,
+ stoparea_id: e.currentTarget.value,
+ user_objectid: e.params.data.user_objectid,
+ longitude: e.params.data.longitude,
+ latitude: e.params.data.latitude,
+ name: e.params.data.name,
+ short_name: e.params.data.short_name,
+ city_name: e.params.data.city_name,
+ area_type: e.params.data.area_type,
+ zip_code: e.params.data.zip_code,
+ comment: e.params.data.comment
+ })
+ }
+
+ parsedText(data) {
+ let a = data.replace('</em></small>', '')
+ let b = a.split('<small><em>')
+ if (b.length > 1) {
+ return (
+ <span>
+ {b[0]}
+ <small><em>{b[1]}</em></small>
+ </span>
+ )
+ } else {
+ return (
+ <span>{data}</span>
+ )
+ }
+ }
+
+ render() {
+ if(this.props.value.edit)
+ return (
+ <div className='select2-bootstrap-append'>
+ <BSelect2 {...this.props} onSelect={ this.onChange.bind(this) }/>
+ </div>
+ )
+ else
+ if(!this.props.value.stoparea_id)
+ return (
+ <div>
+ <BSelect2 {...this.props} onSelect={ this.onChange.bind(this) }/>
+ </div>
+ )
+ else
+ return (
+ <a
+ className='navlink'
+ href={origin + path + '/stop_areas/' + this.props.value.stoparea_id}
+ title="Voir l'arrĂȘt"
+ >
+ {this.parsedText(this.props.value.text)}
+ </a>
+ )
+ }
+}
+
+class BSelect2 extends 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: this.context.I18n.routes.edit.select2.placeholder,
+ 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,
+ target_type: 'zdep'
+ };
+ },
+ processResults: function(data, params) {
+ return {
+ results: data.map(
+ item => _.assign(
+ {},
+ item,
+ { text: item.name + ", " + item.zip_code + " " + item.short_city_name + " <small><em>(" + item.user_objectid + ")</em></small>" }
+ )
+ )
+ };
+ },
+ cache: true
+ },
+ escapeMarkup: function (markup) { return markup; },
+ minimumInputLength: 3
+ }}
+ />
+ )
+ }
+}
+
+BSelect2.contextTypes = {
+ I18n: PropTypes.object
+}
diff --git a/app/javascript/routes/components/OlMap.js b/app/javascript/routes/components/OlMap.js
new file mode 100644
index 000000000..2c01dfa7f
--- /dev/null
+++ b/app/javascript/routes/components/OlMap.js
@@ -0,0 +1,169 @@
+import _ from 'lodash'
+import React, { Component, PropTypes } from 'react'
+
+export default class OlMap extends Component{
+ constructor(props, context){
+ super(props, context)
+ }
+
+ fetchApiURL(id){
+ const origin = window.location.origin
+ const path = window.location.pathname.split('/', 3).join('/')
+ return origin + path + "/autocomplete_stop_areas/" + id + "/around?target_type=zdep"
+ }
+
+ componentDidUpdate(prevProps, prevState){
+ if(prevProps.value.olMap.isOpened == false && this.props.value.olMap.isOpened == true){
+ var source = new ol.source.Vector({
+ format: new ol.format.GeoJSON(),
+ url: this.fetchApiURL(this.props.value.stoparea_id)
+ })
+ var feature = new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(this.props.value.longitude), parseFloat(this.props.value.latitude)]))
+ })
+
+ var defaultStyles = new ol.style.Style({
+ image: new ol.style.Circle(({
+ radius: 4,
+ fill: new ol.style.Fill({
+ color: '#004d87'
+ })
+ }))
+ })
+ var selectedStyles = new ol.style.Style({
+ image: new ol.style.Circle(({
+ radius: 6,
+ fill: new ol.style.Fill({
+ color: '#da2f36'
+ })
+ }))
+ })
+
+ var centerLayer = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ features: [feature]
+ }),
+ style: selectedStyles,
+ zIndex: 2
+ })
+ var vectorLayer = new ol.layer.Vector({
+ source: source,
+ style: defaultStyles,
+ zIndex: 1
+ });
+
+ var map = new ol.Map({
+ target: 'stoppoint_map' + this.props.index,
+ layers: [
+ new ol.layer.Tile({
+ source: new ol.source.OSM()
+ }),
+ vectorLayer,
+ centerLayer
+ ],
+ controls: [ new ol.control.ScaleLine() ],
+ interactions: ol.interaction.defaults({
+ dragPan: false,
+ doubleClickZoom: false,
+ shiftDragZoom: false,
+ mouseWheelZoom: false
+ }),
+ view: new ol.View({
+ center: ol.proj.fromLonLat([parseFloat(this.props.value.longitude), parseFloat(this.props.value.latitude)]),
+ zoom: 18
+ })
+ });
+
+ // Selectable marker
+ var select = new ol.interaction.Select({
+ style: selectedStyles
+ });
+
+ map.addInteraction(select);
+
+ select.on('select', function(e) {
+ feature.setStyle(defaultStyles);
+ centerLayer.setZIndex(0);
+
+ if(e.selected.length != 0) {
+
+ if(e.selected[0].getGeometry() == feature.getGeometry()) {
+ if(e.selected[0].style_.image_.fill_.color_ != '#da2f36'){
+ feature.setStyle(selectedStyles);
+ centerLayer.setZIndex(2);
+ e.preventDefault()
+ return false
+ }
+ }
+ let data = _.assign({}, e.selected[0].getProperties(), {geometry: undefined});
+
+ this.props.onSelectMarker(this.props.index, data)
+ } else {
+ this.props.onUnselectMarker(this.props.index)
+ }
+ }, this);
+ }
+ }
+
+ render() {
+ if (this.props.value.olMap.isOpened) {
+ return (
+ <div className='map_container'>
+ <div className='map_metas'>
+ <p>
+ <strong>{this.props.value.olMap.json.name}</strong>
+ </p>
+ <p>
+ <strong>{this.context.I18n.routes.edit.stop_point_type} : </strong>
+ {this.props.value.olMap.json.area_type}
+ </p>
+ <p>
+ <strong>{this.context.I18n.routes.edit.short_name} : </strong>
+ {this.props.value.olMap.json.short_name}
+ </p>
+ <p>
+ <strong>{this.context.I18n.id_reflex} : </strong>
+ {this.props.value.olMap.json.user_objectid}
+ </p>
+
+ <p><strong>{this.context.I18n.routes.edit.map.coordinates} : </strong></p>
+ <p style={{paddingLeft: 10, marginTop: 0}}>
+ <em>{this.context.I18n.routes.edit.map.proj}.: </em>WSG84<br/>
+ <em>{this.context.I18n.routes.edit.map.lat}.: </em>{this.props.value.olMap.json.latitude} <br/>
+ <em>{this.context.I18n.routes.edit.map.lon}.: </em>{this.props.value.olMap.json.longitude}
+ </p>
+ <p>
+ <strong>{this.context.I18n.routes.edit.map.postal_code} : </strong>
+ {this.props.value.olMap.json.zip_code}
+ </p>
+ <p>
+ <strong>{this.context.I18n.routes.edit.map.city} : </strong>
+ {this.props.value.olMap.json.city_name}
+ </p>
+ <p>
+ <strong>{this.context.I18n.routes.edit.map.comment} : </strong>
+ {this.props.value.olMap.json.comment}
+ </p>
+ {(this.props.value.stoparea_id != this.props.value.olMap.json.stoparea_id) &&(
+ <div className='btn btn-outline-primary btn-sm'
+ onClick= {() => {this.props.onUpdateViaOlMap(this.props.index, this.props.value.olMap.json)}}
+ >{this.context.I18n.actions.select}</div>
+ )}
+ </div>
+ <div className='map_content'>
+ <div id={"stoppoint_map" + this.props.index} className='map'></div>
+ </div>
+ </div>
+ )
+ } else {
+ return false
+ }
+ }
+}
+
+OlMap.PropTypes = {
+}
+
+OlMap.contextTypes = {
+ I18n: PropTypes.object
+}
diff --git a/app/javascript/routes/components/StopPoint.js b/app/javascript/routes/components/StopPoint.js
new file mode 100644
index 000000000..606121f99
--- /dev/null
+++ b/app/javascript/routes/components/StopPoint.js
@@ -0,0 +1,94 @@
+import React, { PropTypes } from 'react'
+import BSelect2 from './BSelect2'
+import OlMap from './OlMap'
+
+export default function StopPoint(props, {I18n}) {
+ return (
+ <div className='nested-fields'>
+ <div className='wrapper'>
+ <div style={{width: 90}}>
+ <span>{props.value.user_objectid}</span>
+ </div>
+
+ <div>
+ <BSelect2 id={'route_stop_points_' + props.id} value={props.value} onChange={props.onChange} index={props.index} />
+ </div>
+
+ <div>
+ <select className='form-control' value={props.value.for_boarding} id="for_boarding" onChange={props.onSelectChange}>
+ <option value="normal">{I18n.routes.edit.stop_point.boarding.normal}</option>
+ <option value="forbidden">{I18n.routes.edit.stop_point.boarding.forbidden}</option>
+ </select>
+ </div>
+
+ <div>
+ <select className='form-control' value={props.value.for_alighting} id="for_alighting" onChange={props.onSelectChange}>
+ <option value="normal">{I18n.routes.edit.stop_point.alighting.normal}</option>
+ <option value="forbidden">{I18n.routes.edit.stop_point.alighting.forbidden}</option>
+ </select>
+ </div>
+
+ <div className='actions-5'>
+ <div
+ className={'btn btn-link' + (props.value.stoparea_id ? '' : ' disabled')}
+ onClick={props.onToggleMap}
+ >
+ <span className='fa fa-map-marker'></span>
+ </div>
+
+ <div
+ className={'btn btn-link' + (props.first ? ' disabled' : '')}
+ onClick={props.onMoveUpClick}
+ >
+ <span className='fa fa-arrow-up'></span>
+ </div>
+ <div
+ className={'btn btn-link' + (props.last ? ' disabled' : '')}
+ onClick={props.onMoveDownClick}
+ >
+ <span className='fa fa-arrow-down'></span>
+ </div>
+
+ <div
+ className='btn btn-link'
+ onClick={props.onToggleEdit}
+ >
+ <span className={'fa' + (props.value.edit ? ' fa-check' : ' fa-pencil')}></span>
+ </div>
+ <div
+ className='btn btn-link'
+ onClick={props.onDeleteClick}
+ >
+ <span className='fa fa-trash text-danger'></span>
+ </div>
+ </div>
+ </div>
+
+ <OlMap
+ value = {props.value}
+ index = {props.index}
+ onSelectMarker = {props.onSelectMarker}
+ onUnselectMarker = {props.onUnselectMarker}
+ onUpdateViaOlMap = {props.onUpdateViaOlMap}
+ />
+ </div>
+ )
+}
+
+StopPoint.PropTypes = {
+ onToggleMap: PropTypes.func.isRequired,
+ onToggleEdit: PropTypes.func.isRequired,
+ 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
+}
+
+StopPoint.contextTypes = {
+ I18n: PropTypes.object
+} \ No newline at end of file
diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js
new file mode 100644
index 000000000..68af16f57
--- /dev/null
+++ b/app/javascript/routes/components/StopPointList.js
@@ -0,0 +1,69 @@
+import React, { PropTypes } from 'react'
+import StopPoint from './StopPoint'
+
+export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange, onToggleMap, onToggleEdit, onSelectMarker, onUnselectMarker, onUpdateViaOlMap }, {I18n}) {
+ return (
+ <div className='subform'>
+ <div className='nested-head'>
+ <div className="wrapper">
+ <div style={{width: 100}}>
+ <div className="form-group">
+ <label className="control-label">{I18n.reflex_id}</label>
+ </div>
+ </div>
+ <div>
+ <div className="form-group">
+ <label className="control-label">{I18n.simple_form.labels.stop_point.name}</label>
+ </div>
+ </div>
+ <div>
+ <div className="form-group">
+ <label className="control-label">{I18n.simple_form.labels.stop_point.for_boarding}</label>
+ </div>
+ </div>
+ <div>
+ <div className="form-group">
+ <label className="control-label">{I18n.simple_form.labels.stop_point.for_alighting}</label>
+ </div>
+ </div>
+ <div className='actions-5'></div>
+ </div>
+ </div>
+ {stopPoints.map((stopPoint, index) =>
+ <StopPoint
+ key={'item-' + index}
+ onDeleteClick={() => onDeleteClick(index)}
+ onMoveUpClick={() => {
+ onMoveUpClick(index)
+ }}
+ onMoveDownClick={() => onMoveDownClick(index)}
+ onChange={ onChange }
+ onSelectChange={ (e) => onSelectChange(e, index) }
+ onToggleMap={() => onToggleMap(index)}
+ onToggleEdit={() => onToggleEdit(index)}
+ onSelectMarker={onSelectMarker}
+ onUnselectMarker={onUnselectMarker}
+ onUpdateViaOlMap={onUpdateViaOlMap}
+ first={ index === 0 }
+ last={ index === (stopPoints.length - 1) }
+ index={ index }
+ value={ stopPoint }
+ />
+ )}
+ </div>
+ )
+}
+
+StopPointList.PropTypes = {
+ stopPoints: PropTypes.array.isRequired,
+ onDeleteClick: PropTypes.func.isRequired,
+ onMoveUpClick: PropTypes.func.isRequired,
+ onMoveDownClick: PropTypes.func.isRequired,
+ onSelectChange: PropTypes.func.isRequired,
+ onSelectMarker: PropTypes.func.isRequired,
+ onUnselectMarker : PropTypes.func.isRequired
+}
+
+StopPointList.contextTypes = {
+ I18n: PropTypes.object
+} \ No newline at end of file