Index: main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts.js	(revision 38350)
+++ main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts.js	(revision 38351)
@@ -241,4 +241,9 @@
 	    addEditMetadataLink(titleDivs[i]);
 
+	    if(i == 0) { // root doc id, has no period-mark in it
+		// user comments are attached to document root
+		addEditUserCommentsLink(titleDivs[i]);
+	    }
+	    
 	    if (gs.variables.isMapGPSEditingAllowed == "1") {
 		addEditMapGPSLink(titleDivs[i]);
Index: main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_usercomments.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_usercomments.js	(revision 38351)
+++ main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_usercomments.js	(revision 38351)
@@ -0,0 +1,149 @@
+/** Javascript file for editing and especially deleting user comments in a documentediting situation */
+
+
+
+function addEditUserCommentsLink(cell) {
+    cell = $(cell);
+    var doc_id = cell.attr("id").substring(6);
+    
+    var edit_usercomments_table = document.getElementById("usercomments-"+doc_id);   
+
+    var edit_meta_table = document.getElementById("meta"+doc_id);
+    var comments = edit_meta_table.querySelectorAll('.metaTableCellArea.gsusercomment');
+    var gsMetaPrefix = "gs"; // metadata name prefix
+    
+    var unames = [];
+    var timestamps = [];
+    
+    
+    if(comments.length <= 0) {
+	gsMetaPrefix = "";
+
+	comments = edit_meta_table.querySelectorAll('.metaTableCellArea.usercomment');
+	if(comments.length <= 0) {	    
+	    return;
+	}	
+    }
+
+    
+    var classname = ".metaTableCellArea." + gsMetaPrefix + "username";
+    unames = edit_meta_table.querySelectorAll(classname); 
+    classname = ".metaTableCellArea." + gsMetaPrefix + "usertimestamp";
+    timestamps = edit_meta_table.querySelectorAll(classname);
+    
+    //console.log(comments[0].textContent);
+    //console.log(unames[0].textContent);
+    //console.log(timestamps[0].textContent);    
+
+
+    var headerRow = document.createElement("tr");    
+    edit_usercomments_table.appendChild(headerRow);    
+
+    var i = 0;
+    // work with tbody child of metadatatable's table element
+    edit_meta_table = edit_meta_table.firstElementChild;
+    for(i = 0; i < comments.length; i++) {
+	var newRow = document.createElement("tr");
+	edit_usercomments_table.appendChild(newRow);
+
+	var rowNumCell, txtNode;
+	if(i == 0) {
+	    rowNumCell = document.createElement("th");
+	    rowNumCell.setAttribute("class", "metaposCell");
+	    txtNode = document.createTextNode("metapos");	    
+	    rowNumCell.appendChild(txtNode);
+	    headerRow.appendChild(rowNumCell);
+	}
+	rowNumCell = document.createElement("td");
+	rowNumCell.setAttribute("class", "metaposCell");
+	txtNode = document.createTextNode(i+"");
+	rowNumCell.appendChild(txtNode);
+	newRow.appendChild(rowNumCell);
+	
+	
+	//Row we work with each time: get the closest ancestor of comments[i] that is a <tr>
+	// If you change the order the rows are moved into usercomments-table below, the
+	// userCommentsMetaFields[] array ordering in documentedit_scripts_util.js will be affected
+	shiftRowData(timestamps[i].closest("tr"), edit_meta_table, newRow, i, headerRow);
+	shiftRowData(unames[i].closest("tr"), edit_meta_table, newRow, i, headerRow);
+	shiftRowData(comments[i].closest("tr"), edit_meta_table, newRow, i, headerRow);
+	
+	//console.log("NEWROW:" + newRow.firstElementChild.textContent);
+	addRemoveLinkToRow(newRow);
+
+    }
+    
+	var row = cell.parent();
+	var newCell = $("<td>", {
+			"style": "font-size:0.7em; padding:0px 10px",
+			"class": "editMapGPSButton"
+		});
+	var linkSpan = $("<span>", {
+			"class": "ui-state-default ui-corner-all",
+			"style": "padding: 2px; float:left;"
+		});
+
+	var linkLabel = $("<span>" + gs.text.de.edit_usercomments + "</span>");
+	var linkIcon = $("<span>", {
+			"class": "ui-icon ui-icon-folder-collapsed"
+		});
+	newCell.linkIcon = linkIcon;
+	newCell.linkLabel = linkLabel;
+
+	var uList = $("<ul>", {
+			"style": "outline: 0 none; margin:0px; padding:0px;"
+		});
+	var labelItem = $("<li>", {
+			"style": "float:left; list-style:none outside none;"
+		});
+	var iconItem = $("<li>", {
+			"style": "float:left; list-style:none outside none;"
+		});
+
+	uList.append(iconItem);
+	uList.append(labelItem);
+	labelItem.append(linkLabel);
+	iconItem.append(linkIcon);
+
+	var newLink = $("<a>", {
+			"href": "javascript:;"
+	});
+    
+	newLink.on("click", function () {
+		if (edit_usercomments_table.style.display == "none") {
+			linkLabel.html(gs.text.de.hide_usercomments);
+			linkIcon.attr("class", "ui-icon ui-icon-folder-open");
+			edit_usercomments_table.style.display = "block";
+		} else {
+		    linkLabel.html(gs.text.de.edit_usercomments);
+		    linkIcon.attr("class", "ui-icon ui-icon-folder-collapsed");
+		    edit_usercomments_table.style.display = "none";
+
+		}
+	});
+
+	newLink.append(uList);
+	linkSpan.append(newLink);
+	newCell.append(linkSpan);
+	row.append(newCell);
+}
+
+function makeHeaderCellFrom(row, headerRow) {
+    var cellName = row.querySelector('.metaTableCellName').textContent;
+    var headerCell = document.createElement("th");
+    headerCell.setAttribute("class", "metaTableCellName");
+    var txt = document.createTextNode(cellName);
+    headerCell.appendChild(txt);
+    headerRow.appendChild(headerCell);
+}
+
+function shiftRowData(row, edit_meta_table, newRow, rownum, headerRow) {
+    if(rownum == 0) {
+	makeHeaderCellFrom(row, headerRow);
+    }
+    edit_meta_table.removeChild(row);
+    var oldCell = row.querySelector('.metaTableCell');	
+    newRow.appendChild(oldCell);
+    var el = oldCell.querySelector('.metaTableCellArea');
+    el.classList.add("threecol");
+}
Index: main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_util.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_util.js	(revision 38350)
+++ main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_util.js	(revision 38351)
@@ -295,8 +295,8 @@
 		for (var j in editableLastStates) 
 		{	
-			if (isNodeChanged(editableLastStates[j])) 
-			{
-				resultArray.push(editableLastStates[j].editableNode);
-			}
+                       if (isNodeChanged(editableLastStates[j])) 
+                       {
+                               resultArray.push(editableLastStates[j].editableNode);
+                       }		    
 		}
 	}
@@ -357,5 +357,5 @@
     collection = gs.cgiParams.p_c;
   }
-  
+
 	var sendBuildRequest = function()
 	{
@@ -429,5 +429,9 @@
 	} // end sendBuildRequest definition
 
-  var metadataChanges = new Array();
+    var metadataChanges = new Array();
+
+    var delCommentsMetapositions = [];
+    var userCommentsMetaFields = [];
+    var _docid;
   if (_deletedMetadata.length > 0) {
     //addCollectionToBuild(collection);
@@ -440,23 +444,74 @@
       var currentElem = currentRow;
       while((currentElem = currentElem.parentNode).tagName != "TABLE");
-      var docID = currentElem.getAttribute("id").substring(4);
-      
-      //Get metadata name
-      var cells = currentRow.getElementsByTagName("TD");
-	var nameCell = cells[0];
-	// metadata name cell might have the multivalue indicator in it, so just want the first word
-	var name = nameCell.innerHTML.split(" ")[0];
-      var valueCell = cells[1];
-	var value = valueCell.getElementsByTagName("TEXTAREA")[0].value;
-	if (value.length) {
-	    // check for non empty value, in case all they have done is add a field then deleted it.
-	    metadataChanges.push({type:'delete', docID:docID, name:name, value:value});
-	    addCollectionToBuild(collection);
-	}
-      removeFromParent(currentRow);
+	
+	var docID;
+	if(currentElem.getAttribute("id").startsWith("usercomments-")) {
+	    
+	    docID = currentElem.getAttribute("id").substring("usercomments-".length);
+	    _docid = docID;
+	    
+	    if(userCommentsMetaFields.length == 0) {
+		var headerRow = currentElem.firstElementChild; // tr
+		var headerCells = headerRow.querySelectorAll("th");
+		for(var th = 1; th < headerCells.length; th++) { // skip th index=0, which is metapos
+		    userCommentsMetaFields.push(headerCells[th].textContent);
+		    //console.log("userCommentsMetaFields:" + userCommentsMetaFields[th-1]);
+		}
+	    }
+	    
+	    // get metapos; collumn names in first row are metanames
+	    var metapos = currentRow.firstElementChild.textContent;
+	    delCommentsMetapositions.push(metapos);
+	    //console.log("docID : " + docID + " - metapos: " + metapos);
+	}
+	else {
+	    docID = currentElem.getAttribute("id").substring(4); // <table> with id ="meta<docid>"
+	    
+	    //Get metadata name
+	    var cells = currentRow.getElementsByTagName("TD");
+	    var nameCell = cells[0];
+	    // metadata name cell might have the multivalue indicator in it, so just want the first word
+	    var name = nameCell.innerHTML.split(" ")[0];
+	    var valueCell = cells[1];
+	    var value = valueCell.getElementsByTagName("TEXTAREA")[0].value;
+	    if (value.length) {
+		// check for non empty value, in case all they have done is add a field then deleted it.
+		metadataChanges.push({type:'delete', docID:docID, name:name, value:value});
+		addCollectionToBuild(collection);
+	    }
+	}
+	removeFromParent(currentRow);
     }
+
+      // build up the data structure for all the usercomments to be deleted
+      if(delCommentsMetapositions.length > 0) {
+	  //console.log("About to delete position: " + delCommentsMetapositions);
+	  var timestamp_rec = {
+	      metaname: userCommentsMetaFields[0],
+	      metapositions: delCommentsMetapositions
+	  };
+	  var username_rec = {
+	      metaname: userCommentsMetaFields[1],
+	      metapositions: delCommentsMetapositions
+	  };    
+	  var comment_rec = {
+	      metaname: userCommentsMetaFields[2],
+	      metapositions: delCommentsMetapositions
+	  };
+    
+    
+	  var doc_rec = {
+	      docid: _docid,
+	      metatable: [username_rec, timestamp_rec, comment_rec],
+	      //metamode: "accumulate"
+	  };
+    
+	  var docArray = [doc_rec];
+	  metadataChanges.push({type:'deleteUserComments', docID:docID, docArray:docArray});
+	  addCollectionToBuild(collection);	 
+      }
   }
 
-  var changes = changesToUpdate();
+    var changes = changesToUpdate();
   
   //Clean changes
@@ -476,5 +531,5 @@
 			var currentElem = changedElem;
 			while((currentElem = currentElem.parentNode).tagName != "TABLE");
-			var docID = currentElem.getAttribute("id").substring(4);
+		        var docID = currentElem.getAttribute("id").substring(4);
 		    
 			//Get metadata name
@@ -590,4 +645,24 @@
 		if (change.type == "delete") {
 		    gs.functions.removeArchivesMetadata(collection, gs.xsltParams.site_name, change.docID, change.name, null, encodeDelimiters(change.value), function(){callbackFunction();});
+		} else if (change.type === "deleteUserComments") {
+		    
+		    //alert("deleteUserComments" + JSON.stringify(change.docArray));
+		    gs.functions.removeMetadataArray(
+			collection,
+			gs.xsltParams.site_name,
+			change.docArray,
+			null, //metamode
+			"import|archives|index",
+			function(ajaxResult) {
+			    console.log("Comments deleted from import/archives/index");
+			    callbackFunction(); // move on to processing next & eventually rebuild
+			},
+			false, // false for asynchronous, see comment in gs.usercomments.addUserComment()
+			function(ajaxError) {
+			    var errData = (ajaxError.responseText) ? ajaxError.responseText : ajaxError;
+			    alert("Remove failed. Got: " + errData);			    
+			}
+		    );		    
+
 		} else {
 		  // Checking "if(change.metapos)" doesn't work for us as it becomes false when the property doesn't exist AND when the property is 0. But metapos IS 0 for us.
Index: main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl	(revision 38350)
+++ main/trunk/greenstone3/web/interfaces/default/transform/pages/document.xsl	(revision 38351)
@@ -243,5 +243,20 @@
 		
 			<xsl:choose>
-			  <xsl:when test="$canDoEditing = 'true' and $editingTurnedOn = 'true'"> 
+			  <xsl:when test="$canDoEditing = 'true' and $editingTurnedOn = 'true'">
+			    <!-- only docroot nodes can have a usercomments table-->
+			    <xsl:if test="not(contains(@nodeID, '.'))">
+			      <table id="usercomments-{@nodeID}">
+					<xsl:attribute name="style">
+						<xsl:choose>
+							<xsl:when test="/page/pageRequest/paramList/param[@name = 'dmd']/@value = 'true'">
+								<xsl:text>display:block;</xsl:text>
+							</xsl:when>
+							<xsl:otherwise>
+								<xsl:text>display:none;</xsl:text>
+							</xsl:otherwise>
+						</xsl:choose>
+					</xsl:attribute>				
+				</table>
+			    </xsl:if>
 				<table id="meta{@nodeID}">
 					<xsl:attribute name="style">
@@ -257,9 +272,9 @@
 					<xsl:value-of select="util:clearMetadataStorage()"/>
 					<xsl:for-each select="metadataList/metadata">
-						<xsl:sort select="@name"/>
-							<tr>
+					  <xsl:sort select="@name"/>
+					  <tr>
 								<td class="metaTableCellName"><xsl:value-of select="@name"/></td>
 								<td class="metaTableCell"> <textarea autocomplete="off"><xsl:attribute name="class">metaTableCellArea <xsl:value-of select="translate(@name, '.-', '')"/></xsl:attribute><xsl:value-of select="."/></textarea></td>
-							</tr>
+						  </tr>
 					</xsl:for-each>
 				</table>
@@ -378,4 +393,5 @@
 			<script type="text/javascript" src="interfaces/{$interface_name}/js/documentedit_scripts.js"><xsl:text> </xsl:text></script>
 			<script type="text/javascript" src="interfaces/{$interface_name}/js/documentedit_scripts_util.js"><xsl:text> </xsl:text></script>
+			<script type="text/javascript" src="interfaces/{$interface_name}/js/documentedit_scripts_usercomments.js"><xsl:text> </xsl:text></script>
 			<script type="text/javascript">
 			  <xsl:text disable-output-escaping="yes">gs.variables.isMapGPSEditingAllowed = "</xsl:text><xsl:value-of select="$isMapGPSEditingAllowed"/><xsl:text disable-output-escaping="yes">";</xsl:text></script>
