FlatpickrField::getAltFormat()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace LeKoala\FormElements;
4
5
use SilverStripe\i18n\i18n;
6
use SilverStripe\Forms\TextField;
7
use SilverStripe\View\Requirements;
8
9
/**
10
 * @link https://chmln.github.io/flatpickr
11
 */
12
class FlatpickrField extends TextField implements LocalizableField
13
{
14
    use BaseElement;
15
    use Localize;
16
    use HasDateTimeFormat;
17
18
    // Formats
19
    const DEFAULT_DATE_FORMAT = 'Y-m-d';
20
    const DEFAULT_TIME_FORMAT = 'H:i';
21
    const DEFAULT_DATETIME_FORMAT = 'Y-m-d H:i';
22
    const DEFAULT_ALT_DATE_FORMAT = 'l j F Y';
23
    const DEFAULT_ALT_TIME_FORMAT = 'H:i';
24
    const DEFAULT_ALT_DATETIME_FORMAT = 'l j F Y H:i';
25
26
    /**
27
     * Override locale. If empty will default to current locale
28
     *
29
     * @var string
30
     */
31
    protected $locale = null;
32
33
    /**
34
     * Disable description
35
     *
36
     * @var boolean
37
     */
38
    protected $disableDescription = false;
39
40
    /**
41
     * Array of plugins
42
     *
43
     * @var array
44
     */
45
    protected $plugins = [];
46
47
    /**
48
     * @var array
49
     */
50
    protected $hooks = [];
51
52
    /**
53
     * @var string
54
     */
55
    protected $theme;
56
57
    /**
58
     * @config
59
     * @var boolean
60
     */
61
    private static $enable_requirements = true;
62
63
    /**
64
     * @config
65
     * @link https://flatpickr.js.org/options/
66
     * @var array
67
     */
68
    private static $default_config = [
69
        'defaultDate' => '',
70
        'time_24hr' => true,
71
    ];
72
73
    public function __construct($name, $title = null, $value = '', $maxLength = null, $form = null)
74
    {
75
        parent::__construct($name, $title, $value, $maxLength, $form);
76
77
        $this->config = self::config()->default_config;
78
        $this->setDatetimeFormat($this->convertDatetimeFormat(self::DEFAULT_ALT_DATE_FORMAT));
79
        $this->setAltFormat(self::DEFAULT_ALT_DATE_FORMAT);
80
    }
81
82
    /**
83
     * Get the value of theme
84
     *
85
     * @return string
86
     */
87
    public function getTheme()
88
    {
89
        return $this->theme;
90
    }
91
92
    /**
93
     * Set the value of theme
94
     *
95
     * @param string $theme
96
     *
97
     * @return $this
98
     */
99
    public function setTheme($theme)
100
    {
101
        $this->theme = $theme;
102
        return $this;
103
    }
104
105
    /**
106
     * Convert a datetime format from Flatpickr to CLDR
107
     *
108
     * This allow to display the right format in php
109
     *
110
     * @see https://flatpickr.js.org/formatting/
111
     * @param string $format
112
     * @return string
113
     */
114
    protected function convertDatetimeFormat($format)
115
    {
116
        return str_replace(
117
            ['F', 'l', 'j', 'd', 'H', 'i', 's'],
118
            ['MMMM', 'cccc', 'd', 'dd', 'HH', 'mm', 'ss'],
119
            $format
120
        );
121
    }
122
123
    public function Type()
124
    {
125
        return 'flatpickr';
126
    }
127
128
    public function extraClass()
129
    {
130
        return 'text ' . parent::extraClass();
131
    }
132
133
    public function getEnableTime()
134
    {
135
        return $this->getConfig('enableTime');
136
    }
137
138
    public function setEnableTime($value)
139
    {
140
        $this->setDatetimeFormat($this->convertDatetimeFormat(self::DEFAULT_ALT_DATETIME_FORMAT));
141
        $this->setAltFormat(self::DEFAULT_ALT_DATETIME_FORMAT);
142
        $this->setConfirmDate(true);
143
        return $this->setConfig('enableTime', $value);
144
    }
145
146
    public function getNoCalendar()
147
    {
148
        return $this->getConfig('noCalendar');
149
    }
150
151
    public function setNoCalendar($value)
152
    {
153
        $this->setDatetimeFormat($this->convertDatetimeFormat(self::DEFAULT_ALT_TIME_FORMAT));
154
        $this->setAltFormat(self::DEFAULT_ALT_TIME_FORMAT);
155
        return $this->setConfig('noCalendar', $value);
156
    }
157
158
    /**
159
     * Show the user a readable date (as per altFormat), but return something totally different to the server.
160
     *
161
     * @return string
162
     */
163
    public function getAltInput()
164
    {
165
        return $this->getConfig('altInput');
166
    }
167
168
    public function setAltInput($value)
169
    {
170
        return $this->setConfig('altInput', $value);
171
    }
172
173
    /**
174
     * Exactly the same as date format, but for the altInput field
175
     *
176
     * @return string
177
     */
178
    public function getAltFormat()
179
    {
180
        return $this->getConfig('altFormat');
181
    }
182
183
    /**
184
     * Please note that altFormat should match the format for the database
185
     *
186
     * @param string $value
187
     * @return $this
188
     */
189
    public function setAltFormat($value)
190
    {
191
        return $this->setConfig('altFormat', $value);
192
    }
193
194
    public function getMinDate()
195
    {
196
        return $this->getConfig('minDate');
197
    }
198
199
    public function setMinDate($value)
200
    {
201
        return $this->setConfig('minDate', $value);
202
    }
203
204
    public function getMaxDate()
205
    {
206
        return $this->getConfig('maxDate');
207
    }
208
209
    public function setMaxDate($value)
210
    {
211
        return $this->setConfig('maxDate', $value);
212
    }
213
214
    public function getInline()
215
    {
216
        return $this->getConfig('inline');
217
    }
218
219
    public function setInline($value)
220
    {
221
        return $this->setConfig('inline', (bool)$value);
222
    }
223
224
    public function getDefaultDate()
225
    {
226
        return $this->getConfig('defaultDate');
227
    }
228
229
    public function setDefaultDate($value)
230
    {
231
        return $this->setConfig('defaultDate', $value);
232
    }
233
234
    public function getDateFormat()
235
    {
236
        return $this->getConfig('dateFormat');
237
    }
238
239
    public function setDateFormat($value)
240
    {
241
        return $this->setConfig('dateFormat', $value);
242
    }
243
244
    public function getDisabledDates()
245
    {
246
        return $this->getConfig('disable');
247
    }
248
249
    /**
250
     * Accepts:
251
     * - an array of values:  ["2025-01-30", "2025-02-21", "2025-03-08"]
252
     * - an array of ranges:  [["from" => "2025-01-30", "to" => "2025-02-10]]
253
     * Js functions are not supported at this time
254
     *
255
     * @param array $value
256
     * @return $this
257
     */
258
    public function setDisabledDates($value)
259
    {
260
        return $this->setConfig('disable', $value);
261
    }
262
263
    public function getEnabledDates()
264
    {
265
        return $this->getConfig('enable');
266
    }
267
268
    /**
269
     * Accepts:
270
     * - an array of values:  ["2025-01-30", "2025-02-21", "2025-03-08"]
271
     * - an array of ranges:  [["from" => "2025-01-30", "to" => "2025-02-10]]
272
     * Js functions are not supported at this time
273
     *
274
     * @param array $value
275
     * @return $this
276
     */
277
    public function setEnabledDates($value)
278
    {
279
        return $this->setConfig('enable', $value);
280
    }
281
282
    /**
283
     * Get id of the second element
284
     *
285
     * @return string
286
     */
287
    public function getRange()
288
    {
289
        return $this->getElementAttribute('data-range');
290
    }
291
292
    /**
293
     * Set id of the second element
294
     *
295
     * eg: #Form_ItemEditForm_EndDate
296
     *
297
     * @param string $range Id of the second element
298
     * @param bool $confirm
299
     * @return $this
300
     */
301
    public function setRange($range, $confirm = true)
302
    {
303
        $this->setElementAttribute('data-range', $range);
304
        if ($confirm) {
305
            $this->setConfirmDate(true);
306
        }
307
        return $this;
308
    }
309
310
    /**
311
     * Get add confirm box
312
     *
313
     * @return bool
314
     */
315
    public function getConfirmDate()
316
    {
317
        return $this->getElementAttribute('data-confirm-date');
318
    }
319
320
    /**
321
     * Set add confirm box
322
     *
323
     * @param bool $confirmDate Add confirm box
324
     *
325
     * @return $this
326
     */
327
    public function setConfirmDate($confirmDate)
328
    {
329
        return $this->setElementAttribute('data-confirm-date', $confirmDate);
330
    }
331
332
    /**
333
     * @return bool
334
     */
335
    public function getMonthSelect()
336
    {
337
        return $this->getElementAttribute('data-month-select');
338
    }
339
340
    /**
341
     * @param bool $monthSelect
342
     *
343
     * @return $this
344
     */
345
    public function setMonthSelect($monthSelect)
346
    {
347
        return $this->setElementAttribute('data-month-select', $monthSelect);
348
    }
349
350
    /**
351
     * @param string $hook
352
     * @return string
353
     */
354
    public function getHook($hook)
355
    {
356
        return $this->hooks[$hook] ?? '';
357
    }
358
359
    /**
360
     * @param string $hook
361
     * @param string $callbackName
362
     * @return $this
363
     */
364
    public function setHook($hook, $callbackName)
365
    {
366
        $this->hooks[$hook] = $callbackName;
367
        return $this;
368
    }
369
370
    public function setDescription($description)
371
    {
372
        // Allows blocking scaffolded UI desc that has no uses
373
        if ($this->disableDescription) {
374
            return $this;
375
        }
376
        return parent::setDescription($description);
377
    }
378
379
    public function Field($properties = array())
380
    {
381
        // Set lang based on locale
382
        $lang = substr($this->getLocale(), 0, 2);
383
        if ($lang != 'en') {
384
            $this->setConfig('locale', $lang);
385
        }
386
387
        if ($this->hooks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->hooks of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
388
            // Use replace callback format
389
            foreach ($this->hooks as $k => $v) {
390
                $this->setConfig($k, [
391
                    "__fn" => $v
392
                ]);
393
            }
394
        }
395
396
        if (self::config()->enable_requirements) {
397
            self::requirements($lang);
398
        }
399
400
        if ($this->readonly) {
401
            if ($this->getNoCalendar() && $this->getEnableTime()) {
402
                $this->setAttribute('placeholder', _t('FlatpickrField.NO_TIME_SELECTED', 'No time'));
403
            } else {
404
                $this->setAttribute('placeholder', _t('FlatpickrField.NO_DATE_SELECTED', 'No date'));
405
            }
406
        } else {
407
            $this->setAttribute('placeholder', _t('FlatpickrField.SELECT_A_DATE', 'Select a date...'));
408
        }
409
410
        // Time formatting can cause value change for no reasons
411
        $this->addExtraClass('no-change-track');
412
413
        return $this->wrapInElement('flatpickr-input', $properties);
414
    }
415
416
    /**
417
     * Add requirements
418
     *
419
     * @param string $lang
420
     * @return void
421
     */
422
    public static function requirements($lang = null)
423
    {
424
        if ($lang === null) {
425
            $lang = substr(i18n::get_locale(), 0, 2);
426
        }
427
428
        // We still need a copy of the cdn js files to load l10n
429
        $langResource = self::moduleResource("client/cdn/flatpickr/l10n/fr.js");
430
        Requirements::javascript("lekoala/silverstripe-form-elements: client/custom-elements/flatpickr-input.min.js");
431
432
        // Load lang (leverage waitDefined from custom element)
433
        if ($lang != 'en') {
434
            $basePath = dirname($langResource->getPath());
435
            if (!is_file("$basePath/$lang.js")) {
436
                $lang = 'en'; // revert to en
437
            }
438
        }
439
        if ($lang != 'en') {
440
            //eg: https://cdn.jsdelivr.net/npm/flatpickr@4/dist/l10n/fr.js
441
            Requirements::javascript("lekoala/silverstripe-form-elements: client/cdn/flatpickr/l10n/$lang.js");
442
        }
443
    }
444
445
    /**
446
     * Get disable description
447
     *
448
     * @return  boolean
449
     */
450
    public function getDisableDescription()
451
    {
452
        return $this->disableDescription;
453
    }
454
455
    /**
456
     * Set disable description
457
     *
458
     * @param boolean $disableDescription
459
     *
460
     * @return $this
461
     */
462
    public function setDisableDescription($disableDescription)
463
    {
464
        $this->disableDescription = $disableDescription;
465
        return $this;
466
    }
467
468
    public function setReadonly($readonly)
469
    {
470
        $this->setConfig('clickOpens', !$readonly);
471
        $this->setConfig('allowInput', !$readonly);
472
        return parent::setReadonly($readonly);
473
    }
474
475
    /**
476
     * Returns a read-only version of this field.
477
     *
478
     * @return FormField
0 ignored issues
show
Bug introduced by
The type LeKoala\FormElements\FormField was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
479
     */
480
    public function performReadonlyTransformation()
481
    {
482
        $clone = $this->castedCopy(self::class);
483
        $clone->replaceConfig($this->config);
484
        $clone->setReadonly(true);
485
        return $clone;
486
    }
487
488
    /**
489
     * Set typical options for a DateTime field
490
     * @return $this
491
     */
492
    public function setDateTimeOptions()
493
    {
494
        $this->setEnableTime(true);
495
        $this->setDisableDescription(true);
496
        return $this;
497
    }
498
499
    /**
500
     * Set typical options for a Time field
501
     * @return $this
502
     */
503
    public function setTimeOptions()
504
    {
505
        $this->setEnableTime(true);
506
        $this->setNoCalendar(true);
507
        return $this;
508
    }
509
}
510