aboutsummaryrefslogtreecommitdiffstats
path: root/www/js/views
diff options
context:
space:
mode:
Diffstat (limited to 'www/js/views')
-rw-r--r--www/js/views/around.js502
-rw-r--r--www/js/views/details.js151
-rw-r--r--www/js/views/details_extra.js108
-rw-r--r--www/js/views/existing.js50
-rw-r--r--www/js/views/fms.js117
-rw-r--r--www/js/views/home.js40
-rw-r--r--www/js/views/locator.js69
-rw-r--r--www/js/views/login.js108
-rw-r--r--www/js/views/offline.js160
-rw-r--r--www/js/views/photo.js137
-rw-r--r--www/js/views/reports.js104
-rw-r--r--www/js/views/save_offline.js32
-rw-r--r--www/js/views/search.js81
-rw-r--r--www/js/views/sent.js44
-rw-r--r--www/js/views/submit.js480
15 files changed, 2183 insertions, 0 deletions
diff --git a/www/js/views/around.js b/www/js/views/around.js
new file mode 100644
index 0000000..57b4bc6
--- /dev/null
+++ b/www/js/views/around.js
@@ -0,0 +1,502 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ AroundView: FMS.LocatorView.extend({
+ template: 'around',
+ id: 'around-page',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick #locate_cancel': 'goSearch',
+ 'vclick #login-options': 'goLogin',
+ 'vclick #view-my-reports': 'goReports',
+ 'vclick #search': 'goSearch',
+ 'vclick .ui-input-clear': 'clearSearchErrors',
+ 'blur #pc': 'clearSearchErrors',
+ 'vclick #relocate': 'centerMapOnPosition',
+ 'vclick #cancel': 'onClickCancel',
+ 'vclick #confirm-map': 'onClickReport',
+ 'vclick #mark-here': 'onClickMark',
+ 'vclick #locate-here': 'onClickMark',
+ 'vclick #reposition': 'onClickReposition',
+ 'vclick a.address': 'goAddress',
+ 'submit #postcodeForm': 'search'
+ },
+
+ render: function(){
+ if ( !this.template ) {
+ FMS.printDebug('no template to render');
+ return;
+ }
+ template = _.template( tpl.get( this.template ) );
+ if ( this.model ) {
+ this.$el.html(template({ model: this.model.toJSON(), user: FMS.currentUser.toJSON() }));
+ } else {
+ this.$el.html(template());
+ }
+ this.afterRender();
+ return this;
+ },
+
+ beforeDisplay: function() {
+ this.origPcPlaceholder = $('#pc').attr('placeholder');
+ $('a[data-role="button"]').hide();
+ $('#view-my-reports').hide();
+ $('#login-options').hide();
+ $('#postcodeForm').hide();
+ $('#relocate').hide();
+ $('#cancel').hide();
+ $('#map_box').removeClass('background-map');
+ this.fixPageHeight();
+ $('#map_box').on('touchend', function() { if ( ! $('#popup').length ) { $('#OpenLayers_Control_Crosshairs_crosshairs').show(); } } );
+ },
+
+ afterDisplay: function() {
+ if ( FMS.isOffline ) {
+ $('#locating').hide();
+ this.navigate( 'offline' );
+ } else if ( this.model && this.model.get('lat') ) {
+ var modelInfo = { coordinates: { latitude: this.model.get('lat'), longitude: this.model.get('lon') } };
+ this.setMapPosition(modelInfo);
+ this.displayButtons(true);
+ this.setReportPosition({ lat: this.model.get('lat'), lon: this.model.get('lon') }, true);
+ this.listenTo(FMS.locator, 'gps_current_position', this.positionUpdate);
+ FMS.locator.trackPosition();
+ } else if ( FMS.currentPosition ) {
+ var info = { coordinates: FMS.currentPosition };
+ FMS.currentPosition = null;
+ if ( !fixmystreet.map ) {
+ this.setMapPosition(info);
+ }
+ this.displayButtons(false);
+ this.listenTo(FMS.locator, 'gps_current_position', this.positionUpdate);
+ FMS.locator.trackPosition();
+ } else {
+ this.locate();
+ this.displayButtons(false);
+ }
+ },
+
+ _back: function(e) {
+ if ( $('#confirm-map').css('display') == 'block' ) {
+ this.onClickCancel(e);
+ } else {
+ navigator.app.exitApp();
+ }
+ },
+
+ setMapPosition: function( info ) {
+ var coords = info.coordinates;
+ fixmystreet.latitude = coords.latitude;
+ fixmystreet.longitude = coords.longitude;
+
+ if ( !fixmystreet.map ) {
+ show_map();
+ } else {
+ FMS.currentPosition = coords;
+ var centre = this.projectCoords( coords );
+ fixmystreet.map.panTo(centre);
+ }
+ },
+
+ gotLocation: function( info ) {
+ $('#relocate').show();
+ this.finishedLocating();
+
+ this.listenTo(FMS.locator, 'gps_current_position', this.positionUpdate);
+
+ this.located = true;
+ this.locateCount = 21;
+
+ this.setMapPosition( info );
+
+ FMS.locator.trackPosition();
+ // FIXME: not sure why I need to do this
+ fixmystreet.select_feature.deactivate();
+ fixmystreet.select_feature.activate();
+ fixmystreet.nav.activate();
+ this.displayHelpIfFirstTime();
+ },
+
+ positionUpdate: function( info ) {
+ if ( $('#front-howto').is(':hidden') ) {
+ $('#relocate').show();
+ }
+ FMS.currentPosition = info.coordinates;
+ var centre = this.projectCoords( info.coordinates );
+
+ var point = new OpenLayers.Geometry.Point( centre.lon, centre.lat );
+
+ fixmystreet.location.removeAllFeatures();
+ var x = new OpenLayers.Feature.Vector(
+ point,
+ {},
+ {
+ graphicZIndex: 3000,
+ graphicName: 'circle',
+ 'externalGraphic': 'images/gps-marker.svg',
+ pointRadius: 16
+ }
+ );
+ fixmystreet.location.addFeatures([ x ]);
+ },
+
+ centerMapOnPosition: function(e) {
+ e.preventDefault();
+ if ( !fixmystreet.map ) {
+ return;
+ }
+
+ // if there isn't a currentPosition then something
+ // is up so we probably should not recenter
+ if ( FMS.currentPosition ) {
+ fixmystreet.map.panTo(this.projectCoords( FMS.currentPosition ));
+
+ // If we've confirmed the report position then we should be able
+ // to reposition it if we've moved the map.
+ if ( $('#confirm-map').css('display') == 'block' ) {
+ var currentPos = this.projectCoords(FMS.currentPosition);
+ var markerPos = this.getMarkerPosition(true);
+
+ // Displaying the button if the report is in the same place as the
+ // GPS location could be confusing so check they are different.
+ // The slight margin of error is there to account for both rounding
+ // wiggle in the projectCoords and also so that small changes due to
+ // GPS noise are ignored
+ if ( Math.abs(markerPos.lat - currentPos.lat) > 1 ||
+ Math.abs(markerPos.lon - currentPos.lon) > 1 ) {
+ $('#reposition').show();
+ }
+ }
+ }
+ },
+
+ failedLocation: function( details ) {
+ this.finishedLocating();
+ this.locateCount = 21;
+ var msg = '';
+ if ( details.msg ) {
+ msg = details.msg;
+ } else {
+ msg = FMS.strings.location_problem;
+ }
+ if ( !fixmystreet.map ) {
+ $('#relocate').hide();
+ $('#mark-here').hide();
+ // if we are going to display the help then we don't want to focus on
+ // the search box as it will show through the help
+ if ( FMS.usedBefore ) {
+ $('#pc').attr('placeholder', FMS.strings.search_placeholder).focus();
+ }
+ }
+ $('#front-howto').html('<p>' + msg + '</p>');
+ $('#front-howto').show();
+
+ this.displayHelpIfFirstTime();
+ },
+
+ displayHelpIfFirstTime: function() {
+ if ( !FMS.usedBefore ) {
+ FMS.helpShow();
+ }
+ },
+
+ displayButtons: function(isLocationSet) {
+ if ( fixmystreet.map ) {
+ fixmystreet.nav.activate();
+ fixmystreet.actionafterdrag.activate();
+ }
+ if (isLocationSet) {
+ $('#cancel').addClass('ui-btn-left').show();
+ $('#confirm-map').show();
+ $('#view-my-reports').hide();
+ $('#login-options').hide();
+ $('#mark-here').hide();
+ $('#locate-here').hide();
+ $('#postcodeForm').hide();
+ if ( fixmystreet.map ) {
+ fixmystreet.markers.setVisibility(false);
+ fixmystreet.select_feature.deactivate();
+ fixmystreet.bbox_strategy.deactivate();
+ }
+ } else {
+ if ( FMS.currentDraft.isPartial() ) {
+ $('#cancel').addClass('ui-btn-left').show();
+ $('#view-my-reports').hide();
+ $('#login-options').hide();
+ $('#locate-here').show();
+ } else {
+ $('#cancel').hide().removeClass('ui-btn-left');
+ $('#view-my-reports').show();
+ $('#login-options').show();
+ $('#mark-here').show();
+ $('#locate-here').hide();
+ }
+ $('#confirm-map').hide();
+ $('#postcodeForm').show();
+ $('#reposition').hide();
+ if ( fixmystreet.map ) {
+ fixmystreet.bbox_strategy.activate();
+ fixmystreet.report_location.setVisibility(false);
+ fixmystreet.markers.setVisibility(true);
+ fixmystreet.select_feature.deactivate();
+ fixmystreet.select_feature.activate();
+ }
+ }
+ },
+
+ setReportPosition: function(lonlat, convertPosition) {
+ var markers = fms_markers_list( [ [ lonlat.lat, lonlat.lon, 'green', 'location', '', 'location' ] ], convertPosition );
+ fixmystreet.report_location.removeAllFeatures();
+ fixmystreet.report_location.addFeatures( markers );
+ fixmystreet.report_location.setVisibility(true);
+ },
+
+ onClickMark: function(e) {
+ e.preventDefault();
+ this.clearSearchErrors();
+ this.displayButtons(true);
+ $('#popup').hide();
+ $('#OpenLayers_Control_Crosshairs_crosshairs').show();
+ $('#reposition').hide();
+
+ var lonlat = this.getCrossHairPosition();
+ this.setReportPosition(lonlat, true);
+ },
+
+ onClickCancel: function(e) {
+ e.preventDefault();
+ fixmystreet.markers.removeAllFeatures();
+ fixmystreet_activate_drag();
+ // force pins to be refetched and displayed
+ fixmystreet.bbox_strategy.update({force: true});
+ if ( this.model.isPartial() ) {
+ FMS.clearCurrentDraft();
+ } else {
+ // it's not partial but we've created a draft anyway so
+ // delete it
+ if ( this.model.id ) {
+ var del = FMS.removeDraft( this.model.id, true );
+ var that = this;
+ del.done( function() { that.decrementDraftCount(); } );
+ }
+ this.model.set('lat', null);
+ this.model.set('lon', null);
+ }
+ this.displayButtons(false);
+ },
+
+ decrementDraftCount: function() {
+ var counter = $('#view-my-reports .draft_count');
+ var count = counter.text();
+ count--;
+ counter.text(count);
+ },
+
+ onClickReposition: function(e) {
+ e.preventDefault();
+ var lonlat = this.getCrossHairPosition();
+ lonlat.transform(
+ new OpenLayers.Projection("EPSG:4326"),
+ fixmystreet.map.getProjectionObject()
+ );
+ fixmystreet.report_location.features[0].move(lonlat);
+ $('#reposition').hide();
+ },
+
+ onClickReport: function(e) {
+ e.preventDefault();
+ var position = this.getMarkerPosition();
+
+ if ( FMS.isOffline ) {
+ this.stopListening(FMS.locator);
+ FMS.locator.stopTracking();
+ // these may be out of the area but lets just save them
+ // for now and they can be checked when we are online.
+ this.model.set('lat', position.lat );
+ this.model.set('lon', position.lon );
+ FMS.saveCurrentDraft();
+ this.navigate( 'offline' );
+ } else {
+ this.listenTo(FMS.locator, 'gps_located', this.goPhoto);
+ this.listenTo(FMS.locator, 'gps_failed', this.locationCheckFailed );
+ FMS.locator.check_location( { latitude: position.lat, longitude: position.lon } );
+ }
+ },
+
+ search: function(e) {
+ $('#pc').blur();
+ // this is to stop form submission
+ e.preventDefault();
+ $('#front-howto').hide();
+ this.clearSearchErrors();
+ this.clearValidationErrors();
+ var pc = this.$('#pc').val();
+ this.listenTo(FMS.locator, 'search_located', this.searchSuccess );
+ this.listenTo(FMS.locator, 'search_failed', this.searchFail);
+
+ FMS.locator.lookup(pc);
+ },
+
+ searchSuccess: function( info ) {
+ this.stopListening(FMS.locator, 'search_located');
+ this.stopListening(FMS.locator, 'search_failed');
+ var coords = info.coordinates;
+ if ( fixmystreet.map ) {
+ fixmystreet.map.panTo(this.projectCoords( coords ));
+ } else {
+ this.setMapPosition(info);
+ this.displayButtons(false);
+ }
+ },
+
+ goAddress: function(e) {
+ $('#relocate').show();
+ $('#front-howto').html('').hide();
+ var t = $(e.target);
+ var lat = t.attr('data-lat');
+ var long = t.attr('data-long');
+
+ var coords = { latitude: lat, longitude: long };
+ if ( fixmystreet.map ) {
+ fixmystreet.map.panTo(this.projectCoords( coords ));
+ } else {
+ this.setMapPosition({ coordinates: coords });
+ }
+ },
+
+ searchError: function(msg) {
+ if ( msg.length < 30 ) {
+ $('#pc').attr('placeholder', msg).addClass('error');;
+ } else {
+ $('#front-howto').html(msg);
+ $('#relocate').hide();
+ $('#front-howto').show();
+ }
+ },
+
+ clearSearchErrors: function() {
+ $('#pc').attr('placeholder', this.origPcPlaceholder).removeClass('error');;
+ if ( fixmystreet.map ) {
+ $('#front-howto').hide();
+ $('#relocate').show();
+ }
+ },
+
+ searchFail: function( details ) {
+ // this makes sure any onscreen keyboard is dismissed
+ $('#submit').focus();
+ this.stopListening(FMS.locator, 'search_located');
+ this.stopListening(FMS.locator, 'search_failed');
+ if ( details.msg ) {
+ this.searchError( details.msg );
+ } else if ( details.locations ) {
+ var multiple = '';
+ for ( var i = 0; i < details.locations.length; i++ ) {
+ var loc = details.locations[i];
+ var li = '<li><a class="address" id="location_' + i + '" data-lat="' + loc.lat + '" data-long="' + loc.long + '">' + loc.address + '</a></li>';
+ multiple = multiple + li;
+ }
+ $('#front-howto').html('<p>Multiple matches found</p><ul data-role="listview" data-inset="true">' + multiple + '</ul>');
+ $('.ui-page').trigger('create');
+ $('#relocate').hide();
+ $('#front-howto').show();
+ } else {
+ this.searchError( FMS.strings.location_problem );
+ }
+ },
+
+ pauseMap: function() {
+ this.stopListening(FMS.locator);
+ FMS.locator.stopTracking();
+ if ( FMS.iPhoneModel > 3 ) {
+ $('#map_box').addClass('background-map');
+ }
+ $('#map_box').off('touchend');
+ if ( fixmystreet.map ) {
+ fixmystreet.nav.deactivate();
+ fixmystreet.actionafterdrag.deactivate();
+ }
+ },
+
+ goPhoto: function(info) {
+ this.pauseMap();
+ this.model.set('lat', info.coordinates.latitude );
+ this.model.set('lon', info.coordinates.longitude );
+ this.model.set('categories', info.details.category );
+ if ( info.details.titles_list ) {
+ this.model.set('titles_list', info.details.titles_list);
+ }
+ FMS.saveCurrentDraft();
+
+ this.navigate( 'photo' );
+ },
+
+ locationCheckFailed: function() {
+ this.displayAlert(FMS.strings.location_check_failed);
+ },
+
+ goSearch: function(e) {
+ e.preventDefault();
+ if ( !fixmystreet.map ) {
+ this.$('#mark-here').hide();
+ this.$('#relocate').hide();
+ $('#front-howto').html('<p>' + FMS.strings.locate_dismissed + '</p>');
+ $('#front-howto').show();
+ }
+ this.finishedLocating();
+ },
+
+ goLogin: function(e) {
+ e.preventDefault();
+ this.pauseMap();
+ this.navigate( 'login' );
+ },
+
+ goReports: function(e) {
+ e.preventDefault();
+ this.pauseMap();
+ this.navigate( 'reports' );
+ },
+
+ getCrossHairPosition: function() {
+ var cross = fixmystreet.map.getControlsByClass(
+ "OpenLayers.Control.Crosshairs");
+
+ var position = cross[0].getMapPosition();
+ position.transform(
+ fixmystreet.map.getProjectionObject(),
+ new OpenLayers.Projection("EPSG:4326")
+ );
+
+ return position;
+ },
+
+ getMarkerPosition: function(skipTransform) {
+ var marker = fixmystreet.report_location.features[0].geometry;
+
+ var position = new OpenLayers.LonLat( marker.x, marker.y );
+ if ( skipTransform ) {
+ return position;
+ }
+ position.transform(
+ fixmystreet.map.getProjectionObject(),
+ new OpenLayers.Projection("EPSG:4326")
+ );
+
+ return position;
+ },
+
+ projectCoords: function( coords ) {
+ var centre = new OpenLayers.LonLat( coords.longitude, coords.latitude );
+ centre.transform(
+ new OpenLayers.Projection("EPSG:4326"),
+ fixmystreet.map.getProjectionObject()
+ );
+
+ return centre;
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/details.js b/www/js/views/details.js
new file mode 100644
index 0000000..9f03d58
--- /dev/null
+++ b/www/js/views/details.js
@@ -0,0 +1,151 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ DetailsView: FMS.FMSView.extend({
+ template: 'details',
+ id: 'details-page',
+ prev: 'photo',
+ next: 'submit-start',
+ bottomMargin: -20,
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext',
+ 'blur textarea': 'updateCurrentReport',
+ 'change select': 'updateSelect',
+ 'blur input': 'updateCurrentReport'
+ },
+
+ afterRender: function() {
+ this.$('#form_category').attr('data-role', 'none');
+
+ if ( this.model.get('category') ) {
+ this.$('#form_category').val( this.model.get('category') );
+ }
+ this.setSelectClass();
+
+ },
+
+ beforeDisplay: function() {
+ this.fixPageHeight();
+ var header = this.$("div[data-role='header']:visible"),
+ detail = this.$('#form_detail'),
+ top = detail.position().top,
+ viewHeight = $(window).height(),
+ contentHeight = viewHeight - header.outerHeight() + 15;
+
+ detail.height( contentHeight - top );
+ },
+
+ onClickButtonPrev: function(e) {
+ e.preventDefault();
+ this.updateCurrentReport();
+ this.navigate( this.prev, true );
+ },
+
+ onClickButtonNext: function(e) {
+ e.preventDefault();
+ // dismiss on screen keyboard
+ $('.ui-btn-right').focus();
+ this.clearValidationErrors();
+ var valid = 1;
+
+ if ( !$('#form_title').val() ) {
+ valid = 0;
+ this.validationError( 'form_title', FMS.validationStrings.title );
+ }
+
+ if ( !$('#form_detail').val() ) {
+ valid = 0;
+ this.validationError( 'form_detail', FMS.validationStrings.detail );
+ }
+
+ var cat = $('#form_category').val();
+ if ( cat == '-- Pick a category --' ) {
+ valid = 0;
+ this.validationError( 'form_category', FMS.validationStrings.category );
+ }
+
+ if ( valid ) {
+ this.clearValidationErrors();
+ this.updateCurrentReport();
+ if ( FMS.isOffline ) {
+ this.navigate( 'save_offline' );
+ } else {
+ var that = this;
+ $.ajax( {
+ url: CONFIG.FMS_URL + '/report/new/category_extras',
+ type: 'POST',
+ data: {
+ category: this.model.get('category'),
+ latitude: this.model.get('lat'),
+ longitude: this.model.get('lon')
+ },
+ dataType: 'json',
+ timeout: 30000,
+ success: function( data, status ) {
+ if ( data && data.category_extra && data.category_extra.length > 0 ) {
+ that.model.set('category_extras', data.category_extra);
+ that.navigate('details_extra');
+ } else {
+ that.navigate( that.next );
+ }
+ },
+ error: function() {
+ that.displayAlert(FMS.strings.category_extra_check_error);
+ }
+ } );
+ }
+ }
+ },
+
+ validationError: function(id, error) {
+ var el_id = '#' + id;
+ var el = $(el_id);
+
+ el.addClass('error');
+ if ( el.val() === '' ) {
+ el.attr('orig-placeholder', el.attr('placeholder'));
+ el.attr('placeholder', error);
+ }
+ },
+
+ clearValidationErrors: function() {
+ $('.error').removeClass('error');
+ $('.error').each(function(el) { if ( el.attr('orig-placeholder') ) { el.attr('placeholder', el.attr('orig-placeholder') ); } } );
+ },
+
+ setSelectClass: function() {
+ var cat = this.$('#form_category');
+ if ( cat.val() !== "" && cat.val() !== '-- Pick a category --' ) {
+ cat.removeClass('noselection');
+ } else {
+ cat.addClass('noselection');
+ }
+ },
+
+ updateSelect: function() {
+ this.updateCurrentReport();
+ this.setSelectClass();
+ },
+
+ updateCurrentReport: function() {
+ var category = $('#form_category').val();
+ if ( category === '-- Pick a category --' ) {
+ category = '';
+ }
+ if ( category && $('#form_title').val() && $('#form_detail').val() ) {
+ $('#next').addClass('page_complete_btn');
+ } else {
+ $('#next').removeClass('page_complete_btn');
+ }
+ this.model.set('category', category);
+ this.model.set('title', $('#form_title').val());
+ this.model.set('details', $('#form_detail').val());
+ FMS.saveCurrentDraft();
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/details_extra.js b/www/js/views/details_extra.js
new file mode 100644
index 0000000..160ff11
--- /dev/null
+++ b/www/js/views/details_extra.js
@@ -0,0 +1,108 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ DetailsExtraView: FMS.FMSView.extend({
+ template: 'details_extra',
+ id: 'details-extra-page',
+ prev: 'details',
+ next: 'submit-start',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext',
+ 'blur textarea': 'updateCurrentReport',
+ 'change select': 'updateCurrentReport',
+ 'blur input': 'updateCurrentReport'
+ },
+
+ afterRender: function() {
+ this.populateFields();
+ },
+
+ onClickButtonPrev: function() {
+ this.model.set('hasExtras', 0);
+ this.updateCurrentReport();
+ this.navigate( this.prev, true );
+ },
+
+ onClickButtonNext: function() {
+ this.clearValidationErrors();
+ var valid = 1;
+ var that = this;
+
+ var isRequired = function(index) {
+ var el = $(this);
+ if ( el.attr('required') && el.val() === '' ) {
+ valid = 0;
+ that.validationError(el.attr('id'), FMS.strings.required);
+ }
+ };
+ // do validation
+ $('input').each(isRequired);
+ $('textarea').each(isRequired);
+ $('select').each(isRequired);
+ this.model.set('hasExtras', 1);
+
+ if ( valid ) {
+ this.clearValidationErrors();
+ this.updateCurrentReport();
+ this.navigate( this.next );
+ }
+ },
+
+ validationError: function(id, error) {
+ var el_id = '#' + id;
+ var el = $(el_id);
+
+ el.addClass('error');
+ if ( el.val() === '' ) {
+ el.attr('orig-placeholder', el.attr('placeholder'));
+ el.attr('placeholder', error);
+ }
+ },
+
+ clearValidationErrors: function() {
+ $('.error').removeClass('error');
+ $('.error').each(function(el) { if ( el.attr('orig-placeholder') ) { el.attr('placeholder', el.attr('orig-placeholder') ); } } );
+ },
+
+ updateSelect: function() {
+ this.updateCurrentReport();
+ },
+
+ updateCurrentReport: function() {
+ var fields = [];
+ var that = this;
+ var update = function(index) {
+ var el = $(this);
+ if ( el.val() !== '' ) {
+ that.model.set(el.attr('name'), el.val());
+ fields.push(el.attr('name'));
+ } else {
+ that.model.set(el.attr('name'), '');
+ }
+
+ };
+
+ $('input').each(update);
+ $('select').each(update);
+ $('textarea').each(update);
+
+ this.model.set('extra_details', fields);
+ FMS.saveCurrentDraft();
+ },
+
+ populateFields: function() {
+ var that = this;
+ var populate = function(index) {
+ that.$(this).val(that.model.get(that.$(this).attr('name')));
+ };
+ this.$('input').each(populate);
+ this.$('select').each(populate);
+ this.$('textarea').each(populate);
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/existing.js b/www/js/views/existing.js
new file mode 100644
index 0000000..a34fd0b
--- /dev/null
+++ b/www/js/views/existing.js
@@ -0,0 +1,50 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ ExistingView: FMS.FMSView.extend({
+ template: 'existing',
+ id: 'existing',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick #use_report': 'useReport',
+ 'vclick #save_report': 'saveReport',
+ 'vclick #discard': 'discardReport'
+ },
+
+ _back: function() {
+ navigator.app.exitApp();
+ },
+
+ setHeight: function(content, height) {
+ content.css( 'min-height', content + 'px');
+ },
+
+ useReport: function(e) {
+ e.preventDefault();
+ FMS.setCurrentDraft(this.model);
+ this.navigate('around');
+ },
+
+ saveReport: function(e) {
+ e.preventDefault();
+ FMS.clearCurrentDraft();
+ this.navigate('around');
+ },
+
+ discardReport: function(e) {
+ e.preventDefault();
+ var reset = FMS.removeDraft(this.model.id, true);
+ var that = this;
+ reset.done( function() { that.onDraftRemove(); } );
+ reset.fail( function() { that.onDraftRemove(); } );
+ },
+
+ onDraftRemove: function() {
+ FMS.clearCurrentDraft();
+ this.navigate( 'around', 'left' );
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/fms.js b/www/js/views/fms.js
new file mode 100644
index 0000000..1b51a27
--- /dev/null
+++ b/www/js/views/fms.js
@@ -0,0 +1,117 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ FMSView: Backbone.View.extend({
+ tag: 'div',
+ bottomMargin: 20,
+ contentSelector: '[data-role="content"]',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext'
+ },
+
+ back: function(e) {
+ if ( $('#help #dismiss').is(':visible') ) {
+ FMS.helpHide();
+ } else if ( this._back ) {
+ this._back(e);
+ } else if ( this.prev ) {
+ this.onClickButtonPrev(e);
+ }
+ },
+
+ render: function(){
+ if ( !this.template ) {
+ FMS.printDebug('no template to render');
+ return;
+ }
+ template = _.template( tpl.get( this.template ) );
+ var args = null;
+ if ( this.options.msg ) {
+ args = { msg: this.options.msg };
+ }
+ if ( this.model ) {
+ if ( args ) {
+ args.model = this.model.toJSON();
+ } else {
+ args = this.model.toJSON();
+ }
+ }
+ this.$el.html(template(args));
+ this.afterRender();
+ return this;
+ },
+
+ fixPageHeight: function() {
+ var header = this.$("div[data-role='header']:visible"),
+ content = this.$(this.contentSelector),
+ top = content.position().top,
+ viewHeight = $(window).height(),
+ contentHeight = FMS.windowHeight - header.outerHeight() - this.bottomMargin;
+
+ this.setHeight( content, contentHeight - top );
+ },
+
+ setHeight: function(content, height) {
+ content.height(height);
+ },
+
+ afterRender: function() {},
+
+ beforeDisplay: function() {
+ this.fixPageHeight();
+ },
+
+ afterDisplay: function() {},
+
+ navigate: function( route, reverse ) {
+ if ( FMS.isAndroid ) {
+ var softkeyboard = window.plugins.SoftKeyBoard;
+ softkeyboard.hide();
+ }
+ if ( reverse ) {
+ FMS.router.reverseTransition();
+ }
+
+ FMS.router.navigate( route, { trigger: true } );
+ },
+
+ onClickButtonPrev: function(e) {
+ e.preventDefault();
+ this.navigate( this.prev, true );
+ },
+
+ onClickButtonNext: function(e) {
+ e.preventDefault();
+ this.navigate( this.next );
+ },
+
+ displayAlert: function(msg) {
+ navigator.notification.alert(msg, null, CONFIG.APP_NAME);
+ },
+
+ validationError: function( id, error ) {
+ var el_id = '#' + id;
+ var el = $(el_id);
+ var err = '<div for="' + id + '" class="form-error">' + error + '</div>';
+ if ( $('div[for='+id+']').length === 0 ) {
+ el.before(err);
+ el.addClass('form-error');
+ }
+ },
+
+ clearValidationErrors: function() {
+ $('div.form-error').remove();
+ $('.form-error').removeClass('form-error');
+ },
+
+ destroy: function() { FMS.printDebug('destory for ' + this.id); this._destroy(); this.remove(); },
+
+ _destroy: function() {}
+ })
+ });
+ _.extend( FMS.FMSView, Backbone.Events );
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/home.js b/www/js/views/home.js
new file mode 100644
index 0000000..998af1c
--- /dev/null
+++ b/www/js/views/home.js
@@ -0,0 +1,40 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ HomeView: FMS.FMSView.extend({
+ template: 'home',
+ id: 'front-page',
+
+ afterRender: function() {
+ /*
+ if ( !can_geolocate && ( !navigator.network || !navigator.network.connection ) ) {
+ geocheck_count++;
+ window.setTimeout( decide_front_page, 1000 );
+ return;
+ }
+
+ // sometime onDeviceReady does not fire so set this here to be sure
+ can_geolocate = true;
+
+ geocheck_count = 0;
+ */
+
+ $('#locating').show();
+
+ },
+
+ afterDisplay: function() {
+ $('#load-screen').hide();
+ if ( FMS.isOffline ) {
+ this.navigate( 'offline' );
+ } else if ( FMS.currentDraft && (
+ FMS.currentDraft.get('title') || FMS.currentDraft.get('lat') ||
+ FMS.currentDraft.get('details') || FMS.currentDraft.get('file') )
+ ) {
+ this.navigate( 'existing' );
+ } else {
+ this.navigate( 'around' );
+ }
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/locator.js b/www/js/views/locator.js
new file mode 100644
index 0000000..8e067a9
--- /dev/null
+++ b/www/js/views/locator.js
@@ -0,0 +1,69 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ LocatorView: FMS.FMSView.extend({
+ skipLocationCheck: false,
+
+ locate: function() {
+ $(document).delegate('.ui-content', 'touchmove', false);
+ $('#locating').show();
+ this.listenTo(FMS.locator, 'gps_located', this.gotLocation);
+ this.listenTo(FMS.locator, 'gps_failed', this.failedLocation);
+ this.listenTo(FMS.locator, 'gps_locating', this.locationUpdate);
+
+ FMS.locator.geolocate(CONFIG.ACCURACY, this.skipLocationCheck);
+ this.startLocateProgress();
+ },
+
+ startLocateProgress: function() {
+ this.located = false;
+ this.locateCount = 1;
+ var that = this;
+ window.setTimeout( function() {that.showLocateProgress();}, 1000);
+ },
+
+ locationUpdate: function( accuracy ) {
+ if ( accuracy && accuracy < 500 ) {
+ $('#progress-bar').css( 'background-color', 'orange' );
+ } else if ( accuracy && accuracy < 250 ) {
+ $('#progress-bar').css( 'background-color', 'yellow' );
+ } else {
+ $('#progress-bar').css( 'background-color', 'grey' );
+ }
+
+ $('#accuracy').text(parseInt(accuracy, 10) + 'm');
+ },
+
+ showLocateProgress: function() {
+ if ( $('#locating').css('display') == 'none' ) {
+ return;
+ }
+ if ( !this.located && this.locateCount > 20 ) {
+ var details = { msg: FMS.strings.geolocation_failed };
+ this.failedLocation(details);
+ return;
+ }
+ var percent = ( this.locateCount / 20 ) * 100;
+ $('#progress-bar').css( 'width', percent + '%' );
+ this.locateCount++;
+ var that = this;
+ window.setTimeout( function() {that.showLocateProgress();}, 1000);
+ },
+
+ finishedLocating: function() {
+ this.stopListening(FMS.locator, 'gps_locating');
+ this.stopListening(FMS.locator, 'gps_located');
+ this.stopListening(FMS.locator, 'gps_failed');
+ $(document).undelegate('.ui-content', 'touchmove', false);
+ $('#locating').hide();
+ },
+
+ failedLocation: function(details) {
+ this.finishedLocating();
+ },
+
+ gotLocation: function(info) {
+ this.finishedLocating();
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/login.js b/www/js/views/login.js
new file mode 100644
index 0000000..c0f16ba
--- /dev/null
+++ b/www/js/views/login.js
@@ -0,0 +1,108 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ LoginView: FMS.FMSView.extend({
+ template: 'login',
+ id: 'login',
+ next: 'around',
+ prev: 'around',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick #login': 'onClickLogin',
+ 'submit #signinForm': 'onClickLogin',
+ 'vclick #logout': 'onClickLogout',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext'
+ },
+
+ onClickLogin: function(e) {
+ // prevent form submission from onscreen keyboard
+ e.preventDefault();
+ $('#login').focus();
+ if ( this.validate() ) {
+ var that = this;
+ $.ajax( {
+ url: CONFIG.FMS_URL + '/auth/ajax/sign_in',
+ type: 'POST',
+ data: {
+ email: $('#form_email').val(),
+ password_sign_in: $('#form_password').val(),
+ remember_me: 1
+ },
+ dataType: 'json',
+ timeout: 30000,
+ success: function( data, status ) {
+ if ( data.name ) {
+ that.model.set('password', $('#form_password').val());
+ that.model.set('email', $('#form_email').val());
+ that.model.set('name', data.name);
+ that.model.save();
+ FMS.isLoggedIn = 1;
+ that.$('#password_row').hide();
+ that.$('#success_row').show();
+ } else {
+ that.validationError('signinForm', FMS.strings.login_details_error);
+ }
+ },
+ error: function() {
+ that.validationError('signinForm', FMS.strings.login_error);
+ }
+ } );
+ }
+ },
+
+ onClickLogout: function(e) {
+ e.preventDefault();
+ var that = this;
+ $.ajax( {
+ url: CONFIG.FMS_URL + '/auth/ajax/sign_out',
+ type: 'GET',
+ dataType: 'json',
+ timeout: 30000,
+ success: function( data, status ) {
+ FMS.isLoggedIn = 0;
+ that.model.set('password', '');
+ that.model.save();
+ that.$('#form_email').val('');
+ that.$('#form_password').val('');
+ that.$('#success_row').hide();
+ that.$('#signed_in_row').hide();
+ that.$('#password_row').show();
+ },
+ error: function() {
+ that.validationError('err', FMS.strings.logout_error);
+ }
+ } );
+ },
+
+ validate: function() {
+ this.clearValidationErrors();
+ var isValid = 1;
+
+ if ( !$('#form_password').val() ) {
+ isValid = 0;
+ this.validationError('form_password', FMS.validationStrings.password );
+ }
+
+ var email = $('#form_email').val();
+ if ( !email ) {
+ isValid = 0;
+ this.validationError('form_email', FMS.validationStrings.email.required);
+ // regexp stolen from jquery validate module
+ } else if ( ! /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(email) ) {
+ isValid = 0;
+ this.validationError('form_email', FMS.validationStrings.email.email);
+ }
+
+ if ( !isValid ) {
+ // this makes sure the onscreen keyboard is dismissed
+ $('#login').focus();
+ }
+
+ return isValid;
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/offline.js b/www/js/views/offline.js
new file mode 100644
index 0000000..5f25223
--- /dev/null
+++ b/www/js/views/offline.js
@@ -0,0 +1,160 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ OfflineView: FMS.LocatorView.extend({
+ template: 'offline',
+ id: 'offline',
+ prev: 'around',
+ next: 'reports',
+ skipLocationCheck: true,
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeShow',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext',
+ 'vclick #id_photo_button': 'takePhoto',
+ 'vclick #id_existing': 'addPhoto',
+ 'vclick #id_del_photo_button': 'deletePhoto',
+ 'vclick #locate': 'onClickLocate',
+ 'vclick #locate_cancel': 'onClickCancel',
+ 'blur input': 'toggleNextButton',
+ 'blur textarea': 'toggleNextButton'
+ },
+
+ _back: function() {
+ navigator.app.exitApp();
+ },
+
+ draftHasContent: function() {
+ var hasContent = false;
+
+ if ( $('#form_title').val() || $('#form_detail').val() ||
+ this.model.get('lat') || this.model.get('file') ) {
+ hasContent = true;
+ }
+
+ return hasContent;
+ },
+
+ afterDisplay: function() {
+ $('body')[0].scrollTop = 0;
+ $('div[data-role="content"]').show();
+ },
+
+ beforeShow: function() {
+ $('div[data-role="content"]').hide();
+ this.toggleNextButton();
+ },
+
+ toggleNextButton: function() {
+ if ( this.draftHasContent() ) {
+ $('#offline-next-btn .ui-btn-text').text('Save');
+ } else {
+ $('#offline-next-btn .ui-btn-text').text('Skip');
+ }
+ },
+
+ failedLocation: function(details) {
+ this.finishedLocating();
+ this.locateCount = 21;
+
+ $('#locate_result').html(FMS.strings.offline_failed_position);
+ },
+
+ gotLocation: function(info) {
+ this.finishedLocating();
+
+ this.model.set('lat', info.coordinates.latitude);
+ this.model.set('lon', info.coordinates.longitude);
+
+ $('#locate_result').html(FMS.strings.offline_got_position);
+ },
+
+ takePhoto: function() {
+ var that = this;
+ navigator.camera.getPicture( function(imgURI) { that.addPhotoSuccess(imgURI); }, function(error) { that.addPhotoFail(error); }, { saveToPhotoAlbum: true, quality: 49, destinationType: Camera.DestinationType.FILE_URI, sourceType: navigator.camera.PictureSourceType.CAMERA, correctOrientation: true });
+ },
+
+ addPhoto: function() {
+ var that = this;
+ navigator.camera.getPicture( function(imgURI) { that.addPhotoSuccess(imgURI); }, function(error) { that.addPhotoFail(error); }, { saveToPhotoAlbum: false, quality: 49, destinationType: Camera.DestinationType.FILE_URI, sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY, correctOrientation: true });
+ },
+
+ addPhotoSuccess: function(imgURI) {
+ var move = FMS.files.moveURI( imgURI );
+
+ var that = this;
+ move.done( function( file ) {
+ $('#photo').attr('src', file.toURL());
+ that.model.set('file', file.toURL());
+ FMS.saveCurrentDraft();
+
+ $('#photo-next-btn .ui-btn-text').text('Next');
+ $('#display_photo').show();
+ $('#add_photo').hide();
+ });
+
+ move.fail( function() { that.addPhotoFail(); } );
+ },
+
+ addPhotoFail: function() {
+ if ( message != 'no image selected' &&
+ message != 'Selection cancelled.' &&
+ message != 'Camera cancelled.' ) {
+ this.displayAlert(FMS.strings.photo_failed);
+ }
+ },
+
+ deletePhoto: function() {
+ var that = this;
+ var del = FMS.files.deleteURI( this.model.get('file') );
+
+ del.done( function() {
+ that.model.set('file', '');
+ FMS.saveCurrentDraft();
+ $('#photo').attr('src', '');
+
+ $('#photo-next-btn .ui-btn-text').text('Skip');
+ $('#display_photo').hide();
+ $('#add_photo').show();
+ });
+ },
+
+ onClickLocate: function(e) {
+ e.preventDefault();
+ this.locate();
+ },
+
+ onClickCancel: function(e) {
+ e.preventDefault();
+ this.finishedLocating();
+ },
+
+ onClickButtonNext: function() {
+ this.updateCurrentReport();
+ if ( !this.draftHasContent() && this.model.id ) {
+ var del = FMS.removeDraft( this.model.id );
+
+ var that = this;
+ del.done( function() { that.draftDeleted(); } );
+ del.fail( function() { that.draftDeleted(); } );
+ } else {
+ FMS.clearCurrentDraft();
+ this.navigate( this.next );
+ }
+ },
+
+ draftDeleted: function() {
+ FMS.clearCurrentDraft();
+ this.navigate( this.next );
+ },
+
+ updateCurrentReport: function() {
+ this.model.set('title', $('#form_title').val());
+ this.model.set('details', $('#form_detail').val());
+ FMS.saveCurrentDraft();
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/photo.js b/www/js/views/photo.js
new file mode 100644
index 0000000..f24207e
--- /dev/null
+++ b/www/js/views/photo.js
@@ -0,0 +1,137 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ PhotoView: FMS.FMSView.extend({
+ template: 'photo',
+ id: 'photo-page',
+ prev: 'around',
+ next: 'details',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext',
+ 'vclick #id_photo_button': 'takePhoto',
+ 'vclick #id_existing': 'addPhoto',
+ 'vclick #id_del_photo_button': 'deletePhoto'
+ },
+
+ beforeDisplay: function() {
+ this.fixPageHeight();
+ this.$('#id_del_photo_button').hide();
+ if ( this.model.get('file') ) {
+ $('#id_photo_button').parents('.ui-btn').hide();
+ $('#id_existing').parents('.ui-btn').hide();
+ window.setTimeout( function() { $('#id_del_photo_button').show(); }, 250 );
+ }
+ },
+
+ getOptions: function(isFromAlbum) {
+ var options = {
+ destinationType: Camera.DestinationType.FILE_URI,
+ sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY,
+ correctOrientation: true,
+ targetHeight: 768,
+ targetWidth: 1024
+ };
+
+ if ( ! isFromAlbum ) {
+ options.saveToPhotoAlbum = true;
+ options.sourceType = navigator.camera.PictureSourceType.CAMERA;
+ }
+
+ // this helps with out of memory errors on iPhones but not on Android it seems
+ if ( ! FMS.isAndroid ) {
+ options.quality = 49;
+ }
+
+ return options;
+ },
+
+ takePhoto: function(e) {
+ e.preventDefault();
+ $.mobile.loading('show');
+ $('#photo').hide();
+ var that = this;
+
+ var options = this.getOptions();
+
+ navigator.camera.getPicture( function(imgURI) { that.addPhotoSuccess(imgURI); }, function(error) { that.addPhotoFail(error); }, options);
+ },
+
+ addPhoto: function(e) {
+ e.preventDefault();
+ $.mobile.loading('show');
+ $('#photo').hide();
+ var that = this;
+ var options = this.getOptions(true);
+ navigator.camera.getPicture( function(imgURI) { that.addPhotoSuccess(imgURI); }, function(error) { that.addPhotoFail(error); }, options);
+ },
+
+ addPhotoSuccess: function(imgURI) {
+ var move;
+ // on iOS the photos go into a temp folder in the apps own filespace so we
+ // can move them, and indeed have to as the tmp space is cleaned out by the OS
+ // so draft reports might have their images removed. on android you access the
+ // images where they are stored on the filesystem so if you move, and then delete
+ // them, you are moving and deleting the only copy of them which is likely to be
+ // surprising and unwelcome so we copy them instead.
+ var fileName = CONFIG.NAMESPACE + '_' + this.model.cid + '_' + moment().unix() + '.jpg';
+ if ( FMS.isAndroid ) {
+ move = FMS.files.copyURI( imgURI, fileName );
+ } else {
+ move = FMS.files.moveURI( imgURI, fileName );
+ }
+
+ var that = this;
+ move.done( function( file ) {
+ $('#nophoto_title').hide();
+ $('#photo_title').html(FMS.strings.photo_added).show();
+ $('#photo').attr('src', file.toURL()).addClass('small').removeClass('placeholder');
+ that.model.set('file', file.toURL());
+ FMS.saveCurrentDraft();
+
+ $('#photo-next-btn .ui-btn-text').text('Next');
+ $('#id_photo_button').parents('.ui-btn').hide();
+ $('#id_existing').parents('.ui-btn').hide();
+ $('#photo').show();
+ window.setTimeout(function() { $('#id_del_photo_button').show() }, 500);
+ window.setTimeout(function() { $.mobile.loading('hide') }, 100);
+ });
+
+ move.fail( function() { that.addPhotoFail(); } );
+ },
+
+ addPhotoFail: function() {
+ $('#photo').show();
+ $.mobile.loading('hide');
+ if ( message != 'no image selected' &&
+ message != 'Selection cancelled.' &&
+ message != 'Camera cancelled.' ) {
+ this.displayAlert(FMS.strings.photo_failed);
+ }
+ },
+
+ deletePhoto: function(e) {
+ e.preventDefault();
+ var that = this;
+ var del = FMS.files.deleteURI( this.model.get('file') );
+
+ del.done( function() {
+ $('#photo_title').hide();
+ $('#nophoto_title').show();
+ $('#id_del_photo_button').hide();
+ that.model.set('file', '');
+ FMS.saveCurrentDraft(true);
+ $('#photo').attr('src', 'images/placeholder-photo.png').addClass('placeholder').removeClass('small');
+
+ $('#photo-next-btn .ui-btn-text').text('Skip');
+ $('#id_photo_button').parents('.ui-btn').show();
+ $('#id_existing').parents('.ui-btn').show();
+ });
+
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/reports.js b/www/js/views/reports.js
new file mode 100644
index 0000000..ff65700
--- /dev/null
+++ b/www/js/views/reports.js
@@ -0,0 +1,104 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ ReportsView: FMS.FMSView.extend({
+ template: 'reports',
+ id: 'reports',
+ next: 'around',
+ prev: 'around',
+ contentSelector: '#drafts',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .del_report': 'deleteReport',
+ 'vclick .use_report': 'useReport',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext'
+ },
+
+ onClickButtonPrev: function(e) {
+ $('#drafts').hide();
+ $('body')[0].scrollTop = 0;
+ e.preventDefault();
+ this.navigate( this.prev, true );
+ },
+
+ onClickButtonNext: function(e) {
+ $('#drafts').hide();
+ $('body')[0].scrollTop = 0;
+ e.preventDefault();
+ this.navigate( this.next );
+ },
+
+ deleteReport: function(e) {
+ e.preventDefault();
+ var el = $(e.target);
+ var id = el.parents('li').attr('id');
+ var del = FMS.removeDraft( id, true );
+ var that = this;
+ del.done( function() { that.onRemoveDraft(el); } );
+ del.fail( function() { that.onRemoveDraft(el); } );
+ },
+
+ setHeight: function(content, height) {
+ content.css( 'min-height', content + 'px');
+ },
+
+ beforeDisplay: function() {
+ if ( FMS.allDrafts.length === 0 ) {
+ $('#noreports').show();
+ } else {
+ $('#report-list').show();
+ }
+ },
+
+ useReport: function(e) {
+ e.preventDefault();
+ var el = $(e.target);
+ var id = el.parents('li').attr('id');
+ FMS.currentDraft = FMS.allDrafts.get(id);
+ $('#drafts').hide();
+ if ( FMS.currentDraft && FMS.currentDraft.get('lat') ) {
+ var coords = { latitude: FMS.currentDraft.get('lat'), longitude: FMS.currentDraft.get('lon') };
+ fixmystreet.latitude = coords.latitude;
+ fixmystreet.longitude = coords.longitude;
+
+ if ( fixmystreet.map ) {
+ var centre = new OpenLayers.LonLat( coords.longitude, coords.latitude );
+ centre.transform(
+ new OpenLayers.Projection("EPSG:4326"),
+ fixmystreet.map.getProjectionObject()
+ );
+
+ fixmystreet.map.panTo(centre);
+ }
+ }
+ this.navigate('around');
+ },
+
+ onRemoveDraft: function(el) {
+ el.parents('li').remove();
+ if ( FMS.allDrafts.length === 0 ) {
+ $('#report-list').hide();
+ $('#noreports').show();
+ }
+ },
+
+ render: function(){
+ if ( !this.template ) {
+ FMS.printDebug('no template to render');
+ return;
+ }
+ template = _.template( tpl.get( this.template ) );
+ if ( this.model ) {
+ this.$el.html(template({ model: this.model.toJSON(), drafts: FMS.allDrafts }));
+ } else {
+ this.$el.html(template());
+ }
+ this.afterRender();
+ return this;
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/save_offline.js b/www/js/views/save_offline.js
new file mode 100644
index 0000000..d00170c
--- /dev/null
+++ b/www/js/views/save_offline.js
@@ -0,0 +1,32 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SaveOfflineView: FMS.FMSView.extend({
+ template: 'save_offline',
+ id: 'save_offline',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick #save_report': 'saveReport',
+ 'vclick #discard': 'discardReport'
+ },
+
+ saveReport: function() {
+ FMS.clearCurrentDraft();
+ this.navigate('reports');
+ },
+
+ discardReport: function() {
+ var reset = FMS.removeDraft(FMS.currentDraft.id, true);
+ var that = this;
+ reset.done( function() { that.onDraftRemove(); } );
+ reset.fail( function() { that.onDraftRemove(); } );
+ },
+
+ onDraftRemove: function() {
+ this.navigate( 'around', 'left' );
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/search.js b/www/js/views/search.js
new file mode 100644
index 0000000..6930e2a
--- /dev/null
+++ b/www/js/views/search.js
@@ -0,0 +1,81 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SearchView: FMS.FMSView.extend({
+ template: 'address_search',
+ id: 'search-page',
+
+ events: {
+ 'vclick a.address': 'goAddress',
+ 'vclick #submit': 'search',
+ 'vclick #locate': 'goLocate',
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'submit #postcodeForm': 'search'
+ },
+
+ afterDisplay: function() {
+ if ( FMS.isOffline ) {
+ this.navigate('offline');
+ }
+ },
+
+ search: function(e) {
+ // this is to stop form submission
+ e.preventDefault();
+ this.clearValidationErrors();
+ var pc = this.$('#pc').val();
+ this.listenTo(FMS.locator, 'search_located', this.searchSuccess );
+ this.listenTo(FMS.locator, 'search_failed', this.searchFail);
+
+ FMS.locator.lookup(pc);
+ },
+
+ searchSuccess: function( info ) {
+ this.stopListening(FMS.locator);
+ var coords = info.coordinates;
+ FMS.currentPosition = coords;
+ this.navigate('around');
+ },
+
+ goAddress: function(e) {
+ var t = $(e.target);
+ var lat = t.attr('data-lat');
+ var long = t.attr('data-long');
+
+ FMS.currentPosition = { latitude: lat, longitude: long };
+ this.navigate('around');
+ },
+
+ searchFail: function( details ) {
+ // this makes sure any onscreen keyboard is dismissed
+ $('#submit').focus();
+ this.stopListening(FMS.locator);
+ if ( details.msg ) {
+ this.validationError( 'pc', details.msg );
+ } else if ( details.locations ) {
+ var multiple = '';
+ for ( var i = 0; i < details.locations.length; i++ ) {
+ var loc = details.locations[i];
+ var li = '<li><a class="address" id="location_' + i + '" data-lat="' + loc.lat + '" data-long="' + loc.long + '">' + loc.address + '</a></li>';
+ multiple = multiple + li;
+ }
+ $('#front-howto').html('<p>Multiple matches found</p><ul data-role="listview" data-inset="true">' + multiple + '</ul>');
+ $('.ui-page').trigger('create');
+ } else {
+ this.validationError( 'pc', FMS.strings.location_problem );
+ }
+ },
+
+ goLocate: function(e) {
+ e.preventDefault();
+ this.navigate( 'around' );
+ },
+
+ _destroy: function() {
+ delete FMS.searchMessage;
+ this.stopListening(FMS.locator);
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/sent.js b/www/js/views/sent.js
new file mode 100644
index 0000000..f25a178
--- /dev/null
+++ b/www/js/views/sent.js
@@ -0,0 +1,44 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SentView: FMS.FMSView.extend({
+ template: 'sent',
+ id: 'sent-page',
+ prev: 'around',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick #id_report_another': 'onClickButtonPrev',
+ 'vclick #open_report': 'onClickOpenReport',
+ 'vclick #rate_app': 'onClickRateApp'
+ },
+
+ render: function(){
+ if ( !this.template ) {
+ FMS.printDebug('no template to render');
+ return;
+ }
+ template = _.template( tpl.get( this.template ) );
+ this.$el.html(template(FMS.createdReport.toJSON()));
+ this.afterRender();
+ return this;
+ },
+
+ onClickOpenReport: function(e) {
+ e.preventDefault();
+ window.open(FMS.createdReport.get('site_url'), '_system');
+ return false;
+ },
+
+ onClickRateApp: function(e) {
+ e.preventDefault();
+ var el = $('#rate_app');
+ var href = el.attr('href');
+ window.open(href, '_system');
+ return false;
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
diff --git a/www/js/views/submit.js b/www/js/views/submit.js
new file mode 100644
index 0000000..6a7c946
--- /dev/null
+++ b/www/js/views/submit.js
@@ -0,0 +1,480 @@
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitView: FMS.FMSView.extend({
+ template: 'submit',
+ id: 'submit-page',
+ prev: 'details',
+ nopassword: 0,
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick .ui-btn-right': 'onClickButtonNext',
+ 'vclick #submit_signed_in': 'onClickSubmit',
+ 'vclick #submit_sign_in': 'onClickSubmit',
+ 'vclick #submit_register': 'onClickSubmit'
+ },
+
+ render: function(){
+ if ( !this.template ) {
+ FMS.printDebug('no template to render');
+ return;
+ }
+ template = _.template( tpl.get( this.template ) );
+ if ( this.model ) {
+ this.$el.html(template({ model: this.model.toJSON(), user: FMS.currentUser.toJSON(), nopassword: this.nopassword }));
+ } else {
+ this.$el.html(template());
+ }
+ this.afterRender();
+ return this;
+ },
+
+ onClickSubmit: function(e) {
+ // in case we are getting here from a form submission
+ e.preventDefault();
+ this.doSubmit();
+ },
+
+ doSubmit: function() {
+ this.beforeSubmit();
+
+ if ( this.validate() ) {
+ this.model.set('user', FMS.currentUser);
+ if ( FMS.isOffline ) {
+ this.navigate( 'save_offline' );
+ } else {
+ this.report = new FMS.Report( this.model.toJSON() );
+ this.listenTo( this.report, 'sync', this.onReportSync );
+ this.listenTo( this.report, 'invalid', this.onReportInvalid );
+ this.listenTo( this.report, 'error', this.onReportError );
+ this.report.save();
+ }
+ }
+ },
+
+ onReportSync: function(model, resp, options) {
+ if ( model.success !== 1 ) {
+ return;
+ }
+ this.stopListening();
+ this.afterSubmit();
+ if ( FMS.currentUser ) {
+ FMS.currentUser.save();
+ }
+ if (resp.report) {
+ this.report.set('site_id', resp.report);
+ this.report.set('site_url', CONFIG.FMS_URL + '/report/' + resp.report);
+ } else {
+ this.report.set('email_confirm', 1);
+ }
+ var reset = FMS.removeDraft( model.id, true);
+ var that = this;
+ reset.done( function() { that.onRemoveDraft(); } );
+ reset.fail( function() { that.onRemoveDraft(); } );
+ },
+
+ onRemoveDraft: function() {
+ FMS.clearCurrentDraft();
+ FMS.createdReport = this.report;
+ this.navigate( 'sent' );
+ },
+
+ onReportInvalid: function(model, err, options) {
+ if ( !this._handleInvalid( model, err, options ) ) {
+ var errors = err.errors;
+ var errorList = '<ul><li class="plain">' + FMS.strings.invalid_report + '</li>';
+ var validErrors = [ 'password', 'category', 'name' ];
+ for ( var k in errors ) {
+ if ( validErrors.indexOf(k) >= 0 || errors[k].match(/required/) ) {
+ if ( k === 'password' ) {
+ error = FMS.strings.password_problem;
+ } else if ( k !== '') {
+ error = errors[k];
+ }
+ errorList += '<li>' + error + '</li>';
+ }
+ }
+ errorList += '</ul>';
+ $('p.top').hide();
+ $('#errors').html(errorList).show();
+ }
+ },
+
+ onReportError: function(model, err, options) {
+ var msg = FMS.strings.unknown_sync_error;
+ if ( err.errors ) {
+ msg = msg + ': ' + err.errors;
+ } else if ( options.aborted ) {
+ msg = FMS.strings.upload_aborted;
+ }
+ var that = this;
+ navigator.notification.confirm(
+ msg,
+ function(index) { that.handleReportError(index); },
+ CONFIG.APP_NAME,
+ [FMS.strings.save_for_later,FMS.strings.try_again]);
+ },
+
+ handleReportError: function(index) {
+ if ( index === 1 ) {
+ this.stopListening();
+ FMS.clearCurrentDraft();
+ this.navigate('reports');
+ } else if ( index === 2 ) {
+ this.doSubmit();
+ }
+ },
+
+ beforeSubmit: function() {},
+ afterSubmit: function() {},
+
+ _handleInvalid: function() {
+ return false;
+ },
+
+ _destroy: function() {
+ this.stopListening();
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitInitialPageView: FMS.SubmitView.extend({
+ onClickButtonPrev: function() {
+ if ( this.model.get('hasExtras') == 1 ) {
+ this.navigate( 'details_extra', true );
+ } else {
+ this.navigate( 'details', true );
+ }
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitEmailView: FMS.SubmitInitialPageView.extend({
+ template: 'submit_email',
+ id: 'submit-email-page',
+ prev: 'details',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick #set_password': 'onClickSetPassword',
+ 'vclick #have_password': 'onClickPassword',
+ 'vclick #email_confirm': 'onClickConfirm'
+ },
+
+ afterRender: function() {
+ // if we are coming back to this page we want to reset how
+ // they are reporting
+ this.model.set('submit_clicked', '');
+ },
+
+ validate: function() {
+ this.clearValidationErrors();
+ var isValid = 1;
+
+ var email = $('#form_email').val();
+ if ( !email ) {
+ isValid = 0;
+ this.validationError('form_email', FMS.validationStrings.email.required);
+ // regexp stolen from jquery validate module
+ } else if ( ! /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(email) ) {
+ isValid = 0;
+ this.validationError('form_email', FMS.validationStrings.email.email);
+ }
+
+ return isValid;
+ },
+
+ onClickSetPassword: function(e) {
+ e.preventDefault();
+ if ( this.validate() ) {
+ this.model.set('submit_clicked', 'submit_register');
+ FMS.currentUser.set('email', $('#form_email').val());
+ this.navigate( 'submit-set-password' );
+ }
+ },
+
+ onClickPassword: function(e) {
+ e.preventDefault();
+ if ( this.validate() ) {
+ FMS.currentUser.set('email', $('#form_email').val());
+ this.navigate( 'submit-password' );
+ }
+ },
+
+ onClickConfirm: function(e) {
+ e.preventDefault();
+ if ( this.validate() ) {
+ FMS.currentUser.set('email', $('#form_email').val());
+ FMS.currentUser.save();
+ this.navigate( 'submit-name' );
+ }
+ },
+
+ _destroy: function() {}
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitNameView: FMS.SubmitView.extend({
+ template: 'submit_name',
+ id: 'submit-name-page',
+ prev: 'submit-email',
+ nopassword: 1,
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick #send_confirm': 'onClickSubmit'
+ },
+
+ initialize: function() {
+ this.listenTo(this.model, 'sync', this.onReportSync );
+ this.listenTo( this.model, 'error', this.onReportError );
+ },
+
+ validate: function() {
+ this.clearValidationErrors();
+ var isValid = 1;
+
+ var name = $('#form_name').val();
+ if ( !name ) {
+ isValid = 0;
+ this.validationError('form_name', FMS.validationStrings.name.required );
+ } else {
+ var validNamePat = /\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i;
+ if ( name.length < 6 || !name.match( /\s/ ) || !name.match( /\S/ ) || name.match( validNamePat ) ) {
+ isValid = 0;
+ this.validationError('form_name', FMS.validationStrings.name.validName);
+ }
+ }
+
+ if ( this.model.get('titles_list') && this.model.get('titles_list').length > 0 ) {
+ if ( $('#form_title').val() === '' ) {
+ this.validationError('form_title', FMS.strings.required);
+ isValid = 0;
+ }
+ }
+
+ return isValid;
+ },
+
+ beforeSubmit: function() {
+ $('#errors').hide();
+ $('p.top').show();
+ this.model.set('name', $('#form_name').val());
+ this.model.set('phone', $('#form_phone').val());
+ this.model.set('may_show_name', $('#form_may_show_name').is(':checked'));
+ FMS.currentUser.set('name', $('#form_name').val());
+ FMS.currentUser.set('may_show_name', $('#form_may_show_name').is(':checked'));
+
+ if ( this.model.get('titles_list') && this.model.get('titles_list').length > 0 ) {
+ FMS.currentUser.set('title', $('#form_title').val());
+ }
+
+ if ( FMS.currentUser ) {
+ FMS.currentUser.save();
+ }
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitNameSetPasswordView: FMS.SubmitNameView.extend({
+ template: 'submit_name',
+ id: 'submit-name-page-set-password',
+ prev: 'submit-set-password',
+ nopassword: 0
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitPasswordView: FMS.SubmitView.extend({
+ template: 'submit_password',
+ id: 'submit-password-page',
+ prev: 'submit-email',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick #report': 'onClickSubmit',
+ 'vclick #confirm_name': 'onClickSubmit',
+ 'submit #passwordForm': 'onClickSubmit'
+ },
+
+ initialize: function() {
+ this.listenTo(this.model, 'sync', this.onReportSync );
+ this.listenTo( this.model, 'error', this.onReportError );
+ },
+
+ validate: function() {
+ var isValid = 1;
+
+ if ( !$('#form_password').val() ) {
+ isValid = 0;
+ this.validationError('form_password', FMS.validationStrings.password );
+ }
+
+ if ( $('#form_name').val() && this.model.get('titles_list') && this.model.get('titles_list').length > 0 ) {
+ if ( $('#form_title').val() === '' ) {
+ this.validationError('form_title', FMS.strings.required);
+ isValid = 0;
+ }
+ }
+
+ return isValid;
+ },
+
+ beforeSubmit: function() {
+ $('#errors').hide();
+ $('p.top').show();
+ $('#report').focus();
+ if ( $('#form_name').val() ) {
+ this.model.set('submit_clicked', 'submit_register');
+ this.model.set('phone', $('#form_phone').val());
+ this.model.set('name', $('#form_name').val());
+ this.model.set('may_show_name', $('#form_may_show_name').is(':checked'));
+ FMS.currentUser.set('name', $('#form_name').val());
+ FMS.currentUser.set('may_show_name', $('#form_may_show_name').is(':checked'));
+ if ( this.model.get('titles_list') && this.model.get('titles_list').length > 0 ) {
+ FMS.currentUser.set('title', $('#form_title').val());
+ }
+ FMS.currentUser.save();
+ } else {
+ // if this is set then we are registering a password
+ if ( ! this.model.get('submit_clicked') ) {
+ this.model.set('submit_clicked', 'submit_sign_in');
+ }
+ FMS.currentUser.set('password', $('#form_password').val());
+ }
+ },
+
+ afterSubmit: function() {
+ FMS.isLoggedIn = 1;
+ },
+
+ _handleInvalid: function(model, err, options) {
+ if ( err.check_name ) {
+ $('#form_name').val(err.check_name);
+ $('#password_row').hide();
+ $('#check_name').show();
+ $('#confirm_name').focus();
+ return true;
+ }
+ return false;
+ }
+
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitSetPasswordView: FMS.SubmitPasswordView.extend({
+ template: 'submit_set_password',
+ id: 'submit-set-password-page',
+ prev: 'submit-email',
+ next: 'submit-name-set-password',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick #continue': 'onClickContinue',
+ 'submit #passwordForm': 'onClickContinue'
+ },
+
+ onClickContinue: function(e) {
+ e.preventDefault();
+ if ( this.validate() ) {
+ $('#continue').focus();
+ if ( ! this.model.get('submit_clicked') ) {
+ this.model.set('submit_clicked', 'submit_sign_in');
+ }
+ FMS.currentUser.set('password', $('#form_password').val());
+ this.navigate( this.next );
+ }
+ }
+ })
+ });
+})(FMS, Backbone, _, $);
+
+(function (FMS, Backbone, _, $) {
+ _.extend( FMS, {
+ SubmitConfirmView: FMS.SubmitInitialPageView.extend({
+ template: 'submit_confirm',
+ id: 'submit-confirm-page',
+ prev: 'details',
+
+ events: {
+ 'pagehide': 'destroy',
+ 'pagebeforeshow': 'beforeDisplay',
+ 'pageshow': 'afterDisplay',
+ 'vclick .ui-btn-left': 'onClickButtonPrev',
+ 'vclick #report': 'onClickSubmit'
+ },
+
+ validate: function() {
+ this.clearValidationErrors();
+ var isValid = 1;
+
+ var name = $('#form_name').val();
+ if ( !name ) {
+ isValid = 0;
+ this.validationError('form_name', FMS.validationStrings.name.required );
+ } else {
+ var validNamePat = /\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i;
+ if ( name.length < 6 || !name.match( /\S/ ) || name.match( validNamePat ) ) {
+ isValid = 0;
+ this.validationError('form_name', FMS.validationStrings.name.validName);
+ }
+ }
+
+ return isValid;
+ },
+
+ beforeSubmit: function() {
+ this.model.set('name', $('#form_name').val());
+ this.model.set('phone', $('#form_phone').val());
+ this.model.set('may_show_name', $('#form_may_show_name').is(':checked'));
+ this.model.set('submit_clicked', 'submit_register');
+ FMS.currentUser.set('name', $('#form_name').val());
+ FMS.currentUser.set('may_show_name', $('#form_may_show_name').is(':checked'));
+ },
+
+ onReportError: function(model, err, options) {
+ // TODO: this is a temporary measure which should be replaced by a more
+ // sensible login mechanism
+ if ( err.check_name ) {
+ this.onClickSubmit();
+ } else {
+ if ( err.errors && err.errors.password ) {
+ this.validationError('form_password', err.errors.password );
+ }
+ }
+ }
+ })
+ });
+})(FMS, Backbone, _, $);