Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
DateInputWidget
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 5
756
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
210
 getJavaScriptClassName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getConfig
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
90
 getInputElement
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 modifyDate
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Widget;
4
5use DateTime;
6use OOUI\TextInputWidget;
7
8/**
9 * Date input widget.
10 *
11 * @since 1.29
12 * @copyright 2016 MediaWiki Widgets Team and others; see AUTHORS.txt
13 * @license MIT
14 */
15class DateInputWidget extends TextInputWidget {
16
17    /** @var string|null */
18    protected $inputFormat = null;
19    /** @var string|null */
20    protected $displayFormat = null;
21    /** @var string|null|false */
22    protected $longDisplayFormat = null;
23    /** @var string|null */
24    protected $placeholderLabel = null;
25    /** @var string|null */
26    protected $placeholderDateFormat = null;
27    /** @var string|null */
28    protected $precision = null;
29    /** @var string|null */
30    protected $mustBeAfter = null;
31    /** @var string|null */
32    protected $mustBeBefore = null;
33
34    /**
35     * @param array $config Configuration options
36     *   - string $config['inputFormat'] Date format string to use for the textual input field.
37     *     Displayed while the widget is active, and the user can type in a date in this format.
38     *     Should be short and easy to type. (default: 'YYYY-MM-DD' or 'YYYY-MM', depending on
39     *     `precision`)
40     *   - string $config['displayFormat'] Date format string to use for the clickable label.
41     *     while the widget is inactive. Should be as unambiguous as possible (for example, prefer
42     *     to spell out the month, rather than rely on the order), even if that makes it longer.
43     *     Applicable only if the widget is infused. (default: language-specific)
44     *   - string $config['longDisplayFormat'] If a custom displayFormat is not specified, use
45     *     unabbreviated day of the week and month names in the default language-specific
46     *     displayFormat. (default: false)
47     *   - string $config['placeholderLabel'] Placeholder text shown when the widget is not
48     *     selected. Applicable only if the widget is infused. (default: taken from message
49     *     `mw-widgets-dateinput-no-date`)
50     *   - string $config['placeholderDateFormat'] User-visible date format string displayed
51     *     in the textual input field when it's empty. Should be the same as `inputFormat`, but
52     *     translated to the user's language. (default: 'YYYY-MM-DD' or 'YYYY-MM', depending on
53     *     `precision`)
54     *   - string $config['precision'] Date precision to use, 'day' or 'month' (default: 'day')
55     *   - string $config['min'] Validates the date to be no earlier than this.
56     *     In the 'YYYY-MM-DD' or 'YYYY-MM' format, depending on `precision`.
57     *   - string $config['mustBeAfter'] Validates the date to be after this. Overrides 'min'.
58     *     In the 'YYYY-MM-DD' or 'YYYY-MM' format, depending on `precision`.
59     *   - string $config['max'] Validates the date to be no later than this.
60     *     In the 'YYYY-MM-DD' or 'YYYY-MM' format, depending on `precision`.
61     *   - string $config['mustBeBefore'] Validates the date to be before this. Overrides 'max'.
62     *     In the 'YYYY-MM-DD' or 'YYYY-MM' format, depending on `precision`.
63     */
64    public function __construct( array $config = [] ) {
65        $config = array_merge( [
66            // Default config values
67            'precision' => 'day',
68            'longDisplayFormat' => false,
69        ], $config );
70
71        // Properties
72        if ( isset( $config['inputFormat'] ) ) {
73            $this->inputFormat = $config['inputFormat'];
74        }
75        if ( isset( $config['placeholderDateFormat'] ) ) {
76            $this->placeholderDateFormat = $config['placeholderDateFormat'];
77        }
78        $this->precision = $config['precision'];
79        if ( isset( $config['mustBeAfter'] ) ) {
80            $this->mustBeAfter = $config['mustBeAfter'];
81        } elseif ( isset( $config['min'] ) ) {
82            $this->mustBeAfter = $this->modifyDate( $config['min'], '-1 day' );
83        }
84        if ( isset( $config['mustBeBefore'] ) ) {
85            $this->mustBeBefore = $config['mustBeBefore'];
86        } elseif ( isset( $config['max'] ) ) {
87            $this->mustBeBefore = $this->modifyDate( $config['max'], '+1 day' );
88        }
89
90        // Properties stored for the infused JS widget
91        if ( isset( $config['displayFormat'] ) ) {
92            $this->displayFormat = $config['displayFormat'];
93        }
94        if ( isset( $config['longDisplayFormat'] ) ) {
95            $this->longDisplayFormat = $config['longDisplayFormat'];
96        }
97        if ( isset( $config['placeholderLabel'] ) ) {
98            $this->placeholderLabel = $config['placeholderLabel'];
99        }
100
101        // Set up placeholder text visible if the browser doesn't override it (logic taken from JS)
102        if ( $this->placeholderDateFormat !== null ) {
103            $placeholder = $this->placeholderDateFormat;
104        } elseif ( $this->inputFormat !== null ) {
105            // We have no way to display a translated placeholder for custom formats
106            $placeholder = '';
107        } else {
108            $placeholder = wfMessage( "mw-widgets-dateinput-placeholder-$this->precision" )->text();
109        }
110
111        $config = array_merge( [
112            // Processed config values
113            'placeholder' => $placeholder,
114        ], $config );
115
116        parent::__construct( $config );
117
118        // Calculate min/max attributes (which are skipped by TextInputWidget) and add to <input>
119        // min/max attributes are inclusive, but mustBeAfter/Before are exclusive
120        if ( $this->mustBeAfter !== null ) {
121            $this->input->setAttributes( [ 'min' => $this->modifyDate( $this->mustBeAfter, '+1 day' ) ] );
122        }
123        if ( $this->mustBeBefore !== null ) {
124            $this->input->setAttributes( [ 'max' => $this->modifyDate( $this->mustBeBefore, '-1 day' ) ] );
125        }
126
127        // Initialization
128        $this->addClasses( [ 'mw-widget-dateInputWidget' ] );
129    }
130
131    protected function getJavaScriptClassName() {
132        return 'mw.widgets.DateInputWidget';
133    }
134
135    public function getConfig( &$config ) {
136        if ( $this->inputFormat !== null ) {
137            $config['inputFormat'] = $this->inputFormat;
138        }
139        if ( $this->displayFormat !== null ) {
140            $config['displayFormat'] = $this->displayFormat;
141        }
142        if ( $this->longDisplayFormat !== null ) {
143            $config['longDisplayFormat'] = $this->longDisplayFormat;
144        }
145        if ( $this->placeholderLabel !== null ) {
146            $config['placeholderLabel'] = $this->placeholderLabel;
147        }
148        if ( $this->placeholderDateFormat !== null ) {
149            $config['placeholderDateFormat'] = $this->placeholderDateFormat;
150        }
151        if ( $this->precision !== null ) {
152            $config['precision'] = $this->precision;
153        }
154        if ( $this->mustBeAfter !== null ) {
155            $config['mustBeAfter'] = $this->mustBeAfter;
156        }
157        if ( $this->mustBeBefore !== null ) {
158            $config['mustBeBefore'] = $this->mustBeBefore;
159        }
160        $config['$overlay'] = true;
161        return parent::getConfig( $config );
162    }
163
164    public function getInputElement( $config ) {
165        // Inserts date/month type attribute
166        return parent::getInputElement( $config )
167            ->setAttributes( [
168                'type' => ( $config['precision'] === 'month' ) ? 'month' : 'date'
169            ] );
170    }
171
172    private function modifyDate( string $date, string $modifier ): string {
173        $datetime = new DateTime( $date );
174        $datetime->modify( $modifier );
175        return $datetime->format( 'Y-m-d' );
176    }
177}