voluntary 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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