Browse Source

Update 'locallib.php'

Fix iLM edition (now is possible to update fields 'reevaluate', 'editingbehavior' and 'evaluate' of table 'iassign_ilm')
leo 1 year ago
parent
commit
c3feba807d
1 changed files with 282 additions and 120 deletions
  1. 282 120
      locallib.php

+ 282 - 120
locallib.php

@@ -4,8 +4,11 @@
  * This class provides all the functionality for an ia (interactive activities).
  *
  * Release Notes:
+ * - v 4.9.8 2022/09/15
+ *   + Fix iLM edition (now is possible to update fields 'reevaluate', 'editingbehavior' and 'evaluate' of table 'iassign_ilm')
  * - v 4.9.7 2022/02/11
- *   + Try to fix teacher edit of activity changing 'statement.id' to 'statement.file' in 'add_edit_iassign()'
+ *   + Try to fix teacher edit of activity changing 'statement.id' to 'statement.file' in 'add_edit_iassign()';
+ *   + Changed fix to activities order in 'show_iassign()', from "student view" to "teacher view"
  *
  * - v 4.9.6 2022/01/21
  *   + Try to fix view activity not sent through report ("view_iassign_current()": else if (!$student_answer) $loadTeacherActivity=true;)
@@ -133,12 +136,9 @@
 $CONF_WWW = 1; //TODO get iLM (JAR) from WWW, avoiding MoodleData
 
 
-/**
- * Standard base class for all iAssign
- */
-
+/// Standard base class for all iAssign
+//  Basic class to iAssign block of activities
 class iassign {
-
   var $cm;
   var $course;
   var $iassign;
@@ -213,7 +213,7 @@ class iassign {
     $this->return = $CFG->wwwroot . "/mod/iassign/view.php?id=" . $this->cm->id;
     $this->bottonPost = 0;
     $this->view_iassign = optional_param('action', false, PARAM_BOOL);
-    $this->activity = new activity(optional_param('iassign_current', NULL, PARAM_TEXT)); // this is the activity inside iAssign block
+    $this->activity = new activity(optional_param('iassign_current', NULL, PARAM_TEXT)); // this is the activity inside iAssign block (content file)
 
     $this->view();
     } // function __construct($iassign, $cm, $course)
@@ -364,6 +364,7 @@ class iassign {
 
 
   /// This method prints the teacher exercise
+  //  @calledby AJAX trhough "function action()" that calls "function auto_evaluate()"
   function get_teacher_exercise () {
     global $DB, $COURSE;
 
@@ -374,7 +375,12 @@ class iassign {
 
     //2021/12: $files = $fs->get_area_files(context_module::instance($this->cm->id)->id, 'mod_iassign', 'exercise', $iassign_statement->filesid);
     //TODO 2022: trocar "$iassign_statement->id" por "$iassign_statement->file"???
-    $files = $fs->get_area_files(context_module::instance($this->cm->id)->id, 'mod_iassign', 'exercise', $iassign_statement->id);
+    // ./lib/filestorage/file_storage.php: public function get_area_files($contextid, $component, $filearea, $itemid = false,...)
+    $files = $fs->get_area_files(context_module::instance($this->cm->id)->id, 'mod_iassign', 'exercise', $iassign_statement->id); // use itemid=$iassign_statement->id
+    if (!$files) { // try with 'iassign_statement->filesid'
+      //D echo "locallib.php: get_teacher_exercise(): com iassign_statement->id=" . $iassign_statement->id . " resulta vazio! Tente com iassign_statement->filesid=" . $iassign_statement->filesid . "<br/>\n";
+      $files = $fs->get_area_files(context_module::instance($this->cm->id)->id, 'mod_iassign', 'exercise', $iassign_statement->filesid);
+      }
 
     foreach ($files as $file) {
       if ($file->get_filename() != ".") {
@@ -641,11 +647,8 @@ class iassign {
     $url = "" . $CFG->wwwroot . "/mod/iassign/view.php?action=get_individual_submission&" . $param_aux . "&submissionid=" . $submissionid;
 
     $atual_submission = $DB->get_record('iassign_allsubmissions', array('id' => $submissionid));
-
     $atual_statement = $DB->get_record("iassign_statement", array("id" => $atual_submission->iassign_statementid));
-
-    $all_submissions = $DB->get_records('iassign_allsubmissions', 
-        array('iassign_statementid' => $atual_submission->iassign_statementid, 'userid' => $atual_submission->userid));
+    $all_submissions = $DB->get_records('iassign_allsubmissions', array('iassign_statementid' => $atual_submission->iassign_statementid, 'userid' => $atual_submission->userid));
 
     $user = $DB->get_record('user', array('id' => $atual_submission->userid));
 
@@ -726,7 +729,7 @@ class iassign {
         // Duplicate activity file
         $files_ids = $DB->get_records_sql('SELECT id FROM {files} WHERE component="mod_iassign" AND itemid=' . $filesid_from);
 
-        print 'Arquivos a serem copiados: ';
+        print("Files to be copied: "); //TODO: universalizar 'Arquivos a serem copiados: '
         print_r($files_ids);
         
         foreach ($files_ids as $fileid) {
@@ -833,7 +836,7 @@ class iassign {
     return $DB->get_records("iassign_statement", array("iassignid" => $iassignid));
     }
 
-  function get_courses_enroled_as_teacher($userid) {
+  function get_courses_enroled_as_teacher ($userid) {
     $all_enroled = enrol_get_users_courses($userid);
     $return = array();
     foreach ($all_enroled as $enroled) {
@@ -935,9 +938,7 @@ class iassign {
 
     print '<div>';
     foreach ($exercises_list as $exercise) {
-
       $submissions_list = $DB->get_records("iassign_allsubmissions", array("iassign_statementid" => $exercise->id));
-
       $iassign_ilm = $DB->get_record("iassign_ilm", array("id" => $exercise->iassign_ilmid));
 
       print '
@@ -956,7 +957,6 @@ class iassign {
       print '<div class="collapse" style="padding: 0 1.5rem;" id="item-'.$exercise->id.'">';
 
       foreach ($students_list as $student) {
-
         $total = 0;
         $student_submissions = [];
         foreach ($submissions_list as $submission) {
@@ -1081,7 +1081,6 @@ class iassign {
 
     // Get list of student id have submit for each exercise:
     foreach ($exercises_list as $exercise) {
-
       $iassign_ilm = $DB->get_record("iassign_ilm", array("id" => $exercise->iassign_ilmid));
 
       print '
@@ -1106,10 +1105,9 @@ class iassign {
         }
       print ']
         },'; // close "
-
       } // foreach ($exercises_list as $exercise)
 
-
+    // Start of JavaScript code to auto-evaluation
     print "        ];\n";
     print '
     var total_submissions = 0;
@@ -1241,7 +1239,6 @@ class iassign {
         }
       }
 
-
     // This function is called by the iLM to get the student s answer (to compare with re-evaluation)
     function getStudentAnswerURL () {
       return actual_answer_url; // to provide the current student answer (to "iassing_integration_functios.js" of iLM)
@@ -1261,7 +1258,6 @@ class iassign {
       $(".progress-bar").css("width", temp + "%").text(temp + "%");
       if (temp >= 100) {
         $(".progress-bar").removeClass("progress-bar-animated progress-bar-striped");
-
         $("#button_start").prop("disabled", false);
         $("#button_stop").prop("disabled", true);
         $("input:checkbox").attr("disabled", false);
@@ -1270,7 +1266,6 @@ class iassign {
         }
       }
 
-
     // Process the re-evaluated "grade" - DEVELOPER: here, do NOT use apostrophe!
     // The iLM method "getiLMContent()" must, after re-evaluate getting "new_grade", call this with "postResultAutoEval(new_grade)"
     function postResultAutoEval (grade = null) {
@@ -1375,7 +1370,6 @@ class iassign {
         actual_student++;
         run_individual_evaluation();
       } else {
-
         actual_student = 0;
         // Does it go to next exercise or is it finished?
         if (actual_exercise < selected_exercises.length) {
@@ -1411,7 +1405,6 @@ class iassign {
         }
       }
 
-
     function stop_evaluation () {
       stoped = true;
       //AJAX
@@ -1420,34 +1413,26 @@ class iassign {
       $(".progress-bar").removeClass("progress-bar-animated progress-bar-striped");
       $("input:checkbox").attr("disabled", false);
       $("#evaluate_alerts").text("' . get_string('auto_evaluate_stopped', 'iassign') . '");
-  clearInterval(var_interval);
-  }
-var exercises = [ '; // '
+     clearInterval(var_interval);
+     }
+    var exercises = [ '; // '
 
     foreach ($exercises_list as $exercise) {
       print $exercise->id . ',';
       }
-
     print ' ];';
-
     print ' var students = [ ';
-
     foreach ($students_list as $student) {
       print $student->userid . ',';
       }
     print '];';
-
     print ' var ilms = [';
-
     foreach ($exercises_list as $exercise) {
       $iassign_ilm = $DB->get_record("iassign_ilm", array("id" => $exercise->iassign_ilmid));
       print "'" . $CFG->wwwroot . "/mod/iassign/" . $iassign_ilm->file_jar . "/" . $iassign_ilm->file_class . "',";
       }
-
     print ']';
-
     print '</script>';
-
     print '
     <div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
       <div class="modal-dialog modal-dialog-centered" role="document">
@@ -1477,9 +1462,9 @@ var exercises = [ '; // '
               </tr>
             </thead>
             <tbody>'; // "
+    // End of JavaScript code to auto-evaluation
 
     foreach ($students_list as $student) {
-
       $user = $DB->get_record('user', array('id' => $student->userid));
       $avatar = new user_picture($user);
       $avatar->courseid = $COURSE->id;
@@ -1562,64 +1547,87 @@ var exercises = [ '; // '
     } // function move_activity()
 
 
+// AQUI
+
   /// This method duplicates an iAssign activity
   function duplicate_activity () {
     global $USER, $CFG, $COURSE, $DB, $OUTPUT;
 
-    $id = $this->cm->id;
+    // Not used: $id = $this->cm->id; // Get {iassign}.id from {course_module}: {iassign_statement}.iassignid = {course_module}.id = $id
     $iassignid = optional_param('iassign_current', NULL, PARAM_TEXT);
 
     $context = context_module::instance($this->cm->id);
 
-    $contextuser = context_user::instance($USER->id);
+    // Not used: $contextuser = context_user::instance($USER->id);
+echo "locallib.php: duplicate_activity()<br/>"; //R
+echo "cm.id=" . $id . ", iassignid=" . $iassignid . ", context.id=" . $contextuser->id . "<br/>"; //R  ", context.instanceid=" . $contextuser->instanceid
 
     // Get the the iAssign acitivity to be duplicated
     $iassign_statement = $DB->get_record("iassign_statement", array("id" => $iassignid));
+echo "{iassign_statement}: #iassign_statement=" . count($iassign_statement) . "<br/>"; //R
 
     // Remove the current id of activity
-    $id_source_copy = $iassign_statement->id;
-    $iassign_statement->id=0;
+    $original_iassign_statement_id = $iassign_statement->id;
+    $iassign_statement->id=0; // will receive the new {iassign_statement}.id - below "$updateentry->id = $id"
 
     // Include prefix (Copy of ...)
-    $iassign_statement->name = get_string('duplicate_iassign_prefix', 'iassign') . ' ' . $iassign_statement->name;
+    $iassign_statement->name = get_string('duplicate_iassign_prefix', 'iassign') . ' ' . $iassign_statement->name; // new name to {iassign_statement}.name
 
     // Get the information about current author, and add this information in author_modified field
-    $author = $DB->get_record("user", array('id' => $USER->id));
-    $iassign_statement->author_modified_name = $author->firstname . '&nbsp;' . $author->lastname;
+    $author = $DB->get_record("user", array('id' => $USER->id)); // id; auth; ... username; password; idnumber; firstname; lastname; email; ... description ...
+    $iassign_statement->author_modified_name = $author->firstname . ' ' . $author->lastname;
     $iassign_statement->author_modified = $iassign_statement->author_modified_name;
+echo "iassign_statement.id=" . $iassign_statement->id . ",iassign_statement.name =" . $iassign_statement->name . ", id_source_copy=" . $original_iassign_statement_id .
+", author.id=" . $author->id . ", author.firstname=" . $author->firstname . "<br/>";
 
     // Store the activity in the table
-    if ($id_ = $DB->insert_record("iassign_statement", $iassign_statement)) {
+//R    if ($new_iassign_statement_id = $DB->insert_record("iassign_statement", $iassign_statement)) {
+if (1==1) { //R REMOVER!!!!
 
       // Duplicate activity file
       $fs = get_file_storage(); // Get reference to all files in Moodle data
       //2021/12 $files = $fs->get_area_files($context->id, 'mod_iassign', 'exercise', $iassign_statement->filesid);
-      $files = $fs->get_area_files($context->id, 'mod_iassign', 'exercise', $id_source_copy);
+      $files = $fs->get_area_files($context->id, 'mod_iassign', 'exercise', $original_iassign_statement_id);
+echo "{files}: #files=" . count($files) . "<br/>"; //R
+// {files}.get_id()
 
       foreach ($files as $value) {
         if ($value->get_filename() != ".") {
-          $last_id = $DB->get_record_sql('SELECT itemid FROM {files} WHERE component="mod_iassign" ORDER BY itemid DESC LIMIT 1')->itemid;
+	  // Must have: {files}.itemid = {iassign_statement}.id ; {iassign_statement}.filesid = {files}.id
+
+	  // Get the last entry in {files} $last_id and use as new {files}.itemid = $last_id+1
+          //2021/12 $last_id = $DB->get_record_sql('SELECT itemid FROM {files} WHERE component="mod_iassign" ORDER BY itemid DESC LIMIT 1')->itemid;
+echo "{files}: id=" . $value->id . "=" . $value->get_id() . ", filename=" . $value->filename . ", itemid=" . $value->itemid . ", contextid=" . $value->contextid . ", component=" . $value->component
+. ", filearea=" . $value->filearea . ", userid=" . $value->userid . "<br/>"; //R
+//print_r($value); echo "<br/>";
+//R echo "last_id = {files}.itemid = " . $last_id . "<br/>";
 
           //2021/12 $newfile = $fs->create_file_from_storedfile(array('contextid' => $context->id, 'component' => 'mod_iassign', 'filearea' => 'exercise', 'itemid' => ($last_id + 1)), $value);
-          $newfile = $fs->create_file_from_storedfile(array('contextid' => $context->id, 'component' => 'mod_iassign', 'filearea' => 'exercise', 'itemid' => $id_), $value);
+/* //R
+          // ./lib/filestorage/file_storage.php: '$newfile' is protected
+          $newfile = $fs->create_file_from_storedfile(array('contextid' => $context->id, 'component' => 'mod_iassign', 'filearea' => 'exercise', 'itemid' => $new_iassign_statement_id), $value);
 
+          // Now update {iassign_statement}.filesid with '$newfile->id': {iassign_statement}.filesid = {files}.id
           $updateentry = new stdClass();
-          $updateentry->id = $id_;
+          $updateentry->id = $new_iassign_statement_id; // points {iassign_statement}.id to the new entry of {iassign_statement}
+
           //2021/12 $updateentry->filesid = $newfile->get_itemid();
-          $updateentry->filesid = $id_;
+          $updateentry->filesid = $newfile->get_id(); // points {iassign_statement}.filesid to the new {files}: {iassign_statement}.filesid = {files}.id
 
           // Update the duplicated iLM iAssign with new file id
           $DB->update_record("iassign_statement", $updateentry);
+*/
           }
         }
       }
 
     // log event --------------------------------------------------------------------------------------
-    iassign_log::add_log('duplicate_iassign_exercise', 'name: ' . $author->firstname, $id_, $this->cm->id);
+//R    iassign_log::add_log('duplicate_iassign_exercise', 'name: ' . $author->firstname, $new_iassign_statement_id, $this->cm->id);
 
-    $this->return_home_course('duplicated_activity');
+//R    $this->return_home_course('duplicated_activity');
     exit;
-    }
+    } // function duplicate_activity()
+
 
   // / This method gets the content from comment and register it
   function add_comment () {
@@ -2282,7 +2290,102 @@ var exercises = [ '; // '
 
     $this->action = 'viewsubmission';
     $this->view_iassign_current();
-    }
+    } // function edit_grade()
+
+
+//2022: ---------------------------------------------------------------------------------------------------------------------------------
+//2022: Recuperacao {files} {iassign_statement}
+//2022/02 see_all_files_context($context, $DB)
+
+  /// Temporary: fix 'iassign_statement.filesid' and 'files.itemid' (iassign_statement.filesid <- files.id; files.itemid <- iassign_statement.id)
+  //  First version of iAssign used a random value to associate 'files.itemid' with 'iassign_statement.file'
+  //  @calledby locallib.php ! get_update_files($context_id, $component, $filearea, $iassign_statement)
+  static function update_iassign_statement_files ($iassign_statement_id, $context_id, $component, $filearea, $files_ilmid) {
+    global $DB; //2022: echo "update_iassign_statement_files:<br/>";//D2022
+    // $files = $DB->get_records("files", array("component" => "mod_iassign", "filearea" => "exercise", "contextid" => $context_id, "itemid" => $files_ilmid)); // contextid=1390 ; itemid=400 ;
+    // $sql_query = "SELECT * FROM {files} WHERE component='mod_iassign' AND filearea='exercise' AND contextid=" . $context_id . " AND filename<>'.' AND itemid=" . $files_ilmid;
+    $sql_query = "SELECT * FROM {files} WHERE component='mod_iassign' AND filearea='exercise' AND contextid=" . $context_id . " AND itemid=" . $files_ilmid;
+//echo "sql_query=" . $sql_query . "<br/>";//D2022
+    $elem_in_files = $DB->get_records_sql($sql_query);
+    if (!$elem_in_files) {
+      print "Vazio! <br/>"; //TODO: se mantiver, internacionalizar!
+      return NULL;
+      }
+    // if (count($elem_in_files)>1) { echo "Problema! Mais de um arquivo!<br/>"; return NULL; }
+    //2022: echo "#files=" . count($elem_in_files) . ": "; // print_r($elem_in_files); echo "<br/>";//D2022
+    foreach ($elem_in_files as $element_file) { // since ID is greater than 0, only "$file1 = $elem_in_files[0]" will not work!
+      if ($element_file->filename != '.') { // If not '.' is the actual file
+        $file1 = $element_file;
+//2022: echo " - files: id=" . $file1->id . "; contextid=" . $file1->contextid . "; filearea=" . $file1->filearea . "; itemid=" . $file1->itemid . " <- " . $iassign_statement_id . "<br/>";
+        // this '$file1' has the 'hashcontent' of the real file content, then it will be used to update 'iassign_statement.filesid' <- 'files.id'
+        // break;
+        }
+      // Update 'files.itemid' with 'iassign_statement.id'
+      $newentry = new stdClass();
+      $newentry->id = $element_file->id; $newentry->itemid = $iassign_statement_id;
+//2022: echo " &nbsp; &nbsp; &nbsp; &nbsp; Update 'files.itemid': "; print_r($newentry); echo "<br/>";
+
+//2022: //leo voltar a atualizacao ou deixar para ADMIN via 'settings_activities.php'???????????????????????????????????????????????????????????????????????????
+//2022:      if (!$DB->update_record('files', $newentry)) print_error('error_update', 'iassign');
+
+      }
+    // Update 'iassign_statement.filesid' with 'files.id'
+    $newentry = new stdClass();
+    $newentry->id = $iassign_statement_id; $newentry->filesid = $file1->id;
+//2022: echo " &nbsp; &nbsp; &nbsp; &nbsp; Update 'iassign_statement.filesid': "; print_r($newentry); echo "<br/>";
+
+//2022: //leo voltar a atualizacao ou deixar para ADMIN via 'settings_activities.php'???????????????????????????????????????????????????????????????????????????
+//2022:    if (!$DB->update_record('iassign_statement', $newentry)) print_error('error_update', 'iassign');
+    } // static function update_iassign_statement_files($iassign_statement_id, $context_id, $component, $filearea, $files_ilmid)
+
+
+  /// Get file from table 'files', if 'files.itemid != iassign_statement.id' then update 'files.itemid' with 'iassign_statement.id'
+  //  Usually 'context.instanceid' is 'course_modules.id' and 'course_modules.instance = iassign.id'
+  //  However since iAssign is a "block of actual activities" from "iassign_statement", we store in 'files.itemid' the 'iassign_statement.id'
+  //  @calledby function add_edit_iassign(): if ($this->action == 'edit'): to edit iAssign activity
+  static function get_update_files ($context_id, $component, $filearea, $iassign_statement, $fs) {
+    // $fs is the reference to all files in Moodle data
+echo "<br/><br/><br/><br/><br/>get_update_files: iassign_statement: " . $context_id . ", " . $component . ", " . $filearea . ", " . 
+     "id=" . $iassign_statement->id . ", file=" . $iassign_statement->file . ", filesid=" . $iassign_statement->filesid .
+     ", iassign_ilmid =" . $iassign_statement->iassign_ilmid . ",name=" . $iassign_statement->name . "<br/>\n";//D2022
+    $msgAux = ""; $must_update_files_itemid = 0;
+    // To consider old versions with improper association 'files.itemid': try 'iassign_statement.id' (correct one), 'iassign_statement.file' and 'iassign_statement.filesid'
+    // Correct association: {files}->itemid = $iassign_statement->id and {files}->id=$iassign_statement->fileid;
+    $files = $fs->get_area_files($context_id, $component, $filearea, $iassign_statement->id); // try: 'iassign_statement.id'
+    if (!$files) { // Could not find with 'iassign_statement.id'
+      $msgAux .= "- Nao com 'iassign_statement.id'<br/>\n"; $must_update_files_itemid = 1;
+      $files = $fs->get_area_files($context_id, $component, $filearea, $iassign_statement->file); // try with 'iassign_statement.file'
+      if (!$files) { // Could not find with 'iassign_statement.file'
+        $msgAux .= "- Nao com 'iassign_statement.file'<br/>\n";
+        $files = $fs->get_area_files($context_id, $component, $filearea, $iassign_statement->filesid); // try with 'iassign_statement.filesid'
+        if (!$files) { // Could not find with 'iassign_statement.file'
+          //$files = $fs->get_area_files($context_id, $component, $filearea, $iassign_statement->filesid-1); // try with 'iassign_statement.filesid'-1
+          //if (!$files) { // Could not find with 'iassign_statement.file'
+          //  $msgAux .= "- Nao com 'iassign_statement.filesid'-1<br/>\n";
+            echo "ERRO completo: " . $msgAux;//D2022
+            return NULL;
+            // Desisto! $files = $fs->get_area_files($context_id, $component, $filearea, $iassign_statement->filesid); // try with 'iassign_statement.filesid'
+          //  }
+          //else { $must_update_files_itemid = $iassign_statement->filesid-1; echo "OK 4, nao com {'id,file,filesid'), mas pegou com 'iassign_statement.filesid'-1=" . $iassign_statement->filesid . "-1<br/>\n"; }
+          }
+        else { $must_update_files_itemid = $iassign_statement->filesid; echo "OK 3, nao com 'id', nem com 'file', mas pegou com 'iassign_statement.filesid'=" . $iassign_statement->filesid . "<br/>\n"; }
+        }
+      else { $must_update_files_itemid = $iassign_statement->file; echo "OK 2, nao com 'id', pegou com 'iassign_statement.file'=" . $iassign_statement->file . "<br/>\n"; }
+      }
+    else echo "OK 1, pegou com 'iassign_statement.id'=" . $iassign_statement->id . "<br/>\n";//D2022
+
+    if ($must_update_files_itemid!=0) {
+      $res_update = iassign::update_iassign_statement_files($iassign_statement->id, $context_id, $component, $filearea, $must_update_files_itemid);
+      }
+
+    foreach ($files as $file) { if ($file->get_filename() != '.') break; }
+    //$files_itemid = $file->get_itemid(); // /var/www/html/saw2021_1/lib/filestorage/stored_file.php: devolve 'files.itemid'
+    //$files_id = $file->get_id(); // file_record
+    echo "files[.]: id=" . $files_id . ", itemid=" . $files_itemid . "<br/>\n"; //D2022
+    return $file;
+    } // function get_update_files($context_id, $component, $filearea, $iassign_statement)
+//2022: Recuperacao {files} {iassign_statement}
+//2022: ---------------------------------------------------------------------------------------------------------------------------------
 
 
   /// Add or Edit interactive activities
@@ -2370,9 +2473,7 @@ var exercises = [ '; // '
       $param->show_answer = 1;
       } // if ($this->action == 'add')
     elseif ($this->action == 'edit') {
-
       $COURSE->iassign_list = array();
-
       $this_activity = $this->activity->get_activity();
 
       if ($this_activity != null) { // first enter here: fill form data
@@ -2465,19 +2566,77 @@ var exercises = [ '; // '
         $param->automatic_evaluate = $iassign_statement_current->automatic_evaluate;
         $param->show_answer = $iassign_statement_current->show_answer;
 
+        // Association {iassign_statement} with {files}
+        // Attention to the {files}.contextid and {files}.itemid used: "{files}.itemid" must be "{iassign_statement}.id" (and {iassign_statement}.filesid={files}.id)
+        // Old version used: {iassign_statement}.files = {files}.itemid with a randam value...
+        // ./lib/filestorage/file_storage.php: public function get_area_files($contextid, $component, $filearea, $itemid = false,...)
         $fs = get_file_storage(); // Get reference to all files in Moodle data
 
-        //2021/12 $files = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->filesid);
-        //2022/02 $files = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->id); // em alguns "_files.id" tem 'file' NAO 'id'
-        $files = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->file); // It must have: {files}->id=$iassign_statement_current->file
-
-        if ($files) {
-          foreach ($files as $file) {
-            if ($file->get_filename() != '.') {
-              $param->filename = $file->get_filename();
-              $param->file = $file->get_id();
-              $param->fileold = $file->get_id();
-              $COURSE->iassign_file_id = $file->get_id();
+        //2021/12 $files_list = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->filesid);
+        //2022/02 $files_list = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->id); // em alguns "_files.id" tem 'file' NAO 'id'
+
+        // It must have: {files}->id=$iassign_statement_current->file
+        //if ($iassign_statement_current->filesid) // new association {files}.itemid = {iassign_statement}.id       //TODO: depois deixar apenas este
+        //  $files_list = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->id); //TODO: depois deixar apenas este
+        //else
+        if ($iassign_statement_current->file) // old association {files}.itemid = {iassign_statement}.file
+          $files_list = $fs->get_area_files($context->id, $component, $filearea, $iassign_statement_current->file);
+
+	// ------------------------------------------------------------------------------------------------------------------------------------
+        // Recover association {iassign_statement}/{files}
+	// It uses "files_functions.php ! update_iassignstatement_files(...)" to (eventually) reconstruct relation
+
+        //D echo "<br/><br/><br/><br/><br/><br/><br/><br/>locallib.php: add_edit_iassign(): #files_list=" . count($files_list) . "<br/>\n";
+        if (!$files_list) { // try with 'iassign_statement->filesid'
+          //D echo "locallib.php: add_edit_iassign(): com iassign_statement->id=" . $iassign_statement->id . " resulta vazio! Tente com iassign_statement->filesid=" . $iassign_statement->filesid . "<br/>\n";
+          //$files_list = $fs->get_area_files(context_module::instance($this->cm->id)->id, 'mod_iassign', 'exercise', $iassign_statement->filesid);
+          $files_list = $fs->get_area_files($context->id, 'mod_iassign', 'exercise', $iassign_statement_current->filesid);
+          if (!$files_list) { // try with 'iassign_statement->id'
+            //D echo "locallib.php: add_edit_iassign(): com iassign_statement->id=" . $iassign_statement->id . " resulta vazio! Tente com iassign_statement->id=" . $iassign_statement->id . "<br/>\n";
+            $files_list = $fs->get_area_files($context->id, 'mod_iassign', 'exercise', $iassign_statement_current->id);
+            }
+          //$files_list = $fs->get_area_files(context_module::instance($this->cm->id)->id, 'mod_iassign', 'exercise', $iassign_statement->filesid);
+          $files_list = $fs->get_area_files($context->id, 'mod_iassign', 'exercise', $iassign_statement_current->filesid);
+          if ($files_list) {
+            // Redefine fields {iassign_statement}.filesid and {files}.itemid such as: {iassign_statement}.filesid={files}.id; {files}.itemid={iassign_statement}.id
+            $is_obj = $iassign_statement_current;
+            $count_fs = 0;
+            foreach ($files_list as $one_files) {
+              if ($count_fs==0) $f1_obj = $one_files; // $files_list[0]; // from {files}
+              else if ($count_fs==1) $f2_obj = $one_files; // $files_list[1]; // from {files}
+              $count_fs++;
+              }
+            //D_ echo " + #files_list = " . count($files_list) . "<br/>\n";
+            //D_ echo " + is_obj: " . $is_obj->name . ", id=" . $is_obj->id . ", files=" . $is_obj->files . ", filesid=" . $is_obj->filesid . ", iassignid=" . $is_obj->iassignid
+            //D_      . ", type_iassign=" . $is_obj->type_iassign . ", author_name=" . $is_obj->author_name . ", iassign_ilmid=" . $is_obj->iassign_ilmid
+            //D_      . ", automatic_evaluate=" . $is_obj->automatic_evaluate . ", show_answer=" . $is_obj->show_answer . ", filesid=" . $is_obj->filesid
+            //D_      . ", store_all_submissions=" . $is_obj->store_all_submissions . "<br/>\n";
+            //D_ echo " + f1_obj: filename = '" . $f1_obj->get_filename() . "', id=" . $f1_obj->get_id()
+            //D_      . "', contenthash=" . $f1_obj->get_contenthash() . "', contextid=" . $f1_obj->get_contextid() . "', filearea=" . $f1_obj->get_filearea()
+            //D_      . "', itemid=" . $f1_obj->get_itemid() . "', userid=" . $f1_obj->get_userid() . "', author=" . $f1_obj->get_author()
+            //D_      . "', timecreated=" . date("d/m/Y H:i:s", $f1_obj->get_timecreated()) . "<br/>\n";
+            //D_ echo " + f2_obj: filename = '" . $f2_obj->get_filename() . "', id=" . $f2_obj->get_id()
+            //D_      . "', contenthash=" . $f2_obj->get_contenthash() . "', contextid=" . $f2_obj->get_contextid() . "', filearea=" . $f2_obj->get_filearea()
+            //D_      . "', itemid=" . $f2_obj->get_itemid() . "', userid=" . $f2_obj->get_userid() . "', author=" . $f2_obj->get_author()
+            //D_      . "', timecreated=" . date("d/m/Y H:i:s", $f2_obj->get_timecreated()) . "<br/>\n";
+            require_once('files_functions.php'); // Get auxiliary functions to manage {iassign_statement}/{files}
+            $result = update_iassignstatement_files($DB, $is_obj->id, $f1_obj->get_id(), $is_obj, $f1_obj, $f2_obj); // ./files_functions.php
+            if (!$result) print "Could not change {iassign_statement}.filesid=" . $is_obj->id . " or {files}.itemid=" . $f1_obj->itemid . "<br/>";
+            }
+          } // if (!$files_list)
+
+        //D //echo "locallib.php: add_edit_iassign(): contextid=" . ($this->cm->id)->id . ", iassign_statement->id=" . $iassign_statement->id . ", iassign_statement->filesid=" . $iassign_statement->filesid . ", #files_list=" . count($files_list) . "<br/>\n";
+        //D echo "locallib.php: add_edit_iassign(): contextid=" . $context->id . ", iassign_statement_current->id=" . $iassign_statement_current->id . ", iassign_statement_current->filesid=" . $iassign_statement_current->filesid . ", #files_list=" . count($files_list) . "<br/>\n";
+
+        // $files_list = iassign::get_update_files($context->id, $component, $filearea, $iassign_statement_current, $fs); //2022: tentativa de recupearar arquivos se perdido
+        if ($files_list) { // get the first {files} with real "filename"
+          foreach ($files_list as $file_item) {
+            if ($file_item->get_filename() != '.') {
+              $param->filename = $file_item->get_filename();
+              $param->file = $file_item->get_id();
+              $param->fileold = $file_item->get_id();
+              $COURSE->iassign_file_id = $file_item->get_id();
+              break; // stop at the first with a "real" filename
               }
             }
           }
@@ -2639,7 +2798,7 @@ var exercises = [ '; // '
         } // foreach ($inter_dependency as $tmp)
       } // if ($iassign_statement)
     return $dependency;
-    }
+    } // function search_sub_dependency($search_iassing_id)
 
 
   // Warning message
@@ -2776,7 +2935,7 @@ var exercises = [ '; // '
       \core\notification::error(get_string('activity_not_found', 'iassign'));
       print $OUTPUT->footer();
       exit;
-    }
+      }
 
     $ilm = new ilm($iassign_statement_activity_item->iassign_ilmid);
 
@@ -3051,24 +3210,18 @@ var exercises = [ '; // '
       print activity::toggle_columns_script();
 
       if ($iassign_submission && $allow_resubmission) {
-
         // Put the iLM to
         print $OUTPUT->box_start();
-
         print '<p><strong>' . $last_iassign . '</strong></p>';
-        //d if ($ilm->confirms_jar ( $iassign_statement_activity_item->file, $iassign_ilm->file_jar, $this->cm->id )) {
+        //d if ($ilm->confirms_jar($iassign_statement_activity_item->file, $iassign_ilm->file_jar, $this->cm->id )) {
         $enderecoPOST = "";
-
         // Prepare tags to present the iLM
         print $ilm->view_iLM($iassign_statement_activity_item, $student_answer, $enderecoPOST, false);
-
         //d } // if ($this->confirms_jar($iassign_statement_activity_item->file, $iassign_ilm->file_jar))
 
         print $OUTPUT->box_end();
-
         } // if ($iassign_submission && $allow_resubmission)
       else { // if ($iassign_submission && $allow_resubmission) - techer view student answer
-
 	// If '$student_answer' is empty, then the student does not submit any solution to the exercice
         // ATTENTION: exception used by iGeom (exercise with "script")
         $loadTeacherActivity = false; // use 'true' whenever 'special_param1 == 1'
@@ -3087,7 +3240,6 @@ var exercises = [ '; // '
         print activity::toggle_columns_script();
         // Prepare tags to present the iLM
         print $OUTPUT->box($ilm->view_iLM($iassign_statement_activity_item, $student_answer, $enderecoPOST, $loadTeacherActivity));
-
         }
 
       //2020 Eliminei daqui o codigo para colocar o quadro com area para enivar e ler comentarios
@@ -3187,10 +3339,9 @@ var exercises = [ '; // '
 
       $enderecoPOST = "" . $CFG->wwwroot . "/mod/iassign/view.php?" . $param_aux;
 
-      $this->activity->view_dates();
+      $this->activity->view_dates(); // prints "Type of activity:", "Available from:"
 
       if ($this->view_iassign) { // Box 5 to 'proposition' - open
-
         print $OUTPUT->box_start();
 
         print '<table width=100% border=0 valign="top">' . "\n";
@@ -3321,7 +3472,6 @@ var exercises = [ '; // '
           print '</tr></table>' . "\n";
 
           // Presents the iLM
-         
           print '<table width=100% border=0 valign="top">' . "\n";
           print '<td width=80% align="left">';
           print '<strong>' . $last_iassign . ' ' . get_string('repeat_msg', 'iassign') . '</strong></td>' . "\n"; // If you want to do this activity from the beginning again, use the \"Redo button\".
@@ -3336,15 +3486,7 @@ var exercises = [ '; // '
           print '<p class="mt-5"><strong>' . get_string('proposition', 'iassign') . '</strong></p>' . "\n";
           print '<div class="proposition">' . $iassign_statement_activity_item->proposition . '</div>' . "\n";
 
-          $output = '';
-
-          if (!$iassign_ilm) {
-            $iassign_ilm = new stdClass();
-            $iassign_ilm->file_jar = "";
-            }
-
-          $output .= $OUTPUT->box_start();
-
+          $output = $OUTPUT->box_start();
           $USER->iassignEdit = $this->bottonPost;
 
           // ---
@@ -3369,7 +3511,7 @@ var exercises = [ '; // '
             $output .= $ilm->view_iLM($iassign_statement_activity_item, $student_answer, $enderecoPOST, $loadTeacherActivity); // presents iLM
             }
 
-           //1 Desse modo entre area para comentario, mas nao seu botao separado - deixar para o final com botao!
+          //1 Desse modo entre area para comentario, mas nao seu botao separado - deixar para o final com botao!
           //1 if ($iassign_statement_activity_item->type_iassign == 3) {
           //1   $history_comment = '';
           //1   if ($iassign_submission) {
@@ -3385,14 +3527,11 @@ var exercises = [ '; // '
           //1   $only_one_send_button = 1; // avoid put comment frame again (bellow)
           //1   }
 
-
           $output .= $OUTPUT->box_end();
           print $output;
           } // if ($this->view_iassign)
 
-
         print $OUTPUT->box_end(); // Box 5 to 'proposition' - close
-
         } // if ($this->view_iassign)
 
       } // elseif (has_capability('mod/iassign:submitiassign', $USER->context, $USER->id))
@@ -3433,7 +3572,6 @@ var exercises = [ '; // '
 
       $output .= $OUTPUT->box_start();
 
-
       //if (!empty($history_comment)) {
         $output .= "<a id='comments'></a>";
         $output .= "  <table id='outlinetable' class='generaltable boxaligncenter' cellpadding='5' width='100%'> \n";
@@ -5384,7 +5522,7 @@ class activity {
   /// Constructor of class.
   //  @param int $id Id of activity
   //  3.1 update PHP 7.0 compatibility for all moodle versions
-  //D public function activity($id) { self::__construct($id); }
+  //  public function activity($id) { self::__construct($id); }
 
   function __construct ($id) {
     global $DB;
@@ -5433,14 +5571,14 @@ class activity {
 
     $bottonDelete_yes = get_string('delete_iassign', 'iassign');
     $deleteiassignyes = $CFG->wwwroot . "/mod/iassign/view.php?id=" . $USER->cm . "&action=deleteyes&iassign_current=" . $this->activity->id;
-    $output .= "<form name='formDelete' id='formDelete' method='post' action='$deleteiassignyes' enctype='multipart/form-data'>\n";
-    $output .= " <input type=submit value='$bottonDelete_yes'/>\n";
+    $output .= "<form name='formDelete' id='formDelete' method='post' action='" . $deleteiassignyes . "' enctype='multipart/form-data'>\n";
+    $output .= " <input type=submit value='" . $bottonDelete_yes . "'/>\n";
     $output .= "</form>\n";
     $output .= '</td><td>';
     $bottonDelete_no = get_string('delete_cancel', 'iassign');
     $deleteiassignno = $CFG->wwwroot . "/mod/iassign/view.php?id=" . $USER->cm . "&action=deleteno&iassign_current=" . $this->activity->id;
-    $output .= "<form name='formDelete' id='formDelete' method='post' action='$deleteiassignno' enctype='multipart/form-data'>\n";
-    $output .= " <p><input type=submit value='$bottonDelete_no'/></p>\n";
+    $output .= "<form name='formDelete' id='formDelete' method='post' action='" . $deleteiassignno . "' enctype='multipart/form-data'>\n";
+    $output .= " <p><input type=submit value='" . $bottonDelete_no . "'/></p>\n";
     $output .= "</form>\n";
     $output .= '</td></tr></table>' . "\n";
     $output .= $OUTPUT->box_end();
@@ -5554,7 +5692,7 @@ class activity {
     }
 
 
-  /// Add news interactive activities (register in table 'iassign_statement')
+  /// Add new interactive activities (register in table 'iassign_statement')
   //  @calledby this->add_edit_iassign() : $iassignid = $this->activity->new_iassign($result);
   //  @see      ilm_manager.php: $ilm_manager_instance->ilm_editor_new();
   function new_iassign ($param) {
@@ -5618,8 +5756,8 @@ class activity {
 
       $itemid = $file->get_itemid() + $id; //TODO Verificar: melhor deixar "$itemid = $file->get_itemid()" pois assim 'files.itemid' guarda 'iassign_statement.id'???
 
-      // IGOR: itemid do arquivo é o mesmo que o id do statemente registrado acima:
-      //$itemid = $id;
+      // ATTENTION: {files}.itemid must be equal to {iassign_statement}.id
+      // $itemid = $id;
 
       // File already inserted in other context!
       //TODO Verificar se apenas esta' inserindo nova referencia em 'files' (NAO deve duplicar no Moodle Data)
@@ -5734,7 +5872,7 @@ class activity {
     if ($events) {
       foreach ($events as $value) {
         if ($value->description == $iassign_statement_activity_item->name) {
-            $DB->delete_records('event', array('id' => $value->id));
+          $DB->delete_records('event', array('id' => $value->id));
           }
         }
       }
@@ -5752,7 +5890,6 @@ class activity {
     $fileold = $fs->get_file_by_id($param->fileold);
 
     if ($param->file != $param->fileold) {
-
       if ($fileold) {
         $fileoldarea = $fs->get_area_files($fileold->get_contextid(), $fileold->get_component(), $fileold->get_filearea(), $fileold->get_itemid());
         foreach ($fileoldarea as $value) {
@@ -5785,14 +5922,10 @@ class activity {
     else
       $proposition_text = $proposition;
     $newentry->proposition = $proposition_text;
-
     $newentry->iassign_ilmid = $param->iassign_ilmid;
-
     $newentry->filesid = $param->file;    // came from a file from 'get_file_storage()' (it is its ID)
-
     $newentry->grade = $param->grade;
     $newentry->author_modified_name = $param->author_modified_name;
-
     $newentry->timemodified = time();
     if ($param->type_iassign == 1) {
       $newentry->timedue = 0;
@@ -6135,9 +6268,13 @@ class ilm_settings {
 
 
   /// Function for get form variables for add, edit, or copy iLM
-  //  @calledby settings_ilm.php (2 times, initially to fill the form, second to register the iLM)
+  //  This function is called to fill in the iLM data to the form
+  //  The function 'edit_ilm(.)' bellow is responsible to process edited data
+  //  @calledby settings_ilm.php: On the first call $ilm_id is defined: the calling is necessary to fill in data to the form
+  //  @calledby settings_ilm.php: On the second call $ilm_id empty (however must be used)
   //  @see      settings_form.php
   //  @see      locallib.php : static function copy_new_version_ilm ($param) : perform the data register (files and database)
+  //  @see      locallib.php : static function edit_ilm ($param,$itemid): perform the data register (files and database) in edition process
   //  @param int $ilm_id Id of iLM
   //  @param string $action String with the action
   //  @return object Return an object with forms variables
@@ -6149,7 +6286,7 @@ class ilm_settings {
     $iassign_ilm = $DB->get_record('iassign_ilm', array('id' => $ilm_id));
 
     $param = new stdClass();
-    //D echo "locallib.php: add_edit_copy_ilm: ilm_id,=$ilm_id, action="; print_r($action); echo "<br/>---------------------------------<br/>";
+
     $param->action = $action;
     $param->ilm_id = $ilm_id;
     $CFG->action_ilm = $action;
@@ -6171,11 +6308,15 @@ class ilm_settings {
       $param->enable = 0; // 0 - hide / 1 - show
       $param->timecreated = time();
       $param->timemodified = time();
-      $param->evaluate = 0;
+      $param->evaluate = 0; // evaluate = 1 => iLM has auto-evaluation method
+      $param->reevaluate = 0; // reevaluate = 1 => allows to the teacher calls method to re-evaluate (does it in batch, to all students)
+      $param->editingbehavior = 0; // editingbehavior = 1 => iLM auto-evaluation remains working over a solution sent by the student (iGeom does not work, iVProg does)
+      $param->submissionbehavior = 0; // 0 => 'After submission, this iLM remains on the same page'; 1 => 'After submission, this iLM changes the current page'
       $param->parent = 0;
       }
     elseif ($action == 'edit') { // static function add_edit_copy_ilm($ilm_id, $action)
       if ($iassign_ilm) {
+        //D echo "* entrou no iassign_ilm="; print_r($iassign_ilm); echo "<br/>\n"; //exit;
         $description = json_decode($iassign_ilm->description);
 
         $param->title = get_string('edit_ilm', 'iassign');
@@ -6214,10 +6355,13 @@ class ilm_settings {
         $param->enable = $iassign_ilm->enable;
         $param->timecreated = $iassign_ilm->timecreated;
         $param->timemodified = time();
-        $param->evaluate = $iassign_ilm->evaluate;
+        $param->evaluate = $iassign_ilm->evaluate; // evaluate = 1 => iLM has auto-evaluation method
+        $param->reevaluate = $iassign_ilm->reevaluate; // reevaluate = 1 => allows to the teacher calls method to re-evaluate (does it in batch, to all students)
+        $param->editingbehavior = $iassign_ilm->editingbehavior; // editingbehavior = 1 => iLM auto-evaluation remains working over a solution sent by the student (iGeom does not work, iVProg does)
+        $param->submissionbehavior = $iassign_ilm->submissionbehavior; // 0 => 'After submission, this iLM remains on the same page'; 1 => 'After submission, this iLM changes the current page'
         $param->parent = $iassign_ilm->parent;
-        }
-      }
+        } // if ($iassign_ilm)
+      } // elseif ($action == 'edit')
     elseif ($action == 'new_version') { // Reaches this point from the form to add new iLM
       // @see ./settings_ilm.php: $param = ilm_settings::add_edit_copy_ilm($ilm_id, $action);
       // $iassign_ilm = $DB->get_record('iassign_ilm', array('id' => $ilm_id));
@@ -6255,9 +6399,12 @@ class ilm_settings {
         $param->timecreated = time();
         $param->timemodified = time();
         $param->evaluate = $iassign_ilm->evaluate;
+        $param->reevaluate = $iassign_ilm->reevaluate; // reevaluate = 1 => allows to the teacher calls method to re-evaluate (does it in batch, to all students)
+        $param->editingbehavior = $iassign_ilm->editingbehavior; // editingbehavior = 1 => iLM auto-evaluation remains working over a solution sent by the student (iGeom does not work, iVProg does)
+        $param->submissionbehavior = $iassign_ilm->submissionbehavior; // 0 => 'After submission, this iLM remains on the same page'; 1 => 'After submission, this iLM changes the current page'
         $param->parent = $iassign_ilm->parent;
-        }
-      }
+        } // if ($iassign_ilm)
+      } // elseif ($action == 'new_version')
     elseif ($action == 'copy') {
       $description = json_decode($iassign_ilm->description);
       if ($iassign_ilm) {
@@ -6284,13 +6431,18 @@ class ilm_settings {
         $param->timecreated = time();
         $param->timemodified = time();
         $param->evaluate = $iassign_ilm->evaluate;
+        $param->reevaluate = $iassign_ilm->reevaluate; // reevaluate = 1 => allows to the teacher calls method to re-evaluate (does it in batch, to all students)
+        $param->editingbehavior = $iassign_ilm->editingbehavior; // editingbehavior = 1 => iLM auto-evaluation remains working over a solution sent by the student (iGeom does not work, iVProg does)
+        $param->submissionbehavior = $iassign_ilm->submissionbehavior; // 0 => 'After submission, this iLM remains on the same page'; 1 => 'After submission, this iLM changes the current page'
         $param->parent = $iassign_ilm->parent;
-        }
-      }
+        } // if ($iassign_ilm)
+      } // elseif ($action == 'copy'
 
+   //D debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    //D echo "Fim: action=" . $param->action . "<br/>---------------------------------<br/>";
    //D var_dump(debug_backtrace());
-   //D print_r(debug_backtrace());
+   //D print_r(debug_backtrace()); echo "param="; print_r($param); echo "<br/>\n";
+   //D echo "<br/>---------------------------------<br/>"; exit;
 
     return $param;
     } // static function add_edit_copy_ilm($ilm_id, $action)
@@ -6466,11 +6618,16 @@ class ilm_settings {
 
 
   /// Function for save in database an iLM edit
+  //  The above function 'add_edit_copy_ilm(.)' is responsible to provide the iLM data in this form
+  //  The data stored through 'ilm_handlers/html5.php' (or 'java.php')
   //  @param object $param An object with iLM params
+  //  @calledby settings_ilm.php: ilm_settings::edit_ilm($formdata, $formdata->file);
   static function edit_ilm ($param, $itemid) {
     // Descobrir o tipo de iLM:
     global $DB, $USER, $CFG;
 
+    //D debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); //exit;
+
     $iassign_t = $DB->get_record('iassign_ilm', array('id' => $param->id));
 
     $pathtemp = $CFG->dataroot . '/temp/';
@@ -8122,7 +8279,6 @@ class ilm_manager {
                  'filename' => $iassign_statement_activity_item->name . "." . $extension[1]); // any filename
 
               $newfile = $fs->create_file_from_string($fileinfo, $value->get_content());
-
               }
             }
           } // if ($files)
@@ -8805,6 +8961,12 @@ class iassign_icons {
     return $string;
     }
 
+  static function insertIT ($icon, $title, $text_alt) {
+    global $CFG;
+    $string = '<img src="' . $CFG->wwwroot . '/mod/iassign/icon/' . $icon . '.gif" title="' . get_string($title, 'iassign') . '" alt="' . get_string($text_alt, 'iassign') . '"/>'; // "\n"
+    return $string;
+    }
+
   }