From 00166aee1f11794514425e263a55eef3f44585a4 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Tue, 7 Feb 2017 08:36:28 +0100
Subject: [PATCH] OO-2487: make the check box pure ajax and don't react to
 submit form

---
 .../elements/MultipleSelectionElement.java    | 19 +++++--
 .../MultipleSelectionElementImpl.java         | 57 +++++++++++++------
 .../elements/MultipleSelectionRenderer.java   | 11 ++++
 .../cl/ui/CheckListAssessmentController.java  | 28 +++++++--
 4 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/elements/MultipleSelectionElement.java b/src/main/java/org/olat/core/gui/components/form/flexible/elements/MultipleSelectionElement.java
index 70d19668c2c..832d54b90a5 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/elements/MultipleSelectionElement.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/elements/MultipleSelectionElement.java
@@ -31,15 +31,11 @@ import java.util.Set;
 
 
 /**
- * Description:<br>
- * TODO: patrickb Class Description for MultipleSelectionElement
  * 
- * <P>
  * Initial Date:  04.01.2007 <br>
  * @author felix
  * @author patrickb
  */
-
 public interface MultipleSelectionElement extends SelectionElement {
 
 	/**
@@ -120,6 +116,21 @@ public interface MultipleSelectionElement extends SelectionElement {
 	 */
 	public void setEscapeHtml(boolean escapeHtml);
 	
+	/**
+	 * @return true if the state of a check box is changed only by ajax
+	 * 					events and not by the submission of a form.
+	 */
+	public boolean isAjaxOnly();
+	
+	/**
+	 * Set to true if the state of the element need to be only
+	 * changed by an ajax event and not by the submission of
+	 *  a form.
+	 *  
+	 * @param ajaxOnlyMode
+	 */
+	public void setAjaxOnly(boolean ajaxOnlyMode);
+	
 	public enum Layout {
 		horizontal,
 		vertical
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java
index 1108e637b3c..96f6fd4d66a 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java
@@ -33,6 +33,7 @@ import java.util.Set;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormItemImpl;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
@@ -59,6 +60,7 @@ public class MultipleSelectionElementImpl extends FormItemImpl implements Multip
 	private final int columns;
 	protected MultipleSelectionComponent component;
 	private String[] original = null;
+	private boolean ajaxOnlyMode = false;
 	private boolean originalIsDefined = false;
 	private boolean escapeHtml = true;
 	private boolean domReplacementWrapperRequired = true;
@@ -91,6 +93,17 @@ public class MultipleSelectionElementImpl extends FormItemImpl implements Multip
 		}
 	}
 
+	@Override
+	public boolean isAjaxOnly() {
+		return ajaxOnlyMode;
+	}
+
+	@Override
+	public void setAjaxOnly(boolean ajaxOnlyMode) {
+		this.ajaxOnlyMode = ajaxOnlyMode;
+		
+	}
+
 	public Layout getLayout() {
 		return layout;
 	}
@@ -228,23 +241,33 @@ public class MultipleSelectionElementImpl extends FormItemImpl implements Multip
 
 	@Override
 	public void evalFormRequest(UserRequest ureq) {
-		if(!isEnabled()){
-			//if element is visible as disabled it would be resetted
-			return;
-		}
-		// which one was selected?
-		// selection change?
-		// mark corresponding comps as dirty
-		String[] reqVals = getRootForm().getRequestParameterValues(getName());
-		if (reqVals == null) {
-			// selection box?
-			reqVals = getRootForm().getRequestParameterValues(getName() + "_SELBOX");
-		}
-		//
-		selected = new HashSet<String>();
-		if (reqVals != null) {
-			for (int i = 0; i < reqVals.length; i++) {
-				selected.add(reqVals[i]);
+		Form form = getRootForm();
+		if(isAjaxOnly()) {
+			String dispatchuri = form.getRequestParameter("dispatchuri");
+			if(dispatchuri != null && dispatchuri.equals(component.getFormDispatchId())) {
+				String key = form.getRequestParameter("achkbox");
+				String checked = form.getRequestParameter("checked");
+				if("true".equals(checked)) {
+					selected.add(key);
+				} else if("false".equals(checked)) {
+					selected.remove(key);
+				}
+			}
+		} else if(isEnabled() ) {
+			// which one was selected?
+			// selection change?
+			// mark corresponding comps as dirty
+			String[] reqVals = form.getRequestParameterValues(getName());
+			if (reqVals == null) {
+				// selection box?
+				reqVals = form.getRequestParameterValues(getName() + "_SELBOX");
+			}
+			//
+			selected = new HashSet<String>();
+			if (reqVals != null) {
+				for (int i = 0; i < reqVals.length; i++) {
+					selected.add(reqVals[i]);
+				}
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionRenderer.java
index bfd9ea4ee23..883149da99b 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionRenderer.java
@@ -24,6 +24,7 @@ import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.DefaultComponentRenderer;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement.Layout;
 import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
+import org.olat.core.gui.components.form.flexible.impl.NameValuePair;
 import org.olat.core.gui.render.RenderResult;
 import org.olat.core.gui.render.Renderer;
 import org.olat.core.gui.render.StringOutput;
@@ -143,6 +144,16 @@ public class MultipleSelectionRenderer extends DefaultComponentRenderer {
 		}
 		if(!stC.isEnabled() || !check.isEnabled()) {
 			sb.append(" disabled='disabled' ");
+		} else if(stF.isAjaxOnly()) {
+			// The implementation is conservative as it send the state of the check box,
+			// this is especially useful if an issue of double evaluation appears.
+			sb.append(" onclick=\"javascript: this.checked ?")
+		      .append(FormJSHelper.getXHRFnCallFor(stF.getRootForm(), stC.getFormDispatchId(), 1, false, false, false,
+		    		  new NameValuePair("achkbox", key), new NameValuePair("checked", "true")))
+		      .append(" : ")
+		      .append(FormJSHelper.getXHRFnCallFor(stF.getRootForm(), stC.getFormDispatchId(), 1, false, false, false,
+		    		  new NameValuePair("achkbox", key), new NameValuePair("checked", "false")))
+			  .append(";\"");
 		} else {
 			//use the selection form dispatch id and not the one of the element!
 			sb.append(FormJSHelper.getRawJSFor(check.getRootForm(), check.getSelectionElementFormDispatchId(), check.getAction()));
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
index dfd27dd3827..82e3de07474 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
@@ -38,12 +38,14 @@ import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
+import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
@@ -187,6 +189,7 @@ public class CheckListAssessmentController extends FormBasicController implement
 		maxScore = (Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MAX);
 
 		initForm(ureq);
+		reloadTable();
 	}
 
 	@Override
@@ -200,10 +203,13 @@ public class CheckListAssessmentController extends FormBasicController implement
 				layoutCont.contextPut("dueDate", dueDate);
 			}
 		}
-		
+
+		FlexiTableSortOptions options = new FlexiTableSortOptions();
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		if(isAdministrativeUser) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18nKey(), Cols.username.ordinal()));
+			options.setDefaultOrderBy(new SortKey(Cols.username.name(), true));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18nKey(), Cols.username.ordinal(),
+					true, Cols.username.name()));
 		}
 		
 		int i=0;
@@ -224,6 +230,9 @@ public class CheckListAssessmentController extends FormBasicController implement
 					col = new DefaultFlexiColumnModel(true, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex, true, propName);
 				}
 				columnsModel.addFlexiColumnModel(col);
+				if(options.getDefaultOrderBy() == null) {
+					options.setDefaultOrderBy(new SortKey(propName, true));
+				}
 			}
 		}
 		
@@ -243,8 +252,7 @@ public class CheckListAssessmentController extends FormBasicController implement
 		}
 		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit.checkbox", translate("table.header.edit.checkbox"), "edit"));
 
-		List<CheckListAssessmentRow> datas = loadDatas();
-		model = new CheckListAssessmentDataModel(checkboxList, datas, columnsModel);
+		model = new CheckListAssessmentDataModel(checkboxList, new ArrayList<>(), columnsModel);
 		table = uifactory.addTableElement(getWindowControl(), "checkbox-list", model, getTranslator(), formLayout);
 		if(coachCourseEnv instanceof UserCourseEnvironmentImpl) {
 			UserCourseEnvironmentImpl env = (UserCourseEnvironmentImpl)coachCourseEnv;
@@ -260,6 +268,8 @@ public class CheckListAssessmentController extends FormBasicController implement
 		}
 		table.setExportEnabled(true);
 		table.setCustomizeColumns(true);
+		FlexiTableSortOptions sortOptions = new FlexiTableSortOptions();
+		table.setSortSettings(sortOptions);
 		table.setAndLoadPersistedPreferences(ureq, "checklist-assessment");
 		
 		pdfExportButton = uifactory.addFormLink("pdf.export", formLayout, Link.BUTTON);
@@ -431,7 +441,13 @@ public class CheckListAssessmentController extends FormBasicController implement
 		}
 		super.formInnerEvent(ureq, source, event);
 	}
-	
+
+	@Override
+	protected void propagateDirtinessToContainer(FormItem fiSrc) {
+		if(!(fiSrc instanceof MultipleSelectionElement)) {
+			super.propagateDirtinessToContainer(fiSrc);
+		}
+	}
 
 	@Override
 	protected void event(UserRequest ureq, Controller source, Event event) {
@@ -508,6 +524,8 @@ public class CheckListAssessmentController extends FormBasicController implement
 				for(int i=0; i<numOfCheckbox; i++) {
 					String checkName = "c" + i + "-" + row.getIdentityKey();
 					checkedEls[i] = uifactory.addCheckboxesHorizontal(checkName, null, flc, onKeys, onValues);
+					checkedEls[i].setAjaxOnly(true);
+					checkedEls[i].setDomReplacementWrapperRequired(false);
 					if(checked != null && i<checked.length && checked[i] != null && checked[i].booleanValue()) {
 						checkedEls[i].select(onKeys[0], true);
 					}
-- 
GitLab