Newer
Older
$choices = array(
__('Agents') => new ArrayObject(),
__('Teams') => new ArrayObject());
$A = current($choices);
$criteria = $this->getCriteria();
$agents = array();
if (($dept=$config['dept']) && $dept->assignMembersOnly()) {
if (($members = $dept->getMembers($criteria)))
foreach ($members as $member)
$agents[$member->getId()] = $member;
} else {
$agents = Staff::getStaffMembers($criteria);
}
$A['s'.$id] = $name;
next($choices);
$T = current($choices);
if (($teams = Team::getTeams()))
foreach ($teams as $id => $name)
$T['t'.$id] = $name;
$this->_choices = $choices;
}
return $this->_choices;
function getValue() {
if (($value = parent::getValue()) && ($id=$this->getClean()))
return $value[$id];
}
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
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
function parse($id) {
return $this->to_php(null, $id);
}
function to_php($value, $id=false) {
if (is_array($id)) {
reset($id);
$id = key($id);
}
return $id;
}
function to_database($value) {
return (is_object($value))
? array($value->getName(), $value->getId())
: $value;
}
function toString($value) {
return (string) $value;
}
function searchable($value) {
return null;
}
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(/*@trans*/ 'Dynamic Fields', function() {
return array(
'assignee' => array(__('Assignee'), AssigneeField),
);
});
class TicketStateField extends ChoiceField {
'name' => /* @trans, @context "ticket state name" */ 'Open',
'verb' => /* @trans, @context "ticket state action" */ 'Open'
'name' => /* @trans, @context "ticket state name" */ 'Closed',
'verb' => /* @trans, @context "ticket state action" */ 'Close'
// Private states
static $_privatestates = array(
'name' => /* @trans, @context "ticket state name" */ 'Archived',
'verb' => /* @trans, @context "ticket state action" */ 'Archive'
'name' => /* @trans, @context "ticket state name" */ 'Deleted',
'verb' => /* @trans, @context "ticket state action" */ 'Delete'
);
function hasIdValue() {
return true;
}
function isChangeable() {
return false;
}
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']);
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
}
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) {
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
$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)) {
if (function_exists('apc_fetch')) {
$key = md5(SECRET_SALT . GIT_VERSION . 'filetypes');
$filetypes = apc_fetch($key);
}
if (!$filetypes)
$filetypes = YamlDataParser::load(INCLUDE_DIR . '/config/filetype.yaml');
if ($key)
apc_store($key, $filetypes, 7200);
}
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 = GenericAttachments::forIdAndType(
// Combine the field and entry ids to make the key
sprintf('%u', crc32('E'.$this->get('id').$e->get('id'))),
'E');
}
return $this->attachments ?: array();
function setAttachments(GenericAttachments $att) {
$this->attachments = $att;
}
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)) {
$this->attachments->keepOnlyFileIds($value);
}
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 to_config($value) {
if ($value && is_array($value))
$value = array_values($value);
return $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($field=false) {
// Delete associated attachments from the database, if any
$this->getFiles();
if (isset($this->attachments)) {
$this->attachments->deleteAll();
}
}
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
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'),
);
}
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
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');
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
}
}
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());
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
}
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['autofocus']))
$autofocus = 'autofocus';
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, $autofocus))); ?>
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;
}