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