Merge "rdbms: make FakeResultWrapper use get_object_vars() again"
[lhc/web/wiklou.git] / resources / src / mediawiki.widgets / mw.widgets.ExpiryInputWidget.js
1 /*!
2 * MediaWiki Widgets - ExpiryWidget class.
3 *
4 * @copyright 2018 MediaWiki Widgets Team and others; see AUTHORS.txt
5 * @license The MIT License (MIT); see LICENSE.txt
6 */
7 /* global moment */
8 ( function () {
9
10 /**
11 * Creates a mw.widgets.ExpiryWidget object.
12 *
13 * @class mw.widgets.ExpiryWidget
14 * @extends OO.ui.Widget
15 *
16 * @constructor
17 * @param {Object} [config] Configuration options
18 */
19 mw.widgets.ExpiryWidget = function ( config ) {
20 var RFC2822 = 'ddd, DD MMM YYYY HH:mm:ss [GMT]';
21
22 // Config initialization
23 config = $.extend( {}, config );
24
25 this.relativeField = new config.RelativeInputClass( config.relativeInput );
26 this.relativeField.$element.addClass( 'mw-widget-ExpiryWidget-relative' );
27
28 // Parent constructor
29 mw.widgets.ExpiryWidget.parent.call( this, config );
30
31 // Properties
32 this.inputSwitch = new OO.ui.ButtonSelectWidget( {
33 tabIndex: -1,
34 items: [
35 new OO.ui.ButtonOptionWidget( {
36 data: 'relative',
37 icon: 'edit'
38 } ),
39 new OO.ui.ButtonOptionWidget( {
40 data: 'date',
41 icon: 'calendar'
42 } )
43 ]
44 } );
45 this.dateTimeField = new mw.widgets.datetime.DateTimeInputWidget( {
46 min: new Date(), // The selected date must at least be now.
47 required: config.required
48 } );
49
50 // Initially hide the dateTime field.
51 this.dateTimeField.toggle( false );
52 // Initially set the relative input.
53 this.inputSwitch.selectItemByData( 'relative' );
54
55 // Events
56
57 // Toggle the visible inputs.
58 this.inputSwitch.on( 'choose', function ( event ) {
59 switch ( event.getData() ) {
60 case 'date':
61 this.dateTimeField.toggle( true );
62 this.relativeField.toggle( false );
63 break;
64 case 'relative':
65 this.dateTimeField.toggle( false );
66 this.relativeField.toggle( true );
67 break;
68 }
69 }.bind( this ) );
70
71 // When the date time field update, update the relative
72 // field.
73 this.dateTimeField.on( 'change', function ( value ) {
74 var datetime;
75
76 // Do not alter the visible input.
77 if ( this.relativeField.isVisible() ) {
78 return;
79 }
80
81 // If the value was cleared, do not attempt to parse it.
82 if ( !value ) {
83 this.relativeField.setValue( value );
84 return;
85 }
86
87 datetime = moment( value );
88
89 // If the datetime is invlaid for some reason, reset the relative field.
90 if ( !datetime.isValid() ) {
91 this.relativeField.setValue( undefined );
92 }
93
94 // Set the relative field value. The field only accepts English strings.
95 this.relativeField.setValue( datetime.utc().locale( 'en' ).format( RFC2822 ) );
96 }.bind( this ) );
97
98 // When the relative field update, update the date time field if it's a
99 // value that moment understands.
100 this.relativeField.on( 'change', function ( event ) {
101 var datetime;
102
103 // Emit a change event for this widget.
104 this.emit( 'change', event );
105
106 // Do not alter the visible input.
107 if ( this.dateTimeField.isVisible() ) {
108 return;
109 }
110
111 // Parsing of free text field may fail, so always check if the date is
112 // valid.
113 datetime = moment( event );
114
115 if ( datetime.isValid() ) {
116 this.dateTimeField.setValue( datetime.utc().toISOString() );
117 } else {
118 this.dateTimeField.setValue( undefined );
119 }
120 }.bind( this ) );
121
122 // Initialization
123 this.$element
124 .addClass( 'mw-widget-ExpiryWidget' )
125 .addClass( 'mw-widget-ExpiryWidget-hasDatePicker' )
126 .append(
127 this.inputSwitch.$element,
128 this.dateTimeField.$element,
129 this.relativeField.$element
130 );
131
132 // Trigger an initial onChange.
133 this.relativeField.emit( 'change', this.relativeField.getValue() );
134 };
135
136 /* Inheritance */
137
138 OO.inheritClass( mw.widgets.ExpiryWidget, OO.ui.Widget );
139
140 /**
141 * @inheritdoc
142 */
143 mw.widgets.ExpiryWidget.static.reusePreInfuseDOM = function ( node, config ) {
144 var relativeElement = $( node ).find( '.mw-widget-ExpiryWidget-relative' );
145
146 config = mw.widgets.ExpiryWidget.parent.static.reusePreInfuseDOM( node, config );
147
148 if ( relativeElement.hasClass( 'oo-ui-textInputWidget' ) ) {
149 config.RelativeInputClass = OO.ui.TextInputWidget;
150 } else if ( relativeElement.hasClass( 'mw-widget-selectWithInputWidget' ) ) {
151 config.RelativeInputClass = mw.widgets.SelectWithInputWidget;
152 }
153
154 config.relativeInput = config.RelativeInputClass.static.reusePreInfuseDOM(
155 relativeElement,
156 config.relativeInput
157 );
158
159 return config;
160 };
161
162 /**
163 * @inheritdoc
164 */
165 mw.widgets.ExpiryWidget.static.gatherPreInfuseState = function ( node, config ) {
166 var state = mw.widgets.ExpiryWidget.parent.static.gatherPreInfuseState( node, config );
167
168 state.relativeInput = config.RelativeInputClass.static.gatherPreInfuseState(
169 $( node ).find( '.mw-widget-ExpiryWidget-relative' ),
170 config.relativeInput
171 );
172
173 return state;
174 };
175
176 /**
177 * @inheritdoc
178 */
179 mw.widgets.ExpiryWidget.prototype.restorePreInfuseState = function ( state ) {
180 mw.widgets.ExpiryWidget.parent.prototype.restorePreInfuseState.call( this, state );
181 this.relativeField.restorePreInfuseState( state.relativeInput );
182 };
183
184 /**
185 * @inheritdoc
186 */
187 mw.widgets.ExpiryWidget.prototype.setDisabled = function ( disabled ) {
188 mw.widgets.ExpiryWidget.parent.prototype.setDisabled.call( this, disabled );
189 this.relativeField.setDisabled( disabled );
190
191 if ( this.inputSwitch ) {
192 this.inputSwitch.setDisabled( disabled );
193 }
194
195 if ( this.dateTimeField ) {
196 this.dateTimeField.setDisabled( disabled );
197 }
198 };
199
200 /**
201 * Gets the value of the widget.
202 *
203 * @return {string}
204 */
205 mw.widgets.ExpiryWidget.prototype.getValue = function () {
206 return this.relativeField.getValue();
207 };
208
209 }() );