Newer
Older
'entry' => array(
'constraint' => array('entry_id' => 'DynamicFormEntry.id'),
),
),
);
var $field;
var $form;
var $entry;
var $deleted = false;
var $_value;
function getEntry() {
return $this->entry;
}
function getForm() {
if (!$this->form)
$this->form = $this->getEntry()->getForm();
return $this->form;
}
function getField() {
if (!isset($this->field)) {
$f = DynamicFormField::lookup($this->get('field_id'));
$this->field = $f->getImpl($f);
}
return $this->field;
}
function getValue() {
if (!isset($this->_value) && isset($this->value)) {
//XXX: We're settting the value here to avoid infinite loop
$this->_value = false;
$this->_value = $this->getField()->to_php(
$this->get('value'), $this->get('value_id'));
function getIdValue() {
return $this->get('value_id');
}
function isDeleted() {
return $this->deleted;
}
function toString() {
return $this->getField()->toString($this->getValue());
}
function display() {
return $this->getField()->display($this->getValue());
}
function getSearchable($include_label=false) {
if ($include_label)
$label = Format::searchable($this->getField()->getLabel()) . " ";
return sprintf("%s%s", $label,
$this->getField()->searchable($this->getValue())
);
}
function getSearchKeys() {
$val = $this->getField()->to_php(
$this->get('value'), $this->get('value_id'));
if (is_array($val))
return array_keys($val);
elseif (is_object($val) && method_exists($val, 'getId'))
return array($val->getId());
return (is_object($this->getValue()))
? $this->getValue() : $this->toString();
}
function getVar($tag) {
if (is_object($this->getValue()) && method_exists($this->getValue(), 'getVar'))
return $this->getValue()->getVar($tag);
function __toString() {
$v = $this->toString();
return is_string($v) ? $v : (string) $this->getValue();
}
class SelectionField extends FormField {
static $widget = 'ChoicesWidget';
function getListId() {
list(,$list_id) = explode('-', $this->get('type'));
return $list_id ?: $this->get('list_id');
if (!$this->_list)
$this->_list = DynamicList::lookup($this->getListId());
function getWidget() {
$config = $this->getConfiguration();
$widgetClass = false;
if ($config['widget'] == 'typeahead')
$widgetClass = 'TypeaheadSelectionWidget';
return parent::getWidget($widgetClass);
}
if (!($list=$this->getList()))
return null;
$config = $this->getConfiguration();
$choices = $this->getChoices();
$selection = array();
if ($value && is_array($value)) {
foreach ($value as $k=>$v) {
if (($i=$list->getItem((int) $k)))
$selection[$i->getId()] = $i->getValue();
elseif (isset($choices[$v]))
$selection[$v] = $choices[$v];
}
}
return $selection;
}
function to_database($value) {
if (is_array($value)) {
reset($value);
}
if ($value && is_array($value))
$value = JsonDataEncoder::encode($value);
return $value;
function to_php($value, $id=false) {
if (is_string($value))
$value = JsonDataParser::parse($value) ?: $value;
if (!is_array($value)) {
$choices = $this->getChoices();
foreach (explode(',', $value) as $V) {
if (isset($choices[$V]))
$values[$V] = $choices[$V];
}
if ($id && isset($choices[$id]))
$values[$id] = $choices[$id];
if ($values)
return $values;
// else return $value unchanged
// Don't set the ID here as multiselect prevents using exactly one
// ID value. Instead, stick with the JSON value only.
return $this->getList()->getForm();
$fields = new ListObject(array(
new TextboxField(array(
// XXX: i18n: Change to a better word when the UI changes
'label' => '['.__('Abbrev').']',
'id' => 'abb',
))
));
$form = $this->getList()->getForm();
if ($form && ($F = $form->getFields()))
$fields->extend($F);
return $fields;
function toString($items) {
return ($items && is_array($items))
? implode(', ', $items) : (string) $items;
function validateEntry($entry) {
parent::validateEntry($entry);
if (!$this->errors()) {
$config = $this->getConfiguration();
if ($config['typeahead']
&& ($entered = $this->getWidget()->getEnteredValue())
&& !in_array($entered, $entry))
$this->_errors[] = __('Select a value from the list');
}
function getConfigurationOptions() {
return array(
'id'=>1,
'label'=>__('Widget'),
'required'=>false, 'default' => 'dropdown',
'dropdown' => __('Drop Down'),
'typeahead' =>__('Typeahead'),
),
'configuration'=>array(
'multiselect' => false,
),
'hint'=>__('Typeahead will work better for large lists')
'id'=>2,
'label'=>__(/* Type of widget allowing multiple selections */ 'Multiselect'),
'required'=>false, 'default'=>false,
'desc'=>__('Allow multiple selections')),
'visibility' => new VisibilityConstraint(
new Q(array('widget__eq'=>'dropdown')),
VisibilityConstraint::HIDDEN
),
'id'=>3,
'label'=>__('Prompt'), 'required'=>false, 'default'=>'',
'hint'=>__('Leading text shown before a value is selected'),
'configuration'=>array('size'=>40, 'length'=>40),
)),
'default' => new SelectionField(array(
'id'=>4, 'label'=>__('Default'), 'required'=>false, 'default'=>'',
'list_id'=>$this->getListId(),
'configuration' => array('prompt'=>__('Select a Default')),
)),
function getConfiguration() {
$config = parent::getConfiguration();
if ($config['widget'])
$config['typeahead'] = $config['widget'] == 'typeahead';
//Typeahed doesn't support multiselect for now TODO: Add!
if ($config['typeahead'])
$config['multiselect'] = false;
return $config;
}
function getChoices($verbose=false) {
if (!$this->_choices || $verbose) {
$this->_choices = array();
foreach ($this->getList()->getItems() as $i)
$this->_choices[$i->getId()] = $i->getValue();
// Retired old selections
$values = ($a=$this->getAnswer()) ? $a->getValue() : array();
if ($values && is_array($values)) {
foreach ($values as $k => $v) {
if (!isset($this->_choices[$k])) {
if ($verbose) $v .= ' '.__('(retired)');
}
return $this->_choices;
}
function getChoice($value) {
$choices = $this->getChoices();
if ($value && is_array($value)) {
$selection = $value;
} elseif (isset($choices[$value]))
$selection[] = $choices[$value];
elseif ($this->get('default'))
$selection[] = $choices[$this->get('default')];
return $selection;
}
// Start with the filter data for the list item as the [0] index
$data = array(parent::getFilterData());
if (($v = $this->getClean())) {
// Add in the properties for all selected list items in sub
// labeled by their field id
foreach ($v as $id=>$L) {
if (!($li = DynamicListItem::lookup($id)))
continue;
foreach ($li->getFilterData() as $prop=>$value) {
if (!isset($data[$prop]))
$data[$prop] = $value;
else
$data[$prop] .= " $value";
}
}
class TypeaheadSelectionWidget extends ChoicesWidget {
function render($how) {
if ($how == 'search')
return parent::render($how);
$name = $this->getEnteredValue();
$config = $this->field->getConfiguration();
if (is_array($this->value)) {
$name = $name ?: current($this->value);
$value = key($this->value);
else {
// Pull configured default (if configured)
$def_key = $this->field->get('default');
if (!$def_key && $config['default'])
$def_key = $config['default'];
if (is_array($def_key))
$name = current($def_key);
}
$source = array();
foreach ($this->field->getList()->getItems() as $i)
$source[] = array(
'info' => sprintf('%s%s',
(($extra= $i->getAbbrev()) ? " — $extra" : '')),
<input type="text" size="30" name="<?php echo $this->name; ?>_name"
id="<?php echo $this->name; ?>" value="<?php echo Format::htmlchars($name); ?>"
placeholder="<?php echo $config['prompt'];
?>" autocomplete="off" />
<input type="hidden" name="<?php echo $this->name;
?>[<?php echo $value; ?>]" id="<?php echo $this->name;
?>_id" value="<?php echo Format::htmlchars($name); ?>"/>
<script type="text/javascript">
$(function() {
$('input#<?php echo $this->name; ?>').typeahead({
source: <?php echo JsonDataEncoder::encode($source); ?>,
$('input#<?php echo $this->name; ?>_name').val(item['value'])
$('input#<?php echo $this->name; ?>_id')
.attr('name', '<?php echo $this->name; ?>[' + item['id'] + ']')
.val(item['value']);
}
});
});
</script>
</span>
<?php
}
function getValue() {
$data = $this->field->getSource();
if (isset($data[$this->name]))
return $data[$this->name];
return parent::getValue();
}
function getEnteredValue() {
// Used to verify typeahead fields
$data = $this->field->getSource();
if (isset($data[$this->name.'_name'])) {
// Drop the extra part, if any
$v = $data[$this->name.'_name'];
$v = substr($v, 0, strrpos($v, ' — '));
return trim($v);
}
return parent::getValue();
}