Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * This filter provides automatic linking to
19
 * glossary entries, aliases and categories when
20
 * found inside every Moodle text.
21
 *
22
 * @package    filter
23
 * @subpackage glossary
24
 * @copyright  2004 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
25
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
27
 
28
defined('MOODLE_INTERNAL') || die();
29
 
30
/**
31
 * Glossary linking filter class.
32
 *
33
 * NOTE: multilang glossary entries are not compatible with this filter.
34
 */
35
class filter_glossary extends moodle_text_filter {
36
    /** @var null|cache_store cache used to store the terms for this course. */
37
    protected $cache = null;
38
 
39
    public function setup($page, $context) {
40
        if ($page->requires->should_create_one_time_item_now('filter_glossary_autolinker')) {
41
            $page->requires->js_call_amd('filter_glossary/autolinker', 'init', []);
42
        }
43
    }
44
 
45
    /**
46
     * Get all the concepts for this context.
47
     * @return filterobject[] the concepts, and filterobjects.
48
     */
49
    protected function get_all_concepts() {
50
        global $USER;
51
 
52
        if ($this->cache === null) {
53
            $this->cache = cache::make_from_params(cache_store::MODE_REQUEST, 'filter', 'glossary');
54
        }
55
 
56
        // Try to get current course.
57
        $coursectx = $this->context->get_course_context(false);
58
        if (!$coursectx) {
59
            // Only global glossaries will be linked.
60
            $courseid = 0;
61
        } else {
62
            $courseid = $coursectx->instanceid;
63
        }
64
 
65
        $cached = $this->cache->get('concepts');
66
        if ($cached !== false && ($cached->cachecourseid != $courseid || $cached->cacheuserid != $USER->id)) {
67
            // Invalidate the page cache.
68
            $cached = false;
69
        }
70
 
71
        if ($cached !== false && is_array($cached->cacheconceptlist)) {
72
            return $cached->cacheconceptlist;
73
        }
74
 
75
        list($glossaries, $allconcepts) = \mod_glossary\local\concept_cache::get_concepts($courseid);
76
 
77
        if (!$allconcepts) {
78
            $tocache = new stdClass();
79
            $tocache->cacheuserid = $USER->id;
80
            $tocache->cachecourseid = $courseid;
81
            $tocache->cacheconceptlist = [];
82
            $this->cache->set('concepts', $tocache);
83
            return [];
84
        }
85
 
86
        $conceptlist = array();
87
 
88
        foreach ($allconcepts as $concepts) {
89
            foreach ($concepts as $concept) {
90
                $conceptlist[] = new filterobject($concept->concept, null, null,
91
                        $concept->casesensitive, $concept->fullmatch, null,
92
                        [$this, 'filterobject_prepare_replacement_callback'], [$concept, $glossaries]);
93
            }
94
        }
95
 
96
        // We sort longest first, so that when we replace the terms,
97
        // the longest ones are replaced first. This does the right thing
98
        // when you have two terms like 'Moodle' and 'Moodle 3.5'. You want the longest match.
99
        usort($conceptlist, [$this, 'sort_entries_by_length']);
100
 
101
        $conceptlist = filter_prepare_phrases_for_filtering($conceptlist);
102
 
103
        $tocache = new stdClass();
104
        $tocache->cacheuserid = $USER->id;
105
        $tocache->cachecourseid = $courseid;
106
        $tocache->cacheconceptlist = $conceptlist;
107
        $this->cache->set('concepts', $tocache);
108
 
109
        return $conceptlist;
110
    }
111
 
112
    /**
113
     * Callback used by filterobject / filter_phrases.
114
     *
115
     * @param object $concept the concept that is being replaced (from get_all_concepts).
116
     * @param array $glossaries the list of glossary titles (from get_all_concepts).
117
     * @return array [$hreftagbegin, $hreftagend, $replacementphrase] for filterobject.
118
     */
119
    public function filterobject_prepare_replacement_callback($concept, $glossaries) {
120
        global $CFG;
121
 
122
        if ($concept->category) { // Link to a category.
123
            $title = get_string('glossarycategory', 'filter_glossary',
124
                    ['glossary' => $glossaries[$concept->glossaryid], 'category' => $concept->concept]);
125
            $link = new moodle_url('/mod/glossary/view.php',
126
                    ['g' => $concept->glossaryid, 'mode' => 'cat', 'hook' => $concept->id]);
127
            $attributes = array(
128
                    'href'  => $link,
129
                    'title' => $title,
130
                    'class' => 'glossary autolink category glossaryid' . $concept->glossaryid);
131
 
132
        } else { // Link to entry or alias.
133
            $title = get_string('glossaryconcept', 'filter_glossary',
134
                    ['glossary' => $glossaries[$concept->glossaryid], 'concept' => $concept->concept]);
135
            // Hardcoding dictionary format in the URL rather than defaulting
136
            // to the current glossary format which may not work in a popup.
137
            // for example "entry list" means the popup would only contain
138
            // a link that opens another popup.
139
            $link = new moodle_url('/mod/glossary/showentry.php',
140
                    ['eid' => $concept->id, 'displayformat' => 'dictionary']);
141
            $attributes = array(
142
                    'href'  => $link,
143
                    'title' => str_replace('&amp;', '&', $title), // Undo the s() mangling.
144
                    'class' => 'glossary autolink concept glossaryid' . $concept->glossaryid,
145
                    'data-entryid' => $concept->id,
146
                );
147
        }
148
 
149
        // This flag is optionally set by resource_pluginfile()
150
        // if processing an embedded file use target to prevent getting nested Moodles.
151
        if (!empty($CFG->embeddedsoforcelinktarget)) {
152
            $attributes['target'] = '_top';
153
        }
154
 
155
        return [html_writer::start_tag('a', $attributes), '</a>', null];
156
    }
157
 
158
    public function filter($text, array $options = array()) {
159
        global $GLOSSARY_EXCLUDEENTRY;
160
 
161
        $conceptlist = $this->get_all_concepts();
162
 
163
        if (empty($conceptlist)) {
164
            return $text;
165
        }
166
 
167
        if (!empty($GLOSSARY_EXCLUDEENTRY)) {
168
            foreach ($conceptlist as $key => $filterobj) {
169
                // The original concept object was stored here in when $filterobj was constructed in
170
                // get_all_concepts(). Get it back out now so we can check to see if it is excluded.
171
                $concept = $filterobj->replacementcallbackdata[0];
172
                if (!$concept->category && $concept->id == $GLOSSARY_EXCLUDEENTRY) {
173
                    unset($conceptlist[$key]);
174
                }
175
            }
176
        }
177
 
178
        if (empty($conceptlist)) {
179
            return $text;
180
        }
181
 
182
        return filter_phrases($text, $conceptlist, null, null, false, true);
183
    }
184
 
185
    /**
186
     * usort helper used in get_all_concepts above.
187
     * @param filterobject $filterobject0 first item to compare.
188
     * @param filterobject $filterobject1 second item to compare.
189
     * @return int -1, 0 or 1.
190
     */
191
    private function sort_entries_by_length($filterobject0, $filterobject1) {
192
        return strlen($filterobject1->phrase) <=> strlen($filterobject0->phrase);
193
    }
194
}