Index: main/trunk/greenstone2/perllib/doc.pm
===================================================================
--- main/trunk/greenstone2/perllib/doc.pm	(revision 33127)
+++ main/trunk/greenstone2/perllib/doc.pm	(revision 33128)
@@ -1138,13 +1138,29 @@
 		
 		if($field =~ m/^(.+\.)?Longitude$/) {
-			# if we are dealing with Longitude meta, we should 1. have Latitude meta; 2. already have processed Latitude meta
+			# if we are dealing with Longitude meta, we should 1. have Latitude meta too; 2. already have processed Latitude meta
 			# in that case, add both Lat and Lng of this section as a Coordinate meta
 			my $latitude = $self->get_metadata_element ($section, "Latitude");			
 			# TODO: would like all Longitude info together followed by all Coordinate info, but the following will add all coord info meta and end of this function will add Longitude meta
-			$self->processCoordinate($section_ptr, $latitude, $value); # value is Longitude
+			$self->processCoordinate($section, $latitude, $value); # value is Longitude
 		}
 	}
 
 	elsif($field eq "GPS.mapOverlay") { # then the value is a JSON string
+	
+		# TODO:
+		# If we already have Coordinate meta for this section of the document (as can happen during buildcol.pl),
+		# let's ASSUME this means we've already processed GPS.mapOverlay meta into Coordinate meta for this section (can have happened during import.pl)
+		# to avoid adding duplicate Coordinates meta, which then end up duplicated in the index
+		# Of course, the assumption is not always true! We could have an image with embedded Lat and Lng meta,
+		# and the same image doc's section could have GPS.mapOverlay meta (from shapes) added via the doc editor.
+		# This very function would then have converted Lat/Lng into Coordinate meta (just in the if stmt above) and added it to the section.
+		# And then by the time we process this section's GPS.mapOverlay meta here, we would notice the section has Coordinate meta already,
+		# and therefore skip converting the GPS.mapOverlay meta into Coordinate meta! What to dooooo?
+		# So the return statement immediately below is a temporary solution, until we find a better one that will always work.
+		my $metaMap = $self->get_metadata_hashmap($section);
+		if($metaMap->{'Coordinate'}) { 
+			return;
+		}
+		
 		print STDERR "GPS.mapOverlay before val: " . $value . "\n";
 		
@@ -1214,8 +1230,8 @@
 				print STDERR "cos $centre_lat is $cos_lat\n";
 
-				$self->processCoordinate($section_ptr, $lat_north, $lng_east);
-				$self->processCoordinate($section_ptr, $lat_south, $lng_east);
-				$self->processCoordinate($section_ptr, $lat_south, $lng_west);
-				$self->processCoordinate($section_ptr, $lat_north, $lng_west);
+				$self->processCoordinate($section, $lat_north, $lng_east);
+				$self->processCoordinate($section, $lat_south, $lng_east);
+				$self->processCoordinate($section, $lat_south, $lng_west);
+				$self->processCoordinate($section, $lat_north, $lng_west);
 			
 			}
@@ -1223,10 +1239,10 @@
 				print STDERR "@@ MARKER FOUND WITH LAT: " . $shape->{"position"}->{"lat"} . "\n";
 				print STDERR "@@ MARKER FOUND WITH LNG: " . $shape->{"position"}->{"lng"} . "\n";
-				$self->processCoordinate($section_ptr, $shape->{"position"}->{"lat"}, $shape->{"position"}->{"lng"});				
+				$self->processCoordinate($section, $shape->{"position"}->{"lat"}, $shape->{"position"}->{"lng"});				
 			}
 			elsif ($type eq "polyline" || $type eq "polygon") {
 				my $path_array = $shape->{"path"};
 				foreach my $position (@$path_array) {									
-					$self->processCoordinate($section_ptr, $position->{"lat"}, $position->{"lng"});
+					$self->processCoordinate($section, $position->{"lat"}, $position->{"lng"});
 				}
 			}
@@ -1235,8 +1251,8 @@
 				my $bounds = $shape->{"bounds"};				
 			
-				$self->processCoordinate($section_ptr, $bounds->{"north"}, $bounds->{"east"});
-				$self->processCoordinate($section_ptr, $bounds->{"south"}, $bounds->{"east"});
-				$self->processCoordinate($section_ptr, $bounds->{"south"}, $bounds->{"west"});
-				$self->processCoordinate($section_ptr, $bounds->{"north"}, $bounds->{"west"});
+				$self->processCoordinate($section, $bounds->{"north"}, $bounds->{"east"});
+				$self->processCoordinate($section, $bounds->{"south"}, $bounds->{"east"});
+				$self->processCoordinate($section, $bounds->{"south"}, $bounds->{"west"});
+				$self->processCoordinate($section, $bounds->{"north"}, $bounds->{"west"});
 			}	
 		
@@ -1280,5 +1296,7 @@
 sub processCoordinate {
 	my $self = shift (@_);
-    my ($section_ptr, $latitude, $longitude) = @_;
+    my ($section, $latitude, $longitude) = @_;
+
+	my $section_ptr = $self->_lookup_section($section);
 
 	my $lat_direction = ($latitude =~ m/^-/) ? "S" : "N";
Index: main/trunk/greenstone3/web/interfaces/default/js/classifier_scripts.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/classifier_scripts.js	(revision 33127)
+++ main/trunk/greenstone3/web/interfaces/default/js/classifier_scripts.js	(revision 33128)
@@ -11,4 +11,17 @@
 	}
 	return false;
+}
+
+// TODO: Is there a better solution
+function _basicToggleSection(sectionID) {
+	// Leave this function here, even though it's empty.
+	// This function is here because:
+	// - it mirrors the identically named version in document_scripts
+	// - and this allows map_scripts to override it without knowing whether it's
+	//   overriding classifier_scripts::toggleSection() or document_scripts::toggleSection().
+	
+	// This method is not meant to call toggleSection. If anything it would be the other way around
+	// (as occurs in doc_scripts.js). But this method has to remain empty for classifier_scripts.js
+	// since map_scripts largely repeats classifier_scripts.js::toggleSection() code.
 }
 
@@ -111,5 +124,5 @@
 	if(!inProgress[sectionID])
 	{
-		inProgress[sectionID] = true;		
+		inProgress[sectionID] = true;
 		
 		var sectionToggle = gs.jqGet("toggle" + sectionID);
Index: main/trunk/greenstone3/web/interfaces/default/js/document_scripts.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/document_scripts.js	(revision 33127)
+++ main/trunk/greenstone3/web/interfaces/default/js/document_scripts.js	(revision 33128)
@@ -1,3 +1,41 @@
 /** Javascript file for viewing documents */
+
+//-------TODO--------//
+// map-scripts.js needs these, but non-map viewing does not. Yet if we add these to map_scripts,
+// then in classifier mode, map_scripts will use classifier_scripts.js which already has these
+// So for now, we add them into this file for when map_scripts is in doc view mode and includes document_scripts.js.
+// It seems suboptimal, as these variables and function will be wasted when in regular non-map mode.
+// But unable to think of any other solution at present.
+var inProgress = new Array();
+var openClassifiers = new Array();
+var busy = false;
+
+
+
+function updateOpenClassifiers()
+{
+	var oc = "";
+	var first = true;
+	for(var key in openClassifiers)
+	{
+		if(first)
+		{
+			first = false;
+		}
+		else
+		{
+			oc += ",";
+		}
+		
+		oc += key;
+	}
+	
+	if(oc != undefined)
+	{
+		window.location.hash = oc;
+	}
+}
+
+//---------------//
 
 /** NOTE, this file uses inline templates which look for httpPath, assocfilepath, Source, Thumb, Title metadata. These need to be added into any xsl file that uses this javascript (using <gsf:metadata name="xx" hidden="true"/> if they are not already being collected. */
@@ -66,6 +104,6 @@
 	url += "&ck=" + gs.cgiParams.ck;
     }
-     
-    
+	
+	
 	
 	$.ajax(url)
@@ -82,5 +120,5 @@
 			}
 			
-			var text = response.substring(textStart, textEnd);
+			var text = response.substring(textStart, textEnd);			
 			callback(text);
 		}
@@ -133,7 +171,8 @@
 				return;
 			}
-			
-			var sections = response.substring(sectionsStart, sectionsEnd);
-			callback(sections);
+			else {
+				var sections = response.substring(sectionsStart, sectionsEnd);
+				callback(sections);
+			}
 		}
 		else
@@ -145,8 +184,15 @@
 	{
 		callback(null);
-	});
-}
-
+	});				
+}
+
+// TODO:
+// DO NOT "MERGE" _basicToggleSection into toggleSection!
+// map_scripts.js calls _basicToggleSection as it redefines toggleSection() to do (more) stuff.
 function toggleSection(sectionID, callback, tocDisabled)
+{
+	_basicToggleSection(sectionID, callback, tocDisabled);	
+}
+function _basicToggleSection(sectionID, callback, tocDisabled)
 {
 	var docElem = gs.jqGet("doc" + sectionID);
@@ -173,5 +219,5 @@
 			{
 				if(text)
-				{	
+				{					
 					var nodeID = sectionID.replace(/\./g, "_");
 					if(text.search("wrap" + nodeID) != -1)
@@ -193,5 +239,5 @@
 							if(callback)
 							{
-								callback(true);
+								callback(true);								
 							}
 							
@@ -219,7 +265,7 @@
 					}
 				}
-			});
-		
-			docToggleElem.attr("src", gs.imageURLs.loading);
+			});		
+			
+			docToggleElem.attr("src", gs.imageURLs.loading);			
 		}
 		else
@@ -310,5 +356,5 @@
 {
 	expandAndExecute(sectionID, level, tocDisabled, function()
-			{
+			{				
 				var topVal = $(document.getElementById("doc" + sectionID)).offset().top - 50;
 				$('html, body').stop().animate({scrollTop: topVal}, 1000);
@@ -332,5 +378,5 @@
 	if(!level)
 	{
-		level = 0;
+		level = 0;		
 	}
 	var parts = sectionID.split(".");
@@ -360,9 +406,9 @@
 		toggleSection(idToExpand, function(success)
 		{
-			if(success)
-			{
-				expandAndExecute(sectionID, level + 1, tocDisabled, executeAfter);
-			}
-		}, tocDisabled);
+				if(success)
+				{
+					expandAndExecute(sectionID, level + 1, tocDisabled, executeAfter);
+				}			
+			}, tocDisabled);		
 	}
 	else
@@ -534,5 +580,6 @@
 {
 	var docElem = gs.jqGet("doc" + sectionID);
-	if(docElem.css("display") == "block")
+	
+	if(docElem.css("display") === "block")
 	{
 		return true;
Index: main/trunk/greenstone3/web/interfaces/default/js/map-scripts.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/map-scripts.js	(revision 33127)
+++ main/trunk/greenstone3/web/interfaces/default/js/map-scripts.js	(revision 33128)
@@ -24,5 +24,5 @@
 	if(jsonNodeDiv.length)
 	{
-		console.log("@@@ JSON node div html: " + jsonNodeDiv.html());
+		//console.log("@@@ JSON node div html: " + jsonNodeDiv.html());
 		var jsonNodes = eval(jsonNodeDiv.html());
 		
@@ -32,7 +32,6 @@
 			{
 				_docList[jsonNodes[i].nodeID] = jsonNodes[i];
-				_docList.ids.push(jsonNodes[i].nodeID);
-				console.log("@@@ JSON node: " + jsonNodes[i]);
-				createMarker(jsonNodes[i], true);
+				_docList.ids.push(jsonNodes[i].nodeID);				
+				createMarkers(jsonNodes[i], true);
 			}
 			updateMap();
@@ -40,7 +39,7 @@
 		else
 		{
+			//hiding the map
 			//$("#map_canvas").css({visibility:"hidden", height:"0px"});
-			$("#map_canvas").css({visibility:"hidden"});
-			//console.log("suppressing hiding the map");
+			$("#map_canvas").css({visibility:"hidden"}); // if you comment this out, add a log message saying "suppressing hiding map"
 		}
 	}
@@ -97,5 +96,4 @@
 	
 	if ($map_canvas.length > 0) {
-		console.log("### map-scripts::setUpMap: map_canvas.exists");
 		_map = new google.maps.Map($map_canvas[0], myOptions);
 		google.maps.event.addListener(_map, 'bounds_changed', performSearchForMarkers);
@@ -254,5 +252,5 @@
 			var endIndex = responseText.indexOf("</");
 
-			console.log("@@@@ performSearch, got response: " + responseText);
+			//console.log("@@@@ performSearch, got response: " + responseText);
 
 			var jsonNodes = eval(responseText.substring(startIndex+1, endIndex));
@@ -271,5 +269,5 @@
 						_docList.ids.push(doc.nodeID);
 
-						createMarker(doc, false);
+						createMarkers(doc, false);
 					}
 				}
@@ -337,7 +335,11 @@
 		}
 
-		if(doc.coord) {
-			var coordInfo = getLatLngForCoord(doc.coord);
-			bounds.extend(new google.maps.LatLng(coordInfo.lat, coordInfo.lng));
+		
+		if(doc.coords) {
+			for(var x = 0; x < doc.coords.length; x++) {
+				var coord = doc.coords[x];
+				var coordInfo = getLatLngForCoord(doc.coords[x]);
+				bounds.extend(new google.maps.LatLng(coordInfo.lat, coordInfo.lng));
+			}
 		}
 		else {
@@ -463,7 +465,10 @@
 		clearInterval(_intervalHandle);
 		_intervalHandle = null;
-		if(doc.coord) {
-			var coordInfo = getLatLngForCoord(doc.coord);
-			_map.panTo(new google.maps.LatLng(coordInfo.lat, coordInfo.lng));
+		if(doc.coords) {
+			for(var x = 0; x < doc.coords.length; x++) {
+				var coord = doc.coords[x];
+				var coordInfo = getLatLngForCoord(doc.coords[x]);
+				_map.panTo(new google.maps.LatLng(coordInfo.lat, coordInfo.lng));
+			}
 		} else {
 			_map.panTo(new google.maps.LatLng(doc.lat, doc.lng));
@@ -488,15 +493,22 @@
 }
 
-function createMarker(doc, mainMarker)
-{
-	var pos;
-	if(doc.coord) {
-		var coordInfo = getLatLngForCoord(doc.coord);			
-		pos = new google.maps.LatLng(coordInfo.lat,coordInfo.lng);		
+function createMarkers(doc, mainMarker) {
+	if(doc.coords) {
+		for(var x = 0; x < doc.coords.length; x++) {
+			var coord = doc.coords[x];
+			var coordInfo = getLatLngForCoord(doc.coords[x]);
+			pos = new google.maps.LatLng(coordInfo.lat,coordInfo.lng);			
+			createMarker(doc, pos, mainMarker);
+		}
 	} else {
 		pos = new google.maps.LatLng(doc.lat,doc.lng);
-	}
-	
-	
+		createMarker(doc, pos, mainMarker);
+	}
+}
+
+
+// Param mainMarker: if set to true, marker is red. If false, marker is blue
+function createMarker(doc, pos, mainMarker)
+{
 	var docEdit = (("docEdit" in gs.cgiParams) && (gs.cgiParams['docEdit']));
 	//var draggable_val = (docEdit) ? true : false;
@@ -609,5 +621,5 @@
 				_docList.ids.push(doc.nodeID);
 
-				createMarker(doc, false);
+				createMarkers(doc, false);
 			}
 			
@@ -825,13 +837,19 @@
 function modifyFunctions()
 {
-	toggleSection = function(sectionID)
-	{
+	// This function "overrides" toggleSection in both classifier_scripts.js and document_scripts.js
+	// However, classifier_scripts.js::toggleSection() only took one parameter, sectionID, whereas
+	// document_scripts.js::toggleSection() took 3 params (sectionID, callback, tocDisabled).
+	// So to be compatible with both, need map-scripts::toggleSection() here to support all 3 in that order.
+	toggleSection = function(sectionID, callback, tocDisabled)
+	{
+		_basicToggleSection(sectionID, callback, tocDisabled);
+		
 		var section = gs.jqGet("div" + sectionID);
-		var sectionToggle = gs.jqGet("toggle" + sectionID);
-		
+		var sectionToggle = gs.jqGet("toggle" + sectionID);		
+				
 		if(sectionToggle == undefined)
-		{
+		{			
 			return;
-		}
+		}		
 		
 		// Test if 'section' exists.  
@@ -839,5 +857,5 @@
 		// http://stackoverflow.com/questions/920236/how-can-i-detect-if-a-selector-returns-null
 		if(section.length !== 0)
-		{			
+		{				
 			if(isExpanded(sectionID))
 			{
@@ -862,5 +880,6 @@
 		{
 			httpRequest(sectionID);
-		}
+		}		
+		
 	}
 	
@@ -901,4 +920,8 @@
 					checkout();
 				}
+				/*else if(gs.cgiParams.documentbasket == "on") // TODO: copied from classifier_scripts.js - should this else block be included here (and happen when mapEnabled) or not?
+				{
+					dmcheckout();
+				}*/
 				updateOpenClassifiers();
 				getSubClassifier(sectionID);
Index: main/trunk/greenstone3/web/interfaces/default/transform/map-tools.xsl
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/transform/map-tools.xsl	(revision 33127)
+++ main/trunk/greenstone3/web/interfaces/default/transform/map-tools.xsl	(revision 33128)
@@ -39,7 +39,13 @@
 	  <xsl:if test="metadataList/metadata[@name = 'Coordinate']">
 		<xsl:text disable-output-escaping="yes">,</xsl:text>
-		<xsl:text disable-output-escaping="yes">"coord":"</xsl:text>		
-		<xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name = 'Coordinate']"/>
-		<xsl:text disable-output-escaping="yes">"</xsl:text>
+		<xsl:text disable-output-escaping="yes">"coords":</xsl:text>
+		<xsl:text>[</xsl:text>
+		<xsl:for-each select="metadataList/metadata[@name = 'Coordinate']">
+			<xsl:text disable-output-escaping="yes">"</xsl:text>
+			<xsl:value-of disable-output-escaping="yes" select="current()"/>
+			<xsl:text disable-output-escaping="yes">"</xsl:text>
+			<xsl:text disable-output-escaping="yes">,</xsl:text>
+		</xsl:for-each>
+		<xsl:text>]</xsl:text>
 	  </xsl:if>
 	  <xsl:text>}</xsl:text>
Index: main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl	(revision 33127)
+++ main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl	(revision 33128)
@@ -140,5 +140,5 @@
 			<xsl:if test="not(/page/pageResponse/format[@type='display' or @type='browse' or @type='search']/gsf:option[@name='sectionExpandCollapse']/@value) or /page/pageResponse/format[@type='display' or @type='browse' or @type='search']/gsf:option[@name='sectionExpandCollapse']/@value = 'true'">
 				<td class="headerTD">
-					<img id="dtoggle{@nodeID}" onclick="toggleSection('{@nodeID}');" class="icon">			
+					<img id="dtoggle{@nodeID}" onclick="toggleSection('{@nodeID}');" class="icon">
 						<xsl:attribute name="src">
 							<xsl:choose>
@@ -856,6 +856,13 @@
 							<xsl:if test="metadataList/metadata[@name = 'Coordinate']">
 								<xsl:text disable-output-escaping="yes">,</xsl:text>
-								<xsl:text disable-output-escaping="yes">"coord":"</xsl:text><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name = 'Coordinate']"/>
-								<xsl:text disable-output-escaping="yes">"</xsl:text>
+								<xsl:text disable-output-escaping="yes">"coords":</xsl:text>
+								<xsl:text>[</xsl:text>
+								<xsl:for-each select="metadataList/metadata[@name = 'Coordinate']">
+									<xsl:text disable-output-escaping="yes">"</xsl:text>
+									<xsl:value-of disable-output-escaping="yes" select="current()"/>
+									<xsl:text disable-output-escaping="yes">"</xsl:text>
+									<xsl:text disable-output-escaping="yes">,</xsl:text>
+								</xsl:for-each>
+								<xsl:text>]</xsl:text>
 							</xsl:if>
 							<xsl:text>}</xsl:text>
@@ -881,6 +888,13 @@
 							<xsl:if test="metadataList/metadata[@name = 'Coordinate']">
 								<xsl:text disable-output-escaping="yes">,</xsl:text>
-								<xsl:text disable-output-escaping="yes">"coord":"</xsl:text><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name = 'Coordinate']"/>
-								<xsl:text disable-output-escaping="yes">"</xsl:text>
+								<xsl:text disable-output-escaping="yes">"coords":</xsl:text>
+								<xsl:text>[</xsl:text>
+								<xsl:for-each select="metadataList/metadata[@name = 'Coordinate']">
+									<xsl:text disable-output-escaping="yes">"</xsl:text>
+									<xsl:value-of disable-output-escaping="yes" select="current()"/>
+									<xsl:text disable-output-escaping="yes">"</xsl:text>
+									<xsl:text disable-output-escaping="yes">,</xsl:text>
+								</xsl:for-each>
+								<xsl:text>]</xsl:text>
 							</xsl:if>
 							<xsl:text>}</xsl:text>
@@ -891,4 +905,7 @@
 			<xsl:text>]</xsl:text>
 		</div>
+		
+		<!-- TODO: Why do we have to do this to see Coordinate appear in extraMetadataList on o=xml page, when Lat and Lng appear without doing the same??? -->
+		<gsf:metadata name="Coordinate" hidden="true"/>
 	</xsl:template>
 	
@@ -914,15 +931,21 @@
 		<xsl:if test="metadataList/metadata[@name = 'Coordinate']">
 			<div style="background:#BBFFBB; padding: 5px; margin:0px auto; width:890px;">
-				<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.map_nearby_docs')"/>
-				<img id="nearbyDocumentsToggle" style="margin-left:5px;" src="interfaces/{$interface_name}/images/expand.png">
-					<xsl:attribute name="onclick">
-						<xsl:text>performDistanceSearchWithCoordinates('</xsl:text>
-						<xsl:value-of select="@nodeID"/>
-						<xsl:text>', '</xsl:text>
-						<gsf:metadata name="Coordinate"/>
-						<xsl:text>', 2);</xsl:text>
-					</xsl:attribute>
-				</img>
-				<div id="nearbyDocuments"><xsl:text> </xsl:text></div>
+			<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.map_nearby_docs')"/>
+			<xsl:for-each select="metadataList/metadata[@name = 'Coordinate']">
+			
+				<xsl:variable name="coordinate"><xsl:value-of select="current()"/></xsl:variable>
+			
+				
+					<img id="nearbyDocumentsToggle" style="margin-left:5px;" src="interfaces/{$interface_name}/images/expand.png">
+						<xsl:attribute name="onclick">
+							<xsl:text>performDistanceSearchWithCoordinates('</xsl:text>
+							<xsl:value-of select="@nodeID"/>
+							<xsl:text>', '</xsl:text>
+							<xsl:value-of select="$coordinate"/><!--<gsf:metadata name="Coordinate"/>-->
+							<xsl:text>', 2);</xsl:text>
+						</xsl:attribute>
+					</img>					
+			</xsl:for-each>	
+			<div id="nearbyDocuments"><xsl:text> </xsl:text></div>				
 			</div>
 		</xsl:if>
