From 799e419646832c40f9dec122b5cc04512113f12d Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Fri, 26 Feb 2021 06:57:41 +0100
Subject: [PATCH] OO-5313: let float the stop assessment mode button

---
 .../ui/tool/AssessmentToolController.java     | 127 ++---------
 .../tool/StopAssessmentWarningController.java | 213 ++++++++++++++++++
 .../ui/tool/event/StopAssessmentEvent.java    |  40 ++++
 .../course/run/CourseRuntimeController.java   |   2 +-
 4 files changed, 272 insertions(+), 110 deletions(-)
 create mode 100644 src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java
 create mode 100644 src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java

diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java
index 755d06ff5bc..7947b45ac67 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java
@@ -22,7 +22,6 @@ package org.olat.course.assessment.ui.tool;
 import java.util.Date;
 import java.util.List;
 
-import org.olat.commons.calendar.CalendarUtils;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -32,32 +31,28 @@ import org.olat.core.gui.components.stack.PopEvent;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel.Align;
 import org.olat.core.gui.components.tree.TreeNode;
-import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.MainLayoutBasicController;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
-import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
-import org.olat.core.util.Formatter;
-import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentMode;
-import org.olat.course.assessment.AssessmentModeCoordinationService;
 import org.olat.course.assessment.AssessmentModeManager;
 import org.olat.course.assessment.AssessmentModule;
 import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.bulk.BulkAssessmentOverviewController;
 import org.olat.course.assessment.ui.tool.event.AssessmentModeStatusEvent;
 import org.olat.course.assessment.ui.tool.event.CourseNodeEvent;
+import org.olat.course.assessment.ui.tool.event.StopAssessmentEvent;
 import org.olat.course.config.ui.AssessmentResetController;
 import org.olat.course.config.ui.AssessmentResetController.AssessmentResetEvent;
 import org.olat.course.nodeaccess.NodeAccessService;
@@ -67,7 +62,6 @@ import org.olat.modules.assessment.ui.AssessedIdentityListState;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.modules.assessment.ui.event.UserSelectionEvent;
-import org.olat.modules.lecture.LectureService;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -88,20 +82,17 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 	private Link overviewLink;
 	private Link bulkAssessmentLink;
 	private Link recalculateLink;
-	private Link stopAssessmentMode;
 	private final TooledStackedPanel stackPanel;
 	private final AssessmentToolContainer toolContainer;
 	private final ButtonGroupComponent segmentButtonsCmp;
 
 	private CloseableModalController cmc;
-	private ConfirmStopAssessmentModeController stopCtrl;
 	private AssessmentCourseTreeController courseTreeCtrl;
 	private AssessmentCourseOverviewController overviewCtrl;
 	private BulkAssessmentOverviewController bulkAssessmentOverviewCtrl;
 	private AssessmentResetController assessmentResetCtrl;
+	private StopAssessmentWarningController stopAssessmentCtrl;
 	
-	@Autowired
-	private LectureService lectureService;
 	@Autowired
 	private CourseAssessmentService courseAssessmentService;
 	@Autowired
@@ -110,8 +101,6 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 	private AssessmentService assessmentService;
 	@Autowired
 	private AssessmentModeManager assessmentModeManager;
-	@Autowired
-	private AssessmentModeCoordinationService assessmentModeCoordinationService;
 	
 	public AssessmentToolController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
 			RepositoryEntry courseEntry, UserCourseEnvironment coachUserEnv, AssessmentToolSecurityCallback assessmentCallback) {
@@ -132,82 +121,22 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 		putInitialPanel(overviewCtrl.getInitialComponent());
 	}
 	
-	public void assessmentModeMessage() {
+	public void assessmentModeMessage(UserRequest ureq) {
 		List<AssessmentMode> modes = assessmentModeManager.getCurrentAssessmentMode(courseEntry, new Date());
 		if(!modes.isEmpty()) {
-			VelocityContainer warn = createVelocityContainer("assessment_mode_warn");
-			if(modes.size() == 1) {
-				AssessmentMode mode = modes.get(0);
-				assessmemntModeMessageFormatting("assessment.mode.now",  modes, warn);
-				if(canStopAssessmentMode(mode)) {
-					String modeName = mode.getName();
-					String label = translate("assessment.tool.stop", new String[] { StringHelper.escapeHtml(modeName) });
-					stopAssessmentMode = LinkFactory.createCustomLink("assessment.stop", "stop", label, Link.BUTTON_SMALL | Link.NONTRANSLATED, warn, this);
-					stopAssessmentMode.setIconLeftCSS("o_icon o_icon-fw o_as_mode_stop");
-					if(assessmentModeCoordinationService.isDisadvantageCompensationExtensionTime(mode)) {
-						stopAssessmentMode.setIconRightCSS("o_icon o_icon-fw o_icon_disadvantage_compensation");
-					}
-					stopAssessmentMode.setUserObject(mode);
-				}
-			} else {
-				assessmemntModeMessageFormatting("assessment.mode.several.now",  modes, warn);
+			// don't use listenTo as the controller must survive the assessment tool controller
+			if(stopAssessmentCtrl != null) {
+				stopAssessmentCtrl.removeControllerListener(this);
 			}
-			stackPanel.setMessageComponent(warn);
+			stopAssessmentCtrl = new StopAssessmentWarningController(ureq, getWindowControl(), stackPanel,
+					courseEntry, modes, assessmentCallback);
+			stopAssessmentCtrl.addControllerListener(this);
+			stackPanel.setMessageComponent(stopAssessmentCtrl.getInitialComponent());
 		} else {
 			stackPanel.setMessageComponent(null);
 		}
 	}
 	
-	private void assessmemntModeMessageFormatting(String i18nMessage, List<AssessmentMode> modes, VelocityContainer warn) {
-		Date begin = getBeginOfModes(modes);
-		Date end = getEndOfModes(modes);
-		
-		String start;
-		String stop;
-		Formatter formatter = Formatter.getInstance(getLocale());
-		if(CalendarUtils.isSameDay(begin, end)) {
-			start = formatter.formatTimeShort(begin);
-			stop = formatter.formatTimeShort(end);
-		} else {
-			start = formatter.formatDateAndTime(begin);
-			stop = formatter.formatDateAndTime(end);
-		}
-		warn.contextPut("message", translate(i18nMessage, new String[] { start, stop }));
-	}
-	
-	private Date getBeginOfModes(List<AssessmentMode> modes) {
-		Date start = null;
-		for(AssessmentMode mode:modes) {
-			Date begin = mode.getBegin();
-			if(start == null || (begin != null && begin.before(start))) {
-				start = begin;
-			}
-		}
-		return start;
-	}
-	
-	private Date getEndOfModes(List<AssessmentMode> modes) {
-		Date stop = null;
-		for(AssessmentMode mode:modes) {
-			Date end = mode.getEnd();
-			if(stop == null || (end != null && end.after(stop))) {
-				stop = end;
-			}
-		}
-		return stop;
-	}
-	
-	private boolean canStopAssessmentMode(AssessmentMode mode) {
-		if(assessmentCallback.canStartStopAllAssessments()) {
-			return assessmentModeCoordinationService.canStop(mode);
-		} else if(mode.getLectureBlock() != null) {
-			List<Identity> teachers = lectureService.getTeachers(mode.getLectureBlock());
-			return teachers.contains(getIdentity())
-					&& assessmentModeCoordinationService.canStop(mode);
-		}
-		return false;
-	}
-	
 	public void initToolbar() {
 		overviewLink = LinkFactory.createToolLink("overview", translate("overview"), this/*, "o_icon_user"*/);
 		overviewLink.setElementCssClass("o_sel_assessment_tool_overview");
@@ -237,6 +166,9 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 		if(stackPanel != null) {
 			stackPanel.removeListener(this);
 		}
+		if(stopAssessmentCtrl != null) {
+			stopAssessmentCtrl.removeControllerListener(this);
+		}
 	}
 	
 	@Override
@@ -271,8 +203,6 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 		} else if(bulkAssessmentLink == source) {
 			cleanUp();
 			doBulkAssessmentView(ureq);
-		} else if(stopAssessmentMode == source) {
-			doConfirmStop(ureq, (AssessmentMode)stopAssessmentMode.getUserObject());
 		} else if(stackPanel == source) {
 			if(event instanceof PopEvent) {
 				PopEvent pe = (PopEvent)event;
@@ -319,14 +249,8 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 					doSelectNodeView(ureq, cne.getIdent());
 				}
 			} else if(event instanceof AssessmentModeStatusEvent) {
-				assessmentModeMessage();
+				assessmentModeMessage(ureq);
 			}
-		} else if(stopCtrl == source) {
-			if(event == Event.DONE_EVENT) {
-				doAfterStop();
-			}
-			cmc.deactivate();
-			cleanUp();
 		} else if(source == assessmentResetCtrl) {
 			if (event instanceof AssessmentResetEvent) {
 				AssessmentResetEvent are = (AssessmentResetEvent)event;
@@ -334,6 +258,10 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 			}
 			cmc.deactivate();
 			cleanUp();
+		} else if(stopAssessmentCtrl == source) {
+			if(event instanceof StopAssessmentEvent) {
+				overviewCtrl.reloadAssessmentModes();
+			}
 		} else if (source == cmc) {
 			cmc.deactivate();
 			cleanUp();
@@ -344,11 +272,9 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 	private void cleanUp() {
 		removeAsListenerAndDispose(bulkAssessmentOverviewCtrl);
 		removeAsListenerAndDispose(assessmentResetCtrl);
-		removeAsListenerAndDispose(stopCtrl);
 		removeAsListenerAndDispose(cmc);
 		bulkAssessmentOverviewCtrl = null;
 		assessmentResetCtrl = null;
-		stopCtrl = null;
 		cmc = null;
 	}
 	
@@ -427,21 +353,4 @@ public class AssessmentToolController extends MainLayoutBasicController implemen
 		segmentButtonsCmp.setSelectedButton(usersLink);
 		return courseTreeCtrl;
 	}
-	
-	private void doConfirmStop(UserRequest ureq, AssessmentMode mode) {
-		if(guardModalController(stopCtrl)) return;
-		
-		stopCtrl = new ConfirmStopAssessmentModeController(ureq, getWindowControl(), mode);
-		listenTo(stopCtrl);
-
-		String title = translate("confirm.stop.title");
-		cmc = new CloseableModalController(getWindowControl(), "close", stopCtrl.getInitialComponent(), true, title, true);
-		cmc.activate();
-		listenTo(cmc);
-	}
-	
-	private void doAfterStop() {
-		assessmentModeMessage();
-		overviewCtrl.reloadAssessmentModes();
-	}
 }
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java b/src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java
new file mode 100644
index 00000000000..e06c2511df9
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java
@@ -0,0 +1,213 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.tool;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.commons.calendar.CalendarUtils;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.id.Identity;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.StringHelper;
+import org.olat.course.assessment.AssessmentMode;
+import org.olat.course.assessment.AssessmentModeCoordinationService;
+import org.olat.course.assessment.AssessmentModeManager;
+import org.olat.course.assessment.ui.tool.event.StopAssessmentEvent;
+import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
+import org.olat.modules.lecture.LectureService;
+import org.olat.repository.RepositoryEntry;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 25 févr. 2021<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class StopAssessmentWarningController extends BasicController {
+	
+	private Link stopAssessmentMode;
+	private final VelocityContainer mainVC;
+	private final TooledStackedPanel stackPanel;
+
+	private final RepositoryEntry courseEntry;
+	private final AssessmentToolSecurityCallback assessmentCallback;
+	
+	private CloseableModalController cmc;
+	private ConfirmStopAssessmentModeController stopCtrl;
+
+	@Autowired
+	private LectureService lectureService;
+	@Autowired
+	private AssessmentModeManager assessmentModeManager;
+	@Autowired
+	private AssessmentModeCoordinationService assessmentModeCoordinationService;
+	
+	public StopAssessmentWarningController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
+			RepositoryEntry courseEntry, List<AssessmentMode> modes, AssessmentToolSecurityCallback assessmentCallback) {
+		super(ureq, wControl);
+		this.stackPanel = stackPanel;
+		this.courseEntry = courseEntry;
+		this.assessmentCallback = assessmentCallback;
+		mainVC = createVelocityContainer("assessment_mode_warn");
+		assessmentModeMessage(modes);
+		putInitialPanel(mainVC);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	private void reloadAssessmentModeMessage() {
+		List<AssessmentMode> modes = assessmentModeManager.getCurrentAssessmentMode(courseEntry, new Date());
+		if(modes.isEmpty()) {
+			stackPanel.setMessageComponent(null);
+		} else {
+			assessmentModeMessage(modes);
+		}
+	}
+	
+	private void assessmentModeMessage(List<AssessmentMode> modes) {
+		if(modes.size() == 1) {
+			AssessmentMode mode = modes.get(0);
+			assessmemntModeMessageFormatting("assessment.mode.now",  modes, mainVC);
+			if(canStopAssessmentMode(mode)) {
+				String modeName = mode.getName();
+				String label = translate("assessment.tool.stop", new String[] { StringHelper.escapeHtml(modeName) });
+				if(stopAssessmentMode == null) {
+					stopAssessmentMode = LinkFactory.createCustomLink("assessment.stop", "stop", label, Link.BUTTON_SMALL | Link.NONTRANSLATED, mainVC, this);
+				}
+				stopAssessmentMode.setIconLeftCSS("o_icon o_icon-fw o_as_mode_stop");
+				if(assessmentModeCoordinationService.isDisadvantageCompensationExtensionTime(mode)) {
+					stopAssessmentMode.setIconRightCSS("o_icon o_icon-fw o_icon_disadvantage_compensation");
+				}
+				stopAssessmentMode.setUserObject(mode);
+			}
+		} else {
+			assessmemntModeMessageFormatting("assessment.mode.several.now",  modes, mainVC);
+		}
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(stopAssessmentMode == source) {
+			doConfirmStop(ureq, (AssessmentMode)stopAssessmentMode.getUserObject());
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(stopCtrl == source) {
+			if(event == Event.DONE_EVENT) {
+				doAfterStop(ureq);
+			}
+			cmc.deactivate();
+			cleanUp();
+		} else if(cmc == source) {
+			cleanUp();
+		}
+		super.event(ureq, source, event);
+	}
+	
+	private void cleanUp() {
+		removeControllerListener(stopCtrl);
+		removeAsListenerAndDispose(cmc);
+		stopCtrl = null;
+		cmc = null;
+	}
+
+	private boolean canStopAssessmentMode(AssessmentMode mode) {
+		if(assessmentCallback.canStartStopAllAssessments()) {
+			return assessmentModeCoordinationService.canStop(mode);
+		} else if(mode.getLectureBlock() != null) {
+			List<Identity> teachers = lectureService.getTeachers(mode.getLectureBlock());
+			return teachers.contains(getIdentity())
+					&& assessmentModeCoordinationService.canStop(mode);
+		}
+		return false;
+	}
+	
+	private void assessmemntModeMessageFormatting(String i18nMessage, List<AssessmentMode> modes, VelocityContainer warn) {
+		Date begin = getBeginOfModes(modes);
+		Date end = getEndOfModes(modes);
+		
+		String start;
+		String stop;
+		Formatter formatter = Formatter.getInstance(getLocale());
+		if(CalendarUtils.isSameDay(begin, end)) {
+			start = formatter.formatTimeShort(begin);
+			stop = formatter.formatTimeShort(end);
+		} else {
+			start = formatter.formatDateAndTime(begin);
+			stop = formatter.formatDateAndTime(end);
+		}
+		warn.contextPut("message", translate(i18nMessage, new String[] { start, stop }));
+	}
+	
+	private Date getBeginOfModes(List<AssessmentMode> modes) {
+		Date start = null;
+		for(AssessmentMode mode:modes) {
+			Date begin = mode.getBegin();
+			if(start == null || (begin != null && begin.before(start))) {
+				start = begin;
+			}
+		}
+		return start;
+	}
+	
+	private Date getEndOfModes(List<AssessmentMode> modes) {
+		Date stop = null;
+		for(AssessmentMode mode:modes) {
+			Date end = mode.getEnd();
+			if(stop == null || (end != null && end.after(stop))) {
+				stop = end;
+			}
+		}
+		return stop;
+	}
+	
+	private void doConfirmStop(UserRequest ureq, AssessmentMode mode) {
+		if(guardModalController(stopCtrl)) return;
+		
+		stopCtrl = new ConfirmStopAssessmentModeController(ureq, getWindowControl(), mode);
+		listenTo(stopCtrl);
+
+		String title = translate("confirm.stop.title");
+		cmc = new CloseableModalController(getWindowControl(), "close", stopCtrl.getInitialComponent(), true, title, true);
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
+	private void doAfterStop(UserRequest ureq) {
+		reloadAssessmentModeMessage();
+		fireEvent(ureq, new StopAssessmentEvent());
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java b/src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java
new file mode 100644
index 00000000000..dbc71c7dc0e
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java
@@ -0,0 +1,40 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.tool.event;
+
+import org.olat.core.gui.control.Event;
+
+/**
+ * 
+ * Initial date: 25 févr. 2021<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class StopAssessmentEvent extends Event {
+
+	private static final long serialVersionUID = -4403100324034839496L;
+	private static final String STOP_ASSESSMENT_EVENT = "stop-assessment-event";
+	
+	public StopAssessmentEvent() {
+		super(STOP_ASSESSMENT_EVENT);
+	}
+	
+	
+}
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index c5c6556bb9b..e8d13df84fb 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -1891,7 +1891,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			ctrl.activate(ureq, null, null);
 			listenTo(ctrl);
 			assessmentToolCtr = pushController(ureq, translate("command.openassessment"), ctrl);
-			assessmentToolCtr.assessmentModeMessage();
+			assessmentToolCtr.assessmentModeMessage(ureq);
 			currentToolCtr = assessmentToolCtr;
 			setActiveTool(assessmentLink);
 			ctrl.initToolbar();
-- 
GitLab