Passed
Pull Request — 1.11.x (#4367)
by Angel Fernando Quiroz
08:56
created

FormValidator::getTimepickerIncrement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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

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