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
/**
19
 * Editor input element
20
 *
21
 * Contains class to create preffered editor form element
22
 *
23
 * @package   core_form
24
 * @copyright 2009 Petr Skoda {@link http://skodak.org}
25
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
27
 
28
global $CFG;
29
 
30
require_once('HTML/QuickForm/element.php');
31
require_once($CFG->dirroot.'/lib/filelib.php');
32
require_once($CFG->dirroot.'/repository/lib.php');
33
require_once('templatable_form_element.php');
34
 
35
/**
36
 * Editor element
37
 *
38
 * It creates preffered editor (textbox/Tiny) form element for the format (Text/HTML) selected.
39
 *
40
 * @package   core_form
41
 * @category  form
42
 * @copyright 2009 Petr Skoda {@link http://skodak.org}
43
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44
 * @todo      MDL-29421 element Freezing
45
 * @todo      MDL-29426 ajax format conversion
46
 */
47
class MoodleQuickForm_editor extends HTML_QuickForm_element implements templatable {
48
    use templatable_form_element {
49
        export_for_template as export_for_template_base;
50
    }
51
 
52
    /** @var string html for help button, if empty then no help will icon will be dispalyed. */
53
    public $_helpbutton = '';
54
 
55
    /** @var string defines the type of editor */
56
    public $_type       = 'editor';
57
 
58
    /** @var array options provided to initalize filepicker */
59
    protected $_options = array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 0, 'changeformat' => 0,
60
            'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 'context' => null, 'noclean' => 0, 'trusttext' => 0,
61
            'return_types' => 15, 'enable_filemanagement' => true, 'removeorphaneddrafts' => false, 'autosave' => true);
62
    // 15 is $_options['return_types'] = FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE | FILE_CONTROLLED_LINK.
63
 
64
    /** @var array values for editor */
65
    protected $_values     = array('text'=>null, 'format'=>null, 'itemid'=>null);
66
 
67
    /** @var bool if true label will be hidden */
68
    protected $_hiddenLabel = false;
69
 
70
    /**
71
     * Constructor
72
     *
73
     * @param string $elementName (optional) name of the editor
74
     * @param string $elementLabel (optional) editor label
75
     * @param array $attributes (optional) Either a typical HTML attribute string
76
     *              or an associative array
77
     * @param array $options set of options to initalize filepicker
78
     */
79
    public function __construct($elementName=null, $elementLabel=null, $attributes=null, $options=null) {
80
        global $CFG, $PAGE;
81
 
82
        $options = (array)$options;
83
        foreach ($options as $name=>$value) {
84
            if (array_key_exists($name, $this->_options)) {
85
                $this->_options[$name] = $value;
86
            }
87
        }
88
        if (!empty($options['maxbytes'])) {
89
            $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $options['maxbytes']);
90
        }
91
        if (!$this->_options['context']) {
92
            // trying to set context to the current page context to make legacy files show in filepicker (e.g. forum post)
93
            if (!empty($PAGE->context->id)) {
94
                $this->_options['context'] = $PAGE->context;
95
            } else {
96
                $this->_options['context'] = context_system::instance();
97
            }
98
        }
99
        $this->_options['trusted'] = trusttext_trusted($this->_options['context']);
100
        parent::__construct($elementName, $elementLabel, $attributes);
101
 
102
        // Note: for some reason the code using this setting does not like bools.
103
        $this->_options['subdirs'] = (int)($this->_options['subdirs'] == 1);
104
 
105
        editors_head_setup();
106
    }
107
 
108
    /**
109
     * Old syntax of class constructor. Deprecated in PHP7.
110
     *
111
     * @deprecated since Moodle 3.1
112
     */
113
    public function MoodleQuickForm_editor($elementName=null, $elementLabel=null, $attributes=null, $options=null) {
114
        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
115
        self::__construct($elementName, $elementLabel, $attributes, $options);
116
    }
117
 
118
    /**
119
     * Called by HTML_QuickForm whenever form event is made on this element
120
     *
121
     * @param string $event Name of event
122
     * @param mixed $arg event arguments
123
     * @param object $caller calling object
124
     * @return bool
125
     */
126
    function onQuickFormEvent($event, $arg, &$caller)
127
    {
128
        switch ($event) {
129
            case 'createElement':
130
                $caller->setType($arg[0] . '[format]', PARAM_ALPHANUM);
131
                $caller->setType($arg[0] . '[itemid]', PARAM_INT);
132
                break;
133
        }
134
        return parent::onQuickFormEvent($event, $arg, $caller);
135
    }
136
 
137
    /**
138
     * Sets name of editor
139
     *
140
     * @param string $name name of the editor
141
     */
142
    function setName($name) {
143
        $this->updateAttributes(array('name'=>$name));
144
    }
145
 
146
    /**
147
     * Returns name of element
148
     *
149
     * @return string
150
     */
151
    function getName() {
152
        return $this->getAttribute('name');
153
    }
154
 
155
    /**
156
     * Updates editor values, if part of $_values
157
     *
158
     * @param array $values associative array of values to set
159
     */
160
    function setValue($values) {
161
        $values = (array)$values;
162
        foreach ($values as $name=>$value) {
163
            if (array_key_exists($name, $this->_values)) {
164
                $this->_values[$name] = $value;
165
            }
166
        }
167
    }
168
 
169
    /**
170
     * Returns editor values
171
     *
172
     * @return array
173
     */
174
    function getValue() {
175
        return $this->_values;
176
    }
177
 
178
    /**
179
     * Returns maximum file size which can be uploaded
180
     *
181
     * @return int
182
     */
183
    function getMaxbytes() {
184
        return $this->_options['maxbytes'];
185
    }
186
 
187
    /**
188
     * Sets maximum file size which can be uploaded
189
     *
190
     * @param int $maxbytes file size
191
     */
192
    function setMaxbytes($maxbytes) {
193
        global $CFG;
194
        $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $maxbytes);
195
    }
196
 
197
     /**
198
     * Returns the maximum size of the area.
199
     *
200
     * @return int
201
     */
202
    function getAreamaxbytes() {
203
        return $this->_options['areamaxbytes'];
204
    }
205
 
206
    /**
207
     * Sets the maximum size of the area.
208
     *
209
     * @param int $areamaxbytes size limit
210
     */
211
    function setAreamaxbytes($areamaxbytes) {
212
        $this->_options['areamaxbytes'] = $areamaxbytes;
213
    }
214
 
215
    /**
216
     * Returns maximum number of files which can be uploaded
217
     *
218
     * @return int
219
     */
220
    function getMaxfiles() {
221
        return $this->_options['maxfiles'];
222
    }
223
 
224
    /**
225
     * Sets maximum number of files which can be uploaded.
226
     *
227
     * @param int $num number of files
228
     */
229
    function setMaxfiles($num) {
230
        $this->_options['maxfiles'] = $num;
231
    }
232
 
233
    /**
234
     * Returns true if subdirectoy can be created, else false
235
     *
236
     * @return bool
237
     */
238
    function getSubdirs() {
239
        return $this->_options['subdirs'];
240
    }
241
 
242
    /**
243
     * Set option to create sub directory, while uploading  file
244
     *
245
     * @param bool $allow true if sub directory can be created.
246
     */
247
    function setSubdirs($allow) {
248
        $this->_options['subdirs'] = (int)($allow == 1);
249
    }
250
 
251
    /**
252
     * Returns editor text content
253
     *
254
     * @return string Text content
255
     */
256
    public function get_text(): string {
257
        return $this->_values['text'];
258
    }
259
 
260
    /**
261
     * Returns editor format
262
     *
263
     * @return int.
264
     */
265
    function getFormat() {
266
        return $this->_values['format'];
267
    }
268
 
269
    /**
270
     * Checks if editor used is a required field
271
     *
272
     * @return bool true if required field.
273
     */
274
    function isRequired() {
275
        return (isset($this->_options['required']) && $this->_options['required']);
276
    }
277
 
278
    /**
279
     * @deprecated since Moodle 2.0
280
     */
281
    function setHelpButton($_helpbuttonargs, $function='_helpbutton') {
282
        throw new coding_exception('setHelpButton() can not be used any more, please see MoodleQuickForm::addHelpButton().');
283
    }
284
 
285
    /**
286
     * Returns html for help button.
287
     *
288
     * @return string html for help button
289
     */
290
    function getHelpButton() {
291
        return $this->_helpbutton;
292
    }
293
 
294
    /**
295
     * Returns type of editor element
296
     *
297
     * @return string
298
     */
299
    function getElementTemplateType() {
300
        if ($this->_flagFrozen){
301
            return 'nodisplay';
302
        } else {
303
            return 'default';
304
        }
305
    }
306
 
307
    /**
308
     * Returns HTML for editor form element.
309
     *
310
     * @return string
311
     */
312
    function toHtml() {
313
        global $CFG, $PAGE, $OUTPUT;
314
        require_once($CFG->dirroot.'/repository/lib.php');
315
 
316
        if ($this->_flagFrozen) {
317
            return $this->getFrozenHtml();
318
        }
319
 
320
        $ctx = $this->_options['context'];
321
 
322
        $id           = $this->_attributes['id'];
323
        $elname       = $this->_attributes['name'];
324
 
325
        $subdirs      = $this->_options['subdirs'];
326
        $maxbytes     = $this->_options['maxbytes'];
327
        $areamaxbytes = $this->_options['areamaxbytes'];
328
        $maxfiles     = $this->_options['maxfiles'];
329
        $changeformat = $this->_options['changeformat']; // TO DO: implement as ajax calls
330
 
331
        $text         = $this->_values['text'];
332
        $format       = $this->_values['format'];
333
        $draftitemid  = $this->_values['itemid'];
334
 
335
        // security - never ever allow guest/not logged in user to upload anything
336
        if (isguestuser() or !isloggedin()) {
337
            $maxfiles = 0;
338
        }
339
 
340
        $str = $this->_getTabs();
341
        $str .= '<div>';
342
 
343
        $editor = editors_get_preferred_editor($format);
344
        $strformats = format_text_menu();
345
        $formats =  $editor->get_supported_formats();
346
        foreach ($formats as $fid) {
347
            $formats[$fid] = $strformats[$fid];
348
        }
349
 
350
        // get filepicker info
351
        //
352
        $fpoptions = array();
353
        if ($maxfiles != 0 ) {
354
            if (empty($draftitemid)) {
355
                // no existing area info provided - let's use fresh new draft area
356
                require_once("$CFG->libdir/filelib.php");
357
                $this->setValue(array('itemid'=>file_get_unused_draft_itemid()));
358
                $draftitemid = $this->_values['itemid'];
359
            }
360
 
361
            $args = new stdClass();
362
            // need these three to filter repositories list
363
            $args->accepted_types = array('web_image');
364
            $args->return_types = $this->_options['return_types'];
365
            $args->context = $ctx;
366
            $args->env = 'filepicker';
367
            // advimage plugin
368
            $image_options = initialise_filepicker($args);
369
            $image_options->context = $ctx;
370
            $image_options->client_id = uniqid();
371
            $image_options->maxbytes = $this->_options['maxbytes'];
372
            $image_options->areamaxbytes = $this->_options['areamaxbytes'];
373
            $image_options->env = 'editor';
374
            $image_options->itemid = $draftitemid;
375
 
376
            // moodlemedia plugin
377
            $args->accepted_types = array('video', 'audio');
378
            $media_options = initialise_filepicker($args);
379
            $media_options->context = $ctx;
380
            $media_options->client_id = uniqid();
381
            $media_options->maxbytes  = $this->_options['maxbytes'];
382
            $media_options->areamaxbytes  = $this->_options['areamaxbytes'];
383
            $media_options->env = 'editor';
384
            $media_options->itemid = $draftitemid;
385
 
386
            // advlink plugin
387
            $args->accepted_types = '*';
388
            $link_options = initialise_filepicker($args);
389
            $link_options->context = $ctx;
390
            $link_options->client_id = uniqid();
391
            $link_options->maxbytes  = $this->_options['maxbytes'];
392
            $link_options->areamaxbytes  = $this->_options['areamaxbytes'];
393
            $link_options->env = 'editor';
394
            $link_options->itemid = $draftitemid;
395
 
396
            $args->accepted_types = array('.vtt');
397
            $subtitle_options = initialise_filepicker($args);
398
            $subtitle_options->context = $ctx;
399
            $subtitle_options->client_id = uniqid();
400
            $subtitle_options->maxbytes  = $this->_options['maxbytes'];
401
            $subtitle_options->areamaxbytes  = $this->_options['areamaxbytes'];
402
            $subtitle_options->env = 'editor';
403
            $subtitle_options->itemid = $draftitemid;
404
 
405
            if (has_capability('moodle/h5p:deploy', $ctx)) {
406
                // Only set H5P Plugin settings if the user can deploy new H5P content.
407
                // H5P plugin.
408
                $args->accepted_types = array('.h5p');
409
                $h5poptions = initialise_filepicker($args);
410
                $h5poptions->context = $ctx;
411
                $h5poptions->client_id = uniqid();
412
                $h5poptions->maxbytes  = $this->_options['maxbytes'];
413
                $h5poptions->areamaxbytes  = $this->_options['areamaxbytes'];
414
                $h5poptions->env = 'editor';
415
                $h5poptions->itemid = $draftitemid;
416
                $fpoptions['h5p'] = $h5poptions;
417
            }
418
 
419
            $fpoptions['image'] = $image_options;
420
            $fpoptions['media'] = $media_options;
421
            $fpoptions['link'] = $link_options;
422
            $fpoptions['subtitle'] = $subtitle_options;
423
        }
424
 
425
        // TODO Remove this in MDL-77334 for Moodle 4.6.
426
        // If editor is required and tinymce, then set required_tinymce option to initalize tinymce validation.
427
        if (($editor instanceof tinymce_texteditor)  && !is_null($this->getAttribute('onchange'))) {
428
            $this->_options['required'] = true;
429
        }
430
 
431
        // print text area - TODO: add on-the-fly switching, size configuration, etc.
432
        $editor->set_text($text);
433
        $editor->use_editor($id, $this->_options, $fpoptions);
434
 
435
        $rows = empty($this->_attributes['rows']) ? 15 : $this->_attributes['rows'];
436
        $cols = empty($this->_attributes['cols']) ? 80 : $this->_attributes['cols'];
437
 
438
        //Apply editor validation if required field
439
        $context = [];
440
        $context['rows'] = $rows;
441
        $context['cols'] = $cols;
442
        $context['frozen'] = $this->_flagFrozen;
443
        foreach ($this->getAttributes() as $name => $value) {
444
            $context[$name] = $value;
445
        }
446
        $context['hasformats'] = count($formats) > 1;
447
        $context['formats'] = [];
448
        if (($format === '' || $format === null) && count($formats)) {
449
            $format = key($formats);
450
        }
451
        foreach ($formats as $formatvalue => $formattext) {
452
            $context['formats'][] = ['value' => $formatvalue, 'text' => $formattext, 'selected' => ($formatvalue == $format)];
453
        }
454
        $context['id'] = $id;
455
        $context['value'] = $text;
456
        $context['format'] = $format;
457
        $context['formatlabel'] = get_string('editorxformat', 'editor', $this->_label);
458
 
459
        if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
460
            $context['changelistener'] = true;
461
        }
462
 
463
        $str .= $OUTPUT->render_from_template('core_form/editor_textarea', $context);
464
 
465
        // during moodle installation, user area doesn't exist
466
        // so we need to disable filepicker here.
467
        if (!during_initial_install() && empty($CFG->adminsetuppending)) {
468
            // 0 means no files, -1 unlimited
469
            if ($maxfiles != 0 ) {
470
                $str .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $elname.'[itemid]',
471
                        'value' => $draftitemid));
472
 
473
                // used by non js editor only
474
                $editorurl = new moodle_url("$CFG->wwwroot/repository/draftfiles_manager.php", array(
475
                    'action'=>'browse',
476
                    'env'=>'editor',
477
                    'itemid'=>$draftitemid,
478
                    'subdirs'=>$subdirs,
479
                    'maxbytes'=>$maxbytes,
480
                    'areamaxbytes' => $areamaxbytes,
481
                    'maxfiles'=>$maxfiles,
482
                    'ctx_id'=>$ctx->id,
483
                    'course'=>$PAGE->course->id,
484
                    'sesskey'=>sesskey(),
485
                    ));
486
                $str .= '<noscript>';
487
                $str .= "<div><object type='text/html' data='$editorurl' height='160' width='600' style='border:1px solid #000'></object></div>";
488
                $str .= '</noscript>';
489
            }
490
        }
491
 
492
 
493
        $str .= '</div>';
494
 
495
        return $str;
496
    }
497
 
498
    public function export_for_template(renderer_base $output) {
499
        $context = $this->export_for_template_base($output);
500
        $context['html'] = $this->toHtml();
501
        return $context;
502
    }
503
 
504
    /**
505
     * Returns the formatted value. The return from parent class is not acceptable.
506
     *
507
     * @return string
508
     */
509
    public function getFrozenHtml(): string {
510
        return format_text($this->get_text(), $this->getFormat()) . $this->_getPersistantData();
511
    }
512
 
513
    /**
514
     * Sets label to be hidden.
515
     *
516
     * @param bool $hiddenLabel Whether the label should be hidden or not.
517
     * @return void
518
     */
519
    function setHiddenLabel($hiddenLabel) {
520
        $this->_hiddenLabel = $hiddenLabel;
521
    }
522
}