Completed
Push — master ( ae5621...ef667c )
by Julito
13:23
created

FormValidator::addButtonDownload()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 3
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Class FormValidator
6
 * create/manipulate/validate user input.
7
 */
8
class FormValidator extends HTML_QuickForm
9
{
10
    const LAYOUT_HORIZONTAL = 'horizontal';
11
    const LAYOUT_INLINE = 'inline';
12
    const LAYOUT_BOX = 'box';
13
    const LAYOUT_BOX_NO_LABEL = 'box-no-label';
14
15
    public $with_progress_bar = false;
16
    private $layout;
17
18
    /**
19
     * Constructor.
20
     *
21
     * @param string $name        Name of the form
22
     * @param string $method      (optional) Method ('post' (default) or 'get')
23
     * @param string $action      (optional) Action (default is $PHP_SELF)
24
     * @param string $target      (optional) Form's target defaults to '_self'
25
     * @param mixed  $attributes  (optional) Extra attributes for <form> tag
26
     * @param string $layout
27
     * @param bool   $trackSubmit (optional) Whether to track if the form was
28
     *                            submitted by adding a special hidden field (default = true)
29
     */
30
    public function __construct(
31
        $name,
32
        $method = 'post',
33
        $action = '',
34
        $target = '',
35
        $attributes = [],
36
        $layout = self::LAYOUT_HORIZONTAL,
37
        $trackSubmit = true
38
    ) {
39
        // Default form class.
40
        if (is_array($attributes) && !isset($attributes['class']) || empty($attributes)) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: {currentAssign}, Probably Intended Meaning: {alternativeAssign}
Loading history...
41
            $attributes['class'] = 'form-horizontal';
42
        }
43
44
        if (isset($attributes['class']) && strpos($attributes['class'], 'form-search') !== false) {
45
            $layout = 'inline';
46
        }
47
48
        $this->setLayout($layout);
49
50
        switch ($layout) {
51
            case self::LAYOUT_HORIZONTAL:
52
                $attributes['class'] = 'form-horizontal';
53
                break;
54
            case self::LAYOUT_INLINE:
55
            case self::LAYOUT_BOX:
56
                $attributes['class'] = 'form-inline';
57
                break;
58
        }
59
60
        parent::__construct($name, $method, $action, $target, $attributes, $trackSubmit);
61
62
        // Modify the default templates
63
        $renderer = &$this->defaultRenderer();
64
65
        // Form template
66
        $formTemplate = $this->getFormTemplate();
67
        $renderer->setFormTemplate($formTemplate);
68
69
        // Element template
70
        if (isset($attributes['class']) && $attributes['class'] == 'form-inline') {
71
            $elementTemplate = ' {label}  {element} ';
72
            $renderer->setElementTemplate($elementTemplate);
73
        } elseif (isset($attributes['class']) && $attributes['class'] == 'form-search') {
74
            $elementTemplate = ' {label}  {element} ';
75
            $renderer->setElementTemplate($elementTemplate);
76
        } else {
77
            $renderer->setElementTemplate($this->getDefaultElementTemplate());
78
79
            // Display a gray div in the buttons
80
            $templateSimple = '<div class="form-actions">{label} {element}</div>';
81
            $renderer->setElementTemplate($templateSimple, 'submit_in_actions');
82
83
            //Display a gray div in the buttons + makes the button available when scrolling
84
            $templateBottom = '<div class="form-actions bottom_actions bg-form">{label} {element}</div>';
85
            $renderer->setElementTemplate($templateBottom, 'submit_fixed_in_bottom');
86
87
            //When you want to group buttons use something like this
88
            /* $group = array();
89
              $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
90
              $group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
91
              $form->addGroup($group, 'buttons_in_action');
92
             */
93
            $renderer->setElementTemplate($templateSimple, 'buttons_in_action');
94
95
            $templateSimpleRight = '<div class="form-actions"> <div class="pull-right">{label} {element}</div></div>';
96
            $renderer->setElementTemplate($templateSimpleRight, 'buttons_in_action_right');
97
        }
98
99
        //Set Header template
100
        $renderer->setHeaderTemplate('<legend>{header}</legend>');
101
102
        //Set required field template
103
        $this->setRequiredNote(
104
            '<span class="form_required">*</span> <small>'.get_lang('ThisFieldIsRequired').'</small>'
105
        );
106
107
        $noteTemplate = <<<EOT
108
	<div class="form-group">
109
		<div class="col-sm-offset-2 col-sm-10">{requiredNote}</div>
110
	</div>
111
EOT;
112
        $renderer->setRequiredNoteTemplate($noteTemplate);
113
    }
114
115
    /**
116
     * @return string
117
     */
118
    public function getFormTemplate()
119
    {
120
        return '<form{attributes}>
121
        <fieldset>
122
            {content}
123
        </fieldset>
124
        {hidden}
125
        </form>';
126
    }
127
128
    /**
129
     * @todo this function should be added in the element class
130
     *
131
     * @return string
132
     */
133
    public function getDefaultElementTemplate()
134
    {
135
        return '
136
            <div class="form-group {error_class}">
137
                <label {label-for} class="col-sm-2 control-label {extra_label_class}" >
138
                    <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
139
                    {label}
140
                </label>
141
                <div class="col-sm-8">
142
                    {icon}
143
                    {element}
144
145
                    <!-- BEGIN label_2 -->
146
                        <p class="help-block">{label_2}</p>
147
                    <!-- END label_2 -->
148
149
                    <!-- BEGIN error -->
150
                        <span class="help-inline help-block">{error}</span>
151
                    <!-- END error -->
152
                </div>
153
                <div class="col-sm-2">
154
                    <!-- BEGIN label_3 -->
155
                        {label_3}
156
                    <!-- END label_3 -->
157
                </div>
158
            </div>';
159
    }
160
161
    /**
162
     * @return string
163
     */
164
    public function getLayout()
165
    {
166
        return $this->layout;
167
    }
168
169
    /**
170
     * @param string $layout
171
     */
172
    public function setLayout($layout)
173
    {
174
        $this->layout = $layout;
175
    }
176
177
    /**
178
     * Adds a text field to the form.
179
     * A trim-filter is attached to the field.
180
     *
181
     * @param string|array $label      The label for the form-element
182
     * @param string       $name       The element name
183
     * @param bool         $required   (optional)    Is the form-element required (default=true)
184
     * @param array        $attributes (optional)    List of attributes for the form-element
185
     *
186
     * @return HTML_QuickForm_text
187
     */
188
    public function addText($name, $label, $required = true, $attributes = [])
189
    {
190
        $element = $this->addElement('text', $name, $label, $attributes);
191
        $this->applyFilter($name, 'trim');
192
        if ($required) {
193
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
194
        }
195
196
        return $element;
197
    }
198
199
    /**
200
     * The "date_range_picker" element creates 2 hidden fields
201
     * "elementName" + "_start"  and "elementName" + "_end"
202
     * For example if the name is "range", you will have 2 new fields
203
     * when executing $form->getSubmitValues()
204
     * "range_start" and "range_end".
205
     *
206
     * @param string $name
207
     * @param string $label
208
     * @param bool   $required
209
     * @param array  $attributes
210
     */
211
    public function addDateRangePicker($name, $label, $required = true, $attributes = [])
212
    {
213
        $this->addElement('date_range_picker', $name, $label, $attributes);
214
        $this->addElement('hidden', $name.'_start');
215
        $this->addElement('hidden', $name.'_end');
216
217
        if ($required) {
218
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
219
        }
220
    }
221
222
    /**
223
     * @param string $name
224
     * @param string $label
225
     * @param array  $attributes
226
     *
227
     * @return mixed
228
     */
229
    public function addDatePicker($name, $label, $attributes = [])
230
    {
231
        return $this->addElement('DatePicker', $name, $label, $attributes);
232
    }
233
234
    /**
235
     * @param string $name
236
     * @param string $label
237
     * @param array  $attributes
238
     *
239
     * @return mixed
240
     */
241
    public function addSelectLanguage($name, $label, $options = [], $attributes = [])
242
    {
243
        return $this->addElement('SelectLanguage', $name, $label, $options, $attributes);
244
    }
245
246
    /**
247
     * @param string $name
248
     * @param string $label
249
     * @param array  $options
250
     * @param array  $attributes
251
     *
252
     * @throws
253
     */
254
    public function addSelectAjax($name, $label, $options = [], $attributes = [])
255
    {
256
        if (!isset($attributes['url'])) {
257
            throw new \Exception('select_ajax needs an URL');
258
        }
259
        $this->addElement(
260
            'select_ajax',
261
            $name,
262
            $label,
263
            $options,
264
            $attributes
265
        );
266
    }
267
268
    /**
269
     * @param string $name
270
     * @param string $label
271
     * @param array  $attributes
272
     *
273
     * @return mixed
274
     */
275
    public function addDateTimePicker($name, $label, $attributes = [])
276
    {
277
        return $this->addElement('DateTimePicker', $name, $label, $attributes);
278
    }
279
280
    /**
281
     * @param string $name
282
     * @param string $value
283
     * @param array  $attributes
284
     */
285
    public function addHidden($name, $value, $attributes = [])
286
    {
287
        $this->addElement('hidden', $name, $value, $attributes);
288
    }
289
290
    /**
291
     * @param string $name
292
     * @param string $label
293
     * @param array  $attributes
294
     *
295
     * @return HTML_QuickForm_textarea
296
     */
297
    public function addTextarea($name, $label, $attributes = [])
298
    {
299
        return $this->addElement('textarea', $name, $label, $attributes);
300
    }
301
302
    /**
303
     * @param string $name
304
     * @param string $label
305
     * @param string $icon          font-awesome
306
     * @param string $style         default|primary|success|info|warning|danger|link
307
     * @param string $size          large|default|small|extra-small
308
     * @param string $class         Example plus is transformed to icon fa fa-plus
309
     * @param array  $attributes
310
     * @param bool   $createElement
311
     *
312
     * @return HTML_QuickForm_button
313
     */
314
    public function addButton(
315
        $name,
316
        $label,
317
        $icon = 'check',
318
        $style = 'default',
319
        $size = 'default',
320
        $class = null,
321
        $attributes = [],
322
        $createElement = false
323
    ) {
324
        if ($createElement) {
325
            return $this->createElement(
326
                'button',
327
                $name,
328
                $label,
329
                $icon,
330
                $style,
331
                $size,
332
                $class,
333
                $attributes
334
            );
335
        }
336
337
        return $this->addElement(
338
            'button',
339
            $name,
340
            $label,
341
            $icon,
342
            $style,
343
            $size,
344
            $class,
345
            $attributes
346
        );
347
    }
348
349
    /**
350
     * Returns a button with the primary color and a check mark.
351
     *
352
     * @param string $label         Text appearing on the button
353
     * @param string $name          Element name (for form treatment purposes)
354
     * @param bool   $createElement Whether to use the create or add method
355
     *
356
     * @return HTML_QuickForm_button
357
     */
358
    public function addButtonSave($label, $name = 'submit', $createElement = false)
359
    {
360
        return $this->addButton(
361
            $name,
362
            $label,
363
            'check',
364
            'primary',
365
            null,
366
            null,
367
            [],
368
            $createElement
369
        );
370
    }
371
372
    /**
373
     * Returns a cancel button.
374
     *
375
     * @param string $label         Text appearing on the button
376
     * @param string $name          Element name (for form treatment purposes)
377
     * @param bool   $createElement Whether to use the create or add method
378
     *
379
     * @return HTML_QuickForm_button
380
     */
381
    public function addButtonCancel($label, $name = 'submit', $createElement = false)
382
    {
383
        return $this->addButton(
384
            $name,
385
            $label,
386
            'times',
387
            'danger',
388
            null,
389
            null,
390
            [],
391
            $createElement
392
        );
393
    }
394
395
    /**
396
     * Returns a button with the primary color and a "plus" icon.
397
     *
398
     * @param string $label         Text appearing on the button
399
     * @param string $name          Element name (for form treatment purposes)
400
     * @param bool   $createElement Whether to use the create or add method
401
     * @param array  $attributes    Additional attributes
402
     *
403
     * @return HTML_QuickForm_button
404
     */
405
    public function addButtonCreate($label, $name = 'submit', $createElement = false, $attributes = [])
406
    {
407
        return $this->addButton(
408
            $name,
409
            $label,
410
            'plus',
411
            'primary',
412
            null,
413
            null,
414
            $attributes,
415
            $createElement
416
        );
417
    }
418
419
    /**
420
     * Returns a button with the primary color and a pencil icon.
421
     *
422
     * @param string $label         Text appearing on the button
423
     * @param string $name          Element name (for form treatment purposes)
424
     * @param bool   $createElement Whether to use the create or add method
425
     *
426
     * @return HTML_QuickForm_button
427
     */
428
    public function addButtonUpdate($label, $name = 'submit', $createElement = false)
429
    {
430
        return $this->addButton(
431
            $name,
432
            $label,
433
            'pencil',
434
            'primary',
435
            null,
436
            null,
437
            [],
438
            $createElement
439
        );
440
    }
441
442
    /**
443
     * Returns a button with the danger color and a trash icon.
444
     *
445
     * @param string $label         Text appearing on the button
446
     * @param string $name          Element name (for form treatment purposes)
447
     * @param bool   $createElement Whether to use the create or add method
448
     *
449
     * @return HTML_QuickForm_button
450
     */
451
    public function addButtonDelete($label, $name = 'submit', $createElement = false)
452
    {
453
        return $this->addButton(
454
            $name,
455
            $label,
456
            'trash',
457
            'danger',
458
            null,
459
            null,
460
            [],
461
            $createElement
462
        );
463
    }
464
465
    /**
466
     * Returns a move style button.
467
     *
468
     * @param string $label         Text appearing on the button
469
     * @param string $name          Element name (for form treatment purposes)
470
     * @param bool   $createElement Whether to use the create or add method
471
     *
472
     * @return HTML_QuickForm_button
473
     */
474
    public function addButtonMove($label, $name = 'submit', $createElement = false)
475
    {
476
        return $this->addButton(
477
            $name,
478
            $label,
479
            'arrow-circle-right',
480
            'primary',
481
            null,
482
            null,
483
            [],
484
            $createElement
485
        );
486
    }
487
488
    /**
489
     * Returns a button with the primary color and a paper-plane icon.
490
     *
491
     * @param string $label         Text appearing on the button
492
     * @param string $name          Element name (for form treatment purposes)
493
     * @param bool   $createElement Whether to use the create or add method
494
     * @param array  $attributes
495
     *
496
     * @return HTML_QuickForm_button
497
     */
498
    public function addButtonSend($label, $name = 'submit', $createElement = false, $attributes = [])
499
    {
500
        return $this->addButton(
501
            $name,
502
            $label,
503
            'paper-plane',
504
            'primary',
505
            null,
506
            null,
507
            $attributes,
508
            $createElement
509
        );
510
    }
511
512
    /**
513
     * Returns a button with the default (grey?) color and a magnifier icon.
514
     *
515
     * @param string $label Text appearing on the button
516
     * @param string $name  Element name (for form treatment purposes)
517
     *
518
     * @return HTML_QuickForm_button
519
     */
520
    public function addButtonSearch($label = null, $name = 'submit')
521
    {
522
        if (empty($label)) {
523
            $label = get_lang('Search');
524
        }
525
526
        return $this->addButton($name, $label, 'search', 'default');
527
    }
528
529
    /**
530
     * Returns a button with the primary color and a right-pointing arrow icon.
531
     *
532
     * @param string $label      Text appearing on the button
533
     * @param string $name       Element name (for form treatment purposes)
534
     * @param array  $attributes Additional attributes
535
     *
536
     * @return HTML_QuickForm_button
537
     */
538
    public function addButtonNext($label, $name = 'submit', $attributes = [])
539
    {
540
        return $this->addButton(
541
            $name,
542
            $label,
543
            'arrow-right',
544
            'primary',
545
            null,
546
            null,
547
            $attributes
548
        );
549
    }
550
551
    /**
552
     * Returns a button with the primary color and a check mark icon.
553
     *
554
     * @param string $label         Text appearing on the button
555
     * @param string $name          Element name (for form treatment purposes)
556
     * @param bool   $createElement Whether to use the create or add method
557
     *
558
     * @return HTML_QuickForm_button
559
     */
560
    public function addButtonImport($label, $name = 'submit', $createElement = false)
561
    {
562
        return $this->addButton(
563
            $name,
564
            $label,
565
            'check',
566
            'primary',
567
            null,
568
            null,
569
            [],
570
            $createElement
571
        );
572
    }
573
574
    /**
575
     * Returns a button with the primary color and a check-mark icon.
576
     *
577
     * @param string $label         Text appearing on the button
578
     * @param string $name          Element name (for form treatment purposes)
579
     * @param bool   $createElement Whether to use the create or add method
580
     *
581
     * @return HTML_QuickForm_button
582
     */
583
    public function addButtonExport($label, $name = 'submit', $createElement = false)
584
    {
585
        return $this->addButton(
586
            $name,
587
            $label,
588
            'check',
589
            'primary',
590
            null,
591
            null,
592
            [],
593
            $createElement
594
        );
595
    }
596
597
    /**
598
     * Shortcut to filter button.
599
     *
600
     * @param string $label         Text appearing on the button
601
     * @param string $name          Element name (for form treatment purposes)
602
     * @param bool   $createElement Whether to use the create or add method
603
     *
604
     * @return HTML_QuickForm_button
605
     */
606
    public function addButtonFilter($label, $name = 'submit', $createElement = false)
607
    {
608
        return $this->addButton(
609
            $name,
610
            $label,
611
            'filter',
612
            'primary',
613
            null,
614
            null,
615
            [],
616
            $createElement
617
        );
618
    }
619
620
    /**
621
     * Shortcut to reset button.
622
     *
623
     * @param string $label         Text appearing on the button
624
     * @param string $name          Element name (for form treatment purposes)
625
     * @param bool   $createElement Whether to use the create or add method
626
     *
627
     * @return HTML_QuickForm_button
628
     */
629
    public function addButtonReset($label, $name = 'reset', $createElement = false)
630
    {
631
        $icon = 'eraser';
632
        $style = 'default';
633
        $size = 'default';
634
        $class = null;
635
        $attributes = [];
636
637
        if ($createElement) {
638
            return $this->createElement(
639
                'reset',
640
                $name,
641
                $label,
642
                $icon,
643
                $style,
644
                $size,
645
                $class,
646
                $attributes
647
            );
648
        }
649
650
        return $this->addElement(
651
            'reset',
652
            $name,
653
            $label,
654
            $icon,
655
            $style,
656
            $size,
657
            $class,
658
            $attributes
659
        );
660
    }
661
662
    /**
663
     * Returns a button with the primary color and an upload icon.
664
     *
665
     * @param string $label         Text appearing on the button
666
     * @param string $name          Element name (for form treatment purposes)
667
     * @param bool   $createElement Whether to use the create or add method
668
     *
669
     * @return HTML_QuickForm_button
670
     */
671
    public function addButtonUpload($label, $name = 'submit', $createElement = false)
672
    {
673
        return $this->addButton(
674
            $name,
675
            $label,
676
            'upload',
677
            'primary',
678
            null,
679
            null,
680
            [],
681
            $createElement
682
        );
683
    }
684
685
    /**
686
     * Returns a button with the primary color and a download icon.
687
     *
688
     * @param string $label         Text appearing on the button
689
     * @param string $name          Element name (for form treatment purposes)
690
     * @param bool   $createElement Whether to use the create or add method
691
     *
692
     * @return HTML_QuickForm_button
693
     */
694
    public function addButtonDownload($label, $name = 'submit', $createElement = false)
695
    {
696
        return $this->addButton(
697
            $name,
698
            $label,
699
            'download',
700
            'primary',
701
            null,
702
            null,
703
            [],
704
            $createElement
705
        );
706
    }
707
708
    /**
709
     * Returns a button with the primary color and a magnifier icon.
710
     *
711
     * @param string $label         Text appearing on the button
712
     * @param string $name          Element name (for form treatment purposes)
713
     * @param bool   $createElement Whether to use the create or add method
714
     *
715
     * @return HTML_QuickForm_button
716
     */
717
    public function addButtonPreview($label, $name = 'submit', $createElement = false)
718
    {
719
        return $this->addButton(
720
            $name,
721
            $label,
722
            'search',
723
            'primary',
724
            null,
725
            null,
726
            [],
727
            $createElement
728
        );
729
    }
730
731
    /**
732
     * Returns a button with the primary color and a copy (double sheet) icon.
733
     *
734
     * @param string $label         Text appearing on the button
735
     * @param string $name          Element name (for form treatment purposes)
736
     * @param bool   $createElement Whether to use the create or add method
737
     *
738
     * @return HTML_QuickForm_button
739
     */
740
    public function addButtonCopy($label, $name = 'submit', $createElement = false)
741
    {
742
        return $this->addButton(
743
            $name,
744
            $label,
745
            'copy',
746
            'primary',
747
            null,
748
            null,
749
            [],
750
            $createElement
751
        );
752
    }
753
754
    /**
755
     * @param string $name
756
     * @param string $label
757
     * @param string $text
758
     * @param array  $attributes
759
     *
760
     * @return HTML_QuickForm_checkbox
761
     */
762
    public function addCheckBox($name, $label, $text = '', $attributes = [])
763
    {
764
        return $this->addElement('checkbox', $name, $label, $text, $attributes);
765
    }
766
767
    /**
768
     * @param string $name
769
     * @param string $label
770
     * @param array  $options
771
     * @param array  $attributes
772
     *
773
     * @return HTML_QuickForm_group
774
     */
775
    public function addCheckBoxGroup($name, $label, $options = [], $attributes = [])
776
    {
777
        $group = [];
778
        foreach ($options as $value => $text) {
779
            $attributes['value'] = $value;
780
            $group[] = $this->createElement(
781
                'checkbox',
782
                $value,
783
                null,
784
                $text,
785
                $attributes
786
            );
787
        }
788
789
        return $this->addGroup($group, $name, $label);
790
    }
791
792
    /**
793
     * @param string $name
794
     * @param string $label
795
     * @param array  $options
796
     * @param array  $attributes
797
     *
798
     * @return HTML_QuickForm_group
799
     */
800
    public function addRadio($name, $label, $options = [], $attributes = [])
801
    {
802
        $group = [];
803
        foreach ($options as $key => $value) {
804
            $group[] = $this->createElement('radio', null, null, $value, $key, $attributes);
805
        }
806
807
        return $this->addGroup($group, $name, $label);
808
    }
809
810
    /**
811
     * @param string $name
812
     * @param string $label
813
     * @param array  $options
814
     * @param array  $attributes
815
     *
816
     * @return HTML_QuickForm_select
817
     */
818
    public function addSelect($name, $label, $options = [], $attributes = [])
819
    {
820
        return $this->addElement('select', $name, $label, $options, $attributes);
821
    }
822
823
    /**
824
     * @param $name
825
     * @param $label
826
     * @param $collection
827
     * @param array  $attributes
828
     * @param bool   $addNoneOption
829
     * @param string $textCallable  set a function getStringValue() by default __toString()
830
     *
831
     * @return HTML_QuickForm_element
832
     */
833
    public function addSelectFromCollection(
834
        $name,
835
        $label,
836
        $collection,
837
        $attributes = [],
838
        $addNoneOption = false,
839
        $textCallable = ''
840
    ) {
841
        $options = [];
842
843
        if ($addNoneOption) {
844
            $options[0] = get_lang('None');
845
        }
846
847
        if (!empty($collection)) {
848
            foreach ($collection as $item) {
849
                $text = $item;
850
                if (!empty($textCallable)) {
851
                    $text = $item->$textCallable();
852
                }
853
                $options[$item->getId()] = $text;
854
            }
855
        }
856
857
        return $this->addElement('select', $name, $label, $options, $attributes);
858
    }
859
860
    /**
861
     * @param string $label
862
     * @param string $text
863
     *
864
     * @return HTML_QuickForm_label
865
     */
866
    public function addLabel($label, $text)
867
    {
868
        return $this->addElement('label', $label, $text);
869
    }
870
871
    /**
872
     * @param string $text
873
     */
874
    public function addHeader($text)
875
    {
876
        $this->addElement('header', $text);
877
    }
878
879
    /**
880
     * @param string $name
881
     * @param string $label
882
     * @param array  $attributes
883
     *
884
     * @throws Exception if the file doesn't have an id
885
     */
886
    public function addFile($name, $label, $attributes = [])
887
    {
888
        $element = $this->addElement('file', $name, $label, $attributes);
889
        if (isset($attributes['crop_image'])) {
890
            $id = $element->getAttribute('id');
891
            if (empty($id)) {
892
                throw new Exception('If you use the crop functionality the element must have an id');
893
            }
894
            $this->addHtml(
895
                '
896
                <div class="form-group" id="'.$id.'-form-group" style="display: none;">
897
                    <div class="col-sm-offset-2 col-sm-8">
898
                        <div id="'.$id.'_crop_image" class="cropCanvas thumbnail">
899
                            <img id="'.$id.'_preview_image">
900
                        </div>
901
                        <button class="btn btn-primary" type="button" name="cropButton" id="'.$id.'_crop_button">
902
                            <em class="fa fa-crop"></em> '.get_lang('CropYourPicture').'
903
                        </button>
904
                    </div>
905
                </div>'
906
            );
907
            $this->addHidden($id.'_crop_result', '');
908
            $this->addHidden($id.'_crop_image_base_64', '');
909
        }
910
    }
911
912
    /**
913
     * @param string $snippet
914
     */
915
    public function addHtml($snippet)
916
    {
917
        $this->addElement('html', $snippet);
918
    }
919
920
    /**
921
     * Adds a HTML-editor to the form.
922
     *
923
     * @param string $name
924
     * @param string $label    The label for the form-element
925
     * @param bool   $required (optional) Is the form-element required (default=true)
926
     * @param bool   $fullPage (optional) When it is true, the editor loads completed html code for a full page
927
     * @param array  $config   (optional) Configuration settings for the online editor
928
     */
929
    public function addHtmlEditor(
930
        $name,
931
        $label,
932
        $required = true,
933
        $fullPage = false,
934
        $config = []
935
    ) {
936
        $attributes = [];
937
        $attributes['rows'] = isset($config['rows']) ? $config['rows'] : 15;
938
        $attributes['cols'] = isset($config['cols']) ? $config['cols'] : 80;
939
        $attributes['cols-size'] = isset($config['cols-size']) ? $config['cols-size'] : [];
940
        $attributes['class'] = isset($config['class']) ? $config['class'] : [];
941
942
        $this->addElement('html_editor', $name, $label, $attributes, $config);
943
        $this->applyFilter($name, 'trim');
944
        if ($required) {
945
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
946
        }
947
948
        /** @var HtmlEditor $element */
949
        $element = $this->getElement($name);
950
        $config['style'] = false;
951
        if ($fullPage) {
952
            $config['fullPage'] = true;
953
            // Adds editor.css in ckEditor
954
            $config['style'] = true;
955
        }
956
957
        if ($element->editor) {
958
            $element->editor->processConfig($config);
959
        }
960
    }
961
962
    /**
963
     * Adds a Google Maps Geolocalization field to the form.
964
     *
965
     * @param $name
966
     * @param $label
967
     */
968
    public function addGeoLocationMapField($name, $label)
969
    {
970
        $gMapsPlugin = GoogleMapsPlugin::create();
971
        $geolocalization = $gMapsPlugin->get('enable_api') === 'true';
972
973
        if ($geolocalization) {
974
            $gmapsApiKey = $gMapsPlugin->get('api_key');
975
            $url = '//maps.googleapis.com/maps/api/js?key='.$gmapsApiKey;
976
            $this->addHtml('<script type="text/javascript" src="'.$url.'" ></script>');
977
        }
978
        $this->addElement(
979
            'text',
980
            $name,
981
            $label,
982
            ['id' => $name]
983
        );
984
        $this->applyFilter($name, 'stripslashes');
985
        $this->applyFilter($name, 'trim');
986
        $this->addHtml('
987
            <div class="form-group">
988
                <label for="geolocalization_'.$name.'" class="col-sm-2 control-label"></label>
989
                <div class="col-sm-8">
990
                    <button class="null btn btn-default" id="geolocalization_'.$name.'" name="geolocalization_'.$name.'" type="submit">
991
                        <em class="fa fa-map-marker"></em> '.get_lang('Geolocalization').'
992
                    </button>
993
                    <button class="null btn btn-default" id="myLocation_'.$name.'" name="myLocation_'.$name.'" type="submit">
994
                    <em class="fa fa-crosshairs"></em> 
995
                    '.get_lang('MyLocation').'
996
                    </button>
997
                </div>
998
            </div>
999
        ');
1000
1001
        $this->addHtml('
1002
            <div class="form-group">
1003
                <label for="map_'.$name.'" class="col-sm-2 control-label">
1004
                    '.$label.' - '.get_lang('Map').'
1005
                </label>
1006
                <div class="col-sm-8">
1007
                    <div name="map_'.$name.'" id="map_'.$name.'" style="width:100%; height:300px;">
1008
                    </div>
1009
                </div>
1010
            </div>
1011
        ');
1012
1013
        $this->addHtml('<script>
1014
            $(function() {
1015
                if (typeof google === "object") {
1016
                    var address = $("#'.$name.'").val();
1017
                    initializeGeo'.$name.'(address, false);
1018
1019
                    $("#geolocalization_'.$name.'").on("click", function() {
1020
                        var address = $("#'.$name.'").val();
1021
                        initializeGeo'.$name.'(address, false);
1022
                        return false;
1023
                    });
1024
1025
                    $("#myLocation_'.$name.'").on("click", function() {
1026
                        myLocation'.$name.'();
1027
                        return false;
1028
                    });
1029
1030
                    $("#'.$name.'").keypress(function (event) {
1031
                        if (event.which == 13) {
1032
                            $("#geolocalization_'.$name.'").click();
1033
                            return false;
1034
                        }
1035
                    });
1036
                } else {
1037
                    $("#map_'.$name.'").html("<div class=\"alert alert-info\">'.get_lang('YouNeedToActivateTheGoogleMapsPluginInAdminPlatformToSeeTheMap').'</div>");
1038
                }
1039
            });
1040
1041
            function myLocation'.$name.'() {
1042
                if (navigator.geolocation) {
1043
                    var geoPosition = function(position) {
1044
                        var lat = position.coords.latitude;
1045
                        var lng = position.coords.longitude;
1046
                        var latLng = new google.maps.LatLng(lat, lng);
1047
                        initializeGeo'.$name.'(false, latLng)
1048
                    };
1049
1050
                    var geoError = function(error) {
1051
                        alert("Geocode '.get_lang('Error').': " + error);
1052
                    };
1053
1054
                    var geoOptions = {
1055
                        enableHighAccuracy: true
1056
                    };
1057
                    navigator.geolocation.getCurrentPosition(geoPosition, geoError, geoOptions);
1058
                }
1059
            }
1060
1061
            function initializeGeo'.$name.'(address, latLng) {
1062
                var geocoder = new google.maps.Geocoder();
1063
                var latlng = new google.maps.LatLng(-34.397, 150.644);
1064
                var myOptions = {
1065
                    zoom: 15,
1066
                    center: latlng,
1067
                    mapTypeControl: true,
1068
                    mapTypeControlOptions: {
1069
                        style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
1070
                    },
1071
                    navigationControl: true,
1072
                    mapTypeId: google.maps.MapTypeId.ROADMAP
1073
                };
1074
1075
                map_'.$name.' = new google.maps.Map(document.getElementById("map_'.$name.'"), myOptions);
1076
                var parameter = address ? { "address": address } : latLng ? { "latLng": latLng } : false;
1077
                if (geocoder && parameter) {
1078
                    geocoder.geocode(parameter, function(results, status) {
1079
                        if (status == google.maps.GeocoderStatus.OK) {
1080
                            if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
1081
                                map_'.$name.'.setCenter(results[0].geometry.location);
1082
                                if (!address) {
1083
                                    $("#'.$name.'").val(results[0].formatted_address);
1084
                                }
1085
                                var infowindow = new google.maps.InfoWindow({
1086
                                    content: "<b>" + $("#'.$name.'").val() + "</b>",
1087
                                    size: new google.maps.Size(150, 50)
1088
                                });
1089
1090
                                var marker = new google.maps.Marker({
1091
                                    position: results[0].geometry.location,
1092
                                    map: map_'.$name.',
1093
                                    title: $("#'.$name.'").val()
1094
                                });
1095
                                google.maps.event.addListener(marker, "click", function() {
1096
                                    infowindow.open(map_'.$name.', marker);
1097
                                });
1098
                            } else {
1099
                                alert("'.get_lang("NotFound").'");
1100
                            }
1101
                        } else {
1102
                            alert("Geocode '.get_lang('Error').': '.get_lang("AddressField").' '.get_lang("NotFound").'");
1103
                        }
1104
                    });
1105
                }
1106
            }
1107
        </script>
1108
        ');
1109
    }
1110
1111
    /**
1112
     * @param string $name
1113
     * @param string $label
1114
     *
1115
     * @return mixed
1116
     */
1117
    public function addButtonAdvancedSettings($name, $label = '')
1118
    {
1119
        $label = !empty($label) ? $label : get_lang('AdvancedParameters');
1120
1121
        return $this->addElement('advanced_settings', $name, $label);
1122
    }
1123
1124
    /**
1125
     * Adds a progress loading image to the form.
1126
     */
1127
    public function addProgress($delay = 2, $label = '')
1128
    {
1129
        if (empty($label)) {
1130
            $label = get_lang('PleaseStandBy');
1131
        }
1132
        $this->with_progress_bar = true;
1133
        $id = $this->getAttribute('id');
1134
1135
        $this->updateAttributes("onsubmit=\"javascript: addProgress('".$id."')\"");
1136
        $this->addHtml('<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/upload.js" type="text/javascript"></script>');
1137
    }
1138
1139
    /**
1140
     * This function has been created for avoiding changes directly within QuickForm class.
1141
     * When we use it, the element is threated as 'required' to be dealt during validation.
1142
     *
1143
     * @param array  $elements The array of elements
1144
     * @param string $message  The message displayed
1145
     */
1146
    public function add_multiple_required_rule($elements, $message)
1147
    {
1148
        $this->_required[] = $elements[0];
0 ignored issues
show
Bug Best Practice introduced by
The property _required does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1149
        $this->addRule($elements, $message, 'multiple_required');
1150
    }
1151
1152
    /**
1153
     * Displays the form.
1154
     * If an element in the form didn't validate, an error message is showed
1155
     * asking the user to complete the form.
1156
     */
1157
    public function display()
1158
    {
1159
        echo $this->returnForm();
1160
    }
1161
1162
    /**
1163
     * Returns the HTML code of the form.
1164
     *
1165
     * @return string $return_value HTML code of the form
1166
     */
1167
    public function returnForm()
1168
    {
1169
        $returnValue = '';
1170
1171
        /** @var HTML_QuickForm_element $element */
1172
        foreach ($this->_elements as $element) {
1173
            $elementError = parent::getElementError($element->getName());
1174
            if (!is_null($elementError)) {
1175
                $returnValue .= Display::return_message($elementError, 'warning').'<br />';
1176
                break;
1177
            }
1178
        }
1179
1180
        $returnValue .= parent::toHtml();
1181
        // Add div-element which is to hold the progress bar
1182
        $id = $this->getAttribute('id');
1183
        if (isset($this->with_progress_bar) && $this->with_progress_bar) {
1184
            // Deprecated
1185
            // $icon = Display::return_icon('progress_bar.gif');
1186
1187
            // @todo improve UI
1188
            $returnValue .= '<br />
1189
1190
            <div id="loading_div_'.$id.'" class="loading_div" style="display:none;margin-left:40%; margin-top:10px; height:50px;">
1191
                <div class="wobblebar-loader"></div>
1192
            </div>
1193
            ';
1194
        }
1195
1196
        return $returnValue;
1197
    }
1198
1199
    /**
1200
     * Returns the HTML code of the form.
1201
     * If an element in the form didn't validate, an error message is showed
1202
     * asking the user to complete the form.
1203
     *
1204
     * @return string $return_value HTML code of the form
1205
     *
1206
     * @author Patrick Cool <[email protected]>, Ghent University, august 2006
1207
     * @author Julio Montoya
1208
     *
1209
     * @deprecated use returnForm()
1210
     */
1211
    public function return_form()
1212
    {
1213
        return $this->returnForm();
1214
    }
1215
1216
    /**
1217
     * Create a form validator based on an array of form data:.
1218
     *
1219
     *         array(
1220
     *             'name' => 'zombie_report_parameters',    //optional
1221
     *             'method' => 'GET',                       //optional
1222
     *             'items' => array(
1223
     *                 array(
1224
     *                     'name' => 'ceiling',
1225
     *                     'label' => 'Ceiling',            //optional
1226
     *                     'type' => 'date',
1227
     *                     'default' => date()              //optional
1228
     *                 ),
1229
     *                 array(
1230
     *                     'name' => 'active_only',
1231
     *                     'label' => 'ActiveOnly',
1232
     *                     'type' => 'checkbox',
1233
     *                     'default' => true
1234
     *                 ),
1235
     *                 array(
1236
     *                     'name' => 'submit_button',
1237
     *                     'type' => 'style_submit_button',
1238
     *                     'value' => get_lang('Search'),
1239
     *                     'attributes' => array('class' => 'search')
1240
     *                 )
1241
     *             )
1242
     *         );
1243
     *
1244
     * @param array $form_data
1245
     *
1246
     * @deprecated use normal FormValidator construct
1247
     *
1248
     * @return FormValidator
1249
     */
1250
    public static function create($form_data)
1251
    {
1252
        if (empty($form_data)) {
1253
            return null;
1254
        }
1255
        $form_name = isset($form_data['name']) ? $form_data['name'] : 'form';
1256
        $form_method = isset($form_data['method']) ? $form_data['method'] : 'POST';
1257
        $form_action = isset($form_data['action']) ? $form_data['action'] : '';
1258
        $form_target = isset($form_data['target']) ? $form_data['target'] : '';
1259
        $form_attributes = isset($form_data['attributes']) ? $form_data['attributes'] : null;
1260
        $form_track_submit = isset($form_data['track_submit']) ? $form_data['track_submit'] : true;
1261
        $reset = null;
1262
        $result = new FormValidator($form_name, $form_method, $form_action, $form_target, $form_attributes, $form_track_submit);
0 ignored issues
show
Bug introduced by
It seems like $form_track_submit can also be of type true; however, parameter $layout of FormValidator::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1262
        $result = new FormValidator($form_name, $form_method, $form_action, $form_target, $form_attributes, /** @scrutinizer ignore-type */ $form_track_submit);
Loading history...
1263
1264
        $defaults = [];
1265
        foreach ($form_data['items'] as $item) {
1266
            $name = $item['name'];
1267
            $type = isset($item['type']) ? $item['type'] : 'text';
1268
            $label = isset($item['label']) ? $item['label'] : '';
1269
            if ($type == 'wysiwyg') {
1270
                $element = $result->addHtmlEditor($name, $label);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $element is correct as $result->addHtmlEditor($name, $label) targeting FormValidator::addHtmlEditor() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1271
            } else {
1272
                $element = $result->addElement($type, $name, $label);
1273
            }
1274
            if (isset($item['attributes'])) {
1275
                $attributes = $item['attributes'];
1276
                $element->setAttributes($attributes);
1277
            }
1278
            if (isset($item['value'])) {
1279
                $value = $item['value'];
1280
                $element->setValue($value);
1281
            }
1282
            if (isset($item['default'])) {
1283
                $defaults[$name] = $item['default'];
1284
            }
1285
            if (isset($item['rules'])) {
1286
                $rules = $item['rules'];
1287
                foreach ($rules as $rule) {
1288
                    $message = $rule['message'];
1289
                    $type = $rule['type'];
1290
                    $format = isset($rule['format']) ? $rule['format'] : null;
1291
                    $validation = isset($rule['validation']) ? $rule['validation'] : 'server';
1292
                    $force = isset($rule['force']) ? $rule['force'] : false;
1293
                    $result->addRule($name, $message, $type, $format, $validation, $reset, $force);
1294
                }
1295
            }
1296
        }
1297
        $result->setDefaults($defaults);
1298
1299
        return $result;
1300
    }
1301
1302
    /**
1303
     * @return HTML_QuickForm_Renderer_Default
1304
     */
1305
    public static function getDefaultRenderer()
1306
    {
1307
        return
1308
            isset($GLOBALS['_HTML_QuickForm_default_renderer']) ?
1309
                $GLOBALS['_HTML_QuickForm_default_renderer'] : null;
1310
    }
1311
1312
    /**
1313
     * Adds a input of type url to the form.
1314
     *
1315
     * @param string $name       The label for the form-element
1316
     * @param string $label      The element name
1317
     * @param bool   $required   Optional. Is the form-element required (default=true)
1318
     * @param array  $attributes Optional. List of attributes for the form-element
1319
     */
1320
    public function addUrl($name, $label, $required = true, $attributes = [])
1321
    {
1322
        $this->addElement('url', $name, $label, $attributes);
1323
        $this->applyFilter($name, 'trim');
1324
        $this->addRule($name, get_lang('InsertAValidUrl'), 'url');
1325
1326
        if ($required) {
1327
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1328
        }
1329
    }
1330
1331
    /**
1332
     * Adds a text field for letters to the form.
1333
     * A trim-filter is attached to the field.
1334
     *
1335
     * @param string $name       The element name
1336
     * @param string $label      The label for the form-element
1337
     * @param bool   $required   Optional. Is the form-element required (default=true)
1338
     * @param array  $attributes Optional. List of attributes for the form-element
1339
     */
1340
    public function addTextLettersOnly(
1341
        $name,
1342
        $label,
1343
        $required = false,
1344
        $attributes = []
1345
    ) {
1346
        $attributes = array_merge(
1347
            $attributes,
1348
            [
1349
                'pattern' => '[a-zA-ZñÑ]+',
1350
                'title' => get_lang('OnlyLetters'),
1351
            ]
1352
        );
1353
1354
        $this->addElement(
1355
            'text',
1356
            $name,
1357
            [
1358
                $label,
1359
                get_lang('OnlyLetters'),
1360
            ],
1361
            $attributes
1362
        );
1363
1364
        $this->applyFilter($name, 'trim');
1365
1366
        if ($required) {
1367
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1368
        }
1369
1370
        $this->addRule(
1371
            $name,
1372
            get_lang('OnlyLetters'),
1373
            'regex',
1374
            '/^[a-zA-ZñÑ]+$/'
1375
        );
1376
    }
1377
1378
    /**
1379
     * Adds a text field for alphanumeric characters to the form.
1380
     * A trim-filter is attached to the field.
1381
     *
1382
     * @param string $name       The element name
1383
     * @param string $label      The label for the form-element
1384
     * @param bool   $required   Optional. Is the form-element required (default=true)
1385
     * @param array  $attributes Optional. List of attributes for the form-element
1386
     */
1387
    public function addTextAlphanumeric(
1388
        $name,
1389
        $label,
1390
        $required = false,
1391
        $attributes = []
1392
    ) {
1393
        $attributes = array_merge(
1394
            $attributes,
1395
            [
1396
                'pattern' => '[a-zA-Z0-9ñÑ]+',
1397
                'title' => get_lang('OnlyLettersAndNumbers'),
1398
            ]
1399
        );
1400
1401
        $this->addElement(
1402
            'text',
1403
            $name,
1404
            [
1405
                $label,
1406
                get_lang('OnlyLettersAndNumbers'),
1407
            ],
1408
            $attributes
1409
        );
1410
1411
        $this->applyFilter($name, 'trim');
1412
1413
        if ($required) {
1414
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1415
        }
1416
1417
        $this->addRule(
1418
            $name,
1419
            get_lang('OnlyLettersAndNumbers'),
1420
            'regex',
1421
            '/^[a-zA-Z0-9ÑÑ]+$/'
1422
        );
1423
    }
1424
1425
    /**
1426
     * @param string $name
1427
     * @param $label
1428
     * @param bool  $required
1429
     * @param array $attributes
1430
     * @param bool  $allowNegative
1431
     * @param int   $minValue
1432
     * @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...
1433
     */
1434
    public function addFloat(
1435
        $name,
1436
        $label,
1437
        $required = false,
1438
        $attributes = [],
1439
        $allowNegative = false,
1440
        $minValue = null,
1441
        $maxValue = null
1442
    ) {
1443
        $this->addElement(
1444
            'FloatNumber',
1445
            $name,
1446
            $label,
1447
            $attributes
1448
        );
1449
1450
        $this->applyFilter($name, 'trim');
1451
1452
        if ($required) {
1453
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1454
        }
1455
1456
        // Rule allows "," and "."
1457
        /*$this->addRule(
1458
            $name,
1459
            get_lang('OnlyNumbers'),
1460
            'regex',
1461
            '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d\d*\,\d*$)|(^-?\,\d\d*$)/'
1462
        );*/
1463
1464
        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...
1465
            $this->addRule(
1466
                $name,
1467
                get_lang('NegativeValue'),
1468
                'compare',
1469
                '>=',
1470
                'server',
1471
                false,
1472
                false,
1473
                0
1474
            );
1475
        }
1476
1477
        if (!is_null($minValue)) {
1478
            $this->addRule(
1479
                $name,
1480
                get_lang('UnderMin'),
1481
                'compare',
1482
                '>=',
1483
                'server',
1484
                false,
1485
                false,
1486
                $minValue
1487
            );
1488
        }
1489
1490
        if (!is_null($maxValue)) {
1491
            $this->addRule(
1492
                $name,
1493
                get_lang('OverMax'),
1494
                'compare',
1495
                '<=',
1496
                'server',
1497
                false,
1498
                false,
1499
                $maxValue
1500
            );
1501
        }
1502
    }
1503
1504
    /**
1505
     * Adds a text field for letters and spaces to the form.
1506
     * A trim-filter is attached to the field.
1507
     *
1508
     * @param string $name       The element name
1509
     * @param string $label      The label for the form-element
1510
     * @param bool   $required   Optional. Is the form-element required (default=true)
1511
     * @param array  $attributes Optional. List of attributes for the form-element
1512
     */
1513
    public function addTextLettersAndSpaces(
1514
        $name,
1515
        $label,
1516
        $required = false,
1517
        $attributes = []
1518
    ) {
1519
        $attributes = array_merge(
1520
            $attributes,
1521
            [
1522
                'pattern' => '[a-zA-ZñÑ\s]+',
1523
                'title' => get_lang('OnlyLettersAndSpaces'),
1524
            ]
1525
        );
1526
1527
        $this->addElement(
1528
            'text',
1529
            $name,
1530
            [
1531
                $label,
1532
                get_lang('OnlyLettersAndSpaces'),
1533
            ],
1534
            $attributes
1535
        );
1536
1537
        $this->applyFilter($name, 'trim');
1538
1539
        if ($required) {
1540
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1541
        }
1542
1543
        $this->addRule(
1544
            $name,
1545
            get_lang('OnlyLettersAndSpaces'),
1546
            'regex',
1547
            '/^[a-zA-ZñÑ\s]+$/'
1548
        );
1549
    }
1550
1551
    /**
1552
     * Adds a text field for alphanumeric and spaces characters to the form.
1553
     * A trim-filter is attached to the field.
1554
     *
1555
     * @param string $name       The element name
1556
     * @param string $label      The label for the form-element
1557
     * @param bool   $required   Optional. Is the form-element required (default=true)
1558
     * @param array  $attributes Optional. List of attributes for the form-element
1559
     */
1560
    public function addTextAlphanumericAndSpaces(
1561
        $name,
1562
        $label,
1563
        $required = false,
1564
        $attributes = []
1565
    ) {
1566
        $attributes = array_merge(
1567
            $attributes,
1568
            [
1569
                'pattern' => '[a-zA-Z0-9ñÑ\s]+',
1570
                'title' => get_lang('OnlyLettersAndNumbersAndSpaces'),
1571
            ]
1572
        );
1573
1574
        $this->addElement(
1575
            'text',
1576
            $name,
1577
            [
1578
                $label,
1579
                get_lang('OnlyLettersAndNumbersAndSpaces'),
1580
            ],
1581
            $attributes
1582
        );
1583
1584
        $this->applyFilter($name, 'trim');
1585
1586
        if ($required) {
1587
            $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
1588
        }
1589
1590
        $this->addRule(
1591
            $name,
1592
            get_lang('OnlyLettersAndNumbersAndSpaces'),
1593
            'regex',
1594
            '/^[a-zA-Z0-9ñÑ\s]+$/'
1595
        );
1596
    }
1597
1598
    /**
1599
     * @param string $url
1600
     * @param string $urlToRedirect after upload redirect to this page
1601
     */
1602
    public function addMultipleUpload($url, $urlToRedirect = '')
1603
    {
1604
        $inputName = 'input_file_upload';
1605
        $this->addMultipleUploadJavascript($url, $inputName, $urlToRedirect);
1606
1607
        $this->addHtml('
1608
            <div class="description-upload">
1609
            '.get_lang('ClickToSelectOrDragAndDropMultipleFilesOnTheUploadField').'
1610
            </div>
1611
            <span class="btn btn-success fileinput-button">
1612
                <i class="glyphicon glyphicon-plus"></i>
1613
                <span>'.get_lang('AddFiles').'</span>
1614
                <!-- The file input field used as target for the file upload widget -->
1615
                <input id="'.$inputName.'" type="file" name="files[]" multiple>
1616
            </span>
1617
            <div id="dropzone">
1618
                <div class="button-load">
1619
                '.get_lang('UploadFiles').'
1620
                </div>
1621
            </div>
1622
            <br />
1623
            <!-- The global progress bar -->
1624
            <div id="progress" class="progress">
1625
                <div class="progress-bar progress-bar-success"></div>
1626
            </div>
1627
            <div id="files" class="files"></div>
1628
        ');
1629
    }
1630
1631
    /**
1632
     * @param string $elementName
1633
     * @param string $groupName   if element is inside a group
1634
     *
1635
     * @throws Exception
1636
     */
1637
    public function addPasswordRule($elementName, $groupName = '')
1638
    {
1639
        // Constant defined in old config/profile.conf.php
1640
        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...
1641
            $message = get_lang('PassTooEasy').': '.api_generate_password();
1642
1643
            if (!empty($groupName)) {
1644
                $groupObj = $this->getElement($groupName);
1645
1646
                if ($groupObj instanceof HTML_QuickForm_group) {
1647
                    $elementName = $groupObj->getElementName($elementName);
1648
1649
                    if ($elementName === false) {
1650
                        throw new Exception("The $groupName doesn't have the element $elementName");
1651
                    }
1652
1653
                    $this->_rules[$elementName][] = [
0 ignored issues
show
Bug Best Practice introduced by
The property _rules does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1654
                        'type' => 'callback',
1655
                        'format' => 'api_check_password',
1656
                        'message' => $message,
1657
                        'validation' => '',
1658
                        'reset' => false,
1659
                        'group' => $groupName,
1660
                    ];
1661
                }
1662
            } else {
1663
                $this->addRule(
1664
                    $elementName,
1665
                    $message,
1666
                    'callback',
1667
                    'api_check_password'
1668
                );
1669
            }
1670
        }
1671
    }
1672
1673
    /**
1674
     * Add an element with user ID and avatar to the form.
1675
     * It needs a Chamilo\UserBundle\Entity\User as value. The exported value is the Chamilo\UserBundle\Entity\User ID.
1676
     *
1677
     * @see \UserAvatar
1678
     *
1679
     * @param string $name
1680
     * @param string $label
1681
     * @param string $imageSize Optional. Small, medium or large image
1682
     * @param string $subtitle  Optional. The subtitle for the field
1683
     *
1684
     * @return \UserAvatar
1685
     */
1686
    public function addUserAvatar($name, $label, $imageSize = 'small', $subtitle = '')
1687
    {
1688
        return $this->addElement('UserAvatar', $name, $label, ['image_size' => $imageSize, 'sub_title' => $subtitle]);
1689
    }
1690
1691
    /**
1692
     * @param string $url           page that will handle the upload
1693
     * @param string $inputName
1694
     * @param string $urlToRedirect
1695
     */
1696
    private function addMultipleUploadJavascript($url, $inputName, $urlToRedirect = '')
1697
    {
1698
        $redirectCondition = '';
1699
        if (!empty($urlToRedirect)) {
1700
            $redirectCondition = "window.location.replace('$urlToRedirect'); ";
1701
        }
1702
        $icon = Display::return_icon('file_txt.gif');
1703
        $this->addHtml("
1704
        <script>
1705
        $(function () {
1706
            'use strict';
1707
            $('#".$this->getAttribute('id')."').submit(function() {
1708
                return false;
1709
            });
1710
1711
            $('#dropzone').on('click', function() {
1712
                $('#".$inputName."').click();
1713
            });
1714
1715
            var url = '".$url."';
1716
            var uploadButton = $('<button/>')
1717
                .addClass('btn btn-primary')
1718
                .prop('disabled', true)
1719
                .text('".addslashes(get_lang('Loading'))."')
1720
                .on('click', function () {
1721
                    var \$this = $(this),
1722
                    data = \$this.data();
1723
                    \$this
1724
                        .off('click')
1725
                        .text('".addslashes(get_lang('Cancel'))."')
1726
                        .on('click', function () {
1727
                            \$this.remove();
1728
                            data.abort();
1729
                        });
1730
                    data.submit().always(function () {
1731
                        \$this.remove();
1732
                    });
1733
                });               
1734
                
1735
            $('#".$inputName."').fileupload({
1736
                url: url,
1737
                dataType: 'json',
1738
                // Enable image resizing, except for Android and Opera,
1739
                // which actually support image resizing, but fail to
1740
                // send Blob objects via XHR requests:
1741
                disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent),
1742
                previewMaxWidth: 50,
1743
                previewMaxHeight: 50,
1744
                previewCrop: true,
1745
                dropzone: $('#dropzone'),                                
1746
            }).on('fileuploadadd', function (e, data) {                
1747
                data.context = $('<div class=\"row\" />').appendTo('#files');
1748
                $.each(data.files, function (index, file) {
1749
                    var node = $('<div class=\"col-sm-5 file_name\">').text(file.name);                    
1750
                    node.appendTo(data.context);
1751
                });
1752
            }).on('fileuploadprocessalways', function (e, data) {
1753
                var index = data.index,
1754
                    file = data.files[index],
1755
                    node = $(data.context.children()[index]);
1756
                if (file.preview) {
1757
                    data.context.prepend($('<div class=\"col-sm-2\">').html(file.preview));
1758
                } else {
1759
                    data.context.prepend($('<div class=\"col-sm-2\">').html('".$icon."'));
1760
                }
1761
                if (index + 1 === data.files.length) {
1762
                    data.context.find('button')
1763
                        .text('Upload')
1764
                        .prop('disabled', !!data.files.error);
1765
                }
1766
            }).on('fileuploadprogressall', function (e, data) {
1767
                var progress = parseInt(data.loaded / data.total * 100, 10);
1768
                $('#progress .progress-bar').css(
1769
                    'width',
1770
                    progress + '%'
1771
                );
1772
            }).on('fileuploaddone', function (e, data) {
1773
                $.each(data.result.files, function (index, file) {
1774
                    if (file.error) {
1775
                        var link = $('<div>')
1776
                            .attr({class : 'panel-image'})                            ;
1777
                        $(data.context.children()[index]).parent().wrap(link);
1778
                        // Update file name with new one from Chamilo
1779
                        $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1780
                        var message = $('<div class=\"col-sm-3\">').html(
1781
                            $('<span class=\"message-image-danger\"/>').text(file.error)
1782
                        );
1783
                        $(data.context.children()[index]).parent().append(message);
1784
1785
                        return;
1786
                    }
1787
                    if (file.url) {
1788
                        var link = $('<a>')
1789
                            .attr({target: '_blank', class : 'panel-image'})
1790
                            .prop('href', file.url);
1791
                        $(data.context.children()[index]).parent().wrap(link);
1792
                    }
1793
                    // Update file name with new one from Chamilo
1794
                    $(data.context.children()[index]).parent().find('.file_name').html(file.name);
1795
                    var message = $('<div class=\"col-sm-3\">').html(
1796
                        $('<span class=\"message-image-success\"/>').text('".addslashes(get_lang('UplUploadSucceeded'))."')
1797
                    );
1798
                    $(data.context.children()[index]).parent().append(message);
1799
                });                
1800
                $('#dropzone').removeClass('hover');                
1801
                ".$redirectCondition."
1802
            }).on('fileuploadfail', function (e, data) {
1803
                $.each(data.files, function (index) {
1804
                    var failedMessage = '".addslashes(get_lang('UplUploadFailed'))."';
1805
                    var error = $('<div class=\"col-sm-3\">').html(
1806
                        $('<span class=\"alert alert-danger\"/>').text(failedMessage)
1807
                    );
1808
                    $(data.context.children()[index]).parent().append(error);
1809
                });
1810
                $('#dropzone').removeClass('hover');
1811
            }).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');           
1812
            
1813
            $('#dropzone').on('dragover', function (e) {
1814
                // dragleave callback implementation                
1815
                $('#dropzone').addClass('hover');
1816
            });
1817
            
1818
            $('#dropzone').on('dragleave', function (e) {                
1819
                $('#dropzone').removeClass('hover');
1820
            });
1821
            $('.fileinput-button').hide();
1822
        });
1823
        </script>");
1824
    }
1825
}
1826
1827
/**
1828
 * Cleans HTML text filter.
1829
 *
1830
 * @param string $html HTML to clean
1831
 * @param int    $mode (optional)
1832
 *
1833
 * @return string The cleaned HTML
1834
 */
1835
function html_filter($html, $mode = NO_HTML)
1836
{
1837
    $allowed_tags = HTML_QuickForm_Rule_HTML::get_allowed_tags($mode);
1838
    $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

1838
    $cleaned_html = /** @scrutinizer ignore-call */ kses($html, $allowed_tags);
Loading history...
1839
1840
    return $cleaned_html;
1841
}
1842
1843
function html_filter_teacher($html)
1844
{
1845
    return html_filter($html, TEACHER_HTML);
1846
}
1847
1848
function html_filter_student($html)
1849
{
1850
    return html_filter($html, STUDENT_HTML);
1851
}
1852
1853
function html_filter_teacher_fullpage($html)
1854
{
1855
    return html_filter($html, TEACHER_HTML_FULLPAGE);
1856
}
1857
1858
function html_filter_student_fullpage($html)
1859
{
1860
    return html_filter($html, STUDENT_HTML_FULLPAGE);
1861
}
1862
1863
/**
1864
 * Cleans mobile phone number text.
1865
 *
1866
 * @param string $mobilePhoneNumber Mobile phone number to clean
1867
 *
1868
 * @return string The cleaned mobile phone number
1869
 */
1870
function mobile_phone_number_filter($mobilePhoneNumber)
1871
{
1872
    $mobilePhoneNumber = str_replace(['+', '(', ')'], '', $mobilePhoneNumber);
1873
1874
    return ltrim($mobilePhoneNumber, '0');
1875
}
1876