Index: main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js	(revision 38188)
+++ main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js	(revision 38189)
@@ -1003,4 +1003,21 @@
 }
 
+gs.functions.removeMetadataAtPos = function(collection, site, documentID, metadataName, metadataPosition, successResponseFunction, errorResponseFunction)
+{
+	if( typeof errorResponseFunction === 'undefined' ) { errorResponseFunction = null; } // force error callback to be defined: either null or has value
+	
+	var nameArray = ["removeImportMetadata", "removeArchivesMetadata", "removeIndexMetadata"];
+	var functionArray = ["remove-import-metadata", "remove-archives-metadata", "remove-metadata"];
+	
+	for(var i = 0; i < nameArray.length; i++)
+	{
+	    gs.functions._callMetadataServer(
+		nameArray[i],
+		gs.functions.getBasicDataForMetadataServer(functionArray[i], collection, site, documentID, metadataName, null /*metamode*/, null /*metadataValue*/, null /*prevmetavalue*/, metadataPosition),
+		successResponseFunction,
+		errorResponseFunction);
+	}
+}
+
 
 /***********************************************************
Index: main/trunk/greenstone3/web/interfaces/default/js/user_comments.js
===================================================================
--- main/trunk/greenstone3/web/interfaces/default/js/user_comments.js	(revision 38188)
+++ main/trunk/greenstone3/web/interfaces/default/js/user_comments.js	(revision 38189)
@@ -112,6 +112,4 @@
     var json_result_str = (data.responseText) ? data.responseText : data; 
 
-    //console.log("Got user comments to display: " + json_result_str);
-
     var result = JSON.parse(json_result_str);
     // result contains only one docrec (result[0]), since we asked for the usercomments of one docid
@@ -122,6 +120,4 @@
 
     var canDeleteComments = gs.variables["userCanDeleteComments"];
-    //alert("canDeleteComments: " + canDeleteComments);
-    
     
     // if there's at least one existing comment OR if the form is currently being displayed
@@ -157,5 +153,5 @@
 	    
 	    // for each usercomment, create a child div with the username, timestamp and comment
-	    gs.usercomments.displayInUserCommentList(usercommentdiv, username, timestamp, comment, canDeleteComments);
+	    gs.usercomments.displayInUserCommentList(usercommentdiv, username, timestamp, comment, canDeleteComments, i);
 	    
 	    i++;
@@ -163,5 +159,7 @@
     }
     
-    if(canDeleteComments) {
+    if(canDeleteComments != 0) {
+	var delButtonDiv = document.createElement("div");
+	delButtonDiv.setAttribute("id", "del-button-div");
 	var delCommentsButton = document.createElement("button");
 	delCommentsButton.innerHTML = "Delete selected";
@@ -170,6 +168,9 @@
 	// alternatively: https://www.w3schools.com/jsref/met_element_addeventlistener.asp
 	delCommentsButton.addEventListener("click", gs.usercomments.deleteSelectedComments);
-	usercommentdiv.appendChild(delCommentsButton);
-	
+	
+	delButtonDiv.appendChild(delCommentsButton);
+
+	var prevNode = document.getElementById("usercomments");
+	gs.usercomments.insertAfter(delButtonDiv, prevNode);
     }
     
@@ -183,5 +184,14 @@
 
 
-gs.usercomments.displayInUserCommentList = function(usercommentdiv, username, timestamp, comment, canDeleteComments) {
+// https://www.javascripttutorial.net/javascript-dom/javascript-insertafter/
+gs.usercomments.insertAfter = function(newNode, existingNode) {
+    existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
+}
+
+gs.usercomments.displayInUserCommentList = function(usercommentdiv, username, timestamp, comment, canDeleteComments, metapos) {
+
+    if(metapos == undefined) {
+	metapos = document.querySelectorAll('div[class=usercomment]').length;
+    }
     
     var divgroup=document.createElement("div");
@@ -194,16 +204,19 @@
     var divcomment=document.createElement("div");
 
+    if(canDeleteComments != 0) {
+	var deleteCheckBox = document.createElement("input");
+	deleteCheckBox.style.cssFloat = "left"; 
+	deleteCheckBox.setAttribute("type", "checkbox");
+	deleteCheckBox.setAttribute("class", "del-me-comment");
+	deleteCheckBox.setAttribute("data-metapos", metapos);
+	deleteCheckBox.setAttribute("data-username", username);
+	deleteCheckBox.setAttribute("data-timestamp", timestamp);
+	deleteCheckBox.setAttribute("data-comment", comment);
+	divgroup.appendChild(deleteCheckBox);
+    }
     
     divgroup.appendChild(divuser);
     var txt=document.createTextNode(username);
-    if(canDeleteComments) {
-	var deleteCheckBox = document.createElement("input");
-	deleteCheckBox.setAttribute("type", "checkbox");
-	deleteCheckBox.setAttribute("class", "del-me-comment");
-	deleteCheckBox.setAttribute("data-user", username);
-	deleteCheckBox.setAttribute("data-timestamp", timestamp);
-	deleteCheckBox.setAttribute("data-comment", comment);
-	divuser.appendChild(deleteCheckBox);
-    }    
+    
     divuser.appendChild(txt);
     
@@ -225,20 +238,133 @@
 }
 
-
 gs.usercomments.deleteSelectedComments = function() {
     // https://stackoverflow.com/questions/590018/getting-all-selected-checkboxes-in-an-array
     // https://stackoverflow.com/questions/6166763/jquery-multiple-checkboxes-array
 
-    //var selectedComments = document.getElementsByClassName("del-me-comment");
-    // var selectedComments = document.querySelectorAll('input[class=del-me-comment]:checked');
     var selectedComments = document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked');
 
-    if(selectedComments.length==0) {	
-	alert("Delete pressed, but nothing selected");
-    } else {
-	//alert("Delete pressed " + selectedComments.length);
-	alert("Delete pressed for docID: " + gs.variables["docID"]
-	      + " on num comments: " + selectedComments.length);
-    }   
+    if(selectedComments.length > 0) {	
+	
+	// Don't allow the user to submit further comments or delete comments
+	// until the metadata has been updated
+	document.getElementById("usercommentSubmitButton").disabled = true;
+	var delCommentsButton = document.getElementById("delCommentsButton");
+	if(delCommentsButton != undefined) {// should be defined when in this function
+	    delCommentsButton.disabled = true;
+	}
+
+	// User comment meta are at topmost section of the document.
+	// So only get the docId up to any period mark:
+	var _docid = document.AddUserCommentForm.d.value;	
+	var period = _docid.indexOf(".");
+	if(period != -1) {
+	    _docid = _docid.substring(0, period);
+	}
+	
+	//document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked').forEach(elem => console.log(elem.getAttribute('data-username')));
+
+	var modifiedMetapos = [];
+	var failure = false;
+
+	// start deleting from end of metadata list, so we don't have to recalculate metapos each time
+	for (var i = selectedComments.length-1; i >= 0; i--) {
+
+	    var metapos = selectedComments[i].getAttribute("data-metapos");
+	    //var username = selectedComments[i].getAttribute("data-username");
+	    //var timestamp = selectedComments[i].getAttribute("data-timestamp");
+	    //var comment = selectedComments[i].getAttribute("data-comment");
+	    //console.log("metapos: " + metapos);
+	    	    
+	    // There is no remove array version yet!!!
+	    
+	    //var result = gs.functions.removeMetadataAtPos(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index");
+	    gs.functions.removeMetadataAtPos(gs.variables["c"],
+					     gs.variables["site"],
+					     _docid,
+					     "gs.username",
+					     metapos, 
+					     //"import|archives|index",
+					     null, //function(ajaxResult) { alert(ajaxResult); },
+					     function(ajaxError) { return gs.usercomments.removeFailed(ajaxError, metapos); },
+					     true); // true for synchronous, meaning is opposite to explanation for addUserComment() function below
+
+	    if(failure) {
+		continue;
+	    }
+	    gs.functions.removeMetadataAtPos(gs.variables["c"],
+					     gs.variables["site"],
+					     _docid,
+					     "gs.usertimestamp",
+					     metapos, 
+					     //"import|archives|index",
+					     null, //function(ajaxResult) { alert(ajaxResult); },
+					     function(ajaxError) { return gs.usercomments.removeFailed(ajaxError, metapos); },
+					     true); // true for synchronous, meaning is opposite to explanation for addUserComment() function below
+
+	    if(failure) {
+		continue;
+	    }
+	    gs.functions.removeMetadataAtPos(gs.variables["c"],
+					     gs.variables["site"],
+					     _docid,
+					     "gs.usercomment",
+					     metapos, 
+					     //"import|archives|index",
+					     null, //function(ajaxResult) { alert(ajaxResult); },
+					     function(ajaxError) { return gs.usercomments.removeFailed(ajaxError, metapos); },
+					     true); // true for synchronous, meaning is opposite to explanation for addUserComment() function below
+
+
+	    gs.usercomments.removedMetadata(metapos, modifiedMetapos);
+	    failure = false; // reinitialise
+	}
+	
+	//console.log("modifiedMetapos: " + modifiedMetapos);
+
+	gs.usercomments.doneRemovingMetadata(modifiedMetapos);
+    }
+}
+
+
+gs.usercomments.removedMetadata = function(metapos, modifiedMetapos) {
+    modifiedMetapos.unshift(metapos); // add metapos to start of array
+}
+
+gs.usercomments.removeFailed = function(data, metapos) {
+    var result = (data.responseText) ? data.responseText : data;
+    alert("Remove failed. Got: " + result);
+    failure = true;
+}
+
+gs.usercomments.doneRemovingMetadata = function(modifiedMetapos) {
+    var userCommentsDiv = document.getElementById("usercomments");
+        
+    // modifiedMetaPos has all the positions for usercomments metadata that need to be removed, in normal (ascending) order
+    // So start at end, removing usercomments with highest metapos
+    for (var i = modifiedMetapos.length-1; i >= 0; i--) {
+	var metapos = modifiedMetapos[i];
+
+	//console.log("About to remove usercomment at metapos " + metapos);
+	
+	// find the checkbox with data-metapos=metapos and delete its username, timestamp, comment
+	var removeUserCommentForCheckbox = document.querySelector("input[data-metapos=\""+metapos+"\"]");
+	var usercommentDivToRemove = removeUserCommentForCheckbox.parentElement; // get the <div class="usercomment"/> above this checkbox
+	userCommentsDiv.removeChild(usercommentDivToRemove);
+    }
+
+    // Now re-number the metapos for all the input class=del-me-comment
+    var usercommentCheckboxes = document.querySelectorAll('input[class=del-me-comment][type=checkbox]');
+    for (var i = 0; i < usercommentCheckboxes.length; i++) {
+	usercommentCheckboxes[i].setAttribute("data-metapos", i);
+    }
+    
+    // whether there was an error or not, re-enable the submit button now
+    // that the removeMetada ajax operations have completed.
+    document.getElementById("usercommentSubmitButton").disabled = false;
+    var delCommentsButton = document.getElementById("delCommentsButton");
+    if(delCommentsButton != undefined) {
+	delCommentsButton.disabled = false;
+    }
+    
 }
 
