diff --git a/include/ajax.forms.php b/include/ajax.forms.php index 47ace2a54aecae50695a91abda04ced0db72ba71..84b2cb3d8da8302fa1ed1fd0ad9600ea8b8fcf4a 100644 --- a/include/ajax.forms.php +++ b/include/ajax.forms.php @@ -39,9 +39,10 @@ class DynamicFormsAjaxAPI extends AjaxController { function saveFieldConfiguration($field_id) { $field = DynamicFormField::lookup($field_id); if (!$field->setConfiguration()) - include(STAFFINC_DIR . 'templates/dynamic-field-config.tmpl.php'); + return (include STAFFINC_DIR . 'templates/dynamic-field-config.tmpl.php'); else $field->save(); + Http::response(201, 'Field successfully updated'); } function deleteAnswer($entry_id, $field_id) { @@ -74,9 +75,11 @@ class DynamicFormsAjaxAPI extends AjaxController { Http::response(404, 'No such list item'); if (!$item->setConfiguration()) - include(STAFFINC_DIR . 'templates/list-item-properties.tmpl.php'); + return (include STAFFINC_DIR . 'templates/list-item-properties.tmpl.php'); else $item->save(); + + Http::response(201, 'Successfully updated record'); } } ?> diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index bb95d76b3f3cc6295603fc712f35b55a565bf4f8..46c5045c3c867bae66eca202686517d610d610bc 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -696,9 +696,14 @@ class DynamicFormEntry extends VerySimpleModel { function forTicket($ticket_id, $force=false) { static $entries = array(); - if (!isset($entries[$ticket_id]) || $force) - $entries[$ticket_id] = DynamicFormEntry::objects() + if (!isset($entries[$ticket_id]) || $force) { + $stuff = DynamicFormEntry::objects() ->filter(array('object_id'=>$ticket_id, 'object_type'=>'T')); + // If forced, don't cache the result + if ($force) + return $stuff; + $entries[$ticket_id] = &$stuff; + } return $entries[$ticket_id]; } function setTicketId($ticket_id) { @@ -936,7 +941,7 @@ class DynamicFormEntryAnswer extends VerySimpleModel { } class SelectionField extends FormField { - static $widget = 'SelectionWidget'; + static $widget = 'ChoicesWidget'; function getListId() { list(,$list_id) = explode('-', $this->get('type')); @@ -950,6 +955,14 @@ class SelectionField extends FormField { return $this->_list; } + function getWidget() { + $config = $this->getConfiguration(); + $widgetClass = false; + if ($config['widget'] == 'typeahead') + $widgetClass = 'TypeaheadSelectionWidget'; + return parent::getWidget($widgetClass); + } + function parse($value) { if (!($list=$this->getList())) @@ -958,16 +971,9 @@ class SelectionField extends FormField { $config = $this->getConfiguration(); $choices = $this->getChoices(); $selection = array(); - if ($config['typeahead']) { - // Entered value - $val = $this->getWidget()->getEnteredValue(); - if (($i=$list->getItem($val)) && $i->getId() == $value) - $selection[$i->getId()] = $i->getValue(); - elseif ($val && isset($choices[$value])) //perhaps old deleted item... - $selection[$value] = $choices[$value]; - } elseif ($value && is_array($value)) { - foreach ($value as $v) { - if (($i=$list->getItem((int) $v))) + 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]; @@ -978,15 +984,26 @@ class SelectionField extends FormField { } function to_database($value) { + $id = null; + if (is_array($value)) { + reset($value); + $id = key($value); + } if ($value && is_array($value)) $value = JsonDataEncoder::encode($value); - return $value; + return array($value, $id); } function to_php($value, $id=false) { - return ($value && !is_array($value)) + $value = ($value && !is_array($value)) ? JsonDataParser::parse($value) : $value; + if (!is_array($value)) { + $choices = $this->getChoices(); + if (isset($choices[$value])) + $value = $choices[$value]; + } + return $value; } function hasIdValue() { @@ -1002,10 +1019,9 @@ class SelectionField extends FormField { parent::validateEntry($entry); if (!$this->errors()) { $config = $this->getConfiguration(); - if (!$entry || count($entry) == 0) - $this->_errors[] = __('Select a value from the list'); - elseif ($config['typeahead'] - && !in_array($this->getWidget()->getEnteredValue(), $entry)) + if ($config['typeahead'] + && ($entered = $this->getWidget()->getEnteredValue()) + && !in_array($entered, $entry)) $this->_errors[] = __('Select a value from the list'); } } @@ -1043,7 +1059,7 @@ class SelectionField extends FormField { $config = parent::getConfiguration(); if ($config['widget']) - $config['typeahead'] = isset($config['widget']['typeahead']); + $config['typeahead'] = $config['widget'] == 'typeahead'; //Typeahed doesn't support multiselect for now TODO: Add! if ($config['typeahead']) @@ -1072,6 +1088,18 @@ class SelectionField extends FormField { 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; + } + function export($value) { if ($value && is_numeric($value) && ($item = DynamicListItem::lookup($value))) @@ -1088,23 +1116,15 @@ class SelectionField extends FormField { } } -class SelectionWidget extends ChoicesWidget { - function render($mode=false) { +class TypeaheadSelectionWidget extends ChoicesWidget { + function render($how) { + if ($how == 'search') + return parent::render($how); - $config = $this->field->getConfiguration(); - if (($value=$this->getValue())) - $value = $this->field->parse($value); - elseif ($this->value) - $value = $this->value; - - if (!$config['typeahead'] || $mode=='search') { - $this->value = $value; - return parent::render($mode); - } - - if ($value && is_array($value)) { - $name = current($value); - $value = key($value); + $name = $this->getEnteredValue(); + if (is_array($this->value)) { + $name = $name ?: current($this->value); + $value = key($this->value); } $source = array(); @@ -1117,20 +1137,23 @@ class SelectionWidget extends ChoicesWidget { ); ?> <span style="display:inline-block"> - <input type="text" size="30" name="<?php echo $this->name; ?>" - id="<?php echo $this->name; ?>" value="<?php echo $name; ?>" + <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; - ?>_id" id="<?php echo $this->name; ?>_id" value="<?php echo $value; ?>"/> + ?>[<?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); ?>, property: 'info', onselect: function(item) { - $('input#<?php echo $this->name; ?>').val(item['value']) - $('input#<?php echo $this->name; ?>_id').val(item['id']) + $('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']); } }); }); @@ -1141,14 +1164,16 @@ class SelectionWidget extends ChoicesWidget { function getValue() { $data = $this->field->getSource(); - // Search for HTML form name first - if (isset($data[$this->name.'_id'])) - return (int) $data[$this->name.'_id']; + 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'])) + return trim($data[$this->name.'_name']); return parent::getValue(); } } diff --git a/include/class.forms.php b/include/class.forms.php index c5c93866e9fa35b9404de09a3cf54dc2fe095628..f51a06fdc40950adda8eb7a63ed04f329ccf4c20 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -506,11 +506,11 @@ class FormField { $this->_config[$prop] = $value; } - function getWidget() { + function getWidget($widgetClass=false) { if (!static::$widget) throw new Exception(__('Widget not defined for this field')); if (!isset($this->_widget)) { - $wc = $this->get('widget') ? $this->get('widget') : static::$widget; + $wc = $widgetClass ?: $this->get('widget') ?: static::$widget; $this->_widget = new $wc($this); $this->_widget->parseValue(); } @@ -757,37 +757,38 @@ class ChoiceField extends FormField { } function parse($value) { - - if (!$value) return null; - - // Assume multiselect - $values = array(); - $choices = $this->getChoices(); - if (is_array($value)) { - foreach($value as $k => $v) - if (isset($choices[$v])) - $values[$v] = $choices[$v]; - } elseif(isset($choices[$value])) { - $values[$value] = $choices[$value]; - } - - return $values ?: null; + return $this->to_php($value ?: null); } function to_database($value) { - if ($value && is_array($value)) + if (!is_array($value)) { + $choices = $this->getChoices(); + if (isset($choices[$value])) + $value = array($value => $choices[$value]); + } + if (is_array($value)) $value = JsonDataEncoder::encode($value); return $value; } function to_php($value) { - return ($value && !is_array($value)) - ? JsonDataParser::parse($value) : $value; + if (is_string($value)) + $array = JsonDataParser::parse($value) ?: $value; + else + $array = $value; + $config = $this->getConfiguration(); + if (is_array($array) && !$config['multiselect'] && count($array) < 2) { + reset($array); + return key($array); + } + return $array; } function toString($value) { - return (string) $this->getChoice($value); + $selection = $this->getChoice($value); + return is_array($selection) ? implode(', ', array_filter($selection)) + : (string) $selection; } function getChoice($value) { @@ -801,7 +802,7 @@ class ChoiceField extends FormField { elseif ($this->get('default')) $selection[] = $choices[$this->get('default')]; - return $selection ? implode(', ', array_filter($selection)) : ''; + return $selection; } function getChoices($verbose=false) { @@ -1171,7 +1172,6 @@ FormField::addFieldTypes('Dynamic Fields', function() { ); }); - class Widget { function __construct($field) { @@ -1321,10 +1321,10 @@ class ChoicesWidget extends Widget { $def_val = $have_def ? $choices[$def_key] : $prompt; } - if (($value=$this->getValue())) - $values = $this->field->parse($value); - elseif ($this->value) - $values = $this->value; + $values = $this->value; + if (!is_array($values)) { + $values = array($values => $this->field->getChoice($values)); + } if ($values === null) $values = $have_def ? array($def_key => $choices[$def_key]) : array(); @@ -1361,6 +1361,23 @@ class ChoicesWidget extends Widget { <?php } } + + function getValue() { + $value = parent::getValue(); + + if (!$value) return null; + + // Assume multiselect + $values = array(); + $choices = $this->field->getChoices(); + if (is_array($value)) { + foreach($value as $k => $v) { + if (isset($choices[$v])) + $values[$v] = $choices[$v]; + } + } + return $values; + } } class CheckboxWidget extends Widget { diff --git a/include/class.list.php b/include/class.list.php index 31a3dd51938e8f56fd841021b7021d72a1ec3291..86a428c222c1069aa24ef09a781e529e6e0a965d 100644 --- a/include/class.list.php +++ b/include/class.list.php @@ -946,8 +946,8 @@ class TicketStatus extends VerySimpleModel implements CustomListItem { } break; case 'state': - if ($val && is_array($val)) - $this->set('state', key($val)); + if ($val) + $this->set('state', $val); else $f->addError(__('Unknown or invalid state'), $name); break; diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php index 0f18c7e89d0db018caefbb2aa3b1035309470f99..b160e2c253f9b993701ad18c7ad651bfcd88a358 100644 --- a/include/staff/dynamic-form.inc.php +++ b/include/staff/dynamic-form.inc.php @@ -150,13 +150,11 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <?php } ?> </select> <?php if ($f->isConfigurable()) { ?> - <a class="action-button" style="float:none;overflow:inherit" + <a class="action-button field-config" style="float:none;overflow:inherit" href="#ajax.php/form/field-config/<?php echo $f->get('id'); ?>" onclick="javascript: - $('#overlay').show(); - $('#field-config .body').empty().load($(this).attr('href').substr(1)); - $('#field-config').show(); + $.dialog($(this).attr('href').substr(1), [201]); return false; "><i class="icon-edit"></i> <?php echo __('Config'); ?></a> <?php } ?> diff --git a/include/staff/dynamic-list.inc.php b/include/staff/dynamic-list.inc.php index 280d85eccf1a08609215299b7b1abdeb8b87224c..f25f671135d4302bcbbda52a389e3fa904199d5b 100644 --- a/include/staff/dynamic-list.inc.php +++ b/include/staff/dynamic-list.inc.php @@ -339,7 +339,7 @@ $(function() { e.preventDefault(); var $id = $(this).attr('id'); var url = 'ajax.php/'+$(this).attr('href').substr(1); - $.dialog(url, [200], function (xhr) { + $.dialog(url, [201], function (xhr) { $('a#'+$id+' i').removeAttr('style'); }); return false; diff --git a/scp/js/scp.js b/scp/js/scp.js index 953712f43b368377454b5ff028b553bb40330c96..83bc2540034237109f99daefc482ca21e7f6d019 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -534,7 +534,8 @@ $.dialog = function (url, codes, cb, options) { $('#overlay').show(); $('div.body', $popup).empty().hide(); - $('div#popup-loading', $popup).show(); + $('div#popup-loading', $popup).show() + .find('h1').css({'margin-top':function() { return $popup.height()/3-$(this).height()/3}}); $popup.show(); $('div.body', $popup).load(url, function () { $('div#popup-loading', $popup).hide(); @@ -548,7 +549,8 @@ $.dialog = function (url, codes, cb, options) { $(document).on('submit.dialog', '.dialog#popup form', function(e) { e.preventDefault(); var $form = $(this); - var $dialog = $form.closest('.dialog'); + $('div#popup-loading', $popup).show() + .find('h1').css({'margin-top':function() { return $popup.height()/3-$(this).height()/3}}); $.ajax({ type: $form.attr('method'), url: 'ajax.php/'+$form.attr('action').substr(1), @@ -557,17 +559,19 @@ $.dialog = function (url, codes, cb, options) { success: function(resp, status, xhr) { if (xhr && xhr.status && codes && $.inArray(xhr.status, codes) != -1) { - $('div.body', $dialog).empty(); - $dialog.hide(); + $('div.body', $popup).empty(); + $popup.hide(); $('#overlay').hide(); if(cb) cb(xhr); } else { - $('div.body', $dialog).html(resp); - $('#msg_notice, #msg_error', $dialog).delay(5000).slideUp(); + $('div.body', $popup).html(resp); + $('#msg_notice, #msg_error', $popup).delay(5000).slideUp(); } } }) - .done(function() { }) + .done(function() { + $('div#popup-loading', $popup).hide(); + }) .fail(function() { }); return false; });