Index: main/trunk/greenstone3/web/interfaces/default/js/map-scripts-shapes-util.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/map-scripts-shapes-util.js	(revision 33139)
+++ main/trunk/greenstone3/web/interfaces/default/js/map-scripts-shapes-util.js	(revision 33140)
@@ -219,5 +219,5 @@
 	var NE = new google.maps.LatLng(north, east);
 	var SW = new google.maps.LatLng(south, west);
-	bounds = new google.maps.LatLngBounds(SW, NE);
+	bounds = new google.maps.LatLngBounds(SW, NE); // THIS IS NOT IN GOOGLE MAPS' RECTANGLE FORMAT!
 	
 	var rect = ShapesUtil._createRectangle(json_rect,bounds);
@@ -485,2 +485,34 @@
 
 
+// function returns an object (representing a Coordinate) of the form {lat: 34.052, lng: -118.243}
+// For each shape's properties: https://developers.google.com/maps/documentation/javascript/shapes
+ShapesUtil.getLabelCoordinate = function(shape) {	
+	
+	if (shape.type === google.maps.drawing.OverlayType.POLYLINE) {
+		var path = shape.getPath(); // assuming a minimum of one path array for each polygon
+		return path.getAt(0); // return the first coord of polyline for now
+	} else if (shape.type === google.maps.drawing.OverlayType.POLYGON) {
+		var path = shape.getPath(); // assuming a minimum of one path array for each polygon
+		return path.getAt(0); // return the first coord for now
+	} else if (shape.type === google.maps.drawing.OverlayType.RECTANGLE) {		
+		// Doesn't work:
+		//var latitude = (shape.bounds.north + shape.bounds.south) / 2;
+		//var longitude = (shape.bounds.east + shape.bounds.west) / 2;
+		//console.log("Rect: " + shape.bounds.toString());
+		//return {lat: shape.bounds.north, lng: shape.bounds.east};
+		// A Google Maps Rectangle's bounds property has 4 attributes/properties: north, south, east, west
+		// But this ShapesUtil.Rectangle class's bounds property has 2 coord properties: SW and NE.
+		// However, it is handy in this case, since we can just call getCenter()
+		return shape.bounds.getCenter();
+	} else if (shape.type === google.maps.drawing.OverlayType.CIRCLE) {		
+		return shape.center; // circles have a centre
+	} else if (shape.type === google.maps.drawing.OverlayType.MARKER){
+		return shape.position;
+	}
+	else {
+		console.error("*** ShapesUtil::getLabelCoordinate() Unrecognized shape type: " +shape.type);
+		return null;
+	}
+}
+
+
Index: main/trunk/greenstone3/web/interfaces/default/js/map-scripts.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/map-scripts.js	(revision 33139)
+++ main/trunk/greenstone3/web/interfaces/default/js/map-scripts.js	(revision 33140)
@@ -326,11 +326,23 @@
 		if(doc.parentCL && doc.parentCL.style.display == "none")
 		{
-			doc.marker.setVisible(false);
+			if(doc.shapes) {
+				for(var x = 0; x < doc.shapes.length; x++) {
+					doc.shapes[x].setVisible(false);
+				}
+			} else {
+				doc.marker.setVisible(false);
+			}
 			continue;
 		}
 		else
 		{
-			doc.marker.setVisible(true);
-			markersOnMap++;
+			if(doc.shapes) {
+				for(var x = 0; x < doc.shapes.length; x++) {
+					doc.shapes[x].setVisible(true);
+				}
+			} else {
+				doc.marker.setVisible(true);
+			}
+			markersOnMap++; // TODO: what do we do with this when we have shapes. This variable may be connected with centring the map?
 		}
 
@@ -424,5 +436,7 @@
 }
 
-function attachClickHandler(marker, nodeID)
+// Unused at present, called by draggableCreateMarker
+// Map used to have editable markers. Now editable markers are restricted to the map-editor.
+function attachDraggableClickHandler(marker, nodeID)
 {	
 	google.maps.event.addListener(marker, 'click', function()
@@ -493,13 +507,9 @@
 }
 
-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 {
+function createMarkers(doc, mainMarker) {	
+	if(doc.mapoverlay) {
+		//console.log("Have shapes: " + doc.mapoverlay.toString());
+		createShapes(doc, mainMarker);
+	} else { // backwards compatible to deal with Lat and Lng meta stored for doc
 		pos = new google.maps.LatLng(doc.lat,doc.lng);
 		createMarker(doc, pos, mainMarker);
@@ -507,7 +517,162 @@
 }
 
-
+function addInfoMarker(doc, shape) {
+	
+	if(!shape.description) {
+		//console.log("@@@@ " + shape.type.toString() + " had no description/label");
+		return;
+	}
+	
+	// else add an InfoWindow for this shape using the label (shape.description)
+	
+	// https://developers.google.com/maps/documentation/javascript/infowindows
+	// An InfoWindow's "position contains the LatLng at which this info window is anchored.
+	// Note: An InfoWindow may be attached either to a Marker object (in which case its position is based on the marker's location)
+	// or on the map itself at a specified LatLng. Opening an info window on a marker will automatically update the position."
+	var infoWindow = new google.maps.InfoWindow({content:shape.description}); // NOTE: if not setting content or position properties
+			// inside this constructor, need to call setContent/setPosition to set them
+	
+	if(shape.type === google.maps.drawing.OverlayType.MARKER) {
+		var marker = shape;
+		//marker.addListener('mouseover', function() {
+          infoWindow.open(_map, marker);
+		//});
+		attachClickHandler(marker, doc.nodeID); // do what the original code used to do here
+	}
+	else {
+		var coord = ShapesUtil.getLabelCoordinate(shape);		
+		console.log("Coord for " + shape.type.toString() + " is " + coord.toString());
+		infoWindow.setPosition(coord);
+		shape.addListener('mouseover', function() {
+			infoWindow.open(_map);
+		});
+		shape.addListener('mouseout', function() {
+			infoWindow.close();
+		});
+		attachClickHandler(shape, doc.nodeID); // as above		
+	}
+}
+
+// This function will create Google Shapes/Overlays and markers out of a given doc JSONNode's doc.mapOverlay
+// (doc.mapOverlay shapes are stored as an array of JSON) and store the shapes/overlays in the doc.shapes array.
+// Note: doc.coords are just an array of all the coordinates in a doc, not indicating to which shapes they belong.
+// They're only **for searching** - for seaching which coords (hence docs) are in a map.
+// Param mainMarker: if set to true, marker is red. If false, marker is blue
+function createShapes(doc, mainMarker)
+{	
+	// for doc.shapes: don't store JSON anymore, convert them to google Shapes overlays and store them instead
+	doc.shapes = [];
+	for (var i=0; i<doc.mapoverlay.length; i++) {
+		var shape = ShapesUtil.JSONToShape(doc.mapoverlay[i]);		
+		doc.shapes[i] = shape;		
+		shape.setMap(_map);
+		shape["title"] = doc.title;
+		
+		// Unset editable and draggable properties of shape
+		// And for markers, which are initialised to clickable besides, undo the clickability
+		// and set them 
+		if(shape.type === google.maps.drawing.OverlayType.MARKER) {
+			var marker = shape;
+			// mainMarkers should be red
+			if(!mainMarker) {
+				marker["icon"] = "interfaces/" + gs.xsltParams.interface_name + "/images/bluemarker.png";
+			}
+			marker.clickable = false; // only markers
+		}
+		
+		shape.editable = false;
+		shape.draggable = false;
+		
+		
+		
+		// doc[i]'s label = doc.shapes[i].description
+		addInfoMarker(doc, shape);
+	}	
+	
+	var docElement = gs.jqGet("div" + doc.nodeID);
+	var parent;
+	if(docElement)
+	{
+		parent = docElement.parentNode;
+	}
+
+	while(parent && parent.nodeName != "BODY")
+	{
+		if($(parent).attr("id") && $(parent).attr("id").search("divCL") != -1)
+		{
+			doc.parentCL = parent;
+			break;
+		}
+		
+		parent = parent.parentNode;
+	}
+}
+
+// This method is only for backwards compatibility: for those collections with docs that only have Lat and Lng meta
+// and no GPS.mapOverlay (and hence Coordinate) meta.
 // Param mainMarker: if set to true, marker is red. If false, marker is blue
 function createMarker(doc, pos, mainMarker)
+{
+	var marker;
+	if(mainMarker)
+	{
+		marker = new google.maps.Marker
+		({
+			position: pos,
+			title:doc.title,
+			map:_map
+		});
+	}
+	else
+	{
+		marker = new google.maps.Marker
+		({
+			position: pos,
+			title:doc.title,
+			map:_map,
+			icon:"interfaces/" + gs.xsltParams.interface_name + "/images/bluemarker.png"
+		});
+	}
+
+	var docElement = gs.jqGet("div" + doc.nodeID);
+	var parent;
+	if(docElement)
+	{
+		parent = docElement.parentNode;
+	}
+
+	while(parent && parent.nodeName != "BODY")
+	{
+		if($(parent).attr("id") && $(parent).attr("id").search("divCL") != -1)
+		{
+			doc.parentCL = parent;
+			break;
+		}
+		
+		parent = parent.parentNode;
+	}
+
+	var info = new google.maps.InfoWindow({content:doc.title});
+	marker.markerInfo = info;
+	doc.marker = marker;
+	attachClickHandler(marker, doc.nodeID);
+}
+
+// TODO: with the following, it seems that clicking on shape expands the entire document
+// Should it be that clicking on a shape should expand the doc section that contains that shape meta?
+function attachClickHandler(shapeOrMarker, nodeID)
+{
+	google.maps.event.addListener(shapeOrMarker, 'click', function()
+	{
+		document.location.href = gs.xsltParams.library_name + "?a=d&ed=1&c=" + gs.cgiParams.c + "&d=" + nodeID + "&dt=hierarchy&p.a=b&p.sa=&p.s=ClassifierBrowse";
+	});
+}
+
+// TODO:
+// Version of createMarker function containing Zeddy's modifications (pre-mapeditor?) to make markers
+// on the public *map* (not on map-editor) draggable/editable and to save these edits/rebuild with them.
+// Do we want to continue supporting editing on the main map? I thought we weren't going to and that editing
+// was exclusive to the map-editor, with the public map only displaying the saved features?
+function draggableCreateMarker(doc, pos, mainMarker)
 {
 	var docEdit = (("docEdit" in gs.cgiParams) && (gs.cgiParams['docEdit']));
@@ -522,5 +687,5 @@
 	var draggable_val = (!docEdit || loggedOutVar) ? false : true;
 	
-	var marker
+	var marker;
 	if(mainMarker)
 	{
@@ -566,5 +731,5 @@
 	marker.markerInfo = info;
 	doc.marker = marker;
-	attachClickHandler(marker, doc.nodeID);
+	attachDraggableClickHandler(marker, doc.nodeID);
 
 	////////////////////////////////////////////////////// TEST
Index: main/trunk/greenstone3/web/interfaces/default/transform/layouts/header.xsl
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/transform/layouts/header.xsl	(revision 33139)
+++ main/trunk/greenstone3/web/interfaces/default/transform/layouts/header.xsl	(revision 33140)
@@ -748,5 +748,6 @@
   <xsl:template name="map-scripts">
     <meta content="initial-scale=1.0, user-scalable=no" name="viewport"/>
-    <script src="http://maps.googleapis.com/maps/api/js?key=AIzaSyCofVTps3xHfMvIcTMHqYMMxe3xXfkAxnI&amp;libraries=drawing" type="text/javascript"><xsl:text> </xsl:text></script>	
+    <script src="http://maps.googleapis.com/maps/api/js?key=AIzaSyCofVTps3xHfMvIcTMHqYMMxe3xXfkAxnI&amp;libraries=drawing" type="text/javascript"><xsl:text> </xsl:text></script>
+	<script src="interfaces/{$interface_name}/js/map-scripts-shapes-util.js" type="text/javascript"><xsl:text> </xsl:text></script>
     <script src="interfaces/{$interface_name}/js/map-scripts.js" type="text/javascript"><xsl:text> </xsl:text></script>
     <script type="text/javascript">$(window).load(initializeMapScripts);</script>
Index: main/trunk/greenstone3/web/interfaces/default/transform/map-tools.xsl
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/transform/map-tools.xsl	(revision 33139)
+++ main/trunk/greenstone3/web/interfaces/default/transform/map-tools.xsl	(revision 33140)
@@ -21,5 +21,5 @@
       <xsl:text>[</xsl:text>
       <xsl:for-each select="//documentNode">
-	<xsl:if test="(metadataList/metadata[@name = 'Latitude'] and metadataList/metadata[@name = 'Longitude']) or metadataList/metadata[@name = 'Coordinate']">
+	<xsl:if test="(metadataList/metadata[@name = 'Latitude'] and metadataList/metadata[@name = 'Longitude']) or metadataList/metadata[@name = 'Coordinate'] or metadataList/metadata[@name = 'GPS.mapOverlay']">
 	  <xsl:text>{</xsl:text>
 	  <xsl:text disable-output-escaping="yes">"nodeID":"</xsl:text>
@@ -49,4 +49,11 @@
 		<xsl:text>]</xsl:text>
 	  </xsl:if>
+	  
+	  <xsl:if test="metadataList/metadata[@name = 'GPS.mapOverlay']">
+		<xsl:text disable-output-escaping="yes">,</xsl:text>
+		<xsl:text disable-output-escaping="yes">"mapoverlay":</xsl:text>
+		<xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name = 'GPS.mapOverlay']"/>
+	  </xsl:if>
+							
 	  <xsl:text>}</xsl:text>
 	  <xsl:if test="not(position() = count(//documentNode))">
Index: main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl	(revision 33139)
+++ main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl	(revision 33140)
@@ -844,5 +844,5 @@
 				<xsl:when test="count(//documentNode) > 0">
 					<xsl:for-each select="//documentNode">
-						<xsl:if test="(metadataList/metadata[@name = 'Latitude'] and metadataList/metadata[@name = 'Longitude']) or metadataList/metadata[@name = 'Coordinate']">
+						<xsl:if test="(metadataList/metadata[@name = 'Latitude'] and metadataList/metadata[@name = 'Longitude']) or metadataList/metadata[@name = 'Coordinate'] or metadataList/metadata[@name = 'GPS.mapOverlay']">
 							<xsl:text>{</xsl:text>
 							<xsl:text disable-output-escaping="yes">"nodeID":"</xsl:text><xsl:value-of select="@nodeID"/><xsl:text disable-output-escaping="yes">",</xsl:text>
@@ -862,12 +862,25 @@
 									<xsl:value-of disable-output-escaping="yes" select="current()"/>
 									<xsl:text disable-output-escaping="yes">"</xsl:text>
+									<!--<xsl:if test="not(position() = count(metadataList/metadata[@name = 'Coordinate'])">
+										<xsl:text>,</xsl:text>
+									</xsl:if>				
+									-->
 									<xsl:text disable-output-escaping="yes">,</xsl:text>
 								</xsl:for-each>
 								<xsl:text>]</xsl:text>
+							</xsl:if>						
+							
+							<xsl:if test="metadataList/metadata[@name = 'GPS.mapOverlay']">
+								<xsl:text disable-output-escaping="yes">,</xsl:text>
+								<xsl:text disable-output-escaping="yes">"mapoverlay":</xsl:text>
+								<xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name = 'GPS.mapOverlay']"/>
 							</xsl:if>
+							
 							<xsl:text>}</xsl:text>
+							
 							<xsl:if test="not(position() = count(//documentNode))">
 								<xsl:text>,</xsl:text>
 							</xsl:if>
+							
 						</xsl:if>
 					</xsl:for-each>
@@ -876,5 +889,5 @@
 				<xsl:otherwise>
 					<xsl:for-each select="/page/pageResponse/document">
-						<xsl:if test="(metadataList/metadata[@name = 'Latitude'] and metadataList/metadata[@name = 'Longitude']) or metadataList/metadata[@name = 'Coordinate']">
+						<xsl:if test="(metadataList/metadata[@name = 'Latitude'] and metadataList/metadata[@name = 'Longitude']) or metadataList/metadata[@name = 'Coordinate']  or metadataList/metadata[@name = 'GPS.mapOverlay']">
 							<xsl:text>{</xsl:text>
 							<xsl:text disable-output-escaping="yes">"nodeID":"</xsl:text><xsl:value-of select="@selectedNode"/><xsl:text disable-output-escaping="yes">",</xsl:text>
@@ -898,4 +911,11 @@
 								<xsl:text>]</xsl:text>
 							</xsl:if>
+							
+							<xsl:if test="metadataList/metadata[@name = 'GPS.mapOverlay']">
+								<xsl:text disable-output-escaping="yes">,</xsl:text>
+								<xsl:text disable-output-escaping="yes">"mapoverlay":</xsl:text>
+								<xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name = 'GPS.mapOverlay']"/>
+							</xsl:if>
+							
 							<xsl:text>}</xsl:text>
 						</xsl:if>
@@ -906,6 +926,9 @@
 		</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??? -->
+		<!-- TODO: Why do we have to do this to see Coordinate meta appear in extraMetadataList on o=xml page, when Lat and Lng appear without doing the same??? 
+			Furthermore, map-tools.xsl already requests Coordinate meta, and map-tools.xsl is always included when format statement for collection in
+			search|browse|doc display view has mapEnabled=true -->
 		<gsf:metadata name="Coordinate" hidden="true"/>
+		<gsf:metadata name="GPS.mapOverlay" hidden="true"/>		
 	</xsl:template>
 	
