__('Datetime', __FILE__), // Module Title 'summary' => __('Inputfield that accepts date and optionally time', __FILE__), // Module Summary 'version' => 103, 'permanent' => true, ); } /** * Initialize the date/time inputfield * */ public function init() { $this->attr('type', 'text'); $this->attr('size', 25); $this->attr('placeholder', ''); $this->set('dateInputFormat', self::defaultDateInputFormat); $this->set('timeInputFormat', ''); $this->set('datepicker', self::datepickerNo); $this->set('yearRange', ''); $this->set('defaultToday', 0); if($this->languages) foreach($this->languages as $language) { // account for alternate formats in other languages if($language->isDefault()) continue; $this->set("dateInputFormat$language", ''); $this->set("timeInputFormat$language", ''); } parent::init(); } /** * Called before the render method, from a hook in the Inputfield class * * We are overriding it here and checking for a datepicker, so that we can make sure * jQuery UI is loaded before the InputfieldDatetime.js * */ public function hookRender($event) { if($this->datepicker) { wire('modules')->get('JqueryCore'); // Jquery Core required before Jquery UI wire('modules')->get('JqueryUI'); } parent::hookRender($event); } /** * Render the date/time inputfield * */ public function ___render() { $dateFormat = ''; $timeFormat = ''; if($this->user->language && !$this->user->language->isDefault()) { // check if alternate language formats are provided $dateFormat = $this->get("dateInputFormat{$this->user->language}"); $timeFormat = $this->get("timeInputFormat{$this->user->language}"); } if(!$dateFormat) $dateFormat = $this->dateInputFormat; if(!$timeFormat) $timeFormat = $this->timeInputFormat; $useTime = false; if($this->datepicker) { $this->addClass("InputfieldDatetimeDatepicker InputfieldDatetimeDatepicker{$this->datepicker}"); if(strlen($timeFormat) && $this->datepicker != self::datepickerInline) { // add in the timepicker script, if applicable $useTime = true; $this->config->scripts->add($this->config->urls->InputfieldDatetime . 'jquery-ui-timepicker-addon.js'); } if($this->languages && $this->user->language) { // include i18n support for the datepicker // note that the 'xx' in the filename is just a placeholder to indicate what should be replaced for translations, as that file doesn't exist $langFile = ltrim($this->_('/wire/modules/Jquery/JqueryUI/i18n/jquery.ui.datepicker-xx.js'), '/'); // Datepicker translation file // Replace 'xx' with jQuery UI language code or specify your own js file if(is_file($this->config->paths->root . $langFile)) { // add a custom language file $this->config->scripts->add($this->config->urls->root . $langFile); } else { // attempt to auto-find one based on the language name (which are often 2 char language codes) $langFile = "wire/modules/Jquery/JqueryUI/i18n/jquery.ui.datepicker-{$this->user->language->name}.js"; if(is_file($this->config->paths->root . $langFile)) $this->config->scripts->add($this->config->urls->root . $langFile); } } } $attrs = $this->getAttributes(); $value = $attrs['value']; $valueTS = (int) $value*1000; // TS=for datepicker/javascript, which uses milliseconds rather than seconds unset($attrs['value']); if(!$value && $this->defaultToday) { $value = date($dateFormat); if($useTime) $value .= ' ' . date($timeFormat); $valueTS = time()*1000; } else if($value) { $value = trim(date($dateFormat . ' ' . $timeFormat, (int) $value)); } $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); $dateFormatJS = htmlspecialchars(FieldtypeDatetime::convertDateFormat($dateFormat, 'js'), ENT_QUOTES, 'UTF-8'); $timeFormatJS = $useTime ? FieldtypeDatetime::convertDateFormat($timeFormat, 'js') : ''; if(strpos($timeFormatJS, 'h24') !== false) { // 24 hour format. timepicker has no codes to represent it, so we identify and convert it to a variable $timeFormatJS = str_replace('h24', 'h', $timeFormatJS); $ampm = 0; } else { $ampm = 1; } if(strlen($timeFormatJS)) $timeFormatJS = htmlspecialchars($timeFormatJS, ENT_QUOTES, 'UTF-8'); if(empty($value)) $value = ''; $yearRange = htmlspecialchars($this->yearRange, ENT_QUOTES, 'UTF-8'); $out = "\n" . "getAttributesString($attrs) . " " . "value='$value' " . "data-dateformat='$dateFormatJS' " . "data-timeformat='$timeFormatJS' " . "data-ts='$valueTS' " . "data-ampm='$ampm' " . (strlen($yearRange) ? "data-yearrange='$yearRange' " : '') . "/>"; return $out; } /** * Render value for presentation, non-input * */ public function ___renderValue() { $value = $this->attr('value'); if(!$value) return ''; $format = trim($this->dateInputFormat . ' ' . $this->timeInputFormat); return FieldtypeDatetime::formatDate($value, trim($format)); } /** * Capture setting of the 'value' attribute and convert string dates to unix timestamp * */ public function setAttribute($key, $value) { if($key == 'value') { $value = FieldtypeDatetime::stringToTimestamp($value, $this->dateInputFormat . ' ' . $this->timeInputFormat); } return parent::setAttribute($key, $value); } /** * Date/time Inputfield configuration, per field * */ public function ___getConfigInputfields() { $inputfields = parent::___getConfigInputfields(); $languages = wire('languages'); $f = $this->modules->get('InputfieldInteger'); $f->setAttribute('name', 'size'); $f->label = $this->_('Size'); $f->attr('value', $this->attr('size')); $f->attr('size', 4); $f->description = $this->_('The displayed width of this field (in characters).'); $inputfields->append($f); $f= $this->modules->get('InputfieldRadios'); $f->label = $this->_('Date Picker'); $f->setAttribute('name', 'datepicker'); $f->addOption(self::datepickerNo, $this->_('No date/time picker')); $f->addOption(self::datepickerClick, $this->_('Date/time picker on button click')); $f->addOption(self::datepickerFocus, $this->_('Date/time picker on field focus')); $f->addOption(self::datepickerInline, $this->_('Inline date picker always visible (no time picker)')); $f->attr('value', (int) $this->datepicker); $inputfields->append($f); $f = $this->modules->get("InputfieldText"); $f->attr('name', 'yearRange'); $f->attr('value', $this->yearRange); $f->attr('size', 10); $f->label = $this->_('Date Picker Year Range'); $f->description = $this->_('When the date picker is used, it has a selectable year range minus and plus 10 years from the current year. To extend or reduce that, specify the quantity of years before and after [current year] in this format: "-30:+20", which would show 30 years before now and 20 years after now.'); $f->notes = $this->_('Default when no value present is "-10:+10" which shows a date picker year range 10 years before now, and 10 years after now.'); $f->collapsed = Inputfield::collapsedBlank; $inputfields->append($f); $fieldset = $this->modules->get('InputfieldFieldset'); $fieldset->label = $this->_('Date/Time Input Formats'); $f = $this->modules->get('InputfieldSelect'); $f->attr('name', '_dateInputFormat'); $f->label = $this->_('Date Input Format'); $f->description = $this->_('Select the format to be used for user input to this field. Your selection will populate the field below this, which you may customize further if needed.'); $f->addOption('', $this->_('None')); $date = strtotime('2012-04-08 5:10:02 PM'); foreach(FieldtypeDatetime::getDateFormats() as $format) { $dateFormatted = FieldtypeDatetime::formatDate($date, $format); if($format == 'U') $dateFormatted .= " (unix timestamp)"; $f->addOption($format, $dateFormatted); if($this->dateInputFormat == $format) $f->attr('value', $format); } $f->attr('onchange', "$('#Inputfield_dateInputFormat').val($(this).val());"); $fieldset->add($f); $f = $this->modules->get('InputfieldSelect'); $f->attr('name', '_timeInputFormat'); $f->label = $this->_('Time Input Format'); $f->addOption('', $this->_('None')); $f->description = $this->_('Select an optional time format to be used for input. If used, the calendar option will include a time picker.'); foreach(FieldtypeDatetime::getTimeFormats() as $format) { $timeFormatted = FieldtypeDatetime::formatDate($date, $format); $f->addOption($format, $timeFormatted); if($this->timeInputFormat == $format) $f->attr('value', $format); } $f->attr('onchange', "$('#Inputfield_timeInputFormat').val($(this).val());"); $f->collapsed = Inputfield::collapsedBlank; $fieldset->add($f); $f = $this->modules->get("InputfieldText"); $f->attr('name', 'dateInputFormat'); $f->attr('value', $this->dateInputFormat ? $this->dateInputFormat : self::defaultDateInputFormat); $f->attr('size', 20); $f->label = $this->_('Date Input Format Code'); $f->description = $this->_('This is automatically built from the date select above, unless you modify it.'); $notes = $this->_('See the [PHP date](http://www.php.net/manual/en/function.date.php) function reference for more information on how to customize these formats.'); if($languages) $notes .= "\n" . $this->_('You may optionally specify formats for other languages here as well. Any languages left blank will inherit the default setting.'); $f->notes = $notes; $f->collapsed = Inputfield::collapsedYes; $f1 = $f; $fieldset->add($f); $f = $this->modules->get("InputfieldText"); $f->attr('name', 'timeInputFormat'); $f->attr('value', $this->timeInputFormat ? $this->timeInputFormat : ''); $f->attr('size', 20); $f->label = $this->_('Time Input Format Code'); $f->description = $this->_('This is automatically built from the time select above, unless you modify it.'); $f->notes = $notes; $f->collapsed = Inputfield::collapsedYes; $f2 = $f; if($languages) { $f1->useLanguages = true; $f2->useLanguages = true; foreach($languages as $language) { if($language->isDefault()) continue; $f1->set("value$language", (string) $this->get("dateInputFormat$language")); $f2->set("value$language", (string) $this->get("timeInputFormat$language")); } } $fieldset->add($f1); $fieldset->add($f2); $inputfields->add($fieldset); $f= $this->modules->get('InputfieldCheckbox'); $f->setAttribute('name', 'defaultToday'); $f->attr('value', 1); if($this->defaultToday) $f->attr('checked', 'checked'); $f->label = $this->_("Default to today's date?"); $f->description = $this->_("If checked, this field will hold the current date when no value is entered."); // Default today description $f->columnWidth = 50; $inputfields->append($f); $field = $this->modules->get('InputfieldText'); $field->setAttribute('name', 'placeholder'); $field->label = $this->_('Placeholder Text'); $field->setAttribute('value', $this->attr('placeholder')); $field->description = $this->_('Optional placeholder text that appears in the field when blank.'); $field->columnWidth = 50; $inputfields->append($field); return $inputfields; } }