4 * Location-related classes for WCF
6 * @author Matthias Schmidt
7 * @copyright 2001-2019 WoltLab GmbH
8 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
9 * @deprecated 6.0 use `<woltlab-core-google-maps>` instead
14 * Provides location-related utility functions.
18 * Passes the user's current latitude and longitude to the given function
19 * as parameters. If the user's current position cannot be determined,
20 * undefined will be passed as both parameters.
22 * @param function callback
23 * @param integer timeout
25 getLocation: function(callback
, timeout
) {
26 var $accessUserLocation
= WCF
.Location
.GoogleMaps
.Settings
.get('accessUserLocation');
27 if (navigator
.geolocation
&& $accessUserLocation
!== null && $accessUserLocation
) {
28 navigator
.geolocation
.getCurrentPosition(function(position
) {
29 callback(position
.coords
.latitude
, position
.coords
.longitude
);
31 callback(undefined, undefined);
33 timeout
: timeout
|| 5000
37 callback(undefined, undefined);
43 * Namespace for Google Maps-related classes.
45 WCF
.Location
.GoogleMaps
= { };
48 * After an authentican error, Google Maps tries to call the `gm_authFailure` function.
49 * (see https://developers.google.com/maps/documentation/javascript/events#auth-errors)
51 function gm_authFailure() {
52 WCF
.System
.Event
.fireEvent('com.woltlab.wcf.googleMaps', 'authenticationFailure');
56 * Handles the global Google Maps settings.
58 WCF
.Location
.GoogleMaps
.Settings
= {
60 * Google Maps settings
66 * Returns the value of a certain setting or null if it doesn't exist.
68 * If no parameter is given, all settings are returned.
70 * @param string setting
73 get: function(setting
) {
74 if (setting
=== undefined) {
75 return this._settings
;
78 if (this._settings
[setting
] !== undefined) {
79 return this._settings
[setting
];
86 * Sets the value of a certain setting.
88 * @param mixed setting
91 set: function(setting
, value
) {
92 if ($.isPlainObject(setting
)) {
93 for (var index
in setting
) {
94 this._settings
[index
] = setting
[index
];
98 this._settings
[setting
] = value
;
104 * Handles a Google Maps map.
106 WCF
.Location
.GoogleMaps
.Map
= Class
.extend({
108 * map object for the displayed map
109 * @var google.maps.Map
114 * list of markers on the map
115 * @var array<google.maps.Marker>
120 * Initializes a new WCF.Location.Map object.
122 * @param string mapContainerID
123 * @param object mapOptions
125 init: function(mapContainerID
, mapOptions
) {
126 this._mapContainer
= $('#' + mapContainerID
);
127 this._mapOptions
= $.extend(true, this._getDefaultMapOptions(), mapOptions
);
129 this._map
= new google
.maps
.Map(this._mapContainer
[0], this._mapOptions
);
132 // fix maps in mobile sidebars by refreshing the map when displaying
134 if (this._mapContainer
.parents('.sidebar').length
) {
135 require(['Ui/Screen'], function(UiScreen
) {
136 UiScreen
.on('screen-sm-down', {
137 setup
: $.proxy(this._addSidebarMapListener
, this)
146 * Adds the event listener to a marker to show the associated info window.
148 * @param google.maps.Marker marker
149 * @param google.maps.InfoWindow infoWindow
151 _addInfoWindowEventListener: function(marker
, infoWindow
) {
152 google
.maps
.event
.addListener(marker
, 'click', $.proxy(function() {
153 infoWindow
.open(this._map
, marker
);
158 * Adds click listener to mobile sidebar toggle button to refresh map.
160 _addSidebarMapListener: function() {
161 $('.content > .mobileSidebarToggleButton').click($.proxy(this.refresh
, this));
165 * Returns the default map options.
169 _getDefaultMapOptions: function() {
170 var $defaultMapOptions
= { };
172 // dummy center value
173 $defaultMapOptions
.center
= new google
.maps
.LatLng(WCF
.Location
.GoogleMaps
.Settings
.get('defaultLatitude'), WCF
.Location
.GoogleMaps
.Settings
.get('defaultLongitude'));
175 // double click to zoom
176 $defaultMapOptions
.disableDoubleClickZoom
= WCF
.Location
.GoogleMaps
.Settings
.get('disableDoubleClickZoom');
179 $defaultMapOptions
.draggable
= WCF
.Location
.GoogleMaps
.Settings
.get('draggable');
182 switch (WCF
.Location
.GoogleMaps
.Settings
.get('mapType')) {
184 $defaultMapOptions
.mapTypeId
= google
.maps
.MapTypeId
.ROADMAP
;
188 $defaultMapOptions
.mapTypeId
= google
.maps
.MapTypeId
.SATELLITE
;
192 $defaultMapOptions
.mapTypeId
= google
.maps
.MapTypeId
.TERRAIN
;
197 $defaultMapOptions
.mapTypeId
= google
.maps
.MapTypeId
.HYBRID
;
201 /// map type controls
202 $defaultMapOptions
.mapTypeControl
= WCF
.Location
.GoogleMaps
.Settings
.get('mapTypeControl') != 'off';
203 if ($defaultMapOptions
.mapTypeControl
) {
204 switch (WCF
.Location
.GoogleMaps
.Settings
.get('mapTypeControl')) {
206 $defaultMapOptions
.mapTypeControlOptions
= {
207 style
: google
.maps
.MapTypeControlStyle
.DROPDOWN_MENU
211 case 'horizontalBar':
212 $defaultMapOptions
.mapTypeControlOptions
= {
213 style
: google
.maps
.MapTypeControlStyle
.HORIZONTAL_BAR
218 $defaultMapOptions
.mapTypeControlOptions
= {
219 style
: google
.maps
.MapTypeControlStyle
.DEFAULT
226 $defaultMapOptions
.scaleControl
= WCF
.Location
.GoogleMaps
.Settings
.get('scaleControl');
227 $defaultMapOptions
.scrollwheel
= WCF
.Location
.GoogleMaps
.Settings
.get('scrollwheel');
230 $defaultMapOptions
.zoom
= WCF
.Location
.GoogleMaps
.Settings
.get('zoom');
232 return $defaultMapOptions
;
236 * Adds a draggable marker at the given position to the map and returns
237 * the created marker object.
239 * @param float latitude
240 * @param float longitude
241 * @return google.maps.Marker
243 addDraggableMarker: function(latitude
, longitude
) {
244 var $marker
= new google
.maps
.Marker({
248 position
: new google
.maps
.LatLng(latitude
, longitude
),
252 this._markers
.push($marker
);
258 * Adds a marker with the given data to the map and returns the created
261 * @param float latitude
262 * @param float longitude
263 * @param string title
265 * @param string information
266 * @return google.maps.Marker
268 addMarker: function(latitude
, longitude
, title
, icon
, information
) {
269 var $marker
= new google
.maps
.Marker({
271 position
: new google
.maps
.LatLng(latitude
, longitude
),
277 $marker
.setIcon(icon
);
280 // add info window for marker information
282 var $infoWindow
= new google
.maps
.InfoWindow({
285 this._addInfoWindowEventListener($marker
, $infoWindow
);
287 // add info window object to marker object
288 $marker
.infoWindow
= $infoWindow
;
291 this._markers
.push($marker
);
297 * Returns all markers on the map.
299 * @return array<google.maps.Marker>
301 getMarkers: function() {
302 return this._markers
;
306 * Returns the Google Maps map object.
308 * @return google.maps.Map
317 refresh: function() {
318 // save current center since resize does not preserve it
319 var $center
= this._map
.getCenter();
321 google
.maps
.event
.trigger(this._map
, 'resize');
323 // set center to old value again
324 this._map
.setCenter($center
);
328 * Refreshes the boundaries of the map to show all markers.
330 refreshBounds: function() {
331 var $minLatitude
= null;
332 var $maxLatitude
= null;
333 var $minLongitude
= null;
334 var $maxLongitude
= null;
336 for (var $index
in this._markers
) {
337 var $marker
= this._markers
[$index
];
338 var $latitude
= $marker
.getPosition().lat();
339 var $longitude
= $marker
.getPosition().lng();
341 if ($minLatitude
=== null) {
342 $minLatitude
= $maxLatitude
= $latitude
;
343 $minLongitude
= $maxLongitude
= $longitude
;
346 if ($minLatitude
> $latitude
) {
347 $minLatitude
= $latitude
;
349 else if ($maxLatitude
< $latitude
) {
350 $maxLatitude
= $latitude
;
353 if ($minLongitude
> $latitude
) {
354 $minLongitude
= $latitude
;
356 else if ($maxLongitude
< $longitude
) {
357 $maxLongitude
= $longitude
;
362 this._map
.fitBounds(new google
.maps
.LatLngBounds(
363 new google
.maps
.LatLng($minLatitude
, $minLongitude
),
364 new google
.maps
.LatLng($maxLatitude
, $maxLongitude
)
369 * Removes all markers from the map.
371 removeMarkers: function() {
372 for (var $index
in this._markers
) {
373 this._markers
[$index
].setMap(null);
380 * Changes the bounds of the map.
382 * @param object northEast
383 * @param object southWest
385 setBounds: function(northEast
, southWest
) {
386 this._map
.fitBounds(new google
.maps
.LatLngBounds(
387 new google
.maps
.LatLng(southWest
.latitude
, southWest
.longitude
),
388 new google
.maps
.LatLng(northEast
.latitude
, northEast
.longitude
)
393 * Sets the center of the map to the given position.
395 * @param float latitude
396 * @param float longitude
398 setCenter: function(latitude
, longitude
) {
399 this._map
.setCenter(new google
.maps
.LatLng(latitude
, longitude
));
404 * Handles a large map with many markers where (new) markers are loaded via AJAX.
406 WCF
.Location
.GoogleMaps
.LargeMap
= WCF
.Location
.GoogleMaps
.Map
.extend({
408 * name of the PHP class executing the 'getMapMarkers' action
411 _actionClassName
: null,
414 * additional parameters for executing the 'getMapMarkers' action
417 _additionalParameters
: { },
420 * indicates if the maps center can be set by location search
421 * @var WCF.Location.GoogleMaps.LocationSearch
423 _locationSearch
: null,
426 * selector for the location search input
429 _locationSearchInputSelector
: null,
432 * cluster handling the markers on the map
433 * @var MarkerClusterer
435 _markerClusterer
: null,
438 * ids of the objects which are already displayed
439 * @var array<integer>
444 * previous coordinates of the north east map boundary
445 * @var google.maps.LatLng
447 _previousNorthEast
: null,
450 * previous coordinates of the south west map boundary
451 * @var google.maps.LatLng
453 _previousSouthWest
: null,
456 * if `true`, the `exludedObjectIds` array will be sent as a JSON string,
457 * otherwise as an array (default)
458 * note: be prepared that in the future, only JSON strings might be supported
461 _stringifyExcludedObjectIds
: false,
464 * @see WCF.Location.GoogleMaps.Map.init()
466 init: function(mapContainerID
, mapOptions
, actionClassName
, locationSearchInputSelector
, additionalParameters
) {
467 this._stringifyExcludedObjectIds
= false;
468 if (mapOptions
&& mapOptions
.stringifyExcludedObjectIds
) {
469 this._stringifyExcludedObjectIds
= mapOptions
.stringifyExcludedObjectIds
;
470 delete mapOptions
.stringifyExcludedObjectIds
;
473 this._super(mapContainerID
, mapOptions
);
475 this._actionClassName
= actionClassName
;
476 this._locationSearchInputSelector
= locationSearchInputSelector
|| '';
477 this._additionalParameters
= additionalParameters
|| { };
478 this._objectIDs
= [ ];
480 if (this._locationSearchInputSelector
) {
481 this._locationSearch
= new WCF
.Location
.GoogleMaps
.LocationSearch(locationSearchInputSelector
, $.proxy(this._centerMap
, this));
484 this._markerClusterer
= new MarkerClusterer(this._map
, this._markers
, {
486 imagePath
: WCF
.Location
.GoogleMaps
.Settings
.get('markerClustererImagePath') + 'm'
489 this._markerSpiderfier
= new OverlappingMarkerSpiderfier(this._map
, {
490 keepSpiderfied
: true,
491 markersWontHide
: true,
492 markersWontMove
: true
494 this._markerSpiderfier
.addListener('click', $.proxy(function(marker
) {
495 if (marker
.infoWindow
) {
496 marker
.infoWindow
.open(this._map
, marker
);
500 this._proxy
= new WCF
.Action
.Proxy({
501 showLoadingOverlay
: false,
502 success
: $.proxy(this._success
, this)
505 this._previousNorthEast
= null;
506 this._previousSouthWest
= null;
507 google
.maps
.event
.addListener(this._map
, 'idle', $.proxy(this._loadMarkers
, this));
511 * @see WCF.Location.GoogleMaps.Map.addMarker()
513 _addInfoWindowEventListener: function(marker
, infoWindow
) {
514 // does nothing, is handled by the event listener of the marker
519 * Centers the map based on a location search result.
523 _centerMap: function(data
) {
524 this.setCenter(data
.location
.lat(), data
.location
.lng());
526 $(this._locationSearchInputSelector
).val(data
.label
);
530 * Loads markers if the map is reloaded. Returns true if new markers will
531 * be loaded and false if for the current map bounds, the markers have already
536 _loadMarkers: function() {
537 var $northEast
= this._map
.getBounds().getNorthEast();
538 var $southWest
= this._map
.getBounds().getSouthWest();
540 // check if the user has zoomed in, then all markers are already
542 if (this._previousNorthEast
&& this._previousNorthEast
.lat() >= $northEast
.lat() && this._previousNorthEast
.lng() >= $northEast
.lng() && this._previousSouthWest
.lat() <= $southWest
.lat() && this._previousSouthWest
.lng() <= $southWest
.lng()) {
546 this._previousNorthEast
= $northEast
;
547 this._previousSouthWest
= $southWest
;
549 this._proxy
.setOption('data', {
550 actionName
: 'getMapMarkers',
551 className
: this._actionClassName
,
552 parameters
: $.extend(this._additionalParameters
, {
553 excludedObjectIDs
: this._stringifyExcludedObjectIds
? JSON
.stringify(this._objectIDs
) : this._objectIDs
,
554 eastLongitude
: $northEast
.lng(),
555 northLatitude
: $northEast
.lat(),
556 southLatitude
: $southWest
.lat(),
557 westLongitude
: $southWest
.lng()
560 this._proxy
.sendRequest();
566 * Handles a successful AJAX request.
569 * @param string textStatus
570 * @param jQuery jqXHR
572 _success: function(data
, textStatus
, jqXHR
) {
573 if (data
.returnValues
&& data
.returnValues
.markers
) {
574 for (var $index
in data
.returnValues
.markers
) {
575 var $markerInfo
= data
.returnValues
.markers
[$index
];
577 this.addMarker($markerInfo
.latitude
, $markerInfo
.longitude
, $markerInfo
.title
, null, $markerInfo
.infoWindow
);
579 if ($markerInfo
.objectID
) {
580 this._objectIDs
.push($markerInfo
.objectID
);
582 else if ($markerInfo
.objectIDs
) {
583 this._objectIDs
= this._objectIDs
.concat($markerInfo
.objectIDs
);
590 * @see WCF.Location.GoogleMaps.Map.addMarker()
592 addMarker: function(latitude
, longitude
, title
, icon
, information
) {
593 var $marker
= this._super(latitude
, longitude
, title
, icon
, information
);
594 this._markerClusterer
.addMarker($marker
);
595 this._markerSpiderfier
.addMarker($marker
);
602 * Extends the large map implementation by treating non-draggable markers as location
605 WCF
.Location
.GoogleMaps
.SuggestionMap
= WCF
.Location
.GoogleMaps
.LargeMap
.extend({
607 * maps control showing/hiding location suggestions
610 _locationSuggestionsButton
: null,
613 * function called when a location is selected
616 _suggestionSelectionCallback
: null,
619 * @see WCF.Location.GoogleMaps.LargeMap.init()
621 init: function(mapContainerID
, mapOptions
, actionClassName
, locationSearchInputSelector
, additionalParameters
) {
622 this._super(mapContainerID
, mapOptions
, actionClassName
, locationSearchInputSelector
, additionalParameters
);
624 var $locationSuggestionDiv
= $('<div class="gmnoprint googleMapsCustomControlContainer"><div class="gm-style-mtc"><div class="googleMapsCustomControl">' + WCF
.Language
.get('wcf.map.showLocationSuggestions') + '</div></div></div>');
625 this._locationSuggestionsButton
= $locationSuggestionDiv
.find('.googleMapsCustomControl').click($.proxy(this._toggleLocationSuggestions
, this));
627 this._map
.controls
[google
.maps
.ControlPosition
.TOP_RIGHT
].push($locationSuggestionDiv
.get(0));
631 * @see WCF.Location.GoogleMaps.LargeMap._loadMarkers()
633 _loadMarkers: function() {
634 if (!this._locationSuggestionsButton
.hasClass('active')) return;
636 if (!this._super()) {
637 this._loadSuggestions
= false;
642 * @see WCF.Location.GoogleMaps.LargeMap._loadMarkers()
644 _success: function(data
, textStatus
, jqXHR
) {
645 var $oldLength
= this._markers
.length
;
646 this._super(data
, textStatus
, jqXHR
);
648 if (this._loadSuggestions
&& $oldLength
== this._markers
.length
) {
649 this._loadSuggestions
= false;
650 new WCF
.System
.Notification(WCF
.Language
.get('wcf.map.noLocationSuggestions'), 'info').show();
655 * Handles clicks on the location suggestions button.
657 _toggleLocationSuggestions: function() {
658 var $showSuggestions
= !this._locationSuggestionsButton
.hasClass('active');
659 if ($showSuggestions
) {
660 this._loadSuggestions
= true;
663 this.showSuggestions($showSuggestions
);
667 * @see WCF.Location.GoogleMaps.Map.addMarker()
669 addMarker: function(latitude
, longitude
, title
, icon
, information
) {
670 var $infoWindow
= $(information
);
671 var $useLocation
= $('<a class="googleMapsUseLocationSuggestionLink" />').text(WCF
.Language
.get('wcf.map.useLocationSuggestion')).click(this._suggestionSelectionCallback
);
672 $infoWindow
.append($('<p />').append($useLocation
));
674 var $marker
= this._super(latitude
, longitude
, title
, '//mt.google.com/vt/icon/name=icons/spotlight/spotlight-waypoint-a.png', $infoWindow
.get(0));
676 $useLocation
.data('marker', $marker
);
682 * Sets the function called when a location is selected.
684 * @param function callback
686 setSuggestionSelectionCallback: function(callback
) {
687 this._suggestionSelectionCallback
= callback
;
691 * Shows or hides the location suggestions.
693 * @param boolean showSuggestions
695 showSuggestions: function(showSuggestions
) {
696 // missing argument means showing the suggestions
697 if (showSuggestions
=== undefined) showSuggestions
= true;
699 this._locationSuggestionsButton
.toggleClass('active', showSuggestions
);
701 var $clusterMarkers
= [ ];
702 for (var $i
= 0, $length
= this._markers
.length
; $i
< $length
; $i
++) {
703 var $marker
= this._markers
[$i
];
705 // ignore draggable markers
706 if (!$marker
.draggable
) {
707 $marker
.setVisible(showSuggestions
);
708 if (showSuggestions
) {
709 $clusterMarkers
.push($marker
);
714 this._markerClusterer
.clearMarkers();
715 if (showSuggestions
) {
716 this._markerClusterer
.addMarkers($clusterMarkers
);
724 * Provides location searches based on google.maps.Geocoder.
726 WCF
.Location
.GoogleMaps
.LocationSearch
= WCF
.Search
.Base
.extend({
728 * Google Maps geocoder object
729 * @var google.maps.Geocoder
734 * @see WCF.Search.Base.init()
736 init: function(searchInput
, callback
, excludedSearchValues
, commaSeperated
, showLoadingOverlay
) {
737 this._super(searchInput
, callback
, excludedSearchValues
, commaSeperated
, showLoadingOverlay
);
740 this._geocoder
= new google
.maps
.Geocoder();
744 * @see WCF.Search.Base._createListItem()
746 _createListItem: function(geocoderResult
) {
747 var $listItem
= $('<li><span>' + WCF
.String
.escapeHTML(geocoderResult
.formatted_address
) + '</span></li>').appendTo(this._list
);
748 $listItem
.data('location', geocoderResult
.geometry
.location
).data('label', geocoderResult
.formatted_address
).click($.proxy(this._executeCallback
, this));
756 * @see WCF.Search.Base._keyUp()
758 _keyUp: function(event
) {
759 // handle arrow keys and return key
760 switch (event
.which
) {
761 case $.ui
.keyCode
.LEFT
:
762 case $.ui
.keyCode
.RIGHT
:
765 case $.ui
.keyCode
.UP
:
766 this._selectPreviousItem();
769 case $.ui
.keyCode
.DOWN
:
770 this._selectNextItem();
773 case $.ui
.keyCode
.ENTER
:
774 return this._selectElement(event
);
777 var $content
= this._getSearchString(event
);
778 if ($content
=== '') {
779 this._clearList(true);
781 else if ($content
.length
>= this._triggerLength
) {
783 if (this._timer
!== null) {
787 this._timer
= new WCF
.PeriodicalExecuter($.proxy(function() {
788 this._geocoder
.geocode({
790 }, $.proxy(this._success
, this));
794 }, this), this._delay
);
797 this._geocoder
.geocode({
799 }, $.proxy(this._success
, this));
803 // input below trigger length
804 this._clearList(false);
809 * Handles a successful geocoder request.
811 * @param array results
812 * @param integer status
814 _success: function(results
, status
) {
815 this._clearList(false);
817 if (status
!= google
.maps
.GeocoderStatus
.OK
) {
821 if ($.getLength(results
)) {
823 for (var $index
in results
) {
824 this._createListItem(results
[$index
]);
826 if (++$count
== 10) {
831 else if (!this._handleEmptyResult()) {
835 WCF
.CloseOverlayHandler
.addCallback('WCF.Search.Base', $.proxy(function() { this._clearList(); }, this));
837 var $containerID
= this._searchInput
.parents('.dropdown').wcfIdentify();
838 if (!WCF
.Dropdown
.getDropdownMenu($containerID
).hasClass('dropdownOpen')) {
839 WCF
.Dropdown
.toggleDropdown($containerID
, true);
842 // pre-select first item
843 this._itemIndex
= -1;
844 if (!WCF
.Dropdown
.getDropdown($containerID
).data('disableAutoFocus')) {
845 this._selectNextItem();
851 * Handles setting a single location on a Google Map.
853 WCF
.Location
.GoogleMaps
.LocationInput
= Class
.extend({
855 * location search object
856 * @var WCF.Location.GoogleMaps.LocationSearch
858 _locationSearch
: null,
862 * @var WCF.Location.GoogleMaps.Map
867 * draggable marker to set the location
868 * @var google.maps.Marker
873 * Initializes a new WCF.Location.GoogleMaps.LocationInput object.
875 * @param string mapContainerID
876 * @param object mapOptions
877 * @param string searchInput
878 * @param float latitude
879 * @param float longitude
880 * @param string actionClassName
882 init: function(mapContainerID
, mapOptions
, searchInput
, latitude
, longitude
, actionClassName
) {
883 this._searchInput
= searchInput
;
885 if (actionClassName
) {
886 this._map
= new WCF
.Location
.GoogleMaps
.SuggestionMap(mapContainerID
, mapOptions
, actionClassName
);
887 this._map
.setSuggestionSelectionCallback($.proxy(this._useSuggestion
, this));
890 this._map
= new WCF
.Location
.GoogleMaps
.Map(mapContainerID
, mapOptions
);
893 this._locationSearch
= new WCF
.Location
.GoogleMaps
.LocationSearch(searchInput
, $.proxy(this._setMarkerByLocation
, this));
895 if (latitude
&& longitude
) {
896 this._marker
= this._map
.addDraggableMarker(latitude
, longitude
);
899 this._marker
= this._map
.addDraggableMarker(WCF
.Location
.GoogleMaps
.Settings
.get('defaultLatitude'), WCF
.Location
.GoogleMaps
.Settings
.get('defaultLongitude'));
901 WCF
.Location
.Util
.getLocation($.proxy(function(latitude
, longitude
) {
902 if (latitude
!== undefined && longitude
!== undefined) {
903 WCF
.Location
.GoogleMaps
.Util
.moveMarker(this._marker
, latitude
, longitude
);
904 WCF
.Location
.GoogleMaps
.Util
.focusMarker(this._marker
);
909 this._marker
.addListener('dragend', $.proxy(this._updateLocation
, this));
913 * Uses a suggestion by clicking on the "Use suggestion" link in the marker's
918 _useSuggestion: function(event
) {
919 var $marker
= $(event
.currentTarget
).data('marker');
921 this._marker
.setPosition($marker
.getPosition());
922 this._updateLocation();
925 this._map
.showSuggestions(false);
929 * Updates location on marker position change.
931 _updateLocation: function() {
932 WCF
.Location
.GoogleMaps
.Util
.reverseGeocoding($.proxy(function(result
) {
933 if (result
!== null) {
934 $(this._searchInput
).val(result
);
936 }, this), this._marker
);
940 * Sets the marker based on an entered location.
944 _setMarkerByLocation: function(data
) {
945 this._marker
.setPosition(data
.location
);
946 WCF
.Location
.GoogleMaps
.Util
.focusMarker(this._marker
);
948 $(this._searchInput
).val(data
.label
);
952 * Returns the related map.
954 * @return WCF.Location.GoogleMaps.Map
961 * Returns the draggable marker used to set the location.
963 * @return google.maps.Marker
965 getMarker: function() {
971 * Provides utility functions for Google Maps maps.
973 WCF
.Location
.GoogleMaps
.Util
= {
976 * @var google.maps.Geocoder
981 * Focuses the given marker's map on the marker.
983 * @param google.maps.Marker marker
985 focusMarker: function(marker
) {
986 marker
.getMap().setCenter(marker
.getPosition());
990 * Returns the latitude and longitude of the given marker.
994 getMarkerPosition: function(marker
) {
996 latitude
: marker
.getPosition().lat(),
997 longitude
: marker
.getPosition().lng()
1002 * Moves the given marker to the given position.
1004 * @param google.maps.Marker marker
1005 * @param float latitude
1006 * @param float longitude
1007 * @param boolean dragend indicates if "dragend" event is fired
1009 moveMarker: function(marker
, latitude
, longitude
, triggerDragend
) {
1010 marker
.setPosition(new google
.maps
.LatLng(latitude
, longitude
));
1012 if (triggerDragend
) {
1013 google
.maps
.event
.trigger(marker
, 'dragend');
1018 * Performs a reverse geocoding request.
1020 * @param object callback
1021 * @param google.maps.Marker marker
1022 * @param string latitude
1023 * @param string longitude
1024 * @param boolean fullResult
1026 reverseGeocoding: function(callback
, marker
, latitude
, longitude
, fullResult
) {
1028 latitude
= marker
.getPosition().lat();
1029 longitude
= marker
.getPosition().lng();
1032 if (this._geocoder
=== null) {
1033 this._geocoder
= new google
.maps
.Geocoder();
1036 var $latLng
= new google
.maps
.LatLng(latitude
, longitude
);
1037 this._geocoder
.geocode({ latLng
: $latLng
}, function(results
, status
) {
1038 if (status
== google
.maps
.GeocoderStatus
.OK
) {
1039 callback((fullResult
? results
: results
[0].formatted_address
));