Add WCF.Location.GoogleMaps.SuggestionMap
authorMatthias Schmidt <gravatronics@live.com>
Wed, 26 Nov 2014 19:24:26 +0000 (20:24 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Wed, 26 Nov 2014 19:24:26 +0000 (20:24 +0100)
com.woltlab.wcf/templates/googleMapsJavaScript.tpl
wcfsetup/install/files/js/WCF.Location.js
wcfsetup/install/files/style/googleMaps.less
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index cc50240d5d3689ffd3ebc9ba06ecc4a195589757..e2ce2c0ad8a4608e2b576ac3ab2bf6b9f202b0b7 100644 (file)
@@ -4,6 +4,12 @@
 <script data-relocate="true">
        //<![CDATA[
        $(function() {
+               WCF.Language.addObject({
+                       'wcf.map.noLocationSuggestions': '{lang}wcf.map.noLocationSuggestions{/lang}',
+                       'wcf.map.showLocationSuggestions': '{lang}wcf.map.showLocationSuggestions{/lang}',
+                       'wcf.map.useLocationSuggestion': '{lang}wcf.map.useLocationSuggestion{/lang}'
+               });
+               
                WCF.Location.GoogleMaps.Settings.set({
                        disableDoubleClickZoom: {if GOOGLE_MAPS_ENABLE_DOUBLE_CLICK_ZOOM}0{else}1{/if},
                        draggable: {@GOOGLE_MAPS_ENABLE_DRAGGING},
index b6fce7e688cbe57105696169fd088d41e86f485c..f5794b28347e5c6f2fbd84f0c70f1e145e76bcd0 100644 (file)
@@ -488,7 +488,11 @@ WCF.Location.GoogleMaps.LargeMap = WCF.Location.GoogleMaps.Map.extend({
        },
        
        /**
-        * Loads markers if the map is reloaded.
+        * Loads markers if the map is reloaded. Returns true if new markers will
+        * be loaded and false if for the current map bounds, the markers have already
+        * been loaded.
+        * 
+        * @return      boolean
         */
        _loadMarkers: function() {
                var $northEast = this._map.getBounds().getNorthEast();
@@ -497,7 +501,7 @@ WCF.Location.GoogleMaps.LargeMap = WCF.Location.GoogleMaps.Map.extend({
                // check if the user has zoomed in, then all markers are already
                // displayed
                if (this._previousNorthEast && this._previousNorthEast.lat() >= $northEast.lat() && this._previousNorthEast.lng() >= $northEast.lng() && this._previousSouthWest.lat() <= $southWest.lat() && this._previousSouthWest.lng() <= $southWest.lng()) {
-                       return;
+                       return false;
                }
                
                this._previousNorthEast = $northEast;
@@ -515,6 +519,8 @@ WCF.Location.GoogleMaps.LargeMap = WCF.Location.GoogleMaps.Map.extend({
                        })
                });
                this._proxy.sendRequest();
+               
+               return true;
        },
        
        /**
@@ -553,6 +559,128 @@ WCF.Location.GoogleMaps.LargeMap = WCF.Location.GoogleMaps.Map.extend({
        }
 });
 
+/**
+ * Extends the large map implementation by treating non-draggable markers as location
+ * suggestions.
+ */
+WCF.Location.GoogleMaps.SuggestionMap = WCF.Location.GoogleMaps.LargeMap.extend({
+       /**
+        * maps control showing/hiding location suggestions
+        * @var jQuery
+        */
+       _locationSuggestionsButton: null,
+       
+       /**
+        * function called when a location is selected
+        * @var function
+        */
+       _suggestionSelectionCallback: null,
+       
+       /**
+        * @see WCF.Location.GoogleMaps.LargeMap.init()
+        */
+       init: function(mapContainerID, mapOptions, actionClassName, locationSearchInputSelector, additionalParameters) {
+               this._super(mapContainerID, mapOptions, actionClassName, locationSearchInputSelector, additionalParameters);
+               
+               var $locationSuggestionDiv = $('<div class="gmnoprint googleMapsCustomControlContainer"><div class="gm-style-mtc"><div class="googleMapsCustomControl">'  + WCF.Language.get('wcf.map.showLocationSuggestions') + '</div></div></div>');
+               this._locationSuggestionsButton = $locationSuggestionDiv.find('.googleMapsCustomControl').click($.proxy(this._toggleLocationSuggestions, this));
+               
+               this._map.controls[google.maps.ControlPosition.TOP_RIGHT].push($locationSuggestionDiv.get(0));
+       },
+       
+       /**
+        * @see WCF.Location.GoogleMaps.LargeMap._loadMarkers()
+        */
+       _loadMarkers: function() {
+               if (!this._locationSuggestionsButton.hasClass('active')) return;
+               
+               if (!this._super()) {
+                       this._loadSuggestions = false;
+               }
+       },
+       
+       /**
+        * @see WCF.Location.GoogleMaps.LargeMap._loadMarkers()
+        */
+       _success: function(data, textStatus, jqXHR) {
+               var $oldLength = this._markers.length;
+               this._super(data, textStatus, jqXHR);
+               
+               if (this._loadSuggestions && $oldLength == this._markers.length) {
+                       this._loadSuggestions = false;
+                       new WCF.System.Notification(WCF.Language.get('wcf.map.noLocationSuggestions'), 'info').show();
+               }
+       },
+       
+       /**
+        * Handles clicks on the location suggestions button.
+        */
+       _toggleLocationSuggestions: function() {
+               var $showSuggestions = !this._locationSuggestionsButton.hasClass('active');
+               if ($showSuggestions) {
+                       this._loadSuggestions = true;
+               }
+               
+               this.showSuggestions($showSuggestions);
+       },
+       
+       /**
+        * @see WCF.Location.GoogleMaps.Map.addMarker()
+        */
+       addMarker: function(latitude, longitude, title, icon, information) {
+               var $infoWindow = $(information);
+               var $useLocation = $('<a class="googleMapsUseLocationSuggestionLink" />').text(WCF.Language.get('wcf.map.useLocationSuggestion')).click(this._suggestionSelectionCallback);
+               $infoWindow.append($('<p class="marginTopTiny" />').append($useLocation));
+               
+               var $marker = this._super(latitude, longitude, title, '//mt.google.com/vt/icon/name=icons/spotlight/spotlight-waypoint-a.png', $infoWindow.get(0));
+               
+               $useLocation.data('marker', $marker);
+               
+               return $marker;
+       },
+       
+       /**
+        * Sets the function called when a location is selected.
+        * 
+        * @param       function                callback
+        */
+       setSuggestionSelectionCallback: function(callback) {
+               this._suggestionSelectionCallback = callback;
+       },
+       
+       /**
+        * Shows or hides the location suggestions.
+        * 
+        * @param       boolean         showSuggestions
+        */
+       showSuggestions: function(showSuggestions) {
+               // missing argument means showing the suggestions
+               if (showSuggestions === undefined) showSuggestions = true;
+               
+               this._locationSuggestionsButton.toggleClass('active', showSuggestions);
+               
+               var $clusterMarkers = [ ];
+               for (var $i = 0, $length = this._markers.length; $i < $length; $i++) {
+                       var $marker = this._markers[$i];
+                       
+                       // ignore draggable markers
+                       if (!$marker.draggable) {
+                               $marker.setVisible(showSuggestions);
+                               if (showSuggestions) {
+                                       $clusterMarkers.push($marker);
+                               }
+                       }
+               }
+               
+               this._markerClusterer.clearMarkers();
+               if (showSuggestions) {
+                       this._markerClusterer.addMarkers($clusterMarkers);
+               }
+               
+               this._loadMarkers();
+       }
+});
+
 /**
  * Provides location searches based on google.maps.Geocoder.
  */
@@ -697,10 +825,19 @@ WCF.Location.GoogleMaps.LocationInput = Class.extend({
         * @param       string          searchInput
         * @param       float           latitude
         * @param       float           longitude
+        * @param       string          actionClassName
         */
-       init: function(mapContainerID, mapOptions, searchInput, latitude, longitude) {
+       init: function(mapContainerID, mapOptions, searchInput, latitude, longitude, actionClassName) {
                this._searchInput = searchInput;
-               this._map = new WCF.Location.GoogleMaps.Map(mapContainerID, mapOptions);
+               
+               if (actionClassName) {
+                       this._map = new WCF.Location.GoogleMaps.SuggestionMap(mapContainerID, mapOptions, actionClassName);
+                       this._map.setSuggestionSelectionCallback($.proxy(this._useSuggestion, this));
+               }
+               else {
+                       this._map = new WCF.Location.GoogleMaps.Map(mapContainerID, mapOptions);
+               }
+               
                this._locationSearch = new WCF.Location.GoogleMaps.LocationSearch(searchInput, $.proxy(this._setMarkerByLocation, this));
                
                if (latitude && longitude) {
@@ -721,21 +858,19 @@ WCF.Location.GoogleMaps.LocationInput = Class.extend({
        },
        
        /**
-        * Returns the related map.
+        * Uses a suggestion by clicking on the "Use suggestion" link in the marker's
+        * info window.
         * 
-        * @return      WCF.Location.GoogleMaps.Map
+        * @param       Event           event
         */
-       getMap: function() {
-               return this._map;
-       },
-       
-       /**
-        * Returns the draggable marker used to set the location.
-        * 
-        * @return      google.maps.Marker
-        */
-       getMarker: function() {
-               return this._marker;
+       _useSuggestion: function(event) {
+               var $marker = $(event.currentTarget).data('marker');
+               
+               this._marker.setPosition($marker.getPosition());
+               this._updateLocation();
+               
+               // hide suggestions
+               this._map.showSuggestions(false);
        },
        
        /**
@@ -759,6 +894,24 @@ WCF.Location.GoogleMaps.LocationInput = Class.extend({
                WCF.Location.GoogleMaps.Util.focusMarker(this._marker);
                
                $(this._searchInput).val(data.label);
+       },
+       
+       /**
+        * Returns the related map.
+        * 
+        * @return      WCF.Location.GoogleMaps.Map
+        */
+       getMap: function() {
+               return this._map;
+       },
+       
+       /**
+        * Returns the draggable marker used to set the location.
+        * 
+        * @return      google.maps.Marker
+        */
+       getMarker: function() {
+               return this._marker;
        }
 });
 
index e4e4923ff52a67408c2ea98c67051bb83a792542..32185652fdac7918da55515d6172aad478666d89 100644 (file)
@@ -5,3 +5,39 @@
 .sidebarGoogleMap {
        height: 250px;
 }
+
+// CSS code taken from map type controls
+.googleMapsCustomControlContainer {
+       cursor: pointer !important;
+       margin-top: 5px;
+       
+       .googleMapsCustomControl {
+               .userSelectNone;
+               
+               text-align: center;
+               position: relative;
+               color: rgb(86, 86, 86);
+               font-size: 11px !important;
+               background-color: rgb(255, 255, 255);
+               padding: 1px 6px;
+               border-radius: 3px;
+               background-clip: padding-box;
+               border: 1px solid rgba(0, 0, 0, 0.14902);
+               box-shadow: rgba(0, 0, 0, 0.298039) 0px 1px 4px -1px;
+               min-width: 29px;
+               
+               &:hover {
+                       background-color: rgb(235, 235, 235);
+                       color: rgb(0, 0, 0);
+               }
+               
+               &.active {
+                       color: rgb(0, 0, 0);
+                       font-weight: 500;
+               }
+       }
+}
+
+.googleMapsUseLocationSuggestionLink {
+       font-size: @wcfSmallFontSize;
+}
index 2ebcc09b8347fd39e21da6536517ad2892b790a8..d74e6ba29e47cc646832fc9362625ca60e106875 100644 (file)
@@ -2251,6 +2251,12 @@ Fehler sind beispielsweise:
                <item name="wcf.like.title.com.woltlab.wcf.user.profileComment.response"><![CDATA[Mag die Antwort {if $responseAuthor}<a href="{link controller='User' object=$responseAuthor}{/link}">von {$responseAuthor->username}</a>{else}eines Gasts{/if} zum Kommentar {if $commentAuthor}von <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a>{else}eines Gasts{/if} an der <a href="{link controller='User' object=$user}#wall{/link}">Pinnwand von {$user->username}</a>{if $like->isDislike()} nicht{/if}.]]></item>
        </category>
        
+       <category name="wcf.map">
+               <item name="wcf.map.noLocationSuggestions"><![CDATA[Für den aktuellen Kartenausschnitt liegen keine Ortsvorschläge vor.]]></item>
+               <item name="wcf.map.showLocationSuggestions"><![CDATA[Orte vorschlagen]]></item>
+               <item name="wcf.map.useLocationSuggestion"><![CDATA[Ort verwenden]]></item>
+       </category>
+       
        <category name="wcf.message">
                <item name="wcf.message.autosave.restored"><![CDATA[Entwurf wiederhergestellt]]></item>
                <item name="wcf.message.autosave.restored.confirm"><![CDATA[Beibehalten]]></item>
index 63df59e1902af283f9f91bd8719a177b2edc7a5f..a256c79421fa7b41f0cbf369d9c5ad807ac351d7 100644 (file)
@@ -2250,6 +2250,12 @@ Errors are:
                <item name="wcf.like.title.com.woltlab.wcf.user.profileComment.response"><![CDATA[{if $like->isDislike()}Dislikes{else}Likes{/if} the response by {if $responseAuthor}<a href="{link controller='User' object=$responseAuthor}{/link}">{$responseAuthor->username}</a>{else}a guest{/if} on the comment by {if $commentAuthor}<a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a>{else}a guest{/if} on <a href="{link controller='User' object=$user}#wall{/link}">{$user->username}’s wall</a>.]]></item>
        </category>
        
+       <category name="wcf.map">
+               <item name="wcf.map.noLocationSuggestions"><![CDATA[There are no location suggestions in the current map section.]]></item>
+               <item name="wcf.map.showLocationSuggestions"><![CDATA[Suggest Locations]]></item>
+               <item name="wcf.map.useLocationSuggestion"><![CDATA[Use Location]]></item>
+       </category>
+       
        <category name="wcf.message">
                <item name="wcf.message.autosave.restored"><![CDATA[Draft restored]]></item>
                <item name="wcf.message.autosave.restored.confirm"><![CDATA[Keep]]></item>