From d889e927748f1c8e2671cfd844ba72e2b93d719a Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 12 Jan 2010 22:35:51 +0000 Subject: [PATCH] Add AJAX Select widget as a field type for custom fields. Select options can be provided using one of three different methods: 1. key=value pairs, one per line, as for a selectbox 2. @filename.php - The file must be in the egw root, and define an array named $options, that has key => value pairs 3. Define the options normally used for the AJAX Select widget (get_rows, get_title, id_field) and it will pull values from the database, as normal. Other options (icon, filter, template, link) can be used regardless of the method used to get the values. --- .../inc/class.ajax_select_widget.inc.php | 121 ++++++++++++++++-- .../inc/class.customfields_widget.inc.php | 29 +++++ etemplate/js/ajax_select.js | 2 +- etemplate/setup/etemplates.inc.php | 4 +- 4 files changed, 144 insertions(+), 12 deletions(-) diff --git a/etemplate/inc/class.ajax_select_widget.inc.php b/etemplate/inc/class.ajax_select_widget.inc.php index 7b3c1e4d9d..ac0220aba4 100644 --- a/etemplate/inc/class.ajax_select_widget.inc.php +++ b/etemplate/inc/class.ajax_select_widget.inc.php @@ -21,6 +21,7 @@ * This widget can get data from any function that can provide data to a nextmatch widget. * This widget is generating html, so it does not work (without an extra implementation) in an other UI */ + class ajax_select_widget { var $public_functions = array( @@ -30,6 +31,29 @@ class ajax_select_widget ); var $human_name = 'AJAX Select'; // this is the name for the editor + // Accepted option keys if you're passing in an array to set up the widget + // Additional options will be passed to the search query + public static $known_options = array( + // These ones can be passed in from eTemplate editor in size + 'get_rows', + 'get_title', + 'id_field', + 'template', + 'filter', + 'filter2', + 'link', + 'icon', + + // Pass by code only + 'values', + ); + + // Flag used in id_field to indicate that the key of the record should be used as the value + const ARRAY_KEY = 'array_key'; + + // Array of static values to emulate a combo-box, with no DB lookup + protected static $static_values = array(); + private $debug = false; function ajax_select_widget($ui='') @@ -103,6 +127,13 @@ class ajax_select_widget $options['template'] = 'etemplate.ajax_select_widget.row'; } + if(array_key_exists('values', $options)) { + if($options['values']) { + self::$static_values[$name] = $options['values']; + } + unset($options['values']); + } + $onchange = ($cell['onchange'] ? $cell['onchange'] : 'false'); // Set current value @@ -121,10 +152,15 @@ class ajax_select_widget $title_obj =& CreateObject($title_app . '.' . $title_class); } } + if(!is_object($title_obj) || !method_exists($title_obj,$title_method)) { echo "$entry_app.$entry_class.$entry_method is not a valid method for getting the title"; } elseif($current_value) { - $title = $title_obj->$title_method($current_value); + if($title_method == 'array_title' && $title_class == __CLASS__) { + $title = self::$title_method($current_value, $name); + } else { + $title = $title_obj->$title_method($current_value); + } } // Check get_rows method @@ -146,6 +182,7 @@ class ajax_select_widget $cell['type'] = 'template'; $cell['size'] = $cell['name']; $value = array('value' => $current_value, 'search' => $title); + $widget = new etemplate('etemplate.ajax_select_widget'); $widget->no_onclick = True; @@ -165,6 +202,9 @@ class ajax_select_widget } else { $search['type'] = 'text'; $search['size'] = ''; + if($current_value == '' && $options['id_field'] == self::ARRAY_KEY) { + $search['blur'] = lang('Search...'); + } } // Icon @@ -173,6 +213,11 @@ class ajax_select_widget $cell['obj'] = &$widget; + // Save static values, if set + if(self::$static_values[$name]) { + $extension_data['values'] = self::$static_values[$name]; + } + // Save options for post_processing $extension_data['options'] = $options; $extension_data['needed'] = $cell['needed']; @@ -181,6 +226,12 @@ class ajax_select_widget $GLOBALS['egw_info']['flags']['include_xajax'] = True; // JavaScript + // converter doesn't handle numeric well + foreach($options as $key => &$value) { + if(is_numeric($value)) { + $value = (string)$value; + } + } $options = $GLOBALS['egw']->js->convert_phparray_jsarray("options['$name']", $options, true); $GLOBALS['egw']->js->set_onload("if(!options) { var options = new Object(); @@ -267,7 +318,7 @@ class ajax_select_widget } } - function ajax_search($id, $value, $set_id, $query) { + function ajax_search($id, $value, $set_id, $query, $etemplate_id) { $base_id = substr($id, 0, strrpos($id, '[')); $result_id = ($set_id ? $set_id : $base_id . '[results]'); $response = new xajaxResponse(); @@ -281,7 +332,7 @@ class ajax_select_widget // Expand lists foreach($query as $key => &$row) { - if(strpos($row, ',')) { + if($row && strpos($row, ',')) { $query[$key] = explode(',', $row); } @@ -293,6 +344,19 @@ class ajax_select_widget } } $query['search'] = $value; + + if($query['id_field'] == self::ARRAY_KEY) { + // Pass base_id so we can get the right values + $query['field_name'] = $base_id; + + // Check for a provided list of values + if($request = etemplate_request::read($etemplate_id)) { + $extension_data = $request->extension_data[$base_id]; + if(is_array($extension_data) && $extension_data['values']) { + self::$static_values[$base_id] = $extension_data['values']; + } + } + } $result_list = array(); $readonlys = array(); @@ -313,7 +377,18 @@ class ajax_select_widget } foreach($result_list as $key => &$row) { if(!is_array($row)) { - continue; + if($query['id_field'] == self::ARRAY_KEY) { + if(!is_array($row)) { + // Restructure $row to be an array + $row = array( + self::ARRAY_KEY => $key, + 'id_field' => $key, + 'title' => $row + ); + } + } else { + continue; + } } //check for multiple id's @@ -331,15 +406,17 @@ class ajax_select_widget } $row['id_field'] = implode(';',$id_field_keys_values); unset($id_field_keys_values); - } else{ + } else { if($query['id_field'] && $query['get_title']) { - if($row[$query['id_field']]) { - $row['title'] = ExecMethod($query['get_title'], $row[$query['id_field']]); + if($row[$query['id_field']] && $query['id_field'] != self::ARRAY_KEY) { + $row['title'] = ExecMethod($query['get_title'], $row[$query['id_field']]); } } - // If we use htmlspecialchars, it causes issues with mixed quotes. addslashes() seems to handle it. - $row['id_field'] = $row[$query['id_field']]; + if($query['id_field'] != self::ARRAY_KEY) { + $row['id_field'] = $row[$query['id_field']]; + } } + // If we use htmlspecialchars, it causes issues with mixed quotes. addslashes() seems to handle it. $row['id_field'] = addslashes($row['id_field']); $data = ($query['nextmatch_template']) ? array(1=>$row) : $row; @@ -359,4 +436,30 @@ class ajax_select_widget } return $response->getXML(); } + + /** + * Use a simple array to get the title + * Values should be passed in to the widget as an array in $size['values'] + */ + protected function array_title($id, $name) { + if(trim($id) == '') { + return lang('Search'); + } + return self::$static_values[$name][$id]; + } + + /** + * Use a simple array to get the results + * Values should be passed in to the widget as an array in $size['values'] + */ + protected function array_rows(&$query, &$result) { + foreach( self::$static_values[$query['field_name']] as $key => $value) { + if($query['search'] && stripos($value, $query['search']) === false) continue; + + $result[$key] = $value; + } + $count = count($result); + $result = array_slice($result, $query['start'], $query['num_rows']); + return $count; + } } diff --git a/etemplate/inc/class.customfields_widget.inc.php b/etemplate/inc/class.customfields_widget.inc.php index f9d00d425b..ffb043c287 100644 --- a/etemplate/inc/class.customfields_widget.inc.php +++ b/etemplate/inc/class.customfields_widget.inc.php @@ -45,6 +45,7 @@ class customfields_widget 'text' => 'Text', 'label' => 'Label', 'select' => 'Selectbox', + 'ajax_select' => 'Search', 'radio' => 'Radiobutton', 'checkbox' => 'Checkbox', 'date' => 'Date', @@ -235,6 +236,34 @@ class customfields_widget */ } break; + case 'ajax_select' : + // Set some reasonable defaults for the widget + $options = array( + 'get_title' => 'etemplate.ajax_select_widget.array_title', + 'get_rows' => 'etemplate.ajax_select_widget.array_rows', + 'id_field' => ajax_select_widget::ARRAY_KEY, + ); + if($field['rows']) { + $options['num_rows'] = $field['rows']; + } + + // If you specify an option known to the AJAX Select widget, it will be pulled from the list of values + // and used as such. All unknown values will be used for selection, not passed through to the query + if (isset($field['values']['@'])) + { + $options['values'] = $this->_get_options_from_file($field['values']['@']); + unset($field['values']['@']); + } else { + $options['values'] = array_diff_key($field['values'], array_flip(ajax_select_widget::$known_options)); + } + $options = array_merge($options, array_intersect_key($field['values'], array_flip(ajax_select_widget::$known_options))); + + $input =& etemplate::empty_cell('ajax_select', $this->prefix.$lname, array( + 'readonly' => $readonly, + 'no_lang' => True, + 'size' => $options + )); + break; case 'label' : $row_class = 'th'; break; diff --git a/etemplate/js/ajax_select.js b/etemplate/js/ajax_select.js index 3ded8a26fe..25c461f03a 100644 --- a/etemplate/js/ajax_select.js +++ b/etemplate/js/ajax_select.js @@ -281,7 +281,7 @@ function change(e, value) { selects[i].style.visibility = 'hidden'; } } - xajax_doXMLHTTP(current_app + ".ajax_select_widget.ajax_search.etemplate", id, value, set_id, query); + xajax_doXMLHTTP(current_app + ".ajax_select_widget.ajax_search.etemplate", id, value, set_id, query, document.getElementById('etemplate_exec_id').value); } diff --git a/etemplate/setup/etemplates.inc.php b/etemplate/setup/etemplates.inc.php index eafe242809..4fceedb422 100644 --- a/etemplate/setup/etemplates.inc.php +++ b/etemplate/setup/etemplates.inc.php @@ -2,7 +2,7 @@ /** * eGroupWare - eTemplates for Application etemplate * http://www.egroupware.org - * generated by soetemplate::dump4setup() 2010-01-08 03:21 + * generated by soetemplate::dump4setup() 2010-01-12 13:39 * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate @@ -39,7 +39,7 @@ div.resultBoxSelected { background-color: #D3DCE3; }','modified' => '1176831076',); -$templ_data[] = array('name' => 'etemplate.ajax_select_widget.row','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:8:"id_field";}s:1:"B";a:3:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:5:"title";}}}s:4:"rows";i:1;s:4:"cols";i:2;}}','size' => '','style' => '','modified' => '1160761596',); +$templ_data[] = array('name' => 'etemplate.ajax_select_widget.row','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:5:"title";}}}s:4:"rows";i:1;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1160761596',); $templ_data[] = array('name' => 'etemplate.captcha_widget','template' => '','lang' => '','group' => '0','version' => '1.7.002','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:3:{s:2:"c1";s:7:",bottom";s:2:"c2";s:4:",top";s:2:"h3";s:10:",!@val_msg";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"image";s:4:"name";s:25:"etemplate/securimage_show";s:4:"size";s:14:",,,,show_image";}s:1:"B";a:2:{s:4:"type";s:5:"image";s:4:"name";s:24:"etemplate/audio_icon.gif";}}i:2;a:2:{s:1:"A";a:4:{s:4:"type";s:4:"text";s:4:"name";s:12:"captcha_code";s:4:"size";s:2:"24";s:6:"needed";s:1:"1";}s:1:"B";a:2:{s:4:"type";s:5:"image";s:4:"name";s:21:"etemplate/refresh.gif";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:7:"val_msg";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:3;s:4:"cols";i:2;s:4:"size";s:8:",,0,,0,0";s:7:"options";a:3:{i:4;s:1:"0";i:5;s:1:"0";i:2;s:1:"0";}}}','size' => ',,0,,0,0','style' => '','modified' => '1245517015',);