Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • Differences Between: [Versions 28 and 29] [Versions 28 and 30] [Versions 28 and 31] [Versions 28 and 32] [Versions 28 and 33] [Versions 28 and 34] [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

       1  <?php
       2  
       3  // This file is part of Moodle - http://moodle.org/
       4  //
       5  // Moodle is free software: you can redistribute it and/or modify
       6  // it under the terms of the GNU General Public License as published by
       7  // the Free Software Foundation, either version 3 of the License, or
       8  // (at your option) any later version.
       9  //
      10  // Moodle is distributed in the hope that it will be useful,
      11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13  // GNU General Public License for more details.
      14  //
      15  // You should have received a copy of the GNU General Public License
      16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
      17  
      18  /**
      19   * Library of functions and constants for module glossary
      20   * (replace glossary with the name of your module and delete this line)
      21   *
      22   * @package   mod_glossary
      23   * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
      24   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      25   */
      26  require_once($CFG->libdir . '/completionlib.php');
      27  
      28  define("GLOSSARY_SHOW_ALL_CATEGORIES", 0);
      29  define("GLOSSARY_SHOW_NOT_CATEGORISED", -1);
      30  
      31  define("GLOSSARY_NO_VIEW", -1);
      32  define("GLOSSARY_STANDARD_VIEW", 0);
      33  define("GLOSSARY_CATEGORY_VIEW", 1);
      34  define("GLOSSARY_DATE_VIEW", 2);
      35  define("GLOSSARY_AUTHOR_VIEW", 3);
      36  define("GLOSSARY_ADDENTRY_VIEW", 4);
      37  define("GLOSSARY_IMPORT_VIEW", 5);
      38  define("GLOSSARY_EXPORT_VIEW", 6);
      39  define("GLOSSARY_APPROVAL_VIEW", 7);
      40  
      41  /// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
      42  /**
      43   * @global object
      44   * @param object $glossary
      45   * @return int
      46   */
      47  function glossary_add_instance($glossary) {
      48      global $DB;
      49  /// Given an object containing all the necessary data,
      50  /// (defined by the form in mod_form.php) this function
      51  /// will create a new instance and return the id number
      52  /// of the new instance.
      53  
      54      if (empty($glossary->ratingtime) or empty($glossary->assessed)) {
      55          $glossary->assesstimestart  = 0;
      56          $glossary->assesstimefinish = 0;
      57      }
      58  
      59      if (empty($glossary->globalglossary) ) {
      60          $glossary->globalglossary = 0;
      61      }
      62  
      63      if (!has_capability('mod/glossary:manageentries', context_system::instance())) {
      64          $glossary->globalglossary = 0;
      65      }
      66  
      67      $glossary->timecreated  = time();
      68      $glossary->timemodified = $glossary->timecreated;
      69  
      70      //Check displayformat is a valid one
      71      $formats = get_list_of_plugins('mod/glossary/formats','TEMPLATE');
      72      if (!in_array($glossary->displayformat, $formats)) {
      73          print_error('unknowformat', '', '', $glossary->displayformat);
      74      }
      75  
      76      $returnid = $DB->insert_record("glossary", $glossary);
      77      $glossary->id = $returnid;
      78      glossary_grade_item_update($glossary);
      79  
      80      return $returnid;
      81  }
      82  
      83  /**
      84   * Given an object containing all the necessary data,
      85   * (defined by the form in mod_form.php) this function
      86   * will update an existing instance with new data.
      87   *
      88   * @global object
      89   * @global object
      90   * @param object $glossary
      91   * @return bool
      92   */
      93  function glossary_update_instance($glossary) {
      94      global $CFG, $DB;
      95  
      96      if (empty($glossary->globalglossary)) {
      97          $glossary->globalglossary = 0;
      98      }
      99  
     100      if (!has_capability('mod/glossary:manageentries', context_system::instance())) {
     101          // keep previous
     102          unset($glossary->globalglossary);
     103      }
     104  
     105      $glossary->timemodified = time();
     106      $glossary->id           = $glossary->instance;
     107  
     108      if (empty($glossary->ratingtime) or empty($glossary->assessed)) {
     109          $glossary->assesstimestart  = 0;
     110          $glossary->assesstimefinish = 0;
     111      }
     112  
     113      //Check displayformat is a valid one
     114      $formats = get_list_of_plugins('mod/glossary/formats','TEMPLATE');
     115      if (!in_array($glossary->displayformat, $formats)) {
     116          print_error('unknowformat', '', '', $glossary->displayformat);
     117      }
     118  
     119      $DB->update_record("glossary", $glossary);
     120      if ($glossary->defaultapproval) {
     121          $DB->execute("UPDATE {glossary_entries} SET approved = 1 where approved <> 1 and glossaryid = ?", array($glossary->id));
     122      }
     123      glossary_grade_item_update($glossary);
     124  
     125      return true;
     126  }
     127  
     128  /**
     129   * Given an ID of an instance of this module,
     130   * this function will permanently delete the instance
     131   * and any data that depends on it.
     132   *
     133   * @global object
     134   * @param int $id glossary id
     135   * @return bool success
     136   */
     137  function glossary_delete_instance($id) {
     138      global $DB, $CFG;
     139  
     140      if (!$glossary = $DB->get_record('glossary', array('id'=>$id))) {
     141          return false;
     142      }
     143  
     144      if (!$cm = get_coursemodule_from_instance('glossary', $id)) {
     145          return false;
     146      }
     147  
     148      if (!$context = context_module::instance($cm->id, IGNORE_MISSING)) {
     149          return false;
     150      }
     151  
     152      $fs = get_file_storage();
     153  
     154      if ($glossary->mainglossary) {
     155          // unexport entries
     156          $sql = "SELECT ge.id, ge.sourceglossaryid, cm.id AS sourcecmid
     157                    FROM {glossary_entries} ge
     158                    JOIN {modules} m ON m.name = 'glossary'
     159                    JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = ge.sourceglossaryid)
     160                   WHERE ge.glossaryid = ? AND ge.sourceglossaryid > 0";
     161  
     162          if ($exported = $DB->get_records_sql($sql, array($id))) {
     163              foreach ($exported as $entry) {
     164                  $entry->glossaryid = $entry->sourceglossaryid;
     165                  $entry->sourceglossaryid = 0;
     166                  $newcontext = context_module::instance($entry->sourcecmid);
     167                  if ($oldfiles = $fs->get_area_files($context->id, 'mod_glossary', 'attachment', $entry->id)) {
     168                      foreach ($oldfiles as $oldfile) {
     169                          $file_record = new stdClass();
     170                          $file_record->contextid = $newcontext->id;
     171                          $fs->create_file_from_storedfile($file_record, $oldfile);
     172                      }
     173                      $fs->delete_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
     174                      $entry->attachment = '1';
     175                  } else {
     176                      $entry->attachment = '0';
     177                  }
     178                  $DB->update_record('glossary_entries', $entry);
     179              }
     180          }
     181      } else {
     182          // move exported entries to main glossary
     183          $sql = "UPDATE {glossary_entries}
     184                     SET sourceglossaryid = 0
     185                   WHERE sourceglossaryid = ?";
     186          $DB->execute($sql, array($id));
     187      }
     188  
     189      // Delete any dependent records
     190      $entry_select = "SELECT id FROM {glossary_entries} WHERE glossaryid = ?";
     191      $DB->delete_records_select('comments', "contextid=? AND commentarea=? AND itemid IN ($entry_select)", array($id, 'glossary_entry', $context->id));
     192      $DB->delete_records_select('glossary_alias',    "entryid IN ($entry_select)", array($id));
     193  
     194      $category_select = "SELECT id FROM {glossary_categories} WHERE glossaryid = ?";
     195      $DB->delete_records_select('glossary_entries_categories', "categoryid IN ($category_select)", array($id));
     196      $DB->delete_records('glossary_categories', array('glossaryid'=>$id));
     197      $DB->delete_records('glossary_entries', array('glossaryid'=>$id));
     198  
     199      // delete all files
     200      $fs->delete_area_files($context->id);
     201  
     202      glossary_grade_item_delete($glossary);
     203  
     204      $DB->delete_records('glossary', array('id'=>$id));
     205  
     206      // Reset caches.
     207      \mod_glossary\local\concept_cache::reset_glossary($glossary);
     208  
     209      return true;
     210  }
     211  
     212  /**
     213   * Return a small object with summary information about what a
     214   * user has done with a given particular instance of this module
     215   * Used for user activity reports.
     216   * $return->time = the time they did it
     217   * $return->info = a short text description
     218   *
     219   * @param object $course
     220   * @param object $user
     221   * @param object $mod
     222   * @param object $glossary
     223   * @return object|null
     224   */
     225  function glossary_user_outline($course, $user, $mod, $glossary) {
     226      global $CFG;
     227  
     228      require_once("$CFG->libdir/gradelib.php");
     229      $grades = grade_get_grades($course->id, 'mod', 'glossary', $glossary->id, $user->id);
     230      if (empty($grades->items[0]->grades)) {
     231          $grade = false;
     232      } else {
     233          $grade = reset($grades->items[0]->grades);
     234      }
     235  
     236      if ($entries = glossary_get_user_entries($glossary->id, $user->id)) {
     237          $result = new stdClass();
     238          $result->info = count($entries) . ' ' . get_string("entries", "glossary");
     239  
     240          $lastentry = array_pop($entries);
     241          $result->time = $lastentry->timemodified;
     242  
     243          if ($grade) {
     244              $result->info .= ', ' . get_string('grade') . ': ' . $grade->str_long_grade;
     245          }
     246          return $result;
     247      } else if ($grade) {
     248          $result = new stdClass();
     249          $result->info = get_string('grade') . ': ' . $grade->str_long_grade;
     250  
     251          //datesubmitted == time created. dategraded == time modified or time overridden
     252          //if grade was last modified by the user themselves use date graded. Otherwise use date submitted
     253          //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704
     254          if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) {
     255              $result->time = $grade->dategraded;
     256          } else {
     257              $result->time = $grade->datesubmitted;
     258          }
     259  
     260          return $result;
     261      }
     262      return NULL;
     263  }
     264  
     265  /**
     266   * @global object
     267   * @param int $glossaryid
     268   * @param int $userid
     269   * @return array
     270   */
     271  function glossary_get_user_entries($glossaryid, $userid) {
     272  /// Get all the entries for a user in a glossary
     273      global $DB;
     274  
     275      return $DB->get_records_sql("SELECT e.*, u.firstname, u.lastname, u.email, u.picture
     276                                     FROM {glossary} g, {glossary_entries} e, {user} u
     277                               WHERE g.id = ?
     278                                 AND e.glossaryid = g.id
     279                                 AND e.userid = ?
     280                                 AND e.userid = u.id
     281                            ORDER BY e.timemodified ASC", array($glossaryid, $userid));
     282  }
     283  
     284  /**
     285   * Print a detailed representation of what a  user has done with
     286   * a given particular instance of this module, for user activity reports.
     287   *
     288   * @global object
     289   * @param object $course
     290   * @param object $user
     291   * @param object $mod
     292   * @param object $glossary
     293   */
     294  function glossary_user_complete($course, $user, $mod, $glossary) {
     295      global $CFG, $OUTPUT;
     296      require_once("$CFG->libdir/gradelib.php");
     297  
     298      $grades = grade_get_grades($course->id, 'mod', 'glossary', $glossary->id, $user->id);
     299      if (!empty($grades->items[0]->grades)) {
     300          $grade = reset($grades->items[0]->grades);
     301          echo $OUTPUT->container(get_string('grade').': '.$grade->str_long_grade);
     302          if ($grade->str_feedback) {
     303              echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
     304          }
     305      }
     306  
     307      if ($entries = glossary_get_user_entries($glossary->id, $user->id)) {
     308          echo '<table width="95%" border="0"><tr><td>';
     309          foreach ($entries as $entry) {
     310              $cm = get_coursemodule_from_instance("glossary", $glossary->id, $course->id);
     311              glossary_print_entry($course, $cm, $glossary, $entry,"","",0);
     312              echo '<p>';
     313          }
     314          echo '</td></tr></table>';
     315      }
     316  }
     317  
     318  /**
     319   * Returns all glossary entries since a given time for specified glossary
     320   *
     321   * @param array $activities sequentially indexed array of objects
     322   * @param int   $index
     323   * @param int   $timestart
     324   * @param int   $courseid
     325   * @param int   $cmid
     326   * @param int   $userid defaults to 0
     327   * @param int   $groupid defaults to 0
     328   * @return void adds items into $activities and increases $index
     329   */
     330  function glossary_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid = 0, $groupid = 0) {
     331      global $COURSE, $USER, $DB;
     332  
     333      if ($COURSE->id == $courseid) {
     334          $course = $COURSE;
     335      } else {
     336          $course = $DB->get_record('course', array('id' => $courseid));
     337      }
     338  
     339      $modinfo = get_fast_modinfo($course);
     340      $cm = $modinfo->cms[$cmid];
     341      $context = context_module::instance($cm->id);
     342  
     343      if (!$cm->uservisible) {
     344          return;
     345      }
     346  
     347      $viewfullnames = has_capability('moodle/site:viewfullnames', $context);
     348      // Groups are not yet supported for glossary. See MDL-10728 .
     349      /*
     350      $accessallgroups = has_capability('moodle/site:accessallgroups', $context);
     351      $groupmode = groups_get_activity_groupmode($cm, $course);
     352       */
     353  
     354      $params['timestart'] = $timestart;
     355  
     356      if ($userid) {
     357          $userselect = "AND u.id = :userid";
     358          $params['userid'] = $userid;
     359      } else {
     360          $userselect = '';
     361      }
     362  
     363      if ($groupid) {
     364          $groupselect = 'AND gm.groupid = :groupid';
     365          $groupjoin   = 'JOIN {groups_members} gm ON  gm.userid=u.id';
     366          $params['groupid'] = $groupid;
     367      } else {
     368          $groupselect = '';
     369          $groupjoin   = '';
     370      }
     371  
     372      $approvedselect = "";
     373      if (!has_capability('mod/glossary:approve', $context)) {
     374          $approvedselect = " AND ge.approved = 1 ";
     375      }
     376  
     377      $params['timestart'] = $timestart;
     378      $params['glossaryid'] = $cm->instance;
     379  
     380      $ufields = user_picture::fields('u', null, 'userid');
     381      $entries = $DB->get_records_sql("
     382                SELECT ge.id AS entryid, ge.glossaryid, ge.concept, ge.definition, ge.approved,
     383                       ge.timemodified, $ufields
     384                  FROM {glossary_entries} ge
     385                  JOIN {user} u ON u.id = ge.userid
     386                       $groupjoin
     387                 WHERE ge.timemodified > :timestart
     388                   AND ge.glossaryid = :glossaryid
     389                       $approvedselect
     390                       $userselect
     391                       $groupselect
     392              ORDER BY ge.timemodified ASC", $params);
     393  
     394      if (!$entries) {
     395          return;
     396      }
     397  
     398      foreach ($entries as $entry) {
     399          // Groups are not yet supported for glossary. See MDL-10728 .
     400          /*
     401          $usersgroups = null;
     402          if ($entry->userid != $USER->id) {
     403              if ($groupmode == SEPARATEGROUPS and !$accessallgroups) {
     404                  if (is_null($usersgroups)) {
     405                      $usersgroups = groups_get_all_groups($course->id, $entry->userid, $cm->groupingid);
     406                      if (is_array($usersgroups)) {
     407                          $usersgroups = array_keys($usersgroups);
     408                      } else {
     409                          $usersgroups = array();
     410                      }
     411                  }
     412                  if (!array_intersect($usersgroups, $modinfo->get_groups($cm->groupingid))) {
     413                      continue;
     414                  }
     415              }
     416          }
     417           */
     418  
     419          $tmpactivity                       = new stdClass();
     420          $tmpactivity->user                 = user_picture::unalias($entry, null, 'userid');
     421          $tmpactivity->user->fullname       = fullname($tmpactivity->user, $viewfullnames);
     422          $tmpactivity->type                 = 'glossary';
     423          $tmpactivity->cmid                 = $cm->id;
     424          $tmpactivity->glossaryid           = $entry->glossaryid;
     425          $tmpactivity->name                 = format_string($cm->name, true);
     426          $tmpactivity->sectionnum           = $cm->sectionnum;
     427          $tmpactivity->timestamp            = $entry->timemodified;
     428          $tmpactivity->content              = new stdClass();
     429          $tmpactivity->content->entryid     = $entry->entryid;
     430          $tmpactivity->content->concept     = $entry->concept;
     431          $tmpactivity->content->definition  = $entry->definition;
     432          $tmpactivity->content->approved    = $entry->approved;
     433  
     434          $activities[$index++] = $tmpactivity;
     435      }
     436  
     437      return true;
     438  }
     439  
     440  /**
     441   * Outputs the glossary entry indicated by $activity
     442   *
     443   * @param object $activity      the activity object the glossary resides in
     444   * @param int    $courseid      the id of the course the glossary resides in
     445   * @param bool   $detail        not used, but required for compatibilty with other modules
     446   * @param int    $modnames      not used, but required for compatibilty with other modules
     447   * @param bool   $viewfullnames not used, but required for compatibilty with other modules
     448   * @return void
     449   */
     450  function glossary_print_recent_mod_activity($activity, $courseid, $detail, $modnames, $viewfullnames) {
     451      global $OUTPUT;
     452  
     453      echo html_writer::start_tag('div', array('class'=>'glossary-activity clearfix'));
     454      if (!empty($activity->user)) {
     455          echo html_writer::tag('div', $OUTPUT->user_picture($activity->user, array('courseid'=>$courseid)),
     456              array('class' => 'glossary-activity-picture'));
     457      }
     458  
     459      echo html_writer::start_tag('div', array('class'=>'glossary-activity-content'));
     460      echo html_writer::start_tag('div', array('class'=>'glossary-activity-entry'));
     461  
     462      if (isset($activity->content->approved) && !$activity->content->approved) {
     463          $urlparams = array('g' => $activity->glossaryid, 'mode' => 'approval', 'hook' => $activity->content->concept);
     464          $class = array('class' => 'dimmed_text');
     465      } else {
     466          $urlparams = array('g' => $activity->glossaryid, 'mode' => 'entry', 'hook' => $activity->content->entryid);
     467          $class = array();
     468      }
     469      echo html_writer::link(new moodle_url('/mod/glossary/view.php', $urlparams),
     470              strip_tags($activity->content->concept), $class);
     471      echo html_writer::end_tag('div');
     472  
     473      $url = new moodle_url('/user/view.php', array('course'=>$courseid, 'id'=>$activity->user->id));
     474      $name = $activity->user->fullname;
     475      $link = html_writer::link($url, $name, $class);
     476  
     477      echo html_writer::start_tag('div', array('class'=>'user'));
     478      echo $link .' - '. userdate($activity->timestamp);
     479      echo html_writer::end_tag('div');
     480  
     481      echo html_writer::end_tag('div');
     482  
     483      echo html_writer::end_tag('div');
     484      return;
     485  }
     486  /**
     487   * Given a course and a time, this module should find recent activity
     488   * that has occurred in glossary activities and print it out.
     489   * Return true if there was output, or false is there was none.
     490   *
     491   * @global object
     492   * @global object
     493   * @global object
     494   * @param object $course
     495   * @param object $viewfullnames
     496   * @param int $timestart
     497   * @return bool
     498   */
     499  function glossary_print_recent_activity($course, $viewfullnames, $timestart) {
     500      global $CFG, $USER, $DB, $OUTPUT, $PAGE;
     501  
     502      //TODO: use timestamp in approved field instead of changing timemodified when approving in 2.0
     503      if (!defined('GLOSSARY_RECENT_ACTIVITY_LIMIT')) {
     504          define('GLOSSARY_RECENT_ACTIVITY_LIMIT', 50);
     505      }
     506      $modinfo = get_fast_modinfo($course);
     507      $ids = array();
     508  
     509      foreach ($modinfo->cms as $cm) {
     510          if ($cm->modname != 'glossary') {
     511              continue;
     512          }
     513          if (!$cm->uservisible) {
     514              continue;
     515          }
     516          $ids[$cm->instance] = $cm->id;
     517      }
     518  
     519      if (!$ids) {
     520          return false;
     521      }
     522  
     523      // generate list of approval capabilities for all glossaries in the course.
     524      $approvals = array();
     525      foreach ($ids as $glinstanceid => $glcmid) {
     526          $context = context_module::instance($glcmid);
     527          if (has_capability('mod/glossary:view', $context)) {
     528              // get records glossary entries that are approved if user has no capability to approve entries.
     529              if (has_capability('mod/glossary:approve', $context)) {
     530                  $approvals[] = ' ge.glossaryid = :glsid'.$glinstanceid.' ';
     531              } else {
     532                  $approvals[] = ' (ge.approved = 1 AND ge.glossaryid = :glsid'.$glinstanceid.') ';
     533              }
     534              $params['glsid'.$glinstanceid] = $glinstanceid;
     535          }
     536      }
     537  
     538      if (count($approvals) == 0) {
     539          return false;
     540      }
     541      $selectsql = 'SELECT ge.id, ge.concept, ge.approved, ge.timemodified, ge.glossaryid,
     542                                          '.user_picture::fields('u',null,'userid');
     543      $countsql = 'SELECT COUNT(*)';
     544  
     545      $joins = array(' FROM {glossary_entries} ge ');
     546      $joins[] = 'JOIN {user} u ON u.id = ge.userid ';
     547      $fromsql = implode($joins, "\n");
     548  
     549      $params['timestart'] = $timestart;
     550      $clausesql = ' WHERE ge.timemodified > :timestart ';
     551  
     552      if (count($approvals) > 0) {
     553          $approvalsql = 'AND ('. implode($approvals, ' OR ') .') ';
     554      } else {
     555          $approvalsql = '';
     556      }
     557      $ordersql = 'ORDER BY ge.timemodified ASC';
     558      $entries = $DB->get_records_sql($selectsql.$fromsql.$clausesql.$approvalsql.$ordersql, $params, 0, (GLOSSARY_RECENT_ACTIVITY_LIMIT+1));
     559  
     560      if (empty($entries)) {
     561          return false;
     562      }
     563  
     564      echo $OUTPUT->heading(get_string('newentries', 'glossary').':', 3);
     565      $strftimerecent = get_string('strftimerecent');
     566      $entrycount = 0;
     567      foreach ($entries as $entry) {
     568          if ($entrycount < GLOSSARY_RECENT_ACTIVITY_LIMIT) {
     569              if ($entry->approved) {
     570                  $dimmed = '';
     571                  $urlparams = array('g' => $entry->glossaryid, 'mode' => 'entry', 'hook' => $entry->id);
     572              } else {
     573                  $dimmed = ' dimmed_text';
     574                  $urlparams = array('id' => $ids[$entry->glossaryid], 'mode' => 'approval', 'hook' => format_text($entry->concept, true));
     575              }
     576              $link = new moodle_url($CFG->wwwroot.'/mod/glossary/view.php' , $urlparams);
     577              echo '<div class="head'.$dimmed.'">';
     578              echo '<div class="date">'.userdate($entry->timemodified, $strftimerecent).'</div>';
     579              echo '<div class="name">'.fullname($entry, $viewfullnames).'</div>';
     580              echo '</div>';
     581              echo '<div class="info"><a href="'.$link.'">'.format_string($entry->concept, true).'</a></div>';
     582              $entrycount += 1;
     583          } else {
     584              $numnewentries = $DB->count_records_sql($countsql.$joins[0].$clausesql.$approvalsql, $params);
     585              echo '<div class="head"><div class="activityhead">'.get_string('andmorenewentries', 'glossary', $numnewentries - GLOSSARY_RECENT_ACTIVITY_LIMIT).'</div></div>';
     586              break;
     587          }
     588      }
     589  
     590      return true;
     591  }
     592  
     593  /**
     594   * @global object
     595   * @param object $log
     596   */
     597  function glossary_log_info($log) {
     598      global $DB;
     599  
     600      return $DB->get_record_sql("SELECT e.*, u.firstname, u.lastname
     601                                    FROM {glossary_entries} e, {user} u
     602                                   WHERE e.id = ? AND u.id = ?", array($log->info, $log->userid));
     603  }
     604  
     605  /**
     606   * Function to be run periodically according to the moodle cron
     607   * This function searches for things that need to be done, such
     608   * as sending out mail, toggling flags etc ...
     609   * @return bool
     610   */
     611  function glossary_cron () {
     612      return true;
     613  }
     614  
     615  /**
     616   * Return grade for given user or all users.
     617   *
     618   * @param stdClass $glossary A glossary instance
     619   * @param int $userid Optional user id, 0 means all users
     620   * @return array An array of grades, false if none
     621   */
     622  function glossary_get_user_grades($glossary, $userid=0) {
     623      global $CFG;
     624  
     625      require_once($CFG->dirroot.'/rating/lib.php');
     626  
     627      $ratingoptions = new stdClass;
     628  
     629      //need these to work backwards to get a context id. Is there a better way to get contextid from a module instance?
     630      $ratingoptions->modulename = 'glossary';
     631      $ratingoptions->moduleid   = $glossary->id;
     632      $ratingoptions->component  = 'mod_glossary';
     633      $ratingoptions->ratingarea = 'entry';
     634  
     635      $ratingoptions->userid = $userid;
     636      $ratingoptions->aggregationmethod = $glossary->assessed;
     637      $ratingoptions->scaleid = $glossary->scale;
     638      $ratingoptions->itemtable = 'glossary_entries';
     639      $ratingoptions->itemtableusercolumn = 'userid';
     640  
     641      $rm = new rating_manager();
     642      return $rm->get_user_grades($ratingoptions);
     643  }
     644  
     645  /**
     646   * Return rating related permissions
     647   *
     648   * @param int $contextid the context id
     649   * @param string $component The component we want to get permissions for
     650   * @param string $ratingarea The ratingarea that we want to get permissions for
     651   * @return array an associative array of the user's rating permissions
     652   */
     653  function glossary_rating_permissions($contextid, $component, $ratingarea) {
     654      if ($component != 'mod_glossary' || $ratingarea != 'entry') {
     655          // We don't know about this component/ratingarea so just return null to get the
     656          // default restrictive permissions.
     657          return null;
     658      }
     659      $context = context::instance_by_id($contextid);
     660      return array(
     661          'view'    => has_capability('mod/glossary:viewrating', $context),
     662          'viewany' => has_capability('mod/glossary:viewanyrating', $context),
     663          'viewall' => has_capability('mod/glossary:viewallratings', $context),
     664          'rate'    => has_capability('mod/glossary:rate', $context)
     665      );
     666  }
     667  
     668  /**
     669   * Validates a submitted rating
     670   * @param array $params submitted data
     671   *            context => object the context in which the rated items exists [required]
     672   *            component => The component for this module - should always be mod_forum [required]
     673   *            ratingarea => object the context in which the rated items exists [required]
     674   *            itemid => int the ID of the object being rated [required]
     675   *            scaleid => int the scale from which the user can select a rating. Used for bounds checking. [required]
     676   *            rating => int the submitted rating
     677   *            rateduserid => int the id of the user whose items have been rated. NOT the user who submitted the ratings. 0 to update all. [required]
     678   *            aggregation => int the aggregation method to apply when calculating grades ie RATING_AGGREGATE_AVERAGE [optional]
     679   * @return boolean true if the rating is valid. Will throw rating_exception if not
     680   */
     681  function glossary_rating_validate($params) {
     682      global $DB, $USER;
     683  
     684      // Check the component is mod_forum
     685      if ($params['component'] != 'mod_glossary') {
     686          throw new rating_exception('invalidcomponent');
     687      }
     688  
     689      // Check the ratingarea is post (the only rating area in forum)
     690      if ($params['ratingarea'] != 'entry') {
     691          throw new rating_exception('invalidratingarea');
     692      }
     693  
     694      // Check the rateduserid is not the current user .. you can't rate your own posts
     695      if ($params['rateduserid'] == $USER->id) {
     696          throw new rating_exception('nopermissiontorate');
     697      }
     698  
     699      $glossarysql = "SELECT g.id as glossaryid, g.scale, g.course, e.userid as userid, e.approved, e.timecreated, g.assesstimestart, g.assesstimefinish
     700                        FROM {glossary_entries} e
     701                        JOIN {glossary} g ON e.glossaryid = g.id
     702                       WHERE e.id = :itemid";
     703      $glossaryparams = array('itemid' => $params['itemid']);
     704      $info = $DB->get_record_sql($glossarysql, $glossaryparams);
     705      if (!$info) {
     706          //item doesn't exist
     707          throw new rating_exception('invaliditemid');
     708      }
     709  
     710      if ($info->scale != $params['scaleid']) {
     711          //the scale being submitted doesnt match the one in the database
     712          throw new rating_exception('invalidscaleid');
     713      }
     714  
     715      //check that the submitted rating is valid for the scale
     716  
     717      // lower limit
     718      if ($params['rating'] < 0  && $params['rating'] != RATING_UNSET_RATING) {
     719          throw new rating_exception('invalidnum');
     720      }
     721  
     722      // upper limit
     723      if ($info->scale < 0) {
     724          //its a custom scale
     725          $scalerecord = $DB->get_record('scale', array('id' => -$info->scale));
     726          if ($scalerecord) {
     727              $scalearray = explode(',', $scalerecord->scale);
     728              if ($params['rating'] > count($scalearray)) {
     729                  throw new rating_exception('invalidnum');
     730              }
     731          } else {
     732              throw new rating_exception('invalidscaleid');
     733          }
     734      } else if ($params['rating'] > $info->scale) {
     735          //if its numeric and submitted rating is above maximum
     736          throw new rating_exception('invalidnum');
     737      }
     738  
     739      if (!$info->approved) {
     740          //item isnt approved
     741          throw new rating_exception('nopermissiontorate');
     742      }
     743  
     744      //check the item we're rating was created in the assessable time window
     745      if (!empty($info->assesstimestart) && !empty($info->assesstimefinish)) {
     746          if ($info->timecreated < $info->assesstimestart || $info->timecreated > $info->assesstimefinish) {
     747              throw new rating_exception('notavailable');
     748          }
     749      }
     750  
     751      $cm = get_coursemodule_from_instance('glossary', $info->glossaryid, $info->course, false, MUST_EXIST);
     752      $context = context_module::instance($cm->id, MUST_EXIST);
     753  
     754      // if the supplied context doesnt match the item's context
     755      if ($context->id != $params['context']->id) {
     756          throw new rating_exception('invalidcontext');
     757      }
     758  
     759      return true;
     760  }
     761  
     762  /**
     763   * Update activity grades
     764   *
     765   * @category grade
     766   * @param stdClass $glossary Null means all glossaries (with extra cmidnumber property)
     767   * @param int $userid specific user only, 0 means all
     768   * @param bool $nullifnone If true and the user has no grade then a grade item with rawgrade == null will be inserted
     769   */
     770  function glossary_update_grades($glossary=null, $userid=0, $nullifnone=true) {
     771      global $CFG, $DB;
     772      require_once($CFG->libdir.'/gradelib.php');
     773  
     774      if (!$glossary->assessed) {
     775          glossary_grade_item_update($glossary);
     776  
     777      } else if ($grades = glossary_get_user_grades($glossary, $userid)) {
     778          glossary_grade_item_update($glossary, $grades);
     779  
     780      } else if ($userid and $nullifnone) {
     781          $grade = new stdClass();
     782          $grade->userid   = $userid;
     783          $grade->rawgrade = NULL;
     784          glossary_grade_item_update($glossary, $grade);
     785  
     786      } else {
     787          glossary_grade_item_update($glossary);
     788      }
     789  }
     790  
     791  /**
     792   * Create/update grade item for given glossary
     793   *
     794   * @category grade
     795   * @param stdClass $glossary object with extra cmidnumber
     796   * @param mixed $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
     797   * @return int, 0 if ok, error code otherwise
     798   */
     799  function glossary_grade_item_update($glossary, $grades=NULL) {
     800      global $CFG;
     801      require_once($CFG->libdir.'/gradelib.php');
     802  
     803      $params = array('itemname'=>$glossary->name, 'idnumber'=>$glossary->cmidnumber);
     804  
     805      if (!$glossary->assessed or $glossary->scale == 0) {
     806          $params['gradetype'] = GRADE_TYPE_NONE;
     807  
     808      } else if ($glossary->scale > 0) {
     809          $params['gradetype'] = GRADE_TYPE_VALUE;
     810          $params['grademax']  = $glossary->scale;
     811          $params['grademin']  = 0;
     812  
     813      } else if ($glossary->scale < 0) {
     814          $params['gradetype'] = GRADE_TYPE_SCALE;
     815          $params['scaleid']   = -$glossary->scale;
     816      }
     817  
     818      if ($grades  === 'reset') {
     819          $params['reset'] = true;
     820          $grades = NULL;
     821      }
     822  
     823      return grade_update('mod/glossary', $glossary->course, 'mod', 'glossary', $glossary->id, 0, $grades, $params);
     824  }
     825  
     826  /**
     827   * Delete grade item for given glossary
     828   *
     829   * @category grade
     830   * @param object $glossary object
     831   */
     832  function glossary_grade_item_delete($glossary) {
     833      global $CFG;
     834      require_once($CFG->libdir.'/gradelib.php');
     835  
     836      return grade_update('mod/glossary', $glossary->course, 'mod', 'glossary', $glossary->id, 0, NULL, array('deleted'=>1));
     837  }
     838  
     839  /**
     840   * @global object
     841   * @param int $gloassryid
     842   * @param int $scaleid
     843   * @return bool
     844   */
     845  function glossary_scale_used ($glossaryid,$scaleid) {
     846  //This function returns if a scale is being used by one glossary
     847      global $DB;
     848  
     849      $return = false;
     850  
     851      $rec = $DB->get_record("glossary", array("id"=>$glossaryid, "scale"=>-$scaleid));
     852  
     853      if (!empty($rec)  && !empty($scaleid)) {
     854          $return = true;
     855      }
     856  
     857      return $return;
     858  }
     859  
     860  /**
     861   * Checks if scale is being used by any instance of glossary
     862   *
     863   * This is used to find out if scale used anywhere
     864   *
     865   * @global object
     866   * @param int $scaleid
     867   * @return boolean True if the scale is used by any glossary
     868   */
     869  function glossary_scale_used_anywhere($scaleid) {
     870      global $DB;
     871  
     872      if ($scaleid and $DB->record_exists('glossary', array('scale'=>-$scaleid))) {
     873          return true;
     874      } else {
     875          return false;
     876      }
     877  }
     878  
     879  //////////////////////////////////////////////////////////////////////////////////////
     880  /// Any other glossary functions go here.  Each of them must have a name that
     881  /// starts with glossary_
     882  
     883  /**
     884   * This function return an array of valid glossary_formats records
     885   * Everytime it's called, every existing format is checked, new formats
     886   * are included if detected and old formats are deleted and any glossary
     887   * using an invalid format is updated to the default (dictionary).
     888   *
     889   * @global object
     890   * @global object
     891   * @return array
     892   */
     893  function glossary_get_available_formats() {
     894      global $CFG, $DB;
     895  
     896      //Get available formats (plugin) and insert (if necessary) them into glossary_formats
     897      $formats = get_list_of_plugins('mod/glossary/formats', 'TEMPLATE');
     898      $pluginformats = array();
     899      foreach ($formats as $format) {
     900          //If the format file exists
     901          if (file_exists($CFG->dirroot.'/mod/glossary/formats/'.$format.'/'.$format.'_format.php')) {
     902              include_once($CFG->dirroot.'/mod/glossary/formats/'.$format.'/'.$format.'_format.php');
     903              //If the function exists
     904              if (function_exists('glossary_show_entry_'.$format)) {
     905                  //Acummulate it as a valid format
     906                  $pluginformats[] = $format;
     907                  //If the format doesn't exist in the table
     908                  if (!$rec = $DB->get_record('glossary_formats', array('name'=>$format))) {
     909                      //Insert the record in glossary_formats
     910                      $gf = new stdClass();
     911                      $gf->name = $format;
     912                      $gf->popupformatname = $format;
     913                      $gf->visible = 1;
     914                      $DB->insert_record("glossary_formats",$gf);
     915                  }
     916              }
     917          }
     918      }
     919  
     920      //Delete non_existent formats from glossary_formats table
     921      $formats = $DB->get_records("glossary_formats");
     922      foreach ($formats as $format) {
     923          $todelete = false;
     924          //If the format in DB isn't a valid previously detected format then delete the record
     925          if (!in_array($format->name,$pluginformats)) {
     926              $todelete = true;
     927          }
     928  
     929          if ($todelete) {
     930              //Delete the format
     931              $DB->delete_records('glossary_formats', array('name'=>$format->name));
     932              //Reasign existing glossaries to default (dictionary) format
     933              if ($glossaries = $DB->get_records('glossary', array('displayformat'=>$format->name))) {
     934                  foreach($glossaries as $glossary) {
     935                      $DB->set_field('glossary','displayformat','dictionary', array('id'=>$glossary->id));
     936                  }
     937              }
     938          }
     939      }
     940  
     941      //Now everything is ready in glossary_formats table
     942      $formats = $DB->get_records("glossary_formats");
     943  
     944      return $formats;
     945  }
     946  
     947  /**
     948   * @param bool $debug
     949   * @param string $text
     950   * @param int $br
     951   */
     952  function glossary_debug($debug,$text,$br=1) {
     953      if ( $debug ) {
     954          echo '<font color="red">' . $text . '</font>';
     955          if ( $br ) {
     956              echo '<br />';
     957          }
     958      }
     959  }
     960  
     961  /**
     962   *
     963   * @global object
     964   * @param int $glossaryid
     965   * @param string $entrylist
     966   * @param string $pivot
     967   * @return array
     968   */
     969  function glossary_get_entries($glossaryid, $entrylist, $pivot = "") {
     970      global $DB;
     971      if ($pivot) {
     972         $pivot .= ",";
     973      }
     974  
     975      return $DB->get_records_sql("SELECT $pivot id,userid,concept,definition,format
     976                                     FROM {glossary_entries}
     977                                    WHERE glossaryid = ?
     978                                          AND id IN ($entrylist)", array($glossaryid));
     979  }
     980  
     981  /**
     982   * @global object
     983   * @global object
     984   * @param object $concept
     985   * @param string $courseid
     986   * @return array
     987   */
     988  function glossary_get_entries_search($concept, $courseid) {
     989      global $CFG, $DB;
     990  
     991      //Check if the user is an admin
     992      $bypassadmin = 1; //This means NO (by default)
     993      if (has_capability('moodle/course:viewhiddenactivities', context_system::instance())) {
     994          $bypassadmin = 0; //This means YES
     995      }
     996  
     997      //Check if the user is a teacher
     998      $bypassteacher = 1; //This means NO (by default)
     999      if (has_capability('mod/glossary:manageentries', context_course::instance($courseid))) {
    1000          $bypassteacher = 0; //This means YES
    1001      }
    1002  
    1003      $conceptlower = core_text::strtolower(trim($concept));
    1004  
    1005      $params = array('courseid1'=>$courseid, 'courseid2'=>$courseid, 'conceptlower'=>$conceptlower, 'concept'=>$concept);
    1006  
    1007      return $DB->get_records_sql("SELECT e.*, g.name as glossaryname, cm.id as cmid, cm.course as courseid
    1008                                     FROM {glossary_entries} e, {glossary} g,
    1009                                          {course_modules} cm, {modules} m
    1010                                    WHERE m.name = 'glossary' AND
    1011                                          cm.module = m.id AND
    1012                                          (cm.visible = 1 OR  cm.visible = $bypassadmin OR
    1013                                              (cm.course = :courseid1 AND cm.visible = $bypassteacher)) AND
    1014                                          g.id = cm.instance AND
    1015                                          e.glossaryid = g.id  AND
    1016                                          ( (e.casesensitive != 0 AND LOWER(concept) = :conceptlower) OR
    1017                                            (e.casesensitive = 0 and concept = :concept)) AND
    1018                                          (g.course = :courseid2 OR g.globalglossary = 1) AND
    1019                                           e.usedynalink != 0 AND
    1020                                           g.usedynalink != 0", $params);
    1021  }
    1022  
    1023  /**
    1024   * @global object
    1025   * @global object
    1026   * @param object $course
    1027   * @param object $course
    1028   * @param object $glossary
    1029   * @param object $entry
    1030   * @param string $mode
    1031   * @param string $hook
    1032   * @param int $printicons
    1033   * @param int $displayformat
    1034   * @param bool $printview
    1035   * @return mixed
    1036   */
    1037  function glossary_print_entry($course, $cm, $glossary, $entry, $mode='',$hook='',$printicons = 1, $displayformat  = -1, $printview = false) {
    1038      global $USER, $CFG;
    1039      $return = false;
    1040      if ( $displayformat < 0 ) {
    1041          $displayformat = $glossary->displayformat;
    1042      }
    1043      if ($entry->approved or ($USER->id == $entry->userid) or ($mode == 'approval' and !$entry->approved) ) {
    1044          $formatfile = $CFG->dirroot.'/mod/glossary/formats/'.$displayformat.'/'.$displayformat.'_format.php';
    1045          if ($printview) {
    1046              $functionname = 'glossary_print_entry_'.$displayformat;
    1047          } else {
    1048              $functionname = 'glossary_show_entry_'.$displayformat;
    1049          }
    1050  
    1051          if (file_exists($formatfile)) {
    1052              include_once($formatfile);
    1053              if (function_exists($functionname)) {
    1054                  $return = $functionname($course, $cm, $glossary, $entry,$mode,$hook,$printicons);
    1055              } else if ($printview) {
    1056                  //If the glossary_print_entry_XXXX function doesn't exist, print default (old) print format
    1057                  $return = glossary_print_entry_default($entry, $glossary, $cm);
    1058              }
    1059          }
    1060      }
    1061      return $return;
    1062  }
    1063  
    1064  /**
    1065   * Default (old) print format used if custom function doesn't exist in format
    1066   *
    1067   * @param object $entry
    1068   * @param object $glossary
    1069   * @param object $cm
    1070   * @return void Output is echo'd
    1071   */
    1072  function glossary_print_entry_default ($entry, $glossary, $cm) {
    1073      global $CFG;
    1074  
    1075      require_once($CFG->libdir . '/filelib.php');
    1076  
    1077      echo $OUTPUT->heading(strip_tags($entry->concept), 4);
    1078  
    1079      $definition = $entry->definition;
    1080  
    1081      $definition = '<span class="nolink">' . strip_tags($definition) . '</span>';
    1082  
    1083      $context = context_module::instance($cm->id);
    1084      $definition = file_rewrite_pluginfile_urls($definition, 'pluginfile.php', $context->id, 'mod_glossary', 'entry', $entry->id);
    1085  
    1086      $options = new stdClass();
    1087      $options->para = false;
    1088      $options->trusted = $entry->definitiontrust;
    1089      $options->context = $context;
    1090      $options->overflowdiv = true;
    1091      $definition = format_text($definition, $entry->definitionformat, $options);
    1092      echo ($definition);
    1093      echo '<br /><br />';
    1094  }
    1095  
    1096  /**
    1097   * Print glossary concept/term as a heading &lt;h4>
    1098   * @param object $entry
    1099   */
    1100  function  glossary_print_entry_concept($entry, $return=false) {
    1101      global $OUTPUT;
    1102  
    1103      $text = $OUTPUT->heading(format_string($entry->concept), 4);
    1104      if (!empty($entry->highlight)) {
    1105          $text = highlight($entry->highlight, $text);
    1106      }
    1107  
    1108      if ($return) {
    1109          return $text;
    1110      } else {
    1111          echo $text;
    1112      }
    1113  }
    1114  
    1115  /**
    1116   *
    1117   * @global moodle_database DB
    1118   * @param object $entry
    1119   * @param object $glossary
    1120   * @param object $cm
    1121   */
    1122  function glossary_print_entry_definition($entry, $glossary, $cm) {
    1123      global $GLOSSARY_EXCLUDEENTRY;
    1124  
    1125      $definition = $entry->definition;
    1126  
    1127      // Do not link self.
    1128      $GLOSSARY_EXCLUDEENTRY = $entry->id;
    1129  
    1130      $context = context_module::instance($cm->id);
    1131      $definition = file_rewrite_pluginfile_urls($definition, 'pluginfile.php', $context->id, 'mod_glossary', 'entry', $entry->id);
    1132  
    1133      $options = new stdClass();
    1134      $options->para = false;
    1135      $options->trusted = $entry->definitiontrust;
    1136      $options->context = $context;
    1137      $options->overflowdiv = true;
    1138  
    1139      $text = format_text($definition, $entry->definitionformat, $options);
    1140  
    1141      // Stop excluding concepts from autolinking
    1142      unset($GLOSSARY_EXCLUDEENTRY);
    1143  
    1144      if (!empty($entry->highlight)) {
    1145          $text = highlight($entry->highlight, $text);
    1146      }
    1147      if (isset($entry->footer)) {   // Unparsed footer info
    1148          $text .= $entry->footer;
    1149      }
    1150      echo $text;
    1151  }
    1152  
    1153  /**
    1154   *
    1155   * @global object
    1156   * @param object $course
    1157   * @param object $cm
    1158   * @param object $glossary
    1159   * @param object $entry
    1160   * @param string $mode
    1161   * @param string $hook
    1162   * @param string $type
    1163   * @return string|void
    1164   */
    1165  function  glossary_print_entry_aliases($course, $cm, $glossary, $entry,$mode='',$hook='', $type = 'print') {
    1166      global $DB;
    1167  
    1168      $return = '';
    1169      if ( $aliases = $DB->get_records('glossary_alias', array('entryid'=>$entry->id))) {
    1170          foreach ($aliases as $alias) {
    1171              if (trim($alias->alias)) {
    1172                  if ($return == '') {
    1173                      $return = '<select id="keyword" style="font-size:8pt">';
    1174                  }
    1175                  $return .= "<option>$alias->alias</option>";
    1176              }
    1177          }
    1178          if ($return != '') {
    1179              $return .= '</select>';
    1180          }
    1181      }
    1182      if ($type == 'print') {
    1183          echo $return;
    1184      } else {
    1185          return $return;
    1186      }
    1187  }
    1188  
    1189  /**
    1190   *
    1191   * @global object
    1192   * @global object
    1193   * @global object
    1194   * @param object $course
    1195   * @param object $cm
    1196   * @param object $glossary
    1197   * @param object $entry
    1198   * @param string $mode
    1199   * @param string $hook
    1200   * @param string $type
    1201   * @return string|void
    1202   */
    1203  function glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode='',$hook='', $type = 'print') {
    1204      global $USER, $CFG, $DB, $OUTPUT;
    1205  
    1206      $context = context_module::instance($cm->id);
    1207  
    1208      $output = false;   //To decide if we must really return text in "return". Activate when needed only!
    1209      $importedentry = ($entry->sourceglossaryid == $glossary->id);
    1210      $ismainglossary = $glossary->mainglossary;
    1211  
    1212  
    1213      $return = '<span class="commands">';
    1214      // Differentiate links for each entry.
    1215      $altsuffix = ': '.strip_tags(format_text($entry->concept));
    1216  
    1217      if (!$entry->approved) {
    1218          $output = true;
    1219          $return .= html_writer::tag('span', get_string('entryishidden','glossary'),
    1220              array('class' => 'glossary-hidden-note'));
    1221      }
    1222  
    1223      if (has_capability('mod/glossary:approve', $context) && !$glossary->defaultapproval && $entry->approved) {
    1224          $output = true;
    1225          $return .= '<a class="action-icon" title="' . get_string('disapprove', 'glossary').
    1226                     '" href="approve.php?newstate=0&amp;eid='.$entry->id.'&amp;mode='.$mode.
    1227                     '&amp;hook='.urlencode($hook).'&amp;sesskey='.sesskey().
    1228                     '"><img src="'.$OUTPUT->pix_url('t/block').'" class="smallicon" alt="'.
    1229                     get_string('disapprove','glossary').$altsuffix.'" /></a>';
    1230      }
    1231  
    1232      $iscurrentuser = ($entry->userid == $USER->id);
    1233  
    1234      if (has_capability('mod/glossary:manageentries', $context) or (isloggedin() and has_capability('mod/glossary:write', $context) and $iscurrentuser)) {
    1235          // only teachers can export entries so check it out
    1236          if (has_capability('mod/glossary:export', $context) and !$ismainglossary and !$importedentry) {
    1237              $mainglossary = $DB->get_record('glossary', array('mainglossary'=>1,'course'=>$course->id));
    1238              if ( $mainglossary ) {  // if there is a main glossary defined, allow to export the current entry
    1239                  $output = true;
    1240                  $return .= '<a class="action-icon" title="'.get_string('exporttomainglossary','glossary') . '" href="exportentry.php?id='.$entry->id.'&amp;prevmode='.$mode.'&amp;hook='.urlencode($hook).'"><img src="'.$OUTPUT->pix_url('export', 'glossary').'" class="smallicon" alt="'.get_string('exporttomainglossary','glossary').$altsuffix.'" /></a>';
    1241              }
    1242          }
    1243  
    1244          if ( $entry->sourceglossaryid ) {
    1245              $icon = $OUTPUT->pix_url('minus', 'glossary');   // graphical metaphor (minus) for deleting an imported entry
    1246          } else {
    1247              $icon = $OUTPUT->pix_url('t/delete');
    1248          }
    1249  
    1250          //Decide if an entry is editable:
    1251          // -It isn't a imported entry (so nobody can edit a imported (from secondary to main) entry)) and
    1252          // -The user is teacher or he is a student with time permissions (edit period or editalways defined).
    1253          $ineditperiod = ((time() - $entry->timecreated <  $CFG->maxeditingtime) || $glossary->editalways);
    1254          if ( !$importedentry and (has_capability('mod/glossary:manageentries', $context) or ($entry->userid == $USER->id and ($ineditperiod and has_capability('mod/glossary:write', $context))))) {
    1255              $output = true;
    1256              $return .= "<a class='action-icon' title=\"" . get_string("delete") . "\" href=\"deleteentry.php?id=$cm->id&amp;mode=delete&amp;entry=$entry->id&amp;prevmode=$mode&amp;hook=".urlencode($hook)."\"><img src=\"";
    1257              $return .= $icon;
    1258              $return .= "\" class=\"smallicon\" alt=\"" . get_string("delete") .$altsuffix."\" /></a>";
    1259  
    1260              $return .= "<a class='action-icon' title=\"" . get_string("edit") . "\" href=\"edit.php?cmid=$cm->id&amp;id=$entry->id&amp;mode=$mode&amp;hook=".urlencode($hook)."\"><img src=\"" . $OUTPUT->pix_url('t/edit') . "\" class=\"smallicon\" alt=\"" . get_string("edit") .$altsuffix. "\" /></a>";
    1261          } elseif ( $importedentry ) {
    1262              $return .= "<font size=\"-1\">" . get_string("exportedentry","glossary") . "</font>";
    1263          }
    1264      }
    1265      if (!empty($CFG->enableportfolios) && (has_capability('mod/glossary:exportentry', $context) || ($iscurrentuser && has_capability('mod/glossary:exportownentry', $context)))) {
    1266          require_once($CFG->libdir . '/portfoliolib.php');
    1267          $button = new portfolio_add_button();
    1268          $button->set_callback_options('glossary_entry_portfolio_caller',  array('id' => $cm->id, 'entryid' => $entry->id), 'mod_glossary');
    1269  
    1270          $filecontext = $context;
    1271          if ($entry->sourceglossaryid == $cm->instance) {
    1272              if ($maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
    1273                  $filecontext = context_module::instance($maincm->id);
    1274              }
    1275          }
    1276          $fs = get_file_storage();
    1277          if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)
    1278           || $files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'entry', $entry->id, "timemodified", false)) {
    1279  
    1280              $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
    1281          } else {
    1282              $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
    1283          }
    1284  
    1285          $return .= $button->to_html(PORTFOLIO_ADD_ICON_LINK);
    1286      }
    1287      $return .= '</span>';
    1288  
    1289      if (!empty($CFG->usecomments) && has_capability('mod/glossary:comment', $context) and $glossary->allowcomments) {
    1290          require_once($CFG->dirroot . '/comment/lib.php');
    1291          $cmt = new stdClass();
    1292          $cmt->component = 'mod_glossary';
    1293          $cmt->context  = $context;
    1294          $cmt->course   = $course;
    1295          $cmt->cm       = $cm;
    1296          $cmt->area     = 'glossary_entry';
    1297          $cmt->itemid   = $entry->id;
    1298          $cmt->showcount = true;
    1299          $comment = new comment($cmt);
    1300          $return .= '<div>'.$comment->output(true).'</div>';
    1301          $output = true;
    1302      }
    1303  
    1304      //If we haven't calculated any REAL thing, delete result ($return)
    1305      if (!$output) {
    1306          $return = '';
    1307      }
    1308      //Print or get
    1309      if ($type == 'print') {
    1310          echo $return;
    1311      } else {
    1312          return $return;
    1313      }
    1314  }
    1315  
    1316  /**
    1317   * @param object $course
    1318   * @param object $cm
    1319   * @param object $glossary
    1320   * @param object $entry
    1321   * @param string $mode
    1322   * @param object $hook
    1323   * @param bool $printicons
    1324   * @param bool $aliases
    1325   * @return void
    1326   */
    1327  function  glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases=true) {
    1328      if ($aliases) {
    1329          $aliases = glossary_print_entry_aliases($course, $cm, $glossary, $entry, $mode, $hook,'html');
    1330      }
    1331      $icons   = '';
    1332      if ($printicons) {
    1333          $icons   = glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode, $hook,'html');
    1334      }
    1335      if ($aliases || $icons || !empty($entry->rating)) {
    1336          echo '<table>';
    1337          if ( $aliases ) {
    1338              echo '<tr valign="top"><td class="aliases">' .
    1339                   '<label for="keyword">' . get_string('aliases','glossary').': </label>' .
    1340                   $aliases . '</td></tr>';
    1341          }
    1342          if ($icons) {
    1343              echo '<tr valign="top"><td class="icons">'.$icons.'</td></tr>';
    1344          }
    1345          if (!empty($entry->rating)) {
    1346              echo '<tr valign="top"><td class="ratings">';
    1347              glossary_print_entry_ratings($course, $entry);
    1348              echo '</td></tr>';
    1349          }
    1350          echo '</table>';
    1351      }
    1352  }
    1353  
    1354  /**
    1355   * Print the list of attachments for this glossary entry
    1356   *
    1357   * @param object $entry
    1358   * @param object $cm The coursemodule
    1359   * @param string $format The format for this view (html, or text)
    1360   * @param string $unused1 This parameter is no longer used
    1361   * @param string $unused2 This parameter is no longer used
    1362   */
    1363  function glossary_print_entry_attachment($entry, $cm, $format = null, $unused1 = null, $unused2 = null) {
    1364      // Valid format values: html: The HTML link for the attachment is an icon; and
    1365      //                      text: The HTML link for the attachment is text.
    1366      if ($entry->attachment) {
    1367          echo '<div class="attachments">';
    1368          echo glossary_print_attachments($entry, $cm, $format);
    1369          echo '</div>';
    1370      }
    1371      if ($unused1) {
    1372          debugging('The align parameter is deprecated, please use appropriate CSS instead', DEBUG_DEVELOPER);
    1373      }
    1374      if ($unused2 !== null) {
    1375          debugging('The insidetable parameter is deprecated, please use appropriate CSS instead', DEBUG_DEVELOPER);
    1376      }
    1377  }
    1378  
    1379  /**
    1380   * @global object
    1381   * @param object $cm
    1382   * @param object $entry
    1383   * @param string $mode
    1384   * @param string $align
    1385   * @param bool $insidetable
    1386   */
    1387  function  glossary_print_entry_approval($cm, $entry, $mode, $align="right", $insidetable=true) {
    1388      global $CFG, $OUTPUT;
    1389  
    1390      if ($mode == 'approval' and !$entry->approved) {
    1391          if ($insidetable) {
    1392              echo '<table class="glossaryapproval" align="'.$align.'"><tr><td align="'.$align.'">';
    1393          }
    1394          echo $OUTPUT->action_icon(
    1395              new moodle_url('approve.php', array('eid' => $entry->id, 'mode' => $mode, 'sesskey' => sesskey())),
    1396              new pix_icon('t/approve', get_string('approve','glossary'), '',
    1397                  array('class' => 'iconsmall', 'align' => $align))
    1398          );
    1399          if ($insidetable) {
    1400              echo '</td></tr></table>';
    1401          }
    1402      }
    1403  }
    1404  
    1405  /**
    1406   * It returns all entries from all glossaries that matches the specified criteria
    1407   *  within a given $course. It performs an $extended search if necessary.
    1408   * It restrict the search to only one $glossary if the $glossary parameter is set.
    1409   *
    1410   * @global object
    1411   * @global object
    1412   * @param object $course
    1413   * @param array $searchterms
    1414   * @param int $extended
    1415   * @param object $glossary
    1416   * @return array
    1417   */
    1418  function glossary_search($course, $searchterms, $extended = 0, $glossary = NULL) {
    1419      global $CFG, $DB;
    1420  
    1421      if ( !$glossary ) {
    1422          if ( $glossaries = $DB->get_records("glossary", array("course"=>$course->id)) ) {
    1423              $glos = "";
    1424              foreach ( $glossaries as $glossary ) {
    1425                  $glos .= "$glossary->id,";
    1426              }
    1427              $glos = substr($glos,0,-1);
    1428          }
    1429      } else {
    1430          $glos = $glossary->id;
    1431      }
    1432  
    1433      if (!has_capability('mod/glossary:manageentries', context_course::instance($glossary->course))) {
    1434          $glossarymodule = $DB->get_record("modules", array("name"=>"glossary"));
    1435          $onlyvisible = " AND g.id = cm.instance AND cm.visible = 1 AND cm.module = $glossarymodule->id";
    1436          $onlyvisibletable = ", {course_modules} cm";
    1437      } else {
    1438  
    1439          $onlyvisible = "";
    1440          $onlyvisibletable = "";
    1441      }
    1442  
    1443      if ($DB->sql_regex_supported()) {
    1444          $REGEXP    = $DB->sql_regex(true);
    1445          $NOTREGEXP = $DB->sql_regex(false);
    1446      }
    1447  
    1448      $searchcond = array();
    1449      $params     = array();
    1450      $i = 0;
    1451  
    1452      $concat = $DB->sql_concat('e.concept', "' '", 'e.definition');
    1453  
    1454  
    1455      foreach ($searchterms as $searchterm) {
    1456          $i++;
    1457  
    1458          $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
    1459                     /// will use it to simulate the "-" operator with LIKE clause
    1460  
    1461      /// Under Oracle and MSSQL, trim the + and - operators and perform
    1462      /// simpler LIKE (or NOT LIKE) queries
    1463          if (!$DB->sql_regex_supported()) {
    1464              if (substr($searchterm, 0, 1) == '-') {
    1465                  $NOT = true;
    1466              }
    1467              $searchterm = trim($searchterm, '+-');
    1468          }
    1469  
    1470          // TODO: +- may not work for non latin languages
    1471  
    1472          if (substr($searchterm,0,1) == '+') {
    1473              $searchterm = trim($searchterm, '+-');
    1474              $searchterm = preg_quote($searchterm, '|');
    1475              $searchcond[] = "$concat $REGEXP :ss$i";
    1476              $params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)";
    1477  
    1478          } else if (substr($searchterm,0,1) == "-") {
    1479              $searchterm = trim($searchterm, '+-');
    1480              $searchterm = preg_quote($searchterm, '|');
    1481              $searchcond[] = "$concat $NOTREGEXP :ss$i";
    1482              $params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)";
    1483  
    1484          } else {
    1485              $searchcond[] = $DB->sql_like($concat, ":ss$i", false, true, $NOT);
    1486              $params['ss'.$i] = "%$searchterm%";
    1487          }
    1488      }
    1489  
    1490      if (empty($searchcond)) {
    1491          $totalcount = 0;
    1492          return array();
    1493      }
    1494  
    1495      $searchcond = implode(" AND ", $searchcond);
    1496  
    1497      $sql = "SELECT e.*
    1498                FROM {glossary_entries} e, {glossary} g $onlyvisibletable
    1499               WHERE $searchcond
    1500                 AND (e.glossaryid = g.id or e.sourceglossaryid = g.id) $onlyvisible
    1501                 AND g.id IN ($glos) AND e.approved <> 0";
    1502  
    1503      return $DB->get_records_sql($sql, $params);
    1504  }
    1505  
    1506  /**
    1507   * @global object
    1508   * @param array $searchterms
    1509   * @param object $glossary
    1510   * @param bool $extended
    1511   * @return array
    1512   */
    1513  function glossary_search_entries($searchterms, $glossary, $extended) {
    1514      global $DB;
    1515  
    1516      $course = $DB->get_record("course", array("id"=>$glossary->course));
    1517      return glossary_search($course,$searchterms,$extended,$glossary);
    1518  }
    1519  
    1520  /**
    1521   * if return=html, then return a html string.
    1522   * if return=text, then return a text-only string.
    1523   * otherwise, print HTML for non-images, and return image HTML
    1524   *     if attachment is an image, $align set its aligment.
    1525   *
    1526   * @global object
    1527   * @global object
    1528   * @param object $entry
    1529   * @param object $cm
    1530   * @param string $type html, txt, empty
    1531   * @param string $unused This parameter is no longer used
    1532   * @return string image string or nothing depending on $type param
    1533   */
    1534  function glossary_print_attachments($entry, $cm, $type=NULL, $unused = null) {
    1535      global $CFG, $DB, $OUTPUT;
    1536  
    1537      if (!$context = context_module::instance($cm->id, IGNORE_MISSING)) {
    1538          return '';
    1539      }
    1540  
    1541      if ($entry->sourceglossaryid == $cm->instance) {
    1542          if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
    1543              return '';
    1544          }
    1545          $filecontext = context_module::instance($maincm->id);
    1546  
    1547      } else {
    1548          $filecontext = $context;
    1549      }
    1550  
    1551      $strattachment = get_string('attachment', 'glossary');
    1552  
    1553      $fs = get_file_storage();
    1554  
    1555      $imagereturn = '';
    1556      $output = '';
    1557  
    1558      if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)) {
    1559          foreach ($files as $file) {
    1560              $filename = $file->get_filename();
    1561              $mimetype = $file->get_mimetype();
    1562              $iconimage = $OUTPUT->pix_icon(file_file_icon($file), get_mimetype_description($file), 'moodle', array('class' => 'icon'));
    1563              $path = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$context->id.'/mod_glossary/attachment/'.$entry->id.'/'.$filename);
    1564  
    1565              if ($type == 'html') {
    1566                  $output .= "<a href=\"$path\">$iconimage</a> ";
    1567                  $output .= "<a href=\"$path\">".s($filename)."</a>";
    1568                  $output .= "<br />";
    1569  
    1570              } else if ($type == 'text') {
    1571                  $output .= "$strattachment ".s($filename).":\n$path\n";
    1572  
    1573              } else {
    1574                  if (in_array($mimetype, array('image/gif', 'image/jpeg', 'image/png'))) {
    1575                      // Image attachments don't get printed as links
    1576                      $imagereturn .= "<br /><img src=\"$path\" alt=\"\" />";
    1577                  } else {
    1578                      $output .= "<a href=\"$path\">$iconimage</a> ";
    1579                      $output .= format_text("<a href=\"$path\">".s($filename)."</a>", FORMAT_HTML, array('context'=>$context));
    1580                      $output .= '<br />';
    1581                  }
    1582              }
    1583          }
    1584      }
    1585  
    1586      if ($type) {
    1587          return $output;
    1588      } else {
    1589          echo $output;
    1590          return $imagereturn;
    1591      }
    1592  }
    1593  
    1594  ////////////////////////////////////////////////////////////////////////////////
    1595  // File API                                                                   //
    1596  ////////////////////////////////////////////////////////////////////////////////
    1597  
    1598  /**
    1599   * Lists all browsable file areas
    1600   *
    1601   * @package  mod_glossary
    1602   * @category files
    1603   * @param stdClass $course course object
    1604   * @param stdClass $cm course module object
    1605   * @param stdClass $context context object
    1606   * @return array
    1607   */
    1608  function glossary_get_file_areas($course, $cm, $context) {
    1609      return array(
    1610          'attachment' => get_string('areaattachment', 'mod_glossary'),
    1611          'entry' => get_string('areaentry', 'mod_glossary'),
    1612      );
    1613  }
    1614  
    1615  /**
    1616   * File browsing support for glossary module.
    1617   *
    1618   * @param file_browser $browser
    1619   * @param array $areas
    1620   * @param stdClass $course
    1621   * @param cm_info $cm
    1622   * @param context $context
    1623   * @param string $filearea
    1624   * @param int $itemid
    1625   * @param string $filepath
    1626   * @param string $filename
    1627   * @return file_info_stored file_info_stored instance or null if not found
    1628   */
    1629  function glossary_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
    1630      global $CFG, $DB, $USER;
    1631  
    1632      if ($context->contextlevel != CONTEXT_MODULE) {
    1633          return null;
    1634      }
    1635  
    1636      if (!isset($areas[$filearea])) {
    1637          return null;
    1638      }
    1639  
    1640      if (is_null($itemid)) {
    1641          require_once($CFG->dirroot.'/mod/glossary/locallib.php');
    1642          return new glossary_file_info_container($browser, $course, $cm, $context, $areas, $filearea);
    1643      }
    1644  
    1645      if (!$entry = $DB->get_record('glossary_entries', array('id' => $itemid))) {
    1646          return null;
    1647      }
    1648  
    1649      if (!$glossary = $DB->get_record('glossary', array('id' => $cm->instance))) {
    1650          return null;
    1651      }
    1652  
    1653      if ($glossary->defaultapproval and !$entry->approved and !has_capability('mod/glossary:approve', $context)) {
    1654          return null;
    1655      }
    1656  
    1657      // this trickery here is because we need to support source glossary access
    1658      if ($entry->glossaryid == $cm->instance) {
    1659          $filecontext = $context;
    1660      } else if ($entry->sourceglossaryid == $cm->instance) {
    1661          if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
    1662              return null;
    1663          }
    1664          $filecontext = context_module::instance($maincm->id);
    1665      } else {
    1666          return null;
    1667      }
    1668  
    1669      $fs = get_file_storage();
    1670      $filepath = is_null($filepath) ? '/' : $filepath;
    1671      $filename = is_null($filename) ? '.' : $filename;
    1672      if (!($storedfile = $fs->get_file($filecontext->id, 'mod_glossary', $filearea, $itemid, $filepath, $filename))) {
    1673          return null;
    1674      }
    1675  
    1676      // Checks to see if the user can manage files or is the owner.
    1677      // TODO MDL-33805 - Do not use userid here and move the capability check above.
    1678      if (!has_capability('moodle/course:managefiles', $context) && $storedfile->get_userid() != $USER->id) {
    1679          return null;
    1680      }
    1681  
    1682      $urlbase = $CFG->wwwroot.'/pluginfile.php';
    1683  
    1684      return new file_info_stored($browser, $filecontext, $storedfile, $urlbase, s($entry->concept), true, true, false, false);
    1685  }
    1686  
    1687  /**
    1688   * Serves the glossary attachments. Implements needed access control ;-)
    1689   *
    1690   * @package  mod_glossary
    1691   * @category files
    1692   * @param stdClass $course course object
    1693   * @param stdClass $cm course module object
    1694   * @param stdClsss $context context object
    1695   * @param string $filearea file area
    1696   * @param array $args extra arguments
    1697   * @param bool $forcedownload whether or not force download
    1698   * @param array $options additional options affecting the file serving
    1699   * @return bool false if file not found, does not return if found - justsend the file
    1700   */
    1701  function glossary_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
    1702      global $CFG, $DB;
    1703  
    1704      if ($context->contextlevel != CONTEXT_MODULE) {
    1705          return false;
    1706      }
    1707  
    1708      require_course_login($course, true, $cm);
    1709  
    1710      if ($filearea === 'attachment' or $filearea === 'entry') {
    1711          $entryid = (int)array_shift($args);
    1712  
    1713          require_course_login($course, true, $cm);
    1714  
    1715          if (!$entry = $DB->get_record('glossary_entries', array('id'=>$entryid))) {
    1716              return false;
    1717          }
    1718  
    1719          if (!$glossary = $DB->get_record('glossary', array('id'=>$cm->instance))) {
    1720              return false;
    1721          }
    1722  
    1723          if ($glossary->defaultapproval and !$entry->approved and !has_capability('mod/glossary:approve', $context)) {
    1724              return false;
    1725          }
    1726  
    1727          // this trickery here is because we need to support source glossary access
    1728  
    1729          if ($entry->glossaryid == $cm->instance) {
    1730              $filecontext = $context;
    1731  
    1732          } else if ($entry->sourceglossaryid == $cm->instance) {
    1733              if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
    1734                  return false;
    1735              }
    1736              $filecontext = context_module::instance($maincm->id);
    1737  
    1738          } else {
    1739              return false;
    1740          }
    1741  
    1742          $relativepath = implode('/', $args);
    1743          $fullpath = "/$filecontext->id/mod_glossary/$filearea/$entryid/$relativepath";
    1744  
    1745          $fs = get_file_storage();
    1746          if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
    1747              return false;
    1748          }
    1749  
    1750          // finally send the file
    1751          send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
    1752  
    1753      } else if ($filearea === 'export') {
    1754          require_login($course, false, $cm);
    1755          require_capability('mod/glossary:export', $context);
    1756  
    1757          if (!$glossary = $DB->get_record('glossary', array('id'=>$cm->instance))) {
    1758              return false;
    1759          }
    1760  
    1761          $cat = array_shift($args);
    1762          $cat = clean_param($cat, PARAM_ALPHANUM);
    1763  
    1764          $filename = clean_filename(strip_tags(format_string($glossary->name)).'.xml');
    1765          $content = glossary_generate_export_file($glossary, NULL, $cat);
    1766  
    1767          send_file($content, $filename, 0, 0, true, true);
    1768      }
    1769  
    1770      return false;
    1771  }
    1772  
    1773  /**
    1774   *
    1775   */
    1776  function glossary_print_tabbed_table_end() {
    1777       echo "</div></div>";
    1778  }
    1779  
    1780  /**
    1781   * @param object $cm
    1782   * @param object $glossary
    1783   * @param string $mode
    1784   * @param string $hook
    1785   * @param string $sortkey
    1786   * @param string $sortorder
    1787   */
    1788  function glossary_print_approval_menu($cm, $glossary,$mode, $hook, $sortkey = '', $sortorder = '') {
    1789      if ($glossary->showalphabet) {
    1790          echo '<div class="glossaryexplain">' . get_string("explainalphabet","glossary") . '</div><br />';
    1791      }
    1792      glossary_print_special_links($cm, $glossary, $mode, $hook);
    1793  
    1794      glossary_print_alphabet_links($cm, $glossary, $mode, $hook,$sortkey, $sortorder);
    1795  
    1796      glossary_print_all_links($cm, $glossary, $mode, $hook);
    1797  
    1798      glossary_print_sorting_links($cm, $mode, 'CREATION', 'asc');
    1799  }
    1800  /**
    1801   * @param object $cm
    1802   * @param object $glossary
    1803   * @param string $hook
    1804   * @param string $sortkey
    1805   * @param string $sortorder
    1806   */
    1807  function glossary_print_import_menu($cm, $glossary, $mode, $hook, $sortkey='', $sortorder = '') {
    1808      echo '<div class="glossaryexplain">' . get_string("explainimport","glossary") . '</div>';
    1809  }
    1810  
    1811  /**
    1812   * @param object $cm
    1813   * @param object $glossary
    1814   * @param string $hook
    1815   * @param string $sortkey
    1816   * @param string $sortorder
    1817   */
    1818  function glossary_print_export_menu($cm, $glossary, $mode, $hook, $sortkey='', $sortorder = '') {
    1819      echo '<div class="glossaryexplain">' . get_string("explainexport","glossary") . '</div>';
    1820  }
    1821  /**
    1822   * @param object $cm
    1823   * @param object $glossary
    1824   * @param string $hook
    1825   * @param string $sortkey
    1826   * @param string $sortorder
    1827   */
    1828  function glossary_print_alphabet_menu($cm, $glossary, $mode, $hook, $sortkey='', $sortorder = '') {
    1829      if ( $mode != 'date' ) {
    1830          if ($glossary->showalphabet) {
    1831              echo '<div class="glossaryexplain">' . get_string("explainalphabet","glossary") . '</div><br />';
    1832          }
    1833  
    1834          glossary_print_special_links($cm, $glossary, $mode, $hook);
    1835  
    1836          glossary_print_alphabet_links($cm, $glossary, $mode, $hook, $sortkey, $sortorder);
    1837  
    1838          glossary_print_all_links($cm, $glossary, $mode, $hook);
    1839      } else {
    1840          glossary_print_sorting_links($cm, $mode, $sortkey,$sortorder);
    1841      }
    1842  }
    1843  
    1844  /**
    1845   * @param object $cm
    1846   * @param object $glossary
    1847   * @param string $hook
    1848   * @param string $sortkey
    1849   * @param string $sortorder
    1850   */
    1851  function glossary_print_author_menu($cm, $glossary,$mode, $hook, $sortkey = '', $sortorder = '') {
    1852      if ($glossary->showalphabet) {
    1853          echo '<div class="glossaryexplain">' . get_string("explainalphabet","glossary") . '</div><br />';
    1854      }
    1855  
    1856      glossary_print_alphabet_links($cm, $glossary, $mode, $hook, $sortkey, $sortorder);
    1857      glossary_print_all_links($cm, $glossary, $mode, $hook);
    1858      glossary_print_sorting_links($cm, $mode, $sortkey,$sortorder);
    1859  }
    1860  
    1861  /**
    1862   * @global object
    1863   * @global object
    1864   * @param object $cm
    1865   * @param object $glossary
    1866   * @param string $hook
    1867   * @param object $category
    1868   */
    1869  function glossary_print_categories_menu($cm, $glossary, $hook, $category) {
    1870       global $CFG, $DB, $OUTPUT;
    1871  
    1872       $context = context_module::instance($cm->id);
    1873  
    1874      // Prepare format_string/text options
    1875      $fmtoptions = array(
    1876          'context' => $context);
    1877  
    1878       echo '<table border="0" width="100%">';
    1879       echo '<tr>';
    1880  
    1881       echo '<td align="center" style="width:20%">';
    1882       if (has_capability('mod/glossary:managecategories', $context)) {
    1883               $options['id'] = $cm->id;
    1884               $options['mode'] = 'cat';
    1885               $options['hook'] = $hook;
    1886               echo $OUTPUT->single_button(new moodle_url("editcategories.php", $options), get_string("editcategories","glossary"), "get");
    1887       }
    1888       echo '</td>';
    1889  
    1890       echo '<td align="center" style="width:60%">';
    1891       echo '<b>';
    1892  
    1893       $menu = array();
    1894       $menu[GLOSSARY_SHOW_ALL_CATEGORIES] = get_string("allcategories","glossary");
    1895       $menu[GLOSSARY_SHOW_NOT_CATEGORISED] = get_string("notcategorised","glossary");
    1896  
    1897       $categories = $DB->get_records("glossary_categories", array("glossaryid"=>$glossary->id), "name ASC");
    1898       $selected = '';
    1899       if ( $categories ) {
    1900            foreach ($categories as $currentcategory) {
    1901                   $url = $currentcategory->id;
    1902                   if ( $category ) {
    1903                       if ($currentcategory->id == $category->id) {
    1904                           $selected = $url;
    1905                       }
    1906                   }
    1907                   $menu[$url] = format_string($currentcategory->name, true, $fmtoptions);
    1908            }
    1909       }
    1910       if ( !$selected ) {
    1911           $selected = GLOSSARY_SHOW_NOT_CATEGORISED;
    1912       }
    1913  
    1914       if ( $category ) {
    1915          echo format_string($category->name, true, $fmtoptions);
    1916       } else {
    1917          if ( $hook == GLOSSARY_SHOW_NOT_CATEGORISED ) {
    1918  
    1919              echo get_string("entrieswithoutcategory","glossary");
    1920              $selected = GLOSSARY_SHOW_NOT_CATEGORISED;
    1921  
    1922          } elseif ( $hook == GLOSSARY_SHOW_ALL_CATEGORIES ) {
    1923  
    1924              echo get_string("allcategories","glossary");
    1925              $selected = GLOSSARY_SHOW_ALL_CATEGORIES;
    1926  
    1927          }
    1928       }
    1929       echo '</b></td>';
    1930       echo '<td align="center" style="width:20%">';
    1931  
    1932       $select = new single_select(new moodle_url("/mod/glossary/view.php", array('id'=>$cm->id, 'mode'=>'cat')), 'hook', $menu, $selected, null, "catmenu");
    1933       $select->set_label(get_string('categories', 'glossary'), array('class' => 'accesshide'));
    1934       echo $OUTPUT->render($select);
    1935  
    1936       echo '</td>';
    1937       echo '</tr>';
    1938  
    1939       echo '</table>';
    1940  }
    1941  
    1942  /**
    1943   * @global object
    1944   * @param object $cm
    1945   * @param object $glossary
    1946   * @param string $mode
    1947   * @param string $hook
    1948   */
    1949  function glossary_print_all_links($cm, $glossary, $mode, $hook) {
    1950  global $CFG;
    1951       if ( $glossary->showall) {
    1952           $strallentries       = get_string("allentries", "glossary");
    1953           if ( $hook == 'ALL' ) {
    1954                echo "<b>$strallentries</b>";
    1955           } else {
    1956                $strexplainall = strip_tags(get_string("explainall","glossary"));
    1957                echo "<a title=\"$strexplainall\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;mode=$mode&amp;hook=ALL\">$strallentries</a>";
    1958           }
    1959       }
    1960  }
    1961  
    1962  /**
    1963   * @global object
    1964   * @param object $cm
    1965   * @param object $glossary
    1966   * @param string $mode
    1967   * @param string $hook
    1968   */
    1969  function glossary_print_special_links($cm, $glossary, $mode, $hook) {
    1970  global $CFG;
    1971       if ( $glossary->showspecial) {
    1972           $strspecial          = get_string("special", "glossary");
    1973           if ( $hook == 'SPECIAL' ) {
    1974                echo "<b>$strspecial</b> | ";
    1975           } else {
    1976                $strexplainspecial = strip_tags(get_string("explainspecial","glossary"));
    1977                echo "<a title=\"$strexplainspecial\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;mode=$mode&amp;hook=SPECIAL\">$strspecial</a> | ";
    1978           }
    1979       }
    1980  }
    1981  
    1982  /**
    1983   * @global object
    1984   * @param object $glossary
    1985   * @param string $mode
    1986   * @param string $hook
    1987   * @param string $sortkey
    1988   * @param string $sortorder
    1989   */
    1990  function glossary_print_alphabet_links($cm, $glossary, $mode, $hook, $sortkey, $sortorder) {
    1991  global $CFG;
    1992       if ( $glossary->showalphabet) {
    1993            $alphabet = explode(",", get_string('alphabet', 'langconfig'));
    1994            for ($i = 0; $i < count($alphabet); $i++) {
    1995                if ( $hook == $alphabet[$i] and $hook) {
    1996                     echo "<b>$alphabet[$i]</b>";
    1997                } else {
    1998                     echo "<a href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;mode=$mode&amp;hook=".urlencode($alphabet[$i])."&amp;sortkey=$sortkey&amp;sortorder=$sortorder\">$alphabet[$i]</a>";
    1999                }
    2000                echo ' | ';
    2001            }
    2002       }
    2003  }
    2004  
    2005  /**
    2006   * @global object
    2007   * @param object $cm
    2008   * @param string $mode
    2009   * @param string $sortkey
    2010   * @param string $sortorder
    2011   */
    2012  function glossary_print_sorting_links($cm, $mode, $sortkey = '',$sortorder = '') {
    2013      global $CFG, $OUTPUT;
    2014  
    2015      $asc    = get_string("ascending","glossary");
    2016      $desc   = get_string("descending","glossary");
    2017      $bopen  = '<b>';
    2018      $bclose = '</b>';
    2019  
    2020       $neworder = '';
    2021       $currentorder = '';
    2022       $currentsort = '';
    2023       if ( $sortorder ) {
    2024           if ( $sortorder == 'asc' ) {
    2025               $currentorder = $asc;
    2026               $neworder = '&amp;sortorder=desc';
    2027               $newordertitle = get_string('changeto', 'glossary', $desc);
    2028           } else {
    2029               $currentorder = $desc;
    2030               $neworder = '&amp;sortorder=asc';
    2031               $newordertitle = get_string('changeto', 'glossary', $asc);
    2032           }
    2033           $icon = " <img src=\"".$OUTPUT->pix_url($sortorder, 'glossary')."\" class=\"icon\" alt=\"$newordertitle\" />";
    2034       } else {
    2035           if ( $sortkey != 'CREATION' and $sortkey != 'UPDATE' and
    2036                 $sortkey != 'FIRSTNAME' and $sortkey != 'LASTNAME' ) {
    2037               $icon = "";
    2038               $newordertitle = $asc;
    2039           } else {
    2040               $newordertitle = $desc;
    2041               $neworder = '&amp;sortorder=desc';
    2042               $icon = ' <img src="'.$OUTPUT->pix_url('asc', 'glossary').'" class="icon" alt="'.$newordertitle.'" />';
    2043           }
    2044       }
    2045       $ficon     = '';
    2046       $fneworder = '';
    2047       $fbtag     = '';
    2048       $fendbtag  = '';
    2049  
    2050       $sicon     = '';
    2051       $sneworder = '';
    2052  
    2053       $sbtag      = '';
    2054       $fbtag      = '';
    2055       $fendbtag      = '';
    2056       $sendbtag      = '';
    2057  
    2058       $sendbtag  = '';
    2059  
    2060       if ( $sortkey == 'CREATION' or $sortkey == 'FIRSTNAME' ) {
    2061           $ficon       = $icon;
    2062           $fneworder   = $neworder;
    2063           $fordertitle = $newordertitle;
    2064           $sordertitle = $asc;
    2065           $fbtag       = $bopen;
    2066           $fendbtag    = $bclose;
    2067       } elseif ($sortkey == 'UPDATE' or $sortkey == 'LASTNAME') {
    2068           $sicon = $icon;
    2069           $sneworder   = $neworder;
    2070           $fordertitle = $asc;
    2071           $sordertitle = $newordertitle;
    2072           $sbtag       = $bopen;
    2073           $sendbtag    = $bclose;
    2074       } else {
    2075           $fordertitle = $asc;
    2076           $sordertitle = $asc;
    2077       }
    2078  
    2079       if ( $sortkey == 'CREATION' or $sortkey == 'UPDATE' ) {
    2080           $forder = 'CREATION';
    2081           $sorder =  'UPDATE';
    2082           $fsort  = get_string("sortbycreation", "glossary");
    2083           $ssort  = get_string("sortbylastupdate", "glossary");
    2084  
    2085           $currentsort = $fsort;
    2086           if ($sortkey == 'UPDATE') {
    2087               $currentsort = $ssort;
    2088           }
    2089           $sort        = get_string("sortchronogically", "glossary");
    2090       } elseif ( $sortkey == 'FIRSTNAME' or $sortkey == 'LASTNAME') {
    2091           $forder = 'FIRSTNAME';
    2092           $sorder =  'LASTNAME';
    2093           $fsort  = get_string("firstname");
    2094           $ssort  = get_string("lastname");
    2095  
    2096           $currentsort = $fsort;
    2097           if ($sortkey == 'LASTNAME') {
    2098               $currentsort = $ssort;
    2099           }
    2100           $sort        = get_string("sortby", "glossary");
    2101       }
    2102       $current = '<span class="accesshide">'.get_string('current', 'glossary', "$currentsort $currentorder").'</span>';
    2103       echo "<br />$current $sort: $sbtag<a title=\"$ssort $sordertitle\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;sortkey=$sorder$sneworder&amp;mode=$mode\">$ssort$sicon</a>$sendbtag | ".
    2104                            "$fbtag<a title=\"$fsort $fordertitle\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;sortkey=$forder$fneworder&amp;mode=$mode\">$fsort$ficon</a>$fendbtag<br />";
    2105  }
    2106  
    2107  /**
    2108   *
    2109   * @param object $entry0
    2110   * @param object $entry1
    2111   * @return int [-1 | 0 | 1]
    2112   */
    2113  function glossary_sort_entries ( $entry0, $entry1 ) {
    2114  
    2115      if ( core_text::strtolower(ltrim($entry0->concept)) < core_text::strtolower(ltrim($entry1->concept)) ) {
    2116          return -1;
    2117      } elseif ( core_text::strtolower(ltrim($entry0->concept)) > core_text::strtolower(ltrim($entry1->concept)) ) {
    2118          return 1;
    2119      } else {
    2120          return 0;
    2121      }
    2122  }
    2123  
    2124  
    2125  /**
    2126   * @global object
    2127   * @global object
    2128   * @global object
    2129   * @param object $course
    2130   * @param object $entry
    2131   * @return bool
    2132   */
    2133  function  glossary_print_entry_ratings($course, $entry) {
    2134      global $OUTPUT;
    2135      if( !empty($entry->rating) ){
    2136          echo $OUTPUT->render($entry->rating);
    2137      }
    2138  }
    2139  
    2140  /**
    2141   *
    2142   * @global object
    2143   * @global object
    2144   * @global object
    2145   * @param int $courseid
    2146   * @param array $entries
    2147   * @param int $displayformat
    2148   */
    2149  function glossary_print_dynaentry($courseid, $entries, $displayformat = -1) {
    2150      global $USER,$CFG, $DB;
    2151  
    2152      echo '<div class="boxaligncenter">';
    2153      echo '<table class="glossarypopup" cellspacing="0"><tr>';
    2154      echo '<td>';
    2155      if ( $entries ) {
    2156          foreach ( $entries as $entry ) {
    2157              if (! $glossary = $DB->get_record('glossary', array('id'=>$entry->glossaryid))) {
    2158                  print_error('invalidid', 'glossary');
    2159              }
    2160              if (! $course = $DB->get_record('course', array('id'=>$glossary->course))) {
    2161                  print_error('coursemisconf');
    2162              }
    2163              if (!$cm = get_coursemodule_from_instance('glossary', $entry->glossaryid, $glossary->course) ) {
    2164                  print_error('invalidid', 'glossary');
    2165              }
    2166  
    2167              //If displayformat is present, override glossary->displayformat
    2168              if ($displayformat < 0) {
    2169                  $dp = $glossary->displayformat;
    2170              } else {
    2171                  $dp = $displayformat;
    2172              }
    2173  
    2174              //Get popupformatname
    2175              $format = $DB->get_record('glossary_formats', array('name'=>$dp));
    2176              $displayformat = $format->popupformatname;
    2177  
    2178              //Check displayformat variable and set to default if necessary
    2179              if (!$displayformat) {
    2180                  $displayformat = 'dictionary';
    2181              }
    2182  
    2183              $formatfile = $CFG->dirroot.'/mod/glossary/formats/'.$displayformat.'/'.$displayformat.'_format.php';
    2184              $functionname = 'glossary_show_entry_'.$displayformat;
    2185  
    2186              if (file_exists($formatfile)) {
    2187                  include_once($formatfile);
    2188                  if (function_exists($functionname)) {
    2189                      $functionname($course, $cm, $glossary, $entry,'','','','');
    2190                  }
    2191              }
    2192          }
    2193      }
    2194      echo '</td>';
    2195      echo '</tr></table></div>';
    2196  }
    2197  
    2198  /**
    2199   *
    2200   * @global object
    2201   * @param array $entries
    2202   * @param array $aliases
    2203   * @param array $categories
    2204   * @return string
    2205   */
    2206  function glossary_generate_export_csv($entries, $aliases, $categories) {
    2207      global $CFG;
    2208      $csv = '';
    2209      $delimiter = '';
    2210      require_once($CFG->libdir . '/csvlib.class.php');
    2211      $delimiter = csv_import_reader::get_delimiter('comma');
    2212      $csventries = array(0 => array(get_string('concept', 'glossary'), get_string('definition', 'glossary')));
    2213      $csvaliases = array(0 => array());
    2214      $csvcategories = array(0 => array());
    2215      $aliascount = 0;
    2216      $categorycount = 0;
    2217  
    2218      foreach ($entries as $entry) {
    2219          $thisaliasesentry = array();
    2220          $thiscategoriesentry = array();
    2221          $thiscsventry = array($entry->concept, nl2br($entry->definition));
    2222  
    2223          if (array_key_exists($entry->id, $aliases) && is_array($aliases[$entry->id])) {
    2224              $thiscount = count($aliases[$entry->id]);
    2225              if ($thiscount > $aliascount) {
    2226                  $aliascount = $thiscount;
    2227              }
    2228              foreach ($aliases[$entry->id] as $alias) {
    2229                  $thisaliasesentry[] = trim($alias);
    2230              }
    2231          }
    2232          if (array_key_exists($entry->id, $categories) && is_array($categories[$entry->id])) {
    2233              $thiscount = count($categories[$entry->id]);
    2234              if ($thiscount > $categorycount) {
    2235                  $categorycount = $thiscount;
    2236              }
    2237              foreach ($categories[$entry->id] as $catentry) {
    2238                  $thiscategoriesentry[] = trim($catentry);
    2239              }
    2240          }
    2241          $csventries[$entry->id] = $thiscsventry;
    2242          $csvaliases[$entry->id] = $thisaliasesentry;
    2243          $csvcategories[$entry->id] = $thiscategoriesentry;
    2244  
    2245      }
    2246      $returnstr = '';
    2247      foreach ($csventries as $id => $row) {
    2248          $aliasstr = '';
    2249          $categorystr = '';
    2250          if ($id == 0) {
    2251              $aliasstr = get_string('alias', 'glossary');
    2252              $categorystr = get_string('category', 'glossary');
    2253          }
    2254          $row = array_merge($row, array_pad($csvaliases[$id], $aliascount, $aliasstr), array_pad($csvcategories[$id], $categorycount, $categorystr));
    2255          $returnstr .= '"' . implode('"' . $delimiter . '"', $row) . '"' . "\n";
    2256      }
    2257      return $returnstr;
    2258  }
    2259  
    2260  /**
    2261   *
    2262   * @param object $glossary
    2263   * @param string $ignored invalid parameter
    2264   * @param int|string $hook
    2265   * @return string
    2266   */
    2267  function glossary_generate_export_file($glossary, $ignored = "", $hook = 0) {
    2268      global $CFG, $DB;
    2269  
    2270      $co  = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    2271  
    2272      $co .= glossary_start_tag("GLOSSARY",0,true);
    2273      $co .= glossary_start_tag("INFO",1,true);
    2274          $co .= glossary_full_tag("NAME",2,false,$glossary->name);
    2275          $co .= glossary_full_tag("INTRO",2,false,$glossary->intro);
    2276          $co .= glossary_full_tag("INTROFORMAT",2,false,$glossary->introformat);
    2277          $co .= glossary_full_tag("ALLOWDUPLICATEDENTRIES",2,false,$glossary->allowduplicatedentries);
    2278          $co .= glossary_full_tag("DISPLAYFORMAT",2,false,$glossary->displayformat);
    2279          $co .= glossary_full_tag("SHOWSPECIAL",2,false,$glossary->showspecial);
    2280          $co .= glossary_full_tag("SHOWALPHABET",2,false,$glossary->showalphabet);
    2281          $co .= glossary_full_tag("SHOWALL",2,false,$glossary->showall);
    2282          $co .= glossary_full_tag("ALLOWCOMMENTS",2,false,$glossary->allowcomments);
    2283          $co .= glossary_full_tag("USEDYNALINK",2,false,$glossary->usedynalink);
    2284          $co .= glossary_full_tag("DEFAULTAPPROVAL",2,false,$glossary->defaultapproval);
    2285          $co .= glossary_full_tag("GLOBALGLOSSARY",2,false,$glossary->globalglossary);
    2286          $co .= glossary_full_tag("ENTBYPAGE",2,false,$glossary->entbypage);
    2287  
    2288          if ( $entries = $DB->get_records("glossary_entries", array("glossaryid"=>$glossary->id))) {
    2289              $co .= glossary_start_tag("ENTRIES",2,true);
    2290              foreach ($entries as $entry) {
    2291                  $permissiongranted = 1;
    2292                  if ( $hook ) {
    2293                      switch ( $hook ) {
    2294                      case "ALL":
    2295                      case "SPECIAL":
    2296                      break;
    2297                      default:
    2298                          $permissiongranted = ($entry->concept[ strlen($hook)-1 ] == $hook);
    2299                      break;
    2300                      }
    2301                  }
    2302                  if ( $hook ) {
    2303                      switch ( $hook ) {
    2304                      case GLOSSARY_SHOW_ALL_CATEGORIES:
    2305                      break;
    2306                      case GLOSSARY_SHOW_NOT_CATEGORISED:
    2307                          $permissiongranted = !$DB->record_exists("glossary_entries_categories", array("entryid"=>$entry->id));
    2308                      break;
    2309                      default:
    2310                          $permissiongranted = $DB->record_exists("glossary_entries_categories", array("entryid"=>$entry->id, "categoryid"=>$hook));
    2311                      break;
    2312                      }
    2313                  }
    2314                  if ( $entry->approved and $permissiongranted ) {
    2315                      $co .= glossary_start_tag("ENTRY",3,true);
    2316                      $co .= glossary_full_tag("CONCEPT",4,false,trim($entry->concept));
    2317                      $co .= glossary_full_tag("DEFINITION",4,false,$entry->definition);
    2318                      $co .= glossary_full_tag("FORMAT",4,false,$entry->definitionformat); // note: use old name for BC reasons
    2319                      $co .= glossary_full_tag("USEDYNALINK",4,false,$entry->usedynalink);
    2320                      $co .= glossary_full_tag("CASESENSITIVE",4,false,$entry->casesensitive);
    2321                      $co .= glossary_full_tag("FULLMATCH",4,false,$entry->fullmatch);
    2322                      $co .= glossary_full_tag("TEACHERENTRY",4,false,$entry->teacherentry);
    2323  
    2324                      if ( $aliases = $DB->get_records("glossary_alias", array("entryid"=>$entry->id))) {
    2325                          $co .= glossary_start_tag("ALIASES",4,true);
    2326                          foreach ($aliases as $alias) {
    2327                              $co .= glossary_start_tag("ALIAS",5,true);
    2328                                  $co .= glossary_full_tag("NAME",6,false,trim($alias->alias));
    2329                              $co .= glossary_end_tag("ALIAS",5,true);
    2330                          }
    2331                          $co .= glossary_end_tag("ALIASES",4,true);
    2332                      }
    2333                      if ( $catentries = $DB->get_records("glossary_entries_categories", array("entryid"=>$entry->id))) {
    2334                          $co .= glossary_start_tag("CATEGORIES",4,true);
    2335                          foreach ($catentries as $catentry) {
    2336                              $category = $DB->get_record("glossary_categories", array("id"=>$catentry->categoryid));
    2337  
    2338                              $co .= glossary_start_tag("CATEGORY",5,true);
    2339                                  $co .= glossary_full_tag("NAME",6,false,$category->name);
    2340                                  $co .= glossary_full_tag("USEDYNALINK",6,false,$category->usedynalink);
    2341                              $co .= glossary_end_tag("CATEGORY",5,true);
    2342                          }
    2343                          $co .= glossary_end_tag("CATEGORIES",4,true);
    2344                      }
    2345  
    2346                      $co .= glossary_end_tag("ENTRY",3,true);
    2347                  }
    2348              }
    2349              $co .= glossary_end_tag("ENTRIES",2,true);
    2350  
    2351          }
    2352  
    2353  
    2354      $co .= glossary_end_tag("INFO",1,true);
    2355      $co .= glossary_end_tag("GLOSSARY",0,true);
    2356  
    2357      return $co;
    2358  }
    2359  /// Functions designed by Eloy Lafuente
    2360  /// Functions to create, open and write header of the xml file
    2361  
    2362  /**
    2363   * Read import file and convert to current charset
    2364   *
    2365   * @global object
    2366   * @param string $file
    2367   * @return string
    2368   */
    2369  function glossary_read_imported_file($file_content) {
    2370      require_once  "../../lib/xmlize.php";
    2371      global $CFG;
    2372  
    2373      return xmlize($file_content, 0);
    2374  }
    2375  
    2376  /**
    2377   * Return the xml start tag
    2378   *
    2379   * @param string $tag
    2380   * @param int $level
    2381   * @param bool $endline
    2382   * @return string
    2383   */
    2384  function glossary_start_tag($tag,$level=0,$endline=false) {
    2385          if ($endline) {
    2386             $endchar = "\n";
    2387          } else {
    2388             $endchar = "";
    2389          }
    2390          return str_repeat(" ",$level*2)."<".strtoupper($tag).">".$endchar;
    2391  }
    2392  
    2393  /**
    2394   * Return the xml end tag
    2395   * @param string $tag
    2396   * @param int $level
    2397   * @param bool $endline
    2398   * @return string
    2399   */
    2400  function glossary_end_tag($tag,$level=0,$endline=true) {
    2401          if ($endline) {
    2402             $endchar = "\n";
    2403          } else {
    2404             $endchar = "";
    2405          }
    2406          return str_repeat(" ",$level*2)."</".strtoupper($tag).">".$endchar;
    2407  }
    2408  
    2409  /**
    2410   * Return the start tag, the contents and the end tag
    2411   *
    2412   * @global object
    2413   * @param string $tag
    2414   * @param int $level
    2415   * @param bool $endline
    2416   * @param string $content
    2417   * @return string
    2418   */
    2419  function glossary_full_tag($tag,$level=0,$endline=true,$content) {
    2420          global $CFG;
    2421  
    2422          $st = glossary_start_tag($tag,$level,$endline);
    2423          $co = preg_replace("/\r\n|\r/", "\n", s($content));
    2424          $et = glossary_end_tag($tag,0,true);
    2425          return $st.$co.$et;
    2426  }
    2427  
    2428  /**
    2429   * How many unrated entries are in the given glossary for a given user?
    2430   *
    2431   * @global moodle_database $DB
    2432   * @param int $glossaryid
    2433   * @param int $userid
    2434   * @return int
    2435   */
    2436  function glossary_count_unrated_entries($glossaryid, $userid) {
    2437      global $DB;
    2438  
    2439      $sql = "SELECT COUNT('x') as num
    2440                FROM {glossary_entries}
    2441               WHERE glossaryid = :glossaryid AND
    2442                     userid <> :userid";
    2443      $params = array('glossaryid' => $glossaryid, 'userid' => $userid);
    2444      $entries = $DB->count_records_sql($sql, $params);
    2445  
    2446      if ($entries) {
    2447          // We need to get the contextid for the glossaryid we have been given.
    2448          $sql = "SELECT ctx.id
    2449                    FROM {context} ctx
    2450                    JOIN {course_modules} cm ON cm.id = ctx.instanceid
    2451                    JOIN {modules} m ON m.id = cm.module
    2452                    JOIN {glossary} g ON g.id = cm.instance
    2453                   WHERE ctx.contextlevel = :contextlevel AND
    2454                         m.name = 'glossary' AND
    2455                         g.id = :glossaryid";
    2456          $contextid = $DB->get_field_sql($sql, array('glossaryid' => $glossaryid, 'contextlevel' => CONTEXT_MODULE));
    2457  
    2458          // Now we need to count the ratings that this user has made
    2459          $sql = "SELECT COUNT('x') AS num
    2460                    FROM {glossary_entries} e
    2461                    JOIN {rating} r ON r.itemid = e.id
    2462                   WHERE e.glossaryid = :glossaryid AND
    2463                         r.userid = :userid AND
    2464                         r.component = 'mod_glossary' AND
    2465                         r.ratingarea = 'entry' AND
    2466                         r.contextid = :contextid";
    2467          $params = array('glossaryid' => $glossaryid, 'userid' => $userid, 'contextid' => $contextid);
    2468          $rated = $DB->count_records_sql($sql, $params);
    2469          if ($rated) {
    2470              // The number or enties minus the number or rated entries equals the number of unrated
    2471              // entries
    2472              if ($entries > $rated) {
    2473                  return $entries - $rated;
    2474              } else {
    2475                  return 0;    // Just in case there was a counting error
    2476              }
    2477          } else {
    2478              return (int)$entries;
    2479          }
    2480      } else {
    2481          return 0;
    2482      }
    2483  }
    2484  
    2485  /**
    2486   *
    2487   * Returns the html code to represent any pagging bar. Paramenters are:
    2488   *
    2489   * The function dinamically show the first and last pages, and "scroll" over pages.
    2490   * Fully compatible with Moodle's print_paging_bar() function. Perhaps some day this
    2491   * could replace the general one. ;-)
    2492   *
    2493   * @param int $totalcount total number of records to be displayed
    2494   * @param int $page page currently selected (0 based)
    2495   * @param int $perpage number of records per page
    2496   * @param string $baseurl url to link in each page, the string 'page=XX' will be added automatically.
    2497   *
    2498   * @param int $maxpageallowed Optional maximum number of page allowed.
    2499   * @param int $maxdisplay Optional maximum number of page links to show in the bar
    2500   * @param string $separator Optional string to be used between pages in the bar
    2501   * @param string $specialtext Optional string to be showed as an special link
    2502   * @param string $specialvalue Optional value (page) to be used in the special link
    2503   * @param bool $previousandnext Optional to decide if we want the previous and next links
    2504   * @return string
    2505   */
    2506  function glossary_get_paging_bar($totalcount, $page, $perpage, $baseurl, $maxpageallowed=99999, $maxdisplay=20, $separator="&nbsp;", $specialtext="", $specialvalue=-1, $previousandnext = true) {
    2507  
    2508      $code = '';
    2509  
    2510      $showspecial = false;
    2511      $specialselected = false;
    2512  
    2513      //Check if we have to show the special link
    2514      if (!empty($specialtext)) {
    2515          $showspecial = true;
    2516      }
    2517      //Check if we are with the special link selected
    2518      if ($showspecial && $page == $specialvalue) {
    2519          $specialselected = true;
    2520      }
    2521  
    2522      //If there are results (more than 1 page)
    2523      if ($totalcount > $perpage) {
    2524          $code .= "<div style=\"text-align:center\">";
    2525          $code .= "<p>".get_string("page").":";
    2526  
    2527          $maxpage = (int)(($totalcount-1)/$perpage);
    2528  
    2529          //Lower and upper limit of page
    2530          if ($page < 0) {
    2531              $page = 0;
    2532          }
    2533          if ($page > $maxpageallowed) {
    2534              $page = $maxpageallowed;
    2535          }
    2536          if ($page > $maxpage) {
    2537              $page = $maxpage;
    2538          }
    2539  
    2540          //Calculate the window of pages
    2541          $pagefrom = $page - ((int)($maxdisplay / 2));
    2542          if ($pagefrom < 0) {
    2543              $pagefrom = 0;
    2544          }
    2545          $pageto = $pagefrom + $maxdisplay - 1;
    2546          if ($pageto > $maxpageallowed) {
    2547              $pageto = $maxpageallowed;
    2548          }
    2549          if ($pageto > $maxpage) {
    2550              $pageto = $maxpage;
    2551          }
    2552  
    2553          //Some movements can be necessary if don't see enought pages
    2554          if ($pageto - $pagefrom < $maxdisplay - 1) {
    2555              if ($pageto - $maxdisplay + 1 > 0) {
    2556                  $pagefrom = $pageto - $maxdisplay + 1;
    2557              }
    2558          }
    2559  
    2560          //Calculate first and last if necessary
    2561          $firstpagecode = '';
    2562          $lastpagecode = '';
    2563          if ($pagefrom > 0) {
    2564              $firstpagecode = "$separator<a href=\"{$baseurl}page=0\">1</a>";
    2565              if ($pagefrom > 1) {
    2566                  $firstpagecode .= "$separator...";
    2567              }
    2568          }
    2569          if ($pageto < $maxpage) {
    2570              if ($pageto < $maxpage -1) {
    2571                  $lastpagecode = "$separator...";
    2572              }
    2573              $lastpagecode .= "$separator<a href=\"{$baseurl}page=$maxpage\">".($maxpage+1)."</a>";
    2574          }
    2575  
    2576          //Previous
    2577          if ($page > 0 && $previousandnext) {
    2578              $pagenum = $page - 1;
    2579              $code .= "&nbsp;(<a  href=\"{$baseurl}page=$pagenum\">".get_string("previous")."</a>)&nbsp;";
    2580          }
    2581  
    2582          //Add first
    2583          $code .= $firstpagecode;
    2584  
    2585          $pagenum = $pagefrom;
    2586  
    2587          //List of maxdisplay pages
    2588          while ($pagenum <= $pageto) {
    2589              $pagetoshow = $pagenum +1;
    2590              if ($pagenum == $page && !$specialselected) {
    2591                  $code .= "$separator<b>$pagetoshow</b>";
    2592              } else {
    2593                  $code .= "$separator<a href=\"{$baseurl}page=$pagenum\">$pagetoshow</a>";
    2594              }
    2595              $pagenum++;
    2596          }
    2597  
    2598          //Add last
    2599          $code .= $lastpagecode;
    2600  
    2601          //Next
    2602          if ($page < $maxpage && $page < $maxpageallowed && $previousandnext) {
    2603              $pagenum = $page + 1;
    2604              $code .= "$separator(<a href=\"{$baseurl}page=$pagenum\">".get_string("next")."</a>)";
    2605          }
    2606  
    2607          //Add special
    2608          if ($showspecial) {
    2609              $code .= '<br />';
    2610              if ($specialselected) {
    2611                  $code .= "<b>$specialtext</b>";
    2612              } else {
    2613                  $code .= "$separator<a href=\"{$baseurl}page=$specialvalue\">$specialtext</a>";
    2614              }
    2615          }
    2616  
    2617          //End html
    2618          $code .= "</p>";
    2619          $code .= "</div>";
    2620      }
    2621  
    2622      return $code;
    2623  }
    2624  
    2625  /**
    2626   * List the actions that correspond to a view of this module.
    2627   * This is used by the participation report.
    2628   *
    2629   * Note: This is not used by new logging system. Event with
    2630   *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
    2631   *       be considered as view action.
    2632   *
    2633   * @return array
    2634   */
    2635  function glossary_get_view_actions() {
    2636      return array('view','view all','view entry');
    2637  }
    2638  
    2639  /**
    2640   * List the actions that correspond to a post of this module.
    2641   * This is used by the participation report.
    2642   *
    2643   * Note: This is not used by new logging system. Event with
    2644   *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
    2645   *       will be considered as post action.
    2646   *
    2647   * @return array
    2648   */
    2649  function glossary_get_post_actions() {
    2650      return array('add category','add entry','approve entry','delete category','delete entry','edit category','update entry');
    2651  }
    2652  
    2653  
    2654  /**
    2655   * Implementation of the function for printing the form elements that control
    2656   * whether the course reset functionality affects the glossary.
    2657   * @param object $mform form passed by reference
    2658   */
    2659  function glossary_reset_course_form_definition(&$mform) {
    2660      $mform->addElement('header', 'glossaryheader', get_string('modulenameplural', 'glossary'));
    2661      $mform->addElement('checkbox', 'reset_glossary_all', get_string('resetglossariesall','glossary'));
    2662  
    2663      $mform->addElement('select', 'reset_glossary_types', get_string('resetglossaries', 'glossary'),
    2664                         array('main'=>get_string('mainglossary', 'glossary'), 'secondary'=>get_string('secondaryglossary', 'glossary')), array('multiple' => 'multiple'));
    2665      $mform->setAdvanced('reset_glossary_types');
    2666      $mform->disabledIf('reset_glossary_types', 'reset_glossary_all', 'checked');
    2667  
    2668      $mform->addElement('checkbox', 'reset_glossary_notenrolled', get_string('deletenotenrolled', 'glossary'));
    2669      $mform->disabledIf('reset_glossary_notenrolled', 'reset_glossary_all', 'checked');
    2670  
    2671      $mform->addElement('checkbox', 'reset_glossary_ratings', get_string('deleteallratings'));
    2672      $mform->disabledIf('reset_glossary_ratings', 'reset_glossary_all', 'checked');
    2673  
    2674      $mform->addElement('checkbox', 'reset_glossary_comments', get_string('deleteallcomments'));
    2675      $mform->disabledIf('reset_glossary_comments', 'reset_glossary_all', 'checked');
    2676  }
    2677  
    2678  /**
    2679   * Course reset form defaults.
    2680   * @return array
    2681   */
    2682  function glossary_reset_course_form_defaults($course) {
    2683      return array('reset_glossary_all'=>0, 'reset_glossary_ratings'=>1, 'reset_glossary_comments'=>1, 'reset_glossary_notenrolled'=>0);
    2684  }
    2685  
    2686  /**
    2687   * Removes all grades from gradebook
    2688   *
    2689   * @param int $courseid The ID of the course to reset
    2690   * @param string $type The optional type of glossary. 'main', 'secondary' or ''
    2691   */
    2692  function glossary_reset_gradebook($courseid, $type='') {
    2693      global $DB;
    2694  
    2695      switch ($type) {
    2696          case 'main'      : $type = "AND g.mainglossary=1"; break;
    2697          case 'secondary' : $type = "AND g.mainglossary=0"; break;
    2698          default          : $type = ""; //all
    2699      }
    2700  
    2701      $sql = "SELECT g.*, cm.idnumber as cmidnumber, g.course as courseid
    2702                FROM {glossary} g, {course_modules} cm, {modules} m
    2703               WHERE m.name='glossary' AND m.id=cm.module AND cm.instance=g.id AND g.course=? $type";
    2704  
    2705      if ($glossarys = $DB->get_records_sql($sql, array($courseid))) {
    2706          foreach ($glossarys as $glossary) {
    2707              glossary_grade_item_update($glossary, 'reset');
    2708          }
    2709      }
    2710  }
    2711  /**
    2712   * Actual implementation of the reset course functionality, delete all the
    2713   * glossary responses for course $data->courseid.
    2714   *
    2715   * @global object
    2716   * @param $data the data submitted from the reset course.
    2717   * @return array status array
    2718   */
    2719  function glossary_reset_userdata($data) {
    2720      global $CFG, $DB;
    2721      require_once($CFG->dirroot.'/rating/lib.php');
    2722  
    2723      $componentstr = get_string('modulenameplural', 'glossary');
    2724      $status = array();
    2725  
    2726      $allentriessql = "SELECT e.id
    2727                          FROM {glossary_entries} e
    2728                               JOIN {glossary} g ON e.glossaryid = g.id
    2729                         WHERE g.course = ?";
    2730  
    2731      $allglossariessql = "SELECT g.id
    2732                             FROM {glossary} g
    2733                            WHERE g.course = ?";
    2734  
    2735      $params = array($data->courseid);
    2736  
    2737      $fs = get_file_storage();
    2738  
    2739      $rm = new rating_manager();
    2740      $ratingdeloptions = new stdClass;
    2741      $ratingdeloptions->component = 'mod_glossary';
    2742      $ratingdeloptions->ratingarea = 'entry';
    2743  
    2744      // delete entries if requested
    2745      if (!empty($data->reset_glossary_all)
    2746           or (!empty($data->reset_glossary_types) and in_array('main', $data->reset_glossary_types) and in_array('secondary', $data->reset_glossary_types))) {
    2747  
    2748          $params[] = 'glossary_entry';
    2749          $DB->delete_records_select('comments', "itemid IN ($allentriessql) AND commentarea=?", $params);
    2750          $DB->delete_records_select('glossary_alias',    "entryid IN ($allentriessql)", $params);
    2751          $DB->delete_records_select('glossary_entries', "glossaryid IN ($allglossariessql)", $params);
    2752  
    2753          // now get rid of all attachments
    2754          if ($glossaries = $DB->get_records_sql($allglossariessql, $params)) {
    2755              foreach ($glossaries as $glossaryid=>$unused) {
    2756                  if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
    2757                      continue;
    2758                  }
    2759                  $context = context_module::instance($cm->id);
    2760                  $fs->delete_area_files($context->id, 'mod_glossary', 'attachment');
    2761  
    2762                  //delete ratings
    2763                  $ratingdeloptions->contextid = $context->id;
    2764                  $rm->delete_ratings($ratingdeloptions);
    2765              }
    2766          }
    2767  
    2768          // remove all grades from gradebook
    2769          if (empty($data->reset_gradebook_grades)) {
    2770              glossary_reset_gradebook($data->courseid);
    2771          }
    2772  
    2773          $status[] = array('component'=>$componentstr, 'item'=>get_string('resetglossariesall', 'glossary'), 'error'=>false);
    2774  
    2775      } else if (!empty($data->reset_glossary_types)) {
    2776          $mainentriessql         = "$allentriessql AND g.mainglossary=1";
    2777          $secondaryentriessql    = "$allentriessql AND g.mainglossary=0";
    2778  
    2779          $mainglossariessql      = "$allglossariessql AND g.mainglossary=1";
    2780          $secondaryglossariessql = "$allglossariessql AND g.mainglossary=0";
    2781  
    2782          if (in_array('main', $data->reset_glossary_types)) {
    2783              $params[] = 'glossary_entry';
    2784              $DB->delete_records_select('comments', "itemid IN ($mainentriessql) AND commentarea=?", $params);
    2785              $DB->delete_records_select('glossary_entries', "glossaryid IN ($mainglossariessql)", $params);
    2786  
    2787              if ($glossaries = $DB->get_records_sql($mainglossariessql, $params)) {
    2788                  foreach ($glossaries as $glossaryid=>$unused) {
    2789                      if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
    2790                          continue;
    2791                      }
    2792                      $context = context_module::instance($cm->id);
    2793                      $fs->delete_area_files($context->id, 'mod_glossary', 'attachment');
    2794  
    2795                      //delete ratings
    2796                      $ratingdeloptions->contextid = $context->id;
    2797                      $rm->delete_ratings($ratingdeloptions);
    2798                  }
    2799              }
    2800  
    2801              // remove all grades from gradebook
    2802              if (empty($data->reset_gradebook_grades)) {
    2803                  glossary_reset_gradebook($data->courseid, 'main');
    2804              }
    2805  
    2806              $status[] = array('component'=>$componentstr, 'item'=>get_string('resetglossaries', 'glossary').': '.get_string('mainglossary', 'glossary'), 'error'=>false);
    2807  
    2808          } else if (in_array('secondary', $data->reset_glossary_types)) {
    2809              $params[] = 'glossary_entry';
    2810              $DB->delete_records_select('comments', "itemid IN ($secondaryentriessql) AND commentarea=?", $params);
    2811              $DB->delete_records_select('glossary_entries', "glossaryid IN ($secondaryglossariessql)", $params);
    2812              // remove exported source flag from entries in main glossary
    2813              $DB->execute("UPDATE {glossary_entries}
    2814                               SET sourceglossaryid=0
    2815                             WHERE glossaryid IN ($mainglossariessql)", $params);
    2816  
    2817              if ($glossaries = $DB->get_records_sql($secondaryglossariessql, $params)) {
    2818                  foreach ($glossaries as $glossaryid=>$unused) {
    2819                      if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
    2820                          continue;
    2821                      }
    2822                      $context = context_module::instance($cm->id);
    2823                      $fs->delete_area_files($context->id, 'mod_glossary', 'attachment');
    2824  
    2825                      //delete ratings
    2826                      $ratingdeloptions->contextid = $context->id;
    2827                      $rm->delete_ratings($ratingdeloptions);
    2828                  }
    2829              }
    2830  
    2831              // remove all grades from gradebook
    2832              if (empty($data->reset_gradebook_grades)) {
    2833                  glossary_reset_gradebook($data->courseid, 'secondary');
    2834              }
    2835  
    2836              $status[] = array('component'=>$componentstr, 'item'=>get_string('resetglossaries', 'glossary').': '.get_string('secondaryglossary', 'glossary'), 'error'=>false);
    2837          }
    2838      }
    2839  
    2840      // remove entries by users not enrolled into course
    2841      if (!empty($data->reset_glossary_notenrolled)) {
    2842          $entriessql = "SELECT e.id, e.userid, e.glossaryid, u.id AS userexists, u.deleted AS userdeleted
    2843                           FROM {glossary_entries} e
    2844                                JOIN {glossary} g ON e.glossaryid = g.id
    2845                                LEFT JOIN {user} u ON e.userid = u.id
    2846                          WHERE g.course = ? AND e.userid > 0";
    2847  
    2848          $course_context = context_course::instance($data->courseid);
    2849          $notenrolled = array();
    2850          $rs = $DB->get_recordset_sql($entriessql, $params);
    2851          if ($rs->valid()) {
    2852              foreach ($rs as $entry) {
    2853                  if (array_key_exists($entry->userid, $notenrolled) or !$entry->userexists or $entry->userdeleted
    2854                    or !is_enrolled($course_context , $entry->userid)) {
    2855                      $DB->delete_records('comments', array('commentarea'=>'glossary_entry', 'itemid'=>$entry->id));
    2856                      $DB->delete_records('glossary_entries', array('id'=>$entry->id));
    2857  
    2858                      if ($cm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
    2859                          $context = context_module::instance($cm->id);
    2860                          $fs->delete_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
    2861  
    2862                          //delete ratings
    2863                          $ratingdeloptions->contextid = $context->id;
    2864                          $rm->delete_ratings($ratingdeloptions);
    2865                      }
    2866                  }
    2867              }
    2868              $status[] = array('component'=>$componentstr, 'item'=>get_string('deletenotenrolled', 'glossary'), 'error'=>false);
    2869          }
    2870          $rs->close();
    2871      }
    2872  
    2873      // remove all ratings
    2874      if (!empty($data->reset_glossary_ratings)) {
    2875          //remove ratings
    2876          if ($glossaries = $DB->get_records_sql($allglossariessql, $params)) {
    2877              foreach ($glossaries as $glossaryid=>$unused) {
    2878                  if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
    2879                      continue;
    2880                  }
    2881                  $context = context_module::instance($cm->id);
    2882  
    2883                  //delete ratings
    2884                  $ratingdeloptions->contextid = $context->id;
    2885                  $rm->delete_ratings($ratingdeloptions);
    2886              }
    2887          }
    2888  
    2889          // remove all grades from gradebook
    2890          if (empty($data->reset_gradebook_grades)) {
    2891              glossary_reset_gradebook($data->courseid);
    2892          }
    2893          $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallratings'), 'error'=>false);
    2894      }
    2895  
    2896      // remove comments
    2897      if (!empty($data->reset_glossary_comments)) {
    2898          $params[] = 'glossary_entry';
    2899          $DB->delete_records_select('comments', "itemid IN ($allentriessql) AND commentarea= ? ", $params);
    2900          $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallcomments'), 'error'=>false);
    2901      }
    2902  
    2903      /// updating dates - shift may be negative too
    2904      if ($data->timeshift) {
    2905          shift_course_mod_dates('glossary', array('assesstimestart', 'assesstimefinish'), $data->timeshift, $data->courseid);
    2906          $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
    2907      }
    2908  
    2909      return $status;
    2910  }
    2911  
    2912  /**
    2913   * Returns all other caps used in module
    2914   * @return array
    2915   */
    2916  function glossary_get_extra_capabilities() {
    2917      return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames', 'moodle/site:trustcontent', 'moodle/rating:view', 'moodle/rating:viewany', 'moodle/rating:viewall', 'moodle/rating:rate', 'moodle/comment:view', 'moodle/comment:post', 'moodle/comment:delete');
    2918  }
    2919  
    2920  /**
    2921   * @param string $feature FEATURE_xx constant for requested feature
    2922   * @return mixed True if module supports feature, null if doesn't know
    2923   */
    2924  function glossary_supports($feature) {
    2925      switch($feature) {
    2926          case FEATURE_GROUPS:                  return false;
    2927          case FEATURE_GROUPINGS:               return false;
    2928          case FEATURE_MOD_INTRO:               return true;
    2929          case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
    2930          case FEATURE_COMPLETION_HAS_RULES:    return true;
    2931          case FEATURE_GRADE_HAS_GRADE:         return true;
    2932          case FEATURE_GRADE_OUTCOMES:          return true;
    2933          case FEATURE_RATE:                    return true;
    2934          case FEATURE_BACKUP_MOODLE2:          return true;
    2935          case FEATURE_SHOW_DESCRIPTION:        return true;
    2936  
    2937          default: return null;
    2938      }
    2939  }
    2940  
    2941  /**
    2942   * Obtains the automatic completion state for this glossary based on any conditions
    2943   * in glossary settings.
    2944   *
    2945   * @global object
    2946   * @global object
    2947   * @param object $course Course
    2948   * @param object $cm Course-module
    2949   * @param int $userid User ID
    2950   * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
    2951   * @return bool True if completed, false if not. (If no conditions, then return
    2952   *   value depends on comparison type)
    2953   */
    2954  function glossary_get_completion_state($course,$cm,$userid,$type) {
    2955      global $CFG, $DB;
    2956  
    2957      // Get glossary details
    2958      if (!($glossary=$DB->get_record('glossary',array('id'=>$cm->instance)))) {
    2959          throw new Exception("Can't find glossary {$cm->instance}");
    2960      }
    2961  
    2962      $result=$type; // Default return value
    2963  
    2964      if ($glossary->completionentries) {
    2965          $value = $glossary->completionentries <=
    2966                   $DB->count_records('glossary_entries',array('glossaryid'=>$glossary->id, 'userid'=>$userid, 'approved'=>1));
    2967          if ($type == COMPLETION_AND) {
    2968              $result = $result && $value;
    2969          } else {
    2970              $result = $result || $value;
    2971          }
    2972      }
    2973  
    2974      return $result;
    2975  }
    2976  
    2977  function glossary_extend_navigation($navigation, $course, $module, $cm) {
    2978      global $CFG;
    2979      $navigation->add(get_string('standardview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'letter')));
    2980      $navigation->add(get_string('categoryview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'cat')));
    2981      $navigation->add(get_string('dateview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'date')));
    2982      $navigation->add(get_string('authorview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'author')));
    2983  }
    2984  
    2985  /**
    2986   * Adds module specific settings to the settings block
    2987   *
    2988   * @param settings_navigation $settings The settings navigation object
    2989   * @param navigation_node $glossarynode The node to add module settings to
    2990   */
    2991  function glossary_extend_settings_navigation(settings_navigation $settings, navigation_node $glossarynode) {
    2992      global $PAGE, $DB, $CFG, $USER;
    2993  
    2994      $mode = optional_param('mode', '', PARAM_ALPHA);
    2995      $hook = optional_param('hook', 'ALL', PARAM_CLEAN);
    2996  
    2997      if (has_capability('mod/glossary:import', $PAGE->cm->context)) {
    2998          $glossarynode->add(get_string('importentries', 'glossary'), new moodle_url('/mod/glossary/import.php', array('id'=>$PAGE->cm->id)));
    2999      }
    3000  
    3001      if (has_capability('mod/glossary:export', $PAGE->cm->context)) {
    3002          $glossarynode->add(get_string('exportentries', 'glossary'), new moodle_url('/mod/glossary/export.php', array('id'=>$PAGE->cm->id, 'mode'=>$mode, 'hook'=>$hook)));
    3003      }
    3004  
    3005      if (has_capability('mod/glossary:approve', $PAGE->cm->context) && ($hiddenentries = $DB->count_records('glossary_entries', array('glossaryid'=>$PAGE->cm->instance, 'approved'=>0)))) {
    3006          $glossarynode->add(get_string('waitingapproval', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$PAGE->cm->id, 'mode'=>'approval')));
    3007      }
    3008  
    3009      if (has_capability('mod/glossary:write', $PAGE->cm->context)) {
    3010          $glossarynode->add(get_string('addentry', 'glossary'), new moodle_url('/mod/glossary/edit.php', array('cmid'=>$PAGE->cm->id)));
    3011      }
    3012  
    3013      $glossary = $DB->get_record('glossary', array("id" => $PAGE->cm->instance));
    3014  
    3015      if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds) && $glossary->rsstype && $glossary->rssarticles && has_capability('mod/glossary:view', $PAGE->cm->context)) {
    3016          require_once("$CFG->libdir/rsslib.php");
    3017  
    3018          $string = get_string('rsstype','forum');
    3019  
    3020          $url = new moodle_url(rss_get_url($PAGE->cm->context->id, $USER->id, 'mod_glossary', $glossary->id));
    3021          $glossarynode->add($string, $url, settings_navigation::TYPE_SETTING, null, null, new pix_icon('i/rss', ''));
    3022      }
    3023  }
    3024  
    3025  /**
    3026   * Running addtional permission check on plugin, for example, plugins
    3027   * may have switch to turn on/off comments option, this callback will
    3028   * affect UI display, not like pluginname_comment_validate only throw
    3029   * exceptions.
    3030   * Capability check has been done in comment->check_permissions(), we
    3031   * don't need to do it again here.
    3032   *
    3033   * @package  mod_glossary
    3034   * @category comment
    3035   *
    3036   * @param stdClass $comment_param {
    3037   *              context  => context the context object
    3038   *              courseid => int course id
    3039   *              cm       => stdClass course module object
    3040   *              commentarea => string comment area
    3041   *              itemid      => int itemid
    3042   * }
    3043   * @return array
    3044   */
    3045  function glossary_comment_permissions($comment_param) {
    3046      return array('post'=>true, 'view'=>true);
    3047  }
    3048  
    3049  /**
    3050   * Validate comment parameter before perform other comments actions
    3051   *
    3052   * @package  mod_glossary
    3053   * @category comment
    3054   *
    3055   * @param stdClass $comment_param {
    3056   *              context  => context the context object
    3057   *              courseid => int course id
    3058   *              cm       => stdClass course module object
    3059   *              commentarea => string comment area
    3060   *              itemid      => int itemid
    3061   * }
    3062   * @return boolean
    3063   */
    3064  function glossary_comment_validate($comment_param) {
    3065      global $DB;
    3066      // validate comment area
    3067      if ($comment_param->commentarea != 'glossary_entry') {
    3068          throw new comment_exception('invalidcommentarea');
    3069      }
    3070      if (!$record = $DB->get_record('glossary_entries', array('id'=>$comment_param->itemid))) {
    3071          throw new comment_exception('invalidcommentitemid');
    3072      }
    3073      if ($record->sourceglossaryid && $record->sourceglossaryid == $comment_param->cm->instance) {
    3074          $glossary = $DB->get_record('glossary', array('id'=>$record->sourceglossaryid));
    3075      } else {
    3076          $glossary = $DB->get_record('glossary', array('id'=>$record->glossaryid));
    3077      }
    3078      if (!$glossary) {
    3079          throw new comment_exception('invalidid', 'data');
    3080      }
    3081      if (!$course = $DB->get_record('course', array('id'=>$glossary->course))) {
    3082          throw new comment_exception('coursemisconf');
    3083      }
    3084      if (!$cm = get_coursemodule_from_instance('glossary', $glossary->id, $course->id)) {
    3085          throw new comment_exception('invalidcoursemodule');
    3086      }
    3087      $context = context_module::instance($cm->id);
    3088  
    3089      if ($glossary->defaultapproval and !$record->approved and !has_capability('mod/glossary:approve', $context)) {
    3090          throw new comment_exception('notapproved', 'glossary');
    3091      }
    3092      // validate context id
    3093      if ($context->id != $comment_param->context->id) {
    3094          throw new comment_exception('invalidcontext');
    3095      }
    3096      // validation for comment deletion
    3097      if (!empty($comment_param->commentid)) {
    3098          if ($comment = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
    3099              if ($comment->commentarea != 'glossary_entry') {
    3100                  throw new comment_exception('invalidcommentarea');
    3101              }
    3102              if ($comment->contextid != $comment_param->context->id) {
    3103                  throw new comment_exception('invalidcontext');
    3104              }
    3105              if ($comment->itemid != $comment_param->itemid) {
    3106                  throw new comment_exception('invalidcommentitemid');
    3107              }
    3108          } else {
    3109              throw new comment_exception('invalidcommentid');
    3110          }
    3111      }
    3112      return true;
    3113  }
    3114  
    3115  /**
    3116   * Return a list of page types
    3117   * @param string $pagetype current page type
    3118   * @param stdClass $parentcontext Block's parent context
    3119   * @param stdClass $currentcontext Current context of block
    3120   */
    3121  function glossary_page_type_list($pagetype, $parentcontext, $currentcontext) {
    3122      $module_pagetype = array(
    3123          'mod-glossary-*'=>get_string('page-mod-glossary-x', 'glossary'),
    3124          'mod-glossary-view'=>get_string('page-mod-glossary-view', 'glossary'),
    3125          'mod-glossary-edit'=>get_string('page-mod-glossary-edit', 'glossary'));
    3126      return $module_pagetype;
    3127  }
    

    Search This Site: