Newer
Older
function getChoices($verbose=false) {
static $_choices;
if (!isset($_choices)) {
// Translate and cache the choices
foreach (static::$_states as $k => $v)
$_choices[$k] = _P('ticket state name', $v['name']);
$this->ht['default'] = '';
}
return $_choices;
}
function getChoice($state) {
if ($state && is_array($state))
$state = key($state);
if (isset(static::$_states[$state]))
return _P('ticket state name', static::$_states[$state]['name']);
if (isset(static::$_privatestates[$state]))
return _P('ticket state name', static::$_privatestates[$state]['name']);
}
function getConfigurationOptions() {
return array(
'prompt' => new TextboxField(array(
'id'=>2, 'label'=> __('Prompt'), 'required'=>false, 'default'=>'',
'hint'=> __('Leading text shown before a value is selected'),
'configuration'=>array('size'=>40, 'length'=>40),
)),
);
}
static function getVerb($state) {
if (isset(static::$_states[$state]))
return _P('ticket state action', static::$_states[$state]['verb']);
if (isset(static::$_privatestates[$state]))
return _P('ticket state action', static::$_privatestates[$state]['verb']);
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
}
FormField::addFieldTypes('Dynamic Fields', function() {
return array(
'state' => array('Ticket State', TicketStateField, false),
);
});
class TicketFlagField extends ChoiceField {
// Supported flags (TODO: move to configurable custom list)
static $_flags = array(
'onhold' => array(
'flag' => 1,
'name' => 'Onhold',
'states' => array('open'),
),
'overdue' => array(
'flag' => 2,
'name' => 'Overdue',
'states' => array('open'),
),
'answered' => array(
'flag' => 4,
'name' => 'Answered',
'states' => array('open'),
)
);
var $_choices;
function hasIdValue() {
return true;
}
function isChangeable() {
return true;
}
function getChoices($verbose=false) {
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
$this->ht['default'] = '';
if (!$this->_choices) {
foreach (static::$_flags as $k => $v)
$this->_choices[$k] = $v['name'];
}
return $this->_choices;
}
function getConfigurationOptions() {
return array(
'prompt' => new TextboxField(array(
'id'=>2, 'label'=>'Prompt', 'required'=>false, 'default'=>'',
'hint'=>'Leading text shown before a value is selected',
'configuration'=>array('size'=>40, 'length'=>40),
)),
);
}
}
FormField::addFieldTypes('Dynamic Fields', function() {
return array(
'flags' => array('Ticket Flags', TicketFlagField, false),
);
});
class FileUploadField extends FormField {
static $widget = 'FileUploadWidget';
protected $attachments;
static function getFileTypes() {
static $filetypes;
if (!isset($filetypes))
$filetypes = YamlDataParser::load(INCLUDE_DIR . '/config/filetype.yaml');
return $filetypes;
}
function getConfigurationOptions() {
// Compute size selections
$sizes = array('262144' => '— '.__('Small').' —');
$next = 512 << 10;
$max = strtoupper(ini_get('upload_max_filesize'));
$limit = (int) $max;
if (!$limit) $limit = 2 << 20; # 2M default value
elseif (strpos($max, 'K')) $limit <<= 10;
elseif (strpos($max, 'M')) $limit <<= 20;
elseif (strpos($max, 'G')) $limit <<= 30;
while ($next <= $limit) {
// Select the closest, larger value (in case the
// current value is between two)
$sizes[$next] = Format::file_size($next);
$next *= 2;
}
// Add extra option if top-limit in php.ini doesn't fall
// at a power of two
if ($next < $limit * 2)
$sizes[$limit] = Format::file_size($limit);
foreach (self::getFileTypes() as $type=>$info) {
$types[$type] = $info['description'];
}
return array(
'size' => new ChoiceField(array(
'label'=>__('Maximum File Size'),
'hint'=>__('Choose maximum size of a single file uploaded to this field'),
'default'=>$cfg->getMaxFileSize(),
'mimetypes' => new ChoiceField(array(
'label'=>__('Restrict by File Type'),
'hint'=>__('Optionally, choose acceptable file types.'),
'required'=>false,
'choices'=>$types,
'configuration'=>array('multiselect'=>true,'prompt'=>__('No restrictions'))
'extensions' => new TextareaField(array(
'label'=>__('Additional File Type Filters'),
'hint'=>__('Optionally, enter comma-separated list of additional file types, by extension. (e.g .doc, .pdf).'),
'configuration'=>array('html'=>false, 'rows'=>2),
)),
'max' => new TextboxField(array(
'label'=>__('Maximum Files'),
'hint'=>__('Users cannot upload more than this many files.'),
'default'=>false,
'required'=>false,
'validator'=>'number',
'configuration'=>array('size'=>8, 'length'=>4, 'placeholder'=>__('No limit')),
function hasSpecialSearch() {
return false;
}
/**
* Called from the ajax handler for async uploads via web clients.
*/
function ajaxUpload($bypass=false) {
$config = $this->getConfiguration();
$files = AttachmentFile::format($_FILES['upload'],
// For numeric fields assume configuration exists
!is_numeric($this->get('id')));
if (count($files) != 1)
Http::response(400, 'Send one file at a time');
$file = array_shift($files);
$file['name'] = urldecode($file['name']);
if (!$bypass && !$this->isValidFileType($file['name'], $file['type']))
Http::response(415, 'File type is not allowed');
$config = $this->getConfiguration();
if (!$bypass && $file['size'] > $config['size'])
Http::response(413, 'File is too large');
if (!($F = AttachmentFile::upload($file)))
Http::response(500, 'Unable to store file: '. $file['error']);
return $F->getId();
/**
* Called from FileUploadWidget::getValue() when manual upload is used
* for browsers which do not support the HTML5 way of uploading async.
*/
function uploadFile($file) {
if (!$this->isValidFileType($file['name'], $file['type']))
throw new FileUploadError(__('File type is not allowed'));
$config = $this->getConfiguration();
if ($file['size'] > $config['size'])
throw new FileUploadError(__('File size is too large'));
return AttachmentFile::upload($file);
}
/**
* Called from API and email routines and such to handle attachments
* sent other than via web upload
*/
function uploadAttachment(&$file) {
if (!$this->isValidFileType($file['name'], $file['type']))
throw new FileUploadError(__('File type is not allowed'));
if (is_callable($file['data']))
$file['data'] = $file['data']();
if (!isset($file['size'])) {
// bootstrap.php include a compat version of mb_strlen
if (extension_loaded('mbstring'))
$file['size'] = mb_strlen($file['data'], '8bit');
else
$file['size'] = strlen($file['data']);
}
$config = $this->getConfiguration();
if ($file['size'] > $config['size'])
throw new FileUploadError(__('File size is too large'));
if (!$F = AttachmentFile::create($file))
throw new FileUploadError(__('Unable to save file'));
return $F;
}
function isValidFileType($name, $type=false) {
$config = $this->getConfiguration();
// Check MIME type - file ext. shouldn't be solely trusted.
if ($type && $config['__mimetypes']
&& in_array($type, $config['__mimetypes']))
// Return true if all file types are allowed (.*)
if (!$config['__extensions'] || in_array('.*', $config['__extensions']))
$allowed = $config['__extensions'];
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
return ($ext && is_array($allowed) && in_array(".$ext", $allowed));
}
function getFiles() {
if (!isset($this->attachments) && ($a = $this->getAnswer())
&& ($e = $a->getEntry()) && ($e->get('id'))
) {
$this->attachments = new GenericAttachments(
// Combine the field and entry ids to make the key
sprintf('%u', crc32('E'.$this->get('id').$e->get('id'))),
'E');
}
return $this->attachments ? $this->attachments->getAll() : array();
}
function getConfiguration() {
$config = parent::getConfiguration();
$_types = self::getFileTypes();
$mimetypes = array();
$extensions = array();
if (isset($config['mimetypes']) && is_array($config['mimetypes'])) {
foreach ($config['mimetypes'] as $type=>$desc) {
foreach ($_types[$type]['types'] as $mime=>$exts) {
$mimetypes[$mime] = true;
if (is_array($exts))
foreach ($exts as $ext)
$extensions['.'.$ext] = true;
}
}
}
if (strpos($config['extensions'], '.*') !== false)
$config['extensions'] = '';
if (is_string($config['extensions'])) {
foreach (preg_split('/\s+/', str_replace(',',' ', $config['extensions'])) as $ext) {
if (!$ext) {
continue;
}
elseif (strpos($ext, '/')) {
}
else {
if ($ext[0] != '.')
$ext = '.' . $ext;
// Ensure that the extension is lower-cased for comparison latr
$ext = strtolower($ext);
// Add this to the MIME types list so it can be exported to
// the @accept attribute
if (!isset($extensions[$ext]))
$mimetypes[$ext] = true;
$extensions[$ext] = true;
}
$config['__extensions'] = array_keys($extensions);
}
elseif (is_array($config['extensions'])) {
$config['__extensions'] = $config['extensions'];
}
// 'mimetypes' is the array represented from the user interface,
// '__mimetypes' is a complete list of supported MIME types.
$config['__mimetypes'] = array_keys($mimetypes);
return $config;
}
// When the field is saved to database, encode the ID listing as a json
// array. Then, inspect the difference between the files actually
// attached to this field
function to_database($value) {
$this->getFiles();
if (isset($this->attachments)) {
$ids = array();
// Handle deletes
foreach ($this->attachments->getAll() as $f) {
if (!in_array($f->id, $value))
$this->attachments->delete($f->id);
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
}
// Handle new files
foreach ($value as $id) {
if (!in_array($id, $ids))
$this->attachments->upload($id);
}
}
return JsonDataEncoder::encode($value);
}
function parse($value) {
// Values in the database should be integer file-ids
return array_map(function($e) { return (int) $e; },
$value ?: array());
}
function to_php($value) {
return JsonDataParser::decode($value);
}
function display($value) {
$links = array();
foreach ($this->getFiles() as $f) {
$links[] = sprintf('<a class="no-pjax" href="%s">%s</a>',
Format::htmlchars($f->file->getDownloadUrl()),
Format::htmlchars($f->file->name));
}
return implode('<br/>', $links);
}
function toString($value) {
$files = array();
foreach ($this->getFiles() as $f) {
}
return implode(', ', $files);
}
function db_cleanup() {
// Delete associated attachments from the database, if any
$this->getFiles();
if (isset($this->attachments)) {
$this->attachments->deleteAll();
}
}
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
function asVar($value, $id=false) {
return new FileFieldAttachments($this->getFiles());
}
function asVarType() {
return 'FileFieldAttachments';
}
}
class FileFieldAttachments {
var $files;
function __construct($files) {
$this->files = $files;
}
function __toString() {
$files = array();
foreach ($this->files as $f) {
$files[] = $f->file->name;
}
return implode(', ', $files);
}
function getVar($tag) {
switch ($tag) {
case 'names':
return $this->__toString();
case 'files':
throw new OOBContent(OOBContent::FILES, $this->files->all());
}
}
static function getVarScope() {
return array(
'names' => __('List of file names'),
'files' => __('Attached files'),
);
}
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
class InlineFormData extends ArrayObject {
var $_form;
function __construct($form, array $data=array()) {
parent::__construct($data);
$this->_form = $form;
}
function getVar($tag) {
foreach ($this->_form->getFields() as $f) {
if ($f->get('name') == $tag)
return $this[$f->get('id')];
}
}
}
class InlineFormField extends FormField {
static $widget = 'InlineFormWidget';
var $_iform = null;
function validateEntry($value) {
if (!$this->getInlineForm()->isValid()) {
$this->_errors[] = __('Correct errors in the inline form');
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
}
}
function parse($value) {
// The InlineFieldWidget returns an array of cleaned data
return $value;
}
function to_database($value) {
return JsonDataEncoder::encode($value);
}
function to_php($value) {
$data = JsonDataParser::decode($value);
// The InlineFormData helps with the variable replacer API
return new InlineFormData($this->getInlineForm(), $data);
}
function display($data) {
$form = $this->getInlineForm();
ob_start(); ?>
<div><?php
foreach ($form->getFields() as $field) { ?>
<span style="display:inline-block;padding:0 5px;vertical-align:top">
<strong><?php echo Format::htmlchars($field->get('label')); ?></strong>
<div><?php
$value = $data[$field->get('id')];
echo $field->display($value); ?></div>
</span><?php
} ?>
</div><?php
return ob_get_clean();
}
function getInlineForm($data=false) {
$form = $this->get('form');
if (is_array($form)) {
$form = new SimpleForm($form, $data ?: $this->value ?: $this->getSource());
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
}
return $form;
}
}
class InlineDynamicFormField extends FormField {
function getInlineForm($data=false) {
if (!isset($this->_iform) || $data) {
$config = $this->getConfiguration();
$this->_iform = DynamicForm::lookup($config['form']);
if ($data)
$this->_iform = $this->_iform->getForm($data);
}
return $this->_iform;
}
function getConfigurationOptions() {
$forms = DynamicForm::objects()->filter(array('type'=>'G'))
->values_flat('id', 'title');
$choices = array();
foreach ($forms as $row) {
list($id, $title) = $row;
$choices[$id] = $title;
}
return array(
'form' => new ChoiceField(array(
'id'=>2, 'label'=>'Inline Form', 'required'=>true,
'default'=>'', 'choices'=>$choices
)),
);
}
}
class InlineFormWidget extends Widget {
function render($mode=false) {
$form = $this->field->getInlineForm();
if (!$form)
return;
// Handle first-step edits -- load data from $this->value
if ($form instanceof DynamicForm && !$form->getSource())
$form = $form->getForm($this->value);
$inc = ($mode == 'client') ? CLIENTINC_DIR : STAFFINC_DIR;
include $inc . 'templates/inline-form.tmpl.php';
}
function getValue() {
$data = $this->field->getSource();
if (!$data)
return null;
$form = $this->field->getInlineForm($data);
if (!$form)
return null;
return $form->getClean();
}
}
function __construct($field) {
$this->field = $field;
$this->name = $field->getFormName();
$this->id = '_' . $this->name;
$this->value = $this->getValue();
if (!isset($this->value) && is_object($this->field->getAnswer()))
$this->value = $this->field->getAnswer()->getValue();
if (!isset($this->value) && isset($this->field->value))
$data = $this->field->getSource();
// Search for HTML form name first
if (isset($data[$this->name]))
return $data[$this->name];
elseif (isset($data[$this->field->get('name')]))
return $data[$this->field->get('name')];
elseif (isset($data[$this->field->get('id')]))
return $data[$this->field->get('id')];
/**
* getJsValueGetter
*
* Used with the dependent fields feature, this function should return a
* single javascript expression which can be used in a larger expression
* (<> == true, where <> is the result of this function). The %s token
* will be replaced with a jQuery variable representing this widget.
*/
function getJsValueGetter() {
return '%s.val()';
}
}
class TextboxWidget extends Widget {
function render($options=array(), $extraConfig=false) {
if (is_array($extraConfig)) {
foreach ($extraConfig as $k=>$v)
if (!isset($config[$k]) || !$config[$k])
$config[$k] = $v;
}
if (isset($config['size']))
$size = "size=\"{$config['size']}\"";
if (isset($config['length']) && $config['length'])
$maxlength = "maxlength=\"{$config['length']}\"";
if (isset($config['classes']))
$classes = 'class="'.$config['classes'].'"';
if (isset($config['autocomplete']))
$autocomplete = 'autocomplete="'.($config['autocomplete']?'on':'off').'"';
if (isset($config['disabled']))
$disabled = 'disabled="disabled"';
if (isset($config['translatable']) && $config['translatable'])
$translatable = 'data-translate-tag="'.$config['translatable'].'"';
$type = static::$input_type;
$types = array(
'email' => 'email',
'phone' => 'tel',
);
if ($type == 'text' && isset($types[$config['validator']]))
$type = $types[$config['validator']];
$placeholder = sprintf('placeholder="%s"', $this->field->getLocal('placeholder',
$config['placeholder']));
<input type="<?php echo $type; ?>"
id="<?php echo $this->id; ?>"
<?php echo implode(' ', array_filter(array(
$size, $maxlength, $classes, $autocomplete, $disabled,
$translatable, $placeholder))); ?>
name="<?php echo $this->name; ?>"
value="<?php echo Format::htmlchars($this->value); ?>"/>
<?php
}
}
class TextboxSelectionWidget extends TextboxWidget {
//TODO: Support multi-input e.g comma separated inputs
function render($options=array()) {
if ($this->value && is_array($this->value))
$this->value = current($this->value);
parent::render($options);
}
function getValue() {
$value = parent::getValue();
if ($value && ($item=$this->field->lookupChoice((string) $value)))
$value = $item;
return $value;
}
}
class PasswordWidget extends TextboxWidget {
static $input_type = 'password';
function render($mode=false, $extra=false) {
$extra = array();
if ($this->field->value) {
$extra['placeholder'] = '••••••••••••';
}
return parent::render($mode, $extra);
}
if ($_SERVER['REQUEST_METHOD'] != 'POST'
|| $this->field->getForm()->isValid())
$class = $cols = $rows = $maxlength = "";
if (isset($config['rows']))
$rows = "rows=\"{$config['rows']}\"";
if (isset($config['cols']))
$cols = "cols=\"{$config['cols']}\"";
if (isset($config['length']) && $config['length'])
$maxlength = "maxlength=\"{$config['length']}\"";
if (isset($config['html']) && $config['html']) {
$class = array('richtext', 'no-bar');
$class[] = @$config['size'] ?: 'small';
$class = sprintf('class="%s"', implode(' ', $class));
$this->value = Format::viewableImages($this->value);
}
if (isset($config['context']))
$attrs['data-root-context'] = '"'.$config['context'].'"';
<span style="display:inline-block;width:100%">
<textarea <?php echo $rows." ".$cols." ".$maxlength." ".$class
.' '.Format::array_implode('=', ' ', $attrs)
.' placeholder="'.$config['placeholder'].'"'; ?>
id="<?php echo $this->id; ?>"
name="<?php echo $this->name; ?>"><?php
echo Format::htmlchars($this->value);
?></textarea>
</span>
<?php
}
}
class PhoneNumberWidget extends Widget {
$config = $this->field->getConfiguration();
list($phone, $ext) = explode("X", $this->value);
?>
<input id="<?php echo $this->id; ?>" type="tel" name="<?php echo $this->name; ?>" value="<?php
echo Format::htmlchars($phone); ?>"/><?php
// Allow display of extension field even if disabled if the phone
// number being edited has an extension
if ($ext || $config['ext']) { ?> <?php echo __('Ext'); ?>:
echo $this->name; ?>-ext" value="<?php echo Format::htmlchars($ext);
?>" size="5"/>
$data = $this->field->getSource();
$base = parent::getValue();
if ($base === null)
return $base;
$ext = $data["{$this->name}-ext"];
// NOTE: 'X' is significant. Don't change it
}
}
class ChoicesWidget extends Widget {
function render($options=array()) {
$mode = isset($options['mode']) ? $options['mode'] : null;
if ($mode == 'view') {
if (!($val = (string) $this->field))
$val = sprintf('<span class="faded">%s</span>', __('None'));
echo $val;
return;
}
if ($mode == 'search') {
$config['multiselect'] = true;
}
// Determine the value for the default (the one listed if nothing is
// selected)
$prompt = ($config['prompt'])
? $this->field->getLocal('prompt', $config['prompt'])
: __('Select'
/* Used as a default prompt for a custom drop-down list */);
// We don't consider the 'default' when rendering in 'search' mode
if (!strcasecmp($mode, 'search')) {
$def_val = $prompt;
} else {
$def_key = $this->field->get('default');
if (!$def_key && $config['default'])
$def_key = $config['default'];
if (is_array($def_key))
$def_key = key($def_key);
$have_def = isset($choices[$def_key]);
$def_val = $have_def ? $choices[$def_key] : $prompt;
$values = $this->value;
if (!is_array($values) && isset($values)) {
$values = array($values => $this->field->getChoice($values));
}
$values = $have_def ? array($def_key => $choices[$def_key]) : array();
?>
<select name="<?php echo $this->name; ?>[]"
id="<?php echo $this->id; ?>"
data-placeholder="<?php echo $prompt; ?>"
<?php if ($config['multiselect'])
<?php if (!$have_def && !$config['multiselect']) { ?>
<option value="<?php echo $def_key; ?>">— <?php
echo $def_val; ?> —</option>
$this->emitChoices($choices, $values, $have_def, $def_key); ?>
if ($config['multiselect']) {
?>
<script type="text/javascript">
$(function() {
.select2({'minimumResultsForSearch':10, 'width': '350px'});
});
</script>
<?php
}
function emitChoices($choices, $values=array(), $have_def=false, $def_key=null) {
reset($choices);
if (is_array(current($choices)) || current($choices) instanceof Traversable)
return $this->emitComplexChoices($choices, $values, $have_def, $def_key);
foreach ($choices as $key => $name) {
if (!$have_def && $key == $def_key)
continue; ?>
<option value="<?php echo $key; ?>" <?php
if (isset($values[$key])) echo 'selected="selected"';
?>><?php echo $name; ?></option>
<?php
}
}
function emitComplexChoices($choices, $values=array(), $have_def=false, $def_key=null) {
foreach ($choices as $label => $group) { ?>
<optgroup label="<?php echo $label; ?>"><?php
foreach ($group as $key => $name) {
if (!$have_def && $key == $def_key)
continue; ?>
<option value="<?php echo $key; ?>" <?php
if (isset($values[$key])) echo 'selected="selected"';
?>><?php echo $name; ?></option>
<?php } ?>
</optgroup><?php
}
}
function getValue() {
if (!($value = parent::getValue()))
return null;
if ($value && !is_array($value))
$value = array($value);
// Assume multiselect
$values = array();
$choices = $this->field->getChoices();
if ($choices && is_array($value)) {
// Complex choices
if (is_array(current($choices))
|| current($choices) instanceof Traversable) {
foreach ($choices as $label => $group) {
foreach ($group as $k => $v)
if (in_array($k, $value))
$values[$k] = $v;
}
} else {
foreach($value as $k => $v) {
if (isset($choices[$v]))
$values[$v] = $choices[$v];
elseif (($i=$this->field->lookupChoice($v)))
$values += $i;
}
return $values;
}
function getJsValueGetter() {
return '%s.find(":selected").val()';
}
}
class CheckboxWidget extends Widget {
function __construct($field) {
parent::__construct($field);
$this->name = '_field-checkboxes';
}
if (!isset($this->value))
$this->value = $this->field->get('default');
<input id="<?php echo $this->id; ?>" style="vertical-align:top;"
type="checkbox" name="<?php echo $this->name; ?>[]" <?php
if ($this->value) echo 'checked="checked"'; ?> value="<?php
echo $this->field->get('id'); ?>"/>
<?php
if ($config['desc']) { ?>
<em style="display:inline-block"><?php
echo Format::viewableImages($config['desc']); ?></em>
<?php }
}
function getValue() {
$data = $this->field->getSource();
if (count($data)) {
if (!isset($data[$this->name]))
return false;
return @in_array($this->field->get('id'), $data[$this->name]);
function getJsValueGetter() {
return '%s.is(":checked")';
}
class DatetimePickerWidget extends Widget {
$config = $this->field->getConfiguration();
if ($this->value) {
$this->value = is_int($this->value) ? $this->value :
strtotime($this->value);
if ($config['gmt']) {
// Convert to GMT time
$tz = new DateTimeZone($cfg->getTimezone());
$D = DateTime::createFromFormat('U', $this->value);
$this->value += $tz->getOffset($D);
}
list($hr, $min) = explode(':', date('H:i', $this->value));
$this->value = Format::date($this->value, false, false, 'UTC');
}
?>
<input type="text" name="<?php echo $this->name; ?>"
id="<?php echo $this->id; ?>"
value="<?php echo Format::htmlchars($this->value); ?>" size="12"
autocomplete="off" class="dp" />
<script type="text/javascript">
$(function() {
$('input[name="<?php echo $this->name; ?>"]').datepicker({
<?php
if ($config['min'])
echo "minDate: new Date({$config['min']}000),";
if ($config['max'])
echo "maxDate: new Date({$config['max']}000),";
elseif (!$config['future'])
echo "maxDate: new Date().getTime(),";
?>
numberOfMonths: 2,
showButtonPanel: true,
buttonImage: './images/cal.png',
dateFormat: $.translate_format('<?php echo $cfg->getDateFormat(true); ?>')
});
});
</script>
<?php
if ($config['time'])
// TODO: Add time picker -- requires time picker or selection with
// Misc::timeDropdown
echo ' ' . Misc::timeDropdown($hr, $min, $this->name . ':time');
}
/**
* Function: getValue
* Combines the datepicker date value and the time dropdown selected
* time value into a single date and time string value.
*/
function getValue() {
$data = $this->field->getSource();
$config = $this->field->getConfiguration();
if ($datetime = parent::getValue()) {
$datetime = is_int($datetime) ? $datetime :
strtotime($datetime);
if ($datetime && isset($data[$this->name . ':time'])) {
list($hr, $min) = explode(':', $data[$this->name . ':time']);
$datetime += $hr * 3600 + $min * 60;
}
if ($datetime && $config['gmt']) {
// Convert to GMT time
$tz = new DateTimeZone($cfg->getTimezone());
$D = DateTime::createFromFormat('U', $datetime);
$datetime -= $tz->getOffset($D);
}