Passed
Push — master ( 5790ec...e60243 )
by Julito
09:33
created

FormValidator::addMultiSelect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 4
dl 0
loc 3
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
/**
6
 * Class FormValidator
7
 * create/manipulate/validate user input.
8
 */
9
class FormValidator extends HTML_QuickForm
10
{
11
    public const LAYOUT_HORIZONTAL = 'horizontal';
12
    public const LAYOUT_INLINE = 'inline';
13
    public const LAYOUT_BOX = 'box';
14
    public const LAYOUT_BOX_NO_LABEL = 'box-no-label';
15
    public const LAYOUT_BOX_SEARCH = 'box-search';
16
    public const LAYOUT_GRID = 'grid';
17
18
    public $with_progress_bar = false;
19
    private $layout;
20
21
    /**
22
     * @param string      $name        Name of the form
23
     * @param string      $method      (optional) Method ('post' (default) or 'get')
24
     * @param string      $action      (optional) Action (default is $PHP_SELF)
25
     * @param string|null $target      (optional) Form's target defaults to '_self'
26
     * @param mixed       $attributes  (optional) Extra attributes for <form> tag
27
     * @param string      $layout
28
     * @param bool        $trackSubmit Whether to track if the form was submitted by adding a special hidden field
29
     */
30
    public function __construct(
31
        string $name,
32
        ?string $method = 'post',
33
        ?string $action = '',
34
        ?string $target = '',
35
        ?array $attributes = [],
36
        string $layout = self::LAYOUT_HORIZONTAL,
37
        bool $trackSubmit = true
38
    ) {
39
        if (null === $attributes) {
40
            $attributes = [];
41
        }
42
43
        // Default form class.
44
        if (!isset($attributes['class']) || empty($attributes)) {
45
            $attributes['class'] = 'form-horizontal q-pt-md';
46
        }
47
48
        if (isset($attributes['class']) && false !== strpos($attributes['class'], 'form-search')) {
49
            $layout = 'inline';
50
        }
51
52
        $this->setLayout($layout);
53
54
        // Form template
55
        $formTemplate = $this->getFormTemplate();
56
57
        switch ($layout) {
58
            case self::LAYOUT_HORIZONTAL:
59
                $attributes['class'] = 'ch w-full ';
60
                break;
61
            case self::LAYOUT_BOX_SEARCH:
62
                $attributes['class'] = 'ch w-full flex gap-2';
63
                $formTemplate = $this->getInLineTemplate();
64
                break;
65
            case self::LAYOUT_INLINE:
66
                $attributes['class'] = 'ch flex gap-2 ';
67
                $formTemplate = $this->getInLineTemplate();
68
                break;
69
            case self::LAYOUT_BOX:
70
                $attributes['class'] = 'ch flex gap-1 ';
71
                break;
72
            case self::LAYOUT_GRID:
73
                $attributes['class'] = 'ch form-grid';
74
                $formTemplate = $this->getGridFormTemplate();
75
                break;
76
        }
77
78
        parent::__construct($name, $method, $action, $target, $attributes, $trackSubmit);
79
80
        // Modify the default templates
81
        $renderer = &$this->defaultRenderer();
82
        $renderer->setFormTemplate($formTemplate);
83
84
        // Element template
85
        if ((isset($attributes['class']) && 'form-inline' === $attributes['class']) ||
86
            (self::LAYOUT_INLINE === $layout || self::LAYOUT_BOX_SEARCH === $layout)
87
        ) {
88
            $elementTemplate = ' {label}  {element} ';
89
            $renderer->setElementTemplate($elementTemplate);
90
        } elseif (isset($attributes['class']) && 'form-search' === $attributes['class']) {
91
            $elementTemplate = ' {label}  {element} ';
92
            $renderer->setElementTemplate($elementTemplate);
93
        } else {
94
            $renderer->setElementTemplate($this->getDefaultElementTemplate());
95
96
            // Display a gray div in the buttons
97
            $templateSimple = '<div class="form-actions">{label} {element}</div>';
98
            $renderer->setElementTemplate($templateSimple, 'submit_in_actions');
99
100
            //Display a gray div in the buttons + makes the button available when scrolling
101
            $templateBottom = '<div class="form-actions bottom_actions bg-form">{label} {element}</div>';
102
            $renderer->setElementTemplate($templateBottom, 'submit_fixed_in_bottom');
103
            $renderer->setElementTemplate($templateSimple, 'buttons_in_action');
104
105
            $templateSimpleRight = '<div class="form-actions"> <div class="pull-right">{label} {element}</div></div>';
106
            $renderer->setElementTemplate($templateSimpleRight, 'buttons_in_action_right');
107
        }
108
109
        //Set Header template
110
        $renderer->setHeaderTemplate(' <h1 class="text-2xl font-small text-gray-800 mb-4">{header}<hr /></h1>');
111
112
        $required = '<span class="form_required">*</span> <small>'.get_lang('Required field').'</small>';
113
        if ((self::LAYOUT_INLINE === $layout || self::LAYOUT_BOX_SEARCH === $layout)) {
114
            $required = '';
115
        }
116
        // Set required field template
117
        $this->setRequiredNote($required);
118
119
        $noteTemplate = <<<EOT
120
	<div class="form-group">
121
		<div class="col-sm-offset-2 col-sm-10">{requiredNote}</div>
122
	</div>
123
EOT;
124
        $renderer->setRequiredNoteTemplate($noteTemplate);
125
    }
126
127
    public function getFormTemplate(): string
128
    {
129
        return '
130
                <div class="pt-4">
131
                    <div class="q-card p-4">
132
                        <form{attributes}>
133
                            {content}
134
                            {hidden}
135
                        </form>
136
                    </div>
137
                </div>
138
        ';
139
    }
140
141
    public function getInLineTemplate(): string
142
    {
143
        return '<form{attributes}>
144
            {content}
145
            {hidden}
146
        </form>';
147
    }
148
149
    public function getGridFormTemplate(): string
150
    {
151
        return '
152
        <style>
153
            .form_list {
154
                display: grid;
155
                grid-template-columns:  repeat(auto-fill, minmax(300px, 1fr));;
156
                grid-gap: 10px 30px;
157
                gap: 10px 30px;
158
            }
159
            .form_list .input-group {
160
                display:block;
161
            }
162
        </style>
163
        <form{attributes}>
164
            <div class="form_list">
165
                {content}
166
            </div>
167
        {hidden}
168
        </form>';
169
    }
170
171
    /**
172
     * @todo this function should be added in the element class
173
     */
174
    public function getDefaultElementTemplate(): string
175
    {
176
        return '
177
            <div class="row mb-3 {error_class}">
178
                <label {label-for} class="col-sm-2 col-form-label {extra_label_class}" >
179
                    <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
180
                    {label}
181
                </label>
182
                <div class="col-sm-8">
183
                    {icon}
184
                    {element}
185
                    <!-- BEGIN label_2 -->
186
                        <p class="help-block">{label_2}</p>
187
                    <!-- END label_2 -->
188
189
                    <!-- BEGIN error -->
190
                        <span class="help-inline help-block">{error}</span>
191
                    <!-- END error -->
192
                </div>
193
                <div class="col-sm-2">
194
                    <!-- BEGIN label_3 -->
195
                        {label_3}
196
                    <!-- END label_3 -->
197
                </div>
198
            </div>';
199
    }
200
201
    /**
202
     * @return string
203
     */
204
    public function getLayout()
205
    {
206
        return $this->layout;
207
    }
208
209
    /**
210
     * @param string $layout
211
     */
212
    public function setLayout($layout)
213
    {
214
        $this->layout = $layout;
215
    }
216
217
    /**
218
     * Adds a text field to the form.
219
     * A trim-filter is attached to the field.
220
     *
221
     * @param string|array $label      The label for the form-element
222
     * @param string       $name       The element name
223
     * @param bool         $required   (optional)    Is the form-element required (default=true)
224
     * @param array        $attributes (optional)    List of attributes for the form-element
225
     *
226
     * @return HTML_QuickForm_text
227
     */
228
    public function addText($name, $label, $required = true, $attributes = [], $createElement = false)
229
    {
230
        if ($createElement) {
231
            $element = $this->createElement('text', $name, $label, $attributes);
232
        } else {
233
            $element = $this->addElement('text', $name, $label, $attributes);
234
        }
235
236
        $this->applyFilter($name, 'trim');
237
        if ($required) {
238
            $this->addRule($name, get_lang('Required field'), 'required');
239
        }
240
241
        return $element;
242
    }
243
244
    /**
245
     * Add hidden course params.
246
     */
247
    public function addCourseHiddenParams()
248
    {
249
        $this->addHidden('cid', api_get_course_id());
250
        $this->addHidden('sid', api_get_session_id());
251
    }
252
253
    /**
254
     * The "date_range_picker" element creates 2 hidden fields
255
     * "elementName" + "_start"  and "elementName" + "_end"
256
     * For example if the name is "range", you will have 2 new fields
257
     * when executing $form->getSubmitValues()
258
     * "range_start" and "range_end".
259
     *
260
     * @param string $name
261
     * @param string $label
262
     * @param bool   $required
263
     * @param array  $attributes
264
     */
265
    public function addDateRangePicker($name, $label, $required = true, $attributes = [])
266
    {
267
        $this->addElement('date_range_picker', $name, $label, $attributes);
268
        $this->addElement('hidden', $name.'_start');
269
        $this->addElement('hidden', $name.'_end');
270
271
        if ($required) {
272
            $this->addRule($name, get_lang('Required field'), 'required');
273
        }
274
    }
275
276
    /**
277
     * @param string $name
278
     * @param string $label
279
     * @param array  $attributes
280
     *
281
     * @return mixed
282
     */
283
    public function addSelectLanguage($name, $label, $options = [], $attributes = [])
284
    {
285
        return $this->addElement('SelectLanguage', $name, $label, $options, $attributes);
286
    }
287
288
    /**
289
     * @param string $name
290
     * @param string $label
291
     * @param array  $options
292
     * @param array  $attributes
293
     *
294
     * @throws Exception
295
     *
296
     * @return SelectAjax
297
     */
298
    public function addSelectAjax($name, $label, $options = [], $attributes = [])
299
    {
300
        if (!isset($attributes['url'])) {
301
            throw new \Exception('select_ajax needs an URL');
302
        }
303
304
        return $this->addElement(
305
            'select_ajax',
306
            $name,
307
            $label,
308
            $options,
309
            $attributes
310
        );
311
    }
312
313
    /**
314
     * @param string $name
315
     * @param string $label
316
     * @param array  $attributes
317
     *
318
     * @return DatePicker
319
     */
320
    public function addDatePicker($name, $label, $attributes = [])
321
    {
322
        return $this->addElement('DatePicker', $name, $label, $attributes);
323
    }
324
325
    /**
326
     * @param string       $name
327
     * @param string|array $label
328
     * @param array        $attributes
329
     *
330
     * @return DateTimePicker
331
     */
332
    public function addDateTimePicker($name, $label, $attributes = [])
333
    {
334
        return $this->addElement('DateTimePicker', $name, $label, $attributes);
335
    }
336
337
    /**
338
     * @param string       $name
339
     * @param string|array $label
340
     * @param array        $attributes
341
     *
342
     * @return DateTimeRangePicker
343
     */
344
    public function addDateTimeRangePicker($name, $label, $attributes = [])
345
    {
346
        return $this->addElement('DateTimeRangePicker', $name, $label, $attributes);
347
    }
348
349
    /**
350
     * @param string $name
351
     * @param string $value
352
     * @param array  $attributes
353
     */
354
    public function addHidden($name, $value, $attributes = [])
355
    {
356
        $this->addElement('hidden', $name, $value, $attributes);
357
    }
358
359
    /**
360
     * @param string       $name
361
     * @param string|array $label
362
     * @param array        $attributes
363
     * @param bool         $required
364
     *
365
     * @return HTML_QuickForm_textarea
366
     */
367
    public function addTextarea($name, $label, $attributes = [], $required = false)
368
    {
369
        $element = $this->addElement('textarea', $name, $label, $attributes);
370
371
        if ($required) {
372
            $this->addRule($name, get_lang('Required field'), 'required');
373
        }
374
375
        return $element;
376
    }
377
378
    /**
379
     * @param string $name
380
     * @param string $label
381
     * @param string $icon          font-awesome
382
     * @param string $style         default|primary|success|info|warning|danger|link
383
     * @param string $size          large|default|small|extra-small
384
     * @param string $class         Example plus is transformed to icon fa fa-plus
385
     * @param array  $attributes
386
     * @param bool   $createElement
387
     *
388
     * @return HTML_QuickForm_button
389
     */
390
    public function addButton(
391
        $name,
392
        $label,
393
        $icon = 'check',
394
        $style = 'default',
395
        $size = 'default',
396
        $class = null,
397
        $attributes = [],
398
        $createElement = false
399
    ) {
400
        if ($createElement) {
401
            return $this->createElement(
402
                'button',
403
                $name,
404
                $label,
405
                $icon,
406
                $style,
407
                $size,
408
                $class,
409
                $attributes
410
            );
411
        }
412
413
        return $this->addElement(
414
            'button',
415
            $name,
416
            $label,
417
            $icon,
418
            $style,
419
            $size,
420
            $class,
421
            $attributes
422
        );
423
    }
424
425
    /**
426
     * Returns a button with the primary color and a check mark.
427
     *
428
     * @param string $label         Text appearing on the button
429
     * @param string $name          Element name (for form treatment purposes)
430
     * @param bool   $createElement Whether to use the create or add method
431
     * @param array  $attributes
432
     *
433
     * @return HTML_QuickForm_button
434
     */
435
    public function addButtonSave($label, $name = 'submit', $createElement = false, $attributes = [])
436
    {
437
        return $this->addButton(
438
            $name,
439
            $label,
440
            'check',
441
            'primary',
442
            null,
443
            null,
444
            $attributes,
445
            $createElement
446
        );
447
    }
448
449
    /**
450
     * Returns a cancel button.
451
     *
452
     * @param string $label         Text appearing on the button
453
     * @param string $name          Element name (for form treatment purposes)
454
     * @param bool   $createElement Whether to use the create or add method
455
     *
456
     * @return HTML_QuickForm_button
457
     */
458
    public function addButtonCancel($label, $name = 'submit', $createElement = false)
459
    {
460
        return $this->addButton(
461
            $name,
462
            $label,
463
            'times',
464
            'danger',
465
            null,
466
            null,
467
            [],
468
            $createElement
469
        );
470
    }
471
472
    /**
473
     * Returns a button with the primary color and a "plus" icon.
474
     *
475
     * @param string $label         Text appearing on the button
476
     * @param string $name          Element name (for form treatment purposes)
477
     * @param bool   $createElement Whether to use the create or add method
478
     * @param array  $attributes    Additional attributes
479
     *
480
     * @return HTML_QuickForm_button
481
     */
482
    public function addButtonCreate($label, $name = 'submit', $createElement = false, $attributes = [])
483
    {
484
        return $this->addButton(
485
            $name,
486
            $label,
487
            'plus',
488
            'primary',
489
            null,
490
            null,
491
            $attributes,
492
            $createElement
493
        );
494
    }
495
496
    /**
497
     * Returns a button with the primary color and a pencil icon.
498
     *
499
     * @param string $label         Text appearing on the button
500
     * @param string $name          Element name (for form treatment purposes)
501
     * @param bool   $createElement Whether to use the create or add method
502
     *
503
     * @return HTML_QuickForm_button
504
     */
505
    public function addButtonUpdate($label, $name = 'submit', $createElement = false)
506
    {
507
        return $this->addButton(
508
            $name,
509
            $label,
510
            'fa fas fa-pencil-alt',
511
            'primary',
512
            null,
513
            null,
514
            [],
515
            $createElement
516
        );
517
    }
518
519
    /**
520
     * Returns a button with the danger color and a trash icon.
521
     *
522
     * @param string $label         Text appearing on the button
523
     * @param string $name          Element name (for form treatment purposes)
524
     * @param bool   $createElement Whether to use the create or add method
525
     *
526
     * @return HTML_QuickForm_button
527
     */
528
    public function addButtonDelete($label, $name = 'submit', $createElement = false)
529
    {
530
        return $this->addButton(
531
            $name,
532
            $label,
533
            'trash',
534
            'danger',
535
            null,
536
            null,
537
            [],
538
            $createElement
539
        );
540
    }
541
542
    /**
543
     * Returns a move style button.
544
     *
545
     * @param string $label         Text appearing on the button
546
     * @param string $name          Element name (for form treatment purposes)
547
     * @param bool   $createElement Whether to use the create or add method
548
     *
549
     * @return HTML_QuickForm_button
550
     */
551
    public function addButtonMove($label, $name = 'submit', $createElement = false)
552
    {
553
        return $this->addButton(
554
            $name,
555
            $label,
556
            'arrow-circle-right',
557
            'primary',
558
            null,
559
            null,
560
            [],
561
            $createElement
562
        );
563
    }
564
565
    /**
566
     * Returns a button with the primary color and a paper-plane icon.
567
     *
568
     * @param string $label         Text appearing on the button
569
     * @param string $name          Element name (for form treatment purposes)
570
     * @param bool   $createElement Whether to use the create or add method
571
     * @param array  $attributes
572
     *
573
     * @return HTML_QuickForm_button
574
     */
575
    public function addButtonSend($label, $name = 'submit', $createElement = false, $attributes = [])
576
    {
577
        return $this->addButton(
578
            $name,
579
            $label,
580
            'paper-plane',
581
            'primary',
582
            null,
583
            null,
584
            $attributes,
585
            $createElement
586
        );
587
    }
588
589
    /**
590
     * Returns a button with the default (grey?) color and a magnifier icon.
591
     *
592
     * @param string $label Text appearing on the button
593
     * @param string $name  Element name (for form treatment purposes)
594
     *
595
     * @return HTML_QuickForm_button
596
     */
597
    public function addButtonSearch($label = null, $name = 'submit')
598
    {
599
        if (empty($label)) {
600
            $label = get_lang('Search');
601
        }
602
603
        return $this->addButton($name, $label, 'search', 'primary');
604
    }
605
606
    /**
607
     * Returns a button with the primary color and a right-pointing arrow icon.
608
     *
609
     * @param string $label      Text appearing on the button
610
     * @param string $name       Element name (for form treatment purposes)
611
     * @param array  $attributes Additional attributes
612
     *
613
     * @return HTML_QuickForm_button
614
     */
615
    public function addButtonNext($label, $name = 'submit', $attributes = [])
616
    {
617
        return $this->addButton(
618
            $name,
619
            $label,
620
            'arrow-right',
621
            'primary',
622
            null,
623
            null,
624
            $attributes
625
        );
626
    }
627
628
    /**
629
     * Returns a button with the primary color and a check mark icon.
630
     *
631
     * @param string $label         Text appearing on the button
632
     * @param string $name          Element name (for form treatment purposes)
633
     * @param bool   $createElement Whether to use the create or add method
634
     *
635
     * @return HTML_QuickForm_button
636
     */
637
    public function addButtonImport($label, $name = 'submit', $createElement = false)
638
    {
639
        return $this->addButton(
640
            $name,
641
            $label,
642
            'check',
643
            'primary',
644
            null,
645
            null,
646
            [],
647
            $createElement
648
        );
649
    }
650
651
    /**
652
     * Returns a button with the primary color and a check-mark icon.
653
     *
654
     * @param string $label         Text appearing on the button
655
     * @param string $name          Element name (for form treatment purposes)
656
     * @param bool   $createElement Whether to use the create or add method
657
     *
658
     * @return HTML_QuickForm_button
659
     */
660
    public function addButtonExport($label, $name = 'submit', $createElement = false)
661
    {
662
        return $this->addButton(
663
            $name,
664
            $label,
665
            'check',
666
            'primary',
667
            null,
668
            null,
669
            [],
670
            $createElement
671
        );
672
    }
673
674
    /**
675
     * Shortcut to filter button.
676
     *
677
     * @param string $label         Text appearing on the button
678
     * @param string $name          Element name (for form treatment purposes)
679
     * @param bool   $createElement Whether to use the create or add method
680
     *
681
     * @return HTML_QuickForm_button
682
     */
683
    public function addButtonFilter($label, $name = 'submit', $createElement = false)
684
    {
685
        return $this->addButton(
686
            $name,
687
            $label,
688
            'filter',
689
            'primary',
690
            null,
691
            null,
692
            [],
693
            $createElement
694
        );
695
    }
696
697
    /**
698
     * Shortcut to reset button.
699
     *
700
     * @param string $label         Text appearing on the button
701
     * @param string $name          Element name (for form treatment purposes)
702
     * @param bool   $createElement Whether to use the create or add method
703
     *
704
     * @return HTML_QuickForm_button
705
     */
706
    public function addButtonReset($label, $name = 'reset', $createElement = false)
707
    {
708
        $icon = 'eraser';
709
        $style = 'default';
710
        $size = 'default';
711
        $class = null;
712
        $attributes = [];
713
714
        if ($createElement) {
715
            return $this->createElement(
716
                'reset',
717
                $name,
718
                $label,
719
                $icon,
720
                $style,
721
                $size,
722
                $class,
723
                $attributes
724
            );
725
        }
726
727
        return $this->addElement(
728
            'reset',
729
            $name,
730
            $label,
731
            $icon,
732
            $style,
733
            $size,
734
            $class,
735
            $attributes
736
        );
737
    }
738
739
    /**
740
     * Returns a button with the primary color and an upload icon.
741
     *
742
     * @param string $label         Text appearing on the button
743
     * @param string $name          Element name (for form treatment purposes)
744
     * @param bool   $createElement Whether to use the create or add method
745
     *
746
     * @return HTML_QuickForm_button
747
     */
748
    public function addButtonUpload($label, $name = 'submit', $createElement = false)
749
    {
750
        return $this->addButton(
751
            $name,
752
            $label,
753
            'upload',
754
            'primary',
755
            null,
756
            null,
757
            [],
758
            $createElement
759
        );
760
    }
761
762
    /**
763
     * Returns a button with the primary color and a download icon.
764
     *
765
     * @param string $label         Text appearing on the button
766
     * @param string $name          Element name (for form treatment purposes)
767
     * @param bool   $createElement Whether to use the create or add method
768
     *
769
     * @return HTML_QuickForm_button
770
     */
771
    public function addButtonDownload($label, $name = 'submit', $createElement = false)
772
    {
773
        return $this->addButton(
774
            $name,
775
            $label,
776
            'download',
777
            'primary',
778
            null,
779
            null,
780
            [],
781
            $createElement
782
        );
783
    }
784
785
    /**
786
     * Returns a button with the primary color and a magnifier icon.
787
     *
788
     * @param string $label         Text appearing on the button
789
     * @param string $name          Element name (for form treatment purposes)
790
     * @param bool   $createElement Whether to use the create or add method
791
     *
792
     * @return HTML_QuickForm_button
793
     */
794
    public function addButtonPreview($label, $name = 'submit', $createElement = false)
795
    {
796
        return $this->addButton(
797
            $name,
798
            $label,
799
            'search',
800
            'primary',
801
            null,
802
            null,
803
            [],
804
            $createElement
805
        );
806
    }
807
808
    /**
809
     * Returns a button with the primary color and a copy (double sheet) icon.
810
     *
811
     * @param string $label         Text appearing on the button
812
     * @param string $name          Element name (for form treatment purposes)
813
     * @param bool   $createElement Whether to use the create or add method
814
     *
815
     * @return HTML_QuickForm_button
816
     */
817
    public function addButtonCopy($label, $name = 'submit', $createElement = false)
818
    {
819
        return $this->addButton(
820
            $name,
821
            $label,
822
            'copy',
823
            'primary',
824
            null,
825
            null,
826
            [],
827
            $createElement
828
        );
829
    }
830
831
    /**
832
     * @param string $name
833
     * @param string $label
834
     * @param string $text
835
     * @param array  $attributes
836
     *
837
     * @return HTML_QuickForm_checkbox
838
     */
839
    public function addCheckBox($name, $label, $text = '', $attributes = [])
840
    {
841
        return $this->addElement('checkbox', $name, $label, $text, $attributes);
842
    }
843
844
    /**
845
     * @param string $name
846
     * @param string $label
847
     * @param array  $options
848
     * @param array  $attributes
849
     *
850
     * @return HTML_QuickForm_group
851
     */
852
    public function addCheckBoxGroup($name, $label, $options = [], $attributes = [])
853
    {
854
        $group = [];
855
        foreach ($options as $value => $text) {
856
            $attributes['value'] = $value;
857
            $group[] = $this->createElement(
858
                'checkbox',
859
                $value,
860
                null,
861
                $text,
862
                $attributes
863
            );
864
        }
865
866
        return $this->addGroup($group, $name, $label);
867
    }
868
869
    /**
870
     * @param string $name
871
     * @param string $label
872
     * @param array  $options
873
     * @param array  $attributes
874
     *
875
     * @return HTML_QuickForm_group
876
     */
877
    public function addRadio($name, $label, $options = [], $attributes = [])
878
    {
879
        $group = [];
880
        foreach ($options as $key => $value) {
881
            $group[] = $this->createElement('radio', null, null, $value, $key, $attributes);
882
        }
883
884
        return $this->addGroup($group, $name, $label);
885
    }
886
887
    /**
888
     * @param string       $name
889
     * @param string|array $label
890
     * @param array        $options
891
     * @param array        $attributes
892
     *
893
     * @return HTML_QuickForm_select
894
     */
895
    public function addSelect($name, $label, $options = [], $attributes = [])
896
    {
897
        return $this->addElement('select', $name, $label, $options, $attributes);
898
    }
899
900
    /**
901
     * @param $name
902
     * @param $label
903
     * @param $collection
904
     * @param array  $attributes
905
     * @param bool   $addNoneOption
906
     * @param string $textCallable  set a function getStringValue() by default __toString()
907
     *
908
     * @return HTML_QuickForm_element
909
     */
910
    public function addSelectFromCollection(
911
        $name,
912
        $label,
913
        $collection,
914
        $attributes = [],
915
        $addNoneOption = false,
916
        $textCallable = ''
917
    ) {
918
        $options = [];
919
920
        if ($addNoneOption) {
921
            $options[0] = get_lang('None');
922
        }
923
924
        if (!empty($collection)) {
925
            foreach ($collection as $item) {
926
                $text = $item;
927
                if (!empty($textCallable)) {
928
                    $text = $item->$textCallable();
929
                }
930
                $options[$item->getId()] = $text;
931
            }
932
        }
933
934
        return $this->addElement('select', $name, $label, $options, $attributes);
935
    }
936
937
    public function addMultiSelect(string $name, $label, array $options, array $attributes = [])
938
    {
939
        $this->addElement('advmultiselect', $name, $label, $options, $attributes);
940
    }
941
942
    /**
943
     * @param string $label
944
     * @param string $text
945
     * @param bool   $createElement
946
     *
947
     * @return HTML_QuickForm_Element
948
     */
949
    public function addLabel($label, $text, $createElement = false)
950
    {
951
        if ($createElement) {
952
            return $this->createElement(
953
                'label',
954
                $label,
955
                $text
956
            );
957
        }
958
959
        return $this->addElement('label', $label, $text);
960
    }
961
962
    /**
963
     * @param string $text
964
     */
965
    public function addHeader($text)
966
    {
967
        if (!empty($text)) {
968
            $this->addElement('header', $text);
969
        }
970
    }
971
972
    /**
973
     * @param string $name
974
     * @param string|array $label
975
     * @param array  $attributes
976
     *
977
     * @throws Exception if the file doesn't have an id
978
     *
979
     * @return HTML_QuickForm_file
980
     */
981
    public function addFile($name, $label, $attributes = [])
982
    {
983
        try {
984
            $element = $this->addElement('file', $name, $label, $attributes);
985
            if (isset($attributes['crop_image'])) {
986
                $id = $element->getAttribute('id');
987
                if (empty($id)) {
988
                    throw new Exception('If you use the crop functionality the element must have an id');
989
                }
990
                $this->addHtml(
991
                    '
992
                <div class="form-group row" id="'.$id.'-form-group" style="display: none;">
993
                    <div class="offset-md-2 col-sm-8">
994
                        <div class="card-cropper">
995
                            <div id="'.$id.'_crop_image" class="cropCanvas">
996
                                <img id="'.$id.'_preview_image">
997
                            </div>
998
                            <button class="btn btn-primary" type="button" name="cropButton" id="'.$id.'_crop_button">
999
                                <em class="fa fa-crop"></em> '.get_lang('Crop your picture').'
1000
                            </button>
1001
                        </div>
1002
                    </div>
1003
                </div>'
1004
                );
1005
                $this->addHidden($id.'_crop_result', '');
1006
                $this->addHidden($id.'_crop_result_for_resource', '');
1007
                $this->addHidden($id.'_crop_image_base_64', '');
1008
            }
1009
        } catch (HTML_Quick | Form_Error $e) {
1010
            var_dump($e->getMessage());
0 ignored issues
show
Security Debugging Code introduced by
var_dump($e->getMessage()) looks like debug code. Are you sure you do not want to remove it?
Loading history...
1011
        }
1012
1013
        return $element;
1014
    }
1015
1016
    /**
1017
     * @param string $snippet
1018
     */
1019
    public function addHtml($snippet)
1020
    {
1021
        if (empty($snippet)) {
1022
            return false;
1023
        }
1024
        $this->addElement('html', $snippet);
1025
1026
        return true;
1027
    }
1028
1029
    /**
1030
     * Draws a panel of options see the course_info/infocours.php page.
1031
     *
1032
     * @param string $name      internal name
1033
     * @param string $title     visible title
1034
     * @param array  $groupList list of group or elements
1035
     */
1036
    public function addPanelOption($name, $title, $groupList, $icon, $open, $parent)
1037
    {
1038
        $html = '<div class="card">';
1039
        $html .= '<div class="card-header" id="card_'.$name.'">';
1040
        $html .= '<h5 class="card-title">';
1041
        $html .= '<a role="button" class="'.(($open) ? 'collapse' : ' ').'"  data-toggle="collapse" data-target="#collapse_'.$name.'" aria-expanded="true" aria-controls="collapse_'.$name.'">';
1042
        if ($icon) {
1043
            $html .= Display::return_icon($icon, null, null, ICON_SIZE_SMALL);
1044
        }
1045
        $html .= $title;
1046
        $html .= '</a></h5></div>';
1047
        $html .= '<div id="collapse_'.$name.'" class="collapse '.(($open) ? 'show' : ' ').'" aria-labelledby="heading_'.$name.'" data-parent="#'.$parent.'">';
1048
        $html .= '<div class="card-body">';
1049
1050
        $this->addHtml($html);
1051
1052
        foreach ($groupList as $groupName => $group) {
1053
            // Add group array
1054
            if (!empty($groupName) && is_array($group)) {
1055
                $this->addGroup($group, '', $groupName);
1056
            }
1057
            // Add element
1058
            if ($group instanceof HTML_QuickForm_element) {
1059
                $this->addElement($group);
1060
            }
1061
        }
1062
1063
        $this->addHtml('</div></div></div>');
1064
    }
1065
1066
    /**
1067
     * Adds a HTML-editor to the form.
1068
     *
1069
     * @param string       $name
1070
     * @param string|array $label      The label for the form-element
1071
     * @param bool         $required   (optional) Is the form-element required (default=true)
1072
     * @param bool         $fullPage   (optional) When it is true, the editor loads completed html code for a full page
1073
     * @param array        $config     (optional) Configuration settings for the online editor
1074
     * @param array        $attributes
1075
     *
1076
     * @throws Exception
1077
     * @throws HTML_QuickForm_Error
1078
     */
1079
    public function addHtmlEditor(
1080
        $name,
1081
        $label,
1082
        $required = true,
1083
        $fullPage = false,
1084
        $config = [],
1085
        $attributes = []
1086
    ) {
1087
        $attributes['rows'] = $config['rows'] ?? 15;
1088
        $attributes['cols'] = $config['cols'] ?? 80;
1089
        $attributes['cols-size'] = $config['cols-size'] ?? [];
1090
        $attributes['class'] = $config['class'] ?? [];
1091
        $cleanName = str_replace(['[', ']', '#'], '', $name);
1092
1093
        if (empty($attributes['id'])) {
1094
            $attributes['id'] = $cleanName;
1095
        }
1096
1097
        //$attributes['id'] = $config['id'] ?? 'editor_'.$cleanName;
1098
1099
        $this->addElement('html_editor', $name, $label, $attributes, $config);
1100
        $this->applyFilter($name, 'trim');
1101
        if ($required) {
1102
            $this->addRule($name, get_lang('Required field'), 'required');
1103
        }
1104
1105
        /** @var HtmlEditor $element */
1106
        $element = $this->getElement($name);
1107
        $config['style'] = $config['style'] ?? false;
1108
        if ($fullPage) {
1109
            $config['fullPage'] = true;
1110
            // Adds editor_content.css in ckEditor
1111
            $config['style'] = true;
1112
        }
1113
1114
        if ($element->editor) {
1115
            $element->editor->processConfig($config);
1116
        }
1117
    }
1118
1119
    /**
1120
     * Adds a Google Maps Geolocalization field to the form.
1121
     *
1122
     * @param      $name
1123
     * @param      $label
1124
     * @param bool $hideGeoLocalizationDetails
1125
     */
1126
    public function addGeoLocationMapField($name, $label, $dataValue, $hideGeoLocalizationDetails = false)
1127
    {
1128
        $gMapsPlugin = GoogleMapsPlugin::create();
1129
        $geolocalization = 'true' === $gMapsPlugin->get('enable_api');
1130
1131
        if ($geolocalization && false === $gMapsPlugin->javascriptIncluded) {
1132
            $gmapsApiKey = $gMapsPlugin->get('api_key');
1133
            $url = '//maps.googleapis.com/maps/api/js?key='.$gmapsApiKey;
1134
            $this->addHtml('<script type="text/javascript" src="'.$url.'" ></script>');
1135
            $gMapsPlugin->javascriptIncluded = true;
1136
        }
1137
1138
        $this->addElement(
1139
            'text',
1140
            $name,
1141
            $label,
1142
            ['id' => $name]
1143
        );
1144
1145
        $this->addHidden(
1146
            $name.'_coordinates',
1147
            '',
1148
            ['id' => $name.'_coordinates']
1149
        );
1150
1151
        $this->applyFilter($name, 'stripslashes');
1152
        $this->applyFilter($name, 'trim');
1153
1154
        $this->addHtml(Extrafield::getLocalizationJavascript($name, $dataValue));
1155
1156
        if ($hideGeoLocalizationDetails) {
1157
            $this->addHtml('<div style="display:none">');
1158
        }
1159
1160
        $this->addHtml(
1161
            Extrafield::getLocalizationInput($name, $label)
1162
        );
1163
1164
        if ($hideGeoLocalizationDetails) {
1165
            $this->addHtml('</div>');
1166
        }
1167
    }
1168
1169
    /**
1170
     * @param string       $name
1171
     * @param string|array $label
1172
     *
1173
     * @return mixed
1174
     */
1175
    public function addButtonAdvancedSettings($name, $label = null)
1176
    {
1177
        $label = !empty($label) ? $label : get_lang('Advanced settings');
1178
1179
        return $this->addElement('advanced_settings', $name, $label);
1180
    }
1181
1182
    /**
1183
     * Adds a progress loading image to the form.
1184
     */
1185
    public function addProgress($delay = 2, $label = '')
1186
    {
1187
        if (empty($label)) {
1188
            $label = get_lang('Please stand by...');
1189
        }
1190
        $this->with_progress_bar = true;
1191
        $id = $this->getAttribute('id');
1192
1193
        $this->updateAttributes("onsubmit=\"javascript: addProgress('".$id."')\"");
1194
        $this->addHtml('<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/upload.js" type="text/javascript"></script>');
1195
    }
1196
1197
    /**
1198
     * This function has been created for avoiding changes directly within QuickForm class.
1199
     * When we use it, the element is threated as 'required' to be dealt during validation.
1200
     *
1201
     * @param array  $elements The array of elements
1202
     * @param string $message  The message displayed
1203
     */
1204
    public function add_multiple_required_rule($elements, $message)
1205
    {
1206
        $this->_required[] = $elements[0];
1207
        $this->addRule($elements, $message, 'multiple_required');
1208
    }
1209
1210
    /**
1211
     * Displays the form.
1212
     * If an element in the form didn't validate, an error message is showed
1213
     * asking the user to complete the form.
1214
     */
1215
    public function display()
1216
    {
1217
        echo $this->returnForm();
1218
    }
1219
1220
    /**
1221
     * Returns the HTML code of the form.
1222
     *
1223
     * @return string $return_value HTML code of the form
1224
     */
1225
    public function returnForm()
1226
    {
1227
        $returnValue = '';
1228
        /** @var HTML_QuickForm_element $element */
1229
        foreach ($this->_elements as &$element) {
1230
            $element->setLayout($this->getLayout());
1231
            $elementError = parent::getElementError($element->getName());
1232
            if (!is_null($elementError)) {
1233
                $returnValue .= Display::return_message($elementError, 'warning').'<br />';
1234
                break;
1235
            }
1236
        }
1237
1238
        $returnValue .= parent::toHtml();
1239
        // Add div-element which is to hold the progress bar
1240
        $id = $this->getAttribute('id');
1241
        if (isset($this->with_progress_bar) && $this->with_progress_bar) {
1242
            // @todo improve UI
1243
            $returnValue .= '<br />
1244
            <div id="loading_div_'.$id.'" class="loading_div" style="display:none;margin-left:40%; margin-top:10px; height:50px;">
1245
                <div class="wobblebar-loader"></div>
1246
            </div>
1247
            ';
1248
        }
1249
1250
        return $returnValue;
1251
    }
1252
1253
    /**
1254
     * Returns the HTML code of the form.
1255
     * If an element in the form didn't validate, an error message is showed
1256
     * asking the user to complete the form.
1257
     *
1258
     * @return string $return_value HTML code of the form
1259
     *
1260
     * @author Patrick Cool <[email protected]>, Ghent University, august 2006
1261
     * @author Julio Montoya
1262
     *
1263
     * @deprecated use returnForm()
1264
     */
1265
    public function return_form()
1266
    {
1267
        return $this->returnForm();
1268
    }
1269
1270
    /**
1271
     * @return HTML_QuickForm_Renderer_Default
1272
     */
1273
    public static function getDefaultRenderer()
1274
    {
1275
        return
1276
            isset($GLOBALS['_HTML_QuickForm_default_renderer']) ?
1277
                $GLOBALS['_HTML_QuickForm_default_renderer'] : null;
1278
    }
1279
1280
    /**
1281
     * Adds a input of type url to the form.
1282
     *
1283
     * @param string $name       The label for the form-element
1284
     * @param string $label      The element name
1285
     * @param bool   $required   Optional. Is the form-element required (default=true)
1286
     * @param array  $attributes Optional. List of attributes for the form-element
1287
     */
1288
    public function addUrl($name, $label, $required = true, $attributes = [])
1289
    {
1290
        $this->addElement('url', $name, $label, $attributes);
1291
        $this->applyFilter($name, 'trim');
1292
        $this->addRule($name, get_lang('Insert a valid URL'), 'url');
1293
1294
        if ($required) {
1295
            $this->addRule($name, get_lang('Required field'), 'required');
1296
        }
1297
    }
1298
1299
    /**
1300
     * Adds a text field for letters to the form.
1301
     * A trim-filter is attached to the field.
1302
     *
1303
     * @param string $name       The element name
1304
     * @param string $label      The label for the form-element
1305
     * @param bool   $required   Optional. Is the form-element required (default=true)
1306
     * @param array  $attributes Optional. List of attributes for the form-element
1307
     */
1308
    public function addTextLettersOnly(
1309
        $name,
1310
        $label,
1311
        $required = false,
1312
        $attributes = []
1313
    ) {
1314
        $attributes = array_merge(
1315
            $attributes,
1316
            [
1317
                'pattern' => '[a-zA-ZñÑ]+',
1318
                'title' => get_lang('Only letters'),
1319
            ]
1320
        );
1321
1322
        $this->addElement(
1323
            'text',
1324
            $name,
1325
            [
1326
                $label,
1327
                get_lang('Only letters'),
1328
            ],
1329
            $attributes
1330
        );
1331
1332
        $this->applyFilter($name, 'trim');
1333
1334
        if ($required) {
1335
            $this->addRule($name, get_lang('Required field'), 'required');
1336
        }
1337
1338
        $this->addRule(
1339
            $name,
1340
            get_lang('Only letters'),
1341
            'regex',
1342
            '/^[a-zA-ZñÑ]+$/'
1343
        );
1344
    }
1345
1346
    /**
1347
     * @param string $name
1348
     * @param string $label
1349
     * @param array  $attributes
1350
     * @param bool   $required
1351
     *
1352
     * @return HTML_QuickForm_element
1353
     */
1354
    public function addNumeric($name, $label, $attributes = [], $required = false)
1355
    {
1356
        $element = $this->addElement('Number', $name, $label, $attributes);
1357
1358
        if ($required) {
1359
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1360
        }
1361
1362
        return $element;
1363
    }
1364
1365
    /**
1366
     * Adds a text field for alphanumeric characters to the form.
1367
     * A trim-filter is attached to the field.
1368
     *
1369
     * @param string $name       The element name
1370
     * @param string $label      The label for the form-element
1371
     * @param bool   $required   Optional. Is the form-element required (default=true)
1372
     * @param array  $attributes Optional. List of attributes for the form-element
1373
     */
1374
    public function addTextAlphanumeric(
1375
        $name,
1376
        $label,
1377
        $required = false,
1378
        $attributes = []
1379
    ) {
1380
        $attributes = array_merge(
1381
            $attributes,
1382
            [
1383
                'pattern' => '[a-zA-Z0-9ñÑ]+',
1384
                'title' => get_lang('Only lettersAndNumbers'),
1385
            ]
1386
        );
1387
1388
        $this->addElement(
1389
            'text',
1390
            $name,
1391
            [
1392
                $label,
1393
                get_lang('Only lettersAndNumbers'),
1394
            ],
1395
            $attributes
1396
        );
1397
1398
        $this->applyFilter($name, 'trim');
1399
1400
        if ($required) {
1401
            $this->addRule($name, get_lang('Required field'), 'required');
1402
        }
1403
1404
        $this->addRule(
1405
            $name,
1406
            get_lang('Only lettersAndNumbers'),
1407
            'regex',
1408
            '/^[a-zA-Z0-9ÑÑ]+$/'
1409
        );
1410
    }
1411
1412
    /**
1413
     * @param string $name
1414
     * @param $label
1415
     * @param bool  $required
1416
     * @param array $attributes
1417
     * @param bool  $allowNegative
1418
     * @param int   $minValue
1419
     * @param null  $maxValue
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $maxValue is correct as it would always require null to be passed?
Loading history...
1420
     */
1421
    public function addFloat(
1422
        $name,
1423
        $label,
1424
        $required = false,
1425
        $attributes = [],
1426
        $allowNegative = false,
1427
        $minValue = null,
1428
        $maxValue = null
1429
    ) {
1430
        $this->addElement(
1431
            'FloatNumber',
1432
            $name,
1433
            $label,
1434
            $attributes
1435
        );
1436
1437
        $this->applyFilter($name, 'trim');
1438
1439
        if ($required) {
1440
            $this->addRule($name, get_lang('Required field'), 'required');
1441
        }
1442
1443
        // Rule allows "," and "."
1444
        /*$this->addRule(
1445
            $name,
1446
            get_lang('Only numbers'),
1447
            'regex',
1448
            '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d\d*\,\d*$)|(^-?\,\d\d*$)/'
1449
        );*/
1450
1451
        if (false == $allowNegative) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1452
            $this->addRule(
1453
                $name,
1454
                get_lang('Negative value'),
1455
                'compare',
1456
                '>=',
1457
                'server',
1458
                false,
1459
                false,
1460
                0
1461
            );
1462
        }
1463
1464
        if (!is_null($minValue)) {
1465
            $this->addRule(
1466
                $name,
1467
                get_lang('Under the minimum.'),
1468
                'compare',
1469
                '>=',
1470
                'server',
1471
                false,
1472
                false,
1473
                $minValue
1474
            );
1475
        }
1476
1477
        if (!is_null($maxValue)) {
1478
            $this->addRule(
1479
                $name,
1480
                get_lang('Value exceeds score.'),
1481
                'compare',
1482
                '<=',
1483
                'server',
1484
                false,
1485
                false,
1486
                $maxValue
1487
            );
1488
        }
1489
    }
1490
1491
    /**
1492
     * Adds a text field for letters and spaces to the form.
1493
     * A trim-filter is attached to the field.
1494
     *
1495
     * @param string $name       The element name
1496
     * @param string $label      The label for the form-element
1497
     * @param bool   $required   Optional. Is the form-element required (default=true)
1498
     * @param array  $attributes Optional. List of attributes for the form-element
1499
     */
1500
    public function addTextLettersAndSpaces(
1501
        $name,
1502
        $label,
1503
        $required = false,
1504
        $attributes = []
1505
    ) {
1506
        $attributes = array_merge(
1507
            $attributes,
1508
            [
1509
                'pattern' => '[a-zA-ZñÑ\s]+',
1510
                'title' => get_lang('Only lettersAndSpaces'),
1511
            ]
1512
        );
1513
1514
        $this->addElement(
1515
            'text',
1516
            $name,
1517
            [
1518
                $label,
1519
                get_lang('Only lettersAndSpaces'),
1520
            ],
1521
            $attributes
1522
        );
1523
1524
        $this->applyFilter($name, 'trim');
1525
1526
        if ($required) {
1527
            $this->addRule($name, get_lang('Required field'), 'required');
1528
        }
1529
1530
        $this->addRule(
1531
            $name,
1532
            get_lang('Only lettersAndSpaces'),
1533
            'regex',
1534
            '/^[a-zA-ZñÑ\s]+$/'
1535
        );
1536
    }
1537
1538
    /**
1539
     * Adds a text field for alphanumeric and spaces characters to the form.
1540
     * A trim-filter is attached to the field.
1541
     *
1542
     * @param string $name       The element name
1543
     * @param string $label      The label for the form-element
1544
     * @param bool   $required   Optional. Is the form-element required (default=true)
1545
     * @param array  $attributes Optional. List of attributes for the form-element
1546
     */
1547
    public function addTextAlphanumericAndSpaces(
1548
        $name,
1549
        $label,
1550
        $required = false,
1551
        $attributes = []
1552
    ) {
1553
        $attributes = array_merge(
1554
            $attributes,
1555
            [
1556
                'pattern' => '[a-zA-Z0-9ñÑ\s]+',
1557
                'title' => get_lang('Only lettersAndNumbersAndSpaces'),
1558
            ]
1559
        );
1560
1561
        $this->addElement(
1562
            'text',
1563
            $name,
1564
            [
1565
                $label,
1566
                get_lang('Only lettersAndNumbersAndSpaces'),
1567
            ],
1568
            $attributes
1569
        );
1570
1571
        $this->applyFilter($name, 'trim');
1572
1573
        if ($required) {
1574
            $this->addRule($name, get_lang('Required field'), 'required');
1575
        }
1576
1577
        $this->addRule(
1578
            $name,
1579
            get_lang('Only lettersAndNumbersAndSpaces'),
1580
            'regex',
1581
            '/^[a-zA-Z0-9ñÑ\s]+$/'
1582
        );
1583
    }
1584
1585
    /**
1586
     * @param string $url
1587
     * @param string $urlToRedirect after upload redirect to this page
1588
     */
1589
    public function addMultipleUpload($url, $urlToRedirect = '')
1590
    {
1591
        $inputName = 'input_file_upload';
1592
        $this->addMultipleUploadJavascript($url, $inputName, $urlToRedirect);
1593
1594
        $this->addHtml('
1595
            <div class="description-upload">
1596
            '.get_lang('Click on the box below to select files from your computer (you can use CTRL + clic to select various files at a time), or drag and drop some files from your desktop directly over the box below. The system will handle the rest!').'
1597
            </div>
1598
            <span class="btn btn-success fileinput-button">
1599
                <i class="glyphicon glyphicon-plus"></i>
1600
                <span>'.get_lang('Add files').'</span>
1601
                <!-- The file input field used as target for the file upload widget -->
1602
                <input id="'.$inputName.'" type="file" name="files[]" multiple>
1603
            </span>
1604
            <div id="dropzone">
1605
                <div class="button-load">
1606
                '.get_lang('Click or drag and drop files here to upload them').'
1607
                </div>
1608
            </div>
1609
            <br />
1610
            <!-- The global progress bar -->
1611
            <div id="progress" class="progress">
1612
                <div class="progress-bar progress-bar-success"></div>
1613
            </div>
1614
            <div id="files" class="files"></div>
1615
        ');
1616
    }
1617
1618
    /**
1619
     * @param string $elementName
1620
     * @param string $groupName   if element is inside a group
1621
     *
1622
     * @throws Exception
1623
     */
1624
    public function addPasswordRule($elementName, $groupName = '')
1625
    {
1626
        if ('true' == api_get_setting('security.check_password')) {
1627
            $message = get_lang('this password  is too simple. Use a pass like this').': '.api_generate_password();
1628
1629
            if (!empty($groupName)) {
1630
                $groupObj = $this->getElement($groupName);
1631
1632
                if ($groupObj instanceof HTML_QuickForm_group) {
1633
                    $elementName = $groupObj->getElementName($elementName);
1634
1635
                    if (false === $elementName) {
1636
                        throw new Exception("The $groupName doesn't have the element $elementName");
1637
                    }
1638
1639
                    $this->_rules[$elementName][] = [
1640
                        'type' => 'callback',
1641
                        'format' => 'api_check_password',
1642
                        'message' => $message,
1643
                        'validation' => '',
1644
                        'reset' => false,
1645
                        'group' => $groupName,
1646
                    ];
1647
                }
1648
            } else {
1649
                $this->addRule(
1650
                    $elementName,
1651
                    $message,
1652
                    'callback',
1653
                    'api_check_password'
1654
                );
1655
            }
1656
        }
1657
    }
1658
1659
    /**
1660
     * Add an element with user ID and avatar to the form.
1661
     * It needs a Chamilo\CoreBundle\Entity\User as value. The exported value is the Chamilo\CoreBundle\Entity\User ID.
1662
     *
1663
     * @see \UserAvatar
1664
     *
1665
     * @param string $name
1666
     * @param string $label
1667
     * @param string $imageSize Optional. Small, medium or large image
1668
     * @param string $subtitle  Optional. The subtitle for the field
1669
     *
1670
     * @return \UserAvatar
1671
     */
1672
    public function addUserAvatar($name, $label, $imageSize = 'small', $subtitle = '')
1673
    {
1674
        return $this->addElement('UserAvatar', $name, $label, ['image_size' => $imageSize, 'sub_title' => $subtitle]);
1675
    }
1676
1677
    /**
1678
     * @param array $typeList
1679
     */
1680
    public function addEmailTemplate($typeList)
1681
    {
1682
        $mailManager = new MailTemplateManager();
1683
        foreach ($typeList as $type) {
1684
            $list = $mailManager->get_all(
1685
                ['where' => ['type = ? AND url_id = ?' => [$type, api_get_current_access_url_id()]]]
1686
            );
1687
1688
            $options = [get_lang('Select')];
1689
            $name = $type;
1690
            $defaultId = '';
1691
            foreach ($list as $item) {
1692
                $options[$item['id']] = $item['name'];
1693
                $name = $item['name'];
1694
                if (empty($defaultId)) {
1695
                    $defaultId = 1 == $item['default_template'] ? $item['id'] : '';
1696
                }
1697
            }
1698
1699
            $url = api_get_path(WEB_AJAX_PATH).'mail.ajax.php?a=select_option';
1700
            $typeNoDots = 'email_template_option_'.str_replace('.tpl', '', $type);
1701
            $this->addSelect(
1702
                'email_template_option['.$type.']',
1703
                $name,
1704
                $options,
1705
                ['id' => $typeNoDots]
1706
            );
1707
1708
            $templateNoDots = 'email_template_'.str_replace('.tpl', '', $type);
1709
            $templateNoDotsBlock = 'email_template_block_'.str_replace('.tpl', '', $type);
1710
            $this->addHtml('<div id="'.$templateNoDotsBlock.'" style="display:none">');
1711
            $this->addTextarea(
1712
                $templateNoDots,
1713
                get_lang('Preview'),
1714
                ['disabled' => 'disabled ', 'id' => $templateNoDots, 'rows' => '5']
1715
            );
1716
            $this->addHtml('</div>');
1717
1718
            $this->addHtml("<script>
1719
            $(function() {
1720
                var defaultValue = '$defaultId';
1721
                $('#$typeNoDots').val(defaultValue);
1722
                $('#$typeNoDots').selectpicker('render');
1723
                if (defaultValue != '') {
1724
                    var selected = $('#$typeNoDots option:selected').val();
1725
                    $.ajax({
1726
                        url: '$url' + '&id=' + selected+ '&template_name=$type',
1727
                        success: function (data) {
1728
                            $('#$templateNoDots').html(data);
1729
                            $('#$templateNoDotsBlock').show();
1730
                            return;
1731
                        },
1732
                    });
1733
                }
1734
1735
                $('#$typeNoDots').on('change', function(){
1736
                    var selected = $('#$typeNoDots option:selected').val();
1737
                    $.ajax({
1738
                        url: '$url' + '&id=' + selected,
1739
                        success: function (data) {
1740
                            $('#$templateNoDots').html(data);
1741
                            $('#$templateNoDotsBlock').show();
1742
                            return;
1743
                        },
1744
                    });
1745
                });
1746
            });
1747
            </script>");
1748
        }
1749
    }
1750
1751
    /**
1752
     * Add email rule for an element.
1753
     */
1754
    public function addEmailRule(string $element)
1755
    {
1756
        $this->addRule(
1757
            $element,
1758
            get_lang('The email address is not complete or contains some invalid characters'),
1759
            'email'
1760
        );
1761
    }
1762
1763
    /**
1764
     * @param string $url           page that will handle the upload
1765
     * @param string $inputName
1766
     * @param string $urlToRedirect
1767
     */
1768
    private function addMultipleUploadJavascript($url, $inputName, $urlToRedirect = '')
1769
    {
1770
        $redirectCondition = '';
1771
        if (!empty($urlToRedirect)) {
1772
            $redirectCondition = "window.location.replace('$urlToRedirect'); ";
1773
        }
1774
        $icon = Display::return_icon('file_txt.gif');
1775
        $this->addHtml("
1776
        <script>
1777
        $(function () {
1778
            'use strict';
1779
            $('#".$this->getAttribute('id')."').submit(function() {
1780
                return false;
1781
            });
1782
1783
            $('#dropzone').on('click', function() {
1784
                $('#".$inputName."').click();
1785
            });
1786
1787
            var url = '".$url."';
1788
            var uploadButton = $('<button/>')
1789
                .addClass('btn btn-primary')
1790
                .prop('disabled', true)
1791
                .text('".addslashes(get_lang('Loading'))."')
1792
                .on('click', function () {
1793
                    var \$this = $(this),
1794
                    data = \$this.data();
1795
                    \$this
1796
                        .off('click')
1797
                        .text('".addslashes(get_lang('Cancel'))."')
1798
                        .on('click', function () {
1799
                            \$this.remove();
1800
                            data.abort();
1801
                        });
1802
                    data.submit().always(function () {
1803
                        \$this.remove();
1804
                    });
1805
                });
1806
1807
            $('#".$inputName."').fileupload({
1808
                url: url,
1809
                dataType: 'json',
1810
                // Enable image resizing, except for Android and Opera,
1811
                // which actually support image resizing, but fail to
1812
                // send Blob objects via XHR requests:
1813
                disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent),
1814
                previewMaxWidth: 300,
1815
                previewMaxHeight: 169,
1816
                previewCrop: true,
1817
                dropzone: $('#dropzone'),
1818
            }).on('fileuploadadd', function (e, data) {
1819
                data.context = $('<div class=\"row\" />').appendTo('#files');
1820
                $.each(data.files, function (index, file) {
1821
                    var node = $('<div class=\"col-sm-5 file_name\">').text(file.name);
1822
                    node.appendTo(data.context);
1823
                });
1824
            }).on('fileuploadprocessalways', function (e, data) {
1825
                var index = data.index,
1826
                    file = data.files[index],
1827
                    node = $(data.context.children()[index]);
1828
                if (file.preview) {
1829
                    data.context.prepend($('<div class=\"col-sm-4\">').html(file.preview));
1830
                } else {
1831
                    data.context.prepend($('<div class=\"col-sm-4\">').html('".$icon."'));
1832
                }
1833
                if (index + 1 === data.files.length) {
1834
                    data.context.find('button')
1835
                        .text('Upload')
1836
                        .prop('disabled', !!data.files.error);
1837
                }
1838
            }).on('fileuploadprogressall', function (e, data) {
1839
                var progress = parseInt(data.loaded / data.total * 100, 10);
1840
                $('#progress .progress-bar').css(
1841
                    'width',
1842
                    progress + '%'
1843
                );
1844
            }).on('fileuploaddone', function (e, data) {
1845
                $.each(data.result.files, function (index, file) {
1846
                    if (file.error) {
1847
                        var link = $('<div>')
1848
                            .attr({class : 'panel-image'})                            ;
1849
                        $(data.context.children()[index]).parent().wrap(link);
1850
                        // Update file name with new one from Chamilo
1851
                        $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1852
                        var message = $('<div class=\"col-sm-3\">').html(
1853
                            $('<span class=\"message-image-danger\"/>').text(file.error)
1854
                        );
1855
                        $(data.context.children()[index]).parent().append(message);
1856
1857
                        return;
1858
                    }
1859
                    if (file.url) {
1860
                        var link = $('<a>')
1861
                            .attr({target: '_blank', class : 'panel-image'})
1862
                            .prop('href', file.url);
1863
                        $(data.context.children()[index]).parent().wrap(link);
1864
                    }
1865
                    // Update file name with new one from Chamilo
1866
                    $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1867
                    var message = $('<div class=\"col-sm-3\">').html(
1868
                        $('<span class=\"message-image-success\"/>').text('".addslashes(get_lang('File upload succeeded!'))."')
1869
                    );
1870
                    $(data.context.children()[index]).parent().append(message);
1871
                });
1872
                $('#dropzone').removeClass('hover');
1873
                ".$redirectCondition."
1874
            }).on('fileuploadfail', function (e, data) {
1875
                $.each(data.files, function (index) {
1876
                    var failedMessage = '".addslashes(get_lang('The file upload has failed.'))."';
1877
                    var error = $('<div class=\"col-sm-3\">').html(
1878
                        $('<span class=\"alert alert-danger\"/>').text(failedMessage)
1879
                    );
1880
                    $(data.context.children()[index]).parent().append(error);
1881
                });
1882
                $('#dropzone').removeClass('hover');
1883
            }).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');
1884
1885
            $('#dropzone').on('dragover', function (e) {
1886
                // dragleave callback implementation
1887
                $('#dropzone').addClass('hover');
1888
            });
1889
1890
            $('#dropzone').on('dragleave', function (e) {
1891
                $('#dropzone').removeClass('hover');
1892
            });
1893
            $('.fileinput-button').hide();
1894
        });
1895
        </script>");
1896
    }
1897
}
1898
1899
/**
1900
 * Cleans HTML text filter.
1901
 *
1902
 * @param string $html HTML to clean
1903
 * @param int    $mode (optional)
1904
 *
1905
 * @return string The cleaned HTML
1906
 */
1907
function html_filter($html, $mode = NO_HTML)
1908
{
1909
    $allowed_tags = HTML_QuickForm_Rule_HTML::get_allowed_tags($mode);
1910
    $cleaned_html = kses($html, $allowed_tags);
0 ignored issues
show
Bug introduced by
The function kses was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1910
    $cleaned_html = /** @scrutinizer ignore-call */ kses($html, $allowed_tags);
Loading history...
1911
1912
    return $cleaned_html;
1913
}
1914
1915
function html_filter_teacher($html)
1916
{
1917
    return html_filter($html, TEACHER_HTML);
1918
}
1919
1920
function html_filter_student($html)
1921
{
1922
    return html_filter($html, STUDENT_HTML);
1923
}
1924
1925
function html_filter_teacher_fullpage($html)
1926
{
1927
    return html_filter($html, TEACHER_HTML_FULLPAGE);
1928
}
1929
1930
function html_filter_student_fullpage($html)
1931
{
1932
    return html_filter($html, STUDENT_HTML_FULLPAGE);
1933
}
1934
1935
/**
1936
 * Cleans mobile phone number text.
1937
 *
1938
 * @param string $mobilePhoneNumber Mobile phone number to clean
1939
 *
1940
 * @return string The cleaned mobile phone number
1941
 */
1942
function mobile_phone_number_filter($mobilePhoneNumber)
1943
{
1944
    $mobilePhoneNumber = str_replace(['+', '(', ')'], '', $mobilePhoneNumber);
1945
1946
    return ltrim($mobilePhoneNumber, '0');
1947
}
1948