TDatePicker   F
last analyzed

Complexity

Total Complexity 119

Size/Duplication

Total Lines 843
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 280
c 2
b 0
f 0
dl 0
loc 843
ccs 0
cts 498
cp 0
rs 2
wmc 119

63 Methods

Rating   Name   Duplication   Size   Complexity  
A setData() 0 3 1
A render() 0 10 3
A renderDropDownListCalendar() 0 27 3
A getTimeStampFromText() 0 6 1
A renderCalendarMonthOptions() 0 16 3
A renderCalendarSelections() 0 11 5
A setDateFormat() 0 3 1
A getFromYear() 0 3 1
A setTimeStamp() 0 8 4
A setInputMode() 0 3 1
A renderDatePickerButtons() 0 10 4
A getDropDownCssClass() 0 3 1
A getCulturalOptions() 0 12 2
A getButtonImageUrl() 0 3 1
A getButtonText() 0 3 1
A getCurrentCulture() 0 5 3
A renderCalendarYearOptions() 0 15 4
B getLocalizedMonthNames() 0 19 7
A setDropDownCssClass() 0 3 1
A renderImageButtonDatePicker() 0 15 3
A getData() 0 3 1
A getClientSide() 0 6 2
A renderCalendarDayOptions() 0 12 3
A getCulture() 0 3 1
A setFromYear() 0 3 1
A publishCalendarStyle() 0 8 2
A getCalendarStyle() 0 3 1
A getFirstDayOfWeek() 0 3 1
A setFirstDayOfWeek() 0 3 1
A addAttributesToRender() 0 4 1
A getShowCalendar() 0 3 1
A loadPostData() 0 11 4
A getMode() 0 3 1
A getUpToYear() 0 3 1
A setDate() 0 3 1
A renderDropDownListOptions() 0 10 3
A onPreRender() 0 5 1
A getValidationPropertyValue() 0 7 3
A getDateFromPostData() 0 41 5
A setCulture() 0 3 1
A renderButtonDatePicker() 0 11 2
A getDate() 0 3 1
A getAssetUrl() 0 4 1
A getLocalizedCalendarInfo() 0 6 1
A setMode() 0 3 1
A getDatePickerOptions() 0 32 5
A setUpToYear() 0 3 1
A setButtonImageUrl() 0 3 1
A setPositionMode() 0 3 1
A getInputMode() 0 3 1
A getDateFormat() 0 3 1
A setButtonText() 0 3 1
A createClientScript() 0 3 1
A getDropDownDayOptions() 0 9 3
A getDatePickerButtonID() 0 3 1
A setAutoPostBack() 0 5 1
A setCalendarStyle() 0 3 1
A getPositionMode() 0 3 1
A setShowCalendar() 0 3 1
A renderClientControlScript() 0 13 3
A registerCalendarClientScriptPre() 0 5 2
A hasDayPattern() 0 4 1
A getTimeStamp() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like TDatePicker often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TDatePicker, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * TDatePicker class file.
5
 *
6
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
7
 * @link https://github.com/pradosoft/prado
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 */
10
11
namespace Prado\Web\UI\WebControls;
12
13
use Prado\Exceptions\TNotSupportedException;
14
use Prado\Prado;
15
use Prado\TPropertyValue;
16
use Prado\Web\Javascripts\TJavaScript;
17
use Prado\Web\UI\TControl;
18
use Prado\Util\TSimpleDateFormatter;
19
use Prado\I18N\core\CultureInfo;
20
21
/**
22
 *
23
 * TDatePicker class.
24
 *
25
 * TDatePicker displays a text box for date input purpose.
26
 * When the text box receives focus, a calendar will pop up and users can
27
 * pick up from it a date that will be automatically entered into the text box.
28
 * The format of the date string displayed in the text box is determined by
29
 * the <b>DateFormat</b> property. Valid formats are the combination of the
30
 * following tokens,
31
 *
32
 * ```
33
 *  Character Format Pattern (en-US)
34
 *  -----------------------------------------
35
 *  d          day digit
36
 *  dd         padded day digit e.g. 01, 02
37
 *  M          month digit
38
 *  MM         padded month digit
39
 *  MMMM       localized month name, e.g. March, April
40
 *  yy         2 digit year
41
 *  yyyy       4 digit year
42
 *  -----------------------------------------
43
 * ```
44
 *
45
 * TDatePicker has four <b>Mode</b> to show the date picker popup.
46
 *
47
 *  # <b>Basic</b> -- Only shows a text input, focusing on the input shows the
48
 *                    date picker. This way you can access the popup using only
49
 *                    the keyboard. Note that because of this, TAB-bing through
50
 *                    this control will automatically select the current date if
51
 *                    no previous date was selected. If you close the popup (eg.
52
 *                    pressing the ESC key) you'll need to un-focus and re-focus
53
 *                    the control again for the popup to reappear.
54
 *  # <b>Clickable</b> -- Only shows a text input, clicking on the input shows the
55
 *                    date picker. This mode solves the two small problems of the
56
 *                    Basic mode. It was first introduced in Prado 3.2.
57
 *  # <b>Button</b> -- Shows a button next to the text input, clicking on the
58
 *                     button shows the date, button text can be by the
59
 *                     <b>ButtonText</b> property
60
 *  # <b>ImageButton</b> -- Shows an image next to the text input, clicking on
61
 *                          the image shows the date picker, image source can be
62
 *                          change through the <b>ButtonImageUrl</b> property.
63
 *
64
 * The <b>CssClass</b> property can be used to override the css class name
65
 * for the date picker panel. <b>CalendarStyle</b> property sets the packages
66
 * styles available. E.g. <b>default</b>.
67
 *
68
 * The <b>InputMode</b> property can be set to "TextBox" or "DropDownList" with
69
 * default as "TextBox".
70
 * In <b>DropDownList</b> mode, in addition to the popup date picker, three
71
 * drop down list (day, month and year) are presented to select the date .
72
 *
73
 * The <b>PositionMode</b> property can be set to "Top" or "Bottom" with default
74
 * as "Bottom". It specifies the position of the calendar popup, relative to the
75
 * input field.
76
 *
77
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
78
 * @author Carl G. Mathisen <[email protected]>
79
 * @since 3.0
80
 */
81
class TDatePicker extends TTextBox
82
{
83
	/**
84
	 * Script path relative to the TClientScriptManager::SCRIPT_PATH
85
	 */
86
	public const SCRIPT_PATH = 'datepicker';
87
88
	/**
89
	 * @var TDatePickerClientScript validator client-script options.
90
	 */
91
	private $_clientScript;
92
	/**
93
	 * AutoPostBack is not supported.
94
	 * @param mixed $value
95
	 */
96
	public function setAutoPostBack($value)
97
	{
98
		throw new TNotSupportedException(
99
			'tdatepicker_autopostback_unsupported',
100
			$this::class
101
		);
102
	}
103
104
	/**
105
	 * @return string the format of the date string
106
	 */
107
	public function getDateFormat()
108
	{
109
		return $this->getViewState('DateFormat', 'dd-MM-yyyy');
110
	}
111
112
	/**
113
	 * Sets the format of the date string.
114
	 * @param string $value the format of the date string
115
	 */
116
	public function setDateFormat($value)
117
	{
118
		$this->setViewState('DateFormat', $value, 'dd-MM-yyyy');
119
	}
120
121
	/**
122
	 * @return bool whether the calendar window should pop up when the control receives focus
123
	 */
124
	public function getShowCalendar()
125
	{
126
		return $this->getViewState('ShowCalendar', true);
127
	}
128
129
	/**
130
	 * Sets whether to pop up the calendar window when the control receives focus
131
	 * @param bool $value whether to show the calendar window
132
	 */
133
	public function setShowCalendar($value)
134
	{
135
		$this->setViewState('ShowCalendar', TPropertyValue::ensureBoolean($value), true);
136
	}
137
138
	/**
139
	 * Gets the current culture.
140
	 * @return string current culture, e.g. en_AU.
141
	 */
142
	public function getCulture()
143
	{
144
		return $this->getViewState('Culture', '');
145
	}
146
147
	/**
148
	 * Sets the culture/language for the date picker.
149
	 * @param string $value a culture string, e.g. en_AU.
150
	 */
151
	public function setCulture($value)
152
	{
153
		$this->setViewState('Culture', $value, '');
154
	}
155
156
	/**
157
	 * @param TDatePickerInputMode $value input method of date values
158
	 */
159
	public function setInputMode($value)
160
	{
161
		$this->setViewState('InputMode', TPropertyValue::ensureEnum($value, TDatePickerInputMode::class), TDatePickerInputMode::TextBox);
162
	}
163
164
	/**
165
	 * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
166
	 */
167
	public function getInputMode()
168
	{
169
		return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getViewSta...ckerInputMode::TextBox) also could return the type string which is incompatible with the documented return type Prado\Web\UI\WebControls\TDatePickerInputMode.
Loading history...
170
	}
171
172
	/**
173
	 * @param TDatePickerMode $value calendar UI mode
174
	 */
175
	public function setMode($value)
176
	{
177
		$this->setViewState('Mode', TPropertyValue::ensureEnum($value, TDatePickerMode::class), TDatePickerMode::Basic);
178
	}
179
180
	/**
181
	 * @return TDatePickerMode current calendar UI mode.
182
	 */
183
	public function getMode()
184
	{
185
		return $this->getViewState('Mode', TDatePickerMode::Basic);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getViewSta...TDatePickerMode::Basic) also could return the type string which is incompatible with the documented return type Prado\Web\UI\WebControls\TDatePickerMode.
Loading history...
186
	}
187
	/**
188
	 * @param string $value the image url for "Image" UI mode.
189
	 */
190
	public function setButtonImageUrl($value)
191
	{
192
		$this->setViewState('ImageUrl', $value, '');
193
	}
194
195
	/**
196
	 * @return string the image url for "Image" UI mode.
197
	 */
198
	public function getButtonImageUrl()
199
	{
200
		return $this->getViewState('ImageUrl', '');
201
	}
202
203
	/**
204
	 * @param string $value set the calendar style
205
	 */
206
	public function setCalendarStyle($value)
207
	{
208
		$this->setViewState('CalendarStyle', $value, 'default');
209
	}
210
211
	/**
212
	 * @return string current calendar style
213
	 */
214
	public function getCalendarStyle()
215
	{
216
		return $this->getViewState('CalendarStyle', 'default');
217
	}
218
219
	/**
220
	 * @param string $value Additional Css class name applied to dropdowns in DropDownList mode.
221
	 */
222
	public function setDropDownCssClass($value)
223
	{
224
		$this->setViewState('DropDownCssClass', $value);
225
	}
226
227
	/**
228
	 * @return string Additional Css class name applied to dropdowns in DropDownList mode.
229
	 */
230
	public function getDropDownCssClass()
231
	{
232
		return $this->getViewState('DropDownCssClass');
233
	}
234
235
	/**
236
	 * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
237
	 * @param int $value 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
238
	 */
239
	public function setFirstDayOfWeek($value)
240
	{
241
		$this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
242
	}
243
244
	/**
245
	 * @return int first day of the week
246
	 */
247
	public function getFirstDayOfWeek()
248
	{
249
		return $this->getViewState('FirstDayOfWeek', 1);
250
	}
251
252
	/**
253
	 * @return string text for the date picker button. Default is "...".
254
	 */
255
	public function getButtonText()
256
	{
257
		return $this->getViewState('ButtonText', '...');
258
	}
259
260
	/**
261
	 * @param string $value text for the date picker button
262
	 */
263
	public function setButtonText($value)
264
	{
265
		$this->setViewState('ButtonText', $value, '...');
266
	}
267
268
	/**
269
	 * @param int $value date picker starting year, default is 2000.
270
	 */
271
	public function setFromYear($value)
272
	{
273
		$this->setViewState('FromYear', TPropertyValue::ensureInteger($value), (int) (@date('Y')) - 5);
274
	}
275
276
	/**
277
	 * @return int date picker starting year, default is -5 years
278
	 */
279
	public function getFromYear()
280
	{
281
		return $this->getViewState('FromYear', (int) (@date('Y')) - 5);
282
	}
283
284
	/**
285
	 * @param int $value date picker ending year, default +10 years
286
	 */
287
	public function setUpToYear($value)
288
	{
289
		$this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), (int) (@date('Y')) + 10);
290
	}
291
292
	/**
293
	 * @return int date picker ending year, default +10 years
294
	 */
295
	public function getUpToYear()
296
	{
297
		return $this->getViewState('UpToYear', (int) (@date('Y')) + 10);
298
	}
299
300
	/**
301
	 * @param TDatePickerPositionMode $value calendar UI position
302
	 */
303
	public function setPositionMode($value)
304
	{
305
		$this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, TDatePickerPositionMode::class), TDatePickerPositionMode::Bottom);
306
	}
307
308
	/**
309
	 * @return TDatePickerPositionMode current calendar UI position.
310
	 */
311
	public function getPositionMode()
312
	{
313
		return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getViewSta...erPositionMode::Bottom) also could return the type string which is incompatible with the documented return type Prado\Web\UI\WebControls\TDatePickerPositionMode.
Loading history...
314
	}
315
316
	/**
317
	 * @return int current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
318
	 */
319
	public function getTimeStamp()
320
	{
321
		if (trim($this->getText()) === '') {
322
			return null;
323
		} else {
324
			return $this->getTimeStampFromText();
325
		}
326
	}
327
328
	/**
329
	 * Sets the date for the date picker using timestamp.
330
	 * @param float $value time stamp for the date picker
331
	 */
332
	public function setTimeStamp($value)
333
	{
334
		if ($value === null || (is_string($value) && trim($value) === '')) {
0 ignored issues
show
introduced by
The condition is_string($value) is always false.
Loading history...
335
			$this->setText('');
336
		} else {
337
			$date = TPropertyValue::ensureFloat($value);
338
			$formatter = new TSimpleDateFormatter($this->getDateFormat());
339
			$this->setText($formatter->format($date));
340
		}
341
	}
342
343
	/**
344
	 * Returns the timestamp selected by the user.
345
	 * This method is required by {@see \Prado\IDataRenderer}.
346
	 * It is the same as {@see getTimeStamp()}.
347
	 * @return int the timestamp of the TDatePicker control.
348
	 * @see getTimeStamp
349
	 * @since 3.1.2
350
	 */
351
	public function getData()
352
	{
353
		return $this->getTimeStamp();
354
	}
355
356
	/**
357
	 * Sets the timestamp represented by this control.
358
	 * This method is required by {@see \Prado\IDataRenderer}.
359
	 * It is the same as {@see setTimeStamp()}.
360
	 * @param int $value the timestamp of the TDatePicker control.
361
	 * @see setTimeStamp
362
	 * @since 3.1.2
363
	 */
364
	public function setData($value)
365
	{
366
		$this->setTimeStamp($value);
367
	}
368
369
	/**
370
	 * @return string the date string.
371
	 */
372
	public function getDate()
373
	{
374
		return $this->getText();
375
	}
376
377
	/**
378
	 * @param string $value date string
379
	 */
380
	public function setDate($value)
381
	{
382
		$this->setText($value);
383
	}
384
385
	/**
386
	 * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
387
	 *
388
	 * The date picker on the client-side supports the following events.
389
	 * # <tt>OnDateChanged</tt> -- raised when the date is changed.
390
	 *
391
	 * You can attach custom javascript code to each of these events
392
	 *
393
	 * @return TDatePickerClientScript javascript validator event options.
394
	 */
395
	public function getClientSide()
396
	{
397
		if ($this->_clientScript === null) {
398
			$this->_clientScript = $this->createClientScript();
399
		}
400
		return $this->_clientScript;
401
	}
402
403
	/**
404
	 * @return TDatePickerClientScript javascript validator event options.
405
	 */
406
	protected function createClientScript()
407
	{
408
		return new TDatePickerClientScript();
409
	}
410
411
	/**
412
	 * Returns the value to be validated.
413
	 * This method is required by \Prado\Web\UI\IValidatable interface.
414
	 * @return int|string the integer timestamp if valid, otherwise the original text.
415
	 */
416
	public function getValidationPropertyValue()
417
	{
418
		if (($text = $this->getText()) === '') {
419
			return '';
420
		}
421
		$date = $this->getTimeStamp();
422
		return $date == null ? $text : $date;
423
	}
424
425
	/**
426
	 * Publish the date picker Css asset files.
427
	 * @param mixed $param
428
	 */
429
	public function onPreRender($param)
430
	{
431
		parent::onPreRender($param);
432
		$this->publishCalendarStyle();
433
		$this->registerCalendarClientScriptPre();
434
	}
435
436
	/**
437
	 * Renders body content.
438
	 * This method overrides parent implementation by adding
439
	 * additional date picker button if Mode is Button or ImageButton.
440
	 * @param \Prado\Web\UI\THtmlWriter $writer writer
441
	 */
442
	public function render($writer)
443
	{
444
		if ($this->getInputMode() == TDatePickerInputMode::TextBox) {
0 ignored issues
show
introduced by
The condition $this->getInputMode() ==...ickerInputMode::TextBox is always false.
Loading history...
445
			parent::render($writer);
446
			$this->renderDatePickerButtons($writer);
447
		} else {
448
			$this->renderDropDownListCalendar($writer);
449
			if ($this->hasDayPattern()) {
450
				$this->renderClientControlScript($writer);
451
				$this->renderDatePickerButtons($writer);
452
			}
453
		}
454
	}
455
456
	/**
457
	 * Renders the date picker popup buttons.
458
	 * @param mixed $writer
459
	 */
460
	protected function renderDatePickerButtons($writer)
461
	{
462
		if ($this->getShowCalendar()) {
463
			switch ($this->getMode()) {
464
				case TDatePickerMode::Button:
465
					$this->renderButtonDatePicker($writer);
466
					break;
467
				case TDatePickerMode::ImageButton:
468
					$this->renderImageButtonDatePicker($writer);
469
					break;
470
			}
471
		}
472
	}
473
474
	/**
475
	 * Loads user input data. Override parent implementation, when InputMode
476
	 * is DropDownList call getDateFromPostData to get date data.
477
	 * This method is primarly used by framework developers.
478
	 * @param string $key the key that can be used to retrieve data from the input data collection
479
	 * @param array $values the input data collection
480
	 * @return bool whether the data of the component has been changed
481
	 */
482
	public function loadPostData($key, $values)
483
	{
484
		if ($this->getInputMode() == TDatePickerInputMode::TextBox) {
0 ignored issues
show
introduced by
The condition $this->getInputMode() ==...ickerInputMode::TextBox is always false.
Loading history...
485
			return parent::loadPostData($key, $values);
486
		}
487
		$value = $this->getDateFromPostData($key, $values);
488
		if (!$this->getReadOnly() && $this->getText() !== $value) {
489
			$this->setText($value);
490
			return true;
491
		} else {
492
			return false;
493
		}
494
	}
495
496
	/**
497
	 * Loads date from drop down list data.
498
	 * @param string $key the key that can be used to retrieve data from the input data collection
499
	 * @param array $values the input data collection
500
	 * @return string the date selected
501
	 */
502
	protected function getDateFromPostData($key, $values)
503
	{
504
		$date = @getdate();
505
506
		$pattern = $this->getDateFormat();
507
		$pattern = str_replace(['MMMM', 'MMM'], ['MM', 'MM'], $pattern);
508
		$formatter = new TSimpleDateFormatter($pattern);
509
510
		$order = $formatter->getDayMonthYearOrdering();
511
512
		if (isset($values[$key . '$day'])) {
513
			$day = (int) ($values[$key . '$day']);
514
		} elseif (in_array('day', $order)) {
515
			$day = $date['mday'];
516
		} else {
517
			$day = 1;
518
		}
519
520
		if (isset($values[$key . '$month'])) {
521
			$month = (int) ($values[$key . '$month']) + 1;
522
		} else {
523
			$month = $date['mon'];
524
		}
525
526
		if (isset($values[$key . '$year'])) {
527
			$year = (int) ($values[$key . '$year']);
528
		} else {
529
			$year = $date['year'];
530
		}
531
532
		$s = new \DateTime();
533
		$s->setDate($year, $month, $day);
534
		$s->setTime(0, 0, 0);
535
		$date = $s->getTimeStamp();
536
		//$date = @mktime(0, 0, 0, $month, $day, $year);
537
538
		$pattern = $this->getDateFormat();
539
		$pattern = str_replace(['MMMM', 'MMM'], ['MM', 'MM'], $pattern);
540
541
		$formatter = new TSimpleDateFormatter($pattern);
542
		return $formatter->format($date);
543
	}
544
545
	/**
546
	 * Get javascript date picker options.
547
	 * @return array date picker client-side options
548
	 */
549
	protected function getDatePickerOptions()
550
	{
551
		$options['ID'] = $this->getClientID();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.
Loading history...
552
		$options['InputMode'] = $this->getInputMode();
553
		$options['Format'] = $this->getDateFormat();
554
		$options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
555
		if (($cssClass = $this->getCssClass()) !== '') {
556
			$options['ClassName'] = $cssClass;
557
		}
558
		$options['CalendarStyle'] = $this->getCalendarStyle();
559
		$options['FromYear'] = $this->getFromYear();
560
		$options['UpToYear'] = $this->getUpToYear();
561
		switch ($this->getMode()) {
562
			case TDatePickerMode::Basic:
563
				break;
564
			case TDatePickerMode::Clickable:
565
				$options['TriggerEvent'] = "click";
566
				break;
567
			default:
568
				$options['Trigger'] = $this->getDatePickerButtonID();
569
				break;
570
		}
571
		$options['PositionMode'] = $this->getPositionMode();
572
573
		$options = array_merge($options, $this->getCulturalOptions());
574
		if ($this->_clientScript !== null) {
575
			$options = array_merge(
576
				$options,
577
				$this->_clientScript->getOptions()->toArray()
578
			);
579
		}
580
		return $options;
581
	}
582
583
	/**
584
	 * Get javascript localization options, e.g. month and weekday names.
585
	 * @return array localization options.
586
	 */
587
	protected function getCulturalOptions()
588
	{
589
		if ($this->getCurrentCulture() == 'en') {
590
			return [];
591
		}
592
593
		$info = $this->getLocalizedCalendarInfo();
594
		$options['MonthNames'] = $info->findInfo('calendar/gregorian/monthNames/format/wide');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.
Loading history...
595
		$options['AbbreviatedMonthNames'] = $info->findInfo('calendar/gregorian/monthNames/format/abbreviated');
596
		$options['ShortWeekDayNames'] = $info->findInfo('calendar/gregorian/dayNames/format/abbreviated');
597
598
		return $options;
599
	}
600
601
	/**
602
	 * @return string the current culture, falls back to application if culture is not set.
603
	 */
604
	protected function getCurrentCulture()
605
	{
606
		$app = $this->getApplication()->getGlobalization(false);
607
		return $this->getCulture() == '' ?
608
				($app ? $app->getCulture() : 'en') : $this->getCulture();
0 ignored issues
show
introduced by
$app is of type Prado\I18N\TGlobalization, thus it always evaluated to true.
Loading history...
609
	}
610
611
	/**
612
	 * @return \Prado\I18N\core\CultureInfo date time format information for the current culture.
613
	 */
614
	protected function getLocalizedCalendarInfo()
615
	{
616
		//expensive operations
617
		$culture = $this->getCurrentCulture();
618
		$info = new CultureInfo($culture);
619
		return $info;
620
	}
621
622
	/**
623
	 * Renders the drop down list date picker.
624
	 * @param mixed $writer
625
	 */
626
	protected function renderDropDownListCalendar($writer)
627
	{
628
		if ($this->getMode() == TDatePickerMode::Basic) {
0 ignored issues
show
introduced by
The condition $this->getMode() == Prad...\TDatePickerMode::Basic is always false.
Loading history...
629
			$this->setMode(TDatePickerMode::ImageButton);
630
		}
631
		parent::addAttributesToRender($writer);
632
		$writer->removeAttribute('name');
633
		$writer->removeAttribute('type');
634
		$writer->addAttribute('id', $this->getClientID());
635
636
		if (strlen($class = $this->getCssClass()) > 0) {
637
			$writer->addAttribute('class', $class);
638
		}
639
		$writer->renderBeginTag('span');
640
641
		$date = new \DateTime();
642
		$date->setTimeStamp($this->getTimeStampFromText());
643
		$this->renderCalendarSelections($writer, $date);
644
645
		//render a hidden input field
646
		$writer->addAttribute('name', $this->getUniqueID());
647
		$writer->addAttribute('type', 'hidden');
648
		$writer->addAttribute('value', $this->getText());
649
		$writer->renderBeginTag('input');
650
651
		$writer->renderEndTag();
652
		$writer->renderEndTag();
653
	}
654
655
	protected function hasDayPattern()
656
	{
657
		$formatter = new TSimpleDateFormatter($this->getDateFormat());
658
		return ($formatter->getDayPattern() !== null);
659
	}
660
661
	/**
662
	 * Renders the calendar drop down list depending on the DateFormat pattern.
663
	 * @param \Prado\Web\UI\THtmlWriter $writer the Html writer to render the drop down lists.
664
	 * @param \DateTime $date the current selected date
665
	 */
666
	protected function renderCalendarSelections($writer, $date)
667
	{
668
		$formatter = new TSimpleDateFormatter($this->getDateFormat());
669
670
		foreach ($formatter->getDayMonthYearOrdering() as $type) {
671
			if ($type == 'day') {
672
				$this->renderCalendarDayOptions($writer, $date->format('j'));
673
			} elseif ($type == 'month') {
674
				$this->renderCalendarMonthOptions($writer, $date->format('n'));
675
			} elseif ($type == 'year') {
676
				$this->renderCalendarYearOptions($writer, $date->format('Y'));
677
			}
678
		}
679
	}
680
681
	/**
682
	 * Gets the date from the text input using TSimpleDateFormatter
683
	 * @return int current selected date timestamp
684
	 */
685
	protected function getTimeStampFromText()
686
	{
687
		$pattern = $this->getDateFormat();
688
		$pattern = str_replace(['MMMM', 'MMM'], ['MM', 'MM'], $pattern);
689
		$formatter = new TSimpleDateFormatter($pattern);
690
		return $formatter->parse($this->getText());
691
	}
692
693
	/**
694
	 * Renders a drop down lists.
695
	 * @param \Prado\Web\UI\THtmlWriter $writer the writer used for the rendering purpose
696
	 * @param array $options list of selection options
697
	 * @param null|mixed $selected selected key.
698
	 */
699
	private function renderDropDownListOptions($writer, $options, $selected = null)
700
	{
701
		foreach ($options as $k => $v) {
702
			$writer->addAttribute('value', $k);
703
			if ($k == $selected) {
704
				$writer->addAttribute('selected', 'selected');
705
			}
706
			$writer->renderBeginTag('option');
707
			$writer->write($v);
708
			$writer->renderEndTag();
709
		}
710
	}
711
712
	/**
713
	 * Renders the day drop down list options.
714
	 * @param \Prado\Web\UI\THtmlWriter $writer the writer used for the rendering purpose
715
	 * @param null|mixed $selected selected day.
716
	 */
717
	protected function renderCalendarDayOptions($writer, $selected = null)
718
	{
719
		$days = $this->getDropDownDayOptions();
720
		$writer->addAttribute('id', $this->getClientID() . TControl::CLIENT_ID_SEPARATOR . 'day');
721
		$writer->addAttribute('name', $this->getUniqueID() . TControl::ID_SEPARATOR . 'day');
722
		$writer->addAttribute('class', 'datepicker_day_options ' . $this->getDropDownCssClass());
723
		if ($this->getReadOnly() || !$this->getEnabled(true)) {
724
			$writer->addAttribute('disabled', 'disabled');
725
		}
726
		$writer->renderBeginTag('select');
727
		$this->renderDropDownListOptions($writer, $days, $selected);
728
		$writer->renderEndTag();
729
	}
730
731
	/**
732
	 * @return array list of day options for a drop down list.
733
	 */
734
	protected function getDropDownDayOptions()
735
	{
736
		$formatter = new TSimpleDateFormatter($this->getDateFormat());
737
		$days = [];
738
		$requiresPadding = $formatter->getDayPattern() === 'dd';
739
		for ($i = 1; $i <= 31; $i++) {
740
			$days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
741
		}
742
		return $days;
743
	}
744
745
	/**
746
	 * Renders the month drop down list options.
747
	 * @param \Prado\Web\UI\THtmlWriter $writer the writer used for the rendering purpose
748
	 * @param null|mixed $selected selected month.
749
	 */
750
	protected function renderCalendarMonthOptions($writer, $selected = null)
751
	{
752
		$info = $this->getLocalizedCalendarInfo();
753
		$writer->addAttribute('id', $this->getClientID() . TControl::CLIENT_ID_SEPARATOR . 'month');
754
		$writer->addAttribute('name', $this->getUniqueID() . TControl::ID_SEPARATOR . 'month');
755
		$writer->addAttribute('class', 'datepicker_month_options ' . $this->getDropDownCssClass());
756
		if ($this->getReadOnly() || !$this->getEnabled(true)) {
757
			$writer->addAttribute('disabled', 'disabled');
758
		}
759
		$writer->renderBeginTag('select');
760
		$this->renderDropDownListOptions(
761
			$writer,
762
			$this->getLocalizedMonthNames($info),
763
			$selected - 1
764
		);
765
		$writer->renderEndTag();
766
	}
767
768
	/**
769
	 * Returns the localized month names that depends on the month format pattern.
770
	 * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
771
	 * and "M" return month digits.
772
	 * @param \Prado\I18N\core\CultureInfo $info localized date format information.
773
	 * @return array localized month names.
774
	 */
775
	protected function getLocalizedMonthNames($info)
776
	{
777
		$formatter = new TSimpleDateFormatter($this->getDateFormat());
778
		switch ($formatter->getMonthPattern()) {
779
			case 'MMM': return $info->findInfo('calendar/gregorian/monthNames/format/abbreviated');
780
			case 'MM':
781
				$array = [];
782
				for ($i = 1; $i <= 12; $i++) {
783
					$array[$i - 1] = $i < 10 ? '0' . $i : $i;
784
				}
785
				return $array;
786
			case 'M':
787
				$array = [];
788
				for ($i = 1; $i <= 12; $i++) {
789
					$array[$i - 1] = $i;
790
				}
791
				return $array;
792
			default:
793
				return $info->findInfo('calendar/gregorian/monthNames/format/wide');
794
		}
795
	}
796
797
	/**
798
	 * Renders the year drop down list options.
799
	 * @param \Prado\Web\UI\THtmlWriter $writer the writer used for the rendering purpose
800
	 * @param null|mixed $selected selected year.
801
	 */
802
	protected function renderCalendarYearOptions($writer, $selected = null)
803
	{
804
		$years = [];
805
		for ($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++) {
806
			$years[$i] = $i;
807
		}
808
		$writer->addAttribute('id', $this->getClientID() . TControl::CLIENT_ID_SEPARATOR . 'year');
809
		$writer->addAttribute('name', $this->getUniqueID() . TControl::ID_SEPARATOR . 'year');
810
		$writer->addAttribute('class', 'datepicker_year_options ' . $this->getDropDownCssClass());
811
		if ($this->getReadOnly() || !$this->getEnabled(true)) {
812
			$writer->addAttribute('disabled', 'disabled');
813
		}
814
		$writer->renderBeginTag('select');
815
		$this->renderDropDownListOptions($writer, $years, $selected);
816
		$writer->renderEndTag();
817
	}
818
819
	/**
820
	 * Gets the ID for the date picker trigger button.
821
	 * @return string unique button ID
822
	 */
823
	protected function getDatePickerButtonID()
824
	{
825
		return $this->getClientID() . 'button';
826
	}
827
828
	/**
829
	 * Adds an additional button such that when clicked it shows the date picker.
830
	 * @param \Prado\Web\UI\THtmlWriter $writer
831
	 */
832
	protected function renderButtonDatePicker($writer)
833
	{
834
		$writer->addAttribute('id', $this->getDatePickerButtonID());
835
		$writer->addAttribute('type', 'button');
836
		$writer->addAttribute('class', $this->getCssClass() . ' TDatePickerButton');
837
		$writer->addAttribute('value', $this->getButtonText());
838
		if (!$this->getEnabled(true)) {
839
			$writer->addAttribute('disabled', 'disabled');
840
		}
841
		$writer->renderBeginTag("input");
842
		$writer->renderEndTag();
843
	}
844
845
	/**
846
	 * Adds an additional image button such that when clicked it shows the date picker.
847
	 * @param \Prado\Web\UI\THtmlWriter $writer
848
	 */
849
	protected function renderImageButtonDatePicker($writer)
850
	{
851
		$url = $this->getButtonImageUrl();
852
		$url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
853
		$writer->addAttribute('id', $this->getDatePickerButtonID());
854
		$writer->addAttribute('src', $url);
855
		$writer->addAttribute('alt', ' ');
856
		$writer->addAttribute('class', $this->getCssClass() . ' TDatePickerImageButton');
857
		if (!$this->getEnabled(true)) {
858
			$writer->addAttribute('disabled', 'disabled');
859
		}
860
		$writer->addAttribute('type', 'image');
861
		$writer->addAttribute('onclick', 'return false;');
862
		$writer->renderBeginTag('input');
863
		$writer->renderEndTag();
864
	}
865
866
	/**
867
	 * @param string $file date picker asset file in the self::SCRIPT_PATH directory.
868
	 * @return string date picker asset url.
869
	 */
870
	protected function getAssetUrl($file = '')
871
	{
872
		$base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
873
		return $base . '/' . self::SCRIPT_PATH . '/' . $file;
874
	}
875
876
	/**
877
	 * Publish the calendar style Css asset file.
878
	 * @return string Css file url.
879
	 */
880
	protected function publishCalendarStyle()
881
	{
882
		$url = $this->getAssetUrl($this->getCalendarStyle() . '.css');
883
		$cs = $this->getPage()->getClientScript();
884
		if (!$cs->isStyleSheetFileRegistered($url)) {
885
			$cs->registerStyleSheetFile($url, $url);
886
		}
887
		return $url;
888
	}
889
890
	/**
891
	 * Add the client id to the input textbox, and register the client scripts.
892
	 * @param \Prado\Web\UI\THtmlWriter $writer writer
893
	 */
894
	protected function addAttributesToRender($writer)
895
	{
896
		parent::addAttributesToRender($writer);
897
		$writer->addAttribute('id', $this->getClientID());
898
	}
899
900
	/**
901
	 * Registers the javascript code to initialize the date picker.
902
	 */
903
	protected function registerCalendarClientScriptPre()
904
	{
905
		if ($this->getShowCalendar()) {
906
			$cs = $this->getPage()->getClientScript();
907
			$cs->registerPradoScript("datepicker");
908
		}
909
	}
910
911
	protected function renderClientControlScript($writer)
912
	{
913
		if ($this->getShowCalendar()) {
914
			$cs = $this->getPage()->getClientScript();
915
			if (!$cs->isEndScriptRegistered('TDatePicker.spacer')) {
916
				$spacer = $this->getAssetUrl('spacer.gif');
917
				$code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
918
				$cs->registerEndScript('TDatePicker.spacer', $code);
919
			}
920
921
			$options = TJavaScript::encode($this->getDatePickerOptions());
922
			$code = "new Prado.WebUI.TDatePicker($options);";
923
			$cs->registerEndScript("prado:" . $this->getClientID(), $code);
924
		}
925
	}
926
}
927