diff --git a/amd/build/mod_form.min.js b/amd/build/mod_form.min.js
index 048e6b2..1f74815 100644
--- a/amd/build/mod_form.min.js
+++ b/amd/build/mod_form.min.js
@@ -1,3 +1,3 @@
-define("mod_mumie/mod_form",["jquery","core/templates","core/modal_factory","auth_mumie/mumie_server_config","core/ajax"],(function(){const addServerButton=document.getElementById("id_add_server_button"),missingConfig=document.getElementsByName("mumie_missing_config")[0];let lmsSelectorUrl,systemLanguage;const serverController=function(){let serverStructure;const serverDropDown=document.getElementById("id_server");return{init:function(structure){serverStructure=structure},getSelectedServer:function(){const selectedServerName=serverDropDown.options[serverDropDown.selectedIndex].text;return serverStructure.find((server=>server.name===selectedServerName))},disable:function(){serverDropDown.disabled=!0,function(elem){for(;elem.firstChild;)elem.removeChild(elem.firstChild)}(serverDropDown)}}}(),problemSelectorController=function(){const problemSelectorButton=document.getElementById("id_prb_selector_btn"),multiProblemSelectorButton=document.getElementById("id_multi_problem_selector_btn");let problemSelectorWindow;const mumieOrg=document.getElementsByName("mumie_org")[0].value;function sendResponse(response){problemSelectorWindow&&problemSelectorWindow.postMessage(JSON.stringify(response),lmsSelectorUrl)}function sendSuccess(){let message=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";sendResponse({success:!0,message:message})}function addMessageListener(){window.addEventListener("message",(event=>{var _importObj$worksheet;if(event.origin!==lmsSelectorUrl)return;const importObj=JSON.parse(event.data),isGraded=!1!==importObj.isGraded,worksheet=null!==(_importObj$worksheet=importObj.worksheet)&&void 0!==_importObj$worksheet?_importObj$worksheet:null;try{courseController.setCourse(importObj.path_to_coursefile),langController.setLanguage(importObj.language),taskController.setSelection(importObj.link,importObj.language,importObj.name),taskController.setIsGraded(isGraded),worksheetController.setWorksheet(worksheet),sendSuccess(),window.focus(),require(["core/str","core/notification"],(function(str,notification){str.get_strings([{key:"mumie_form_updated_selection",component:"mod_mumie"}]).done((function(s){notification.addNotification({message:s[0],type:"info"})})).fail(notification.exception)}))}catch(error){!function(){sendResponse({success:!1,message:arguments.length>0&&void 0!==arguments[0]?arguments[0]:""})}(error.message)}}),!1)}return{init:function(){const gradingType=taskController.getGradingType();problemSelectorButton.onclick=function(){problemSelectorWindow=window.open(lmsSelectorUrl+"/lms-problem-selector?org="+mumieOrg+"&serverUrl="+encodeURIComponent(serverController.getSelectedServer().urlprefix)+"&problemLang="+langController.getSelectedLanguage()+"&origin="+encodeURIComponent(window.location.origin)+"&uiLang="+systemLanguage+"&gradingType="+gradingType+"&multiCourse=true&worksheet=true","_blank")},window.onclose=function(){sendSuccess()},window.addEventListener("beforeunload",(function(){sendSuccess()}),!1),addMessageListener(),multiProblemSelectorButton.onclick=function(e){e.preventDefault(),problemSelectorWindow=window.open(lmsSelectorUrl+"/lms-problem-selector?serverUrl="+encodeURIComponent(serverController.getSelectedServer().urlprefix)+"&gradingType=all","_blank","toolbar=0,location=0,menubar=0")}},disable:function(){problemSelectorButton.disabled=!0}}}(),courseController=function(){const courseNameElem=document.getElementById("id_mumie_course"),coursefileElem=document.getElementsByName("mumie_coursefile")[0];function updateCourseName(){var _selectedCourse$name$;const selectedCourse=courseController.getSelectedCourse(),selectedLanguage=langController.getSelectedLanguage();selectedCourse&&selectedLanguage&&(courseNameElem.value=null===(_selectedCourse$name$=selectedCourse.name.find((translation=>translation.language===selectedLanguage)))||void 0===_selectedCourse$name$?void 0:_selectedCourse$name$.value)}return{init:function(){updateCourseName()},getSelectedCourse:function(){return serverController.getSelectedServer().courses.find((course=>course.coursefile===coursefileElem.value))},setCourse:function(courseFile){var coursefile;coursefile=courseFile,coursefileElem.value=coursefile,updateCourseName()}}}(),langController=function(){const languageElem=document.getElementById("id_language");return{getSelectedLanguage:function(){return languageElem.value},setLanguage:function(lang){languageElem.value=lang}}}(),taskController=function(){const taskSelectionInput=document.getElementsByName("taskurl")[0],nameElem=document.getElementById("id_name"),taskDisplayElement=document.getElementById("id_task_display_element"),isGradedElem=document.getElementById("id_mumie_isgraded");function updateTaskDisplayElemement(localizedLink){taskDisplayElement.value=localizedLink}return{init:function(){updateTaskDisplayElemement(taskSelectionInput.value)},setSelection:function(link,language,name){!function(link,language){const localizedLink=link+"?lang="+language;taskSelectionInput.value=localizedLink,updateTaskDisplayElemement(localizedLink)}(link,language),function(name){nameElem.value=name}(name)},setIsGraded:function(isGraded){null===isGraded&&(isGradedElem.value=null),isGradedElem.value=isGraded?"1":"0",function(){const disabled="0"===isGradedElem.value;document.getElementById("id_points").disabled=disabled,document.getElementById("id_gradepass").disabled=disabled,document.getElementById("id_duedate_enabled").disabled=disabled,document.getElementById("id_gradecat").disabled=disabled}()},getGradingType:function(){const isGraded=isGradedElem.value;return"1"===isGraded?"graded":"0"===isGraded?"ungraded":"all"}}}(),multiTaskEditController=function(){const propertySelectionInputs=document.getElementsByName("mumie_multi_edit_property"),selectedTaskProperties=document.getElementsByName("mumie_selected_task_properties")[0];let selectedTaskProp=[];const taskSelectionInputs=document.getElementsByName("mumie_multi_edit_task"),selectedTasks=document.getElementsByName("mumie_selected_tasks")[0];let selectedTaskIds=[];const sectionInputs=document.getElementsByName("mumie_multi_edit_section");return{init:function(){taskSelectionInputs.forEach((function(checkbox){checkbox.onchange=function(){checkbox.checked?selectedTaskIds.push(checkbox.value):selectedTaskIds=selectedTaskIds.filter((elem=>elem!==checkbox.value)),selectedTasks.value=JSON.stringify(selectedTaskIds)}})),propertySelectionInputs.forEach((function(checkbox){checkbox.onchange=function(){checkbox.checked?selectedTaskProp.push(checkbox.value):selectedTaskProp=selectedTaskProp.filter((elem=>elem!==checkbox.value)),selectedTaskProperties.value=JSON.stringify(selectedTaskProp)}})),sectionInputs.forEach((function(sectionCheckbox){sectionCheckbox.onchange=function(){sectionCheckbox.checked?taskSelectionInputs.forEach((function(taskCheckbox){var array,element;taskCheckbox.getAttribute("section")===sectionCheckbox.value&&(taskCheckbox.checked=!0,array=selectedTaskIds,element=taskCheckbox.value,array.includes(element)||array.push(element))})):taskSelectionInputs.forEach((function(taskCheckbox){taskCheckbox.getAttribute("section")===sectionCheckbox.value&&(taskCheckbox.checked=!1,selectedTaskIds=selectedTaskIds.filter((elem=>taskCheckbox.value!==elem)))})),selectedTasks.value=JSON.stringify(selectedTaskIds)}}))}}}(),worksheetController=function(){const worksheetElement=document.getElementById("id_mumie_worksheet");return{setWorksheet:function(worksheet){worksheet?worksheetElement.setAttribute("value",JSON.stringify(worksheet)):worksheetElement.removeAttribute("value")}}}();function disableDropDownMenus(errorKey){require(["core/str","core/notification"],(function(str,notification){str.get_strings([{key:errorKey,component:"mod_mumie"}]).done((function(s){notification.addNotification({message:s[0]+""+missingConfig.getAttribute("value")+"",type:"problem"})})).fail(notification.exception)})),serverController.disable(),problemSelectorController.disable()}return{init:function(contextid,prbSelectorUrl,lang){lmsSelectorUrl=prbSelectorUrl,systemLanguage=lang;const isEdit=document.getElementById("id_name").getAttribute("value"),serverStructure=JSON.parse(document.getElementsByName("mumie_server_structure")[0].value);isEdit&&""!==document.getElementsByName("mumie_missing_config")[0].getAttribute("value")?disableDropDownMenus("mumie_form_missing_server"):serverStructure.length?(serverController.init(serverStructure),courseController.init(),taskController.init(),multiTaskEditController.init(),problemSelectorController.init()):disableDropDownMenus("mumie_form_no_server_conf"),multiTaskEditController.init(),addServerButton&&require(["auth_mumie/mumie_server_config"],(function(MumieServer){MumieServer.init(addServerButton,contextid)}))}}}));
+define("mod_mumie/mod_form",["jquery","core/templates","core/modal_factory","auth_mumie/mumie_server_config","core/ajax"],(function(){const addServerButton=document.getElementById("id_add_server_button"),missingConfig=document.getElementsByName("mumie_missing_config")[0];let lmsSelectorUrl,systemLanguage,contextId;const serverController=function(){let serverStructure;const serverDropDown=document.getElementById("id_server");return{init:function(structure){serverStructure=structure},getSelectedServer:function(){const selectedServerName=serverDropDown.options[serverDropDown.selectedIndex].text;return serverStructure.find((server=>server.name===selectedServerName))},disable:function(){serverDropDown.disabled=!0,function(elem){for(;elem.firstChild;)elem.removeChild(elem.firstChild)}(serverDropDown)}}}(),problemSelectorController=function(){const problemSelectorButton=document.getElementById("id_prb_selector_btn"),multiProblemSelectorButton=document.getElementById("id_multi_problem_selector_btn");let problemSelectorWindow;const mumieOrg=document.getElementsByName("mumie_org")[0].value;function sendResponse(response){problemSelectorWindow&&problemSelectorWindow.postMessage(JSON.stringify(response),lmsSelectorUrl)}function sendSuccess(){let message=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";sendResponse({success:!0,message:message})}function addMessageListener(){window.addEventListener("message",(event=>{var _importObj$worksheet;if(event.origin!==lmsSelectorUrl)return;const importObj=JSON.parse(event.data),isGraded=!1!==importObj.isGraded,worksheet=null!==(_importObj$worksheet=importObj.worksheet)&&void 0!==_importObj$worksheet?_importObj$worksheet:null;try{courseController.setCourse(importObj.path_to_coursefile),langController.setLanguage(importObj.language),taskController.setSelection(importObj.link,importObj.language,importObj.name),taskController.setIsGraded(isGraded),worksheetController.setWorksheet(worksheet),sendSuccess(),window.focus(),require(["core/str","core/notification"],(function(str,notification){str.get_strings([{key:"mumie_form_updated_selection",component:"mod_mumie"}]).done((function(s){notification.addNotification({message:s[0],type:"info"})})).fail(notification.exception)}))}catch(error){!function(){sendResponse({success:!1,message:arguments.length>0&&void 0!==arguments[0]?arguments[0]:""})}(error.message)}}),!1)}function buildURL(){const gradingType=taskController.getGradingType(),selection=taskController.getDelocalizedTaskLink(),selectedServer=serverController.getSelectedServer().urlprefix;var selectedServerUrl;return(selectedServerUrl=selectedServer,new URL(lmsSelectorUrl).origin===new URL(selectedServerUrl).origin)?"/auth/mumie/problem_selector.php?org="+mumieOrg+"&serverurl="+encodeURIComponent(selectedServer)+"&problemlang="+langController.getSelectedLanguage()+"&origin="+encodeURIComponent(window.location.origin)+"&gradingtype="+gradingType+"&contextid="+contextId+(selection?"&selection="+selection:""):lmsSelectorUrl+"/lms-problem-selector?org="+mumieOrg+"&serverUrl="+encodeURIComponent(selectedServer)+"&problemLang="+langController.getSelectedLanguage()+"&origin="+encodeURIComponent(window.location.origin)+"&uiLang="+systemLanguage+"&gradingType="+gradingType+"&multiCourse=true&worksheet=true"+(selection?"&selection="+selection:"")}return{init:function(){problemSelectorButton.onclick=function(){problemSelectorWindow=window.open(buildURL(),"_blank")},window.onclose=function(){sendSuccess()},window.addEventListener("beforeunload",(function(){sendSuccess()}),!1),addMessageListener(),multiProblemSelectorButton.onclick=function(e){e.preventDefault(),problemSelectorWindow=window.open(lmsSelectorUrl+"/lms-problem-selector?serverUrl="+encodeURIComponent(serverController.getSelectedServer().urlprefix)+"&gradingType=all","_blank","toolbar=0,location=0,menubar=0")}},disable:function(){problemSelectorButton.disabled=!0}}}(),courseController=function(){const courseNameElem=document.getElementById("id_mumie_course"),coursefileElem=document.getElementsByName("mumie_coursefile")[0];function updateCourseName(){var _selectedCourse$name$;const selectedCourse=courseController.getSelectedCourse(),selectedLanguage=langController.getSelectedLanguage();selectedCourse&&selectedLanguage&&(courseNameElem.value=null===(_selectedCourse$name$=selectedCourse.name.find((translation=>translation.language===selectedLanguage)))||void 0===_selectedCourse$name$?void 0:_selectedCourse$name$.value)}return{init:function(){updateCourseName()},getSelectedCourse:function(){return serverController.getSelectedServer().courses.find((course=>course.coursefile===coursefileElem.value))},setCourse:function(courseFile){var coursefile;coursefile=courseFile,coursefileElem.value=coursefile,updateCourseName()}}}(),langController=function(){const languageElem=document.getElementById("id_language");return{getSelectedLanguage:function(){return languageElem.value},setLanguage:function(lang){languageElem.value=lang}}}(),taskController=function(){const taskSelectionInput=document.getElementsByName("taskurl")[0],nameElem=document.getElementById("id_name"),taskDisplayElement=document.getElementById("id_task_display_element"),isGradedElem=document.getElementById("id_mumie_isgraded");function updateTaskDisplayElemement(localizedLink){taskDisplayElement.value=localizedLink}function updateTaskUri(link,language){const localizedLink=function(link,language){return link+"?lang="+language}(link,language);taskSelectionInput.value=localizedLink,updateTaskDisplayElemement(localizedLink)}return{init:function(){updateTaskDisplayElemement(taskSelectionInput.value)},setSelection:function(link,language,name){updateTaskUri(link,language),function(name){nameElem.value=name}(name)},setIsGraded:function(isGraded){null===isGraded&&(isGradedElem.value=null),isGradedElem.value=isGraded?"1":"0",function(){const disabled="0"===isGradedElem.value;document.getElementById("id_points").disabled=disabled,document.getElementById("id_gradepass").disabled=disabled,document.getElementById("id_duedate_enabled").disabled=disabled,document.getElementById("id_gradecat").disabled=disabled}()},getGradingType:function(){const isGraded=isGradedElem.value;return"1"===isGraded?"graded":"0"===isGraded?"ungraded":"all"},getDelocalizedTaskLink:function(){return(link=taskSelectionInput.value).includes("?lang=")?link.split("?lang=")[0]:link;var link}}}(),multiTaskEditController=function(){const propertySelectionInputs=document.getElementsByName("mumie_multi_edit_property"),selectedTaskProperties=document.getElementsByName("mumie_selected_task_properties")[0];let selectedTaskProp=[];const taskSelectionInputs=document.getElementsByName("mumie_multi_edit_task"),selectedTasks=document.getElementsByName("mumie_selected_tasks")[0];let selectedTaskIds=[];const sectionInputs=document.getElementsByName("mumie_multi_edit_section");return{init:function(){taskSelectionInputs.forEach((function(checkbox){checkbox.onchange=function(){checkbox.checked?selectedTaskIds.push(checkbox.value):selectedTaskIds=selectedTaskIds.filter((elem=>elem!==checkbox.value)),selectedTasks.value=JSON.stringify(selectedTaskIds)}})),propertySelectionInputs.forEach((function(checkbox){checkbox.onchange=function(){checkbox.checked?selectedTaskProp.push(checkbox.value):selectedTaskProp=selectedTaskProp.filter((elem=>elem!==checkbox.value)),selectedTaskProperties.value=JSON.stringify(selectedTaskProp)}})),sectionInputs.forEach((function(sectionCheckbox){sectionCheckbox.onchange=function(){sectionCheckbox.checked?taskSelectionInputs.forEach((function(taskCheckbox){var array,element;taskCheckbox.getAttribute("section")===sectionCheckbox.value&&(taskCheckbox.checked=!0,array=selectedTaskIds,element=taskCheckbox.value,array.includes(element)||array.push(element))})):taskSelectionInputs.forEach((function(taskCheckbox){taskCheckbox.getAttribute("section")===sectionCheckbox.value&&(taskCheckbox.checked=!1,selectedTaskIds=selectedTaskIds.filter((elem=>taskCheckbox.value!==elem)))})),selectedTasks.value=JSON.stringify(selectedTaskIds)}}))}}}(),worksheetController=function(){const worksheetElement=document.getElementById("id_mumie_worksheet");return{setWorksheet:function(worksheet){worksheet?worksheetElement.setAttribute("value",JSON.stringify(worksheet)):worksheetElement.removeAttribute("value")}}}();function disableDropDownMenus(errorKey){require(["core/str","core/notification"],(function(str,notification){str.get_strings([{key:errorKey,component:"mod_mumie"}]).done((function(s){notification.addNotification({message:s[0]+""+missingConfig.getAttribute("value")+"",type:"problem"})})).fail(notification.exception)})),serverController.disable(),problemSelectorController.disable()}return{init:function(contextIdParam,prbSelectorUrl,lang){lmsSelectorUrl=prbSelectorUrl,systemLanguage=lang,contextId=contextIdParam;const isEdit=document.getElementById("id_name").getAttribute("value"),serverStructure=JSON.parse(document.getElementsByName("mumie_server_structure")[0].value);isEdit&&""!==document.getElementsByName("mumie_missing_config")[0].getAttribute("value")?disableDropDownMenus("mumie_form_missing_server"):serverStructure.length?(serverController.init(serverStructure),courseController.init(),taskController.init(),multiTaskEditController.init(),problemSelectorController.init()):disableDropDownMenus("mumie_form_no_server_conf"),multiTaskEditController.init(),addServerButton&&require(["auth_mumie/mumie_server_config"],(function(MumieServer){MumieServer.init(addServerButton,contextId)}))}}}));
//# sourceMappingURL=mod_form.min.js.map
\ No newline at end of file
diff --git a/amd/build/mod_form.min.js.map b/amd/build/mod_form.min.js.map
index d5dcfe0..71550b5 100644
--- a/amd/build/mod_form.min.js.map
+++ b/amd/build/mod_form.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"mod_form.min.js","sources":["../src/mod_form.js"],"sourcesContent":["define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_server_config', 'core/ajax'],\n function() {\n const addServerButton = document.getElementById(\"id_add_server_button\");\n const missingConfig = document.getElementsByName(\"mumie_missing_config\")[0];\n let lmsSelectorUrl;\n let systemLanguage;\n const serverController = (function() {\n let serverStructure;\n const serverDropDown = document.getElementById(\"id_server\");\n\n return {\n init: function(structure) {\n serverStructure = structure;\n },\n getSelectedServer: function() {\n const selectedServerName = serverDropDown.options[serverDropDown.selectedIndex].text;\n return serverStructure.find(server => server.name === selectedServerName);\n },\n disable: function() {\n serverDropDown.disabled = true;\n removeChildElems(serverDropDown);\n }\n };\n })();\n\n const problemSelectorController = (function() {\n const problemSelectorButton = document.getElementById('id_prb_selector_btn');\n const multiProblemSelectorButton = document.getElementById('id_multi_problem_selector_btn');\n let problemSelectorWindow;\n const mumieOrg = document.getElementsByName('mumie_org')[0].value;\n\n /**\n * Send a message to the problem selector window.\n *\n * Don't do anything if there is no problem selector window.\n * @param {Object} response\n */\n function sendResponse(response) {\n if (!problemSelectorWindow) {\n return;\n }\n problemSelectorWindow.postMessage(JSON.stringify(response), lmsSelectorUrl);\n }\n\n /**\n * Send a success message to problem selector window\n * @param {string} message\n */\n function sendSuccess(message = '') {\n sendResponse({\n success: true,\n message: message\n });\n }\n\n /**\n * Send a failure message to problem selector window\n * @param {string} message\n */\n function sendFailure(message = '') {\n sendResponse({\n success: false,\n message: message\n });\n }\n\n /**\n * Add an event listener that accepts messages from LMS-Browser and updates the selected problem.\n */\n function addMessageListener() {\n window.addEventListener('message', (event) => {\n if (event.origin !== lmsSelectorUrl) {\n return;\n }\n const importObj = JSON.parse(event.data);\n const isGraded = importObj.isGraded !== false;\n const worksheet = importObj.worksheet ?? null;\n try {\n courseController.setCourse(importObj.path_to_coursefile);\n langController.setLanguage(importObj.language);\n taskController.setSelection(importObj.link, importObj.language, importObj.name);\n taskController.setIsGraded(isGraded);\n worksheetController.setWorksheet(worksheet);\n sendSuccess();\n window.focus();\n displayProblemSelectedMessage();\n } catch (error) {\n sendFailure(error.message);\n }\n }, false);\n }\n\n /**\n * Display a success message in Moodle that a problem was successfully selected.\n */\n function displayProblemSelectedMessage() {\n require(['core/str', \"core/notification\"], function(str, notification) {\n str.get_strings([{\n 'key': 'mumie_form_updated_selection',\n component: 'mod_mumie'\n }]).done(function(s) {\n notification.addNotification({\n message: s[0],\n type: \"info\"\n });\n }).fail(notification.exception);\n });\n }\n\n return {\n init: function() {\n const gradingType = taskController.getGradingType();\n problemSelectorButton.onclick = function() {\n problemSelectorWindow = window.open(\n lmsSelectorUrl\n + '/lms-problem-selector?'\n + 'org='\n + mumieOrg\n + '&serverUrl='\n + encodeURIComponent(serverController.getSelectedServer().urlprefix)\n + '&problemLang='\n + langController.getSelectedLanguage()\n + '&origin=' + encodeURIComponent(window.location.origin)\n + '&uiLang=' + systemLanguage\n + '&gradingType=' + gradingType\n + '&multiCourse=true'\n + '&worksheet=true'\n , '_blank'\n );\n };\n\n window.onclose = function() {\n sendSuccess();\n };\n\n window.addEventListener(\"beforeunload\", function() {\n sendSuccess();\n }, false);\n\n addMessageListener();\n\n multiProblemSelectorButton.onclick = function(e) {\n e.preventDefault();\n problemSelectorWindow = window.open(\n lmsSelectorUrl\n + '/lms-problem-selector?'\n + \"serverUrl=\"\n + encodeURIComponent(serverController.getSelectedServer().urlprefix)\n + '&gradingType=all',\n \"_blank\",\n 'toolbar=0,location=0,menubar=0'\n );\n };\n },\n disable: function() {\n problemSelectorButton.disabled = true;\n }\n };\n })();\n\n const courseController = (function() {\n const courseNameElem = document.getElementById(\"id_mumie_course\");\n const coursefileElem = document.getElementsByName(\"mumie_coursefile\")[0];\n\n\n /**\n * Update the hidden input field with the selected course's course file path\n *\n * @param {string} coursefile\n */\n function updateCoursefilePath(coursefile) {\n coursefileElem.value = coursefile;\n updateCourseName();\n }\n\n /**\n * Update displayed course name.\n */\n function updateCourseName() {\n const selectedCourse = courseController.getSelectedCourse();\n const selectedLanguage = langController.getSelectedLanguage();\n if (!selectedCourse || !selectedLanguage) {\n return;\n }\n courseNameElem.value = selectedCourse.name\n .find(translation => translation.language === selectedLanguage)?.value;\n }\n\n return {\n init: function() {\n updateCourseName();\n },\n getSelectedCourse: function() {\n const courses = serverController.getSelectedServer().courses;\n return courses.find(course => course.coursefile === coursefileElem.value);\n },\n setCourse: function(courseFile) {\n updateCoursefilePath(courseFile);\n }\n };\n })();\n\n const langController = (function() {\n const languageElem = document.getElementById(\"id_language\");\n return {\n getSelectedLanguage: function() {\n return languageElem.value;\n },\n setLanguage: function(lang) {\n languageElem.value = lang;\n }\n };\n })();\n\n const taskController = (function() {\n const taskSelectionInput = document.getElementsByName(\"taskurl\")[0];\n const nameElem = document.getElementById(\"id_name\");\n const taskDisplayElement = document.getElementById(\"id_task_display_element\");\n const isGradedElem = document.getElementById('id_mumie_isgraded');\n\n\n /**\n * Update the activity's name in the input field\n * @param {string} name\n */\n function updateName(name) {\n nameElem.value = name;\n }\n\n /**\n * @param {string} localizedLink\n */\n function updateTaskDisplayElemement(localizedLink) {\n taskDisplayElement.value = localizedLink;\n }\n\n /**\n * Update task uri\n * @param {string} link\n * @param {string} language\n */\n function updateTaskUri(link, language) {\n const localizedLink = link + \"?lang=\" + language;\n taskSelectionInput.value = localizedLink;\n updateTaskDisplayElemement(localizedLink);\n }\n\n /**\n * Form inputs related to grades should be disabled, if the MUMIE Task is not graded.\n */\n function updateGradeEditability() {\n const disabled = isGradedElem.value === '0';\n document.getElementById('id_points').disabled = disabled;\n document.getElementById('id_gradepass').disabled = disabled;\n document.getElementById('id_duedate_enabled').disabled = disabled;\n document.getElementById('id_gradecat').disabled = disabled;\n }\n\n return {\n init: function() {\n updateTaskDisplayElemement(taskSelectionInput.value);\n },\n setSelection: function(link, language, name) {\n updateTaskUri(link, language);\n updateName(name);\n },\n setIsGraded: function(isGraded) {\n if (isGraded === null) {\n isGradedElem.value = null;\n }\n isGradedElem.value = isGraded ? '1' : '0';\n updateGradeEditability();\n },\n getGradingType: function() {\n const isGraded = isGradedElem.value;\n if (isGraded === '1') {\n return 'graded';\n } else if (isGraded === '0') {\n return 'ungraded';\n }\n return 'all';\n }\n };\n })();\n\n\n const multiTaskEditController = (function() {\n const propertySelectionInputs = document.getElementsByName(\"mumie_multi_edit_property\");\n const selectedTaskProperties = document.getElementsByName(\"mumie_selected_task_properties\")[0];\n let selectedTaskProp = [];\n const taskSelectionInputs = document.getElementsByName(\"mumie_multi_edit_task\");\n const selectedTasks = document.getElementsByName(\"mumie_selected_tasks\")[0];\n let selectedTaskIds = [];\n const sectionInputs = document.getElementsByName(\"mumie_multi_edit_section\");\n\n /**\n * Push an element to an array, if it's not already included.\n *\n * @param {string[]} array\n * @param {string} element\n */\n function pushIfNotExists(array, element) {\n if (!array.includes(element)) {\n array.push(element);\n }\n }\n\n /**\n * Set selection listeners for other MUMIE Tasks in the course.\n */\n function setTaskSelectionListeners() {\n taskSelectionInputs.forEach(function(checkbox) {\n checkbox.onchange = function() {\n if (!checkbox.checked) {\n selectedTaskIds = selectedTaskIds.filter(elem => elem !== checkbox.value);\n } else {\n selectedTaskIds.push(checkbox.value);\n }\n selectedTasks.value = JSON.stringify(selectedTaskIds);\n };\n });\n }\n\n /**\n * Set selection listeners for properties to apply to MUMIE Tasks in the course.\n */\n function setPropertySelectionListeners() {\n propertySelectionInputs.forEach(function(checkbox) {\n checkbox.onchange = function() {\n if (!checkbox.checked) {\n selectedTaskProp = selectedTaskProp.filter(elem => elem !== checkbox.value);\n } else {\n selectedTaskProp.push(checkbox.value);\n }\n selectedTaskProperties.value = JSON.stringify(selectedTaskProp);\n };\n });\n }\n\n /**\n * Set selection listeners for entire section of MUMIE Tasks in the course\n */\n function setSectionSelectionListeners() {\n sectionInputs.forEach(function(sectionCheckbox) {\n sectionCheckbox.onchange = function() {\n if (!sectionCheckbox.checked) {\n taskSelectionInputs.forEach(function(taskCheckbox) {\n if (taskCheckbox.getAttribute('section') === sectionCheckbox.value) {\n taskCheckbox.checked = false;\n selectedTaskIds = selectedTaskIds.filter(elem => taskCheckbox.value !== elem);\n }\n });\n } else {\n taskSelectionInputs.forEach(function(taskCheckbox) {\n if (taskCheckbox.getAttribute('section') === sectionCheckbox.value) {\n taskCheckbox.checked = true;\n pushIfNotExists(selectedTaskIds, taskCheckbox.value);\n }\n });\n }\n selectedTasks.value = JSON.stringify(selectedTaskIds);\n };\n });\n }\n\n return {\n init: function() {\n setTaskSelectionListeners();\n setPropertySelectionListeners();\n setSectionSelectionListeners();\n },\n };\n })();\n\n const worksheetController = (function() {\n const worksheetElement = document.getElementById(\"id_mumie_worksheet\");\n return {\n setWorksheet: function(worksheet) {\n if (worksheet) {\n worksheetElement.setAttribute(\"value\", JSON.stringify(worksheet));\n } else {\n worksheetElement.removeAttribute(\"value\");\n }\n }\n };\n })();\n\n /**\n * Disable all dropdown menus and show notification\n * @param {string} errorKey\n */\n function disableDropDownMenus(errorKey) {\n require(['core/str', \"core/notification\"], function(str, notification) {\n str.get_strings([{\n 'key': errorKey,\n component: 'mod_mumie'\n }]).done(function(s) {\n notification.addNotification({\n message: s[0] + \"\" + missingConfig.getAttribute(\"value\") + \"\",\n type: \"problem\"\n });\n }).fail(notification.exception);\n });\n serverController.disable();\n problemSelectorController.disable();\n }\n\n return {\n init: function(contextid, prbSelectorUrl, lang) {\n lmsSelectorUrl = prbSelectorUrl;\n systemLanguage = lang;\n const isEdit = document.getElementById(\"id_name\").getAttribute('value');\n const serverStructure = JSON.parse(document.getElementsByName('mumie_server_structure')[0].value);\n if (isEdit && !serverConfigExists()) {\n disableDropDownMenus('mumie_form_missing_server');\n } else if (!serverStructure.length) {\n disableDropDownMenus('mumie_form_no_server_conf');\n } else {\n serverController.init(serverStructure);\n courseController.init();\n taskController.init();\n multiTaskEditController.init();\n problemSelectorController.init();\n }\n multiTaskEditController.init();\n if (addServerButton) {\n require(['auth_mumie/mumie_server_config'], function(MumieServer) {\n MumieServer.init(addServerButton, contextid);\n });\n }\n }\n };\n\n /**\n * Remove all child elements of a given html element\n * @param {Object} elem\n */\n function removeChildElems(elem) {\n while (elem.firstChild) {\n elem.removeChild(elem.firstChild);\n }\n }\n\n /**\n * Check, if the flag for an existing config is set\n * @returns {boolean}\n */\n function serverConfigExists() {\n return document.getElementsByName(\"mumie_missing_config\")[0].getAttribute(\"value\") === \"\";\n }\n });\n"],"names":["define","addServerButton","document","getElementById","missingConfig","getElementsByName","lmsSelectorUrl","systemLanguage","serverController","serverStructure","serverDropDown","init","structure","getSelectedServer","selectedServerName","options","selectedIndex","text","find","server","name","disable","disabled","elem","firstChild","removeChild","removeChildElems","problemSelectorController","problemSelectorButton","multiProblemSelectorButton","problemSelectorWindow","mumieOrg","value","sendResponse","response","postMessage","JSON","stringify","sendSuccess","message","success","addMessageListener","window","addEventListener","event","origin","importObj","parse","data","isGraded","worksheet","courseController","setCourse","path_to_coursefile","langController","setLanguage","language","taskController","setSelection","link","setIsGraded","worksheetController","setWorksheet","focus","require","str","notification","get_strings","component","done","s","addNotification","type","fail","exception","error","sendFailure","gradingType","getGradingType","onclick","open","encodeURIComponent","urlprefix","getSelectedLanguage","location","onclose","e","preventDefault","courseNameElem","coursefileElem","updateCourseName","selectedCourse","getSelectedCourse","selectedLanguage","translation","_selectedCourse$name$","courses","course","coursefile","courseFile","languageElem","lang","taskSelectionInput","nameElem","taskDisplayElement","isGradedElem","updateTaskDisplayElemement","localizedLink","updateTaskUri","updateName","updateGradeEditability","multiTaskEditController","propertySelectionInputs","selectedTaskProperties","selectedTaskProp","taskSelectionInputs","selectedTasks","selectedTaskIds","sectionInputs","forEach","checkbox","onchange","checked","push","filter","sectionCheckbox","taskCheckbox","array","element","getAttribute","includes","worksheetElement","setAttribute","removeAttribute","disableDropDownMenus","errorKey","contextid","prbSelectorUrl","isEdit","length","MumieServer"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"mod_form.min.js","sources":["../src/mod_form.js"],"sourcesContent":["define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_server_config', 'core/ajax'],\n function() {\n const addServerButton = document.getElementById(\"id_add_server_button\");\n const missingConfig = document.getElementsByName(\"mumie_missing_config\")[0];\n let lmsSelectorUrl;\n let systemLanguage;\n let contextId;\n const serverController = (function() {\n let serverStructure;\n const serverDropDown = document.getElementById(\"id_server\");\n\n return {\n init: function(structure) {\n serverStructure = structure;\n },\n getSelectedServer: function() {\n const selectedServerName = serverDropDown.options[serverDropDown.selectedIndex].text;\n return serverStructure.find(server => server.name === selectedServerName);\n },\n disable: function() {\n serverDropDown.disabled = true;\n removeChildElems(serverDropDown);\n }\n };\n })();\n\n const problemSelectorController = (function() {\n const problemSelectorButton = document.getElementById('id_prb_selector_btn');\n const multiProblemSelectorButton = document.getElementById('id_multi_problem_selector_btn');\n let problemSelectorWindow;\n const mumieOrg = document.getElementsByName('mumie_org')[0].value;\n\n /**\n * Send a message to the problem selector window.\n *\n * Don't do anything if there is no problem selector window.\n * @param {Object} response\n */\n function sendResponse(response) {\n if (!problemSelectorWindow) {\n return;\n }\n problemSelectorWindow.postMessage(JSON.stringify(response), lmsSelectorUrl);\n }\n\n /**\n * Send a success message to problem selector window\n * @param {string} message\n */\n function sendSuccess(message = '') {\n sendResponse({\n success: true,\n message: message\n });\n }\n\n /**\n * Send a failure message to problem selector window\n * @param {string} message\n */\n function sendFailure(message = '') {\n sendResponse({\n success: false,\n message: message\n });\n }\n\n /**\n * Add an event listener that accepts messages from LMS-Browser and updates the selected problem.\n */\n function addMessageListener() {\n window.addEventListener('message', (event) => {\n if (event.origin !== lmsSelectorUrl) {\n return;\n }\n const importObj = JSON.parse(event.data);\n const isGraded = importObj.isGraded !== false;\n const worksheet = importObj.worksheet ?? null;\n try {\n courseController.setCourse(importObj.path_to_coursefile);\n langController.setLanguage(importObj.language);\n taskController.setSelection(importObj.link, importObj.language, importObj.name);\n taskController.setIsGraded(isGraded);\n worksheetController.setWorksheet(worksheet);\n sendSuccess();\n window.focus();\n displayProblemSelectedMessage();\n } catch (error) {\n sendFailure(error.message);\n }\n }, false);\n }\n\n /**\n * Display a success message in Moodle that a problem was successfully selected.\n */\n function displayProblemSelectedMessage() {\n require(['core/str', \"core/notification\"], function(str, notification) {\n str.get_strings([{\n 'key': 'mumie_form_updated_selection',\n component: 'mod_mumie'\n }]).done(function(s) {\n notification.addNotification({\n message: s[0],\n type: \"info\"\n });\n }).fail(notification.exception);\n });\n }\n\n /**\n * Builds the URL to the Problem Selector\n * @returns {string} URL to the Problem Selector\n */\n function buildURL() {\n const gradingType = taskController.getGradingType();\n const selection = taskController.getDelocalizedTaskLink();\n const selectedServer = serverController.getSelectedServer().urlprefix;\n const useSSO = shouldUseSSO(lmsSelectorUrl, selectedServer);\n if (useSSO) {\n return '/auth/mumie/problem_selector.php?'\n + 'org='\n + mumieOrg\n + '&serverurl='\n + encodeURIComponent(selectedServer)\n + '&problemlang='\n + langController.getSelectedLanguage()\n + '&origin=' + encodeURIComponent(window.location.origin)\n + '&gradingtype=' + gradingType\n + '&contextid=' + contextId\n + (selection ? '&selection=' + selection : '');\n }\n return lmsSelectorUrl\n + '/lms-problem-selector?'\n + 'org='\n + mumieOrg\n + '&serverUrl='\n + encodeURIComponent(selectedServer)\n + '&problemLang='\n + langController.getSelectedLanguage()\n + '&origin=' + encodeURIComponent(window.location.origin)\n + '&uiLang=' + systemLanguage\n + '&gradingType=' + gradingType\n + '&multiCourse=true'\n + '&worksheet=true'\n + (selection ? '&selection=' + selection : '');\n }\n\n /**\n * Determines whether the Single Sign-On (SSO) should be used when opening the Problem Selector.\n * SSO is only supposed to be used when the Problem Selector URL has the same origin as the\n * URL of the selected MUMIE server.\n *\n * @param {string} problemSelectorUrl - The URL of the problem selector.\n * @param {string} selectedServerUrl - The URL of the selected MUMIE server\n * @returns {boolean} Whether SSO should be used for the Problem Selector or not\n */\n function shouldUseSSO(problemSelectorUrl, selectedServerUrl) {\n return new URL(problemSelectorUrl).origin === new URL(selectedServerUrl).origin;\n }\n\n return {\n init: function() {\n problemSelectorButton.onclick = function() {\n problemSelectorWindow = window.open(buildURL(), '_blank');\n };\n\n window.onclose = function() {\n sendSuccess();\n };\n\n window.addEventListener(\"beforeunload\", function() {\n sendSuccess();\n }, false);\n\n addMessageListener();\n\n multiProblemSelectorButton.onclick = function(e) {\n e.preventDefault();\n problemSelectorWindow = window.open(\n lmsSelectorUrl\n + '/lms-problem-selector?'\n + \"serverUrl=\"\n + encodeURIComponent(serverController.getSelectedServer().urlprefix)\n + '&gradingType=all',\n \"_blank\",\n 'toolbar=0,location=0,menubar=0'\n );\n };\n },\n disable: function() {\n problemSelectorButton.disabled = true;\n }\n };\n })();\n\n const courseController = (function() {\n const courseNameElem = document.getElementById(\"id_mumie_course\");\n const coursefileElem = document.getElementsByName(\"mumie_coursefile\")[0];\n\n\n /**\n * Update the hidden input field with the selected course's course file path\n *\n * @param {string} coursefile\n */\n function updateCoursefilePath(coursefile) {\n coursefileElem.value = coursefile;\n updateCourseName();\n }\n\n /**\n * Update displayed course name.\n */\n function updateCourseName() {\n const selectedCourse = courseController.getSelectedCourse();\n const selectedLanguage = langController.getSelectedLanguage();\n if (!selectedCourse || !selectedLanguage) {\n return;\n }\n courseNameElem.value = selectedCourse.name\n .find(translation => translation.language === selectedLanguage)?.value;\n }\n\n return {\n init: function() {\n updateCourseName();\n },\n getSelectedCourse: function() {\n const courses = serverController.getSelectedServer().courses;\n return courses.find(course => course.coursefile === coursefileElem.value);\n },\n setCourse: function(courseFile) {\n updateCoursefilePath(courseFile);\n }\n };\n })();\n\n const langController = (function() {\n const languageElem = document.getElementById(\"id_language\");\n return {\n getSelectedLanguage: function() {\n return languageElem.value;\n },\n setLanguage: function(lang) {\n languageElem.value = lang;\n }\n };\n })();\n\n const taskController = (function() {\n const taskSelectionInput = document.getElementsByName(\"taskurl\")[0];\n const nameElem = document.getElementById(\"id_name\");\n const taskDisplayElement = document.getElementById(\"id_task_display_element\");\n const isGradedElem = document.getElementById('id_mumie_isgraded');\n const LANG_REQUEST_PARAM_PREFIX = \"?lang=\";\n\n /**\n * Update the activity's name in the input field\n * @param {string} name\n */\n function updateName(name) {\n nameElem.value = name;\n }\n\n /**\n * @param {string} localizedLink\n */\n function updateTaskDisplayElemement(localizedLink) {\n taskDisplayElement.value = localizedLink;\n }\n\n /**\n * Update task uri\n * @param {string} link\n * @param {string} language\n */\n function updateTaskUri(link, language) {\n const localizedLink = localizeLink(link, language);\n taskSelectionInput.value = localizedLink;\n updateTaskDisplayElemement(localizedLink);\n }\n\n /**\n * Add lang request param to link\n * @param {string} link\n * @param {string} language\n * @returns {string} Link with lang request param\n */\n function localizeLink(link, language) {\n return link + LANG_REQUEST_PARAM_PREFIX + language;\n }\n\n /**\n * Remove lang request param from link\n * @param {string} link Link that may have lang request param\n * @returns {string} Link without lang request param\n */\n function delocalizeLink(link) {\n if (link.includes(LANG_REQUEST_PARAM_PREFIX)) {\n return link.split(LANG_REQUEST_PARAM_PREFIX)[0];\n }\n return link;\n }\n\n /**\n * Form inputs related to grades should be disabled, if the MUMIE Task is not graded.\n */\n function updateGradeEditability() {\n const disabled = isGradedElem.value === '0';\n document.getElementById('id_points').disabled = disabled;\n document.getElementById('id_gradepass').disabled = disabled;\n document.getElementById('id_duedate_enabled').disabled = disabled;\n document.getElementById('id_gradecat').disabled = disabled;\n }\n\n return {\n init: function() {\n updateTaskDisplayElemement(taskSelectionInput.value);\n },\n setSelection: function(link, language, name) {\n updateTaskUri(link, language);\n updateName(name);\n },\n setIsGraded: function(isGraded) {\n if (isGraded === null) {\n isGradedElem.value = null;\n }\n isGradedElem.value = isGraded ? '1' : '0';\n updateGradeEditability();\n },\n getGradingType: function() {\n const isGraded = isGradedElem.value;\n if (isGraded === '1') {\n return 'graded';\n } else if (isGraded === '0') {\n return 'ungraded';\n }\n return 'all';\n },\n getDelocalizedTaskLink: function() {\n return delocalizeLink(taskSelectionInput.value);\n }\n };\n })();\n\n\n const multiTaskEditController = (function() {\n const propertySelectionInputs = document.getElementsByName(\"mumie_multi_edit_property\");\n const selectedTaskProperties = document.getElementsByName(\"mumie_selected_task_properties\")[0];\n let selectedTaskProp = [];\n const taskSelectionInputs = document.getElementsByName(\"mumie_multi_edit_task\");\n const selectedTasks = document.getElementsByName(\"mumie_selected_tasks\")[0];\n let selectedTaskIds = [];\n const sectionInputs = document.getElementsByName(\"mumie_multi_edit_section\");\n\n /**\n * Push an element to an array, if it's not already included.\n *\n * @param {string[]} array\n * @param {string} element\n */\n function pushIfNotExists(array, element) {\n if (!array.includes(element)) {\n array.push(element);\n }\n }\n\n /**\n * Set selection listeners for other MUMIE Tasks in the course.\n */\n function setTaskSelectionListeners() {\n taskSelectionInputs.forEach(function(checkbox) {\n checkbox.onchange = function() {\n if (!checkbox.checked) {\n selectedTaskIds = selectedTaskIds.filter(elem => elem !== checkbox.value);\n } else {\n selectedTaskIds.push(checkbox.value);\n }\n selectedTasks.value = JSON.stringify(selectedTaskIds);\n };\n });\n }\n\n /**\n * Set selection listeners for properties to apply to MUMIE Tasks in the course.\n */\n function setPropertySelectionListeners() {\n propertySelectionInputs.forEach(function(checkbox) {\n checkbox.onchange = function() {\n if (!checkbox.checked) {\n selectedTaskProp = selectedTaskProp.filter(elem => elem !== checkbox.value);\n } else {\n selectedTaskProp.push(checkbox.value);\n }\n selectedTaskProperties.value = JSON.stringify(selectedTaskProp);\n };\n });\n }\n\n /**\n * Set selection listeners for entire section of MUMIE Tasks in the course\n */\n function setSectionSelectionListeners() {\n sectionInputs.forEach(function(sectionCheckbox) {\n sectionCheckbox.onchange = function() {\n if (!sectionCheckbox.checked) {\n taskSelectionInputs.forEach(function(taskCheckbox) {\n if (taskCheckbox.getAttribute('section') === sectionCheckbox.value) {\n taskCheckbox.checked = false;\n selectedTaskIds = selectedTaskIds.filter(elem => taskCheckbox.value !== elem);\n }\n });\n } else {\n taskSelectionInputs.forEach(function(taskCheckbox) {\n if (taskCheckbox.getAttribute('section') === sectionCheckbox.value) {\n taskCheckbox.checked = true;\n pushIfNotExists(selectedTaskIds, taskCheckbox.value);\n }\n });\n }\n selectedTasks.value = JSON.stringify(selectedTaskIds);\n };\n });\n }\n\n return {\n init: function() {\n setTaskSelectionListeners();\n setPropertySelectionListeners();\n setSectionSelectionListeners();\n },\n };\n })();\n\n const worksheetController = (function() {\n const worksheetElement = document.getElementById(\"id_mumie_worksheet\");\n return {\n setWorksheet: function(worksheet) {\n if (worksheet) {\n worksheetElement.setAttribute(\"value\", JSON.stringify(worksheet));\n } else {\n worksheetElement.removeAttribute(\"value\");\n }\n }\n };\n })();\n\n /**\n * Disable all dropdown menus and show notification\n * @param {string} errorKey\n */\n function disableDropDownMenus(errorKey) {\n require(['core/str', \"core/notification\"], function(str, notification) {\n str.get_strings([{\n 'key': errorKey,\n component: 'mod_mumie'\n }]).done(function(s) {\n notification.addNotification({\n message: s[0] + \"\" + missingConfig.getAttribute(\"value\") + \"\",\n type: \"problem\"\n });\n }).fail(notification.exception);\n });\n serverController.disable();\n problemSelectorController.disable();\n }\n\n return {\n init: function(contextIdParam, prbSelectorUrl, lang) {\n lmsSelectorUrl = prbSelectorUrl;\n systemLanguage = lang;\n contextId = contextIdParam;\n const isEdit = document.getElementById(\"id_name\").getAttribute('value');\n const serverStructure = JSON.parse(document.getElementsByName('mumie_server_structure')[0].value);\n if (isEdit && !serverConfigExists()) {\n disableDropDownMenus('mumie_form_missing_server');\n } else if (!serverStructure.length) {\n disableDropDownMenus('mumie_form_no_server_conf');\n } else {\n serverController.init(serverStructure);\n courseController.init();\n taskController.init();\n multiTaskEditController.init();\n problemSelectorController.init();\n }\n multiTaskEditController.init();\n if (addServerButton) {\n require(['auth_mumie/mumie_server_config'], function(MumieServer) {\n MumieServer.init(addServerButton, contextId);\n });\n }\n }\n };\n\n /**\n * Remove all child elements of a given html element\n * @param {Object} elem\n */\n function removeChildElems(elem) {\n while (elem.firstChild) {\n elem.removeChild(elem.firstChild);\n }\n }\n\n /**\n * Check, if the flag for an existing config is set\n * @returns {boolean}\n */\n function serverConfigExists() {\n return document.getElementsByName(\"mumie_missing_config\")[0].getAttribute(\"value\") === \"\";\n }\n });\n"],"names":["define","addServerButton","document","getElementById","missingConfig","getElementsByName","lmsSelectorUrl","systemLanguage","contextId","serverController","serverStructure","serverDropDown","init","structure","getSelectedServer","selectedServerName","options","selectedIndex","text","find","server","name","disable","disabled","elem","firstChild","removeChild","removeChildElems","problemSelectorController","problemSelectorButton","multiProblemSelectorButton","problemSelectorWindow","mumieOrg","value","sendResponse","response","postMessage","JSON","stringify","sendSuccess","message","success","addMessageListener","window","addEventListener","event","origin","importObj","parse","data","isGraded","worksheet","courseController","setCourse","path_to_coursefile","langController","setLanguage","language","taskController","setSelection","link","setIsGraded","worksheetController","setWorksheet","focus","require","str","notification","get_strings","component","done","s","addNotification","type","fail","exception","error","sendFailure","buildURL","gradingType","getGradingType","selection","getDelocalizedTaskLink","selectedServer","urlprefix","selectedServerUrl","URL","encodeURIComponent","getSelectedLanguage","location","onclick","open","onclose","e","preventDefault","courseNameElem","coursefileElem","updateCourseName","selectedCourse","getSelectedCourse","selectedLanguage","translation","_selectedCourse$name$","courses","course","coursefile","courseFile","languageElem","lang","taskSelectionInput","nameElem","taskDisplayElement","isGradedElem","updateTaskDisplayElemement","localizedLink","updateTaskUri","localizeLink","updateName","updateGradeEditability","includes","split","multiTaskEditController","propertySelectionInputs","selectedTaskProperties","selectedTaskProp","taskSelectionInputs","selectedTasks","selectedTaskIds","sectionInputs","forEach","checkbox","onchange","checked","push","filter","sectionCheckbox","taskCheckbox","array","element","getAttribute","worksheetElement","setAttribute","removeAttribute","disableDropDownMenus","errorKey","contextIdParam","prbSelectorUrl","isEdit","length","MumieServer"],"mappings":"AAAAA,4BAAO,CAAC,SAAU,iBAAkB,qBAAsB,iCAAkC,cACxF,iBACUC,gBAAkBC,SAASC,eAAe,wBAC1CC,cAAgBF,SAASG,kBAAkB,wBAAwB,OACrEC,eACAC,eACAC,gBACEC,iBAAoB,eAClBC,sBACEC,eAAiBT,SAASC,eAAe,mBAExC,CACHS,KAAM,SAASC,WACXH,gBAAkBG,WAEtBC,kBAAmB,iBACTC,mBAAqBJ,eAAeK,QAAQL,eAAeM,eAAeC,YACzER,gBAAgBS,MAAKC,QAAUA,OAAOC,OAASN,sBAE1DO,QAAS,WACLX,eAAeY,UAAW,WA+dZC,WACfA,KAAKC,YACRD,KAAKE,YAAYF,KAAKC,YAhelBE,CAAiBhB,kBAdH,GAmBpBiB,0BAA6B,iBACzBC,sBAAwB3B,SAASC,eAAe,uBAChD2B,2BAA6B5B,SAASC,eAAe,qCACvD4B,4BACEC,SAAW9B,SAASG,kBAAkB,aAAa,GAAG4B,eAQnDC,aAAaC,UACbJ,uBAGLA,sBAAsBK,YAAYC,KAAKC,UAAUH,UAAW7B,yBAOvDiC,kBAAYC,+DAAU,GAC3BN,aAAa,CACTO,SAAS,EACTD,QAASA,mBAkBRE,qBACLC,OAAOC,iBAAiB,WAAYC,oCAC5BA,MAAMC,SAAWxC,4BAGfyC,UAAYV,KAAKW,MAAMH,MAAMI,MAC7BC,UAAkC,IAAvBH,UAAUG,SACrBC,uCAAYJ,UAAUI,+DAAa,SAErCC,iBAAiBC,UAAUN,UAAUO,oBACrCC,eAAeC,YAAYT,UAAUU,UACrCC,eAAeC,aAAaZ,UAAUa,KAAMb,UAAUU,SAAUV,UAAU1B,MAC1EqC,eAAeG,YAAYX,UAC3BY,oBAAoBC,aAAaZ,WACjCZ,cACAI,OAAOqB,QAYfC,QAAQ,CAAC,WAAY,sBAAsB,SAASC,IAAKC,cACrDD,IAAIE,YAAY,CAAC,KACN,+BACPC,UAAW,eACXC,MAAK,SAASC,GACdJ,aAAaK,gBAAgB,CACzBhC,QAAS+B,EAAE,GACXE,KAAM,YAEXC,KAAKP,aAAaQ,cAnBnB,MAAOC,mBA1Bb1C,aAAa,CACTO,SAAS,EACTD,+DAHuB,KA4BnBqC,CAAYD,MAAMpC,aAErB,YAwBAsC,iBACCC,YAAcrB,eAAesB,iBAC7BC,UAAYvB,eAAewB,yBAC3BC,eAAiB1E,iBAAiBK,oBAAoBsE,cAwCtBC,yBAAAA,kBAvCMF,eAwCrC,IAAIG,IAxCiBhF,gBAwCOwC,SAAW,IAAIwC,IAAID,mBAAmBvC,QAtC9D,wCAEDd,SACA,cACAuD,mBAAmBJ,gBACnB,gBACA5B,eAAeiC,sBACf,WAAaD,mBAAmB5C,OAAO8C,SAAS3C,QAChD,gBAAkBiC,YAClB,cAAgBvE,WACfyE,UAAY,cAAgBA,UAAY,IAE5C3E,eAAAA,6BAGD0B,SACA,cACAuD,mBAAmBJ,gBACnB,gBACA5B,eAAeiC,sBACf,WAAaD,mBAAmB5C,OAAO8C,SAAS3C,QAChD,WAAavC,eACb,gBAAkBwE,YAVjBzE,oCAaA2E,UAAY,cAAgBA,UAAY,UAgB5C,CACHrE,KAAM,WACFiB,sBAAsB6D,QAAU,WAC5B3D,sBAAwBY,OAAOgD,KAAKb,WAAY,WAGpDnC,OAAOiD,QAAU,WACbrD,eAGJI,OAAOC,iBAAiB,gBAAgB,WACpCL,iBACA,GAEJG,qBAEAZ,2BAA2B4D,QAAU,SAASG,GAC1CA,EAAEC,iBACF/D,sBAAwBY,OAAOgD,KAC7BrF,eAAAA,mCAGEiF,mBAAmB9E,iBAAiBK,oBAAoBsE,WACxD,mBACF,SACA,oCAIV9D,QAAS,WACLO,sBAAsBN,UAAW,IArKV,GA0K7B6B,iBAAoB,iBAChB2C,eAAiB7F,SAASC,eAAe,mBACzC6F,eAAiB9F,SAASG,kBAAkB,oBAAoB,YAgB7D4F,mDACCC,eAAiB9C,iBAAiB+C,oBAClCC,iBAAmB7C,eAAeiC,sBACnCU,gBAAmBE,mBAGxBL,eAAe9D,oCAAQiE,eAAe7E,KACjCF,MAAKkF,aAAeA,YAAY5C,WAAa2C,2DAD3BE,sBAC8CrE,aAGlE,CACHrB,KAAM,WACFqF,oBAEJE,kBAAmB,kBACC1F,iBAAiBK,oBAAoByF,QACtCpF,MAAKqF,QAAUA,OAAOC,aAAeT,eAAe/D,SAEvEoB,UAAW,SAASqD,gBA1BMD,WAAAA,WA2BDC,WA1BzBV,eAAe/D,MAAQwE,WACvBR,qBAZkB,GA0CpB1C,eAAkB,iBACdoD,aAAezG,SAASC,eAAe,qBACtC,CACHqF,oBAAqB,kBACVmB,aAAa1E,OAExBuB,YAAa,SAASoD,MAClBD,aAAa1E,MAAQ2E,OAPT,GAYlBlD,eAAkB,iBACdmD,mBAAqB3G,SAASG,kBAAkB,WAAW,GAC3DyG,SAAW5G,SAASC,eAAe,WACnC4G,mBAAqB7G,SAASC,eAAe,2BAC7C6G,aAAe9G,SAASC,eAAe,8BAcpC8G,2BAA2BC,eAChCH,mBAAmB9E,MAAQiF,uBAQtBC,cAAcvD,KAAMH,gBACnByD,uBAWYtD,KAAMH,iBACjBG,KAnCuB,SAmCYH,SAZpB2D,CAAaxD,KAAMH,UACzCoD,mBAAmB5E,MAAQiF,cAC3BD,2BAA2BC,qBAoCxB,CACHtG,KAAM,WACFqG,2BAA2BJ,mBAAmB5E,QAElD0B,aAAc,SAASC,KAAMH,SAAUpC,MACnC8F,cAAcvD,KAAMH,mBA5DRpC,MAChByF,SAAS7E,MAAQZ,KA4DbgG,CAAWhG,OAEfwC,YAAa,SAASX,UACD,OAAbA,WACA8D,aAAa/E,MAAQ,MAEzB+E,aAAa/E,MAAQiB,SAAW,IAAM,qBAnBpC3B,SAAkC,MAAvByF,aAAa/E,MAC9B/B,SAASC,eAAe,aAAaoB,SAAWA,SAChDrB,SAASC,eAAe,gBAAgBoB,SAAWA,SACnDrB,SAASC,eAAe,sBAAsBoB,SAAWA,SACzDrB,SAASC,eAAe,eAAeoB,SAAWA,SAgB9C+F,IAEJtC,eAAgB,iBACN9B,SAAW8D,aAAa/E,YACb,MAAbiB,SACO,SACa,MAAbA,SACA,WAEJ,OAEXgC,uBAAwB,kBA1CJtB,KA2CMiD,mBAAmB5E,OA1CpCsF,SA5CqB,UA6CnB3D,KAAK4D,MA7Cc,UA6CmB,GAE1C5D,SAJaA,OAhDJ,GAiGlB6D,wBAA2B,iBACvBC,wBAA0BxH,SAASG,kBAAkB,6BACrDsH,uBAAyBzH,SAASG,kBAAkB,kCAAkC,OACxFuH,iBAAmB,SACjBC,oBAAsB3H,SAASG,kBAAkB,yBACjDyH,cAAgB5H,SAASG,kBAAkB,wBAAwB,OACrE0H,gBAAkB,SAChBC,cAAgB9H,SAASG,kBAAkB,kCAwE1C,CACHO,KAAM,WAvDNiH,oBAAoBI,SAAQ,SAASC,UACjCA,SAASC,SAAW,WACXD,SAASE,QAGVL,gBAAgBM,KAAKH,SAASjG,OAF9B8F,gBAAkBA,gBAAgBO,QAAO9G,MAAQA,OAAS0G,SAASjG,QAIvE6F,cAAc7F,MAAQI,KAAKC,UAAUyF,qBAS7CL,wBAAwBO,SAAQ,SAASC,UACrCA,SAASC,SAAW,WACXD,SAASE,QAGVR,iBAAiBS,KAAKH,SAASjG,OAF/B2F,iBAAmBA,iBAAiBU,QAAO9G,MAAQA,OAAS0G,SAASjG,QAIzE0F,uBAAuB1F,MAAQI,KAAKC,UAAUsF,sBAStDI,cAAcC,SAAQ,SAASM,iBAC3BA,gBAAgBJ,SAAW,WAClBI,gBAAgBH,QAQjBP,oBAAoBI,SAAQ,SAASO,kBApD5BC,MAAOC,QAqDRF,aAAaG,aAAa,aAAeJ,gBAAgBtG,QACzDuG,aAAaJ,SAAU,EAtDtBK,MAuDeV,gBAvDRW,QAuDyBF,aAAavG,MAtD7DwG,MAAMlB,SAASmB,UAChBD,MAAMJ,KAAKK,aA2CHb,oBAAoBI,SAAQ,SAASO,cAC7BA,aAAaG,aAAa,aAAeJ,gBAAgBtG,QACzDuG,aAAaJ,SAAU,EACvBL,gBAAkBA,gBAAgBO,QAAO9G,MAAQgH,aAAavG,QAAUT,WAWpFsG,cAAc7F,MAAQI,KAAKC,UAAUyF,uBA1EpB,GAwF3BjE,oBAAuB,iBACnB8E,iBAAmB1I,SAASC,eAAe,4BAC1C,CACH4D,aAAc,SAASZ,WACfA,UACAyF,iBAAiBC,aAAa,QAASxG,KAAKC,UAAUa,YAEtDyF,iBAAiBE,gBAAgB,WAPpB,YAiBpBC,qBAAqBC,UAC1B/E,QAAQ,CAAC,WAAY,sBAAsB,SAASC,IAAKC,cACrDD,IAAIE,YAAY,CAAC,KACL4E,SACR3E,UAAW,eACXC,MAAK,SAASC,GACdJ,aAAaK,gBAAgB,CACzBhC,QAAS+B,EAAE,GAAK,MAAQnE,cAAcuI,aAAa,SAAW,OAC9DlE,KAAM,eAEXC,KAAKP,aAAaQ,cAEzBlE,iBAAiBa,UACjBM,0BAA0BN,gBAGvB,CACHV,KAAM,SAASqI,eAAgBC,eAAgBtC,MAC3CtG,eAAiB4I,eACjB3I,eAAiBqG,KACjBpG,UAAYyI,qBACNE,OAASjJ,SAASC,eAAe,WAAWwI,aAAa,SACzDjI,gBAAkB2B,KAAKW,MAAM9C,SAASG,kBAAkB,0BAA0B,GAAG4B,OACvFkH,QAmC+E,KAAhFjJ,SAASG,kBAAkB,wBAAwB,GAAGsI,aAAa,SAlClEI,qBAAqB,6BACbrI,gBAAgB0I,QAGxB3I,iBAAiBG,KAAKF,iBACtB0C,iBAAiBxC,OACjB8C,eAAe9C,OACf6G,wBAAwB7G,OACxBgB,0BAA0BhB,QAN1BmI,qBAAqB,6BAQzBtB,wBAAwB7G,OACpBX,iBACAgE,QAAQ,CAAC,mCAAmC,SAASoF,aACjDA,YAAYzI,KAAKX,gBAAiBO"}
\ No newline at end of file
diff --git a/amd/src/mod_form.js b/amd/src/mod_form.js
index f086fbe..e07c5f3 100644
--- a/amd/src/mod_form.js
+++ b/amd/src/mod_form.js
@@ -4,6 +4,7 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
const missingConfig = document.getElementsByName("mumie_missing_config")[0];
let lmsSelectorUrl;
let systemLanguage;
+ let contextId;
const serverController = (function() {
let serverStructure;
const serverDropDown = document.getElementById("id_server");
@@ -107,26 +108,61 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
});
}
+ /**
+ * Builds the URL to the Problem Selector
+ * @returns {string} URL to the Problem Selector
+ */
+ function buildURL() {
+ const gradingType = taskController.getGradingType();
+ const selection = taskController.getDelocalizedTaskLink();
+ const selectedServer = serverController.getSelectedServer().urlprefix;
+ const useSSO = shouldUseSSO(lmsSelectorUrl, selectedServer);
+ if (useSSO) {
+ return '/auth/mumie/problem_selector.php?'
+ + 'org='
+ + mumieOrg
+ + '&serverurl='
+ + encodeURIComponent(selectedServer)
+ + '&problemlang='
+ + langController.getSelectedLanguage()
+ + '&origin=' + encodeURIComponent(window.location.origin)
+ + '&gradingtype=' + gradingType
+ + '&contextid=' + contextId
+ + (selection ? '&selection=' + selection : '');
+ }
+ return lmsSelectorUrl
+ + '/lms-problem-selector?'
+ + 'org='
+ + mumieOrg
+ + '&serverUrl='
+ + encodeURIComponent(selectedServer)
+ + '&problemLang='
+ + langController.getSelectedLanguage()
+ + '&origin=' + encodeURIComponent(window.location.origin)
+ + '&uiLang=' + systemLanguage
+ + '&gradingType=' + gradingType
+ + '&multiCourse=true'
+ + '&worksheet=true'
+ + (selection ? '&selection=' + selection : '');
+ }
+
+ /**
+ * Determines whether the Single Sign-On (SSO) should be used when opening the Problem Selector.
+ * SSO is only supposed to be used when the Problem Selector URL has the same origin as the
+ * URL of the selected MUMIE server.
+ *
+ * @param {string} problemSelectorUrl - The URL of the problem selector.
+ * @param {string} selectedServerUrl - The URL of the selected MUMIE server
+ * @returns {boolean} Whether SSO should be used for the Problem Selector or not
+ */
+ function shouldUseSSO(problemSelectorUrl, selectedServerUrl) {
+ return new URL(problemSelectorUrl).origin === new URL(selectedServerUrl).origin;
+ }
+
return {
init: function() {
- const gradingType = taskController.getGradingType();
problemSelectorButton.onclick = function() {
- problemSelectorWindow = window.open(
- lmsSelectorUrl
- + '/lms-problem-selector?'
- + 'org='
- + mumieOrg
- + '&serverUrl='
- + encodeURIComponent(serverController.getSelectedServer().urlprefix)
- + '&problemLang='
- + langController.getSelectedLanguage()
- + '&origin=' + encodeURIComponent(window.location.origin)
- + '&uiLang=' + systemLanguage
- + '&gradingType=' + gradingType
- + '&multiCourse=true'
- + '&worksheet=true'
- , '_blank'
- );
+ problemSelectorWindow = window.open(buildURL(), '_blank');
};
window.onclose = function() {
@@ -217,7 +253,7 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
const nameElem = document.getElementById("id_name");
const taskDisplayElement = document.getElementById("id_task_display_element");
const isGradedElem = document.getElementById('id_mumie_isgraded');
-
+ const LANG_REQUEST_PARAM_PREFIX = "?lang=";
/**
* Update the activity's name in the input field
@@ -240,11 +276,33 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
* @param {string} language
*/
function updateTaskUri(link, language) {
- const localizedLink = link + "?lang=" + language;
+ const localizedLink = localizeLink(link, language);
taskSelectionInput.value = localizedLink;
updateTaskDisplayElemement(localizedLink);
}
+ /**
+ * Add lang request param to link
+ * @param {string} link
+ * @param {string} language
+ * @returns {string} Link with lang request param
+ */
+ function localizeLink(link, language) {
+ return link + LANG_REQUEST_PARAM_PREFIX + language;
+ }
+
+ /**
+ * Remove lang request param from link
+ * @param {string} link Link that may have lang request param
+ * @returns {string} Link without lang request param
+ */
+ function delocalizeLink(link) {
+ if (link.includes(LANG_REQUEST_PARAM_PREFIX)) {
+ return link.split(LANG_REQUEST_PARAM_PREFIX)[0];
+ }
+ return link;
+ }
+
/**
* Form inputs related to grades should be disabled, if the MUMIE Task is not graded.
*/
@@ -279,6 +337,9 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
return 'ungraded';
}
return 'all';
+ },
+ getDelocalizedTaskLink: function() {
+ return delocalizeLink(taskSelectionInput.value);
}
};
})();
@@ -406,9 +467,10 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
}
return {
- init: function(contextid, prbSelectorUrl, lang) {
+ init: function(contextIdParam, prbSelectorUrl, lang) {
lmsSelectorUrl = prbSelectorUrl;
systemLanguage = lang;
+ contextId = contextIdParam;
const isEdit = document.getElementById("id_name").getAttribute('value');
const serverStructure = JSON.parse(document.getElementsByName('mumie_server_structure')[0].value);
if (isEdit && !serverConfigExists()) {
@@ -425,7 +487,7 @@ define(['jquery', 'core/templates', 'core/modal_factory', 'auth_mumie/mumie_serv
multiTaskEditController.init();
if (addServerButton) {
require(['auth_mumie/mumie_server_config'], function(MumieServer) {
- MumieServer.init(addServerButton, contextid);
+ MumieServer.init(addServerButton, contextId);
});
}
}
diff --git a/classes/mumie_participants.php b/classes/mumie_participants.php
index 5a427a2..f14d184 100644
--- a/classes/mumie_participants.php
+++ b/classes/mumie_participants.php
@@ -278,12 +278,12 @@ function ($searchparam) {
}
/**
- * Check if a given string contains an property the participants list cannot be sorted by.
+ * Check if a given string contains a property the participants list cannot be sorted by.
*
* @param string $searchparam the search term we are checking
* @return bool
*/
private function is_unsortable_column_header($searchparam) {
- return strpos($searchparam, 'duedate') !== false || strpos($searchparam, 'submissions') !== false;
+ return $searchparam === null || strpos($searchparam, 'duedate') !== false || strpos($searchparam, 'submissions') !== false;
}
}