1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-08 07:47:00 +02:00

Add support for custom jQuery UI datepicker settings in InputfieldDatetime per processwire/processwire-requests#523 and also makes several new options interactively configurable in the field settings (Input tab > Datepicker settings fieldset).

This commit is contained in:
Ryan Cramer
2024-04-19 14:37:18 -04:00
parent a37f237900
commit 4e2d798d49
4 changed files with 156 additions and 8 deletions

View File

@@ -20,7 +20,6 @@ function InputfieldDatetimeDatepicker($t) {
if(pickerVisible) {
// datepicker always visible (inline)
var $datepicker = $("<div></div>");
//$t.parent('p').after($datepicker);
$t.after($datepicker);
} else {
// datepicker doesn't appear till requested
@@ -36,9 +35,18 @@ function InputfieldDatetimeDatepicker($t) {
dateFormat: dateFormat,
gotoCurrent: true,
defaultDate: tsDate
// buttonImage: config.urls.admin_images + 'icons/calendar.gif',
// dateFormat: config.date_format
};
var attrOptions = JSON.parse($t.attr('data-datepicker'));
var customOptions = {};
if(typeof ProcessWire.config.InputfieldDatetimeDatepickerDefaults === 'object') {
options = $.extend({}, ProcessWire.config.InputfieldDatetimeDatepickerDefaults, options);
}
if(typeof ProcessWire.config.InputfieldDatetimeDatepickerOptions === 'object') {
customOptions = ProcessWire.config.InputfieldDatetimeDatepickerOptions;
}
if(yearRange && yearRange.length) options.yearRange = yearRange;
@@ -51,8 +59,10 @@ function InputfieldDatetimeDatepicker($t) {
}
if(timeFormat.indexOf('ss') > -1) options.showSecond = true;
if(timeFormat.indexOf('m') == -1) options.showMinute = false;
options = $.extend(options, attrOptions, customOptions);
$datepicker.datetimepicker(options);
} else {
options = $.extend(options, attrOptions, customOptions);
$datepicker.datepicker(options);
}

View File

@@ -1 +1 @@
function InputfieldDatetimeDatepicker($t){var pickerVisible=$t.is(".InputfieldDatetimeDatepicker2");var ts=parseInt($t.attr("data-ts"));var tsDate=null;var dateFormat=$t.attr("data-dateformat");var timeFormat=$t.attr("data-timeformat");var timeSelect=parseInt($t.attr("data-timeselect"));var hasTimePicker=timeFormat.length>0&&!pickerVisible;var showOn=$t.is(".InputfieldDatetimeDatepicker3")?"focus":"button";var ampm=parseInt($t.attr("data-ampm"))>0;var yearRange=$t.attr("data-yearrange");if(ts>1)tsDate=new Date(ts);if(pickerVisible){var $datepicker=$("<div></div>");$t.after($datepicker)}else{var $datepicker=$t}var options={changeMonth:true,changeYear:true,showOn:showOn,buttonText:"&gt;",showAnim:"fadeIn",dateFormat:dateFormat,gotoCurrent:true,defaultDate:tsDate};if(yearRange&&yearRange.length)options.yearRange=yearRange;if(hasTimePicker){options.ampm=ampm;options.timeFormat=timeFormat;if(timeSelect>0){options.controlType="select";options.oneLine=true}if(timeFormat.indexOf("ss")>-1)options.showSecond=true;if(timeFormat.indexOf("m")==-1)options.showMinute=false;$datepicker.datetimepicker(options)}else{$datepicker.datepicker(options)}if(pickerVisible){$datepicker.on("change",function(e){var d=$datepicker.datepicker("getDate");var str=$.datepicker.formatDate(dateFormat,d);$t.val(str)})}if(showOn=="button"){var $button=$t.next("button.ui-datepicker-trigger");if($button.length){var $a=$("<a class='pw-ui-datepicker-trigger' href='#'><i class='fa fa-calendar'></i></a>");$button.after($a).hide();$a.on("click",function(){$button.trigger("click");return false})}}$t.addClass("initDatepicker")}function InputfieldDatetimeSelect(){function validate($select){var $parent=$select.parent(),$month=$parent.children(".InputfieldDatetimeMonth"),month=parseInt($month.val()),$day=$parent.children(".InputfieldDatetimeDay"),day=parseInt($day.val()),$year=$parent.children(".InputfieldDatetimeYear"),year=parseInt($year.val()),$value=$parent.children(".InputfieldDatetimeValue"),date=month&&day&&year?new Date(year,month-1,day):null,errorClass="InputfieldDatetimeError";if(date&&date.getMonth()+1!=month){day="";$day.val("").addClass(errorClass)}else{$day.removeClass(errorClass)}$value.val(date&&day?year+"-"+month+"-"+day:"")}function yearChange($select){var value=$select.val();if(value!=="-"&&value!=="+")return;var $blankOption=$select.find('option[value=""]'),$option=$select.find('option[value="'+value+'"]'),fromYear=parseInt($select.attr("data-from-year")),toYear=parseInt($select.attr("data-to-year")),numYears=toYear-fromYear,n=0,$o;if(numYears<10)numYears=10;if(value==="-"){toYear=fromYear-1;fromYear=fromYear-numYears;for(n=toYear;n>=fromYear;n--){$o=jQuery("<option />").val(n).text(n);$select.prepend($o)}$option.html("&lt; "+fromYear);$select.prepend($option).prepend($blankOption);$select.val(toYear);$select.attr("data-from-year",fromYear)}else if(value==="+"){fromYear=toYear+1;toYear+=numYears;for(n=fromYear;n<=toYear;n++){$o=$("<option />").val(n).text(n);$select.append($o)}$option.html("&gt; "+toYear);$select.append($option);$select.val(fromYear);$select.attr("data-to-year",toYear)}}jQuery(document).on("change",".InputfieldDatetimeSelect select",function(){var $select=jQuery(this);if($select.hasClass("InputfieldDatetimeYear"))yearChange($select);validate($select)})}jQuery(document).ready(function($){$("input.InputfieldDatetimeDatepicker:not(.InputfieldDatetimeDatepicker3):not(.initDatepicker)").each(function(n){InputfieldDatetimeDatepicker($(this))});$(document).on("focus","input.InputfieldDatetimeDatepicker3:not(.hasDatepicker)",function(){InputfieldDatetimeDatepicker($(this))});InputfieldDatetimeSelect()});
function InputfieldDatetimeDatepicker($t){var pickerVisible=$t.is(".InputfieldDatetimeDatepicker2");var ts=parseInt($t.attr("data-ts"));var tsDate=null;var dateFormat=$t.attr("data-dateformat");var timeFormat=$t.attr("data-timeformat");var timeSelect=parseInt($t.attr("data-timeselect"));var hasTimePicker=timeFormat.length>0&&!pickerVisible;var showOn=$t.is(".InputfieldDatetimeDatepicker3")?"focus":"button";var ampm=parseInt($t.attr("data-ampm"))>0;var yearRange=$t.attr("data-yearrange");if(ts>1)tsDate=new Date(ts);if(pickerVisible){var $datepicker=$("<div></div>");$t.after($datepicker)}else{var $datepicker=$t}var options={changeMonth:true,changeYear:true,showOn:showOn,buttonText:"&gt;",showAnim:"fadeIn",dateFormat:dateFormat,gotoCurrent:true,defaultDate:tsDate};var attrOptions=JSON.parse($t.attr("data-datepicker"));var customOptions={};if(typeof ProcessWire.config.InputfieldDatetimeDatepickerDefaults==="object"){options=$.extend({},ProcessWire.config.InputfieldDatetimeDatepickerDefaults,options)}if(typeof ProcessWire.config.InputfieldDatetimeDatepickerOptions==="object"){customOptions=ProcessWire.config.InputfieldDatetimeDatepickerOptions}if(yearRange&&yearRange.length)options.yearRange=yearRange;if(hasTimePicker){options.ampm=ampm;options.timeFormat=timeFormat;if(timeSelect>0){options.controlType="select";options.oneLine=true}if(timeFormat.indexOf("ss")>-1)options.showSecond=true;if(timeFormat.indexOf("m")==-1)options.showMinute=false;options=$.extend(options,attrOptions,customOptions);$datepicker.datetimepicker(options)}else{options=$.extend(options,attrOptions,customOptions);$datepicker.datepicker(options)}if(pickerVisible){$datepicker.on("change",function(e){var d=$datepicker.datepicker("getDate");var str=$.datepicker.formatDate(dateFormat,d);$t.val(str)})}if(showOn=="button"){var $button=$t.next("button.ui-datepicker-trigger");if($button.length){var $a=$("<a class='pw-ui-datepicker-trigger' href='#'><i class='fa fa-calendar'></i></a>");$button.after($a).hide();$a.on("click",function(){$button.trigger("click");return false})}}$t.addClass("initDatepicker")}function InputfieldDatetimeSelect(){function validate($select){var $parent=$select.parent(),$month=$parent.children(".InputfieldDatetimeMonth"),month=parseInt($month.val()),$day=$parent.children(".InputfieldDatetimeDay"),day=parseInt($day.val()),$year=$parent.children(".InputfieldDatetimeYear"),year=parseInt($year.val()),$value=$parent.children(".InputfieldDatetimeValue"),date=month&&day&&year?new Date(year,month-1,day):null,errorClass="InputfieldDatetimeError";if(date&&date.getMonth()+1!=month){day="";$day.val("").addClass(errorClass)}else{$day.removeClass(errorClass)}$value.val(date&&day?year+"-"+month+"-"+day:"")}function yearChange($select){var value=$select.val();if(value!=="-"&&value!=="+")return;var $blankOption=$select.find('option[value=""]'),$option=$select.find('option[value="'+value+'"]'),fromYear=parseInt($select.attr("data-from-year")),toYear=parseInt($select.attr("data-to-year")),numYears=toYear-fromYear,n=0,$o;if(numYears<10)numYears=10;if(value==="-"){toYear=fromYear-1;fromYear=fromYear-numYears;for(n=toYear;n>=fromYear;n--){$o=jQuery("<option />").val(n).text(n);$select.prepend($o)}$option.html("&lt; "+fromYear);$select.prepend($option).prepend($blankOption);$select.val(toYear);$select.attr("data-from-year",fromYear)}else if(value==="+"){fromYear=toYear+1;toYear+=numYears;for(n=fromYear;n<=toYear;n++){$o=$("<option />").val(n).text(n);$select.append($o)}$option.html("&gt; "+toYear);$select.append($option);$select.val(fromYear);$select.attr("data-to-year",toYear)}}jQuery(document).on("change",".InputfieldDatetimeSelect select",function(){var $select=jQuery(this);if($select.hasClass("InputfieldDatetimeYear"))yearChange($select);validate($select)})}jQuery(document).ready(function($){$("input.InputfieldDatetimeDatepicker:not(.InputfieldDatetimeDatepicker3):not(.initDatepicker)").each(function(n){InputfieldDatetimeDatepicker($(this))});$(document).on("focus","input.InputfieldDatetimeDatepicker3:not(.hasDatepicker)",function(){InputfieldDatetimeDatepicker($(this))});InputfieldDatetimeSelect()});

View File

@@ -8,7 +8,7 @@
* For documentation about the fields used in this class, please see:
* /wire/core/Fieldtype.php
*
* ProcessWire 3.x, Copyright 2023 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
* ~~~~~~
@@ -52,6 +52,13 @@
* @property string $dateInputFormat Date input format to use, see WireDateTime::$dateFormats (default='Y-m-d')
* @property string $timeInputFormat Time input format to use, see WireDateTime::$timeFormats (default='')
* @property string $placeholder Placeholder attribute text
* @property string $showAnim Animation type (default='fade')
* @property bool|int $changeMonth Show a select dropdown to allow changing month? (default=true)
* @property bool|int $changeYear Show a select dropdown to allow changing year? (default=true)
* @property bool|int $showButtonPanel Show "Today" and "Done" buttons under the calendar? (default=false)
* @property int $numberOfMonths Number of month calendars to show together side-by-sidee (default=1)
* @property bool|int $showMonthAfterYear Show the month after the year? (default=false)
* @property bool|int $showOtherMonths Show dates in other months (non-selectable) at the start or end of the current month? (default=false)
*
* Properties specific to "html" input type
* ========================================
@@ -80,7 +87,7 @@ class InputfieldDatetime extends Inputfield {
return array(
'title' => __('Datetime', __FILE__), // Module Title
'summary' => __('Inputfield that accepts date and optionally time', __FILE__), // Module Summary
'version' => 107,
'version' => 108,
'permanent' => true,
);
}
@@ -126,7 +133,14 @@ class InputfieldDatetime extends Inputfield {
*
*/
protected $inputTypes = array();
/**
* jQuery UI custom datepicker options set from datepickerOptions() method
*
* @var array
*
*/
protected $datepickerOptions = array();
/**
* Initialize the date/time inputfield
@@ -356,6 +370,37 @@ class InputfieldDatetime extends Inputfield {
return parent::setAttribute($key, $value);
}
/**
* Get or set jQuery UI datepicker options
*
* <https://api.jqueryui.com/datepicker/>
*
* ~~~~~
* // set custom options
* $inputfield->datepickerOptions([ 'changeMonth' => false, 'changeYear' => false ]);
*
* // set the defaults for all datepicker fields/inputs to start from
* $config->js('InputfieldDatetimeDatepickerDefaults', [ 'showButtonPanel' => true ]);
*
* // override settings for all datetime fields/inputs
* $config->js('InputfieldDatetimeDatepickerOptions', [ 'showAnim' => 'drop' ]);
*
* // override settings for all datetime fields/inputs (from JS)
* $.extend(ProcessWire.config.InputfieldDatetimeDatepickerOptions, { 'showAnim': 'drop' });
*
* ~~~~~
*
* @param array $options
* @return array
*
*/
public function datepickerOptions($options = array()) {
if(count($options)) {
$this->datepickerOptions = array_merge($this->datepickerOptions, $options);
}
return $this->datepickerOptions;
}
/**
* Date/time Inputfield configuration, per field
*

View File

@@ -44,6 +44,13 @@ class InputfieldDatetimeText extends InputfieldDatetimeType {
'timeInputFormat' => '',
'timeInputSelect' => 0,
'yearRange' => '',
'showAnim' => 'fade',
'changeMonth' => true,
'changeYear' => true,
'showButtonPane' => false,
'numberOfMonths' => 1,
'showMonthAfterYear' => false,
'showOtherMonths' => false,
);
if($languages) {
@@ -171,6 +178,28 @@ class InputfieldDatetimeText extends InputfieldDatetimeType {
$yearRange = $sanitizer->entities($this->getSetting('yearRange'));
$timeInputSelect = $this->getSetting('timeInputSelect');
$datepickerSettings = array();
$settingNames = array(
'showAnim', 'changeMonth', 'changeYear', 'showButtonPanel',
'numberOfMonths', 'showMonthAfterYear', 'showOtherMonths',
);
foreach($settingNames as $name) {
$val = $this->inputfield->getSetting($name);
if($name === 'showAnim') {
$val = (string) $val;
if($val === 'none') $val = '';
} else if($name === 'numberOfMonths') {
$val = (int) $val;
if($val < 1) $val = 1;
} else {
$val = (bool) ((int) $val);
}
$datepickerSettings[$name] = $val;
}
// merge in any custom settings
$datepickerSettings = array_merge($datepickerSettings, $this->inputfield->datepickerOptions());
$out =
"<input " . $this->inputfield->getAttributesString($attrs) . " " .
@@ -182,6 +211,7 @@ class InputfieldDatetimeText extends InputfieldDatetimeType {
"data-ts='$valueTS' " .
"data-ampm='$ampm' " .
(strlen($yearRange) ? "data-yearrange='$yearRange' " : '') .
"data-datepicker='" . htmlspecialchars(json_encode($datepickerSettings)) . "' " .
"/>";
return $out;
@@ -392,6 +422,13 @@ class InputfieldDatetimeText extends InputfieldDatetimeType {
$f->description = $this->_('The displayed width of this field (in characters).');
$f->columnWidth = 50;
$inputfields->append($f);
$fieldset = $inputfields->InputfieldFieldset;
$fieldset->attr('name', '_datepicker_settings');
$fieldset->label = $this->_('Datepicker settings');
$fieldset->showIf = "datepicker!=" . self::datepickerNo;
$inputfields->add($fieldset);
$module = $this->inputfield;
/** @var InputfieldText $f */
$f = $modules->get("InputfieldText");
@@ -405,8 +442,64 @@ class InputfieldDatetimeText extends InputfieldDatetimeType {
$f->notes = $this->_('Default is `-10:+10` which shows a year range 10 years before and after now.');
$f->icon = 'arrows-h';
$f->collapsed = Inputfield::collapsedBlank;
$inputfields->append($f);
$fieldset->append($f);
$f = $inputfields->InputfieldSelect;
$f->attr('name', 'showAnim');
$f->label = $this->_('Animation type');
$f->addOption('none', $this->_('None'));
$f->addOption('fade', $this->_('Fade'));
$f->addOption('show', $this->_('Show'));
$f->addOption('clip', $this->_('Clip'));
$f->addOption('drop', $this->_('Drop'));
$f->addOption('puff', $this->_('Puff'));
$f->addOption('scale', $this->_('Scale'));
$f->addOption('slide', $this->_('Slide'));
$f->val($module->get('showAnim'));
$f->columnWidth = 50;
$fieldset->add($f);
$f = $inputfields->InputfieldInteger;
$f->attr('name', 'numberOfMonths');
$f->label = $this->_('Number of month to show side-by-side in datepicker');
$f->val((int) $module->get('numberOfMonths'));
$f->columnWidth = 50;
$fieldset->add($f);
$f = $inputfields->InputfieldToggle;
$f->attr('name', 'changeMonth');
$f->label = $this->_('Render month as select rather than text?');
$f->val($module->get('changeMonth'));
$f->columnWidth = 50;
$fieldset->add($f);
$f = $inputfields->InputfieldToggle;
$f->attr('name', 'changeYear');
$f->label = $this->_('Render year as select rather than text?');
$f->val($module->get('changeYear'));
$f->columnWidth = 50;
$fieldset->add($f);
$f = $inputfields->InputfieldToggle;
$f->attr('name', 'showButtonPanel');
$f->label = $this->_('Display “Today” and “Done” buttons under calendar?');
$f->val($module->get('showButtonPane'));
$f->columnWidth = 50;
$fieldset->add($f);
$f = $inputfields->InputfieldToggle;
$f->attr('name', 'showMonthAfterYear');
$f->label = $this->_('Show month after year?');
$f->val($module->get('showMonthAfterYear'));
$f->columnWidth = 50;
$fieldset->add($f);
$f = $inputfields->InputfieldToggle;
$f->attr('name', 'showOtherMonths');
$f->label = $this->_('Show days in other months at start/end of months?');
$f->val($module->get('showOtherMonths'));
$f->columnWidth = 100;
$fieldset->add($f);
}