Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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
     * Returns html for help button.
280
     *
281
     * @return string html for help button
282
     */
283
    function getHelpButton() {
284
        return $this->_helpbutton;
285
    }
286
 
287
    /**
288
     * Returns type of editor element
289
     *
290
     * @return string
291
     */
292
    function getElementTemplateType() {
293
        if ($this->_flagFrozen){
294
            return 'nodisplay';
295
        } else {
296
            return 'default';
297
        }
298
    }
299
 
300
    /**
301
     * Returns HTML for editor form element.
302
     *
303
     * @return string
304
     */
305
    function toHtml() {
306
        global $CFG, $PAGE, $OUTPUT;
307
        require_once($CFG->dirroot.'/repository/lib.php');
308
 
309
        if ($this->_flagFrozen) {
310
            return $this->getFrozenHtml();
311
        }
312
 
313
        $ctx = $this->_options['context'];
314
 
315
        $id           = $this->_attributes['id'];
316
        $elname       = $this->_attributes['name'];
317
 
318
        $subdirs      = $this->_options['subdirs'];
319
        $maxbytes     = $this->_options['maxbytes'];
320
        $areamaxbytes = $this->_options['areamaxbytes'];
321
        $maxfiles     = $this->_options['maxfiles'];
322
        $changeformat = $this->_options['changeformat']; // TO DO: implement as ajax calls
323
 
324
        $text         = $this->_values['text'];
325
        $format       = $this->_values['format'];
326
        $draftitemid  = $this->_values['itemid'];
327
 
328
        // security - never ever allow guest/not logged in user to upload anything
329
        if (isguestuser() or !isloggedin()) {
330
            $maxfiles = 0;
331
        }
332
 
333
        $str = $this->_getTabs();
334
        $str .= '<div>';
335
 
336
        $editor = editors_get_preferred_editor($format);
337
        $strformats = format_text_menu();
338
        $formats =  $editor->get_supported_formats();
339
        foreach ($formats as $fid) {
340
            $formats[$fid] = $strformats[$fid];
341
        }
342
 
343
        // get filepicker info
344
        //
345
        $fpoptions = array();
346
        if ($maxfiles != 0 ) {
347
            if (empty($draftitemid)) {
348
                // no existing area info provided - let's use fresh new draft area
349
                require_once("$CFG->libdir/filelib.php");
350
                $this->setValue(array('itemid'=>file_get_unused_draft_itemid()));
351
                $draftitemid = $this->_values['itemid'];
352
            }
353
 
354
            $args = new stdClass();
355
            // need these three to filter repositories list
356
            $args->accepted_types = array('web_image');
357
            $args->return_types = $this->_options['return_types'];
358
            $args->context = $ctx;
359
            $args->env = 'filepicker';
360
            // advimage plugin
361
            $image_options = initialise_filepicker($args);
362
            $image_options->context = $ctx;
363
            $image_options->client_id = uniqid();
364
            $image_options->maxbytes = $this->_options['maxbytes'];
365
            $image_options->areamaxbytes = $this->_options['areamaxbytes'];
366
            $image_options->env = 'editor';
367
            $image_options->itemid = $draftitemid;
368
 
369
            // moodlemedia plugin
370
            $args->accepted_types = array('video', 'audio');
371
            $media_options = initialise_filepicker($args);
372
            $media_options->context = $ctx;
373
            $media_options->client_id = uniqid();
374
            $media_options->maxbytes  = $this->_options['maxbytes'];
375
            $media_options->areamaxbytes  = $this->_options['areamaxbytes'];
376
            $media_options->env = 'editor';
377
            $media_options->itemid = $draftitemid;
378
 
379
            // advlink plugin
380
            $args->accepted_types = '*';
381
            $link_options = initialise_filepicker($args);
382
            $link_options->context = $ctx;
383
            $link_options->client_id = uniqid();
384
            $link_options->maxbytes  = $this->_options['maxbytes'];
385
            $link_options->areamaxbytes  = $this->_options['areamaxbytes'];
386
            $link_options->env = 'editor';
387
            $link_options->itemid = $draftitemid;
388
 
389
            $args->accepted_types = array('.vtt');
390
            $subtitle_options = initialise_filepicker($args);
391
            $subtitle_options->context = $ctx;
392
            $subtitle_options->client_id = uniqid();
393
            $subtitle_options->maxbytes  = $this->_options['maxbytes'];
394
            $subtitle_options->areamaxbytes  = $this->_options['areamaxbytes'];
395
            $subtitle_options->env = 'editor';
396
            $subtitle_options->itemid = $draftitemid;
397
 
398
            if (has_capability('moodle/h5p:deploy', $ctx)) {
399
                // Only set H5P Plugin settings if the user can deploy new H5P content.
400
                // H5P plugin.
401
                $args->accepted_types = array('.h5p');
402
                $h5poptions = initialise_filepicker($args);
403
                $h5poptions->context = $ctx;
404
                $h5poptions->client_id = uniqid();
405
                $h5poptions->maxbytes  = $this->_options['maxbytes'];
406
                $h5poptions->areamaxbytes  = $this->_options['areamaxbytes'];
407
                $h5poptions->env = 'editor';
408
                $h5poptions->itemid = $draftitemid;
409
                $fpoptions['h5p'] = $h5poptions;
410
            }
411
 
412
            $fpoptions['image'] = $image_options;
413
            $fpoptions['media'] = $media_options;
414
            $fpoptions['link'] = $link_options;
415
            $fpoptions['subtitle'] = $subtitle_options;
416
        }
417
 
418
        // TODO Remove this in MDL-77334 for Moodle 4.6.
419
        // If editor is required and tinymce, then set required_tinymce option to initalize tinymce validation.
420
        if (($editor instanceof tinymce_texteditor)  && !is_null($this->getAttribute('onchange'))) {
421
            $this->_options['required'] = true;
422
        }
423
 
424
        // print text area - TODO: add on-the-fly switching, size configuration, etc.
425
        $editor->set_text($text);
426
        $editor->use_editor($id, $this->_options, $fpoptions);
427
 
428
        $rows = empty($this->_attributes['rows']) ? 15 : $this->_attributes['rows'];
429
        $cols = empty($this->_attributes['cols']) ? 80 : $this->_attributes['cols'];
430
 
431
        //Apply editor validation if required field
432
        $context = [];
433
        $context['rows'] = $rows;
434
        $context['cols'] = $cols;
435
        $context['frozen'] = $this->_flagFrozen;
436
        foreach ($this->getAttributes() as $name => $value) {
437
            $context[$name] = $value;
438
        }
439
        $context['hasformats'] = count($formats) > 1;
440
        $context['formats'] = [];
441
        if (($format === '' || $format === null) && count($formats)) {
442
            $format = key($formats);
443
        }
444
        foreach ($formats as $formatvalue => $formattext) {
445
            $context['formats'][] = ['value' => $formatvalue, 'text' => $formattext, 'selected' => ($formatvalue == $format)];
446
        }
447
        $context['id'] = $id;
448
        $context['value'] = $text;
449
        $context['format'] = $format;
450
        $context['formatlabel'] = get_string('editorxformat', 'editor', $this->_label);
451
 
452
        if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
453
            $context['changelistener'] = true;
454
        }
455
 
456
        $str .= $OUTPUT->render_from_template('core_form/editor_textarea', $context);
457
 
458
        // during moodle installation, user area doesn't exist
459
        // so we need to disable filepicker here.
460
        if (!during_initial_install() && empty($CFG->adminsetuppending)) {
461
            // 0 means no files, -1 unlimited
462
            if ($maxfiles != 0 ) {
463
                $str .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $elname.'[itemid]',
464
                        'value' => $draftitemid));
465
 
466
                // used by non js editor only
467
                $editorurl = new moodle_url("$CFG->wwwroot/repository/draftfiles_manager.php", array(
468
                    'action'=>'browse',
469
                    'env'=>'editor',
470
                    'itemid'=>$draftitemid,
471
                    'subdirs'=>$subdirs,
472
                    'maxbytes'=>$maxbytes,
473
                    'areamaxbytes' => $areamaxbytes,
474
                    'maxfiles'=>$maxfiles,
475
                    'ctx_id'=>$ctx->id,
476
                    'course'=>$PAGE->course->id,
477
                    'sesskey'=>sesskey(),
478
                    ));
479
                $str .= '<noscript>';
480
                $str .= "<div><object type='text/html' data='$editorurl' height='160' width='600' style='border:1px solid #000'></object></div>";
481
                $str .= '</noscript>';
482
            }
483
        }
484
 
485
 
486
        $str .= '</div>';
487
 
488
        return $str;
489
    }
490
 
491
    public function export_for_template(renderer_base $output) {
492
        $context = $this->export_for_template_base($output);
493
        $context['html'] = $this->toHtml();
494
        return $context;
495
    }
496
 
497
    /**
498
     * Returns the formatted value. The return from parent class is not acceptable.
499
     *
500
     * @return string
501
     */
502
    public function getFrozenHtml(): string {
503
        return format_text($this->get_text(), $this->getFormat()) . $this->_getPersistantData();
504
    }
505
 
506
    /**
507
     * Sets label to be hidden.
508
     *
509
     * @param bool $hiddenLabel Whether the label should be hidden or not.
510
     * @return void
511
     */
512
    function setHiddenLabel($hiddenLabel) {
513
        $this->_hiddenLabel = $hiddenLabel;
514
    }
515
}