Passed
Pull Request — 1.11.x (#4352)
by Angel Fernando Quiroz
09:11
created

FormValidator::addPasswordRule()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 40
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
c 0
b 0
f 0
dl 0
loc 40
rs 8.8657
cc 6
nc 8
nop 2
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\UserBundle\Entity\User;
6
7
/**
8
 * Class FormValidator
9
 * create/manipulate/validate user input.
10
 */
11
class FormValidator extends HTML_QuickForm
12
{
13
    public const LAYOUT_HORIZONTAL = 'horizontal';
14
    public const LAYOUT_INLINE = 'inline';
15
    public const LAYOUT_BOX = 'box';
16
    public const LAYOUT_BOX_NO_LABEL = 'box-no-label';
17
    public const LAYOUT_GRID = 'grid';
18
19
    public $with_progress_bar = false;
20
    private $layout;
21
22
    /**
23
     * Constructor.
24
     *
25
     * @param string $name        Name of the form
26
     * @param string $method      (optional) Method ('post' (default) or 'get')
27
     * @param string $action      (optional) Action (default is $PHP_SELF)
28
     * @param string $target      (optional) Form's target defaults to '_self'
29
     * @param mixed  $attributes  (optional) Extra attributes for <form> tag
30
     * @param string $layout
31
     * @param bool   $trackSubmit (optional) Whether to track if the form was
32
     *                            submitted by adding a special hidden field (default = true)
33
     */
34
    public function __construct(
35
        $name,
36
        $method = 'post',
37
        $action = '',
38
        $target = '',
39
        $attributes = [],
40
        $layout = self::LAYOUT_HORIZONTAL,
41
        $trackSubmit = true
42
    ) {
43
        // Default form class.
44
        if (is_array($attributes) && !isset($attributes['class']) || empty($attributes)) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_array($attributes) &...) || empty($attributes), Probably Intended Meaning: is_array($attributes) &&... || empty($attributes))
Loading history...
45
            $attributes['class'] = 'form-horizontal';
46
        }
47
48
        if (isset($attributes['class']) && strpos($attributes['class'], 'form-search') !== false) {
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'] = 'form-horizontal';
60
                break;
61
            case self::LAYOUT_INLINE:
62
                $attributes['class'] = 'form-inline';
63
                break;
64
            case self::LAYOUT_BOX:
65
                $attributes['class'] = 'form-inline-box';
66
                break;
67
            case self::LAYOUT_GRID:
68
                $attributes['class'] = 'form-grid';
69
                $formTemplate = $this->getGridFormTemplate();
70
                break;
71
        }
72
73
        parent::__construct($name, $method, $action, $target, $attributes, $trackSubmit);
74
75
        // Modify the default templates
76
        $renderer = &$this->defaultRenderer();
77
78
        $renderer->setFormTemplate($formTemplate);
79
80
        // Element template
81
        if (isset($attributes['class']) && $attributes['class'] == 'form-inline') {
82
            $elementTemplate = ' {label}  {element} ';
83
            $renderer->setElementTemplate($elementTemplate);
84
        } elseif (isset($attributes['class']) && $attributes['class'] == 'form-search') {
85
            $elementTemplate = ' {label}  {element} ';
86
            $renderer->setElementTemplate($elementTemplate);
87
        } else {
88
            $renderer->setElementTemplate($this->getDefaultElementTemplate());
89
90
            // Display a gray div in the buttons
91
            $templateSimple = '<div class="form-actions">{label} {element}</div>';
92
            $renderer->setElementTemplate($templateSimple, 'submit_in_actions');
93
94
            //Display a gray div in the buttons + makes the button available when scrolling
95
            $templateBottom = '<div class="form-actions bottom_actions bg-form">{label} {element}</div>';
96
            $renderer->setElementTemplate($templateBottom, 'submit_fixed_in_bottom');
97
            $renderer->setElementTemplate($templateSimple, 'buttons_in_action');
98
99
            $templateSimpleRight = '<div class="form-actions"> <div class="pull-right">{label} {element}</div></div>';
100
            $renderer->setElementTemplate($templateSimpleRight, 'buttons_in_action_right');
101
        }
102
103
        //Set Header template
104
        $renderer->setHeaderTemplate('<legend>{header}</legend>');
105
106
        //Set required field template
107
        $this->setRequiredNote(
108
            '<span class="form_required">*</span> <small>'.get_lang('ThisFieldIsRequired').'</small>'
109
        );
110
111
        $noteTemplate = <<<EOT
112
	<div class="form-group">
113
		<div class="col-sm-offset-2 col-sm-10">{requiredNote}</div>
114
	</div>
115
EOT;
116
        $renderer->setRequiredNoteTemplate($noteTemplate);
117
    }
118
119
    /**
120
     * @return string
121
     */
122
    public function getFormTemplate()
123
    {
124
        return '<form{attributes}>
125
        <fieldset>
126
            {content}
127
        </fieldset>
128
        {hidden}
129
        </form>';
130
    }
131
132
    /**
133
     * @return string
134
     */
135
    public function getGridFormTemplate()
136
    {
137
        return '
138
        <style>
139
140
        </style>
141
        <form{attributes}>
142
            <div class="form_list">
143
                {content}
144
            </div>
145
        {hidden}
146
        </form>';
147
    }
148
149
    /**
150
     * @todo this function should be added in the element class
151
     *
152
     * @return string
153
     */
154
    public function getDefaultElementTemplate()
155
    {
156
        return '
157
            <div class="form-group {error_class}">
158
                <label {label-for} class="col-sm-2 control-label {extra_label_class}" >
159
                    <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
160
                    {label}
161
                </label>
162
                <div class="col-sm-8">
163
                    {icon}
164
                    {element}
165
                    <!-- BEGIN label_2 -->
166
                        <p class="help-block">{label_2}</p>
167
                    <!-- END label_2 -->
168
169
                    <!-- BEGIN error -->
170
                        <span class="help-inline help-block">{error}</span>
171
                    <!-- END error -->
172
                </div>
173
                <div class="col-sm-2">
174
                    <!-- BEGIN label_3 -->
175
                        {label_3}
176
                    <!-- END label_3 -->
177
                </div>
178
            </div>';
179
    }
180
181
    /**
182
     * @return string
183
     */
184
    public function getLayout()
185
    {
186
        return $this->layout;
187
    }
188
189
    /**
190
     * @param string $layout
191
     */
192
    public function setLayout($layout)
193
    {
194
        $this->layout = $layout;
195
    }
196
197
    /**
198
     * Adds a text field to the form.
199
     * A trim-filter is attached to the field.
200
     *
201
     * @param string|array $label      The label for the form-element
202
     * @param string       $name       The element name
203
     * @param bool         $required   (optional)    Is the form-element required (default=true)
204
     * @param array        $attributes (optional)    List of attributes for the form-element
205
     *
206
     * @return HTML_QuickForm_text
207
     */
208
    public function addText($name, $label, $required = true, $attributes = [], $createElement = false)
209
    {
210
        if ($createElement) {
211
            $element = $this->createElement('text', $name, $label, $attributes);
212
        } else {
213
            $element = $this->addElement('text', $name, $label, $attributes);
214
        }
215
216
        $this->applyFilter($name, 'trim');
217
        if ($required) {
218
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
219
        }
220
221
        return $element;
222
    }
223
224
    /**
225
     * Add hidden course params.
226
     */
227
    public function addCourseHiddenParams()
228
    {
229
        $this->addHidden('cidReq', api_get_course_id());
230
        $this->addHidden('id_session', api_get_session_id());
231
    }
232
233
    /**
234
     * The "date_range_picker" element creates 2 hidden fields
235
     * "elementName" + "_start"  and "elementName" + "_end"
236
     * For example if the name is "range", you will have 2 new fields
237
     * when executing $form->getSubmitValues()
238
     * "range_start" and "range_end".
239
     *
240
     * @param string $name
241
     * @param string $label
242
     * @param bool   $required
243
     * @param array  $attributes
244
     */
245
    public function addDateRangePicker($name, $label, $required = true, $attributes = [])
246
    {
247
        $this->addElement('date_range_picker', $name, $label, $attributes);
248
        $this->addElement('hidden', $name.'_start');
249
        $this->addElement('hidden', $name.'_end');
250
251
        if ($required) {
252
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
253
        }
254
    }
255
256
    /**
257
     * @param string $name
258
     * @param string $label
259
     * @param array  $attributes
260
     *
261
     * @return DatePicker
262
     */
263
    public function addDatePicker($name, $label, $attributes = [])
264
    {
265
        return $this->addElement('DatePicker', $name, $label, $attributes);
266
    }
267
268
    /**
269
     * @param string $name
270
     * @param string $label
271
     * @param array  $attributes
272
     *
273
     * @return mixed
274
     */
275
    public function addSelectLanguage($name, $label, $options = [], $attributes = [])
276
    {
277
        return $this->addElement('SelectLanguage', $name, $label, $options, $attributes);
278
    }
279
280
    /**
281
     * @param string $name
282
     * @param string $label
283
     * @param array  $options
284
     * @param array  $attributes
285
     *
286
     * @throws Exception
287
     *
288
     * @return HTML_QuickForm_element
289
     */
290
    public function addSelectAjax($name, $label, $options = [], $attributes = [])
291
    {
292
        if (!isset($attributes['url'])) {
293
            throw new \Exception('select_ajax needs an URL');
294
        }
295
296
        return $this->addElement(
297
            'select_ajax',
298
            $name,
299
            $label,
300
            $options,
301
            $attributes
302
        );
303
    }
304
305
    /**
306
     * @param string       $name
307
     * @param string|array $label
308
     * @param array        $attributes
309
     *
310
     * @return DateTimePicker
311
     */
312
    public function addDateTimePicker($name, $label, $attributes = [])
313
    {
314
        return $this->addElement('DateTimePicker', $name, $label, $attributes);
315
    }
316
317
    /**
318
     * @param string       $name
319
     * @param string|array $label
320
     * @param array        $attributes
321
     *
322
     * @return DateTimeRangePicker
323
     */
324
    public function addDateTimeRangePicker($name, $label, $attributes = [])
325
    {
326
        return $this->addElement('DateTimeRangePicker', $name, $label, $attributes);
327
    }
328
329
    /**
330
     * @param string $name
331
     * @param string $value
332
     * @param array  $attributes
333
     */
334
    public function addHidden($name, $value, $attributes = [])
335
    {
336
        $this->addElement('hidden', $name, $value, $attributes);
337
    }
338
339
    /**
340
     * @param string       $name
341
     * @param string|array $label
342
     * @param array        $attributes
343
     * @param bool         $required
344
     *
345
     * @return HTML_QuickForm_textarea
346
     */
347
    public function addTextarea($name, $label, $attributes = [], $required = false)
348
    {
349
        $element = $this->addElement('textarea', $name, $label, $attributes);
350
351
        if ($required) {
352
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
353
        }
354
355
        return $element;
356
    }
357
358
    /**
359
     * @param string $name
360
     * @param string $label
361
     * @param string $icon          font-awesome
362
     * @param string $style         default|primary|success|info|warning|danger|link
363
     * @param string $size          large|default|small|extra-small
364
     * @param string $class         Example plus is transformed to icon fa fa-plus
365
     * @param array  $attributes
366
     * @param bool   $createElement
367
     *
368
     * @return HTML_QuickForm_button
369
     */
370
    public function addButton(
371
        $name,
372
        $label,
373
        $icon = 'check',
374
        $style = 'default',
375
        $size = 'default',
376
        $class = null,
377
        $attributes = [],
378
        $createElement = false
379
    ) {
380
        if ($createElement) {
381
            return $this->createElement(
382
                'button',
383
                $name,
384
                $label,
385
                $icon,
386
                $style,
387
                $size,
388
                $class,
389
                $attributes
390
            );
391
        }
392
393
        return $this->addElement(
394
            'button',
395
            $name,
396
            $label,
397
            $icon,
398
            $style,
399
            $size,
400
            $class,
401
            $attributes
402
        );
403
    }
404
405
    /**
406
     * Returns a button with the primary color and a check mark.
407
     *
408
     * @param string $label         Text appearing on the button
409
     * @param string $name          Element name (for form treatment purposes)
410
     * @param bool   $createElement Whether to use the create or add method
411
     *
412
     * @return HTML_QuickForm_button
413
     */
414
    public function addButtonSave($label, $name = 'submit', $createElement = false)
415
    {
416
        return $this->addButton(
417
            $name,
418
            $label,
419
            'check',
420
            'primary',
421
            null,
422
            null,
423
            [],
424
            $createElement
425
        );
426
    }
427
428
    /**
429
     * Returns a cancel button.
430
     *
431
     * @param string $label         Text appearing on the button
432
     * @param string $name          Element name (for form treatment purposes)
433
     * @param bool   $createElement Whether to use the create or add method
434
     *
435
     * @return HTML_QuickForm_button
436
     */
437
    public function addButtonCancel($label, $name = 'submit', $createElement = false)
438
    {
439
        return $this->addButton(
440
            $name,
441
            $label,
442
            'times',
443
            'danger',
444
            null,
445
            null,
446
            [],
447
            $createElement
448
        );
449
    }
450
451
    /**
452
     * Returns a button with the primary color and a "plus" icon.
453
     *
454
     * @param string $label         Text appearing on the button
455
     * @param string $name          Element name (for form treatment purposes)
456
     * @param bool   $createElement Whether to use the create or add method
457
     * @param array  $attributes    Additional attributes
458
     *
459
     * @return HTML_QuickForm_button
460
     */
461
    public function addButtonCreate($label, $name = 'submit', $createElement = false, $attributes = [])
462
    {
463
        return $this->addButton(
464
            $name,
465
            $label,
466
            'plus',
467
            'primary',
468
            null,
469
            null,
470
            $attributes,
471
            $createElement
472
        );
473
    }
474
475
    /**
476
     * Returns a button with the primary color and a pencil icon.
477
     *
478
     * @param string $label         Text appearing on the button
479
     * @param string $name          Element name (for form treatment purposes)
480
     * @param bool   $createElement Whether to use the create or add method
481
     *
482
     * @return HTML_QuickForm_button
483
     */
484
    public function addButtonUpdate($label, $name = 'submit', $createElement = false)
485
    {
486
        return $this->addButton(
487
            $name,
488
            $label,
489
            'pencil',
490
            'primary',
491
            null,
492
            null,
493
            [],
494
            $createElement
495
        );
496
    }
497
498
    /**
499
     * Returns a button with the danger color and a trash icon.
500
     *
501
     * @param string $label         Text appearing on the button
502
     * @param string $name          Element name (for form treatment purposes)
503
     * @param bool   $createElement Whether to use the create or add method
504
     *
505
     * @return HTML_QuickForm_button
506
     */
507
    public function addButtonDelete($label, $name = 'submit', $createElement = false)
508
    {
509
        return $this->addButton(
510
            $name,
511
            $label,
512
            'trash',
513
            'danger',
514
            null,
515
            null,
516
            [],
517
            $createElement
518
        );
519
    }
520
521
    /**
522
     * Returns a move style button.
523
     *
524
     * @param string $label         Text appearing on the button
525
     * @param string $name          Element name (for form treatment purposes)
526
     * @param bool   $createElement Whether to use the create or add method
527
     *
528
     * @return HTML_QuickForm_button
529
     */
530
    public function addButtonMove($label, $name = 'submit', $createElement = false)
531
    {
532
        return $this->addButton(
533
            $name,
534
            $label,
535
            'arrow-circle-right',
536
            'primary',
537
            null,
538
            null,
539
            [],
540
            $createElement
541
        );
542
    }
543
544
    /**
545
     * Returns a button with the primary color and a paper-plane icon.
546
     *
547
     * @param string $label         Text appearing on the button
548
     * @param string $name          Element name (for form treatment purposes)
549
     * @param bool   $createElement Whether to use the create or add method
550
     * @param array  $attributes
551
     * @param string $size
552
     * @param string $class
553
     *
554
     * @return HTML_QuickForm_button
555
     */
556
    public function addButtonSend(
557
        $label,
558
        $name = 'submit',
559
        $createElement = false,
560
        $attributes = [],
561
        $size = 'default',
562
        $class = ''
563
    ) {
564
        return $this->addButton(
565
            $name,
566
            $label,
567
            'paper-plane',
568
            'primary',
569
            $size,
570
            $class,
571
            $attributes,
572
            $createElement
573
        );
574
    }
575
576
    /**
577
     * Returns a button with the default (grey?) color and a magnifier icon.
578
     *
579
     * @param string $label Text appearing on the button
580
     * @param string $name  Element name (for form treatment purposes)
581
     *
582
     * @return HTML_QuickForm_button
583
     */
584
    public function addButtonSearch($label = null, $name = 'submit')
585
    {
586
        if (empty($label)) {
587
            $label = get_lang('Search');
588
        }
589
590
        return $this->addButton($name, $label, 'search', 'default');
591
    }
592
593
    /**
594
     * Returns a button with the primary color and a right-pointing arrow icon.
595
     *
596
     * @param string $label      Text appearing on the button
597
     * @param string $name       Element name (for form treatment purposes)
598
     * @param array  $attributes Additional attributes
599
     *
600
     * @return HTML_QuickForm_button
601
     */
602
    public function addButtonNext($label, $name = 'submit', $attributes = [])
603
    {
604
        return $this->addButton(
605
            $name,
606
            $label,
607
            'arrow-right',
608
            'primary',
609
            null,
610
            null,
611
            $attributes
612
        );
613
    }
614
615
    /**
616
     * Returns a button with the primary color and a check mark icon.
617
     *
618
     * @param string $label         Text appearing on the button
619
     * @param string $name          Element name (for form treatment purposes)
620
     * @param bool   $createElement Whether to use the create or add method
621
     *
622
     * @return HTML_QuickForm_button
623
     */
624
    public function addButtonImport($label, $name = 'submit', $createElement = false)
625
    {
626
        return $this->addButton(
627
            $name,
628
            $label,
629
            'check',
630
            'primary',
631
            null,
632
            null,
633
            [],
634
            $createElement
635
        );
636
    }
637
638
    /**
639
     * Returns a button with the primary color and a check-mark icon.
640
     *
641
     * @param string $label         Text appearing on the button
642
     * @param string $name          Element name (for form treatment purposes)
643
     * @param bool   $createElement Whether to use the create or add method
644
     *
645
     * @return HTML_QuickForm_button
646
     */
647
    public function addButtonExport($label, $name = 'submit', $createElement = false)
648
    {
649
        return $this->addButton(
650
            $name,
651
            $label,
652
            'check',
653
            'primary',
654
            null,
655
            null,
656
            [],
657
            $createElement
658
        );
659
    }
660
661
    /**
662
     * Shortcut to filter button.
663
     *
664
     * @param string $label         Text appearing on the button
665
     * @param string $name          Element name (for form treatment purposes)
666
     * @param bool   $createElement Whether to use the create or add method
667
     *
668
     * @return HTML_QuickForm_button
669
     */
670
    public function addButtonFilter($label, $name = 'submit', $createElement = false)
671
    {
672
        return $this->addButton(
673
            $name,
674
            $label,
675
            'filter',
676
            'primary',
677
            null,
678
            null,
679
            [],
680
            $createElement
681
        );
682
    }
683
684
    /**
685
     * Shortcut to reset button.
686
     *
687
     * @param string $label         Text appearing on the button
688
     * @param string $name          Element name (for form treatment purposes)
689
     * @param bool   $createElement Whether to use the create or add method
690
     *
691
     * @return HTML_QuickForm_button
692
     */
693
    public function addButtonReset($label, $name = 'reset', $createElement = false)
694
    {
695
        $icon = 'eraser';
696
        $style = 'default';
697
        $size = 'default';
698
        $class = null;
699
        $attributes = [];
700
701
        if ($createElement) {
702
            return $this->createElement(
703
                'reset',
704
                $name,
705
                $label,
706
                $icon,
707
                $style,
708
                $size,
709
                $class,
710
                $attributes
711
            );
712
        }
713
714
        return $this->addElement(
715
            'reset',
716
            $name,
717
            $label,
718
            $icon,
719
            $style,
720
            $size,
721
            $class,
722
            $attributes
723
        );
724
    }
725
726
    /**
727
     * Returns a button with the primary color and an upload icon.
728
     *
729
     * @param string $label         Text appearing on the button
730
     * @param string $name          Element name (for form treatment purposes)
731
     * @param bool   $createElement Whether to use the create or add method
732
     *
733
     * @return HTML_QuickForm_button
734
     */
735
    public function addButtonUpload($label, $name = 'submit', $createElement = false)
736
    {
737
        return $this->addButton(
738
            $name,
739
            $label,
740
            'upload',
741
            'primary',
742
            null,
743
            null,
744
            [],
745
            $createElement
746
        );
747
    }
748
749
    /**
750
     * Returns a button with the primary color and a download icon.
751
     *
752
     * @param string $label         Text appearing on the button
753
     * @param string $name          Element name (for form treatment purposes)
754
     * @param bool   $createElement Whether to use the create or add method
755
     *
756
     * @return HTML_QuickForm_button
757
     */
758
    public function addButtonDownload($label, $name = 'submit', $createElement = false)
759
    {
760
        return $this->addButton(
761
            $name,
762
            $label,
763
            'download',
764
            'primary',
765
            null,
766
            null,
767
            [],
768
            $createElement
769
        );
770
    }
771
772
    /**
773
     * Returns a button with the primary color and a magnifier icon.
774
     *
775
     * @param string $label         Text appearing on the button
776
     * @param string $name          Element name (for form treatment purposes)
777
     * @param bool   $createElement Whether to use the create or add method
778
     *
779
     * @return HTML_QuickForm_button
780
     */
781
    public function addButtonPreview($label, $name = 'submit', $createElement = false)
782
    {
783
        return $this->addButton(
784
            $name,
785
            $label,
786
            'search',
787
            'primary',
788
            null,
789
            null,
790
            [],
791
            $createElement
792
        );
793
    }
794
795
    /**
796
     * Returns a button with the primary color and a copy (double sheet) icon.
797
     *
798
     * @param string $label         Text appearing on the button
799
     * @param string $name          Element name (for form treatment purposes)
800
     * @param bool   $createElement Whether to use the create or add method
801
     *
802
     * @return HTML_QuickForm_button
803
     */
804
    public function addButtonCopy($label, $name = 'submit', $createElement = false)
805
    {
806
        return $this->addButton(
807
            $name,
808
            $label,
809
            'copy',
810
            'primary',
811
            null,
812
            null,
813
            [],
814
            $createElement
815
        );
816
    }
817
818
    /**
819
     * @param string $name
820
     * @param string $label
821
     * @param string $text
822
     * @param array  $attributes
823
     *
824
     * @return HTML_QuickForm_checkbox
825
     */
826
    public function addCheckBox($name, $label, $text = '', $attributes = [])
827
    {
828
        return $this->addElement('checkbox', $name, $label, $text, $attributes);
829
    }
830
831
    /**
832
     * @param string $name
833
     * @param string $label
834
     * @param array  $options
835
     * @param array  $attributes
836
     *
837
     * @return HTML_QuickForm_group
838
     */
839
    public function addCheckBoxGroup($name, $label, $options = [], $attributes = [])
840
    {
841
        $group = [];
842
        foreach ($options as $value => $text) {
843
            $attributes['value'] = $value;
844
            $group[] = $this->createElement(
845
                'checkbox',
846
                $value,
847
                null,
848
                $text,
849
                $attributes
850
            );
851
        }
852
853
        return $this->addGroup($group, $name, $label);
854
    }
855
856
    /**
857
     * @param string $name
858
     * @param string $label
859
     * @param array  $options
860
     * @param array  $attributes
861
     *
862
     * @return HTML_QuickForm_group
863
     */
864
    public function addRadio($name, $label, $options = [], $attributes = [])
865
    {
866
        $group = [];
867
        $counter = 1;
868
        foreach ($options as $key => $value) {
869
            $attributes['data-order'] = $counter;
870
            $group[] = $this->createElement('radio', null, null, $value, $key, $attributes);
871
            $counter++;
872
        }
873
874
        return $this->addGroup($group, $name, $label);
875
    }
876
877
    /**
878
     * @param string $name
879
     * @param mixed  $label      String, or array if form element with a comment
880
     * @param array  $options
881
     * @param array  $attributes
882
     *
883
     * @return HTML_QuickForm_select
884
     */
885
    public function addSelect($name, $label, $options = [], $attributes = [])
886
    {
887
        return $this->addElement('select', $name, $label, $options, $attributes);
888
    }
889
890
    /**
891
     * @param $name
892
     * @param $label
893
     * @param $collection
894
     * @param array  $attributes
895
     * @param bool   $addNoneOption
896
     * @param string $textCallable  set a function getStringValue() by default __toString()
897
     *
898
     * @return HTML_QuickForm_element
899
     */
900
    public function addSelectFromCollection(
901
        $name,
902
        $label,
903
        $collection,
904
        $attributes = [],
905
        $addNoneOption = false,
906
        $textCallable = ''
907
    ) {
908
        $options = [];
909
910
        if ($addNoneOption) {
911
            $options[0] = get_lang('None');
912
        }
913
914
        if (!empty($collection)) {
915
            foreach ($collection as $item) {
916
                $text = $item;
917
                if (!empty($textCallable)) {
918
                    $text = $item->$textCallable();
919
                }
920
                $options[$item->getId()] = $text;
921
            }
922
        }
923
924
        return $this->addElement('select', $name, $label, $options, $attributes);
925
    }
926
927
    /**
928
     * @param string $label
929
     * @param string $text
930
     * @param bool   $createElement
931
     *
932
     * @return HTML_QuickForm_Element
933
     */
934
    public function addLabel($label, $text, $createElement = false)
935
    {
936
        if ($createElement) {
937
            return $this->createElement(
938
                'label',
939
                $label,
940
                $text
941
            );
942
        }
943
944
        return $this->addElement('label', $label, $text);
945
    }
946
947
    /**
948
     * @param string $text
949
     */
950
    public function addHeader($text)
951
    {
952
        if (!empty($text)) {
953
            $this->addElement('header', $text);
954
        }
955
    }
956
957
    /**
958
     * @param string $name
959
     * @param string $label
960
     * @param array  $attributes
961
     *
962
     * @throws Exception if the file doesn't have an id
963
     *
964
     * @return HTML_QuickForm_file
965
     */
966
    public function addFile($name, $label, $attributes = [])
967
    {
968
        $element = $this->addElement('file', $name, $label, $attributes);
969
        if (isset($attributes['crop_image'])) {
970
            $id = $element->getAttribute('id');
971
            if (empty($id)) {
972
                throw new Exception('If you use the crop functionality the element must have an id');
973
            }
974
            $this->addHtml(
975
                '
976
                <div class="form-group" id="'.$id.'-form-group" style="display: none;">
977
                    <div class="col-sm-offset-2 col-sm-8">
978
                        <div id="'.$id.'_crop_image" class="cropCanvas thumbnail">
979
                            <img id="'.$id.'_preview_image">
980
                        </div>
981
                        <button class="btn btn-primary" type="button" name="cropButton" id="'.$id.'_crop_button">
982
                            <em class="fa fa-crop"></em> '.get_lang('CropYourPicture').'
983
                        </button>
984
                    </div>
985
                </div>'
986
            );
987
            $this->addHidden($id.'_crop_result', '');
988
            $this->addHidden($id.'_crop_image_base_64', '');
989
        }
990
991
        return $element;
992
    }
993
994
    /**
995
     * @param string $snippet
996
     */
997
    public function addHtml($snippet)
998
    {
999
        if (empty($snippet)) {
1000
            return false;
1001
        }
1002
        $this->addElement('html', $snippet);
1003
1004
        return true;
1005
    }
1006
1007
    /**
1008
     * Draws a panel of options see the course_info/infocours.php page.
1009
     *
1010
     * @param string $name      internal name
1011
     * @param string $title     visible title
1012
     * @param array  $groupList list of group or elements
1013
     */
1014
    public function addPanelOption($name, $title, $groupList)
1015
    {
1016
        $this->addHtml('<div class="panel panel-default">');
1017
        $this->addHtml(
1018
            '
1019
            <div class="panel-heading" role="tab" id="heading-'.$name.'-settings">
1020
                <h4 class="panel-title">
1021
                    <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion"
1022
                       href="#collapse-'.$name.'-settings" aria-expanded="false" aria-controls="collapse-'.$name.'-settings">
1023
        '
1024
        );
1025
        $this->addHtml($title);
1026
        $this->addHtml('</a></h4></div>');
1027
        $this->addHtml('<div id="collapse-'.$name.'-settings" class="panel-collapse collapse" role="tabpanel"
1028
             aria-labelledby="heading-'.$name.'-settings">
1029
            <div class="panel-body">
1030
        ');
1031
1032
        foreach ($groupList as $groupName => $group) {
1033
            // Add group array
1034
            if (!empty($groupName) && is_array($group)) {
1035
                $this->addGroup($group, '', $groupName);
1036
            }
1037
            // Add element
1038
            if ($group instanceof HTML_QuickForm_element) {
1039
                $this->addElement($group);
1040
            }
1041
        }
1042
1043
        $this->addHtml('</div></div>');
1044
        $this->addHtml('</div>');
1045
    }
1046
1047
    /**
1048
     * Adds a HTML-editor to the form.
1049
     *
1050
     * @param string       $name
1051
     * @param string|array $label    The label for the form-element
1052
     * @param bool         $required (optional) Is the form-element required (default=true)
1053
     * @param bool         $fullPage (optional) When it is true, the editor loads completed html code for a full page
1054
     * @param array        $config   (optional) Configuration settings for the online editor
1055
     */
1056
    public function addHtmlEditor(
1057
        $name,
1058
        $label,
1059
        $required = true,
1060
        $fullPage = false,
1061
        $config = []
1062
    ) {
1063
        $attributes = [];
1064
        $attributes['rows'] = isset($config['rows']) ? $config['rows'] : 15;
1065
        $attributes['cols'] = isset($config['cols']) ? $config['cols'] : 80;
1066
        $attributes['cols-size'] = isset($config['cols-size']) ? $config['cols-size'] : [];
1067
        $attributes['class'] = isset($config['class']) ? $config['class'] : [];
1068
        $attributes['id'] = isset($config['id']) ? $config['id'] : '';
1069
1070
        if (empty($attributes['id'])) {
1071
            $attributes['id'] = $name;
1072
        }
1073
1074
        $this->addElement('html_editor', $name, $label, $attributes, $config);
1075
        $this->applyFilter($name, 'trim');
1076
        if ($required) {
1077
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1078
        }
1079
1080
        /** @var HtmlEditor $element */
1081
        $element = $this->getElement($name);
1082
        $config['style'] = isset($config['style']) ? $config['style'] : false;
1083
        if ($fullPage) {
1084
            $config['fullPage'] = true;
1085
            // Adds editor_content.css in ckEditor
1086
            $config['style'] = true;
1087
        }
1088
1089
        if ($element->editor) {
1090
            $element->editor->processConfig($config);
1091
        }
1092
    }
1093
1094
    /**
1095
     * Adds a Google Maps Geolocalization field to the form.
1096
     *
1097
     * @param      $name
1098
     * @param      $label
1099
     * @param bool $hideGeoLocalizationDetails
1100
     */
1101
    public function addGeoLocationMapField($name, $label, $dataValue, $hideGeoLocalizationDetails = false)
1102
    {
1103
        $gMapsPlugin = GoogleMapsPlugin::create();
1104
        $geolocalization = $gMapsPlugin->get('enable_api') === 'true';
1105
1106
        if ($geolocalization && $gMapsPlugin->javascriptIncluded === false) {
1107
            $gmapsApiKey = $gMapsPlugin->get('api_key');
1108
            $url = '//maps.googleapis.com/maps/api/js?key='.$gmapsApiKey;
1109
            $this->addHtml('<script type="text/javascript" src="'.$url.'" ></script>');
1110
            $gMapsPlugin->javascriptIncluded = true;
1111
        }
1112
1113
        $this->addElement(
1114
            'text',
1115
            $name,
1116
            $label,
1117
            ['id' => $name]
1118
        );
1119
1120
        $this->addHidden(
1121
            $name.'_coordinates',
1122
            '',
1123
            ['id' => $name.'_coordinates']
1124
        );
1125
1126
        $this->applyFilter($name, 'stripslashes');
1127
        $this->applyFilter($name, 'trim');
1128
1129
        $this->addHtml(Extrafield::getLocalizationJavascript($name, $dataValue));
1130
1131
        if ($hideGeoLocalizationDetails) {
1132
            $this->addHtml('<div style="display:none">');
1133
        }
1134
1135
        $this->addHtml(
1136
            Extrafield::getLocalizationInput($name, $label)
1137
        );
1138
1139
        if ($hideGeoLocalizationDetails) {
1140
            $this->addHtml('</div>');
1141
        }
1142
    }
1143
1144
    /**
1145
     * @param string $name
1146
     * @param string $label
1147
     *
1148
     * @return mixed
1149
     */
1150
    public function addButtonAdvancedSettings($name, $label = '')
1151
    {
1152
        $label = !empty($label) ? $label : get_lang('AdvancedParameters');
1153
1154
        return $this->addElement('advanced_settings', $name, $label);
1155
    }
1156
1157
    /**
1158
     * Adds a progress loading image to the form.
1159
     */
1160
    public function addProgress($delay = 2, $label = '')
1161
    {
1162
        if (empty($label)) {
1163
            $label = get_lang('PleaseStandBy');
1164
        }
1165
        $this->with_progress_bar = true;
1166
        $id = $this->getAttribute('id');
1167
1168
        $this->updateAttributes("onsubmit=\"javascript: addProgress('".$id."')\"");
1169
        $this->addHtml('<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/upload.js" type="text/javascript"></script>');
1170
    }
1171
1172
    /**
1173
     * This function has been created for avoiding changes directly within QuickForm class.
1174
     * When we use it, the element is threated as 'required' to be dealt during validation.
1175
     *
1176
     * @param array  $elements The array of elements
1177
     * @param string $message  The message displayed
1178
     */
1179
    public function add_multiple_required_rule($elements, $message)
1180
    {
1181
        $this->_required[] = $elements[0];
1182
        $this->addRule($elements, $message, 'multiple_required');
1183
    }
1184
1185
    /**
1186
     * Displays the form.
1187
     * If an element in the form didn't validate, an error message is showed
1188
     * asking the user to complete the form.
1189
     */
1190
    public function display()
1191
    {
1192
        echo $this->returnForm();
1193
    }
1194
1195
    /**
1196
     * Returns the HTML code of the form.
1197
     *
1198
     * @return string $return_value HTML code of the form
1199
     */
1200
    public function returnForm()
1201
    {
1202
        $returnValue = '';
1203
1204
        /** @var HTML_QuickForm_element $element */
1205
        foreach ($this->_elements as &$element) {
1206
            $element->setLayout($this->getLayout());
1207
            $elementError = parent::getElementError($element->getName());
1208
            if (!is_null($elementError)) {
1209
                $returnValue .= Display::return_message($elementError, 'warning').'<br />';
1210
                break;
1211
            }
1212
        }
1213
1214
        $returnValue .= parent::toHtml();
1215
        // Add div-element which is to hold the progress bar
1216
        $id = $this->getAttribute('id');
1217
        if (isset($this->with_progress_bar) && $this->with_progress_bar) {
1218
            // @todo improve UI
1219
            $returnValue .= '<br />
1220
            <div id="loading_div_'.$id.'" class="loading_div" style="display:none;margin-left:40%; margin-top:10px; height:50px;">
1221
                <div class="wobblebar-loader"></div>
1222
            </div>
1223
            ';
1224
        }
1225
1226
        return $returnValue;
1227
    }
1228
1229
    /**
1230
     * Returns the HTML code of the form.
1231
     * If an element in the form didn't validate, an error message is showed
1232
     * asking the user to complete the form.
1233
     *
1234
     * @return string $return_value HTML code of the form
1235
     *
1236
     * @author Patrick Cool <[email protected]>, Ghent University, august 2006
1237
     * @author Julio Montoya
1238
     *
1239
     * @deprecated use returnForm()
1240
     */
1241
    public function return_form()
1242
    {
1243
        return $this->returnForm();
1244
    }
1245
1246
    /**
1247
     * @return HTML_QuickForm_Renderer_Default
1248
     */
1249
    public static function getDefaultRenderer()
1250
    {
1251
        return
1252
            isset($GLOBALS['_HTML_QuickForm_default_renderer']) ?
1253
                $GLOBALS['_HTML_QuickForm_default_renderer'] : null;
1254
    }
1255
1256
    /**
1257
     * Adds a input of type url to the form.
1258
     *
1259
     * @param string $name       The label for the form-element
1260
     * @param string $label      The element name
1261
     * @param bool   $required   Optional. Is the form-element required (default=true)
1262
     * @param array  $attributes Optional. List of attributes for the form-element
1263
     */
1264
    public function addUrl($name, $label, $required = true, $attributes = [])
1265
    {
1266
        $this->addElement('url', $name, $label, $attributes);
1267
        $this->applyFilter($name, 'trim');
1268
        $this->addRule($name, get_lang('InsertAValidUrl'), 'url');
1269
1270
        if ($required) {
1271
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1272
        }
1273
    }
1274
1275
    /**
1276
     * Adds a text field for letters to the form.
1277
     * A trim-filter is attached to the field.
1278
     *
1279
     * @param string $name       The element name
1280
     * @param string $label      The label for the form-element
1281
     * @param bool   $required   Optional. Is the form-element required (default=true)
1282
     * @param array  $attributes Optional. List of attributes for the form-element
1283
     */
1284
    public function addTextLettersOnly(
1285
        $name,
1286
        $label,
1287
        $required = false,
1288
        $attributes = []
1289
    ) {
1290
        $attributes = array_merge(
1291
            $attributes,
1292
            [
1293
                'pattern' => '[a-zA-ZñÑ]+',
1294
                'title' => get_lang('OnlyLetters'),
1295
            ]
1296
        );
1297
1298
        $this->addElement(
1299
            'text',
1300
            $name,
1301
            [
1302
                $label,
1303
                get_lang('OnlyLetters'),
1304
            ],
1305
            $attributes
1306
        );
1307
1308
        $this->applyFilter($name, 'trim');
1309
1310
        if ($required) {
1311
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1312
        }
1313
1314
        $this->addRule(
1315
            $name,
1316
            get_lang('OnlyLetters'),
1317
            'regex',
1318
            '/^[a-zA-ZñÑ]+$/'
1319
        );
1320
    }
1321
1322
    /**
1323
     * @param string $name
1324
     * @param string $label
1325
     * @param array  $attributes
1326
     * @param bool   $required
1327
     *
1328
     * @return HTML_QuickForm_element
1329
     */
1330
    public function addNumeric($name, $label, $attributes = [], $required = false)
1331
    {
1332
        $element = $this->addElement('Number', $name, $label, $attributes);
1333
1334
        if ($required) {
1335
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1336
        }
1337
1338
        return $element;
1339
    }
1340
1341
    /**
1342
     * Adds a text field for alphanumeric characters to the form.
1343
     * A trim-filter is attached to the field.
1344
     *
1345
     * @param string $name       The element name
1346
     * @param string $label      The label for the form-element
1347
     * @param bool   $required   Optional. Is the form-element required (default=true)
1348
     * @param array  $attributes Optional. List of attributes for the form-element
1349
     */
1350
    public function addTextAlphanumeric(
1351
        $name,
1352
        $label,
1353
        $required = false,
1354
        $attributes = []
1355
    ) {
1356
        $attributes = array_merge(
1357
            $attributes,
1358
            [
1359
                'pattern' => '[a-zA-Z0-9ñÑ]+',
1360
                'title' => get_lang('OnlyLettersAndNumbers'),
1361
            ]
1362
        );
1363
1364
        $this->addElement(
1365
            'text',
1366
            $name,
1367
            [
1368
                $label,
1369
                get_lang('OnlyLettersAndNumbers'),
1370
            ],
1371
            $attributes
1372
        );
1373
1374
        $this->applyFilter($name, 'trim');
1375
1376
        if ($required) {
1377
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1378
        }
1379
1380
        $this->addRule(
1381
            $name,
1382
            get_lang('OnlyLettersAndNumbers'),
1383
            'regex',
1384
            '/^[a-zA-Z0-9ÑÑ]+$/'
1385
        );
1386
    }
1387
1388
    /**
1389
     * @param string $name
1390
     * @param $label
1391
     * @param bool  $required
1392
     * @param array $attributes
1393
     * @param bool  $allowNegative
1394
     * @param int   $minValue
1395
     * @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...
1396
     */
1397
    public function addFloat(
1398
        $name,
1399
        $label,
1400
        $required = false,
1401
        $attributes = [],
1402
        $allowNegative = false,
1403
        $minValue = null,
1404
        $maxValue = null
1405
    ) {
1406
        $this->addElement(
1407
            'FloatNumber',
1408
            $name,
1409
            $label,
1410
            $attributes
1411
        );
1412
1413
        $this->applyFilter($name, 'trim');
1414
1415
        if ($required) {
1416
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1417
        }
1418
1419
        // Rule allows "," and "."
1420
        /*$this->addRule(
1421
            $name,
1422
            get_lang('OnlyNumbers'),
1423
            'regex',
1424
            '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d\d*\,\d*$)|(^-?\,\d\d*$)/'
1425
        );*/
1426
1427
        if ($allowNegative == false) {
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...
1428
            $this->addRule(
1429
                $name,
1430
                get_lang('NegativeValue'),
1431
                'compare',
1432
                '>=',
1433
                'server',
1434
                false,
1435
                false,
1436
                0
1437
            );
1438
        }
1439
1440
        if (!is_null($minValue)) {
1441
            $this->addRule(
1442
                $name,
1443
                get_lang('UnderMin'),
1444
                'compare',
1445
                '>=',
1446
                'server',
1447
                false,
1448
                false,
1449
                $minValue
1450
            );
1451
        }
1452
1453
        if (!is_null($maxValue)) {
1454
            $this->addRule(
1455
                $name,
1456
                get_lang('OverMax'),
1457
                'compare',
1458
                '<=',
1459
                'server',
1460
                false,
1461
                false,
1462
                $maxValue
1463
            );
1464
        }
1465
    }
1466
1467
    /**
1468
     * Adds a text field for letters and spaces to the form.
1469
     * A trim-filter is attached to the field.
1470
     *
1471
     * @param string $name       The element name
1472
     * @param string $label      The label for the form-element
1473
     * @param bool   $required   Optional. Is the form-element required (default=true)
1474
     * @param array  $attributes Optional. List of attributes for the form-element
1475
     */
1476
    public function addTextLettersAndSpaces(
1477
        $name,
1478
        $label,
1479
        $required = false,
1480
        $attributes = []
1481
    ) {
1482
        $attributes = array_merge(
1483
            $attributes,
1484
            [
1485
                'pattern' => '[a-zA-ZñÑ\s]+',
1486
                'title' => get_lang('OnlyLettersAndSpaces'),
1487
            ]
1488
        );
1489
1490
        $this->addElement(
1491
            'text',
1492
            $name,
1493
            [
1494
                $label,
1495
                get_lang('OnlyLettersAndSpaces'),
1496
            ],
1497
            $attributes
1498
        );
1499
1500
        $this->applyFilter($name, 'trim');
1501
1502
        if ($required) {
1503
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1504
        }
1505
1506
        $this->addRule(
1507
            $name,
1508
            get_lang('OnlyLettersAndSpaces'),
1509
            'regex',
1510
            '/^[a-zA-ZñÑ\s]+$/'
1511
        );
1512
    }
1513
1514
    /**
1515
     * Adds a text field for alphanumeric and spaces characters to the form.
1516
     * A trim-filter is attached to the field.
1517
     *
1518
     * @param string $name       The element name
1519
     * @param string $label      The label for the form-element
1520
     * @param bool   $required   Optional. Is the form-element required (default=true)
1521
     * @param array  $attributes Optional. List of attributes for the form-element
1522
     */
1523
    public function addTextAlphanumericAndSpaces(
1524
        $name,
1525
        $label,
1526
        $required = false,
1527
        $attributes = []
1528
    ) {
1529
        $attributes = array_merge(
1530
            $attributes,
1531
            [
1532
                'pattern' => '[a-zA-Z0-9ñÑ\s]+',
1533
                'title' => get_lang('OnlyLettersAndNumbersAndSpaces'),
1534
            ]
1535
        );
1536
1537
        $this->addElement(
1538
            'text',
1539
            $name,
1540
            [
1541
                $label,
1542
                get_lang('OnlyLettersAndNumbersAndSpaces'),
1543
            ],
1544
            $attributes
1545
        );
1546
1547
        $this->applyFilter($name, 'trim');
1548
1549
        if ($required) {
1550
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1551
        }
1552
1553
        $this->addRule(
1554
            $name,
1555
            get_lang('OnlyLettersAndNumbersAndSpaces'),
1556
            'regex',
1557
            '/^[a-zA-Z0-9ñÑ\s]+$/'
1558
        );
1559
    }
1560
1561
    /**
1562
     * @param string $url
1563
     * @param string $urlToRedirect after upload redirect to this page
1564
     */
1565
    public function addMultipleUpload($url, $urlToRedirect = '')
1566
    {
1567
        $inputName = 'input_file_upload';
1568
        $this->addMultipleUploadJavascript($url, $inputName, $urlToRedirect);
1569
1570
        $this->addHtml('
1571
            <div class="description-upload">
1572
            '.get_lang('ClickToSelectOrDragAndDropMultipleFilesOnTheUploadField').'
1573
            </div>
1574
            <span class="btn btn-success fileinput-button">
1575
                <i class="glyphicon glyphicon-plus"></i>
1576
                <span>'.get_lang('AddFiles').'</span>
1577
                <!-- The file input field used as target for the file upload widget -->
1578
                <input id="'.$inputName.'" type="file" name="files[]" multiple>
1579
            </span>
1580
            <div id="dropzone">
1581
                <div class="button-load">
1582
                '.get_lang('UploadFiles').'
1583
                </div>
1584
            </div>
1585
            <br />
1586
            <!-- The global progress bar -->
1587
            <div id="progress" class="progress">
1588
                <div class="progress-bar progress-bar-success"></div>
1589
            </div>
1590
            <div id="files" class="files"></div>
1591
        ');
1592
    }
1593
1594
    /**
1595
     * @throws Exception
1596
     */
1597
    public function addNoSamePasswordRule(string $elementName, User $user)
1598
    {
1599
        $passwordRequirements = api_get_configuration_value('password_requirements');
1600
1601
        if (!empty($passwordRequirements) && $passwordRequirements['force_different_password']) {
1602
            $this->addRule(
1603
                $elementName,
1604
                get_lang('NewPasswordCannotBeSameAsCurrent'),
1605
                'no_same_current_password',
1606
                $user
1607
            );
1608
        }
1609
    }
1610
1611
    /**
1612
     * @param string $elementName
1613
     * @param string $groupName   if element is inside a group
1614
     *
1615
     * @throws Exception
1616
     */
1617
    public function addPasswordRule($elementName, $groupName = '')
1618
    {
1619
        // Constant defined in old config/profile.conf.php
1620
        if (CHECK_PASS_EASY_TO_FIND === true) {
0 ignored issues
show
Bug introduced by
The constant CHECK_PASS_EASY_TO_FIND was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1621
            $message = get_lang('PassTooEasy').': '.api_generate_password();
1622
1623
            if (!empty($groupName)) {
1624
                $groupObj = $this->getElement($groupName);
1625
1626
                if ($groupObj instanceof HTML_QuickForm_group) {
1627
                    $elementName = $groupObj->getElementName($elementName);
1628
1629
                    if ($elementName === false) {
1630
                        throw new Exception("The $groupName doesn't have the element $elementName");
1631
                    }
1632
1633
                    $this->_rules[$elementName][] = [
1634
                        'type' => 'callback',
1635
                        'format' => 'api_check_password',
1636
                        'message' => $message,
1637
                        'validation' => '',
1638
                        'reset' => false,
1639
                        'group' => $groupName,
1640
                    ];
1641
                }
1642
            } else {
1643
                $this->addRule(
1644
                    $elementName,
1645
                    $message,
1646
                    'callback',
1647
                    'api_check_password'
1648
                );
1649
            }
1650
1651
            if (!$this->isSubmitted()) {
1652
                $element = $this->getElement($elementName);
1653
                $label = $element->getLabel();
1654
                $element->setLabel([
1655
                    $label,
1656
                    Security::getPasswordRequirementsToString(),
1657
                ]);
1658
            }
1659
        }
1660
    }
1661
1662
    /**
1663
     * Add an element with user ID and avatar to the form.
1664
     * It needs a Chamilo\UserBundle\Entity\User as value. The exported value is the Chamilo\UserBundle\Entity\User ID.
1665
     *
1666
     * @see \UserAvatar
1667
     *
1668
     * @param string $name
1669
     * @param string $label
1670
     * @param string $imageSize Optional. Small, medium or large image
1671
     * @param string $subtitle  Optional. The subtitle for the field
1672
     *
1673
     * @return \UserAvatar
1674
     */
1675
    public function addUserAvatar($name, $label, $imageSize = 'small', $subtitle = '')
1676
    {
1677
        return $this->addElement('UserAvatar', $name, $label, ['image_size' => $imageSize, 'sub_title' => $subtitle]);
1678
    }
1679
1680
    public function addCaptcha()
1681
    {
1682
        $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
1683
        $options = [
1684
            'width' => 220,
1685
            'height' => 90,
1686
            'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
1687
            'sessionVar' => basename(__FILE__, '.php'),
1688
            'imageOptions' => [
1689
                'font_size' => 20,
1690
                'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
1691
                'font_file' => 'OpenSans-Regular.ttf',
1692
                //'output' => 'gif'
1693
            ],
1694
        ];
1695
1696
        $captcha_question = $this->addElement(
1697
            'CAPTCHA_Image',
1698
            'captcha_question',
1699
            '',
1700
            $options
1701
        );
1702
        $this->addElement('static', null, null, get_lang('ClickOnTheImageForANewOne'));
1703
1704
        $this->addElement(
1705
            'text',
1706
            'captcha',
1707
            get_lang('EnterTheLettersYouSee'),
1708
            ['size' => 40]
1709
        );
1710
        $this->addRule(
1711
            'captcha',
1712
            get_lang('EnterTheCharactersYouReadInTheImage'),
1713
            'required',
1714
            null,
1715
            'client'
1716
        );
1717
        $this->addRule(
1718
            'captcha',
1719
            get_lang('TheTextYouEnteredDoesNotMatchThePicture'),
1720
            'CAPTCHA',
1721
            $captcha_question
1722
        );
1723
    }
1724
1725
    /**
1726
     * @param array $typeList
1727
     */
1728
    public function addEmailTemplate($typeList)
1729
    {
1730
        $mailManager = new MailTemplateManager();
1731
        foreach ($typeList as $type) {
1732
            $list = $mailManager->get_all(
1733
                ['where' => ['type = ? AND url_id = ?' => [$type, api_get_current_access_url_id()]]]
1734
            );
1735
1736
            $options = [get_lang('Select')];
1737
            $name = $type;
1738
            $defaultId = '';
1739
            foreach ($list as $item) {
1740
                $options[$item['id']] = $item['name'];
1741
                $name = $item['name'];
1742
                if (empty($defaultId)) {
1743
                    $defaultId = $item['default_template'] == 1 ? $item['id'] : '';
1744
                }
1745
            }
1746
1747
            $url = api_get_path(WEB_AJAX_PATH).'mail.ajax.php?a=select_option';
1748
            $typeNoDots = 'email_template_option_'.str_replace('.tpl', '', $type);
1749
            $this->addSelect(
1750
                'email_template_option['.$type.']',
1751
                $name,
1752
                $options,
1753
                ['id' => $typeNoDots]
1754
            );
1755
1756
            $templateNoDots = 'email_template_'.str_replace('.tpl', '', $type);
1757
            $templateNoDotsBlock = 'email_template_block_'.str_replace('.tpl', '', $type);
1758
            $this->addHtml('<div id="'.$templateNoDotsBlock.'" style="display:none">');
1759
            $this->addTextarea(
1760
                $templateNoDots,
1761
                get_lang('Preview'),
1762
                ['disabled' => 'disabled ', 'id' => $templateNoDots, 'rows' => '5']
1763
            );
1764
            $this->addHtml('</div>');
1765
1766
            $this->addHtml("<script>
1767
            $(function() {
1768
                var defaultValue = '$defaultId';
1769
                $('#$typeNoDots').val(defaultValue);
1770
                $('#$typeNoDots').selectpicker('render');
1771
                if (defaultValue != '') {
1772
                    var selected = $('#$typeNoDots option:selected').val();
1773
                    $.ajax({
1774
                        url: '$url' + '&id=' + selected+ '&template_name=$type',
1775
                        success: function (data) {
1776
                            $('#$templateNoDots').html(data);
1777
                            $('#$templateNoDotsBlock').show();
1778
                            return;
1779
                        },
1780
                    });
1781
                }
1782
1783
                $('#$typeNoDots').on('change', function(){
1784
                    var selected = $('#$typeNoDots option:selected').val();
1785
                    $.ajax({
1786
                        url: '$url' + '&id=' + selected,
1787
                        success: function (data) {
1788
                            $('#$templateNoDots').html(data);
1789
                            $('#$templateNoDotsBlock').show();
1790
                            return;
1791
                        },
1792
                    });
1793
                });
1794
            });
1795
            </script>");
1796
        }
1797
    }
1798
1799
    /**
1800
     * @param string $url           page that will handle the upload
1801
     * @param string $inputName
1802
     * @param string $urlToRedirect
1803
     */
1804
    private function addMultipleUploadJavascript($url, $inputName, $urlToRedirect = '')
1805
    {
1806
        $redirectCondition = '';
1807
        if (!empty($urlToRedirect)) {
1808
            $redirectCondition = "window.location.replace('$urlToRedirect'); ";
1809
        }
1810
        $icon = Display::return_icon('file_txt.gif');
1811
        $this->addHtml("
1812
        <script>
1813
        $(function () {
1814
            'use strict';
1815
            $('#".$this->getAttribute('id')."').submit(function() {
1816
                return false;
1817
            });
1818
1819
            $('#dropzone').on('click', function() {
1820
                $('#".$inputName."').click();
1821
            });
1822
1823
            var url = '".$url."';
1824
            var uploadButton = $('<button/>')
1825
                .addClass('btn btn-primary')
1826
                .prop('disabled', true)
1827
                .text('".addslashes(get_lang('Loading'))."')
1828
                .on('click', function () {
1829
                    var \$this = $(this),
1830
                    data = \$this.data();
1831
                    \$this
1832
                        .off('click')
1833
                        .text('".addslashes(get_lang('Cancel'))."')
1834
                        .on('click', function () {
1835
                            \$this.remove();
1836
                            data.abort();
1837
                        });
1838
                    data.submit().always(function () {
1839
                        \$this.remove();
1840
                    });
1841
                });
1842
1843
            var counter = 0,
1844
                total = 0;
1845
            $('#".$inputName."').fileupload({
1846
                url: url,
1847
                dataType: 'json',
1848
                // Enable image resizing, except for Android and Opera,
1849
                // which actually support image resizing, but fail to
1850
                // send Blob objects via XHR requests:
1851
                disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent),
1852
                previewMaxWidth: 300,
1853
                previewMaxHeight: 169,
1854
                previewCrop: true,
1855
                dropzone: $('#dropzone'),
1856
                maxChunkSize: 10000000, // 10 MB
1857
                sequentialUploads: true,
1858
            }).on('fileuploadchunksend', function (e, data) {
1859
                console.log('fileuploadchunkbeforesend');
1860
                console.log(data);
1861
                data.url = url + '&chunkAction=send';
1862
            }).on('fileuploadchunkdone', function (e, data) {
1863
                console.log('fileuploadchunkdone');
1864
                console.log(data);
1865
                if (data.uploadedBytes >= data.total) {
1866
                    data.url = url + '&chunkAction=done';
1867
                    data.submit();
1868
                }
1869
            }).on('fileuploadchunkfail', function (e, data) {
1870
                console.log('fileuploadchunkfail');
1871
                console.log(data);
1872
1873
            }).on('fileuploadadd', function (e, data) {
1874
                data.context = $('<div class=\"row\" />').appendTo('#files');
1875
                $.each(data.files, function (index, file) {
1876
                    var node = $('<div class=\"col-sm-5 file_name\">').text(file.name);
1877
                    node.appendTo(data.context);
1878
                    var iconLoading = $('<div class=\"col-sm-3\">').html(
1879
                        $('<span id=\"image-loading'+index+'\"/>').html('".Display::return_icon('loading1.gif', get_lang('Uploading'), [], ICON_SIZE_MEDIUM)."')
1880
                    );
1881
                    $(data.context.children()[index]).parent().append(iconLoading);
1882
                    total++;
1883
                });
1884
            }).on('fileuploadprocessalways', function (e, data) {
1885
                var index = data.index,
1886
                    file = data.files[index],
1887
                    node = $(data.context.children()[index]);
1888
                if (file.preview) {
1889
                    data.context.prepend($('<div class=\"col-sm-4\">').html(file.preview));
1890
                } else {
1891
                    data.context.prepend($('<div class=\"col-sm-4\">').html('".$icon."'));
1892
                }
1893
                if (index + 1 === data.files.length) {
1894
                    data.context.find('button')
1895
                        .text('Upload')
1896
                        .prop('disabled', !!data.files.error);
1897
                }
1898
            }).on('fileuploadprogressall', function (e, data) {
1899
                var progress = parseInt(data.loaded / data.total * 100, 10) - 2;
1900
                $('#progress .progress-bar').css(
1901
                    'width',
1902
                    progress + '%'
1903
                );
1904
                $('#progress .progress-bar').text(progress + '%');
1905
            }).on('fileuploaddone', function (e, data) {
1906
                $.each(data.result.files, function (index, file) {
1907
                    if (file.error) {
1908
                        var link = $('<div>')
1909
                            .attr({class : 'panel-image'})                            ;
1910
                        $(data.context.children()[index]).parent().wrap(link);
1911
                        // Update file name with new one from Chamilo
1912
                        $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1913
                        var message = $('<div class=\"col-sm-3\">').html(
1914
                            $('<span class=\"message-image-danger\"/>').text(file.error)
1915
                        );
1916
                        $(data.context.children()[index]).parent().append(message);
1917
1918
                        return;
1919
                    }
1920
                    if (file.url) {
1921
                        var link = $('<a>')
1922
                            .attr({target: '_blank', class : 'panel-image'})
1923
                            .prop('href', file.url);
1924
                        $(data.context.children()[index]).parent().wrap(link);
1925
                    }
1926
                    // Update file name with new one from Chamilo
1927
                    $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1928
                    $('#image-loading'+index).remove();
1929
                    var message = $('<div class=\"col-sm-3\">').html(
1930
                        $('<span class=\"message-image-success\"/>').text('".addslashes(get_lang('UplUploadSucceeded'))."')
1931
                    );
1932
                    $(data.context.children()[index]).parent().append(message);
1933
                    counter++;
1934
                });
1935
                if (counter == total) {
1936
                    $('#progress .progress-bar').css('width', '100%');
1937
                    $('#progress .progress-bar').text('100%');
1938
                }
1939
                $('#dropzone').removeClass('hover');
1940
                ".$redirectCondition."
1941
            }).on('fileuploadfail', function (e, data) {
1942
                $.each(data.files, function (index) {
1943
                    var failedMessage = '".addslashes(get_lang('UplUploadFailed'))."';
1944
                    var error = $('<div class=\"col-sm-3\">').html(
1945
                        $('<span class=\"alert alert-danger\"/>').text(failedMessage)
1946
                    );
1947
                    $(data.context.children()[index]).parent().append(error);
1948
                });
1949
                $('#dropzone').removeClass('hover');
1950
            }).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');
1951
1952
            $('#dropzone').on('dragover', function (e) {
1953
                // dragleave callback implementation
1954
                $('#dropzone').addClass('hover');
1955
            });
1956
1957
            $('#dropzone').on('dragleave', function (e) {
1958
                $('#dropzone').removeClass('hover');
1959
            });
1960
            $('.fileinput-button').hide();
1961
        });
1962
        </script>");
1963
    }
1964
}
1965
1966
/**
1967
 * Cleans HTML text filter.
1968
 *
1969
 * @param string $html HTML to clean
1970
 * @param int    $mode (optional)
1971
 *
1972
 * @return string The cleaned HTML
1973
 */
1974
function html_filter($html, $mode = NO_HTML)
1975
{
1976
    $allowed_tags = HTML_QuickForm_Rule_HTML::get_allowed_tags($mode);
1977
    $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

1977
    $cleaned_html = /** @scrutinizer ignore-call */ kses($html, $allowed_tags);
Loading history...
1978
1979
    return $cleaned_html;
1980
}
1981
1982
function html_filter_teacher($html)
1983
{
1984
    return html_filter($html, TEACHER_HTML);
1985
}
1986
1987
function html_filter_student($html)
1988
{
1989
    return html_filter($html, STUDENT_HTML);
1990
}
1991
1992
function html_filter_teacher_fullpage($html)
1993
{
1994
    return html_filter($html, TEACHER_HTML_FULLPAGE);
1995
}
1996
1997
function html_filter_student_fullpage($html)
1998
{
1999
    return html_filter($html, STUDENT_HTML_FULLPAGE);
2000
}
2001
2002
/**
2003
 * Cleans mobile phone number text.
2004
 *
2005
 * @param string $mobilePhoneNumber Mobile phone number to clean
2006
 *
2007
 * @return string The cleaned mobile phone number
2008
 */
2009
function mobile_phone_number_filter($mobilePhoneNumber)
2010
{
2011
    $mobilePhoneNumber = str_replace(['+', '(', ')'], '', $mobilePhoneNumber);
2012
2013
    return ltrim($mobilePhoneNumber, '0');
2014
}
2015