Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 11... Línea 11...
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
12
// GNU General Public License for more details.
13
//
13
//
14
// You should have received a copy of the GNU General Public License
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/>.
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
/**
-
 
17
 * Display H5P filter
-
 
18
 *
-
 
19
 * @package    filter_displayh5p
-
 
20
 * @copyright  2019 Victor Deniz <victor@moodle.com>
-
 
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
-
 
22
 */
-
 
23
 
-
 
24
defined('MOODLE_INTERNAL') || die;
-
 
25
 
-
 
26
use core_h5p\local\library\autoloader;
-
 
Línea 27... Línea 16...
27
 
16
 
28
/**
17
/**
29
 * Display H5P filter
18
 * File only retained to prevent fatal errors in code that tries to require/include this.
30
 *
19
 *
31
 * This filter will replace any occurrence of H5P URLs with the corresponding H5P content embed code
-
 
-
 
20
 * @todo MDL-82708 delete this file as part of Moodle 6.0 development.
32
 *
21
 * @deprecated This file is no longer required in Moodle 4.5+.
33
 * @package    filter_displayh5p
22
 * @package filter_displayh5p
34
 * @copyright  2019 Victor Deniz <victor@moodle.com>
23
 * @copyright Victor Deniz <victor@moodle.com>
35
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
-
 
37
class filter_displayh5p extends moodle_text_filter {
-
 
38
 
-
 
39
    /**
-
 
40
     * @var boolean $loadresizerjs This is whether to request the resize.js script.
-
 
41
     */
-
 
42
    private static $loadresizerjs = true;
-
 
43
 
-
 
44
    /**
-
 
45
     * Function filter replaces any h5p-sources.
-
 
46
     *
-
 
47
     * @param  string $text    HTML content to process
-
 
48
     * @param  array  $options options passed to the filters
-
 
49
     * @return string
-
 
50
     */
-
 
51
    public function filter($text, array $options = array()) {
-
 
52
        global $CFG, $USER;
-
 
53
 
-
 
54
        if (!is_string($text) or empty($text)) {
-
 
55
            // Non string data can not be filtered anyway.
-
 
56
            return $text;
-
 
57
        }
-
 
58
 
-
 
59
        // We are trying to minimize performance impact checking there's some H5P related URL.
-
 
60
        $h5purl = '(http[^ &<]*h5p)';
-
 
61
        if (!preg_match($h5purl, $text)) {
-
 
62
            return $text;
-
 
63
        }
-
 
64
 
-
 
65
        $allowedsources = get_config('filter_displayh5p', 'allowedsources');
-
 
66
        $allowedsources = array_filter(array_map('trim', explode("\n", $allowedsources)));
-
 
67
 
-
 
68
        $localsource = '('.preg_quote($CFG->wwwroot, '~').'/[^ &\#"\'<]*\.h5p([?][^ "\'<]*)?[^ \#"\'<]*)';
-
 
69
        $allowedsources[] = $localsource;
-
 
70
 
-
 
71
        $params = array(
-
 
72
            'tagbegin' => '<iframe src="',
-
 
73
            'tagend' => '</iframe>'
-
 
74
        );
-
 
75
 
-
 
76
        $specialchars = ['?', '&'];
-
 
77
        $escapedspecialchars = ['\?', '&amp;'];
-
 
78
        $h5pcontents = array();
-
 
79
        $h5plinks = array();
-
 
80
 
-
 
81
        // Check all allowed sources.
-
 
82
        foreach ($allowedsources as $source) {
-
 
83
            // It is needed to add "/embed" at the end of URLs like https:://*.h5p.com/content/12345 (H5P.com).
-
 
84
            $params['urlmodifier'] = '';
-
 
85
 
-
 
86
            // Local files may display a button below the content to modify it when editing mode is on. This button will appear
-
 
87
            // only if the user has the proper capabilities.
-
 
88
            $params['canbeedited'] = (!empty($USER->editing)) && ($source == $localsource);
-
 
89
            if ($source == $localsource) {
-
 
90
                $params['tagbegin'] = '<iframe src="'.$CFG->wwwroot.'/h5p/embed.php?url=';
-
 
91
                $escapechars = $source;
-
 
92
                $ultimatepattern = $source;
-
 
93
            } else {
-
 
94
                if (!stripos($source, 'embed')) {
-
 
95
                    $params['urlmodifier'] = '/embed';
-
 
96
                }
-
 
97
                // Convert special chars.
-
 
98
                $sourceid = str_replace('[id]', '[0-9]+', $source);
-
 
99
                $escapechars = str_replace($specialchars, $escapedspecialchars, $sourceid);
-
 
100
                $ultimatepattern = '(' . $escapechars . ')';
-
 
101
            }
-
 
102
 
-
 
103
            // Improve performance creating filterobjects only when needed.
-
 
104
            if (!preg_match($ultimatepattern, $text)) {
-
 
105
                continue;
-
 
106
            }
-
 
107
 
-
 
108
            $h5pcontenturl = new filterobject($source, null, null, false,
-
 
109
                false, null, [$this, 'filterobject_prepare_replacement_callback'], $params + ['ish5plink' => false]);
-
 
110
 
-
 
111
            $h5pcontenturl->workregexp = '#'.$ultimatepattern.'#';
-
 
112
            $h5pcontents[] = $h5pcontenturl;
-
 
113
 
-
 
114
            // Regex to find h5p extensions in an <a> tag.
-
 
115
            $linkregexp = '~<a [^>]*href=["\']('.$escapechars.'[^"\']*)["\'][^>]*>([^<]*)</a>~is';
-
 
116
 
-
 
117
            $h5plinkurl = new filterobject($linkregexp, null, null, false,
-
 
118
                false, null, [$this, 'filterobject_prepare_replacement_callback'], $params + ['ish5plink' => true]);
-
 
119
            $h5plinkurl->workregexp = $linkregexp;
-
 
120
            $h5plinks[] = $h5plinkurl;
-
 
121
        }
-
 
122
 
-
 
123
        if (empty($h5pcontents) && empty($h5links)) {
-
 
124
            // No matches to deal with.
-
 
125
            return $text;
-
 
126
        }
-
 
127
 
-
 
128
        // Apply filter inside <a> tag href attribute.
-
 
129
        // We can not use filter_phrase function because it removes all tags and can not be applied in tag attributes.
-
 
130
        foreach ($h5plinks as $h5plink) {
-
 
131
            $text = preg_replace_callback($h5plink->workregexp,
-
 
132
                function ($matches) use ($h5plink) {
-
 
133
                    if ($matches[1] == $matches[2]) {
-
 
134
                        filter_prepare_phrase_for_replacement($h5plink);
-
 
135
 
-
 
136
                        return str_replace('$1', $matches[1], $h5plink->workreplacementphrase);
-
 
137
                    } else {
-
 
138
                        return $matches[0];
-
 
139
                    }
-
 
140
                }, $text);
-
 
141
        }
-
 
142
 
-
 
143
        // The "Edit" button below each H5P content will be displayed only for users with permissions to edit the content (to
-
 
144
        // avoid confusion). So the original H5P file behind this URL will be obtained and checked using the methods in the API.
-
 
145
        // As the H5P URL is required in order to get this information, this action can be done only here(the
-
 
146
        // prepare_replacement_callback method has only the placeholders).
-
 
147
        foreach ($h5pcontents as $h5pcontent) {
-
 
148
            $text = preg_replace_callback($h5pcontent->workregexp,
-
 
149
                function ($matches) use ($h5pcontent) {
-
 
150
                    global $USER, $CFG;
-
 
151
 
-
 
152
                    // The Edit button placeholder has been added only if the file can be edited.
-
 
153
                    if ($h5pcontent->replacementcallbackdata['canbeedited']) {
-
 
154
                        // If the content was originally a link, ignore it (it won't have the placeholder).
-
 
155
                        $matchurl = new \moodle_url($matches[0]);
-
 
156
                        if (strpos($matchurl->get_path(), 'h5p/embed.php') !== false) {
-
 
157
                            return $matches[0];
-
 
158
                        }
-
 
159
 
-
 
160
                        $contenturl = $matches[0];
-
 
161
                        list($file, $h5p) = \core_h5p\api::get_original_content_from_pluginfile_url($contenturl, true, true);
-
 
162
                        if ($file) {
-
 
163
                            filter_prepare_phrase_for_replacement($h5pcontent);
-
 
164
 
-
 
165
                            // Check if the user can edit this content.
-
 
166
                            if (\core_h5p\api::can_edit_content($file)) {
-
 
167
                                // If the user can modify the content, replace the placeholder with a link to the editor.
-
 
168
                                $title = get_string('editcontent', 'core_h5p');
-
 
169
                                $editorurl = $CFG->wwwroot . '/h5p/edit.php?url=' . $contenturl;
-
 
170
                                $htmlcode = html_writer::start_tag(
-
 
171
                                    'a',
-
 
172
                                    ['class' => 'autolink', 'title' => $title, 'href' => $editorurl]
25
 */
173
                                );
-
 
174
                                $htmlcode .= $title . html_writer::end_tag('a');
-
 
175
                                $content = str_replace('$2', $htmlcode, $h5pcontent->workreplacementphrase);
-
 
176
                            } else {
-
 
177
                                // If the user can't edit the content, remove the placeholder.
-
 
178
                                $content = str_replace('$2', '', $h5pcontent->workreplacementphrase);
-
 
179
                            }
-
 
180
 
-
 
181
                            return str_replace('$1', $contenturl, $content);
-
 
182
                        }
-
 
183
                    }
-
 
184
 
-
 
185
                    return $matches[0];
-
 
186
                }, $text);
-
 
187
        }
-
 
188
 
-
 
189
        $result = filter_phrases($text, $h5pcontents, null, null, false, true);
-
 
190
 
-
 
191
        // Encoding H5P file URLs.
-
 
192
        // embed.php page is requesting a PARAM_LOCALURL url parameter, so for files/directories use non-alphanumeric
-
 
193
        // characters, we need to encode the parameter. Fetch url parameter added to embed.php and encode the whole url.
-
 
194
        $localurl = '#\?url=([^" <]*[\/]+[^" <]*\.h5p)([?][^"]*)?#';
-
 
195
        $result = preg_replace_callback($localurl,
-
 
196
            function ($matches) {
-
 
197
                $baseurl = rawurlencode($matches[1]);
-
 
198
                // Deal with possible parameters in the url link.
-
 
199
                if (!empty($matches[2])) {
-
 
200
                    $match = explode('?', $matches[2]);
-
 
201
                    if (!empty($match[1])) {
-
 
202
                        $baseurl = $baseurl."&".$match[1];
-
 
203
                    }
-
 
204
                }
-
 
205
                return "?url=".$baseurl;
-
 
206
            }, $result);
-
 
207
 
-
 
208
        return $result;
-
 
209
    }
-
 
210
 
-
 
211
    /**
-
 
212
     * Callback used by filterobject / filter_phrases.
-
 
213
     *
-
 
214
     * @param string $tagbegin HTML to insert before any match
-
 
215
     * @param string $tagend HTML to insert after any match
-
 
216
     * @param string $urlmodifier string to add to the match URL
-
 
217
     * @param bool $canbeedited Whether the content can be modified or not (to display a link to edit it or not).
-
 
218
     * @param bool $ish5plink Whether the original content comes from an H5P link or not.
-
 
219
     * @return array [$hreftagbegin, $hreftagend, $replacementphrase] for filterobject.
-
 
220
     */
-
 
221
    public function filterobject_prepare_replacement_callback($tagbegin, $tagend, $urlmodifier, $canbeedited, $ish5plink) {
-
 
222
 
-
 
223
        $sourceurl = "$1";
-
 
224
        if ($urlmodifier !== "") {
-
 
225
            $sourceurl .= $urlmodifier;
-
 
226
        }
-
 
227
 
-
 
228
        $h5piframesrc = $sourceurl . '" class="h5p-iframe" name="h5pcontent"' .
-
 
229
            ' style="height:230px; width: 100%; border: 0;" allowfullscreen="allowfullscreen">';
-
 
230
 
-
 
231
        // We want to request the resizing script only once.
-
 
232
        if (self::$loadresizerjs) {
-
 
233
            $resizerurl = autoloader::get_h5p_core_library_url('js/h5p-resizer.js');
-
 
234
            $tagend .= '<script src="' . $resizerurl->out() . '"></script>';
-
 
235
            self::$loadresizerjs = false;
-
 
236
        }
-
 
237
 
-
 
238
        if ($canbeedited && !$ish5plink) {
-
 
239
            // Placeholder to be replaced by the edit content button (depending on the user permissions).
-
 
240
            $tagend .= "$2";
-
 
Línea 241... Línea 26...
241
        }
26
defined('MOODLE_INTERNAL') || die();
242
 
-
 
243
        return [$tagbegin, $tagend, $h5piframesrc];
-