\ No newline at end of file
diff --git a/Modules/Scorm2004/Editor/templates/default/tpl.question_overview_row.html b/Modules/Scorm2004/Editor/templates/default/tpl.question_overview_row.html
new file mode 100644
index 000000000000..6af6942df2c5
--- /dev/null
+++ b/Modules/Scorm2004/Editor/templates/default/tpl.question_overview_row.html
@@ -0,0 +1,8 @@
+
+
+ {PAGE}
+
+
+ {QUESTION}
+
+
\ No newline at end of file
diff --git a/Modules/Scorm2004/classes/class.ilSCORM2004ScoGUI.php b/Modules/Scorm2004/classes/class.ilSCORM2004ScoGUI.php
index e4f592cd5da7..43492434c4f5 100755
--- a/Modules/Scorm2004/classes/class.ilSCORM2004ScoGUI.php
+++ b/Modules/Scorm2004/classes/class.ilSCORM2004ScoGUI.php
@@ -239,60 +239,30 @@ public function updateProperties()
public function sahs_questions()
{
- $tpl = $this->tpl;
- $lng = $this->lng;
- $ilCtrl = $this->ctrl;
-
$this->setTabs();
$this->setLocator();
- include_once "./Services/Table/classes/class.ilTableGUI.php";
- include_once "./Modules/Scorm2004/classes/class.ilSCORM2004Page.php";
- include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
- include_once("./Services/COPage/classes/class.ilPCQuestionGUI.php");
-
- // load template for table
- $tpl->addBlockfile("ADM_CONTENT", "adm_content", "tpl.table.html");
- $tpl->addBlockfile("TBL_CONTENT", "tbl_content", "tpl.scormeditor_sco_question.html", "Modules/Scorm2004");
-
- $tbl = new ilTableGUI();
- $tbl->setTitle("Questions for " . $this->node_object->getTitle());
- $tbl->setHeaderNames(array("Question","Page"));
- $cols = array("question","page");
- // $tbl->setHeaderVars($cols, $header_params);
- $tbl->setHeaderVars($cols, 0);
- $tbl->setColumnWidth(array("50%", "50%"));
- $tbl->disable("sort");
- $tbl->disable("footer");
-
$tree = new ilTree($this->slm_object->getId());
$tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
$tree->setTreeTablePK("slm_id");
- $i = 0;
-
+ $questions = [];
foreach ($tree->getSubTree($tree->getNodeData($this->node_object->getId()), true, 'page') as $page) {
// get question ids
- include_once("./Services/COPage/classes/class.ilPCQuestion.php");
$qids = ilPCQuestion::_getQuestionIdsForPage("sahs", $page["obj_id"]);
if (count($qids) > 0) {
// output questions
foreach ($qids as $qid) {
- $tpl->setCurrentBlock("tbl_content");
- $tpl->setVariable("TXT_PAGE_TITLE", $page["title"]);
- $ilCtrl->setParameterByClass("ilscorm2004pagenodegui", "obj_id", $page["obj_id"]);
- $tpl->setVariable("HREF_EDIT_PAGE", $ilCtrl->getLinkTargetByClass("ilscorm2004pagenodegui", "edit"));
-
- $qtitle = assQuestion::_getTitle($qid);
- $tpl->setVariable("TXT_QUESTION", $qtitle);
- $ilCtrl->setParameterByClass("ilscorm2004pagenodegui", "obj_id", $page["obj_id"]);
- //$tpl->setVariable("HREF_EDIT_QUESTION", $ilCtrl->getLinkTargetByClass("ilscorm2004pagenodegui", "edit"));
-
- $tpl->setVariable("CSS_ROW", ilUtil::switchColor($i++, "tblrow1", "tblrow2"));
- $tpl->parseCurrentBlock();
+ $questions[] = [
+ "page" => $page,
+ "qid" => $qid
+ ];
}
}
}
- $tbl->render();
+
+ $tab = new ILIAS\Scorm2004\Editor\ilSCORMQuestionOverviewTableGUI($this, "sahs_questions");
+ $tab->setData($questions);
+ $this->tpl->setContent($tab->getHTML());
}
public function getEditTree()
@@ -769,110 +739,14 @@ public function getExportResources()
public function sco_resources()
{
- $tpl = $this->tpl;
- $lng = $this->lng;
- $ilCtrl = $this->ctrl;
-
$this->setTabs();
$this->setLocator();
- $i = 0;
-
$export_files = $this->getExportResources();
- // create table
- require_once("./Services/Table/classes/class.ilTableGUI.php");
- $tbl = new ilTableGUI();
-
- // load files templates
- $tpl->addBlockfile("ADM_CONTENT", "adm_content", "tpl.table.html");
-
- // load template for table content data
- $tpl->addBlockfile("TBL_CONTENT", "tbl_content", "tpl.download_file_row.html", "Modules/LearningModule");
-
- $num = 0;
+ $tab = new \ILIAS\Scorm2004\Editor\ilSCORMMediaOverviewTableGUI($this, "sco_resources");
+ $tab->setData($export_files);
- $tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
-
- $tbl->setTitle($lng->txt("cont_files"));
-
- $tbl->setHeaderNames(array($lng->txt("cont_format"),
- $lng->txt("cont_file"),
- $lng->txt("size"), $lng->txt("date"),
- ""));
-
- $cols = array("format", "file", "size", "date", "download");
- $header_params = array("ref_id" => $_GET["ref_id"], "obj_id" => $_GET["obj_id"],
- "cmd" => "sco_resources", "cmdClass" => strtolower(get_class($this)),
- "cmdNode" => $_GET["cmdNode"], "baseClass" => $_GET["baseClass"]);
- $tbl->setHeaderVars($cols, $header_params);
- $tbl->setColumnWidth(array("10%", "30%", "20%", "20%","20%"));
- $tbl->disable("sort");
-
- $tbl->setOrderColumn($_GET["sort_by"]);
- $tbl->setOrderDirection($_GET["sort_order"]);
- $tbl->setLimit($_GET["limit"]);
- $tbl->setOffset($_GET["offset"]);
- $tbl->setMaxCount($this->maxcount); // ???
-
-
- $tbl->setMaxCount(count($export_files));
-
- // footer
- $tbl->setFooter("tblfooter", $lng->txt("previous"), $lng->txt("next"));
- //$tbl->disable("footer");
-
- $tbl->setMaxCount(count($export_files));
- $export_files = array_slice($export_files, $_GET["offset"], $_GET["limit"]);
-
- $tbl->render();
- if (count($export_files) > 0) {
- $i = 0;
- foreach ($export_files as $exp_file) {
- /* remote files (youtube videos) have no size, so we allow them now
- if (!$exp_file["size"] > 0)
- {
- continue;
- }
- */
-
- $tpl->setCurrentBlock("tbl_content");
- $tpl->setVariable("TXT_FILENAME", $exp_file["file"]);
-
- $css_row = ilUtil::switchColor($i++, "tblrow1", "tblrow2");
- $tpl->setVariable("CSS_ROW", $css_row);
-
- $tpl->setVariable("TXT_SIZE", $exp_file["size"]);
- $tpl->setVariable("TXT_FORMAT", $exp_file["type"]);
-
- $tpl->setVariable("TXT_DATE", $exp_file["date"]);
-
- if ($exp_file["size"] > 0) {
- $tpl->setVariable("TXT_DOWNLOAD", $lng->txt("download"));
- $ilCtrl->setParameter($this, "resource", rawurlencode($exp_file["path"]));
- $ilCtrl->setParameter($this, "file_id", rawurlencode($exp_file["file_id"]));
- $tpl->setVariable(
- "LINK_DOWNLOAD",
- $ilCtrl->getLinkTarget($this, "downloadResource")
- );
- } else {
- $tpl->setVariable("TXT_DOWNLOAD", $lng->txt("show"));
- $tpl->setVariable("LINK_TARGET", " target=\"_blank\"");
- $tpl->setVariable("LINK_DOWNLOAD", $exp_file["path"]);
- }
-
- $tpl->parseCurrentBlock();
- }
- } //if is_array
- /* not found in template?
- else
- {
- $tpl->setCurrentBlock("notfound");
- $tpl->setVariable("TXT_OBJECT_NOT_FOUND", $lng->txt("obj_not_found"));
- $tpl->setVariable("NUM_COLS", 4);
- $tpl->parseCurrentBlock();
- }
- */
- // $tpl->parseCurrentBlock();
+ $this->tpl->setContent($tab->getHTML());
}
public function downloadResource()
diff --git a/Modules/Scorm2004/scripts/buildrte/rte-min.js b/Modules/Scorm2004/scripts/buildrte/rte-min.js
index f64ddbe5784a..0ffa362781f2 100644
--- a/Modules/Scorm2004/scripts/buildrte/rte-min.js
+++ b/Modules/Scorm2004/scripts/buildrte/rte-min.js
@@ -1,4 +1,4 @@
-// Build: 2018118230830
+// Build: 2021217191655
function ADLAuxiliaryResource()
{}
@@ -2591,8 +2591,12 @@ if(async)
{xhttp.onreadystatechange=onStateChange;xhttp.send(data?String(data):'');}else
{xhttp.send(data?String(data):'');return onStateChange();}}
function sendJSONRequest(url,data,callback,user,password,headers)
-{if(typeof headers!=="object"){headers={};}
-headers['Accept']='text/javascript';headers['Accept-Charset']='UTF-8';var r=sendAndLoad(url,toJSONString(data),callback,user,password,headers);if(r.content){if(r.content.indexOf("login.php")>-1||r.content.indexOf("formlogin")>-1){var thref=window.location.href;thref=thref.substring(0,thref.indexOf('ilias.php'))+"Modules/Scorm2004/templates/default/session_timeout.html";window.location.href=thref;}}
+{function unloadChrome(){if(navigator.userAgent.indexOf("Chrom")>-1){if(typeof(document.getElementById("res"))!="undefined"&&typeof(document.getElementById("res").contentWindow)!="undefined"&&typeof(document.getElementById("res").contentWindow.event)!="undefined"&&(document.getElementById("res").contentWindow.event.type=="unload"||document.getElementById("res").contentWindow.event.type=="beforeunload")){return true;}}
+return false;}
+if(typeof headers!=="object"){headers={};}
+headers['Accept']='text/javascript';headers['Accept-Charset']='UTF-8';if(url==this.config.store_url&&unloadChrome()){var r=sendAndLoad(url,toJSONString(data),true,user,password,headers);console.log("async request for chrome");return"1";}
+if(url==this.config.scorm_player_unload_url&&navigator.userAgent.indexOf("Chrom")>-1){navigator.sendBeacon(url,toJSONString(data));return"1";}
+var r=sendAndLoad(url,toJSONString(data),callback,user,password,headers);if(r.content){if(r.content.indexOf("login.php")>-1||r.content.indexOf("formlogin")>-1){var thref=window.location.href;thref=thref.substring(0,thref.indexOf('ilias.php'))+"Modules/Scorm2004/templates/default/session_timeout.html";window.location.href=thref;}}
if((r.status===200&&(/^text\/javascript;?.*/i).test(r.type))||r.status===0)
{return parseJSONString(r.content);}
else
@@ -2643,6 +2647,7 @@ var userInteraction=false;function launchTarget(target,isJump){if(userInteractio
onItemUndeliver();mlaunch=msequencer.navigateStr(target,isJump);if(mlaunch.mSeqNonContent==null){onItemDeliver(activities[mlaunch.mActivityID]);}else{loadPage(gConfig.specialpage_url+"&page="+mlaunch.mSeqNonContent);}}
function launchNavType(navType,isUserCurrentlyInteracting){if(!isUserCurrentlyInteracting&&userInteraction){userInteraction=false;return null;}
if(navType=='SuspendAll'){err=currentAPI.SetValueIntern("cmi.exit","suspend");activities[msequencer.mSeqTree.mCurActivity.mActivityID].exit="suspend";}
+if(navType==='ExitAll'||navType==='Exit'||navType==='SuspendAll'){onWindowUnload();}
onItemUndeliver();mlaunch=new ADLLaunch();if(navType==='Start'){mlaunch=msequencer.navigate(NAV_START);}
if(navType==='ResumeAll'){mlaunch=msequencer.navigate(NAV_RESUMEALL);}
if(navType==='Exit'){mlaunch=msequencer.navigate(NAV_EXIT);}
@@ -2960,7 +2965,7 @@ if(mObjStatus.mHasProgressMeasure)
obj="cmi.objectives."+idx+".completion_status";err=currentAPI.SetValueIntern(obj,mObjStatus.mCompletionStatus);}}}}
function syncCMIADLTree(){var mPRIMARY_OBJ_ID=null;var masteryStatus=null;var sessionTime=null;var entry=null;var normalScore=-1.0;var progressMeasure=null;var completionStatus=null;var SCOEntry=null;var suspended=false;SCOEntry=currentAPI.GetValueIntern("cmi.exit");completionStatus=currentAPI.GetValueIntern("cmi.completion_status");var completionSetBySCO=currentAPI.GetValueIntern("cmi.completion_status_SetBySco");if(completionStatus=="not attempted")completionStatus="incomplete";progressMeasure=currentAPI.GetValueIntern("cmi.progress_measure");if(progressMeasure==""||progressMeasure=="unknown")
{progressMeasure=null;}
-masteryStatus=currentAPI.GetValueIntern("cmi.success_status");var masterySetBySCO=currentAPI.GetValueIntern("cmi.success_status_SetBySco");SCOEntry=currentAPI.GetValueIntern("cmi.entry");score=currentAPI.GetValueIntern("cmi.score.scaled");sessionTime=currentAPI.GetValueIntern("cmi.session_time");var act=msequencer.mSeqTree.getActivity(mlaunch.mActivityID);if(act.getIsTracked())
+masteryStatus=currentAPI.GetValueIntern("cmi.success_status");var masterySetBySCO=currentAPI.GetValueIntern("cmi.success_status_SetBySco");SCOEntry=currentAPI.GetValueIntern("cmi.entry");score=currentAPI.GetValueIntern("cmi.score.scaled");sessionTime=currentAPI.GetValueIntern("cmi.session_time");var act=msequencer.mSeqTree.getActivity(mlaunch.mActivityID);if(act&&act.getIsTracked())
{var primaryObjID=null;var foundPrimaryObj=false;var setPrimaryObjSuccess=false;var setPrimaryObjScore=false;objs=act.getObjectives();if(objs!=null){for(var j=0;j -1) {
+ if (typeof(document.getElementById("res")) != "undefined"
+ && typeof(document.getElementById("res").contentWindow) != "undefined"
+ && typeof(document.getElementById("res").contentWindow.event) != "undefined"
+ && (document.getElementById("res").contentWindow.event.type=="unload" || document.getElementById("res").contentWindow.event.type=="beforeunload")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
if (typeof headers !== "object") {headers = {};}
headers['Accept'] = 'text/javascript';
headers['Accept-Charset'] = 'UTF-8';
+ if (url == this.config.store_url && unloadChrome()) {
+ var r = sendAndLoad(url, toJSONString(data), true, user, password, headers);
+ console.log("async request for chrome");
+ // navigator.sendBeacon(url, toJSONString(data));
+ // console.log('use sendBeacon');
+ return "1";
+ }
+ if (url == this.config.scorm_player_unload_url && navigator.userAgent.indexOf("Chrom") > -1) {
+ navigator.sendBeacon(url, toJSONString(data));
+ return "1";
+ }
+
var r = sendAndLoad(url, toJSONString(data), callback, user, password, headers);
if (r.content) {
@@ -12362,7 +12386,10 @@ function launchNavType(navType, isUserCurrentlyInteracting) {
//sync
activities[msequencer.mSeqTree.mCurActivity.mActivityID].exit="suspend";
}
-
+ if (navType==='ExitAll' || navType==='Exit' || navType==='SuspendAll') {
+ onWindowUnload();
+ }
+
//throw away API from previous sco and sync CMI and ADLTree, no api...SCO has to care for termination
onItemUndeliver();
@@ -14181,7 +14208,7 @@ function syncCMIADLTree(){
//get current activity
var act = msequencer.mSeqTree.getActivity(mlaunch.mActivityID);
- if (act.getIsTracked())
+ if (act && act.getIsTracked())
{
//alert("main.syncCMIADLTree:\nactivityid: " + mlaunch.mActivityID);
var primaryObjID = null;
@@ -14582,7 +14609,7 @@ function updateNav(ignore) {
var disable=true;
var disabled_str = "";
var test=null;
- if (mlaunch.mNavState.mChoice!=null) {
+ if (mlaunch.mNavState && typeof(mlaunch.mNavState.mChoice)!="undefined" && mlaunch.mNavState.mChoice!=null) {
test=mlaunch.mNavState.mChoice[i];
}
if (test) {
diff --git a/Modules/Scorm2004/scripts/rtemain/main.js b/Modules/Scorm2004/scripts/rtemain/main.js
index 233adbce23f6..70550db73389 100644
--- a/Modules/Scorm2004/scripts/rtemain/main.js
+++ b/Modules/Scorm2004/scripts/rtemain/main.js
@@ -1353,10 +1353,34 @@ function sendAndLoad(url, data, callback, user, password, headers)
}
function sendJSONRequest (url, data, callback, user, password, headers)
-{
+{
+ function unloadChrome() {
+ if (navigator.userAgent.indexOf("Chrom") > -1) {
+ if (typeof(document.getElementById("res")) != "undefined"
+ && typeof(document.getElementById("res").contentWindow) != "undefined"
+ && typeof(document.getElementById("res").contentWindow.event) != "undefined"
+ && (document.getElementById("res").contentWindow.event.type=="unload" || document.getElementById("res").contentWindow.event.type=="beforeunload")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
if (typeof headers !== "object") {headers = {};}
headers['Accept'] = 'text/javascript';
headers['Accept-Charset'] = 'UTF-8';
+ if (url == this.config.store_url && unloadChrome()) {
+ var r = sendAndLoad(url, toJSONString(data), true, user, password, headers);
+ console.log("async request for chrome");
+ // navigator.sendBeacon(url, toJSONString(data));
+ // console.log('use sendBeacon');
+ return "1";
+ }
+ if (url == this.config.scorm_player_unload_url && navigator.userAgent.indexOf("Chrom") > -1) {
+ navigator.sendBeacon(url, toJSONString(data));
+ return "1";
+ }
+
var r = sendAndLoad(url, toJSONString(data), callback, user, password, headers);
if (r.content) {
@@ -1577,7 +1601,10 @@ function launchNavType(navType, isUserCurrentlyInteracting) {
//sync
activities[msequencer.mSeqTree.mCurActivity.mActivityID].exit="suspend";
}
-
+ if (navType==='ExitAll' || navType==='Exit' || navType==='SuspendAll') {
+ onWindowUnload();
+ }
+
//throw away API from previous sco and sync CMI and ADLTree, no api...SCO has to care for termination
onItemUndeliver();
@@ -3396,7 +3423,7 @@ function syncCMIADLTree(){
//get current activity
var act = msequencer.mSeqTree.getActivity(mlaunch.mActivityID);
- if (act.getIsTracked())
+ if (act && act.getIsTracked())
{
//alert("main.syncCMIADLTree:\nactivityid: " + mlaunch.mActivityID);
var primaryObjID = null;
@@ -3797,7 +3824,7 @@ function updateNav(ignore) {
var disable=true;
var disabled_str = "";
var test=null;
- if (mlaunch.mNavState.mChoice!=null) {
+ if (mlaunch.mNavState && typeof(mlaunch.mNavState.mChoice)!="undefined" && mlaunch.mNavState.mChoice!=null) {
test=mlaunch.mNavState.mChoice[i];
}
if (test) {
diff --git a/Modules/ScormAicc/classes/SCORM/class.ilObjSCORMTracking.php b/Modules/ScormAicc/classes/SCORM/class.ilObjSCORMTracking.php
index 5a34e28481b9..1993a75a6088 100755
--- a/Modules/ScormAicc/classes/SCORM/class.ilObjSCORMTracking.php
+++ b/Modules/ScormAicc/classes/SCORM/class.ilObjSCORMTracking.php
@@ -277,8 +277,6 @@ public static function syncGlobalStatus($userId, $packageId, $data, $new_global_
$saved_global_status = $data->saved_global_status;
$ilLog->write("saved_global_status=" . $saved_global_status);
- //last_visited!
-
// get attempts
if (!$data->packageAttempts) {
$val_set = $ilDB->queryF(
@@ -299,9 +297,9 @@ public static function syncGlobalStatus($userId, $packageId, $data, $new_global_
$totalTime = (int) $data->totalTimeCentisec;
$totalTime = round($totalTime / 100);
$ilDB->queryF(
- 'UPDATE sahs_user SET sco_total_time_sec=%s, status=%s, percentage_completed=%s, package_attempts=%s WHERE obj_id = %s AND user_id = %s',
- array('integer', 'integer', 'integer', 'integer', 'integer', 'integer'),
- array($totalTime, $new_global_status, $data->percentageCompleted, $attempts, $packageId, $userId)
+ 'UPDATE sahs_user SET last_visited=%s, last_access = %s, sco_total_time_sec=%s, status=%s, percentage_completed=%s, package_attempts=%s WHERE obj_id = %s AND user_id = %s',
+ array('text', 'timestamp', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer'),
+ array($data->last_visited, date('Y-m-d H:i:s'), $totalTime, $new_global_status, $data->percentageCompleted, $attempts, $packageId, $userId)
);
// self::ensureObjectDataCacheExistence();
diff --git a/Modules/ScormAicc/scripts/basisAPI.js b/Modules/ScormAicc/scripts/basisAPI.js
index e3b0928bd0d1..e7e7f81eeb52 100644
--- a/Modules/ScormAicc/scripts/basisAPI.js
+++ b/Modules/ScormAicc/scripts/basisAPI.js
@@ -77,12 +77,9 @@ function sendRequest (url, data, callback, user, password, headers) {
}
function useSendBeacon() {
- if (navigator.userAgent.indexOf("Chrome") > -1) {
+ if (navigator.userAgent.indexOf("Chrom") > -1) {
if (typeof(window.sahs_content) != "undefined" && typeof(window.sahs_content.event) != "undefined" && (window.sahs_content.event.type=="unload" || window.sahs_content.event.type=="beforeunload")) {
- var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
- var version = raw ? parseInt(raw[2], 10) : false;
- if (version === false) return false;
- if (version >= 80) return true;
+ return true;
}
}
return false;
@@ -316,6 +313,8 @@ function IliasCommit() {
}
var s_s="",a_tmp,s_v,a_cmiTmp,i_numCompleted=0,b_statusFailed=false;
var LP_STATUS_IN_PROGRESS_NUM=1, LP_STATUS_COMPLETED_NUM=2,LP_STATUS_FAILED_NUM=3;
+ $last_visited = "";
+ if (iv.b_autoLastVisited==true) $last_visited = iv.launchId;
var o_data={
"cmi":[],
"saved_global_status":iv.status.saved_global_status,
@@ -324,7 +323,8 @@ function IliasCommit() {
"lp_mode":iv.status.lp_mode,
"hash":iv.status.hash,
"p":iv.status.p,
- "totalTimeCentisec":0
+ "totalTimeCentisec":0,
+ "last_visited":$last_visited
};
for (var i=0; isetDisabledObjectTypes(array("itgr", "sess"));
+ $gui->setDisabledObjectTypes(
+ array_merge(
+ [
+ 'itgr', 'sess'
+ ],
+ $objDefinition->getSideBlockTypes()
+ )
+ );
$gui->setAfterCreationCallback($this->ref_id);
$gui->render();
diff --git a/Modules/StudyProgramme/classes/class.ilObjStudyProgramme.php b/Modules/StudyProgramme/classes/class.ilObjStudyProgramme.php
index 9c5f728e2922..6ea12d02e2f3 100644
--- a/Modules/StudyProgramme/classes/class.ilObjStudyProgramme.php
+++ b/Modules/StudyProgramme/classes/class.ilObjStudyProgramme.php
@@ -734,6 +734,9 @@ public function getParents(bool $include_references = false)
continue;
}
$r_parent = $reference->getParent();
+ if (is_null($r_parent)) {
+ continue;
+ }
array_push($queque, $r_parent);
$parents[] = $r_parent;
}
@@ -1005,8 +1008,8 @@ public function putInTree($a_parent_ref)
/**
* Remove a node from this object.
*
- * Throws when node is no child of the object. Throws, when manipulation
- * of tree is not allowed due to invariants that need to hold on the tree.
+ * Throws when node is no child of the object.
+ * Throws when manipulation of tree is not allowed due to invariants that need to hold on the tree.
*
* @throws ilException
* @throws ilStudyProgrammeTreeException
@@ -1079,8 +1082,8 @@ public function addLeaf(ilStudyProgrammeLeaf $a_leaf) : ilObjStudyProgramme
/**
* Remove a leaf from this object.
*
- * Throws when leaf is not a child of this object. Throws, when manipulation
- * of tree is not allowed due to invariants that need to hold on the tree.
+ * Throws when leaf is not a child of this object.
+ * Throws when manipulation of tree is not allowed due to invariants that need to hold on the tree.
*
* @throws ilException
* @throws ilStudyProgrammeTreeException
@@ -1101,7 +1104,7 @@ public function removeLeaf(ilStudyProgrammeLeaf $a_leaf) : ilObjStudyProgramme
/**
* Move this tree node to a new parent.
*
- * Throws, when manipulation of tree is not allowed due to invariants that
+ * Throws when manipulation of tree is not allowed due to invariants that
* need to hold on the tree.
*
* @throws ilStudyProgrammeTreeException
@@ -1388,8 +1391,30 @@ public function getProgressForAssignment(int $a_assignment_id) : ilStudyProgramm
*/
public function addMissingProgresses() : void
{
- foreach ($this->getAssignments() as $ass) {
- $ass->addMissingProgresses();
+ $progress_repository = $this->progress_repository;
+ $log = $this->getLog();
+
+ foreach ($this->getAssignments() as $ass) { /** ilStudyProgrammeUserAssignment[] */
+ $id = $ass->getId();
+ $assignment = $ass->getSPAssignment();
+
+ $mapping = function (ilObjStudyProgramme $node) use ($id, $log, $progress_repository, $assignment) {
+ try {
+ $node->getProgressForAssignment($id);
+ } catch (ilStudyProgrammeNoProgressForAssignmentException $e) {
+ $log->debug("Adding progress for: " . $id . " " . $node->getId());
+ $progress_repository->update(
+ $progress_repository->createFor(
+ $node->getRawSettings(),
+ $assignment
+ )->setStatus(
+ ilStudyProgrammeProgress::STATUS_NOT_RELEVANT
+ )
+ );
+ }
+ };
+
+ $this->applyToSubTreeNodes($mapping, true);
}
}
@@ -1991,7 +2016,7 @@ public static function sendReAssignedMail(int $ref_id, int $usr_id) : bool
{
global $DIC;
$lng = $DIC['lng'];
- $log = $DIC['ilLog'];
+ $log = $this->getLog();
$lng->loadLanguageModule("prg");
$lng->loadLanguageModule("mail");
@@ -2067,4 +2092,10 @@ public static function sendInvalidateMail(int $ref_id, int $usr_id) : bool
return $send;
}
+
+
+ protected function getLog()
+ {
+ return ilLoggerFactory::getLogger($this->type);
+ }
}
diff --git a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeAutoMembershipsGUI.php b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeAutoMembershipsGUI.php
index 8b4683618fa6..de5e077c3441 100644
--- a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeAutoMembershipsGUI.php
+++ b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeAutoMembershipsGUI.php
@@ -245,6 +245,8 @@ protected function save()
(is_null($src_type) || $src_type == "") ||
(is_null($src_id) || $src_id == 0)
) {
+ ilUtil::sendFailure($this->txt('no_srctype_or_id'), true);
+ $this->ctrl->redirect($this, self::CMD_VIEW);
return;
}
@@ -265,6 +267,7 @@ protected function save()
}
$this->getObject()->storeAutomaticMembershipSource($src_type, (int) $src_id);
+ $this->ctrl->redirect($this, self::CMD_VIEW);
}
protected function deleteConfirmation()
diff --git a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeGUI.php b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeGUI.php
index 6e3de4ec51e5..ebf6fed51dec 100644
--- a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeGUI.php
+++ b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeGUI.php
@@ -435,9 +435,13 @@ protected function view()
{
$this->denyAccessIfNot("read");
$this->tabs_gui->activateTab(self::TAB_VIEW_CONTENT);
-
parent::renderObject();
}
+ public function isActiveAdministrationPanel()
+ {
+ return false;
+ }
+
/**
* Initialize the form for editing advanced meta data
diff --git a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeIndividualPlanGUI.php b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeIndividualPlanGUI.php
index 416b8037f5b4..627c9b41f82c 100644
--- a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeIndividualPlanGUI.php
+++ b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeIndividualPlanGUI.php
@@ -174,6 +174,9 @@ protected function updateFromCurrentPlan()
);
}
$ass->updateFromProgram();
+ $ass->updateValidityFromProgram();
+ $ass->updateDeadlineFromProgram();
+
$this->ctrl->setParameter($this, "ass_id", $ass->getId());
$this->showSuccessMessage("update_from_plan_successful");
$this->ctrl->redirect($this, "manage");
@@ -352,7 +355,7 @@ protected function buildFrame($tab, $content)
$user_id = $ass->getUserId();
$tpl->setVariable("USERNAME", ilObjUser::_lookupFullname($user_id));
$tabs = [];
- if($this->ilAccess->checkAccess("manage_members", "", $ref_id)) {
+ if ($this->ilAccess->checkAccess("manage_members", "", $ref_id)) {
$tabs[] = 'view';
$tabs[] = 'manage';
}
diff --git a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeMembersGUI.php b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeMembersGUI.php
index 725da4d622bf..1ff5f66cc587 100644
--- a/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeMembersGUI.php
+++ b/Modules/StudyProgramme/classes/class.ilObjStudyProgrammeMembersGUI.php
@@ -11,6 +11,7 @@
* @ilCtrl_Calls ilObjStudyProgrammeMembersGUI: ilStudyProgrammeMailMemberSearchGUI
* @ilCtrl_Calls ilObjStudyProgrammeMembersGUI: ilStudyProgrammeChangeExpireDateGUI
* @ilCtrl_Calls ilObjStudyProgrammeMembersGUI: ilStudyProgrammeChangeDeadlineGUI
+ * @ilCtrl_Calls ilObjStudyProgrammeMembersGUI: ilFormPropertyDispatchGUI
*/
class ilObjStudyProgrammeMembersGUI
{
@@ -214,7 +215,7 @@ protected function getDefaultCommand() : string
protected function getAssignmentsById() : array
{
$assignments = $this->object->getAssignments();
- ;
+
return array_filter($assignments, function (ilStudyProgrammeUserAssignment $assignment) {
return $assignment->getStudyProgramme()->getId() == $this->object->getId();
});
@@ -499,6 +500,9 @@ protected function markAccreditedById(int $prgrs_id) : void
);
}
$prgrs->markAccredited($this->user->getId());
+
+ $ass = $this->sp_user_assignment_db->getInstanceById($prgrs->getAssignmentId());
+ $this->updateUserAssignmentFromProgramm($ass);
}
/**
@@ -529,6 +533,9 @@ protected function unmarkAccreditedByProgressId(int $prgrs_id) : void
);
}
$prgrs->unmarkAccredited();
+
+ $ass = $this->sp_user_assignment_db->getInstanceById($prgrs->getAssignmentId());
+ $this->updateUserAssignmentFromProgramm($ass);
}
/**
@@ -627,7 +634,9 @@ public function updateFromCurrentPlanMulti() : void
$not_updated = array();
foreach ($prgrs_ids as $key => $prgrs_id) {
+ //** ilStudyProgrammeUserProgress */
$prgrs = $this->getProgressObject((int) $prgrs_id);
+ //** ilStudyProgrammeUserAssignment */
$ass = $this->sp_user_assignment_db->getInstanceById($prgrs->getAssignmentId());
$prg = $ass->getStudyProgramme();
if ($prg->getRefId() != $this->ref_id) {
@@ -635,7 +644,7 @@ public function updateFromCurrentPlanMulti() : void
continue;
}
- $ass->updateFromProgram();
+ $this->updateUserAssignmentFromProgramm($ass);
}
if (count($not_updated) == count($prgrs_ids)) {
@@ -960,4 +969,11 @@ public function isOperationAllowedForUser(int $usr_id, string $operation) : bool
return $this->mayManageMembers()
|| $this->position_based_access->isUserAccessibleForOperationAtPrg($usr_id, $this->object, $operation);
}
+
+ protected function updateUserAssignmentFromProgramm(ilStudyProgrammeUserAssignment $ass) : void
+ {
+ $ass->updateFromProgram();
+ $ass->updateValidityFromProgram();
+ $ass->updateDeadlineFromProgram();
+ }
}
diff --git a/Modules/StudyProgramme/classes/class.ilStudyProgrammeDIC.php b/Modules/StudyProgramme/classes/class.ilStudyProgrammeDIC.php
index 092167d7e9c1..a2e842fae65c 100644
--- a/Modules/StudyProgramme/classes/class.ilStudyProgrammeDIC.php
+++ b/Modules/StudyProgramme/classes/class.ilStudyProgrammeDIC.php
@@ -197,9 +197,7 @@ protected static function buildDIC() : Container
return new ilStudyProgrammeUserAssignmentDB(
$dic['ilStudyProgrammeUserProgressDB'],
$dic['model.Assignment.ilStudyProgrammeAssignmentRepository'],
- $dic['model.Progress.ilStudyProgrammeProgressRepository'],
$tree,
- $logger,
$dic['ilStudyProgrammeEvents']
);
};
diff --git a/Modules/StudyProgramme/classes/class.ilStudyProgrammeMembersTableGUI.php b/Modules/StudyProgramme/classes/class.ilStudyProgrammeMembersTableGUI.php
index eed296b0664f..1c8174d18702 100644
--- a/Modules/StudyProgramme/classes/class.ilStudyProgrammeMembersTableGUI.php
+++ b/Modules/StudyProgramme/classes/class.ilStudyProgrammeMembersTableGUI.php
@@ -303,10 +303,6 @@ protected function buildActionDropDown(
ilOrgUnitOperation::OP_VIEW_INDIVIDUAL_PLAN
);
- $manage_members = $parent->isOperationAllowedForUser(
- $usr_id,
- ilOrgUnitOperation::OP_MANAGE_MEMBERS
- ) && in_array($usr_id, $this->getParentObject()->getLocalMembers());
foreach ($actions as $action) {
switch ($action) {
@@ -322,6 +318,10 @@ protected function buildActionDropDown(
}
break;
case ilStudyProgrammeUserProgress::ACTION_REMOVE_USER:
+ $manage_members =
+ $parent->isOperationAllowedForUser($usr_id, ilOrgUnitOperation::OP_MANAGE_MEMBERS)
+ && in_array($usr_id, $this->getParentObject()->getLocalMembers());
+
if (!$manage_members) {
continue 2;
}
@@ -393,6 +393,7 @@ protected function fetchData(
$sql .= $this->getFrom();
$sql .= $this->getWhere($prg_id);
$sql .= $this->getFilterWhere($filter);
+ $sql .= $this->getOrguValidUsersFilter();
if ($limit !== null) {
$this->db->setLimit($limit, $offset !== null ? $offset : 0);
@@ -402,6 +403,7 @@ protected function fetchData(
$now = (new DateTime())->format('Y-m-d H:i:s');
$members_list = array();
+
while ($rec = $this->db->fetchAssoc($res)) {
$rec["actions"] = ilStudyProgrammeUserProgress::getPossibleActions(
$prg_id,
@@ -707,4 +709,22 @@ protected function isPermissionControlledByOrguPosition()
$this->prg->getPositionSettingsIsActiveForPrg()
);
}
+
+ protected function getOrguValidUsersFilter() : string
+ {
+ if ($this->getParentObject()->mayManageMembers()) {
+ return '';
+ }
+
+ $valid_user_ids = $this->position_based_access->getUsersInPrgAccessibleForOperation(
+ $this->getParentObject()->object,
+ ilOrgUnitOperation::OP_MANAGE_MEMBERS
+ );
+ if (count($valid_user_ids) < 1) {
+ return ' AND false';
+ }
+ return ' AND pcp.usr_id in ('
+ . implode(',', $valid_user_ids)
+ . ')';
+ }
}
diff --git a/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignment.php b/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignment.php
index a35393ba6204..cc81603b932d 100644
--- a/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignment.php
+++ b/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignment.php
@@ -15,7 +15,7 @@ class ilStudyProgrammeUserAssignment
/**
* @var ilStudyProgrammeAssignment
*/
- public $assignment;
+ protected $assignment;
/**
* @var ilStudyProgrammeUserProgressDB
@@ -27,16 +27,6 @@ class ilStudyProgrammeUserAssignment
*/
protected $assignment_repository;
- /**
- * @var ilStudyProgrammeProgressRepository
- */
- protected $progress_repository;
-
- /**
- * @var ilLogger
- */
- protected $log;
-
/**
* @var ilStudyProgrammeEvents
*/
@@ -46,19 +36,14 @@ public function __construct(
ilStudyProgrammeAssignment $assignment,
ilStudyProgrammeUserProgressDB $sp_user_progress_db,
ilStudyProgrammeAssignmentRepository $assignment_repository,
- ilStudyProgrammeProgressRepository $progress_repository,
- ilLogger $log,
ilStudyProgrammeEvents $sp_events
) {
$this->assignment = $assignment;
$this->sp_user_progress_db = $sp_user_progress_db;
$this->assignment_repository = $assignment_repository;
- $this->progress_repository = $progress_repository;
- $this->log = $log;
$this->sp_events = $sp_events;
}
-
/**
* Get the id of the assignment.
*/
@@ -113,8 +98,8 @@ public function getRootProgress() : ilStudyProgrammeUserProgress
}
/**
- * Assign the user belonging to this assignemnt to the prg
- * belonging to this assignemnt again.
+ * Assign the user belonging to this assignment to the prg
+ * belonging to this assignment again.
*
* @throws ilException
*/
@@ -185,39 +170,48 @@ function (ilObjStudyProgramme $node) use ($id) {
return $this;
}
- /**
- * Add missing progresses for new nodes in the programm.
- *
- * The new progresses will be set to not relevant.
- */
- public function addMissingProgresses() : ilStudyProgrammeUserAssignment
+ public function updateValidityFromProgram() : void
{
$prg = $this->getStudyProgramme();
- $id = $this->getId();
- $log = $this->log;
- $progress_repository = $this->progress_repository;
- $assignment = $this->assignment;
- // Make $this->assignment protected again afterwards.
- $prg->applyToSubTreeNodes(
- function (ilObjStudyProgramme $node) use ($id,$log,$progress_repository,$assignment) {
- try {
- $node->getProgressForAssignment($id);
- } catch (ilStudyProgrammeNoProgressForAssignmentException $e) {
- $log->write("Adding progress for: " . $id . " " . $node->getId());
- $progress_repository->update(
- $progress_repository->createFor(
- $node->getRawSettings(),
- $assignment
- )->setStatus(
- ilStudyProgrammeProgress::STATUS_NOT_RELEVANT
- )
- );
- }
- },
- true
- );
+ $progress = $this->getRootProgress();
+ if (!$progress->hasSuccessStatus()) {
+ return;
+ }
- return $this;
+ $validity_settings = $prg->getValidityOfQualificationSettings();
+ $period = $validity_settings->getQualificationPeriod();
+ $date = $validity_settings->getQualificationDate();
+
+ if ($period) {
+ $date = $progress->getCompletionDate();
+ $date->add(new DateInterval('P' . $period . 'D'));
+ }
+ $progress->setValidityOfQualification($date);
+ $progress->storeProgress();
+ }
+
+ public function updateDeadlineFromProgram() : void
+ {
+ $prg = $this->getStudyProgramme();
+ $progress = $this->getRootProgress();
+ if ($progress->hasSuccessStatus()) {
+ return;
+ }
+
+ $deadline_settings = $prg->getDeadlineSettings();
+ $period = $deadline_settings->getDeadlinePeriod();
+ $date = $deadline_settings->getDeadlineDate();
+ if ($period) {
+ $date = $progress->getAssignmentDate();
+ $date->add(new DateInterval('P' . $period . 'D'));
+ }
+ $progress->setDeadline($date);
+ $progress->storeProgress();
+ }
+
+ public function getSPAssignment() : ilStudyProgrammeAssignment
+ {
+ return $this->assignment;
}
/**
diff --git a/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignmentDB.php b/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignmentDB.php
index 1a2181c46a35..072ba0026b2c 100644
--- a/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignmentDB.php
+++ b/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserAssignmentDB.php
@@ -14,21 +14,11 @@ class ilStudyProgrammeUserAssignmentDB
*/
protected $assignment_repository;
- /**
- * @var ilStudyProgrammeProgressRepository
- */
- protected $progress_repository;
-
/**
* @var ilTree
*/
protected $tree;
- /**
- * @var ilLogger
- */
- protected $log;
-
/**
* @var ilStudyProgrammeEvents
*/
@@ -37,16 +27,12 @@ class ilStudyProgrammeUserAssignmentDB
public function __construct(
ilStudyProgrammeUserProgressDB $sp_user_progress_db,
ilStudyProgrammeAssignmentRepository $assignment_repository,
- ilStudyProgrammeProgressRepository $progress_repository,
ilTree $tree,
- ilLogger $log,
ilStudyProgrammeEvents $sp_events
) {
$this->sp_user_progress_db = $sp_user_progress_db;
$this->assignment_repository = $assignment_repository;
- $this->progress_repository = $progress_repository;
$this->tree = $tree;
- $this->log = $log;
$this->sp_events = $sp_events;
}
@@ -61,8 +47,6 @@ public function getInstanceById(int $id)
$assignment,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
}
@@ -73,8 +57,6 @@ public function getInstanceByModel(\ilStudyProgrammeAssignment $assignment)
$assignment,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
}
@@ -93,8 +75,6 @@ public function getInstancesOfUser(int $user_id)
$ass,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
continue 2;
@@ -112,8 +92,6 @@ public function getInstancesForProgram(int $program_id)
$ass,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
}, array_values($assignments)); // use array values since we want keys 0...
@@ -130,8 +108,6 @@ function ($ass) {
$ass,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
},
@@ -150,8 +126,6 @@ function ($ass) {
$ass,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
},
@@ -175,8 +149,6 @@ public function getDashboardInstancesforUser(int $usr_id) : array
$assignment,
$this->sp_user_progress_db,
$this->assignment_repository,
- $this->progress_repository,
- $this->log,
$this->sp_events
);
}
diff --git a/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserProgress.php b/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserProgress.php
index d13def6e8753..9021b1725dc9 100644
--- a/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserProgress.php
+++ b/Modules/StudyProgramme/classes/class.ilStudyProgrammeUserProgress.php
@@ -53,9 +53,9 @@ public function __construct(
}
/**
- * Get the program node where this progress belongs to was made.
+ * Get the program node this progress belongs to.
*
- * Throws when program this assignment is about has no ref id.
+ * Throws when the according program has no ref id.
*
* TODO: I'm quite sure, this will profit from caching.
*
@@ -213,6 +213,11 @@ public function setValidityOfQualification(DateTime $date = null) : void
$this->progress->setValidityOfQualification($date);
}
+ public function storeProgress() : void
+ {
+ $this->progress_repository->update($this->progress);
+ }
+
/**
* Delete the assignment from database.
*/
@@ -1001,4 +1006,15 @@ public static function sendRiskyToFailMail(int $progress_id, int $usr_id) : void
$usr_progress_db->reminderSendFor($usr_progress->getId());
}
}
+
+ public function hasSuccessStatus() : bool
+ {
+ return in_array(
+ $this->getStatus(),
+ [
+ ilStudyProgrammeProgress::STATUS_COMPLETED,
+ ilStudyProgrammeProgress::STATUS_ACCREDITED
+ ]
+ );
+ }
}
diff --git a/Modules/StudyProgramme/classes/model/Assignments/class.ilStudyProgrammeAssignment.php b/Modules/StudyProgramme/classes/model/Assignments/class.ilStudyProgrammeAssignment.php
index 0e21325e05dd..42174042fef5 100644
--- a/Modules/StudyProgramme/classes/model/Assignments/class.ilStudyProgrammeAssignment.php
+++ b/Modules/StudyProgramme/classes/model/Assignments/class.ilStudyProgrammeAssignment.php
@@ -218,7 +218,7 @@ public function getRestartDate()
}
/**
- * Set the date, at which the user was be reassigned to the programme
+ * Set the id of the assignment which was intiated due to expiring progress of this assignment.
*/
public function setRestartedAssignmentId(int $id) : ilStudyProgrammeAssignment
{
@@ -227,7 +227,7 @@ public function setRestartedAssignmentId(int $id) : ilStudyProgrammeAssignment
}
/**
- * Get the date, at which the user was reassigned to the programme
+ * Get the id of the assignment which was intiated due to expiring progress of this assignment.
*
* @return int
*/
diff --git a/Modules/StudyProgramme/classes/model/Progress/class.ilStudyProgrammeProgress.php b/Modules/StudyProgramme/classes/model/Progress/class.ilStudyProgrammeProgress.php
index 45c1ca0a0a21..d500c0b13e8f 100644
--- a/Modules/StudyProgramme/classes/model/Progress/class.ilStudyProgrammeProgress.php
+++ b/Modules/StudyProgramme/classes/model/Progress/class.ilStudyProgrammeProgress.php
@@ -288,8 +288,7 @@ public function getStatus() : int
/**
* Set the status of this node.
*
- * Throws when status is none of ilStudyProgrammeProgress::STATUS_*. Throws when
- * current status is STATUS_COMPLETED.
+ * Throws when status is none of ilStudyProgrammeProgress::STATUS_*.
*/
public function setStatus(int $a_status) : ilStudyProgrammeProgress
{
@@ -346,7 +345,7 @@ public function getLastChangeBy()
*/
public function setLastChangeBy(int $a_usr_id = null) : ilStudyProgrammeProgress
{
- if ($a_usr_id !== null && ilObject::_lookupType($a_usr_id) != "usr") {
+ if (is_null($a_usr_id) || $a_usr_id < 0) {
throw new ilException("ilStudyProgrammeProgress::setLastChangeBy: '$a_usr_id' "
. "is no id of a user.");
}
diff --git a/Modules/StudyProgramme/test/model/Progress/ilStudyProgrammeProgressTest.php b/Modules/StudyProgramme/test/model/Progress/ilStudyProgrammeProgressTest.php
index 31a5fca9f441..159693767218 100644
--- a/Modules/StudyProgramme/test/model/Progress/ilStudyProgrammeProgressTest.php
+++ b/Modules/StudyProgramme/test/model/Progress/ilStudyProgrammeProgressTest.php
@@ -1,26 +1,7 @@
-expectException(\ilException::class);
$spp = (new ilStudyProgrammeProgress(123))->setAmountOfPoints(-321);
}
@@ -85,11 +66,11 @@ public function test_current_amount_of_points()
public function status()
{
return [
- [1]
- ,[2]
- ,[3]
- ,[4]
- ,[5]
+ [ilStudyProgrammeProgress::STATUS_IN_PROGRESS],
+ [ilStudyProgrammeProgress::STATUS_COMPLETED],
+ [ilStudyProgrammeProgress::STATUS_ACCREDITED],
+ [ilStudyProgrammeProgress::STATUS_NOT_RELEVANT],
+ [ilStudyProgrammeProgress::STATUS_FAILED]
];
}
@@ -104,10 +85,10 @@ public function test_status($status)
/**
* @depends test_init_and_id
- * @expectedException ilException
*/
public function test_status_invalid()
{
+ $this->expectException(\ilException::class);
$spp = (new ilStudyProgrammeProgress(123))->setStatus(321);
}
@@ -131,13 +112,22 @@ public function test_last_change_by()
/**
* @depends test_init_and_id
- * @expectedException ilException
*/
public function test_last_change_by_invalid()
{
+ $this->expectException(\ilException::class);
$spp = (new ilStudyProgrammeProgress(123))->setLastChangeBy(-1);
}
+ /**
+ * @depends test_init_and_id
+ */
+ public function test_last_change_by_null()
+ {
+ $this->expectException(\ilException::class);
+ $spp = (new ilStudyProgrammeProgress(123))->setLastChangeBy();
+ }
+
/**
* @depends test_init_and_id
*/
@@ -194,22 +184,22 @@ public function test_invalidate()
}
/**
- * @expectedException ilException
* @depends test_vq_date
*/
public function test_invalidate_non_expired_1()
{
+ $this->expectException(\ilException::class);
$tomorrow = new DateTime();
$tomorrow->add(new DateInterval('P1D'));
$spp = (new ilStudyProgrammeProgress(123))->setValidityOfQualification($tomorrow)->invalidate();
}
/**
- * @expectedException ilException
* @depends test_vq_date
*/
public function test_invalidate_non_expired_2()
{
+ $this->expectException(\ilException::class);
$spp = (new ilStudyProgrammeProgress(123))->invalidate();
}
}
diff --git a/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReference.php b/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReference.php
index b4c246298cd3..58d2fd578e02 100644
--- a/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReference.php
+++ b/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReference.php
@@ -28,17 +28,18 @@ public function putInTree($a_parent_ref)
if (ilObject::_lookupType($a_parent_ref, true) == "prg") {
$par = ilObjStudyProgramme::getInstanceByRefId($a_parent_ref);
$par->nodeInserted($this->getReferencedObject());
- } else {
- throw new Exception('invalid parent type');
}
return $res;
}
- public function getParent()
+ public function getParent() : ?\ilObjStudyProgramme
{
$parent_data = $this->tree->getParentNodeData($this->getRefId());
- return ilObjStudyProgramme::getInstanceByRefId($parent_data["ref_id"]);
+ if ($parent_data["type"] === "prg" && !$parent_data["deleted"]) {
+ return ilObjStudyProgramme::getInstanceByRefId($parent_data["ref_id"]);
+ }
+ return null;
}
public function getReferencedObject()
diff --git a/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReferenceAccess.php b/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReferenceAccess.php
index 11442ed06ebf..cc2753c9081d 100644
--- a/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReferenceAccess.php
+++ b/Modules/StudyProgrammeReference/classes/class.ilObjStudyProgrammeReferenceAccess.php
@@ -43,21 +43,23 @@ public function _checkAccess($a_cmd, $a_permission, $a_ref_id, $a_obj_id, $a_use
$prg = ilObjStudyProgramme::getInstanceByRefId($target_ref_id);
$target_id = $prg->getId();
$progress_db = ilStudyProgrammeDIC::dic()['ilStudyProgrammeUserProgressDB'];
- foreach (ilObjStudyProgramme::getInstanceByRefId(
- $tree->getParentId($a_ref_id)
- )->getProgresses() as $parent_progress
- ) {
- try {
- $progress =
- $progress_db->getInstanceForAssignment(
- $target_id,
- $parent_progress->getAssignmentId()
- );
- } catch (ilStudyProgrammeNoProgressForAssignmentException $e) {
- continue;
- }
- if ($progress->isRelevant()) {
- return false;
+ $parent = $tree->getParentNodeData($a_ref_id);
+ if ($parent["type"] === "prg" && !$parent["deleted"]) {
+ $parent = ilObjStudyProgramme::getInstanceByRefId($parent["ref_id"]);
+ foreach ($parent->getProgresses() as $parent_progress
+ ) {
+ try {
+ $progress =
+ $progress_db->getInstanceForAssignment(
+ $target_id,
+ $parent_progress->getAssignmentId()
+ );
+ } catch (ilStudyProgrammeNoProgressForAssignmentException $e) {
+ continue;
+ }
+ if ($progress->isRelevant()) {
+ return false;
+ }
}
}
diff --git a/Modules/Survey/Evaluation/class.ilSurveyEvaluationGUI.php b/Modules/Survey/Evaluation/class.ilSurveyEvaluationGUI.php
index 0b116682c6c7..dd1605148885 100644
--- a/Modules/Survey/Evaluation/class.ilSurveyEvaluationGUI.php
+++ b/Modules/Survey/Evaluation/class.ilSurveyEvaluationGUI.php
@@ -724,7 +724,7 @@ protected function buildExportModal($a_id, $a_cmd)
return $modal->getHTML();
}
- public function evaluation($details = 0)
+ public function evaluation($details = 0, $pdf = false, $return_pdf = false)
{
$rbacsystem = $this->rbacsystem;
$ilToolbar = $this->toolbar;
@@ -759,8 +759,10 @@ public function evaluation($details = 0)
}
$this->log->debug("check access ok");
-
- $ilToolbar->setFormAction($this->ctrl->getFormAction($this));
+
+ if (!$pdf) {
+ $ilToolbar->setFormAction($this->ctrl->getFormAction($this));
+ }
$this->tpl->addBlockFile("ADM_CONTENT", "adm_content", "tpl.il_svy_svy_evaluation.html", "Modules/Survey");
@@ -804,38 +806,40 @@ public function evaluation($details = 0)
$this->lng->loadLanguageModule("content");
$toc_tpl->setVariable("TITLE_TOC", $this->lng->txt('cont_toc'));
}
-
- $modal_id = "svy_ev_exp";
- $modal = $this->buildExportModal($modal_id, $details
- ? 'exportDetailData'
- : 'exportData');
-
- $button = ilLinkButton::getInstance();
- $button->setCaption("export");
- $button->setOnClick('$(\'#' . $modal_id . '\').modal(\'show\')');
- $ilToolbar->addButtonInstance($button);
-
- $ilToolbar->addSeparator();
- $button = ilLinkButton::getInstance();
- $button->setCaption("print");
- $button->setOnClick("if(il.Accordion) { il.Accordion.preparePrint(); } window.print(); return false;");
- $button->setOmitPreventDoubleSubmission(true);
- $ilToolbar->addButtonInstance($button);
+ if (!$pdf) {
+ $modal_id = "svy_ev_exp";
+ $modal = $this->buildExportModal($modal_id, $details
+ ? 'exportDetailData'
+ : 'exportData');
- // patch BGHW jluetzen-ilias
- $this->ctrl->setParameter($this, "cp", $_POST["cp"]);
- $this->ctrl->setParameter($this, "vw", $_POST["vw"]);
- $url = $this->ctrl->getLinkTarget($this, $details
- ? "evaluationdetailspdf"
- : "evaluationpdf");
- $this->ctrl->setParameter($this, "cp", "");
- $this->ctrl->setParameter($this, "vw", "");
- $button = ilLinkButton::getInstance();
- $button->setCaption("svy_export_pdf");
- $button->setUrl($url);
- $button->setOmitPreventDoubleSubmission(true);
- $ilToolbar->addButtonInstance($button);
+ $button = ilLinkButton::getInstance();
+ $button->setCaption("export");
+ $button->setOnClick('$(\'#' . $modal_id . '\').modal(\'show\')');
+ $ilToolbar->addButtonInstance($button);
+
+ $ilToolbar->addSeparator();
+
+ $button = ilLinkButton::getInstance();
+ $button->setCaption("print");
+ $button->setOnClick("if(il.Accordion) { il.Accordion.preparePrint(); } window.print(); return false;");
+ $button->setOmitPreventDoubleSubmission(true);
+ $ilToolbar->addButtonInstance($button);
+
+ // patch BGHW jluetzen-ilias
+ $this->ctrl->setParameter($this, "cp", $_POST["cp"]);
+ $this->ctrl->setParameter($this, "vw", $_POST["vw"]);
+ $url = $this->ctrl->getLinkTarget($this, $details
+ ? "evaluationdetailspdf"
+ : "evaluationpdf");
+ $this->ctrl->setParameter($this, "cp", "");
+ $this->ctrl->setParameter($this, "vw", "");
+ $button = ilLinkButton::getInstance();
+ $button->setCaption("svy_export_pdf");
+ $button->setUrl($url);
+ $button->setOmitPreventDoubleSubmission(true);
+ $ilToolbar->addButtonInstance($button);
+ }
$finished_ids = null;
if ($appr_id) {
@@ -871,7 +875,7 @@ public function evaluation($details = 0)
if ($details) {
//$this->renderDetails($details_view, $details_figure, $dtmpl, $qdata, $q_eval, $q_res);
- $this->renderDetails($details_view, $details_figure, $qdata, $q_eval, $q_res);
+ $this->renderDetails($details_view, $details_figure, $qdata, $q_eval, $q_res, $pdf);
// TABLE OF CONTENTS
if ($qdata["questionblock_id"] &&
@@ -946,6 +950,14 @@ public function evaluation($details = 0)
}
$this->log->debug("end");
+ if ($pdf) {
+ $html = $this->tpl->printToString();
+ if ($return_pdf) {
+ return $html;
+ } else {
+ $this->generateAndSendPDF($html);
+ }
+ }
// $this->tpl->addCss("./Modules/Survey/templates/default/survey_print.css", "print");
}
@@ -961,7 +973,7 @@ public function evaluation($details = 0)
* @param ilSurveyEvaluationResults|array $a_results
*/
//protected function renderDetails($a_details_parts, $a_details_figure, ilTemplate $a_tpl, array $a_qdata, SurveyQuestionEvaluation $a_eval, $a_results)
- protected function renderDetails($a_details_parts, $a_details_figure, array $a_qdata, SurveyQuestionEvaluation $a_eval, $a_results)
+ protected function renderDetails($a_details_parts, $a_details_figure, array $a_qdata, SurveyQuestionEvaluation $a_eval, $a_results, $pdf)
{
$ui_factory = $this->ui->factory();
$a_tpl = new ilTemplate("tpl.svy_results_details_panel.html", true, true, "Modules/Survey");
@@ -1115,9 +1127,11 @@ protected function renderDetails($a_details_parts, $a_details_figure, array $a_q
}
// patch BGHW jluezen
- $this->ctrl->setParameter($this, "qid", $question->getId());
- $url = $this->ctrl->getLinkTarget($this, "downloadChart");
- $this->ctrl->setParameter($this, "qid", "");
+ if (!$pdf) {
+ $this->ctrl->setParameter($this, "qid", $question->getId());
+ $url = $this->ctrl->getLinkTarget($this, "downloadChart");
+ $this->ctrl->setParameter($this, "qid", "");
+ }
$a_tpl->setVariable("CHART", $chart);
$a_tpl->setVariable("CHART_DL_URL", $url);
@@ -1665,32 +1679,14 @@ protected function hasResultsAccess()
return $this->access->checkRbacOrPositionPermissionAccess('read_results', 'access_results', $this->object->getRefId());
}
- //
- // PATCH BGHW
- //
-
public function evaluationpdf()
{
- $this->ctrl->setParameter($this, "pdf", 1);
- $this->ctrl->setParameter($this, "cp", $_GET["cp"]);
- $this->ctrl->setParameter($this, "vw", $_GET["vw"]);
- $this->callPhantom(
- $this->ctrl->getLinkTarget($this, "evaluation", "", false, false),
- "pdf",
- $this->object->getTitle() . ".pdf"
- );
+ $this->evaluation(0, true);
}
public function evaluationdetailspdf()
{
- $this->ctrl->setParameter($this, "pdf", 1);
- $this->ctrl->setParameter($this, "cp", $_GET["cp"]);
- $this->ctrl->setParameter($this, "vw", $_GET["vw"]);
- $this->callPhantom(
- $this->ctrl->getLinkTarget($this, "evaluationdetails", "", false, false),
- "pdf",
- $this->object->getTitle() . ".pdf"
- );
+ $this->evaluation(1, true);
}
public function downloadChart()
@@ -1700,14 +1696,7 @@ public function downloadChart()
return;
}
- $this->ctrl->setParameter($this, "qid", $qid);
- $url = $this->ctrl->getLinkTarget($this, "renderChartOnly", "", false, false);
- $this->ctrl->setParameter($this, "qid", "");
-
- include_once "./Modules/SurveyQuestionPool/classes/class.SurveyQuestion.php";
- $file = $this->object->getTitle() . " - " . SurveyQuestion::_getTitle($qid);
-
- $this->callPhantom($url, "png", $file . ".png");
+ $this->renderChartOnly();
}
public function renderChartOnly()
@@ -1729,7 +1718,6 @@ public function renderChartOnly()
}
// parse answer data in evaluation results
- include_once "./Modules/SurveyQuestionPool/classes/class.SurveyQuestion.php";
foreach ($this->object->getSurveyQuestions() as $qdata) {
if ($qid == $qdata["question_id"]) {
$q_eval = SurveyQuestion::_instanciateQuestionEvaluation($qdata["question_id"], $finished_ids);
@@ -1758,26 +1746,37 @@ public function renderChartOnly()
}
// "print view"
- $ptpl = new ilTemplate("tpl.main.html", true, true);
- foreach ($tpl->css_files as $css) {
- $ptpl->setCurrentBlock("css_file");
- $ptpl->setVariable("CSS_FILE", $css["file"]);
- $ptpl->setVariable("CSS_MEDIA", $css["media"]);
- $ptpl->parseCurrentBlock();
- }
- foreach ($tpl->js_files as $js) {
- $ptpl->setCurrentBlock("js_file");
- $ptpl->setVariable("JS_FILE", $js);
- $ptpl->parseCurrentBlock();
- }
- $ptpl->setVariable("LOCATION_STYLESHEET", ilUtil::getStyleSheetLocation());
- $ptpl->setVariable("LOCATION_CONTENT_STYLESHEET", ilUtil::getNewContentStyleSheetLocation());
- $ptpl->setVariable("CONTENT", $dtmpl->get());
- echo $ptpl->get();
- exit();
+ $this->tpl->setContent($dtmpl->get());
+
+ $html = $this->tpl->printToString();
+ $this->generateAndSendPDF($html, $this->object->getTitle() . " - " . SurveyQuestion::_getTitle($qid).".pdf");
+ }
+
+ /**
+ *
+ * @param $html
+ * @param $filename
+ * @throws Exception
+ */
+ public function generateAndSendPDF($html, $filename = "")
+ {
+ // :TODO: fixing css dummy parameters
+ $html = preg_replace("/\?dummy\=[0-9]+/", "", $html);
+ $html = preg_replace("/\?vers\=[0-9A-Za-z\-]+/", "", $html);
+ $html = str_replace('.css$Id$', ".css", $html);
+ $html = preg_replace("/src=\"\\.\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
+ $html = preg_replace("/href=\"\\.\\//ims", "href=\"" . ILIAS_HTTP_PATH . "/", $html);
+
+ //echo $html; exit;
+
+ if ($filename == "") {
+ $filename = $this->object->getTitle() . ".pdf";
+ }
+ $pdf_factory = new ilHtmlToPdfTransformerFactory();
+ $pdf_factory->deliverPDFFromHTMLString($html, $filename, ilHtmlToPdfTransformerFactory::PDF_OUTPUT_DOWNLOAD, "Survey", "Results");
}
- public function callPhantom($a_url, $a_suffix, $a_filename, $a_return = false)
+ public function callPdfGeneration($a_url, $a_suffix, $a_filename, $a_return = false)
{
$script = ILIAS_ABSOLUTE_PATH . "/Modules/Survey/js/phantom.js";
diff --git a/Modules/Survey/Mail/FormMailCodesGUI.php b/Modules/Survey/Mail/FormMailCodesGUI.php
index 199e9712bc9b..c897d2259c7c 100644
--- a/Modules/Survey/Mail/FormMailCodesGUI.php
+++ b/Modules/Survey/Mail/FormMailCodesGUI.php
@@ -97,14 +97,10 @@ public function __construct($guiclass)
}
}
- if ($ilAccess->checkAccess("write", "", $_GET["ref_id"]) && $rbacsystem->checkAccess('smtp_mail', ilMailGlobalServices::getMailObjectRefId())) {
- if ((int) $ilSetting->get('mail_allow_external')) {
- $this->addCommandButton("sendCodesMail", $this->lng->txt("send"));
- } else {
- ilUtil::sendInfo($lng->txt("cant_send_email_smtp_disabled"));
- }
+ if ((int) $ilSetting->get('mail_allow_external')) {
+ $this->addCommandButton("sendCodesMail", $this->lng->txt("send"));
} else {
- ilUtil::sendInfo($lng->txt("cannot_send_emails"));
+ ilUtil::sendInfo($lng->txt("cant_send_email_smtp_disabled"));
}
}
diff --git a/Modules/Survey/README.md b/Modules/Survey/README.md
index cc6185e607df..4038c4f08e19 100644
--- a/Modules/Survey/README.md
+++ b/Modules/Survey/README.md
@@ -7,6 +7,11 @@
This component does currently not offer any public services.
+# PDF Generation
+
+- If wkhtmltopdf is being used you must set the "Use print media type instead of screen" flag.
+- Both PhantomJS and wkhtmltopdf struggle with canvas rendering, see e.g. https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1964
+
# Internal Documentation
This section documents the general concepts and structures of the Survey Module. These are internal implementations which SHOULD not be used outside of this module unless mentioned in the API section of this README.
diff --git a/Modules/Survey/classes/class.ilObjSurvey.php b/Modules/Survey/classes/class.ilObjSurvey.php
index 93fe4b4c17c3..594310cf8554 100755
--- a/Modules/Survey/classes/class.ilObjSurvey.php
+++ b/Modules/Survey/classes/class.ilObjSurvey.php
@@ -6126,20 +6126,33 @@ public function sendTutorResults()
$_GET["baseClass"] = "ilObjSurveyGUI";
$ilCtrl->setParameterByClass("ilSurveyEvaluationGUI", "ref_id", $this->getRefId());
-
- include_once "./Modules/Survey/classes/class.ilSurveyEvaluationGUI.php";
- $gui = new ilSurveyEvaluationGUI($this);
- $url = $ilCtrl->getLinkTargetByClass(array("ilObjSurveyGUI", "ilSurveyEvaluationGUI"), "evaluationdetails", "", false, false);
+ try {
+ $gui = new ilSurveyEvaluationGUI($this);
+ $html = $gui->evaluation(1, true, true);
+ } catch (Exception $exception) {
+ $_GET["ref_id"] = $old_ref_id;
+ $_GET["baseClass"] = $old_base_class;
+ throw $exception;
+ }
$_GET["ref_id"] = $old_ref_id;
$_GET["baseClass"] = $old_base_class;
+ $html = preg_replace("/\?dummy\=[0-9]+/", "", $html);
+ $html = preg_replace("/\?vers\=[0-9A-Za-z\-]+/", "", $html);
+ $html = str_replace('.css$Id$', ".css", $html);
+ $html = preg_replace("/src=\"\\.\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
+ $html = preg_replace("/href=\"\\.\\//ims", "href=\"" . ILIAS_HTTP_PATH . "/", $html);
+ $pdf_factory = new ilHtmlToPdfTransformerFactory();
+ $pdf = $pdf_factory->deliverPDFFromHTMLString($html, "survey.pdf", ilHtmlToPdfTransformerFactory::PDF_OUTPUT_FILE, "Survey", "Results");
+
+ /*
$log->debug("calling phantom for ref_id: " . $this->getRefId());
- $pdf = $gui->callPhantom($url, "pdf", true, true);
+ $pdf = $gui->callPdfGeneration($url, "pdf", true, true);
- $log->debug("phantom called : " . $pdf);
+ $log->debug("phantom called : " . $pdf);*/
if (!$pdf ||
!file_exists($pdf)) {
diff --git a/Modules/Survey/classes/class.ilSurveyCronNotification.php b/Modules/Survey/classes/class.ilSurveyCronNotification.php
index 9e2bc932ecb4..8746d08574d5 100644
--- a/Modules/Survey/classes/class.ilSurveyCronNotification.php
+++ b/Modules/Survey/classes/class.ilSurveyCronNotification.php
@@ -43,7 +43,7 @@ public function getTitle()
$lng = $this->lng;
$lng->loadLanguageModule("survey");
- return $lng->txt("survey_reminder_setting");
+ return $lng->txt("survey_reminder_cron");
}
public function getDescription()
diff --git a/Modules/Survey/module.xml b/Modules/Survey/module.xml
index 8a15eee2d9ad..02fd603c5c80 100644
--- a/Modules/Survey/module.xml
+++ b/Modules/Survey/module.xml
@@ -28,4 +28,7 @@
+
+
+
diff --git a/Modules/SurveyQuestionPool/Material/class.ilMaterialExplorer.php b/Modules/SurveyQuestionPool/Material/class.ilMaterialExplorer.php
index 327daaf38885..24f05b08e6c5 100644
--- a/Modules/SurveyQuestionPool/Material/class.ilMaterialExplorer.php
+++ b/Modules/SurveyQuestionPool/Material/class.ilMaterialExplorer.php
@@ -42,7 +42,7 @@ public function __construct($a_parent_obj, $a_parent_cmd, $a_selectable_type)
$this->ctrl = $DIC->ctrl();
$tree = $DIC->repositoryTree();
- parent::__construct("rep_exp", $a_parent_obj, $a_parent_cmd, $tree);
+ parent::__construct("mat_rep_exp", $a_parent_obj, $a_parent_cmd, $tree);
$this->current_type = $a_selectable_type;
diff --git a/Modules/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolListGUI.php b/Modules/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolListGUI.php
index 5d30993259d7..e20a018a516f 100644
--- a/Modules/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolListGUI.php
+++ b/Modules/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolListGUI.php
@@ -25,7 +25,7 @@ public function init()
$this->gui_class_name = "ilobjsurveyquestionpoolgui";
// general commands array
- $this->commands = ilObjSurveyQUestionPoolAccess::_getCommands();
+ $this->commands = ilObjSurveyQuestionPoolAccess::_getCommands();
}
diff --git a/Modules/Test/classes/class.ilObjTest.php b/Modules/Test/classes/class.ilObjTest.php
index 6fef5161bf87..477d310196ff 100755
--- a/Modules/Test/classes/class.ilObjTest.php
+++ b/Modules/Test/classes/class.ilObjTest.php
@@ -7086,7 +7086,14 @@ public static function _getAvailableTests($use_object_id = false)
$ilDB = $DIC['ilDB'];
$result_array = array();
- $tests = ilUtil::_getObjectsByOperations("tst", "write", $ilUser->getId(), -1);
+ $tests = array_slice(
+ array_reverse(
+ ilUtil::_getObjectsByOperations("tst", "write", $ilUser->getId(), PHP_INT_MAX)
+ ),
+ 0,
+ 10000
+ );
+
if (count($tests)) {
$titles = ilObject::_prepareCloneSelection($tests, "tst");
foreach ($tests as $ref_id) {
@@ -10598,7 +10605,7 @@ public function getEvaluationAdditionalFields()
{
include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
- $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI(''), 'outEvaluation', $this->getAnonymity());
+ $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI($this->getRefId()), 'outEvaluation', $this->getAnonymity());
return $table_gui->getSelectedColumns();
}
diff --git a/Modules/Test/classes/class.ilObjTestGUI.php b/Modules/Test/classes/class.ilObjTestGUI.php
index ea86ff5947d5..a9a24d883073 100755
--- a/Modules/Test/classes/class.ilObjTestGUI.php
+++ b/Modules/Test/classes/class.ilObjTestGUI.php
@@ -88,8 +88,9 @@ class ilObjTestGUI extends ilObjectGUI
/**
* Constructor
* @access public
+ * @param mixed|null $refId
*/
- public function __construct()
+ public function __construct($refId = null)
{
global $DIC;
$lng = $DIC['lng'];
@@ -101,7 +102,10 @@ public function __construct()
$this->type = "tst";
$this->ctrl = $ilCtrl;
$this->ctrl->saveParameter($this, array("ref_id", "test_ref_id", "calling_test", "test_express_mode", "q_id"));
- parent::__construct("", $_GET["ref_id"], true, false);
+ if (isset($_GET['ref_id']) && is_numeric($_GET['ref_id'])) {
+ $refId = (int) $_GET['ref_id'];
+ }
+ parent::__construct("", (int) $refId, true, false);
if ($this->object instanceof ilObjTest) {
require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
diff --git a/Modules/Test/classes/class.ilParticipantsTestResultsGUI.php b/Modules/Test/classes/class.ilParticipantsTestResultsGUI.php
index 04bcd4392898..d7d812cc093c 100644
--- a/Modules/Test/classes/class.ilParticipantsTestResultsGUI.php
+++ b/Modules/Test/classes/class.ilParticipantsTestResultsGUI.php
@@ -486,10 +486,6 @@ public function createUserResults($show_pass_details, $show_answers, $show_reach
$count = 0;
foreach ($show_user_results as $key => $active_id) {
- if ($this->getTestObj()->getFixedParticipants()) {
- $active_id = $this->getTestObj()->getActiveIdOfUser($active_id);
- }
-
if (!in_array($active_id, $participantData->getActiveIds())) {
continue;
}
diff --git a/Modules/Test/classes/class.ilTestEvaluationData.php b/Modules/Test/classes/class.ilTestEvaluationData.php
index 8a9cff6de9ae..542cde83f18d 100755
--- a/Modules/Test/classes/class.ilTestEvaluationData.php
+++ b/Modules/Test/classes/class.ilTestEvaluationData.php
@@ -205,6 +205,7 @@ public function generateOverview()
$this->getParticipant($row["active_fi"])->getPass($row["pass"])->setNrOfAnsweredQuestions($row["answeredquestions"]);
$this->getParticipant($row["active_fi"])->getPass($row["pass"])->setWorkingTime($row["workingtime"]);
+ $this->getParticipant($row["active_fi"])->getPass($row["pass"])->setExamId((string) $row["exam_id"]);
$this->getParticipant($row['active_fi'])->getPass($row['pass'])->setRequestedHintsCount($row['hint_count']);
$this->getParticipant($row['active_fi'])->getPass($row['pass'])->setDeductedHintPoints($row['hint_points']);
diff --git a/Modules/Test/classes/class.ilTestEvaluationGUI.php b/Modules/Test/classes/class.ilTestEvaluationGUI.php
index 3948db49b3bd..acaef018b1f4 100644
--- a/Modules/Test/classes/class.ilTestEvaluationGUI.php
+++ b/Modules/Test/classes/class.ilTestEvaluationGUI.php
@@ -274,6 +274,7 @@ public function outEvaluation()
$evaluationrow['reached'] = $userdata->getReached();
$evaluationrow['max'] = $userdata->getMaxpoints();
$evaluationrow['hint_count'] = $userdata->getRequestedHintsCountFromScoredPass();
+ $evaluationrow['exam_id'] = $userdata->getExamIdFromScoredPass();
$percentage = $userdata->getReachedPointsInPercent();
$mark = $this->object->getMarkSchema()->getMatchingMark($percentage);
if (is_object($mark)) {
@@ -1017,6 +1018,7 @@ public function outParticipantsPassDetails()
$template->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
+ $this->populateExamId($template, (int) $active_id, (int) $pass);
$this->populatePassFinishDate($template, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
$this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
@@ -1351,6 +1353,7 @@ public function outUserPassDetails()
}
}
+ $this->populateExamId($tpl, (int) $active_id, (int) $pass);
$this->populatePassFinishDate($tpl, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
$this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
diff --git a/Modules/Test/classes/class.ilTestEvaluationPassData.php b/Modules/Test/classes/class.ilTestEvaluationPassData.php
index ef0570722434..e285e91fa7c8 100755
--- a/Modules/Test/classes/class.ilTestEvaluationPassData.php
+++ b/Modules/Test/classes/class.ilTestEvaluationPassData.php
@@ -87,11 +87,14 @@ class ilTestEvaluationPassData
* @var boolean
*/
private $obligationsAnswered = null;
+
+ /** @var string */
+ private $examId = '';
public function __sleep()
{
return array('answeredQuestions', 'pass', 'nrOfAnsweredQuestions', 'reachedpoints',
- 'maxpoints', 'questioncount', 'workingtime');
+ 'maxpoints', 'questioncount', 'workingtime', 'examId');
}
/**
@@ -181,7 +184,7 @@ public function addAnsweredQuestion($question_id, $max_points, $reached_points,
);
}
- public function &getAnsweredQuestion($index)
+ public function getAnsweredQuestion($index)
{
if (array_key_exists($index, $this->answeredQuestions)) {
return $this->answeredQuestions[$index];
@@ -190,7 +193,7 @@ public function &getAnsweredQuestion($index)
}
}
- public function &getAnsweredQuestionByQuestionId($question_id)
+ public function getAnsweredQuestionByQuestionId($question_id)
{
foreach ($this->answeredQuestions as $question) {
if ($question["id"] == $question_id) {
@@ -254,7 +257,23 @@ public function setObligationsAnswered($obligationsAnswered)
{
$this->obligationsAnswered = (bool) $obligationsAnswered;
}
-
+
+ /**
+ * @return string
+ */
+ public function getExamId() : string
+ {
+ return $this->examId;
+ }
+
+ /**
+ * @param string $examId
+ */
+ public function setExamId(string $examId) : void
+ {
+ $this->examId = $examId;
+ }
+
/**
* getter for property obligationsAnswered.
* if property wasn't set yet the method is trying
diff --git a/Modules/Test/classes/class.ilTestEvaluationUserData.php b/Modules/Test/classes/class.ilTestEvaluationUserData.php
index 571c09087e66..d7780f2c98fb 100755
--- a/Modules/Test/classes/class.ilTestEvaluationUserData.php
+++ b/Modules/Test/classes/class.ilTestEvaluationUserData.php
@@ -123,7 +123,7 @@ class ilTestEvaluationUserData
/**
* Test passes
*
- * @var array
+ * @var array
*/
public $passes;
@@ -340,13 +340,21 @@ public function getPasses()
{
return $this->passes;
}
-
+
+ /**
+ * @param int $pass_nr
+ * @param ilTestEvaluationPassData $pass
+ */
public function addPass($pass_nr, $pass)
{
$this->passes[$pass_nr] = $pass;
}
-
- public function &getPass($pass_nr)
+
+ /**
+ * @param $pass_nr
+ * @return ilTestEvaluationPassData|null
+ */
+ public function getPass($pass_nr)
{
if (array_key_exists($pass_nr, $this->passes)) {
return $this->passes[$pass_nr];
@@ -409,7 +417,7 @@ public function getQuestionTitles()
return $this->questionTitles;
}
- public function &getQuestions($pass = 0)
+ public function getQuestions($pass = 0)
{
if (array_key_exists($pass, $this->questions)) {
return $this->questions[$pass];
@@ -432,7 +440,7 @@ public function addQuestion($original_id, $question_id, $max_points, $sequence =
);
}
- public function &getQuestion($index, $pass = 0)
+ public function getQuestion($index, $pass = 0)
{
if (array_key_exists($index, $this->questions[$pass])) {
return $this->questions[$pass][$index];
@@ -527,6 +535,21 @@ public function getRequestedHintsCountFromScoredPass()
{
return $this->getRequestedHintsCount($this->getScoredPass());
}
+
+ /**
+ * @return string
+ */
+ public function getExamIdFromScoredPass() : string
+ {
+ $examId = '';
+ $scoredPass = $this->getScoredPass();
+
+ if (isset($this->passes[$scoredPass]) && $this->passes[$scoredPass] instanceof ilTestEvaluationPassData) {
+ $examId = $this->passes[$scoredPass]->getExamId();
+ }
+
+ return $examId;
+ }
/**
* returns the count of hints requested by participant for given testpass
diff --git a/Modules/Test/classes/class.ilTestExport.php b/Modules/Test/classes/class.ilTestExport.php
index 4c032aa41776..623a00e3062a 100755
--- a/Modules/Test/classes/class.ilTestExport.php
+++ b/Modules/Test/classes/class.ilTestExport.php
@@ -354,6 +354,10 @@ public function exportToExcel($deliver = true, $filterby = "", $filtertext = "",
if (count($additionalFields)) {
foreach ($additionalFields as $fieldname) {
+ if (strcmp($fieldname, "exam_id") == 0) {
+ $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('exam_id_label'));
+ continue;
+ }
$worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt($fieldname));
}
}
@@ -411,6 +415,8 @@ public function exportToExcel($deliver = true, $filterby = "", $filtertext = "",
foreach ($additionalFields as $fieldname) {
if (strcmp($fieldname, 'gender') == 0) {
$worksheet->setCell($row, $col++, $this->lng->txt('gender_' . $userfields[$fieldname]));
+ } elseif (strcmp($fieldname, "exam_id") == 0) {
+ $worksheet->setCell($row, $col++, $userdata->getExamIdFromScoredPass());
} else {
$worksheet->setCell($row, $col++, $userfields[$fieldname]);
}
@@ -547,6 +553,9 @@ public function exportToExcel($deliver = true, $filterby = "", $filtertext = "",
if (strcmp($fieldname, "matriculation") == 0) {
$worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('matriculation'));
}
+ if (strcmp($fieldname, "exam_id") == 0) {
+ $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('exam_id_label'));
+ }
}
}
$worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('test'));
@@ -577,6 +586,13 @@ public function exportToExcel($deliver = true, $filterby = "", $filtertext = "",
$col++;
}
}
+ if (strcmp($fieldname, "exam_id") == 0) {
+ if (strlen($userfields[$fieldname])) {
+ $worksheet->setCell($row, $col++, $userdata->getExamIdFromScoredPass());
+ } else {
+ $col++;
+ }
+ }
}
}
$worksheet->setCell($row, $col++, $this->test_obj->getTitle());
@@ -618,6 +634,9 @@ public function exportToExcel($deliver = true, $filterby = "", $filtertext = "",
if (strcmp($fieldname, "matriculation") == 0) {
$worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('matriculation'));
}
+ if (strcmp($fieldname, "exam_id") == 0) {
+ $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('exam_id_label'));
+ }
}
}
$worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('test'));
@@ -648,6 +667,13 @@ public function exportToExcel($deliver = true, $filterby = "", $filtertext = "",
$col++;
}
}
+ if (strcmp($fieldname, "exam_id") == 0) {
+ if (strlen($userfields[$fieldname])) {
+ $worksheet->setCell($row, $col++, $userdata->getExamIdFromScoredPass());
+ } else {
+ $col++;
+ }
+ }
}
}
$worksheet->setCell($row, $col++, $this->test_obj->getTitle());
@@ -764,6 +790,11 @@ public function exportToCSV($deliver = true, $filterby = "", $filtertext = "", $
$additionalFields = $this->test_obj->getEvaluationAdditionalFields();
if (count($additionalFields)) {
foreach ($additionalFields as $fieldname) {
+ if (strcmp($fieldname, "exam_id") == 0) {
+ array_push($datarow, $this->lng->txt('exam_id_label'));
+ $col++;
+ continue;
+ }
array_push($datarow, $this->lng->txt($fieldname));
$col++;
}
@@ -833,6 +864,8 @@ public function exportToCSV($deliver = true, $filterby = "", $filtertext = "", $
foreach ($additionalFields as $fieldname) {
if (strcmp($fieldname, "gender") == 0) {
array_push($datarow2, $this->lng->txt("gender_" . $userfields[$fieldname]));
+ } elseif (strcmp($fieldname, "exam_id") == 0) {
+ array_push($datarow2, $userdata->getExamIdFromScoredPass());
} else {
array_push($datarow2, $userfields[$fieldname]);
}
diff --git a/Modules/Test/classes/class.ilTestLP.php b/Modules/Test/classes/class.ilTestLP.php
index 4d1a3ed9d3e6..db1b0524744c 100644
--- a/Modules/Test/classes/class.ilTestLP.php
+++ b/Modules/Test/classes/class.ilTestLP.php
@@ -109,7 +109,7 @@ protected static function isLPMember(array &$a_res, $a_usr_id, $a_obj_ids)
$set = $ilDB->query("SELECT tt.obj_fi" .
" FROM tst_active ta" .
" JOIN tst_tests tt ON (ta.test_fi = tt.test_id)" .
- " WHERE " . $ilDB->in("tt.obj_fi", (array) $a_obj_ids, "", "integer") .
+ " WHERE " . $ilDB->in("tt.obj_fi", (array) $a_obj_ids, false, "integer") .
" AND ta.user_fi = " . $ilDB->quote($a_usr_id, "integer"));
while ($row = $ilDB->fetchAssoc($set)) {
$a_res[$row["obj_fi"]] = true;
diff --git a/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php b/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php
index 24a997355184..979d6ba507f3 100755
--- a/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php
+++ b/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php
@@ -1483,6 +1483,9 @@ public function outProcessingTime($active_id)
$this->tpl->setVariable("USER_REMAINING_TIME", sprintf($this->lng->txt("tst_time_already_spent_left"), $str_time_left));
$this->tpl->parseCurrentBlock();
+ // jQuery is required by tpl.workingtime.js
+ require_once "./Services/jQuery/classes/class.iljQueryUtil.php";
+ iljQueryUtil::initjQuery();
$template = new ilTemplate("tpl.workingtime.js", true, true, 'Modules/Test');
$template->setVariable("STRING_MINUTE", $this->lng->txt("minute"));
$template->setVariable("STRING_MINUTES", $this->lng->txt("minutes"));
@@ -1557,13 +1560,19 @@ abstract protected function isQuestionSummaryFinishTestButtonRequired();
/**
* Output of a summary of all test questions for test participants
*/
- public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = false, $obligationsNotAnswered = false, $obligationsFilter = false)
+ public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = false, $obligationsInfo = false, $obligationsFilter = false)
{
if ($fullpage) {
$this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_question_summary.html", "Modules/Test");
}
-
- if ($obligationsNotAnswered) {
+
+ $obligationsFulfilled = \ilObjTest::allObligationsAnswered(
+ $this->object->getId(),
+ $this->testSession->getActiveId(),
+ $this->testSession->getPass()
+ );
+
+ if ($obligationsInfo && $this->object->areObligationsEnabled() && !$obligationsFulfilled) {
ilUtil::sendFailure($this->lng->txt('not_all_obligations_answered'));
}
@@ -1588,7 +1597,7 @@ public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = fal
$table_gui->setShowPointsEnabled(!$this->object->getTitleOutput());
$table_gui->setShowMarkerEnabled($this->object->getShowMarker());
- $table_gui->setObligationsNotAnswered($obligationsNotAnswered);
+ $table_gui->setObligationsNotAnswered(!$obligationsFulfilled);
$table_gui->setShowObligationsEnabled($this->object->areObligationsEnabled());
$table_gui->setObligationsFilterEnabled($obligationsFilter);
$table_gui->setFinishTestButtonEnabled($this->isQuestionSummaryFinishTestButtonRequired());
@@ -1602,6 +1611,17 @@ public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = fal
if ($this->object->getEnableProcessingTime()) {
$this->outProcessingTime($active_id);
}
+
+ if ($this->object->isShowExamIdInTestPassEnabled()) {
+ $this->tpl->setCurrentBlock('exam_id_footer');
+ $this->tpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
+ $this->testSession->getActiveId(),
+ $this->testSession->getPass(),
+ $this->object->getId()
+ ));
+ $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
+ $this->tpl->parseCurrentBlock();
+ }
}
}
@@ -2569,10 +2589,6 @@ protected function populateModals()
$this->populateNextLocksUnchangedModal();
}
-
- if ($this->object->getKioskMode()) {
- $this->tpl->addJavaScript(ilUIFramework::BOWER_BOOTSTRAP_JS, true);
- }
}
protected function populateDiscardSolutionModal()
diff --git a/Modules/Test/classes/class.ilTestScoringByQuestionsGUI.php b/Modules/Test/classes/class.ilTestScoringByQuestionsGUI.php
index 6249df535590..07bf6cc555a5 100644
--- a/Modules/Test/classes/class.ilTestScoringByQuestionsGUI.php
+++ b/Modules/Test/classes/class.ilTestScoringByQuestionsGUI.php
@@ -359,6 +359,22 @@ protected function getAnswerDetail()
$data = $this->object->getCompleteEvaluationData(false);
$participant = $data->getParticipant($active_id);
$question_gui = $this->object->createQuestionGUI('', $question_id);
+ $tmp_tpl = new ilTemplate('tpl.il_as_tst_correct_solution_output.html', true, true, 'Modules/Test');
+ if($question_gui instanceof assTextQuestionGUI && $this->object->getAutosave()) {
+ $aresult_output = $question_gui->getAutoSavedSolutionOutput(
+ $active_id,
+ $pass,
+ false,
+ false,
+ false,
+ $this->object->getShowSolutionFeedback(),
+ false,
+ true
+ );
+ $tmp_tpl->setVariable('TEXT_ASOLUTION_OUTPUT', $this->lng->txt('autosavecontent'));
+ $tmp_tpl->setVariable('ASOLUTION_OUTPUT', $aresult_output);
+
+ }
$result_output = $question_gui->getSolutionOutput(
$active_id,
$pass,
@@ -370,7 +386,7 @@ protected function getAnswerDetail()
true
);
$max_points = $question_gui->object->getMaximumPoints();
- $tmp_tpl = new ilTemplate('tpl.il_as_tst_correct_solution_output.html', true, true, 'Modules/Test');
+
$this->appendUserNameToModal($tmp_tpl, $participant);
$this->appendQuestionTitleToModal($tmp_tpl, $question_id, $max_points, $question_gui->object->getTitle());
$this->appendSolutionAndPointsToModal(
@@ -401,6 +417,7 @@ protected function getAnswerDetail()
$question_title . ' (' . $max_points . ' ' . $lng . ')' . $add_title
);
$tmp_tpl->setVariable('SOLUTION_OUTPUT', $result_output);
+
$tmp_tpl->setVariable(
'RECEIVED_POINTS',
sprintf(
diff --git a/Modules/Test/classes/class.ilTestServiceGUI.php b/Modules/Test/classes/class.ilTestServiceGUI.php
index ccc91f26e804..5afdf8f78da3 100755
--- a/Modules/Test/classes/class.ilTestServiceGUI.php
+++ b/Modules/Test/classes/class.ilTestServiceGUI.php
@@ -857,6 +857,7 @@ public function getResultsOfUserOutput($testSession, $active_id, $pass, $targetG
$template->setVariable("TEXT_HEADING", sprintf($this->lng->txt("tst_result_user_name"), $uname));
$template->setVariable("USER_DATA", $user_data);
+ $this->populateExamId($template, (int) $active_id, (int) $pass);
$this->populatePassFinishDate($template, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
return $template->get();
@@ -1198,6 +1199,22 @@ public function populatePassFinishDate($tpl, $passFinishDate)
$tpl->setVariable("PASS_FINISH_DATE_LABEL", $this->lng->txt('tst_pass_finished_on'));
$tpl->setVariable("PASS_FINISH_DATE_VALUE", $passFinishDate);
}
+
+ /**
+ * @param ilTemplate $tpl
+ * @param int $activeId
+ * @param int $pass
+ */
+ public function populateExamId(ilTemplate $tpl, int $activeId, int $pass)
+ {
+ if ($this->object->isShowExamIdInTestResultsEnabled()) {
+ $tpl->setVariable("EXAM_ID_TXT", $this->lng->txt('exam_id'));
+ $tpl->setVariable('EXAM_ID', ilObjTest::lookupExamId(
+ $activeId,
+ $pass
+ ));
+ }
+ }
}
// internal sort function to sort the result array
diff --git a/Modules/Test/classes/class.ilTestSubmissionReviewGUI.php b/Modules/Test/classes/class.ilTestSubmissionReviewGUI.php
index e07532f16b57..1286501d36fa 100644
--- a/Modules/Test/classes/class.ilTestSubmissionReviewGUI.php
+++ b/Modules/Test/classes/class.ilTestSubmissionReviewGUI.php
@@ -185,8 +185,21 @@ protected function show()
$html = $this->buildToolbar('review_nav_top')->getHTML();
$html .= $this->buildUserReviewOutput() . ' ';
$html .= $this->buildToolbar('review_nav_bottom')->getHTML();
+
+ if ($this->object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode()) {
+ $examIdTpl = new ilTemplate("tpl.exam_id_block.html", true, true, 'Modules/Test');
+ $examIdTpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
+ $this->testSession->getActiveId(),
+ $this->testSession->getPass(),
+ $this->object->getId()
+ ));
+ $examIdTpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
+ $html .= $examIdTpl->get();
+ }
- $this->tpl->setVariable($this->getContentBlockName(), $html);
+ $this->tpl->setVariable(
+ $this->getContentBlockName(), $html
+ );
}
protected function pdfDownload()
diff --git a/Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php b/Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php
index c791dca90308..2f8b71565d92 100644
--- a/Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php
+++ b/Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php
@@ -51,6 +51,9 @@ public function __construct($a_parent_obj, $a_parent_cmd, $anonymity = false, $o
if (strcmp($c, 'email') == 0) {
$this->addColumn($this->lng->txt("email"), 'email', '');
}
+ if (strcmp($c, 'exam_id') == 0 && $this->parent_obj->object->isShowExamIdInTestResultsEnabled()) {
+ $this->addColumn($this->lng->txt("exam_id_label"), 'exam_id', '');
+ }
if (strcmp($c, 'institution') == 0) {
$this->addColumn($this->lng->txt("institution"), 'institution', '');
}
@@ -133,6 +136,7 @@ public function numericOrdering($a_field)
break;
case 'reached':
case 'hint_count':
+ case 'exam_id':
case 'answered':
return true;
break;
@@ -191,6 +195,12 @@ public function getSelectableColumns()
"txt" => $lng->txt("matriculation"),
"default" => false
);
+ if ($this->parent_obj->object->isShowExamIdInTestResultsEnabled()) {
+ $cols["exam_id"] = array(
+ "txt" => $lng->txt("exam_id_label"),
+ "default" => false
+ );
+ }
}
if ($this->parent_obj->object->getECTSOutput()) {
$cols["ects_grade"] = array(
@@ -308,6 +318,12 @@ protected function fillRow($data)
$this->tpl->setVariable("MATRICULATION", strlen($data['matriculation']) ? $data['matriculation'] : ' ');
$this->tpl->parseCurrentBlock();
}
+ if (strcmp($c, 'exam_id') == 0 && $this->parent_obj->object->isShowExamIdInTestResultsEnabled()) {
+ $this->tpl->setCurrentBlock('exam_id');
+ $examId = is_string($data['exam_id']) && strlen($data['exam_id']) ? $data['exam_id'] : ' ';
+ $this->tpl->setVariable('EXAM_ID', $examId);
+ $this->tpl->parseCurrentBlock();
+ }
}
if ($this->parent_obj->object->getECTSOutput()) {
if (strcmp($c, 'ects_grade') == 0) {
diff --git a/Modules/Test/templates/default/tpl.exam_id_block.html b/Modules/Test/templates/default/tpl.exam_id_block.html
new file mode 100644
index 000000000000..8dd2564e5c28
--- /dev/null
+++ b/Modules/Test/templates/default/tpl.exam_id_block.html
@@ -0,0 +1 @@
+
{EXAM_ID_TXT} {EXAM_ID_VAL}
\ No newline at end of file
diff --git a/Modules/Test/templates/default/tpl.il_as_tst_correct_solution_output.html b/Modules/Test/templates/default/tpl.il_as_tst_correct_solution_output.html
index a2a44fefac1d..d8c23736ff5d 100755
--- a/Modules/Test/templates/default/tpl.il_as_tst_correct_solution_output.html
+++ b/Modules/Test/templates/default/tpl.il_as_tst_correct_solution_output.html
@@ -12,6 +12,11 @@
{QUESTION_TITLE}
{TEXT_SOLUTION_OUTPUT}:
{SOLUTION_OUTPUT}
+
+
{TEXT_ASOLUTION_OUTPUT}:
+ {ASOLUTION_OUTPUT}
+
+
{TEXT_RECEIVED_POINTS}:
{RECEIVED_POINTS}
diff --git a/Modules/Test/templates/default/tpl.il_as_tst_question_summary.html b/Modules/Test/templates/default/tpl.il_as_tst_question_summary.html
index ffb94ac33203..e6e17b5c2cef 100644
--- a/Modules/Test/templates/default/tpl.il_as_tst_question_summary.html
+++ b/Modules/Test/templates/default/tpl.il_as_tst_question_summary.html
@@ -11,4 +11,7 @@
{TEXT_CANCELTEST}
-{TABLE_LIST_OF_QUESTIONS}
\ No newline at end of file
+{TABLE_LIST_OF_QUESTIONS}
+
+
{EXAM_ID_TXT} {EXAM_ID_VAL}
+
\ No newline at end of file
diff --git a/Modules/Test/templates/default/tpl.table_evaluation_all.html b/Modules/Test/templates/default/tpl.table_evaluation_all.html
index 61196522320b..d8eacc08bfc4 100644
--- a/Modules/Test/templates/default/tpl.table_evaluation_all.html
+++ b/Modules/Test/templates/default/tpl.table_evaluation_all.html
@@ -10,6 +10,7 @@
{COUNTRY}
{DEPARTMENT}
{MATRICULATION}
+
{EXAM_ID}
{REACHED}
{HINT_COUNT}
{MARK}
diff --git a/Modules/Test/templates/default/tpl.workingtime.js b/Modules/Test/templates/default/tpl.workingtime.js
index 5c1a714191ad..bbde116a5e41 100644
--- a/Modules/Test/templates/default/tpl.workingtime.js
+++ b/Modules/Test/templates/default/tpl.workingtime.js
@@ -1,45 +1,104 @@
- var serverdate = -1;
- var unsaved = true;
-
- function setWorkingTime()
- {
- if (serverdate == -1)
- {
- var n = new Date({YEAR}, {MONTHNOW}, {DAYNOW}, {HOURNOW}, {MINUTENOW}, {SECONDNOW});
- serverdate = n.getTime() / 1000;
+/*global il:false, jQuery:false*/
+(function(w, $) {
+
+ var test_end = -1,
+ local_timer_start = -1,
+ unsaved = true,
+ interval = 0;
+
+ if (w.performance) {
+ local_timer_start = performance.now();
+ }
+
+ var server_date = (new Date({YEAR}, {MONTHNOW}, {DAYNOW}, {HOURNOW}, {MINUTENOW}, {SECONDNOW})).getTime() / 1000,
+ // first tick happens immediately, and older browser use tick-based
+ // counter which increments as soon as jQuery fires $(document).ready
+ now = server_date - 1,
+ test_start = (new Date({YEAR}, {MONTH}, {DAY}, {HOUR}, {MINUTE}, {SECOND})).getTime() / 1000,
+ test_time_min = {PTIME_M},
+ test_time_sec = {PTIME_S},
+ minute = "{STRING_MINUTE}",
+ minutes = "{STRING_MINUTES}",
+ second = "{STRING_SECOND}",
+ seconds = "{STRING_SECONDS}",
+ timeleft = "{STRING_TIMELEFT}",
+ redirectUrl = "{REDIRECT_URL}",
+ and = "{AND}",
+ time_left_span;
+
+
+ test_end = (new Date({ENDYEAR}, {ENDMONTH}, {ENDDAY}, {ENDHOUR}, {ENDMINUTE}, {ENDSECOND})).getTime() / 1000;
+
+
+ /**
+ * invoke test player's auto-save if available
+ */
+ function autoSave() {
+ unsaved = false;
+ if (typeof il.TestPlayerQuestionEditControl !== 'undefined') {
+ il.TestPlayerQuestionEditControl.saveOnTimeReached();
}
- else
- {
- serverdate++;
+ }
+
+ /**
+ * submit form to redirectUrl
+ */
+ function redirect() {
+ $("#listofquestions").attr('action', redirectUrl).submit();
+ }
+
+ /**
+ * Format a "time left" string from parameters provided.
+ * @param {Number} avail Time available in full seconds.
+ * @param {Number} avail_m Full minutes available.
+ * @param {Number} avail_s Seconds available subtracted by full minutes (i.e. avail mod 60).
+ * @return {String} Text telling how much time is left to finish the test in user's language
+ */
+ function formatString(avail, avail_m, avail_s) {
+ var output = avail_m + " ";
+ if (avail_m === 1) {
+ output += minute;
+ } else {
+ output += minutes;
}
- var startd = new Date({YEAR}, {MONTH}, {DAY}, {HOUR}, {MINUTE}, {SECOND});
- var enddtime = -1;
-
- var endd = new Date({ENDYEAR}, {ENDMONTH}, {ENDDAY}, {ENDHOUR}, {ENDMINUTE}, {ENDSECOND});
- enddtime = endd.getTime() / 1000;
-
- var ptime_m = {PTIME_M};
- var ptime_s = {PTIME_S};
- var minute = "{STRING_MINUTE}";
- var minutes = "{STRING_MINUTES}";
- var second = "{STRING_SECOND}";
- var seconds = "{STRING_SECONDS}";
- var timeleft = "{STRING_TIMELEFT}";
- var redirectUrl = "{REDIRECT_URL}";
- var and = "{AND}";
- var now = serverdate;
- var then = startd.getTime() / 1000;
+ // show seconds if less than 5min (300s) left
+ if (avail < 300) {
+ if (avail_s < 10) {
+ output += " " + and + " 0" + avail_s + " ";
+ } else {
+ output += " " + and + " " + avail_s + " ";
+ }
+ if (avail_m == 0) {
+ if (avail_s < 10) {
+ output = "0" + avail_s + " ";
+ } else {
+ output = avail_s + " ";
+ }
+ }
+ if (avail_s == 1) {
+ output += second;
+ } else {
+ output += seconds;
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Calculate remaining working time and dispatch actions based on that
+ */
+ function setWorkingTime() {
// time since start in seconds
- var diff = Math.floor(now - then);
- // available time
- var avail = ptime_m * 60 + ptime_s - diff;
- if (avail < 0)
- {
+ var diff = Math.floor(now - test_start),
+ // available time
+ avail = test_time_min * 60 + test_time_sec - diff,
+ avail_m, avail_s, output;
+
+ if (avail < 0) {
avail = 0;
}
- if (enddtime > -1)
- {
- var diffToEnd = Math.floor(enddtime - now);
+ if (test_end > -1) {
+ var diffToEnd = Math.floor(test_end - now);
if ((diffToEnd > 0) && (diffToEnd < avail))
{
avail = diffToEnd;
@@ -49,64 +108,49 @@
avail = 0;
}
}
- if ((avail <= 0) && unsaved)
- {
- unsaved = false;
-// fau: testNav - call saveOnTimeReached in the new control script
- if (typeof il.TestPlayerQuestionEditControl != 'undefined')
- {
- il.TestPlayerQuestionEditControl.saveOnTimeReached();
- }
-// fau.
+ if ((avail <= 0) && unsaved) {
+ autoSave();
}
- if((avail <= 0) && redirectUrl != "") {
- $("#listofquestions").attr('action', redirectUrl).submit();
+ if((avail <= 0) && redirectUrl !== "") {
+ redirect();
}
- var avail_m = Math.floor(avail / 60);
- var avail_s = avail - (avail_m * 60);
- var output = avail_m + " ";
- if (avail_m == 1)
- {
- output += minute;
- }
- else
- {
- output += minutes;
- }
- if (avail < 300)
- {
- if (avail_s < 10)
- {
- output += " " + and + " 0" + avail_s + " ";
- }
- else
- {
- output += " " + and + " " + avail_s + " ";
- }
- if (avail_m == 0)
- {
- if (avail_s < 10)
- {
- output = "0" + avail_s + " ";
- }
- else
- {
- output = avail_s + " ";
- }
- }
- if (avail_s == 1)
- {
- output += second;
- }
- else
- {
- output += seconds;
+ avail_m = Math.floor(avail / 60);
+ avail_s = avail - (avail_m * 60);
+ output = formatString(avail, avail_m, avail_s);
+
+ time_left_span.html( timeleft.replace(/%s/, output) );
+ }
+
+ /**
+ * MUST be invoked every 1000ms in older browsers
+ * (SHOULD for those that support window.performance)
+ */
+ function tick() {
+ if (local_timer_start >= 0) {
+ // use performance API
+ var local_timer_now = performance.now();
+ if (local_timer_now >= local_timer_start) {
+ // floor in order to ensure the test is not submitted before end
+ // in which case ILIAS would display "autosave [failed|succeeded]"
+ // and not "the test ended ..."
+ now = Math.floor(server_date + (local_timer_now - local_timer_start) / 1000);
+ } else {
+ // result by performance API does not make sense, maybe it's broken
+ // in this browser/version or blocked by a privacy plugin
+ now++;
}
+ } else {
+ // performance API unsupported by client
+ now++;
}
- var span = document.getElementById("timeleft");
- span.innerHTML = timeleft.replace(/%s/, output);
+ setWorkingTime();
}
- window.setWorkingTime = setWorkingTime;
-
- window.setInterval('setWorkingTime()',1000);
\ No newline at end of file
+
+ $(function() {
+ time_left_span = $('#timeleft');
+ tick();
+ interval = w.setInterval(tick, 1000);
+ });
+
+}(window, jQuery));
diff --git a/Modules/TestQuestionPool/classes/class.assClozeTest.php b/Modules/TestQuestionPool/classes/class.assClozeTest.php
index ffd3c7afa8df..edfed90aac48 100755
--- a/Modules/TestQuestionPool/classes/class.assClozeTest.php
+++ b/Modules/TestQuestionPool/classes/class.assClozeTest.php
@@ -43,7 +43,7 @@ class assClozeTest extends assQuestion implements ilObjQuestionScoringAdjustable
public $gap_combinations_exists;
-
+
/**
* The start tag beginning a cloze gap
*
@@ -61,7 +61,7 @@ class assClozeTest extends assQuestion implements ilObjQuestionScoringAdjustable
* @var string
*/
public $end_tag;
-
+
/**
* The rating option for text gaps
*
@@ -93,12 +93,12 @@ class assClozeTest extends assQuestion implements ilObjQuestionScoringAdjustable
public $fixedTextLength;
public $cloze_text;
-
+
/**
* @var ilAssClozeTestFeedback
*/
public $feedbackOBJ;
-
+
protected $feedbackMode = ilAssClozeTestFeedback::FB_MODE_GAP_QUESTION;
/**
@@ -158,12 +158,30 @@ public function isComplete()
*/
public function cleanQuestiontext($text)
{
- $text = preg_replace("/\[gap[^\]]*?\]/", "[gap]", $text);
+ // fau: fixGapReplace - mask dollars for replacement
+ $text = str_replace('$','GAPMASKEDDOLLAR', $text);$text = preg_replace("/\[gap[^\]]*?\]/", "[gap]", $text);
$text = preg_replace("/\]*?)\>/", "[gap]", $text);
- $text = str_replace("", "[/gap]", $text);
+ $text = str_replace("", "[/gap]", $text);$text = str_replace('GAPMASKEDDOLLAR', '$', $text);
+// fau.
return $text;
}
+ // fau: fixGapReplace - add function replaceFirstGap()
+ /**
+ * Replace the first gap in a string without treating backreferences
+ * @param string $gaptext text with gap tags
+ * @param string $content content for the first gap
+ * @return string
+ */
+ public function replaceFirstGap($gaptext, $content)
+ {
+ $content = str_replace('$','GAPMASKEDDOLLAR', $content);
+ $output = preg_replace("/\[gap\].*?\[\/gap\]/", $content, $gaptext, 1);
+ $output = str_replace('GAPMASKEDDOLLAR', '$', $output);
+
+ return $output;
+ }
+// fau.
/**
* Loads a assClozeTest object from a database
*
@@ -208,7 +226,7 @@ public function loadFromDb($question_id)
$this->cloze_text = ilRTE::_replaceMediaObjectImageSrc($this->cloze_text, 1);
$this->setTextgapRating($data["textgap_rating"]);
$this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
-
+
try {
$this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
} catch (ilTestQuestionPoolException $e) {
@@ -236,7 +254,7 @@ public function loadFromDb($question_id)
$data["aorder"]
);
$this->gaps[$data["gap_id"]]->setGapSize($data['gap_size']);
-
+
$this->gaps[$data["gap_id"]]->addItem($answer);
break;
case CLOZE_SELECT:
@@ -279,7 +297,7 @@ public function loadFromDb($question_id)
}
#region Save question to db
-
+
/**
* Saves a assClozeTest object to a database
*
@@ -305,7 +323,7 @@ public function saveAnswerSpecificDataToDb()
{
global $DIC;
$ilDB = $DIC['ilDB'];
-
+
$ilDB->manipulateF(
"DELETE FROM qpl_a_cloze WHERE question_fi = %s",
array( "integer" ),
@@ -325,14 +343,14 @@ public function saveAnswerSpecificDataToDb()
public function saveAdditionalQuestionDataToDb()
{
global $DIC; /* @var ILIAS\DI\Container $DIC */
-
-
+
+
$DIC->database()->manipulateF(
"DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
array( "integer" ),
array( $this->getId() )
);
-
+
$DIC->database()->insert($this->getAdditionalTableName(), array(
'question_fi' => array('integer', $this->getId()),
'textgap_rating' => array('text', $this->getTextgapRating()),
@@ -456,7 +474,7 @@ protected function saveClozeNumericGapRecordToDb($next_id, $key, $item, $gap)
{
global $DIC;
$ilDB = $DIC['ilDB'];
-
+
include_once "./Services/Math/classes/class.EvalMath.php";
$eval = new EvalMath();
$eval->suppress_errors = true;
@@ -541,7 +559,7 @@ public function setClozeTextValue($cloze_text = "")
{
$this->cloze_text = $cloze_text;
}
-
+
/**
* Returns the cloze text
*
@@ -577,7 +595,7 @@ public function setStartTag($start_tag = "[gap]")
{
$this->start_tag = $start_tag;
}
-
+
/**
* Returns the end tag of a cloze gap
*
@@ -601,7 +619,7 @@ public function setEndTag($end_tag = "[/gap]")
{
$this->end_tag = $end_tag;
}
-
+
/**
* @return string
*/
@@ -609,7 +627,7 @@ public function getFeedbackMode()
{
return $this->feedbackMode;
}
-
+
/**
* @param string $feedbackMode
*/
@@ -644,7 +662,7 @@ public function createGapsFromQuestiontext()
}
}
}
-
+
/**
* Set the type of a gap with a given index
*
@@ -722,7 +740,7 @@ public function addGapAnswer($gap_index, $order, $answer)
$this->gaps[$gap_index]->addItem(new assAnswerCloze($answer, 0, $order));
}
}
-
+
/**
* Returns the gap at a given index
*
@@ -746,7 +764,7 @@ public function setGapSize($gap_index, $order, $size)
$this->gaps[$gap_index]->setGapSize($size);
}
}
-
+
/**
* Sets the points of a gap with a given index and an answer with a given order. The index of the first
* gap is 0, the index of the second gap is 1 and so on.
@@ -784,7 +802,7 @@ public function addGapText($gap_index)
$this->gaps[$gap_index]->addItem($answer);
}
}
-
+
/**
* Adds a ClozeGap object at a given index
*
@@ -876,7 +894,7 @@ public function getMaximumPoints()
}
}
}
-
+
return $points;
}
@@ -894,16 +912,16 @@ public function duplicate($for_test = true, $title = "", $author = "", $owner =
// duplicate the question in database
$this_id = $this->getId();
$thisObjId = $this->getObjId();
-
+
$clone = $this;
include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
$original_id = assQuestion::_getOriginalId($this->id);
$clone->id = -1;
-
+
if ((int) $testObjId > 0) {
$clone->setObjId($testObjId);
}
-
+
if ($title) {
$clone->setTitle($title);
}
@@ -935,7 +953,7 @@ public function duplicate($for_test = true, $title = "", $author = "", $owner =
return $clone->getId();
}
-
+
/**
* Copies an assClozeTest object
*
@@ -947,10 +965,10 @@ public function copyObject($target_questionpool_id, $title = "")
// The question has not been saved. It cannot be duplicated
return;
}
-
+
$thisId = $this->getId();
$thisObjId = $this->getObjId();
-
+
$clone = $this;
include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
$original_id = assQuestion::_getOriginalId($this->getId());
@@ -973,7 +991,7 @@ public function copyObject($target_questionpool_id, $title = "")
$clone->copyXHTMLMediaObjectsOfQuestion($original_id);
$clone->onCopy($thisObjId, $thisId, $clone->getObjId(), $clone->getId());
-
+
return $clone->getId();
}
@@ -1000,7 +1018,7 @@ public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuest
}
$clone->saveToDb();
-
+
if ($this->gap_combinations_exists) {
$this->copyGapCombination($sourceQuestionId, $clone->getId());
$clone->saveToDb();
@@ -1014,7 +1032,7 @@ public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuest
return $clone->id;
}
-
+
public function copyGapCombination($orgID, $newID)
{
$assClozeGapCombinationObj = new assClozeGapCombination();
@@ -1035,12 +1053,14 @@ public function updateClozeTextFromGaps()
foreach ($gap->getItemsRaw() as $item) {
array_push($answers, str_replace(",", "\\,", $item->getAnswerText()));
}
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", "[_gap]" . $this->prepareTextareaOutput(join(",", $answers), true) . "[/_gap]", $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->replaceFirstGap($output, "[_gap]" . $this->prepareTextareaOutput(join(",", $answers), true) . "[/_gap]");
+// fau.
}
$output = str_replace("_gap]", "gap]", $output);
$this->cloze_text = $output;
}
-
+
/**
* Deletes the answer text of a gap with a given index and an answer with a given order. The index of the first
* gap is 0, the index of the second gap is 1 and so on.
@@ -1082,9 +1102,13 @@ public function deleteGap($gap_index)
array_push($answers, str_replace(",", "\\,", $item->getAnswerText()));
}
if ($replace_gap_index == $gap_index) {
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", "", $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->replaceFirstGap($output, '');
+// fau.
} else {
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", "[_gap]" . join(",", $answers) . "[/_gap]", $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->replaceFirstGap($output, "[_gap]" . join(",", $answers) . "[/_gap]");
+// fau.
}
}
$output = str_replace("_gap]", "gap]", $output);
@@ -1147,7 +1171,7 @@ public function getTextgapPoints($a_original, $a_entered, $max_points)
}
return $result;
}
-
+
/**
* Returns the points for a text gap and compares the given solution with
* the entered solution using the text gap rating options.
@@ -1215,7 +1239,7 @@ public function calculateReachedPoints($active_id, $pass = null, $authorized = t
{
global $DIC;
$ilDB = $DIC['ilDB'];
-
+
if (is_null($pass)) {
$pass = $this->getSolutionMaxPass($active_id);
}
@@ -1230,7 +1254,7 @@ public function calculateReachedPoints($active_id, $pass = null, $authorized = t
);
}
}
-
+
ksort($user_result); // this is required when identical scoring for same solutions is disabled
if ($returndetails) {
@@ -1238,45 +1262,45 @@ public function calculateReachedPoints($active_id, $pass = null, $authorized = t
$this->calculateReachedPointsForSolution($user_result, $detailed);
return $detailed;
}
-
+
return $this->calculateReachedPointsForSolution($user_result);
}
-
+
protected function isValidNumericSubmitValue($submittedValue)
{
if (is_numeric($submittedValue)) {
return true;
}
-
+
if (preg_match('/^[-+]{0,1}\d+\/\d+$/', $submittedValue)) {
return true;
}
-
+
return false;
}
-
+
public function validateSolutionSubmit()
{
foreach ($this->getSolutionSubmitValidation() as $gapIndex => $value) {
$gap = $this->getGap($gapIndex);
-
+
if ($gap->getType() != CLOZE_NUMERIC) {
continue;
}
-
+
if (strlen($value) && !$this->isValidNumericSubmitValue($value)) {
ilUtil::sendFailure($this->lng->txt("err_no_numeric_value"), true);
return false;
}
}
-
+
return true;
}
-
+
public function fetchSolutionSubmit($submit)
{
$solutionSubmit = array();
-
+
foreach ($submit as $key => $value) {
if (preg_match("/^gap_(\d+)/", $key, $matches)) {
$value = ilUtil::stripSlashes($value, false);
@@ -1295,7 +1319,7 @@ public function fetchSolutionSubmit($submit)
}
}
}
-
+
return $solutionSubmit;
}
@@ -1328,7 +1352,7 @@ public function getSolutionSubmit()
{
return $this->fetchSolutionSubmit($_POST);
}
-
+
/**
* Saves the learners input of the question to the database.
*
@@ -1377,7 +1401,7 @@ public function saveWorkingData($active_id, $pass = null, $authorized = true)
assQuestion::logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
}
}
-
+
return true;
}
@@ -1474,7 +1498,7 @@ public function getAnswerTableName()
{
return array("qpl_a_cloze",'qpl_a_cloze_combi_res');
}
-
+
/**
* Sets a fixed text length for all text fields in the cloze question
*
@@ -1485,7 +1509,7 @@ public function setFixedTextLength($a_text_len)
{
$this->fixedTextLength = $a_text_len;
}
-
+
/**
* Gets the fixed text length for all text fields in the cloze question
*
@@ -1587,7 +1611,7 @@ public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
return $startrow + $i + 1;
}
-
+
/**
* @param ilAssSelfAssessmentMigrator $migrator
*/
@@ -1598,7 +1622,7 @@ protected function lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigra
$this->cloze_text = $migrator->migrateToLmContent($this->getClozeText());
// DO NOT USE SETTER FOR CLOZE TEXT -> SETTER DOES RECREATE GAP OBJECTS without having gap type info ^^
}
-
+
/**
* Returns a JSON representation of the question
*/
@@ -1617,7 +1641,7 @@ public function toJSON()
'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
);
-
+
$gaps = array();
foreach ($this->getGaps() as $key => $gap) {
$items = array();
@@ -1642,7 +1666,7 @@ public function toJSON()
$jgap['shuffle'] = $gap->getShuffle();
$jgap['type'] = $gap->getType();
$jgap['item'] = $items;
-
+
array_push($gaps, $jgap);
}
$result['gaps'] = $gaps;
@@ -1722,7 +1746,7 @@ public function getUserQuestionResult($active_id, $pass)
array($active_id, $pass, $this->getId())
);
}
-
+
while ($row = $ilDB->fetchAssoc($data)) {
if ($row["cloze_type"] == 1) {
$row["value2"]++;
@@ -1758,9 +1782,9 @@ public function getAvailableAnswerOptions($index = null)
public function calculateCombinationResult($user_result)
{
$points = 0;
-
+
$assClozeGapCombinationObj = new assClozeGapCombination();
-
+
if ($assClozeGapCombinationObj->combinationExistsForQid($this->getId())) {
$combinations_for_question = $assClozeGapCombinationObj->getCleanCombinationArray($this->getId());
$gap_answers = array();
@@ -1848,7 +1872,7 @@ protected function calculateReachedPointsForSolution($user_result, &$detailed =
if (is_string($value)) {
$value = array("value" => $value);
}
-
+
if (array_key_exists($gap_id, $this->gaps) && !array_key_exists($gap_id, $combinations[1])) {
switch ($this->gaps[$gap_id]->getType()) {
case CLOZE_TEXT:
@@ -1920,62 +1944,62 @@ protected function calculateReachedPointsForSolution($user_result, &$detailed =
}
}
}
-
+
return $points;
}
public function calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
{
$userSolution = array();
-
+
foreach ($previewSession->getParticipantsSolution() as $key => $val) {
$userSolution[] = array('gap_id' => $key, 'value' => $val);
}
-
+
$reachedPoints = $this->calculateReachedPointsForSolution($userSolution);
$reachedPoints = $this->deductHintPointsFromReachedPoints($previewSession, $reachedPoints);
-
+
return $this->ensureNonNegativePoints($reachedPoints);
}
-
+
public function fetchAnswerValueForGap($userSolution, $gapIndex)
{
$answerValue = '';
-
+
foreach ($userSolution as $value1 => $value2) {
if ($value1 == $gapIndex) {
$answerValue = $value2;
break;
}
}
-
+
return $answerValue;
}
-
+
public function isAddableAnswerOptionValue($qIndex, $answerOptionValue)
{
$gap = $this->getGap($qIndex);
-
+
if ($gap->getType() != CLOZE_TEXT) {
return false;
}
-
+
foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $item) {
if ($item->getAnswertext() == $answerOptionValue) {
return false;
}
}
-
+
return true;
}
-
+
public function addAnswerOptionValue($qIndex, $answerOptionValue, $points)
{
$gap = $this->getGap($qIndex); /* @var assClozeGap $gap */
-
+
$item = new assAnswerCloze($answerOptionValue, $points);
$item->setOrder($gap->getItemCount());
-
+
$gap->addItem($item);
}
diff --git a/Modules/TestQuestionPool/classes/class.assClozeTestGUI.php b/Modules/TestQuestionPool/classes/class.assClozeTestGUI.php
index 0abee346ff51..466acf95336b 100755
--- a/Modules/TestQuestionPool/classes/class.assClozeTestGUI.php
+++ b/Modules/TestQuestionPool/classes/class.assClozeTestGUI.php
@@ -23,12 +23,12 @@
class assClozeTestGUI extends assQuestionGUI implements ilGuiQuestionScoringAdjustable, ilGuiAnswerScoringAdjustable
{
const OLD_CLOZE_TEST_UI = false;
-
+
/**
* A temporary variable to store gap indexes of ilCtrl commands in the getCommand method
*/
private $gapIndex;
-
+
/**
* assClozeTestGUI constructor
*
@@ -89,17 +89,17 @@ public function writeAnswerSpecificPostData(ilPropertyFormGUI $form)
if ($this->ctrl->getCmd() != 'createGaps') {
$this->object->clearGapAnswers();
}
-
+
foreach ($_POST['gap'] as $idx => $hidden) {
$clozetype = $_POST['clozetype_' . $idx];
-
+
$this->object->setGapType($idx, $clozetype);
-
+
switch ($clozetype) {
case CLOZE_TEXT:
$this->object->setGapShuffle($idx, 0);
-
+
if ($this->ctrl->getCmd() != 'createGaps') {
if (is_array($_POST['gap_' . $idx]['answer'])) {
foreach ($_POST['gap_' . $idx]['answer'] as $order => $value) {
@@ -109,7 +109,7 @@ public function writeAnswerSpecificPostData(ilPropertyFormGUI $form)
$this->object->addGapAnswer($idx, 0, '');
}
}
-
+
if (is_array($_POST['gap_' . $idx]['points'])) {
foreach ($_POST['gap_' . $idx]['points'] as $order => $value) {
$this->object->setGapAnswerPoints($idx, $order, $value);
@@ -119,9 +119,9 @@ public function writeAnswerSpecificPostData(ilPropertyFormGUI $form)
if (array_key_exists('gap_' . $idx . '_gapsize', $_POST)) {
$this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize']);
}
-
+
break;
-
+
case CLOZE_SELECT:
$this->object->setGapShuffle($idx, (int) (isset($_POST["shuffle_$idx"]) && $_POST["shuffle_$idx"]));
@@ -135,7 +135,7 @@ public function writeAnswerSpecificPostData(ilPropertyFormGUI $form)
$this->object->addGapAnswer($idx, 0, '');
}
}
-
+
if (is_array($_POST['gap_' . $idx]['points'])) {
foreach ($_POST['gap_' . $idx]['points'] as $order => $value) {
$this->object->setGapAnswerPoints($idx, $order, $value);
@@ -144,14 +144,14 @@ public function writeAnswerSpecificPostData(ilPropertyFormGUI $form)
break;
case CLOZE_NUMERIC:
-
+
$this->object->setGapShuffle($idx, 0);
$gap = $this->object->getGap($idx);
if (!$gap) {
break;
}
-
+
$this->object->getGap($idx)->clearItems();
if (array_key_exists('gap_' . $idx . '_numeric', $_POST)) {
@@ -180,7 +180,7 @@ public function writeAnswerSpecificPostData(ilPropertyFormGUI $form)
if ($this->ctrl->getCmd() != 'createGaps') {
$this->object->addGapAnswer($idx, 0, '');
}
-
+
$this->object->setGapAnswerLowerBound($idx, 0, '');
$this->object->setGapAnswerUpperBound($idx, 0, '');
@@ -327,7 +327,7 @@ public function addBasicQuestionFormProperties($form)
// $button = new ilCustomInputGUI(' ','');
// $button->setHtml($tpl->get());
// $form->addItem($button);
-
+
if (!$this->object->getSelfAssessmentEditingMode()) {
// duration
$duration = new ilDurationInputGUI($this->lng->txt("working_time"), "Estimated");
@@ -443,7 +443,7 @@ public function populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
// text field length
$fixedTextLength = new ilNumberInputGUI($this->lng->txt("cloze_fixed_textlength"), "fixedTextLength");
$ftl = $this->object->getFixedTextLength();
-
+
$fixedTextLength->setValue($ftl > 0 ? $ftl : '');
$fixedTextLength->setMinValue(0);
$fixedTextLength->setSize(3);
@@ -516,7 +516,7 @@ protected function populateJSON()
'points' => $value[$j]->getPoints(),
'error' => false
);
-
+
if ($content->getType() == 1) {
$shuffle = $content->getShuffle();
}
@@ -571,7 +571,7 @@ protected function populateGapFormPart($form, $gapCounter)
if ($gap->getType() == CLOZE_TEXT) {
$this->populateGapSizeFormPart($form, $gap, $gapCounter);
-
+
if (count($gap->getItemsRaw()) == 0) {
$gap->addItem(new assAnswerCloze("", 0, 0));
}
@@ -583,7 +583,7 @@ protected function populateGapFormPart($form, $gapCounter)
$this->populateSelectGapFormPart($form, $gap, $gapCounter);
} elseif ($gap->getType() == CLOZE_NUMERIC) {
$this->populateGapSizeFormPart($form, $gap, $gapCounter);
-
+
if (count($gap->getItemsRaw()) == 0) {
$gap->addItem(new assAnswerCloze("", 0, 0));
}
@@ -602,7 +602,7 @@ protected function populateGapFormPart($form, $gapCounter)
protected function populateGapSizeFormPart($form, $gap, $gapCounter)
{
$gapSizeFormItem = new ilNumberInputGUI($this->lng->txt('cloze_fixed_textlength'), "gap_" . $gapCounter . '_gapsize');
-
+
$gapSizeFormItem->allowDecimals(false);
$gapSizeFormItem->setMinValue(0);
$gapSizeFormItem->setSize(3);
@@ -610,10 +610,10 @@ protected function populateGapSizeFormPart($form, $gap, $gapCounter)
$gapSizeFormItem->setInfo($this->lng->txt('cloze_gap_size_info'));
$gapSizeFormItem->setValue($gap->getGapSize());
$form->addItem($gapSizeFormItem);
-
+
return $form;
}
-
+
/**
* Populates the form-part for a select gap.
*
@@ -713,7 +713,7 @@ protected function populateNumericGapFormPart($form, $gap, $gapCounter)
$upperbound = new ilNumberInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
$upperbound->allowDecimals(true);
}
-
+
$value->setSize(10);
$value->setValue(ilUtil::prepareFormOutput($gap->getAnswertext()));
$value->setRequired(true);
@@ -788,7 +788,7 @@ public function addgap()
public function getPreview($show_question_only = false, $showInlineFeedback = false)
{
$user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
-
+
// generate the question output
include_once "./Services/UICore/classes/class.ilTemplate.php";
$template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", true, true, "Modules/TestQuestionPool");
@@ -810,7 +810,9 @@ public function getPreview($show_question_only = false, $showInlineFeedback = fa
$gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
}
}
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
case CLOZE_SELECT:
$gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", true, true, "Modules/TestQuestionPool");
@@ -828,8 +830,9 @@ public function getPreview($show_question_only = false, $showInlineFeedback = fa
$gaptemplate->parseCurrentBlock();
}
$gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
- $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ $gaptemplate->setVariable("GAP_COUNTER", $gap_index);// fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
case CLOZE_NUMERIC:
$gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", true, true, "Modules/TestQuestionPool");
@@ -845,7 +848,9 @@ public function getPreview($show_question_only = false, $showInlineFeedback = fa
$gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
}
}
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
}
}
@@ -915,7 +920,7 @@ public function getSolutionOutput(
// output of ok/not ok icons for user entered solutions
$details = $this->object->calculateReachedPoints($active_id, $pass, true, true);
$check = $details[$gap_index];
-
+
if (count($check_for_gap_combinations) != 0) {
$gaps_used_in_combination = $assClozeGapCombinationObject->getGapsWhichAreUsedInCombination($this->object->getId());
$custom_user_solution = array();
@@ -1007,7 +1012,9 @@ public function getSolutionOutput(
$solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
}
$this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
case CLOZE_SELECT:
$solutiontext = "";
@@ -1030,7 +1037,9 @@ public function getSolutionOutput(
$solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
}
$this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
case CLOZE_NUMERIC:
$solutiontext = "";
@@ -1046,11 +1055,13 @@ public function getSolutionOutput(
$solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
}
$this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
}
}
-
+
if ($show_question_text) {
$template->setVariable(
"QUESTIONTEXT",
@@ -1069,7 +1080,7 @@ public function getSolutionOutput(
$fb = $this->getGenericFeedbackOutput($active_id, $pass);
$feedback .= strlen($fb) ? $fb : '';
}
-
+
$fb = $this->getSpecificFeedbackOutput(
$this->object->fetchIndexedValuesFromValuePairs($user_solution)
);
@@ -1080,11 +1091,11 @@ public function getSolutionOutput(
$this->hasCorrectSolution($active_id, $pass) ?
ilAssQuestionFeedback::CSS_CLASS_FEEDBACK_CORRECT : ilAssQuestionFeedback::CSS_CLASS_FEEDBACK_WRONG
);
-
+
$solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
$solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
}
-
+
$solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
$solutionoutput = $solutiontemplate->get();
@@ -1093,7 +1104,7 @@ public function getSolutionOutput(
// get page object output
$solutionoutput = $this->getILIASPage($solutionoutput);
}
-
+
return $solutionoutput;
}
@@ -1140,7 +1151,7 @@ public function getAnswerFeedbackOutput($active_id, $pass)
$test = new ilObjTest($this->object->active_id);
return $this->object->prepareTextareaOutput($output, true);
}
-
+
public function getTestOutput(
$active_id,
// hey: prevPassSolutions - will be always available from now on
@@ -1168,7 +1179,7 @@ public function getTestOutput(
$user_solution = array();
}
}
-
+
// generate the question output
include_once "./Services/UICore/classes/class.ilTemplate.php";
$template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", true, true, "Modules/TestQuestionPool");
@@ -1184,14 +1195,16 @@ public function getTestOutput(
$gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
$gaptemplate->parseCurrentBlock();
}
-
+
$gaptemplate->setVariable("GAP_COUNTER", $gap_index);
foreach ($user_solution as $solution) {
if (strcmp($solution["value1"], $gap_index) == 0) {
$gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
}
}
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
case CLOZE_SELECT:
$gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", true, true, "Modules/TestQuestionPool");
@@ -1209,8 +1222,9 @@ public function getTestOutput(
$gaptemplate->parseCurrentBlock();
}
$gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
- $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ $gaptemplate->setVariable("GAP_COUNTER", $gap_index);// fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
case CLOZE_NUMERIC:
$gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", true, true, "Modules/TestQuestionPool");
@@ -1220,18 +1234,20 @@ public function getTestOutput(
$gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
$gaptemplate->parseCurrentBlock();
}
-
+
$gaptemplate->setVariable("GAP_COUNTER", $gap_index);
foreach ($user_solution as $solution) {
if (strcmp($solution["value1"], $gap_index) == 0) {
$gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
}
}
- $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
+ // fau: fixGapReplace - use replace function
+ $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
+// fau.
break;
}
}
-
+
$template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
$template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
$questionoutput = $template->get();
@@ -1253,7 +1269,7 @@ public function setQuestionTabs()
$ilTabs = $DIC['ilTabs'];
$ilTabs->clearTargets();
-
+
$this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
$q_type = $this->object->getQuestionType();
@@ -1277,7 +1293,7 @@ public function setQuestionTabs()
$force_active
);
}
-
+
$this->addTab_QuestionPreview($ilTabs);
}
@@ -1310,7 +1326,7 @@ public function setQuestionTabs()
// add tab for question feedback within common class assQuestionGUI
$this->addTab_QuestionFeedback($ilTabs);
-
+
// add tab for question hint within common class assQuestionGUI
$this->addTab_QuestionHints($ilTabs);
@@ -1330,13 +1346,13 @@ public function setQuestionTabs()
$this->addBackTab($ilTabs);
}
-
+
public function getSpecificFeedbackOutput($userSolution)
{
if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
return '';
}
-
+
global $DIC;
$lng = $DIC['lng'];
@@ -1346,7 +1362,7 @@ public function getSpecificFeedbackOutput($userSolution)
$answerValue = $this->object->fetchAnswerValueForGap($userSolution, $gapIndex);
$answerIndex = $this->object->feedbackOBJ->determineAnswerIndexForAnswerValue($gap, $answerValue);
$fb = $this->object->feedbackOBJ->determineTestOutputGapFeedback($gapIndex, $answerIndex);
-
+
$caption = $lng->txt('gap') . ' ' . ($gapIndex + 1) . ': ';
$feedback .= '
';
$feedback .= $caption . '
';
@@ -1506,21 +1522,21 @@ private function populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
$gaptemplate->setVariable('SELECT_SOLUTION', $solutiontext);
} else {
$gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
-
+
if ($gap_size > 0) {
$gaptemplate->setCurrentBlock('gap_size');
$gaptemplate->setVariable("GAP_SIZE", $gap_size);
$gaptemplate->parseCurrentBlock();
}
-
+
$gaptemplate->setCurrentBlock('gap_input');
$gaptemplate->setVariable('INPUT_SOLUTION', $solutiontext);
}
-
-
+
+
$gaptemplate->parseCurrentBlock();
}
-
+
protected function hasAddAnswerAction($relevantAnswers, $questionIndex)
{
foreach ($this->getAnswersFrequency($relevantAnswers, $questionIndex) as $answer) {
@@ -1528,145 +1544,145 @@ protected function hasAddAnswerAction($relevantAnswers, $questionIndex)
return true;
}
}
-
+
return false;
}
-
+
public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
{
global $DIC; /* @var ILIAS\DI\Container $DIC */
-
+
$table = parent::getAnswerFrequencyTableGUI(
$parentGui,
$parentCmd,
$relevantAnswers,
$questionIndex
);
-
+
$table->setTitle(sprintf(
$DIC->language()->txt('tst_corrections_answers_tbl_subindex'),
$DIC->language()->txt('gap') . ' ' . ($questionIndex + 1)
));
-
+
if ($this->hasAddAnswerAction($relevantAnswers, $questionIndex)) {
$table->addColumn('', '', '200');
}
-
+
return $table;
}
-
+
public function getSubQuestionsIndex()
{
return array_keys($this->object->getGaps());
}
-
+
protected function getAnswerTextLabel($gapIndex, $answer)
{
$gap = $this->object->getGap($gapIndex);
-
+
switch ($gap->type) {
case CLOZE_NUMERIC:
case CLOZE_TEXT:
return $answer;
-
+
case CLOZE_SELECT:
-
+
$items = $gap->getItems(new ilArrayElementOrderKeeper());
return $items[$answer]->getAnswertext();
}
}
-
+
protected function completeAddAnswerAction($answers, $questionIndex)
{
$gap = $this->object->getGap($questionIndex);
-
+
if ($gap->type != CLOZE_TEXT) {
return $answers;
}
-
+
foreach ($answers as $key => $ans) {
$found = false;
-
+
foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $item) {
- if ($ans['answer'] != $item->getAnswerText()) {
+ if ($ans['answer'] !== $item->getAnswerText()) {
continue;
}
-
+
$found = true;
break;
}
-
+
if (!$found) {
$answers[$key]['addable'] = true;
}
}
-
+
return $answers;
}
-
+
public function getAnswersFrequency($relevant_answers, $questionIndex)
{
$answers = array();
-
+
foreach ($relevant_answers as $row) {
if ($row['value1'] != $questionIndex) {
continue;
}
-
+
if (!isset($answers[$row['value2']])) {
$label = $this->getAnswerTextLabel($row['value1'], $row['value2']);
-
+
$answers[$row['value2']] = array(
'answer' => $label, 'frequency' => 0
);
}
-
+
$answers[$row['value2']]['frequency']++;
}
-
+
$answers = $this->completeAddAnswerAction($answers, $questionIndex);
-
+
return $answers;
}
-
+
protected function isUsedInCombinations($gapIndex)
{
foreach ($this->object->getGapCombinations() as $combination) {
if ($combination['gap_fi'] != $gapIndex) {
continue;
}
-
+
return true;
}
-
+
return false;
}
-
+
protected function getGapCombinations()
{
$combinations = array();
-
+
foreach ($this->object->getGapCombinations() as $c) {
if (!isset($combinations[$c['cid']])) {
$combinations[$c['cid']] = array();
}
-
+
if (!isset($combinations[$c['cid']][$c['row_id']])) {
$combinations[$c['cid']][$c['row_id']] = array(
'gaps' => array(), 'points' => $c['points'],
);
}
-
+
if (!isset($combinations[$c['cid']][$c['row_id']]['gaps'][$c['gap_fi']])) {
$combinations[$c['cid']][$c['row_id']]['gaps'][$c['gap_fi']] = array();
}
-
+
$combinations[$c['cid']][$c['row_id']]['gaps'][$c['gap_fi']] = $c['answer'];
}
-
+
return $combinations;
}
-
+
public function populateCorrectionsFormProperties(ilPropertyFormGUI $form)
{
foreach ($this->object->getGaps() as $gapIndex => $gap) {
@@ -1677,26 +1693,26 @@ public function populateCorrectionsFormProperties(ilPropertyFormGUI $form)
$this->isUsedInCombinations($gapIndex)
);
}
-
+
if ($this->object->getGapCombinationsExists()) {
foreach ($this->getGapCombinations() as $combiIndex => $gapCombination) {
$this->populateGapCombinationCorrectionFormProperty($form, $gapCombination, $combiIndex);
}
}
}
-
+
protected function populateGapCombinationCorrectionFormProperty(ilPropertyFormGUI $form, $gapCombi, $combiIndex)
{
$header = new ilFormSectionHeaderGUI();
$header->setTitle("Gap Combination " . ($combiIndex + 1));
$form->addItem($header);
-
+
require_once 'Modules/TestQuestionPool/classes/forms/class.ilAssClozeTestCombinationVariantsInputGUI.php';
$inp = new ilAssClozeTestCombinationVariantsInputGUI('Answers', 'combination_' . $combiIndex);
$inp->setValues($gapCombi);
$form->addItem($inp);
}
-
+
/**
* @param ilPropertyFormGUI $form
* @param assClozeGap $gap
@@ -1707,7 +1723,7 @@ protected function populateGapCorrectionFormProperties($form, $gap, $gapIndex, $
$header = new ilFormSectionHeaderGUI();
$header->setTitle($this->lng->txt("gap") . " " . ($gapIndex + 1));
$form->addItem($header);
-
+
if ($gap->getType() == CLOZE_TEXT || $gap->getType() == CLOZE_SELECT) {
$this->populateTextOrSelectGapCorrectionFormProperty($form, $gap, $gapIndex, $hidePoints);
} elseif ($gap->getType() == CLOZE_NUMERIC) {
@@ -1716,7 +1732,7 @@ protected function populateGapCorrectionFormProperties($form, $gap, $gapIndex, $
}
}
}
-
+
protected function populateTextOrSelectGapCorrectionFormProperty($form, $gap, $gapIndex, $hidePoints)
{
require_once "Modules/TestQuestionPool/classes/forms/class.ilAssAnswerCorrectionsInputGUI.php";
@@ -1727,7 +1743,7 @@ protected function populateTextOrSelectGapCorrectionFormProperty($form, $gap, $g
$values->setValues($gap->getItemsRaw());
$form->addItem($values);
}
-
+
protected function populateNumericGapCorrectionFormProperty($form, $item, $gapIndex, $hidePoints)
{
$value = new ilNumberInputGUI($this->lng->txt('value'), "gap_" . $gapIndex . "_numeric");
@@ -1736,21 +1752,21 @@ protected function populateNumericGapCorrectionFormProperty($form, $item, $gapIn
$value->setValue(ilUtil::prepareFormOutput($item->getAnswertext()));
$value->setRequired(true);
$form->addItem($value);
-
+
$lowerbound = new ilNumberInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $gapIndex . "_numeric_lower");
$lowerbound->allowDecimals(true);
$lowerbound->setSize(10);
$lowerbound->setRequired(true);
$lowerbound->setValue(ilUtil::prepareFormOutput($item->getLowerBound()));
$form->addItem($lowerbound);
-
+
$upperbound = new ilNumberInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapIndex . "_numeric_upper");
$upperbound->allowDecimals(true);
$upperbound->setSize(10);
$upperbound->setRequired(true);
$upperbound->setValue(ilUtil::prepareFormOutput($item->getUpperBound()));
$form->addItem($upperbound);
-
+
if (!$hidePoints) {
$points = new ilNumberInputGUI($this->lng->txt('points'), "gap_" . $gapIndex . "_numeric_points");
$points->allowDecimals(true);
@@ -1760,7 +1776,7 @@ protected function populateNumericGapCorrectionFormProperty($form, $item, $gapIn
$form->addItem($points);
}
}
-
+
/**
* @param ilPropertyFormGUI $form
*/
@@ -1770,15 +1786,15 @@ public function saveCorrectionsFormProperties(ilPropertyFormGUI $form)
if ($this->isUsedInCombinations($gapIndex)) {
continue;
}
-
+
$this->saveGapCorrectionFormProperty($form, $gap, $gapIndex);
}
-
+
if ($this->object->getGapCombinationsExists()) {
$this->saveGapCombinationCorrectionFormProperties($form);
}
}
-
+
protected function saveGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
{
if ($gap->getType() == CLOZE_TEXT || $gap->getType() == CLOZE_SELECT) {
@@ -1789,16 +1805,16 @@ protected function saveGapCorrectionFormProperty(ilPropertyFormGUI $form, assClo
}
}
}
-
+
protected function saveTextOrSelectGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
{
$answers = $form->getItemByPostVar('gap_' . $gapIndex)->getValues();
-
+
foreach ($gap->getItemsRaw() as $index => $item) {
$item->setPoints((float) $answers[$index]->getPoints());
}
}
-
+
protected function saveNumericGapCorrectionFormProperty(ilPropertyFormGUI $form, assAnswerCloze $item, $gapIndex)
{
$item->setAnswertext($form->getInput('gap_' . $gapIndex . '_numeric'));
@@ -1806,36 +1822,36 @@ protected function saveNumericGapCorrectionFormProperty(ilPropertyFormGUI $form,
$item->setUpperBound($form->getInput('gap_' . $gapIndex . '_numeric_upper'));
$item->setPoints($form->getInput('gap_' . $gapIndex . '_numeric_points'));
}
-
+
protected function saveGapCombinationCorrectionFormProperties(ilPropertyFormGUI $form)
{
// please dont ask (!) -.-
-
+
$combinationPoints = array('points' => array(), 'select' => array());
$combinationValues = array();
-
+
foreach ($this->getGapCombinations() as $combiId => $combi) {
$values = $form->getItemByPostVar('combination_' . $combiId)->getValues();
-
+
if (!isset($combinationPoints['points'][$combiId])) {
$combinationPoints['points'][$combiId] = array();
$combinationPoints['select'][$combiId] = array();
$combinationValues[$combiId] = array();
}
-
+
foreach ($combi as $varId => $variant) {
$combinationPoints['points'][$combiId][$varId] = (float) $values[$varId]['points'];
$combinationPoints['select'][$combiId] = array_keys($values[$varId]['gaps']);
$combinationValues[$combiId][$varId] = array_values($values[$varId]['gaps']);
}
}
-
+
$combinationPoints = ilUtil::stripSlashesRecursive($combinationPoints);
$combinationValues = ilUtil::stripSlashesRecursive($combinationValues);
-
+
$assClozeGapCombinationObject = new assClozeGapCombination();
$assClozeGapCombinationObject->clearGapCombinationsFromDb($this->object->getId());
-
+
$assClozeGapCombinationObject->saveGapCombinationToDb(
$this->object->getId(),
$combinationPoints,
diff --git a/Modules/TestQuestionPool/classes/class.assImagemapQuestionGUI.php b/Modules/TestQuestionPool/classes/class.assImagemapQuestionGUI.php
index 9d6dfa8613b8..7cba31980182 100755
--- a/Modules/TestQuestionPool/classes/class.assImagemapQuestionGUI.php
+++ b/Modules/TestQuestionPool/classes/class.assImagemapQuestionGUI.php
@@ -327,11 +327,11 @@ public function areaEditor($shape = '')
ilUtil::sendInfo($this->lng->txt("polygon_click_starting_point"));
} elseif (count($coords) == 1) {
ilUtil::sendInfo($this->lng->txt("polygon_click_next_point"));
- $preview->addPoint($preview->getAreaCount(), join(",", $coords), true, "blue");
+ $preview->addPoint($preview->getAreaCount(), implode(",", $coords), true, "blue");
} elseif (count($coords) > 1) {
ilUtil::sendInfo($this->lng->txt("polygon_click_next_or_save"));
$disabled_save = "";
- $c = join(",". $coords);
+ $c = implode(",", $coords);
}
break;
}
diff --git a/Modules/TestQuestionPool/classes/class.assTextQuestion.php b/Modules/TestQuestionPool/classes/class.assTextQuestion.php
index cc044768d7f9..17979c0b26be 100755
--- a/Modules/TestQuestionPool/classes/class.assTextQuestion.php
+++ b/Modules/TestQuestionPool/classes/class.assTextQuestion.php
@@ -1078,4 +1078,31 @@ public function countWords($text)
return count(explode(' ', $text));
}
+
+ public function getLatestAutosaveContent($active_id)
+ {
+ $question_fi = $this->getId();
+
+ // Do we have an unauthorized result?
+ $cntresult = $this->db->query('
+ SELECT count(solution_id) cnt
+ FROM tst_solutions
+ WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
+ AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
+ AND authorized = ' . $this->db->quote(0, 'int')
+ );
+ $row = $this->db->fetchAssoc($cntresult);
+ if($row['cnt'] > 0 ) {
+ $tresult = $this->db->query('
+ SELECT value1
+ FROM tst_solutions
+ WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
+ AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
+ AND authorized = ' . $this->db->quote(0, 'int')
+ );
+ $trow = $this->db->fetchAssoc($tresult);
+ return $trow['value1'];
+ }
+ return '';
+ }
}
diff --git a/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php b/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php
index a73f7a9da75f..a0e163143de0 100755
--- a/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php
+++ b/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php
@@ -266,6 +266,116 @@ public function getSolutionOutput(
return $solutionoutput;
}
+ /**
+ * Get the question solution output
+ *
+ * @param integer $active_id The active user id
+ * @param integer $pass The test pass
+ * @param boolean $graphicalOutput Show visual feedback for right/wrong answers
+ * @param boolean $result_output Show the reached points for parts of the question
+ * @param boolean $show_question_only Show the question without the ILIAS content around
+ * @param boolean $show_feedback Show the question feedback
+ * @param boolean $show_correct_solution Show the correct solution instead of the user solution
+ * @param boolean $show_manual_scoring Show specific information for the manual scoring output
+ * @return The solution output of the question as HTML code
+ */
+ public function getAutoSavedSolutionOutput(
+ $active_id,
+ $pass = null,
+ $graphicalOutput = false,
+ $result_output = false,
+ $show_question_only = true,
+ $show_feedback = false,
+ $show_correct_solution = false,
+ $show_manual_scoring = false,
+ $show_question_text = true
+ ) {
+ // get the solution of the user for the active pass or from the last pass if allowed
+
+ $user_solution = $this->getUserAnswer($active_id, $pass);
+
+ if (($active_id > 0) && (!$show_correct_solution)) {
+ $solution = $user_solution;
+ } else {
+ $solution = $this->getBestAnswer($this->renderPurposeSupportsFormHtml());
+ }
+
+ // generate the question output
+ include_once "./Services/UICore/classes/class.ilTemplate.php";
+ $template = new ilTemplate("tpl.il_as_qpl_text_question_output_solution.html", true, true, "Modules/TestQuestionPool");
+ $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
+
+ $solution = $this->object->getHtmlUserSolutionPurifier()->purify($this->object->getLatestAutosaveContent($active_id));
+ if ($this->renderPurposeSupportsFormHtml()) {
+ $template->setCurrentBlock('essay_div');
+ $template->setVariable("DIV_ESSAY", $this->object->prepareTextareaOutput($solution, true));
+ } else {
+ $template->setCurrentBlock('essay_textarea');
+ $template->setVariable("TA_ESSAY", $this->object->prepareTextareaOutput($solution, true, true));
+ }
+ $template->parseCurrentBlock();
+
+ $questiontext = $this->object->getQuestion();
+
+ if (!$show_correct_solution) {
+ $max_no_of_chars = $this->object->getMaxNumOfChars();
+
+ if ($max_no_of_chars == 0) {
+ $max_no_of_chars = ucfirst($this->lng->txt('unlimited'));
+ }
+
+ $act_no_of_chars = $this->object->countLetters($solution);
+ $template->setVariable("CHARACTER_INFO", '' . $max_no_of_chars . '' .
+ $this->lng->txt('answer_characters') . ' ' . $act_no_of_chars . '');
+
+ if ($this->object->isWordCounterEnabled()) {
+ $template->setCurrentBlock('word_count');
+ $template->setVariable(
+ 'WORD_COUNT',
+ $this->lng->txt('qst_essay_written_words') .
+ ' ' . $this->object->countWords($solution) . ''
+ );
+ $template->parseCurrentBlock();
+ }
+ }
+ if ($show_question_text == true) {
+ $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
+ }
+ $questionoutput = $template->get();
+
+ $feedback = '';
+ if ($show_feedback) {
+ if (!$this->isTestPresentationContext()) {
+ $fb = $this->getGenericFeedbackOutput($active_id, $pass);
+ $feedback .= strlen($fb) ? $fb : '';
+ }
+
+ $fb = $this->getSpecificFeedbackOutput(
+ array($user_solution => '')
+ );
+
+ $feedback .= strlen($fb) ? $fb : '';
+ }
+ if (strlen($feedback)) {
+ $cssClass = (
+ $this->hasCorrectSolution($active_id, $pass) ?
+ ilAssQuestionFeedback::CSS_CLASS_FEEDBACK_CORRECT : ilAssQuestionFeedback::CSS_CLASS_FEEDBACK_WRONG
+ );
+
+ $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
+ $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
+ }
+
+ $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
+
+ $solutionoutput = $solutiontemplate->get();
+ if (!$show_question_only) {
+ // get page object output
+ $solutionoutput = $this->getILIASPage($solutionoutput);
+ }
+ return $solutionoutput;
+ }
+
private function getBestAnswer($asHtml)
{
$answers = $this->object->getAnswers();
diff --git a/Modules/TestQuestionPool/classes/feedback/class.ilAssQuestionFeedback.php b/Modules/TestQuestionPool/classes/feedback/class.ilAssQuestionFeedback.php
index b65c0f3f1a50..35f4b0d8fd15 100644
--- a/Modules/TestQuestionPool/classes/feedback/class.ilAssQuestionFeedback.php
+++ b/Modules/TestQuestionPool/classes/feedback/class.ilAssQuestionFeedback.php
@@ -499,7 +499,7 @@ final public function duplicateFeedback($originalQuestionId, $duplicateQuestionI
* @param integer $originalQuestionId
* @param integer $duplicateQuestionId
*/
- final private function duplicateGenericFeedback($originalQuestionId, $duplicateQuestionId)
+ private function duplicateGenericFeedback($originalQuestionId, $duplicateQuestionId)
{
$res = $this->db->queryF(
"SELECT * FROM {$this->getGenericFeedbackTableName()} WHERE question_fi = %s",
@@ -558,7 +558,7 @@ final public function syncFeedback($originalQuestionId, $duplicateQuestionId)
* @param integer $originalQuestionId
* @param integer $duplicateQuestionId
*/
- final private function syncGenericFeedback($originalQuestionId, $duplicateQuestionId)
+ private function syncGenericFeedback($originalQuestionId, $duplicateQuestionId)
{
// delete generic feedback of the original question
$this->db->manipulateF(
@@ -725,7 +725,7 @@ public function getClassNameByType($a_type, $a_gui = false)
* @param integer $pageObjectId
* @return string $pageObjectEditingLink
*/
- final private function getPageObjectEditingLink($pageObjectType, $pageObjectId)
+ private function getPageObjectEditingLink($pageObjectType, $pageObjectId)
{
$cl = $this->getClassNameByType($pageObjectType, true);
$this->ctrl->setParameterByClass($cl, 'feedback_type', $pageObjectType);
@@ -814,7 +814,7 @@ final protected function getPageObjectXML($pageObjectType, $pageObjectId)
* @param string $pageObjectType
* @param integer $pageObjectId
*/
- final private function ensurePageObjectExists($pageObjectType, $pageObjectId)
+ private function ensurePageObjectExists($pageObjectType, $pageObjectId)
{
if ($pageObjectType == ilAssQuestionFeedback::PAGE_OBJECT_TYPE_GENERIC_FEEDBACK) {
include_once("./Modules/TestQuestionPool/classes/feedback/class.ilAssGenFeedbackPage.php");
diff --git a/Modules/TestQuestionPool/templates/default/cloze_gap_builder.js b/Modules/TestQuestionPool/templates/default/cloze_gap_builder.js
index 48fed5e51119..0d54aa201e21 100644
--- a/Modules/TestQuestionPool/templates/default/cloze_gap_builder.js
+++ b/Modules/TestQuestionPool/templates/default/cloze_gap_builder.js
@@ -1132,6 +1132,34 @@ var ClozeGapBuilder = (function () {
}
};
+ pro.removeSelectOption = function() {
+ let getPosition, pos, value;
+ if ($(this).attr('class') !== 'clone_fields_remove combination btn btn-link') {
+ value = $(this).parent().parent().find('.text_field').val();
+ $('[data-answer="' + value + '"]').show();
+ getPosition = $(this).attr('name');
+ pos = getPosition.split('_');
+ pos = getPosition.split('_');
+ ClozeSettings.gaps_php[0][pos[2]].values.splice(pos[3], 1);
+ pro.editTextarea(pos[2]);
+ if (ClozeSettings.gaps_php[0][pos[2]].values.length === 0) {
+ ClozeSettings.gaps_php[0].splice(pos[2], 1);
+ pro.removeFromTextarea(pos[2]);
+ }
+ } else {
+ getPosition = $(this).parent().attr('name');
+ pos = getPosition.split('_');
+ ClozeSettings.gaps_combination[pos[2]][0].splice(parseInt(pos[3], 10), 1);
+ ClozeSettings.gaps_combination[pos[2]][1].forEach(function (answers) {
+ answers.splice(parseInt(pos[3], 10), 1);
+ });
+ if (ClozeSettings.gaps_combination[pos[2]][0].length < 2) {
+ ClozeSettings.gaps_combination.splice(parseInt(pos[2], 10), 1);
+ }
+ }
+ pub.paintGaps();
+ return false;
+ },
pro.appendEventListenerToBeRefactored = function(){
$('.clone_fields_add').off('click');
@@ -1198,38 +1226,8 @@ var ClozeGapBuilder = (function () {
return false;
});
- $('.clone_fields_remove').on('click', function ()
- {
- var getPosition, pos, value;
- if($(this).attr('class') != 'clone_fields_remove combination btn btn-link')
- {
- value = $(this).parent().parent().find('.text_field').val();
- $('[data-answer="'+value+'"]').show();
- getPosition = $(this).attr('name');
- pos = getPosition.split('_');
- ClozeSettings.gaps_php[0][pos[2]].values.splice(pos[3], 1);
- pro.editTextarea(pos[2]);
- if (ClozeSettings.gaps_php[0][pos[2]].values.length === 0) {
- ClozeSettings.gaps_php[0].splice(pos[2], 1);
- pro.removeFromTextarea(pos[2]);
- }
- }
- else
- {
- getPosition = $(this).parent().attr('name');
- pos = getPosition.split('_');
- ClozeSettings.gaps_combination[pos[2]][0].splice(parseInt(pos[3], 10), 1);
- ClozeSettings.gaps_combination[pos[2]][1].forEach(function (answers) {
- answers.splice(parseInt(pos[3], 10), 1);
- });
- if(ClozeSettings.gaps_combination[pos[2]][0].length < 2)
- {
- ClozeSettings.gaps_combination.splice(parseInt(pos[2], 10),1);
- }
- }
- pub.paintGaps();
- return false;
- });
+ $('.clone_fields_remove').off('click', pro.removeSelectOption);
+ $('.clone_fields_remove').on('click', pro.removeSelectOption);
$('.remove_gap_button').off('click');
$('.remove_gap_button').on('click', function () {
diff --git a/Modules/Wiki/classes/class.ilObjWikiAccess.php b/Modules/Wiki/classes/class.ilObjWikiAccess.php
index 30fbc2ac171b..c8d9c05bd83a 100755
--- a/Modules/Wiki/classes/class.ilObjWikiAccess.php
+++ b/Modules/Wiki/classes/class.ilObjWikiAccess.php
@@ -190,6 +190,28 @@ public static function _lookupOnline($a_id)
return $wk_rec["is_online"];
}
+ /**
+ * Check wether learning module is online (legacy version)
+ *
+ * @deprecated
+ */
+ public static function _lookupOnlineStatus($a_ids)
+ {
+ global $DIC;
+
+ $ilDB = $DIC->database();
+
+ $q = "SELECT id, is_online FROM il_wiki_data WHERE " .
+ $ilDB->in("id", $a_ids, false, "integer");
+ $lm_set = $ilDB->query($q);
+ $status = [];
+ while ($r = $ilDB->fetchAssoc($lm_set)) {
+ $status[$r["id"]] = $r["is_online"];
+ }
+ return $status;
+ }
+
+
/**
* Check wether files should be public
*
diff --git a/Modules/Wiki/classes/class.ilObjWikiGUI.php b/Modules/Wiki/classes/class.ilObjWikiGUI.php
index e5cc75be328d..6486dc1cc624 100755
--- a/Modules/Wiki/classes/class.ilObjWikiGUI.php
+++ b/Modules/Wiki/classes/class.ilObjWikiGUI.php
@@ -1648,6 +1648,7 @@ public function pdfExportObject()
// :TODO: fixing css dummy parameters
$html = preg_replace("/\?dummy\=[0-9]+/", "", $html);
$html = preg_replace("/\?vers\=[0-9A-Za-z\-]+/", "", $html);
+ $html = str_replace('.css$Id$', ".css", $html);
if (false) {
include_once "Services/PDFGeneration/classes/class.ilPDFGeneration.php";
diff --git a/Services/ActiveRecord/class.ActiveRecordList.php b/Services/ActiveRecord/class.ActiveRecordList.php
index 43933aa5e8da..1938afa6202f 100644
--- a/Services/ActiveRecord/class.ActiveRecordList.php
+++ b/Services/ActiveRecord/class.ActiveRecordList.php
@@ -257,7 +257,7 @@ public function innerjoinAR(ActiveRecord $ar, $on_this, $on_external, $fields =
* @throws arException
*/
- protected function join($type = arJoin::TYPE_INNER, $tablename, $on_this, $on_external, $fields = array( '*' ), $operator = '=', $both_external = false)
+ protected function join($type, $tablename, $on_this, $on_external, $fields = array( '*' ), $operator = '=', $both_external = false)
{
if (!$this->getAR()->getArFieldList()->isField($on_this) and !$both_external) {
throw new arException(arException::LIST_JOIN_ON_WRONG_FIELD, $on_this);
diff --git a/Services/Administration/classes/class.ilAdministrationGUI.php b/Services/Administration/classes/class.ilAdministrationGUI.php
index 04fd36996fc9..98fc5a190bb4 100755
--- a/Services/Administration/classes/class.ilAdministrationGUI.php
+++ b/Services/Administration/classes/class.ilAdministrationGUI.php
@@ -206,6 +206,7 @@ public function executeCommand()
}
$class_path = $this->ctrl->lookupClassPath($next_class);
+ require_once $class_path;
// get gui class instance
$class_name = $this->ctrl->getClassForClasspath($class_path);
if (($next_class == "ilobjrolegui" || $next_class == "ilobjusergui"
@@ -221,13 +222,21 @@ public function executeCommand()
if ($objDefinition->isPlugin(ilObject::_lookupType($this->cur_ref_id, true))) {
$this->gui_obj = new $class_name($this->cur_ref_id);
} else {
- if (is_subclass_of($class_name, "ilObject2GUI")) {
- $this->gui_obj = new $class_name($this->cur_ref_id, ilObject2GUI::REPOSITORY_NODE_ID);
+ if (!$this->creation_mode) {
+ if (is_subclass_of($class_name, "ilObject2GUI")) {
+ $this->gui_obj = new $class_name($this->cur_ref_id, ilObject2GUI::REPOSITORY_NODE_ID);
+ } else {
+ $this->gui_obj = new $class_name("", $this->cur_ref_id, true, false);
+ }
} else {
- $this->gui_obj = new $class_name("", $this->cur_ref_id, true, false);
+ if (is_subclass_of($class_name, "ilObject2GUI")) {
+ $this->gui_obj = new $class_name(null, ilObject2GUI::REPOSITORY_NODE_ID, $this->cur_ref_id);
+ } else {
+ $this->gui_obj = new $class_name("", 0, true, false);
+ }
}
}
- $this->gui_obj->setCreationMode(false);
+ $this->gui_obj->setCreationMode($this->creation_mode);
}
$tabs_out = true;
$ilHelp->setScreenIdComponent(ilObject::_lookupType($this->cur_ref_id, true));
diff --git a/Services/AdvancedMetaData/classes/Types/class.ilAdvancedMDFieldDefinitionSelect.php b/Services/AdvancedMetaData/classes/Types/class.ilAdvancedMDFieldDefinitionSelect.php
index ac972bcd49e8..881dc5a0d3e7 100644
--- a/Services/AdvancedMetaData/classes/Types/class.ilAdvancedMDFieldDefinitionSelect.php
+++ b/Services/AdvancedMetaData/classes/Types/class.ilAdvancedMDFieldDefinitionSelect.php
@@ -229,7 +229,6 @@ public function prepareCustomDefinitionFormConfirmation(ilPropertyFormGUI $a_for
$objDefinition = $DIC['objDefinition'];
$a_form->getItemByPostVar("opts")->setDisabled(true);
-
if (is_array($this->confirm_objects) && count($this->confirm_objects) > 0) {
$new_options = $a_form->getInput("opts");
@@ -275,10 +274,8 @@ public function prepareCustomDefinitionFormConfirmation(ilPropertyFormGUI $a_for
ilUtil::sendFailure($lng->txt("form_input_not_valid"));
}
}
-
$single = new ilRadioOption($lng->txt("md_adv_confirm_definition_select_option_single"), "sgl");
$details->addOption($single);
-
foreach ($items as $item) {
$obj_id = $item[0];
$sub_type = $item[1];
@@ -294,7 +291,8 @@ public function prepareCustomDefinitionFormConfirmation(ilPropertyFormGUI $a_for
$class = "ilObj" . $objDefinition->getClassName($type);
$class_path = $objDefinition->getLocation($type);
include_once $class_path . "/class." . $class . ".php";
- if (class_implements($class, ilAdvancedMetaDataSubItem)) {
+ $ints = class_implements($class);
+ if (isset($ints["ilAdvancedMetaDataSubItems"])) {
$sub_title = $class::getAdvMDSubItemTitle($obj_id, $sub_type, $sub_id);
if ($sub_title) {
$title .= ' (' . $sub_title . ')';
diff --git a/Services/Authentication/classes/Frontend/class.ilAuthFrontendCredentialsSoap.php b/Services/Authentication/classes/Frontend/class.ilAuthFrontendCredentialsSoap.php
new file mode 100644
index 000000000000..f160e56fce6d
--- /dev/null
+++ b/Services/Authentication/classes/Frontend/class.ilAuthFrontendCredentialsSoap.php
@@ -0,0 +1,96 @@
+httpRequest = $httpRequest;
+ $this->ctrl = $ctrl;
+ $this->settings = $settings;
+ parent::__construct();
+ }
+
+ /**
+ * Check if an authentication attempt should be done when login page has been called.
+ */
+ public function tryAuthenticationOnLoginPage()
+ {
+ $cmd = '';
+ if (isset($this->httpRequest->getQueryParams()['cmd']) && is_string($this->httpRequest->getQueryParams()['cmd'])) {
+ $cmd = $this->httpRequest->getQueryParams()['cmd'];
+ }
+ if ('' === $cmd) {
+ if (isset($this->httpRequest->getParsedBody()['cmd']) && is_string($this->httpRequest->getParsedBody()['cmd'])) {
+ $cmd = $this->httpRequest->getParsedBody()['cmd'];
+ }
+ }
+
+ $passedSso = '';
+ if (isset($this->httpRequest->getQueryParams()['passed_sso']) && is_string($this->httpRequest->getQueryParams()['passed_sso'])) {
+ $passedSso = $this->httpRequest->getParsedBody()['passed_sso'];
+ }
+
+ if ('force_login' === $cmd || !empty($passedSso)) {
+ return false;
+ }
+
+ if (!$this->settings->get('soap_auth_active', false)) {
+ return false;
+ }
+
+ if (empty($this->getUsername()) || empty($this->getPassword())) {
+ return false;
+ }
+
+ $this->getLogger()->debug('Using SOAP authentication.');
+
+ $status = ilAuthStatus::getInstance();
+
+ require_once 'Services/SOAPAuth/classes/class.ilAuthProviderSoap.php';
+ $provider = new ilAuthProviderSoap($this);
+
+ $frontend_factory = new ilAuthFrontendFactory();
+ $frontend_factory->setContext(ilAuthFrontendFactory::CONTEXT_STANDARD_FORM);
+ $frontend = $frontend_factory->getFrontend(
+ $GLOBALS['DIC']['ilAuthSession'],
+ $status,
+ $this,
+ [$provider]
+ );
+
+ $frontend->authenticate();
+
+ switch ($status->getStatus()) {
+ case ilAuthStatus::STATUS_AUTHENTICATED:
+ ilLoggerFactory::getLogger('auth')->debug(
+ 'Redirecting to default starting page.'
+ );
+ ilInitialisation::redirectToStartingPage();
+ break;
+
+ case ilAuthStatus::STATUS_AUTHENTICATION_FAILED:
+ ilUtil::sendFailure($status->getTranslatedReason(), true);
+ $this->ctrl->redirectToURL(ilUtil::appendUrlParameterString(
+ $this->ctrl->getLinkTargetByClass('ilStartupGUI', 'showLoginPage', '', false, false),
+ 'passed_sso=1'
+ ));
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Services/Authentication/classes/Provider/class.ilAuthProviderFactory.php b/Services/Authentication/classes/Provider/class.ilAuthProviderFactory.php
index f3b7ee658b62..328708c3f21b 100644
--- a/Services/Authentication/classes/Provider/class.ilAuthProviderFactory.php
+++ b/Services/Authentication/classes/Provider/class.ilAuthProviderFactory.php
@@ -76,6 +76,11 @@ public function getProviderByAuthMode(ilAuthCredentials $credentials, $a_authmod
include_once './Services/Authentication/classes/Provider/class.ilAuthProviderDatabase.php';
return new ilAuthProviderDatabase($credentials);
+ case AUTH_SOAP:
+ $this->getLogger()->debug('Using SOAP authentication.');
+ include_once './Services/SOAPAuth/classes/class.ilAuthProviderSoap.php';
+ return new ilAuthProviderSoap($credentials);
+
case AUTH_APACHE:
$this->getLogger()->debug('Using apache authentication.');
include_once './Services/AuthApache/classes/class.ilAuthProviderApache.php';
diff --git a/Services/Authentication/classes/class.ilObjAuthSettingsGUI.php b/Services/Authentication/classes/class.ilObjAuthSettingsGUI.php
index 09d9b2a1ba85..ea87cb65493c 100755
--- a/Services/Authentication/classes/class.ilObjAuthSettingsGUI.php
+++ b/Services/Authentication/classes/class.ilObjAuthSettingsGUI.php
@@ -1274,6 +1274,12 @@ private function validateApacheAuthAllowedDomains($text)
return join("\n", preg_split("/[\r\n]+/", $text));
}
+ public function registrationSettingsObject()
+ {
+ $registration_gui = new ilRegistrationSettingsGUI();
+ $this->ctrl->redirect($registration_gui);
+ }
+
/**
* @param string $a_form_id
* @return array
@@ -1283,11 +1289,16 @@ public function addToExternalSettingsForm($a_form_id)
switch ($a_form_id) {
case ilAdministrationSettingsFormHandler::FORM_ACCESSIBILITY:
require_once 'Services/Captcha/classes/class.ilCaptchaUtil.php';
- $fields = array(
+ $fields_login = array(
'adm_captcha_anonymous_short' => array(ilCaptchaUtil::isActiveForLogin(), ilAdministrationSettingsFormHandler::VALUE_BOOL),
);
- return array('authentication_settings' => array('authSettings', $fields));
+ $fields_registration = array(
+ 'adm_captcha_anonymous_short' => array(ilCaptchaUtil::isActiveForRegistration(), ilAdministrationSettingsFormHandler::VALUE_BOOL)
+ );
+
+
+ return array('adm_auth_login' => array('authSettings', $fields_login), 'adm_auth_reg' => array('registrationSettings', $fields_registration));
}
}
} // END class.ilObjAuthSettingsGUI
diff --git a/Services/BackgroundTasks/classes/Jobs/class.ilCopyFilesToTempDirectoryJob.php b/Services/BackgroundTasks/classes/Jobs/class.ilCopyFilesToTempDirectoryJob.php
index 3101ae749e74..e7d381269d61 100644
--- a/Services/BackgroundTasks/classes/Jobs/class.ilCopyFilesToTempDirectoryJob.php
+++ b/Services/BackgroundTasks/classes/Jobs/class.ilCopyFilesToTempDirectoryJob.php
@@ -131,6 +131,13 @@ protected function createTargetDirectory($a_tmpdir)
protected function copyFiles($tmpdir, ilCopyDefinition $definition)
{
foreach ($definition->getCopyDefinitions() as $copy_task) {
+
+ $this->logger->debug('Creating directory: ' . $tmpdir . '/' . dirname($copy_task[ilCopyDefinition::COPY_TARGET_DIR]));
+ ilUtil::makeDirParents(
+ $tmpdir . '/' . dirname($copy_task[ilCopyDefinition::COPY_TARGET_DIR])
+ );
+
+
if (!file_exists($copy_task[ilCopyDefinition::COPY_SOURCE_DIR])) {
// if the "file" to be copied is an empty folder the directory has to be created so it will be contained in the download zip
$is_empty_folder = preg_match_all("/\/$/", $copy_task[ilCopyDefinition::COPY_TARGET_DIR]);
@@ -142,10 +149,7 @@ protected function copyFiles($tmpdir, ilCopyDefinition $definition)
}
continue;
}
- $this->logger->debug('Creating directory: ' . $tmpdir . '/' . dirname($copy_task[ilCopyDefinition::COPY_TARGET_DIR]));
- ilUtil::makeDirParents(
- $tmpdir . '/' . dirname($copy_task[ilCopyDefinition::COPY_TARGET_DIR])
- );
+
$this->logger->debug(
'Copying from: ' .
diff --git a/Services/COPage/classes/class.ilPCContentInclude.php b/Services/COPage/classes/class.ilPCContentInclude.php
index 8926792bfdef..69acafeacd90 100644
--- a/Services/COPage/classes/class.ilPCContentInclude.php
+++ b/Services/COPage/classes/class.ilPCContentInclude.php
@@ -248,7 +248,7 @@ public function modifyPageContentPostXsl($a_html, $a_mode, $a_abstract_only = fa
$page_gui = new ilMediaPoolPageGUI($param[1], 0, true, $snippet_lang);
if ($a_mode != "offline") {
$page_gui->setFileDownloadLink($this->getFileDownloadLink());
- $page_gui->setFullscreenLink($this->getFullscreenLink());
+ $page_gui->setFullscreenLink($this->getFullscreenLink()."&pg_type=mep");
$page_gui->setSourcecodeDownloadScript($this->getSourcecodeDownloadScript());
} else {
$page_gui->setOutputMode(ilPageObjectGUI::OFFLINE);
diff --git a/Services/COPage/classes/class.ilPageObjectGUI.php b/Services/COPage/classes/class.ilPageObjectGUI.php
index a4b1ad081266..c649f3a2ac68 100755
--- a/Services/COPage/classes/class.ilPageObjectGUI.php
+++ b/Services/COPage/classes/class.ilPageObjectGUI.php
@@ -1834,6 +1834,7 @@ public function showPage()
// check cache (same parameters, non-edit mode and rendered time
// > last change
+ $is_error = false;
if (($this->getOutputMode() == "preview" || $this->getOutputMode() == "presentation") &&
!$this->getCompareMode() &&
!$this->getAbstractOnly() &&
@@ -1845,12 +1846,18 @@ public function showPage()
$output = $this->obj->getRenderedContent();
} else {
$xsl = file_get_contents("./Services/COPage/xsl/page.xsl");
-
$this->log->debug("Calling XSLT, content: " . substr($content, 0, 100));
- $args = array( '/_xml' => $content, '/_xsl' => $xsl );
- $xh = xslt_create();
- $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params);
-
+ try {
+ $args = array( '/_xml' => $content, '/_xsl' => $xsl );
+ $xh = xslt_create();
+ $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params);
+ } catch (Exception $e) {
+ $output = "";
+ if ($this->getOutputMode() == "edit") {
+ $output = "