voluntary 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e0d6d9bf2a37688124de536d7859f1830abf3c6
4
- data.tar.gz: 94f456e0b313a7d306724a1612e0bedea268d0f6
3
+ metadata.gz: e733d65d2735dc9749ec9be14d46cdb88c56ca85
4
+ data.tar.gz: b14d3f3b9dfc746dd1f906208610d47f2b0cdb1d
5
5
  SHA512:
6
- metadata.gz: 7e2b60e9b3b05d5f3c0bd8733b96908fd3cc687db7c03999dcd36c69834030e595c7ec77cfa961ebc93ff739830e53d228e67f74931e19732a3cd53d195eff74
7
- data.tar.gz: d5affd0cc24ceb1af706ce02afaedaf1e9441509f033b6f884ee1b3516b93fe91f6409f4692b4241726e2d1f9180e4458eebe2ea3f7dac545ced13e0a6033b74
6
+ metadata.gz: fdb14cddd47477319fb349c3fea0ae821e3b070e95db6030fb39b6f5efab15cf512a17b1e249615658beea7c34586bea1e03be65539ada401e88eadf46794dc4
7
+ data.tar.gz: 1b7d07d75916d31fd56d77f4762c60a8f6d975b517d49d29b71e361aba451cd2b8fd80ea2d217b9c7f5410c2944c0d1023d9fbfcd082358b346e1441ccbbd965
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## unreleased ##
2
2
 
3
+ ## 0.7.0 (October 29, 2015) ##
4
+
5
+ * [#94](https://github.com/volontariat/voluntary/issues/94) Customization for classified advertisement product.
6
+ * [#97](https://github.com/volontariat/voluntary/issues/97) User form does not show errors like country can't be blank.
7
+ * [#96](https://github.com/volontariat/voluntary/issues/96) Regard user's timezone.
8
+ * [BUGFIX] Remove obsolete scroll bar from modals.
9
+
3
10
  ## 0.6.0 (October 1, 2015) ##
4
11
 
5
12
  * [#93](https://github.com/volontariat/voluntary/issues/93) Core customizations for survey product.
@@ -1,6 +1,7 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
3
  //= require jquery-ui-bootstrap
4
+ //= require moment
4
5
  //= require twitter/bootstrap
5
6
  //= require bootstrap-datetimepicker
6
7
  //= require jquery.tokeninput
@@ -0,0 +1,405 @@
1
+ (function ( $ ) {
2
+
3
+ /**
4
+ * Holds google map object and related utility entities.
5
+ * @constructor
6
+ */
7
+ function GMapContext(domElement, options) {
8
+ var _map = new google.maps.Map(domElement, options);
9
+ var _marker = new google.maps.Marker({
10
+ position: new google.maps.LatLng(54.19335, -3.92695),
11
+ map: _map,
12
+ title: "Drag Me",
13
+ draggable: options.draggable
14
+ });
15
+ return {
16
+ map: _map,
17
+ marker: _marker,
18
+ circle: null,
19
+ location: _marker.position,
20
+ radius: options.radius,
21
+ locationName: options.locationName,
22
+ addressComponents: {
23
+ formatted_address: null,
24
+ addressLine1: null,
25
+ addressLine2: null,
26
+ streetName: null,
27
+ streetNumber: null,
28
+ city: null,
29
+ district: null,
30
+ state: null,
31
+ stateOrProvince: null
32
+ },
33
+ settings: options.settings,
34
+ domContainer: domElement,
35
+ geodecoder: new google.maps.Geocoder()
36
+ }
37
+ }
38
+
39
+ // Utility functions for Google Map Manipulations
40
+ var GmUtility = {
41
+ /**
42
+ * Draw a circle over the the map. Returns circle object.
43
+ * Also writes new circle object in gmapContext.
44
+ *
45
+ * @param center - LatLng of the center of the circle
46
+ * @param radius - radius in meters
47
+ * @param gmapContext - context
48
+ * @param options
49
+ */
50
+ drawCircle: function(gmapContext, center, radius, options) {
51
+ if (gmapContext.circle != null) {
52
+ gmapContext.circle.setMap(null);
53
+ }
54
+ if (radius > 0) {
55
+ radius *= 1;
56
+ options = $.extend({
57
+ strokeColor: "#0000FF",
58
+ strokeOpacity: 0.35,
59
+ strokeWeight: 2,
60
+ fillColor: "#0000FF",
61
+ fillOpacity: 0.20
62
+ }, options);
63
+ options.map = gmapContext.map;
64
+ options.radius = radius;
65
+ options.center = center;
66
+ gmapContext.circle = new google.maps.Circle(options);
67
+ return gmapContext.circle;
68
+ }
69
+ return null;
70
+ },
71
+ /**
72
+ *
73
+ * @param gMapContext
74
+ * @param location
75
+ * @param callback
76
+ */
77
+ setPosition: function(gMapContext, location, callback) {
78
+ gMapContext.location = location;
79
+ gMapContext.marker.setPosition(location);
80
+ gMapContext.map.panTo(location);
81
+ this.drawCircle(gMapContext, location, gMapContext.radius, {});
82
+ if (gMapContext.settings.enableReverseGeocode) {
83
+ gMapContext.geodecoder.geocode({latLng: gMapContext.location}, function(results, status){
84
+ if (status == google.maps.GeocoderStatus.OK && results.length > 0){
85
+ gMapContext.locationName = results[0].formatted_address;
86
+ gMapContext.addressComponents =
87
+ GmUtility.address_component_from_google_geocode(results[0].address_components);
88
+ }
89
+ if (callback) {
90
+ callback.call(this, gMapContext);
91
+ }
92
+ });
93
+ } else {
94
+ if (callback) {
95
+ callback.call(this, gMapContext);
96
+ }
97
+ }
98
+
99
+ },
100
+ locationFromLatLng: function(lnlg) {
101
+ return {latitude: lnlg.lat(), longitude: lnlg.lng()}
102
+ },
103
+ address_component_from_google_geocode: function(address_components) {
104
+ var result = {};
105
+ for (var i = address_components.length-1; i>=0; i--) {
106
+ var component = address_components[i];
107
+ // Postal code
108
+ if (component.types.indexOf('postal_code') >= 0) {
109
+ result.postalCode = component.short_name;
110
+ }
111
+ // Street number
112
+ else if (component.types.indexOf('street_number') >= 0) {
113
+ result.streetNumber = component.short_name;
114
+ }
115
+ // Street name
116
+ else if (component.types.indexOf('route') >= 0) {
117
+ result.streetName = component.short_name;
118
+ }
119
+ // City
120
+ else if (component.types.indexOf('locality') >= 0) {
121
+ result.city = component.short_name;
122
+ }
123
+ // District
124
+ else if (component.types.indexOf('sublocality') >= 0) {
125
+ result.district = component.short_name;
126
+ }
127
+ // State \ Province
128
+ else if (component.types.indexOf('administrative_area_level_1') >= 0) {
129
+ result.stateOrProvince = component.short_name;
130
+ }
131
+ // State \ Province
132
+ else if (component.types.indexOf('country') >= 0) {
133
+ result.country = component.short_name;
134
+ }
135
+ }
136
+ result.addressLine1 = [result.streetNumber, result.streetName].join(' ').trim();
137
+ result.addressLine2 = '';
138
+ return result;
139
+ }
140
+ };
141
+
142
+ function isPluginApplied(domObj) {
143
+ return getContextForElement(domObj) != undefined;
144
+ }
145
+
146
+ function getContextForElement(domObj) {
147
+ return $(domObj).data("locationpicker");
148
+ }
149
+
150
+ function updateInputValues(inputBinding, gmapContext){
151
+ if (!inputBinding) return;
152
+ var currentLocation = GmUtility.locationFromLatLng(gmapContext.location);
153
+ if (inputBinding.latitudeInput) {
154
+ inputBinding.latitudeInput.val(currentLocation.latitude).change();
155
+ }
156
+ if (inputBinding.longitudeInput) {
157
+ inputBinding.longitudeInput.val(currentLocation.longitude).change();
158
+ }
159
+ if (inputBinding.radiusInput) {
160
+ inputBinding.radiusInput.val(gmapContext.radius).change();
161
+ }
162
+ if (inputBinding.locationNameInput) {
163
+ inputBinding.locationNameInput.val(gmapContext.locationName).change();
164
+ }
165
+ }
166
+
167
+ function setupInputListenersInput(inputBinding, gmapContext) {
168
+ if (inputBinding) {
169
+ if (inputBinding.radiusInput){
170
+ inputBinding.radiusInput.on("change", function(e) {
171
+ if (!e.originalEvent) { return }
172
+ gmapContext.radius = $(this).val();
173
+ GmUtility.setPosition(gmapContext, gmapContext.location, function(context){
174
+ context.settings.onchanged.apply(gmapContext.domContainer,
175
+ [GmUtility.locationFromLatLng(context.location), context.radius, false]);
176
+ });
177
+ });
178
+ }
179
+ if (inputBinding.locationNameInput && gmapContext.settings.enableAutocomplete) {
180
+ var blur = false;
181
+ gmapContext.autocomplete = new google.maps.places.Autocomplete(inputBinding.locationNameInput.get(0));
182
+ google.maps.event.addListener(gmapContext.autocomplete, 'place_changed', function() {
183
+ blur = false;
184
+ var place = gmapContext.autocomplete.getPlace();
185
+ if (!place.geometry) {
186
+ gmapContext.settings.onlocationnotfound(place.name);
187
+ return;
188
+ }
189
+ GmUtility.setPosition(gmapContext, place.geometry.location, function(context) {
190
+ updateInputValues(inputBinding, context);
191
+ context.settings.onchanged.apply(gmapContext.domContainer,
192
+ [GmUtility.locationFromLatLng(context.location), context.radius, false]);
193
+ });
194
+ });
195
+ if(gmapContext.settings.enableAutocompleteBlur) {
196
+ inputBinding.locationNameInput.on("change", function(e) {
197
+ if (!e.originalEvent) { return }
198
+ blur = true;
199
+ });
200
+ inputBinding.locationNameInput.on("blur", function(e) {
201
+ if (!e.originalEvent) { return }
202
+ setTimeout(function() {
203
+ var address = $(inputBinding.locationNameInput).val();
204
+ if (address.length > 5 && blur) {
205
+ blur = false;
206
+ gmapContext.geodecoder.geocode({'address': address}, function(results, status) {
207
+ if(status == google.maps.GeocoderStatus.OK && results && results.length) {
208
+ GmUtility.setPosition(gmapContext, results[0].geometry.location, function(context) {
209
+ updateInputValues(inputBinding, context);
210
+ context.settings.onchanged.apply(gmapContext.domContainer,
211
+ [GmUtility.locationFromLatLng(context.location), context.radius, false]);
212
+ });
213
+ }
214
+ });
215
+ }
216
+ }, 1000);
217
+ });
218
+ }
219
+ }
220
+ if (inputBinding.latitudeInput) {
221
+ inputBinding.latitudeInput.on("change", function(e) {
222
+ if (!e.originalEvent) { return }
223
+ GmUtility.setPosition(gmapContext, new google.maps.LatLng($(this).val(), gmapContext.location.lng()), function(context){
224
+ context.settings.onchanged.apply(gmapContext.domContainer,
225
+ [GmUtility.locationFromLatLng(context.location), context.radius, false]);
226
+ });
227
+ });
228
+ }
229
+ if (inputBinding.longitudeInput) {
230
+ inputBinding.longitudeInput.on("change", function(e) {
231
+ if (!e.originalEvent) { return }
232
+ GmUtility.setPosition(gmapContext, new google.maps.LatLng(gmapContext.location.lat(), $(this).val()), function(context){
233
+ context.settings.onchanged.apply(gmapContext.domContainer,
234
+ [GmUtility.locationFromLatLng(context.location), context.radius, false]);
235
+ });
236
+ });
237
+ }
238
+ }
239
+ }
240
+
241
+ function autosize(gmapContext) {
242
+ google.maps.event.trigger(gmapContext.map, 'resize');
243
+ setTimeout(function() {
244
+ gmapContext.map.setCenter(gmapContext.marker.position);
245
+ }, 300);
246
+ }
247
+
248
+ function updateMap(gmapContext, $target, options) {
249
+ var settings = $.extend({}, $.fn.locationpicker.defaults, options ),
250
+ latNew = settings.location.latitude,
251
+ lngNew = settings.location.longitude,
252
+ radiusNew = settings.radius,
253
+ latOld = gmapContext.settings.location.latitude,
254
+ lngOld = gmapContext.settings.location.longitude,
255
+ radiusOld = gmapContext.settings.radius;
256
+
257
+ if (latNew == latOld && lngNew == lngOld && radiusNew == radiusOld)
258
+ return;
259
+
260
+ gmapContext.settings.location.latitude = latNew;
261
+ gmapContext.settings.location.longitude = lngNew;
262
+ gmapContext.radius = radiusNew;
263
+
264
+ GmUtility.setPosition(gmapContext, new google.maps.LatLng(gmapContext.settings.location.latitude, gmapContext.settings.location.longitude), function(context){
265
+ setupInputListenersInput(gmapContext.settings.inputBinding, gmapContext);
266
+ context.settings.oninitialized($target);
267
+ });
268
+ }
269
+ /**
270
+ * Initializeialization:
271
+ * $("#myMap").locationpicker(options);
272
+ * @param options
273
+ * @param params
274
+ * @returns {*}
275
+ */
276
+ $.fn.locationpicker = function( options, params ) {
277
+ if (typeof options == 'string') { // Command provided
278
+ var _targetDomElement = this.get(0);
279
+ // Plug-in is not applied - nothing to do.
280
+ if (!isPluginApplied(_targetDomElement)) return;
281
+ var gmapContext = getContextForElement(_targetDomElement);
282
+ switch (options) {
283
+ case "location":
284
+ if (params == undefined) { // Getter
285
+ var location = GmUtility.locationFromLatLng(gmapContext.location);
286
+ location.radius = gmapContext.radius;
287
+ location.name = gmapContext.locationName;
288
+ return location;
289
+ } else { // Setter
290
+ if (params.radius) {
291
+ gmapContext.radius = params.radius;
292
+ }
293
+ GmUtility.setPosition(gmapContext, new google.maps.LatLng(params.latitude, params.longitude), function(gmapContext) {
294
+ updateInputValues(gmapContext.settings.inputBinding, gmapContext);
295
+ });
296
+ }
297
+ break;
298
+ case "subscribe":
299
+ /**
300
+ * Provides interface for subscribing for GoogleMap events.
301
+ * See Google API documentation for details.
302
+ * Parameters:
303
+ * - event: string, name of the event
304
+ * - callback: function, callback function to be invoked
305
+ */
306
+ if (params == undefined) { // Getter is not available
307
+ return null;
308
+ } else {
309
+ var event = params.event;
310
+ var callback = params.callback;
311
+ if (!event || ! callback) {
312
+ console.error("LocationPicker: Invalid arguments for method \"subscribe\"")
313
+ return null;
314
+ }
315
+ google.maps.event.addListener(gmapContext.map, event, callback);
316
+ }
317
+ break;
318
+ case "map":
319
+ /**
320
+ * Returns object which allows access actual google widget and marker paced on it.
321
+ * Structure: {
322
+ * map: Instance of the google map widget
323
+ * marker: marker placed on map
324
+ * }
325
+ */
326
+ if (params == undefined) { // Getter
327
+ var locationObj = GmUtility.locationFromLatLng(gmapContext.location);
328
+ locationObj.formattedAddress = gmapContext.locationName;
329
+ locationObj.addressComponents = gmapContext.addressComponents;
330
+ return {
331
+ map: gmapContext.map,
332
+ marker: gmapContext.marker,
333
+ location: locationObj
334
+ }
335
+ } else { // Setter is not available
336
+ return null;
337
+ }
338
+ case "autosize":
339
+ autosize(gmapContext);
340
+ return this;
341
+ }
342
+ return null;
343
+ }
344
+ return this.each(function() {
345
+ var $target = $(this);
346
+ // If plug-in hasn't been applied before - initialize, otherwise - skip
347
+ if (isPluginApplied(this)){
348
+ updateMap(getContextForElement(this), $(this), options);
349
+ return;
350
+ }
351
+ // Plug-in initialization is required
352
+ // Defaults
353
+ var settings = $.extend({}, $.fn.locationpicker.defaults, options );
354
+ // Initialize
355
+ var gmapContext = new GMapContext(this, {
356
+ zoom: settings.zoom,
357
+ center: new google.maps.LatLng(settings.location.latitude, settings.location.longitude),
358
+ mapTypeId: google.maps.MapTypeId.ROADMAP,
359
+ mapTypeControl: false,
360
+ disableDoubleClickZoom: false,
361
+ scrollwheel: settings.scrollwheel,
362
+ streetViewControl: false,
363
+ radius: settings.radius,
364
+ locationName: settings.locationName,
365
+ settings: settings,
366
+ draggable: settings.draggable
367
+ });
368
+ $target.data("locationpicker", gmapContext);
369
+ // Subscribe GMap events
370
+ google.maps.event.addListener(gmapContext.marker, "dragend", function(event) {
371
+ GmUtility.setPosition(gmapContext, gmapContext.marker.position, function(context){
372
+ var currentLocation = GmUtility.locationFromLatLng(gmapContext.location);
373
+ context.settings.onchanged.apply(gmapContext.domContainer, [currentLocation, context.radius, true]);
374
+ updateInputValues(gmapContext.settings.inputBinding, gmapContext);
375
+ });
376
+ });
377
+ GmUtility.setPosition(gmapContext, new google.maps.LatLng(settings.location.latitude, settings.location.longitude), function(context){
378
+ updateInputValues(settings.inputBinding, gmapContext);
379
+ // Set input bindings if needed
380
+ setupInputListenersInput(settings.inputBinding, gmapContext);
381
+ context.settings.oninitialized($target);
382
+ });
383
+ });
384
+ };
385
+ $.fn.locationpicker.defaults = {
386
+ location: {latitude: 40.7324319, longitude: -73.82480777777776},
387
+ locationName: "",
388
+ radius: 500,
389
+ zoom: 15,
390
+ scrollwheel: true,
391
+ inputBinding: {
392
+ latitudeInput: null,
393
+ longitudeInput: null,
394
+ radiusInput: null,
395
+ locationNameInput: null
396
+ },
397
+ enableAutocomplete: false,
398
+ enableAutocompleteBlur: false,
399
+ enableReverseGeocode: true,
400
+ draggable: true,
401
+ onchanged: function(currentLocation, radius, isMarkerDropped) {},
402
+ onlocationnotfound: function(locationName) {},
403
+ oninitialized: function (component) {}
404
+ }
405
+ }( jQuery ));
@@ -10,6 +10,8 @@ module Voluntary
10
10
 
11
11
  helper_method :parent, :application_navigation, :navigation_product_path, :navigation_product_name, :voluntary_application_stylesheets
12
12
  helper_method :voluntary_application_javascripts
13
+
14
+ before_filter :set_timezone
13
15
  end
14
16
 
15
17
  def voluntary_application_stylesheets
@@ -77,6 +79,10 @@ module Voluntary
77
79
 
78
80
  private
79
81
 
82
+ def set_timezone
83
+ Time.zone = current_user.try(:timezone).present? ? current_user.timezone : 'UTC'
84
+ end
85
+
80
86
  def current_namespace
81
87
  controller_name_segments = params[:controller].split('/')
82
88
  controller_name_segments.pop