1<?php
2
3/// This page prints a particular instance of glossary
4require_once("../../config.php");
5require_once("lib.php");
6require_once($CFG->libdir . '/completionlib.php');
7require_once("$CFG->libdir/rsslib.php");
8
9$id = optional_param('id', 0, PARAM_INT);           // Course Module ID
10$g  = optional_param('g', 0, PARAM_INT);            // Glossary ID
11
12$tab  = optional_param('tab', GLOSSARY_NO_VIEW, PARAM_ALPHA);    // browsing entries by categories?
13$displayformat = optional_param('displayformat',-1, PARAM_INT);  // override of the glossary display format
14
15$mode       = optional_param('mode', '', PARAM_ALPHA);           // term entry cat date letter search author approval
16$hook       = optional_param('hook', '', PARAM_CLEAN);           // the term, entry, cat, etc... to look for based on mode
17$fullsearch = optional_param('fullsearch', 0,PARAM_INT);         // full search (concept and definition) when searching?
18$sortkey    = optional_param('sortkey', '', PARAM_ALPHA);// Sorted view: CREATION | UPDATE | FIRSTNAME | LASTNAME...
19$sortorder  = optional_param('sortorder', 'ASC', PARAM_ALPHA);   // it defines the order of the sorting (ASC or DESC)
20$offset     = optional_param('offset', 0,PARAM_INT);             // entries to bypass (for paging purposes)
21$page       = optional_param('page', 0,PARAM_INT);               // Page to show (for paging purposes)
22$show       = optional_param('show', '', PARAM_ALPHA);           // [ concept | alias ] => mode=term hook=$show
23
24if (!empty($id)) {
25    if (! $cm = get_coursemodule_from_id('glossary', $id)) {
26        print_error('invalidcoursemodule');
27    }
28    if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
29        print_error('coursemisconf');
30    }
31    if (! $glossary = $DB->get_record("glossary", array("id"=>$cm->instance))) {
32        print_error('invalidid', 'glossary');
33    }
34
35} else if (!empty($g)) {
36    if (! $glossary = $DB->get_record("glossary", array("id"=>$g))) {
37        print_error('invalidid', 'glossary');
38    }
39    if (! $course = $DB->get_record("course", array("id"=>$glossary->course))) {
40        print_error('invalidcourseid');
41    }
42    if (!$cm = get_coursemodule_from_instance("glossary", $glossary->id, $course->id)) {
43        print_error('invalidcoursemodule');
44    }
45    $id = $cm->id;
46} else {
47    print_error('invalidid', 'glossary');
48}
49
50require_course_login($course->id, true, $cm);
51$context = context_module::instance($cm->id);
52require_capability('mod/glossary:view', $context);
53
54// Prepare format_string/text options
55$fmtoptions = array(
56    'context' => $context);
57
58require_once($CFG->dirroot . '/comment/lib.php');
59comment::init();
60
61/// redirecting if adding a new entry
62if ($tab == GLOSSARY_ADDENTRY_VIEW ) {
63    redirect("edit.php?cmid=$cm->id&amp;mode=$mode");
64}
65
66/// setting the defaut number of entries per page if not set
67if ( !$entriesbypage = $glossary->entbypage ) {
68    $entriesbypage = $CFG->glossary_entbypage;
69}
70
71// If we have received a page, recalculate offset and page size.
72$pagelimit = $entriesbypage;
73if ($page > 0 && $offset == 0) {
74    $offset = $page * $entriesbypage;
75} else if ($page < 0) {
76    $offset = 0;
77    $pagelimit = 0;
78}
79
80/// setting the default values for the display mode of the current glossary
81/// only if the glossary is viewed by the first time
82if ( $dp = $DB->get_record('glossary_formats', array('name'=>$glossary->displayformat)) ) {
83/// Based on format->defaultmode, we build the defaulttab to be showed sometimes
84    $showtabs = glossary_get_visible_tabs($dp);
85    switch ($dp->defaultmode) {
86        case 'cat':
87            $defaulttab = GLOSSARY_CATEGORY_VIEW;
88
89            // Handle defaultmode if 'category' tab is disabled. Fallback to 'standard' tab.
90            if (!in_array(GLOSSARY_CATEGORY, $showtabs)) {
91                $defaulttab = GLOSSARY_STANDARD_VIEW;
92            }
93
94            break;
95        case 'date':
96            $defaulttab = GLOSSARY_DATE_VIEW;
97
98            // Handle defaultmode if 'date' tab is disabled. Fallback to 'standard' tab.
99            if (!in_array(GLOSSARY_DATE, $showtabs)) {
100                $defaulttab = GLOSSARY_STANDARD_VIEW;
101            }
102
103            break;
104        case 'author':
105            $defaulttab = GLOSSARY_AUTHOR_VIEW;
106
107            // Handle defaultmode if 'author' tab is disabled. Fallback to 'standard' tab.
108            if (!in_array(GLOSSARY_AUTHOR, $showtabs)) {
109                $defaulttab = GLOSSARY_STANDARD_VIEW;
110            }
111
112            break;
113        default:
114            $defaulttab = GLOSSARY_STANDARD_VIEW;
115    }
116/// Fetch the rest of variables
117    $printpivot = $dp->showgroup;
118    if ( $mode == '' and $hook == '' and $show == '') {
119        $mode      = $dp->defaultmode;
120        $hook      = $dp->defaulthook;
121        $sortkey   = $dp->sortkey;
122        $sortorder = $dp->sortorder;
123    }
124} else {
125    $defaulttab = GLOSSARY_STANDARD_VIEW;
126    $showtabs = array($defaulttab);
127    $printpivot = 1;
128    if ( $mode == '' and $hook == '' and $show == '') {
129        $mode = 'letter';
130        $hook = 'ALL';
131    }
132}
133
134if ( $displayformat == -1 ) {
135     $displayformat = $glossary->displayformat;
136}
137
138if ( $show ) {
139    $mode = 'term';
140    $hook = $show;
141    $show = '';
142}
143
144/// stablishing flag variables
145if ( $sortorder = strtolower($sortorder) ) {
146    if ($sortorder != 'asc' and $sortorder != 'desc') {
147        $sortorder = '';
148    }
149}
150if ( $sortkey = strtoupper($sortkey) ) {
151    if ($sortkey != 'CREATION' and
152        $sortkey != 'UPDATE' and
153        $sortkey != 'FIRSTNAME' and
154        $sortkey != 'LASTNAME'
155        ) {
156        $sortkey = '';
157    }
158}
159
160switch ( $mode = strtolower($mode) ) {
161case 'search': /// looking for terms containing certain word(s)
162    $tab = GLOSSARY_STANDARD_VIEW;
163
164    //Clean a bit the search string
165    $hook = trim(strip_tags($hook));
166
167break;
168
169case 'entry':  /// Looking for a certain entry id
170    $tab = GLOSSARY_STANDARD_VIEW;
171    if ( $dp = $DB->get_record("glossary_formats", array("name"=>$glossary->displayformat)) ) {
172        $displayformat = $dp->popupformatname;
173    }
174break;
175
176case 'cat':    /// Looking for a certain cat
177    $tab = GLOSSARY_CATEGORY_VIEW;
178
179    // Validation - we don't want to display 'category' tab if it is disabled.
180    if (!in_array(GLOSSARY_CATEGORY, $showtabs)) {
181        $tab = GLOSSARY_STANDARD_VIEW;
182    }
183
184    if ( $hook > 0 ) {
185        $category = $DB->get_record("glossary_categories", array("id"=>$hook));
186    }
187break;
188
189case 'approval':    /// Looking for entries waiting for approval
190    $tab = GLOSSARY_APPROVAL_VIEW;
191    // Override the display format with the approvaldisplayformat
192    if ($glossary->approvaldisplayformat !== 'default' && ($df = $DB->get_record("glossary_formats",
193            array("name" => $glossary->approvaldisplayformat)))) {
194        $displayformat = $df->popupformatname;
195    }
196    if ( !$hook and !$sortkey and !$sortorder) {
197        $hook = 'ALL';
198    }
199break;
200
201case 'term':   /// Looking for entries that include certain term in its concept, definition or aliases
202    $tab = GLOSSARY_STANDARD_VIEW;
203break;
204
205case 'date':
206    $tab = GLOSSARY_DATE_VIEW;
207
208    // Validation - we dont want to display 'date' tab if it is disabled.
209    if (!in_array(GLOSSARY_DATE, $showtabs)) {
210        $tab = GLOSSARY_STANDARD_VIEW;
211    }
212
213    if ( !$sortkey ) {
214        $sortkey = 'UPDATE';
215    }
216    if ( !$sortorder ) {
217        $sortorder = 'desc';
218    }
219break;
220
221case 'author':  /// Looking for entries, browsed by author
222    $tab = GLOSSARY_AUTHOR_VIEW;
223
224    // Validation - we dont want to display 'author' tab if it is disabled.
225    if (!in_array(GLOSSARY_AUTHOR, $showtabs)) {
226        $tab = GLOSSARY_STANDARD_VIEW;
227    }
228
229    if ( !$hook ) {
230        $hook = 'ALL';
231    }
232    if ( !$sortkey ) {
233        $sortkey = 'FIRSTNAME';
234    }
235    if ( !$sortorder ) {
236        $sortorder = 'asc';
237    }
238break;
239
240case 'letter':  /// Looking for entries that begin with a certain letter, ALL or SPECIAL characters
241default:
242    $tab = GLOSSARY_STANDARD_VIEW;
243    if ( !$hook ) {
244        $hook = 'ALL';
245    }
246break;
247}
248
249switch ( $tab ) {
250case GLOSSARY_IMPORT_VIEW:
251case GLOSSARY_EXPORT_VIEW:
252case GLOSSARY_APPROVAL_VIEW:
253    $showcommonelements = 0;
254break;
255
256default:
257    $showcommonelements = 1;
258break;
259}
260
261// Trigger module viewed event.
262glossary_view($glossary, $course, $cm, $context, $mode);
263
264/// Printing the heading
265$strglossaries = get_string("modulenameplural", "glossary");
266$strglossary = get_string("modulename", "glossary");
267$strallcategories = get_string("allcategories", "glossary");
268$straddentry = get_string("addentry", "glossary");
269$strnoentries = get_string("noentries", "glossary");
270$strsearchindefinition = get_string("searchindefinition", "glossary");
271$strsearch = get_string("search");
272$strwaitingapproval = get_string('waitingapproval', 'glossary');
273
274/// If we are in approval mode, prit special header
275$PAGE->set_title($glossary->name);
276$PAGE->set_heading($course->fullname);
277$url = new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id));
278if (isset($mode)) {
279    $url->param('mode', $mode);
280}
281$PAGE->set_url($url);
282$PAGE->force_settings_menu();
283
284if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds)
285    && $glossary->rsstype && $glossary->rssarticles) {
286
287    $rsstitle = format_string($course->shortname, true, array('context' => context_course::instance($course->id))) . ': '. format_string($glossary->name);
288    rss_add_http_header($context, 'mod_glossary', $glossary, $rsstitle);
289}
290
291if ($tab == GLOSSARY_APPROVAL_VIEW) {
292    require_capability('mod/glossary:approve', $context);
293    $PAGE->navbar->add($strwaitingapproval);
294    echo $OUTPUT->header();
295    echo $OUTPUT->heading($strwaitingapproval);
296} else { /// Print standard header
297    echo $OUTPUT->header();
298}
299echo $OUTPUT->heading(format_string($glossary->name), 2);
300
301/// All this depends if whe have $showcommonelements
302if ($showcommonelements) {
303/// To calculate available options
304    $availableoptions = '';
305
306/// Decide about to print the import link
307    /*if (has_capability('mod/glossary:import', $context)) {
308        $availableoptions = '<span class="helplink">' .
309                            '<a href="' . $CFG->wwwroot . '/mod/glossary/import.php?id=' . $cm->id . '"' .
310                            '  title="' . s(get_string('importentries', 'glossary')) . '">' .
311                            get_string('importentries', 'glossary') . '</a>' .
312                            '</span>';
313    }
314/// Decide about to print the export link
315    if (has_capability('mod/glossary:export', $context)) {
316        if ($availableoptions) {
317            $availableoptions .= '&nbsp;/&nbsp;';
318        }
319        $availableoptions .='<span class="helplink">' .
320                            '<a href="' . $CFG->wwwroot . '/mod/glossary/export.php?id=' . $cm->id .
321                            '&amp;mode='.$mode . '&amp;hook=' . urlencode($hook) . '"' .
322                            '  title="' . s(get_string('exportentries', 'glossary')) . '">' .
323                            get_string('exportentries', 'glossary') . '</a>' .
324                            '</span>';
325    }*/
326
327/// Decide about to print the approval link
328    if (has_capability('mod/glossary:approve', $context)) {
329    /// Check we have pending entries
330        if ($hiddenentries = $DB->count_records('glossary_entries', array('glossaryid'=>$glossary->id, 'approved'=>0))) {
331            if ($availableoptions) {
332                $availableoptions .= '<br />';
333            }
334            $availableoptions .='<span class="helplink">' .
335                                '<a href="' . $CFG->wwwroot . '/mod/glossary/view.php?id=' . $cm->id .
336                                '&amp;mode=approval' . '"' .
337                                '  title="' . s(get_string('waitingapproval', 'glossary')) . '">' .
338                                get_string('waitingapproval', 'glossary') . ' ('.$hiddenentries.')</a>' .
339                                '</span>';
340        }
341    }
342
343/// Start to print glossary controls
344//        print_box_start('glossarycontrol clearfix');
345    echo '<div class="glossarycontrol" style="text-align: right">';
346    echo $availableoptions;
347
348/// The print icon
349    if ( $showcommonelements and $mode != 'search') {
350        if (has_capability('mod/glossary:manageentries', $context) or $glossary->allowprintview) {
351            $params = array(
352                'id'        => $cm->id,
353                'mode'      => $mode,
354                'hook'      => $hook,
355                'sortkey'   => $sortkey,
356                'sortorder' => $sortorder,
357                'offset'    => $offset,
358                'pagelimit' => $pagelimit
359            );
360            $printurl = new moodle_url('/mod/glossary/print.php', $params);
361            $printtitle = get_string('printerfriendly', 'glossary');
362            $printattributes = array(
363                'class' => 'printicon',
364                'title' => $printtitle
365            );
366            echo html_writer::link($printurl, $printtitle, $printattributes);
367        }
368    }
369/// End glossary controls
370//        print_box_end(); /// glossarycontrol
371    echo '</div><br />';
372
373//        print_box('&nbsp;', 'clearer');
374}
375
376/// Info box
377if ($glossary->intro && $showcommonelements) {
378    echo $OUTPUT->box(format_module_intro('glossary', $glossary, $cm->id), 'generalbox', 'intro');
379}
380
381/// Search box
382if ($showcommonelements ) {
383    echo '<form method="post" class="form form-inline mb-1" action="' . $CFG->wwwroot . '/mod/glossary/view.php">';
384
385
386    if ($mode == 'search') {
387        echo '<input type="text" name="hook" size="20" value="'.s($hook).'" alt="'.$strsearch.'" class="form-control"/> ';
388    } else {
389        echo '<input type="text" name="hook" size="20" value="" alt="'.$strsearch.'" class="form-control"/> ';
390    }
391    echo '<input type="submit" value="'.$strsearch.'" name="searchbutton" class="btn btn-secondary mr-1"/> ';
392    if ($fullsearch || $mode != 'search') {
393        $fullsearchchecked = 'checked="checked"';
394    } else {
395        $fullsearchchecked = '';
396    }
397    echo '<span class="checkbox"><label for="fullsearch">';
398    echo ' <input type="checkbox" name="fullsearch" id="fullsearch" value="1" '.$fullsearchchecked.'/> ';
399    echo '<input type="hidden" name="mode" value="search" />';
400    echo '<input type="hidden" name="id" value="'.$cm->id.'" />';
401    echo $strsearchindefinition.'</label></span>';
402
403    echo '</form>';
404}
405
406/// Show the add entry button if allowed
407if (has_capability('mod/glossary:write', $context) && $showcommonelements ) {
408    echo '<div class="singlebutton glossaryaddentry">';
409    echo "<form class=\"form form-inline mb-1\" id=\"newentryform\" method=\"get\" action=\"$CFG->wwwroot/mod/glossary/edit.php\">";
410    echo '<div>';
411    echo "<input type=\"hidden\" name=\"cmid\" value=\"$cm->id\" />";
412    echo '<input type="submit" value="'.get_string('addentry', 'glossary').'" class="btn btn-secondary" />';
413    echo '</div>';
414    echo '</form>';
415    echo "</div>\n";
416}
417
418
419require("tabs.php");
420
421require("sql.php");
422
423/// printing the entries
424$entriesshown = 0;
425$currentpivot = '';
426$paging = NULL;
427
428if ($allentries) {
429
430    //Decide if we must show the ALL link in the pagebar
431    $specialtext = '';
432    if ($glossary->showall) {
433        $specialtext = get_string("allentries","glossary");
434    }
435
436    //Build paging bar
437    $baseurl = new moodle_url('/mod/glossary/view.php', ['id' => $id, 'mode' => $mode, 'hook' => $hook,
438        'sortkey' => $sortkey, 'sortorder' => $sortorder, 'fullsearch' => $fullsearch]);
439    $paging = glossary_get_paging_bar($count, $page, $entriesbypage, $baseurl->out() . '&amp;',
440        9999, 10, '&nbsp;&nbsp;', $specialtext, -1);
441
442    echo '<div class="paging">';
443    echo $paging;
444    echo '</div>';
445
446    //load ratings
447    require_once($CFG->dirroot.'/rating/lib.php');
448    if ($glossary->assessed != RATING_AGGREGATE_NONE) {
449        $ratingoptions = new stdClass;
450        $ratingoptions->context = $context;
451        $ratingoptions->component = 'mod_glossary';
452        $ratingoptions->ratingarea = 'entry';
453        $ratingoptions->items = $allentries;
454        $ratingoptions->aggregate = $glossary->assessed;//the aggregation method
455        $ratingoptions->scaleid = $glossary->scale;
456        $ratingoptions->userid = $USER->id;
457        $ratingoptions->returnurl = $CFG->wwwroot.'/mod/glossary/view.php?id='.$cm->id;
458        $ratingoptions->assesstimestart = $glossary->assesstimestart;
459        $ratingoptions->assesstimefinish = $glossary->assesstimefinish;
460
461        $rm = new rating_manager();
462        $allentries = $rm->get_ratings($ratingoptions);
463    }
464
465    foreach ($allentries as $entry) {
466
467        // Setting the pivot for the current entry
468        if ($printpivot) {
469            $pivot = $entry->{$pivotkey};
470            $upperpivot = core_text::strtoupper($pivot);
471            $pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
472
473            // Reduce pivot to 1cc if necessary.
474            if (!$fullpivot) {
475                $upperpivot = core_text::substr($upperpivot, 0, 1);
476                $pivottoshow = core_text::substr($pivottoshow, 0, 1);
477            }
478
479            // If there's a group break.
480            if ($currentpivot != $upperpivot) {
481                $currentpivot = $upperpivot;
482
483                // print the group break if apply
484
485                echo '<div>';
486                echo '<table cellspacing="0" class="glossarycategoryheader">';
487
488                echo '<tr>';
489                if ($userispivot) {
490                // printing the user icon if defined (only when browsing authors)
491                    echo '<th align="left">';
492                    $user = mod_glossary_entry_query_builder::get_user_from_record($entry);
493                    echo $OUTPUT->user_picture($user, array('courseid'=>$course->id));
494                    $pivottoshow = fullname($user, has_capability('moodle/site:viewfullnames', context_course::instance($course->id)));
495                } else {
496                    echo '<th >';
497                }
498
499                echo $OUTPUT->heading($pivottoshow, 3);
500                echo "</th></tr></table></div>\n";
501            }
502        }
503
504        /// highlight the term if necessary
505        if ($mode == 'search') {
506            //We have to strip any word starting by + and take out words starting by -
507            //to make highlight works properly
508            $searchterms = explode(' ', $hook);    // Search for words independently
509            foreach ($searchterms as $key => $searchterm) {
510                if (preg_match('/^\-/',$searchterm)) {
511                    unset($searchterms[$key]);
512                } else {
513                    $searchterms[$key] = preg_replace('/^\+/','',$searchterm);
514                }
515                //Avoid highlight of <2 len strings. It's a well known hilight limitation.
516                if (strlen($searchterm) < 2) {
517                    unset($searchterms[$key]);
518                }
519            }
520            $strippedsearch = implode(' ', $searchterms);    // Rebuild the string
521            $entry->highlight = $strippedsearch;
522        }
523
524        /// and finally print the entry.
525        glossary_print_entry($course, $cm, $glossary, $entry, $mode, $hook,1,$displayformat);
526        $entriesshown++;
527    }
528    // The all entries value may be a recordset or an array.
529    if ($allentries instanceof moodle_recordset) {
530        $allentries->close();
531    }
532}
533if ( !$entriesshown ) {
534    echo $OUTPUT->box(get_string("noentries","glossary"), "generalbox boxaligncenter boxwidthwide");
535}
536
537if (!empty($formsent)) {
538    // close the form properly if used
539    echo "</div>";
540    echo "</form>";
541}
542
543if ( $paging ) {
544    echo '<hr />';
545    echo '<div class="paging">';
546    echo $paging;
547    echo '</div>';
548}
549echo '<br />';
550glossary_print_tabbed_table_end();
551
552/// Finish the page
553echo $OUTPUT->footer();
554