View file PF.Base/module/feed/static/jscript/places.js

File size: 16.54Kb
/* Implements Google Places into the Feed to achieve a Check-In, it also checks for existing Pages first */
$Core.Feed = 
{
	/*For some reason a user may not want to fetch places from Google (only from Pages) or in case the admin has not set the Google API Key which is required */
	bUseGoogle : true,
	
	bGoogleReady: false,
	
	/* We store the maps and other information related to maps that only show when hovering over their locations in the feed entries */
	aHoverPlaces: {},
	
	/* Here we store the places gotten from Google and Pages. This array is reset as the user moves away from the found place */
	aPlaces : [],
	aPlacesKey: [],

	/* The id of the div that will display the map of the current location */
	sMapId : 'js_feed_check_in_map',
	
	/* This is the button that will trigger loading the autocomplete and the map*/
	sButtonId : 'btn_display_check_in',
	
	/* Google requires the key to be passed so we store it here*/
	sGoogleKey : '',
	
	/* Google's Geocoder object */
	gGeoCoder: undefined,
	
	/* Google's marker in the map */
	gMarker: undefined,
	
	gAutocomplete: undefined,
	
	/* If the browser does not support Navigator we can get the latitude and longitude using the IPInfoDBKey */	
	sIPInfoDbKey: '',
		
	/* Google object holding my location*/
	gMyLatLng : undefined,	
	
	/* Avoid collisions */
	sLastSearch: '',
	
	/* This is the google map object, we can control the map from this variable */
	gMap : undefined,
	
	/* The current status can be:
	 * 0 => Uninitialized
	 * 1 => Waiting for location from IPInfoDb
	 * 2 => Ready to query Google and server
	 */
	iStatus: 0,
	
	/* Prepare our location. If we have the location of the user in the database this function is called After gMyLatLng has been defined. */
	init: function(bForce)
	{
		if (!bCheckinInit) {
			$('#' + $Core.Feed.sMapId)
				.css({
					height: '300px'
				})
				.hide();

			$('#js_location_input, #js_add_location').hide();
		}

		if ($Core.Feed.sGoogleKey.length < 1 )
		{
			return;
		}


		$('#' + $Core.Feed.sButtonId)
			.click(function(){
				bCheckinInit = true;
				if (typeof $Core.Feed.gMyLatLng != 'undefined')
				{
					$Core.Feed.createMap();
					$Core.Feed.showMap();
					return;
				}
				$($Core.Feed).on('mapCreated', function(){ $Core.Feed.showMap(); });
				$Core.Feed.getVisitorLocation();

				return false;	
			});
		
		$('#js_add_location_suggestions')
			.on('mouseout', function(){
				/* $('#js_add_location_suggestions').hide();*/
			});
		
		$('#hdn_location_name')
			.focus(function(){				
				$('#js_feed_check_in_map, #js_add_location_suggestions').show();
				google.maps.event.trigger($Core.Feed.gMap, 'resize');
				$Core.Feed.gMap.setCenter($Core.Feed.gMyLatLng);
			})
			.on('keyup',function(){
				var sName = $(this).val();
				
				if ($(this).val().length < 3 )
				{
					return;
				}
				if ($Core.Feed.sLastSearch == sName)
				{
					return;
				}

				for (var i in $Core.Feed.aPlaces)
				{
					if (typeof $Core.Feed.aPlaces[i]['is_auto_suggested'] != 'undefined' && $Core.Feed.aPlaces[i]['is_auto_suggested'])
					{
						$Core.Feed.aPlacesKey.splice( $.inArray($Core.Feed.aPlaces[i]['id'], $Core.Feed.aPlacesKey), 1 );
						$Core.Feed.aPlaces.splice(i,1);
					}

				}

				$Core.Feed.sLastSearch = sName;
				$Core.Feed.gSearch.nearbySearch(
				{
					/*//bounds: $Core.Feed.gBounds,*/
					location: $Core.Feed.gMyLatLng,
					radius: 6000,
					keyword: sName
				//	rankBy: google.maps.places.RankBy.DISTANCE
				}, 
				function(results, status)
				{
					if (status == google.maps.places.PlacesServiceStatus.OK)
					{
						results.map(function(oResult)
						{
							if ($.inArray(oResult['id'], $Core.Feed.aPlacesKey) == '-1') {
								oResult['is_auto_suggested'] = true;
								$Core.Feed.aPlaces.push(oResult);
								$Core.Feed.aPlacesKey.push(oResult['id']);
							}
						});
					}

					$Core.Feed.displaySuggestions();
				});
			})
			.on('focus', function(){
				if ($('#js_add_location_suggestions').is(':visible') != true)
				{
				    $('#js_add_location_suggestions').show();
				}
			})
			.on('click', function(){
				/* Needed if they are selecting text */
				google.maps.event.trigger($Core.Feed.gMap, 'resize');
			});
		
		
		$($Core.Feed).on('gotVisitorLocation', function(){$Core.Feed.createMap();});

	},
	
	/* This function is called after a map exists ($Core.Feed.createMap() has been executed), it only shows it like when clicking the button */
	showMap : function()
	{
		if (typeof google == 'undefined')
		{
			$Core.Feed.iTimeShowMap = setTimeout($Core.Feed.showMap, 1000);
			return;
		}		
		
		if (typeof $Core.Feed.iTimeShowMap != 'undefined')
		{
			clearTimeout($Core.Feed.iTimeShowMap);
		}
		

		var gTempLat = false;
		$('#li_location_name, #js_location_input, #hdn_location_name, #js_add_location, #js_add_location_suggestions, #js_feed_check_in_map, #' + $Core.Feed.sMapId).show(400);
		$('.activity_feed_form_button_position').hide(400);
		setTimeout(
		    function()
		    {
			$('#' + $Core.Feed.sMapId).css('height', '300px');			
			
			/*setTimeout(function(){*/
				if (gTempLat == true)
				{
					return;
				}
				else
				{
					gTempLat = true;
				}
				
				$Core.Feed.getNewLocations(true);
				$('#hdn_location_name').focus();
				/*setTimeout(function(){*/
					google.maps.event.trigger($Core.Feed.gMap, 'resize');
					$Core.Feed.gMap.setCenter($Core.Feed.gMyLatLng);
				/*}, 700);*/
				
			/*}, 400);*/
		    }, 400
		);
		
	},
	
	
	getVisitorLocation :function(sFunction)
	{
		$('#js_add_location, #js_add_location_suggestions').show();
		if (typeof $Core.Feed.gMyLatLng != 'undefined')
		{
			if (typeof sFunction == 'function')
			{
				sFunction();
			}
			/* We already have a location */
			return false;
		}
		/* Get the visitors location */
		if(navigator.geolocation)
		{
			navigator.geolocation.getCurrentPosition(function(oPos) 
			{
				if (oPos.coords.latitude == 0 && oPos.coords.longitude == 0)
				{
					return;
				}
				$Core.Feed.gMyLatLng = new google.maps.LatLng(oPos.coords.latitude, oPos.coords.longitude);				
				$($Core.Feed).trigger('gotVisitorLocation');
				$.ajaxCall('user.saveMyLatLng', 'lat=' + oPos.coords.latitude + '&lng=' + oPos.coords.longitude);
			},
				function(){ $Core.Feed.getLocationWithoutHtml5(sFunction); }
			);
		}
		else
		{
			this.getLocationWithoutHtml5();
		}		
	},
	
	getLocationWithoutHtml5: function(sFunction)
	{
		/* Get visitor's city  */
		var sCookieLocation = getCookie('core_places_location');
		if (sCookieLocation != null)
		{
			var aLocation = sCookieLocation.split(',');
			$Core.Feed.gMyLatLng = new google.maps.LatLng( aLocation[0], aLocation[1]);
			$($Core.Feed).trigger('gotVisitorLocation');
		}
		else
		{
			var sParams = 'section=feed';
			switch (sFunction)
			{
				case 'showMap': sParams += '&callback=$Core.Feed.showMap'; break;
				case 'createMap': sParams += '&callback=$Core.Feed.createMap'; break;
			}
			$.ajaxCall('core.getMyCity', sParams);
		}
	},
	
	/* Called from the template when we have the location of the visitor */
	setVisitorLocation : function(fLat, fLng)
	{
		return false;
		$Core.Feed.gMyLatLng = new google.maps.LatLng(fLat, fLng);
		$($Core.Feed).trigger('gotVisitorLocation');
	},
		
	createMap : function()
	{
		/* Creating map */
		if (typeof $Core.Feed.gMyLatLng == 'undefined' || typeof $Core.Feed.gMap != 'undefined')
		{
			return;
		}
		
		/* Build the map*/		
		var oMapOptions = 
		{
			zoom: 13,
			mapTypeId: google.maps.MapTypeId.ROADMAP,
			center: $Core.Feed.gMyLatLng,
			streetViewControl: false,
			scrollWheel: false
		};
		
		$('#js_add_location, #js_feed_check_in_map, #' + $Core.Feed.sMapId).show(400);
		setTimeout( function()
		{
			$Core.Feed.gMap = new google.maps.Map(document.getElementById($Core.Feed.sMapId), oMapOptions);
			/* Create the search object*/
			$Core.Feed.gSearch = new google.maps.places.PlacesService($Core.Feed.gMap);
			/* Build the marker */
			$Core.Feed.gMarker = new google.maps.Marker({
				map: $Core.Feed.gMap,
				position: $Core.Feed.gMyLatLng,
				draggable: true,
				animation: google.maps.Animation.DROP
			});
			
			/* Now attach an event for the marker */
			google.maps.event.addListener( $Core.Feed.gMarker, 'mouseup', function()
			{
				/* Refresh gMyLatLng*/
				$Core.Feed.gMyLatLng = new google.maps.LatLng($Core.Feed.gMarker.getPosition().lat(), $Core.Feed.gMarker.getPosition().lng());
				
				/* Center the map */
				$Core.Feed.gMap.panTo($Core.Feed.gMyLatLng);					
				
				$Core.Feed.getNewLocations();
			});
			
		}, 400);
		
		/* We need the name of the city to pre-populate the input */
		$Core.Feed.gGeoCoder = new google.maps.Geocoder();
		$Core.Feed.gGeoCoder.geocode({'latLng': $Core.Feed.gMyLatLng }, function(oResults, iStatus)
		{
			if (iStatus == google.maps.GeocoderStatus.OK && oResults[1])
			{
				$('#hdn_location_name').val( oResults[1].formatted_address );	
				$('#val_location_name').val( oResults[1].formatted_address );
				$('#val_location_name').val( oResults[1].geometry.location.lat() + ',' + oResults[1].geometry.location.lng() );
				
				oResults[1]['default_location'] = true;
				
				$Core.Feed.oDefaultPlace = oResults[1];				
				$Core.Feed.oDefaultPlace.name = oResults[1].formatted_address;
				$Core.Feed.oDefaultPlace.id = Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
			}
		});
		
		$Core.Feed.gBounds = new google.maps.LatLngBounds(
			new google.maps.LatLng( $Core.Feed.gMyLatLng.lat() - 1, $Core.Feed.gMyLatLng.lng()),
			new google.maps.LatLng( $Core.Feed.gMyLatLng.lat(), $Core.Feed.gMyLatLng.lng() + 1)
		);
		
		
		/* At this point gMyLatLng must exist */
		$.ajaxCall('feed.loadEstablishments', 'latitude=' + $Core.Feed.gMyLatLng.lat() + '&longitude=' + $Core.Feed.gMyLatLng.lng());
		
		$($Core.Feed).trigger('mapCreated');
	},
	
	getHash: function(sStr)
	{
		var iHash = 0;
		if (sStr.length == 0) return iHash;
		for (var i = 0; i < sStr.length; i++)
		{
			iHash = ((iHash << 5) - iHash) + sStr.charCodeAt(i);			
		}
		return iHash;
	},
	
	/* Populates and displays the div to show establishments given the current position as defined by gMyLatLng.
	 * it checks all of the items in aPlaces and gets the 10 nearer gMyLatLng, places the name of the city first.*/	 
	displaySuggestions: function()
	{		
		var sOut = '';
		
	//	$Core.Feed.aPlaces.push( $Core.Feed.oDefaultPlace );
		$Core.Feed.aPlaces.reverse();
		
		$Core.Feed.aPlaces.map(function(oPlace)
		{
			sOut += '<div class="js_div_place" onmouseover="$Core.Feed.hintPlace(\''+oPlace['id']+'\');" onclick="$Core.Feed.chooseLocation(\'' + oPlace['id'] + '\');">';
			sOut += '<div class="js_div_place_name">' + oPlace['name'] + '</div>';
			if (typeof oPlace['vicinity'] != 'undefined')
			{
				sOut += '<div class="js_div_place_vicinity">, ' + oPlace['vicinity'] + '</div>';
			}
			sOut += '</div>';
		});
		
		$('#js_add_location_suggestions').html(sOut).css({'z-index': 900, 'max-height':'150px'}).show();
	},
	
	/* Move the marker and pan the map to a location */
	hintPlace: function(sId)
	{
		$Core.Feed.aPlaces.map(function(oPlace)
		{
			if (oPlace['id'] == sId)
			{
				$Core.Feed.gMap.panTo( oPlace['geometry']['location'] );
				$Core.Feed.gMarker.setPosition(oPlace['geometry']['location']);
			}
		});
		
	},
	
	/* Visually accepts a suggestion and sets the internal value for the form*/
	chooseLocation: function(id)
	{
		var oPlace = false;
		$Core.Feed.aPlaces.map(function(oCheck){
			if (oCheck['id'] == id){ oPlace = oCheck; return; }
		});
		if (oPlace == false)
		{
			return;
		}
		
		if (typeof oPlace['latitude'] != 'undefined')
		{
			$('#val_location_latlng').val( oPlace['latitude'] + ',' + oPlace['longitude']);
		}
		else if (typeof oPlace['geometry'] != 'undefined')
		{
			$('#val_location_latlng').val( oPlace['geometry']['location'].lat() + ',' +  oPlace['geometry']['location'].lng());
		}
		$('#hdn_location_name, #val_location_name').val( oPlace['name']);
		$('#js_location_feedback').html( oTranslations['at_location'].replace('{location}', oPlace['name'])).show();
		$('#js_add_location_suggestions, #js_feed_check_in_map, #js_location_input').hide();
		$('.activity_feed_form_button_position').show();
	},
	
	/* Adds New places to the $Core.Feed.aPlaces array by scannig the existing items before adding a new one,
	 * Receives a string in json format, called from an ajax response. The second parameter is an optional callback function */
	storePlaces: function(jPlaces, oCallback)
	{
		var oPlaces = $.parseJSON(jPlaces);
		$(oPlaces).each(function(iPlace, oNewPlace)
		{
			var bAddPage = true;
			$Core.Feed.aPlaces.map(function(oFeedPlace)
			{
				if (typeof oFeedPlace['page_id'] != 'undefined' && oFeedPlace['page_id'] == oNewPlace['page_id'])
				{
					/* its a page that we already added*/
					bAddPage = false;
				}
			});
			
			if (bAddPage)
			{
				if (typeof oNewPlace['id'] == 'undefined')
				{
					oNewPlace['id'] = Math.round(1000000*Math.random());
					oNewPlace['geometry']['location'] = new google.maps.LatLng( oNewPlace['geometry']['latitude'], oNewPlace['geometry']['longitude'] );
				}
				
				$Core.Feed.aPlaces.push(oNewPlace);
				$Core.Feed.aPlacesKey.push(oNewPlace['id']);
			}
		});
		
		if (typeof oCallback == 'function')
		{
			oCallback();
		}
	},
	
	/* Ajax call to get more locations, needs to be called after a marker exists */
	getNewLocations: function(bAuto)
	{
		if (typeof $Core.Feed.gSearch == 'undefined')
		{
		    $Core.Feed.gSearch = new google.maps.places.PlacesService($Core.Feed.gMap);
		}
		var aTemp = [];
		$Core.Feed.aPlaces.map(function(oPlace){
			if (typeof oPlace['page_id'] != 'undefined') aTemp.push(oPlace);
		});
		
		$Core.Feed.aPlaces = aTemp;
		
		var sOut = '';
		
		$Core.Feed.gSearch.nearbySearch({
			location: $Core.Feed.gMyLatLng,
			radius: '500'			
		}, function(aResults, iStatus){
			if (iStatus == google.maps.places.PlacesServiceStatus.OK) 
			{
				for (var i = 0; i < aResults.length; i++) 
				{
					if (typeof bAuto == 'boolean' && bAuto == true)
					{
						aResults[i]['is_auto_suggested'] = true;
					}
					$Core.Feed.aPlaces.push(aResults[i]);
					$Core.Feed.aPlacesKey.push(aResults[i]['id']);
				}
			}
			$Core.Feed.displaySuggestions();
		});
	},
	
	/* Does'nt have to be exact or in any specific measure, just needs to reliably tell *a* distance*/
	getDistanceFromPoints: function(oPlace1, oPlace2)
	{
		var xs = Math.pow( (oPlace2['latitude'] - oPlace1['latitude']), 2);
		var ys = Math.pow( (oPlace2['longitude'] - oPlace1['longitude']), 2);
		
		return Math.sqrt(xs + ys);
	},
	
	googleReady : function(sGoogleKey)
	{
		if ($Core.Feed.bGoogleReady) {
			$Core.Feed.init();
			return false;
		}
		if (typeof google !== 'undefined') {
			$Core.Feed.bGoogleReady = true;
			$Core.Feed.init();
			return false;
		}
		sAddr = 'http://';
		if (window.location.protocol == "https:")
		{
			sAddr = 'https://';
		}
		var script  = document.createElement("script");
		script.type = "text/javascript";
		script.src  = sAddr+"maps.google.com/maps/api/js?libraries=places&sensor=true&key=" + sGoogleKey + "&callback=$Core.Feed.init";
		document.body.appendChild(script);
		$Core.Feed.bGoogleReady = true;
	},
	
	showHoverMap : function(fLat, fLng, oObj)
	{
		/* Check if this item already has a map */
		if ($(oObj).siblings('.js_location_map').length > 0 )
		{
			$(oObj).siblings('.js_location_map').show();
			/* Trigger the resize to avoid visual glitches */
			google.maps.event.trigger($Core.Feed.aHoverPlaces[ $(oObj).siblings('.js_location_map').attr('id') ], 'resize');
			return;
		}
		
		var sId = 'js_map_' + Math.floor(Math.random() * 100000);
		
		var sInfoWindow = '<div class="js_location_map" id="' + sId + '"></div>';
		
		/* Load the map */
		$(oObj).after(sInfoWindow);
		
		var gLatLng = new google.maps.LatLng(fLat, fLng);
		var oMapOptions = 
		{
		  zoom: 13,
		  mapTypeId: google.maps.MapTypeId.ROADMAP,
		  center: gLatLng,
		  streetViewControl: false,
		  disableDefaultUI: true
		};
		
		$Core.Feed.aHoverPlaces[sId] = {
			map: new google.maps.Map(document.getElementById(sId), oMapOptions),
			geometry: {location : gLatLng}
			};

		/* Build the marker */
		$Core.Feed.gMarker = new google.maps.Marker({
			map: $Core.Feed.aHoverPlaces[sId]['map'],
			position: gLatLng,
			draggable: true,
			animation: google.maps.Animation.DROP
		});
		
		google.maps.event.trigger( $Core.Feed.aHoverPlaces[sId]['map'], 'resize');
		$(oObj).on('mouseout', function(){
			$('#' + sId).hide();			
		});
	},
	
	resetLocation:function()
	{
		$.ajaxCall('core.getMyCity', 'section=feed&saveLocation=1');
		$('#hdn_location_name').val(oTranslations['loading']);
	},
	
	
	cancelCheckIn: function()
	{
		/* Visually hide everything */
		$('#js_add_location, #js_location_input').hide();
		$('.activity_feed_form_button_position').show();
		$('#hdn_location_name, #val_location_name ,#val_location_latlng').val('');
	}
};