diff --git a/importexport/inc/class.filter_widget.inc.php b/importexport/inc/class.filter_widget.inc.php
new file mode 100644
index 0000000000..a9bc5cda2a
--- /dev/null
+++ b/importexport/inc/class.filter_widget.inc.php
@@ -0,0 +1,257 @@
+ value combination
+ * we send via col_filter, but the plugin gets a chance to interpret the filter
+ * settings.
+ *
+ * Selectboxes are easy, we just turn them into multi-selects.
+ *
+ * For dates we either use a relative date selection, or a literal date selection.
+ * Relative date options are in importexport_helper_functions::$relative_dates
+ *
+ * Most text fields are ignored.
+ */
+class filter_widget extends customfields_widget
+{
+
+ public $prefix = '';
+ public $human_name = array(
+ 'filter' => 'Import|Export filter'
+ );
+
+ public function __construct($ui, $appname = null)
+ {
+ $this->advanced_search = true;
+ parent::__construct($ui, $appname);
+ }
+
+ /**
+ * pre-processing of the extension
+ *
+ * This function is called before the extension gets rendered
+ *
+ * @param string $form_name form-name of the control
+ * @param mixed &$value value / existing content, can be modified
+ * @param array &$cell array with the widget, can be modified for ui-independent widgets
+ * @param array &$readonlys names of widgets as key, to be made readonly
+ * @param mixed &$extension_data data the extension can store persisten between pre- and post-process
+ * @param etemplate &$tmpl reference to the template we belong too
+ * @return boolean true if extra label is allowed, false otherwise
+ */
+ public function pre_process($form_name,&$value,&$cell,&$readonlys,&$extension_data,$tmpl)
+ {
+ $fields = $value['fields'];
+ unset($value['fields']);
+
+ list($relative_dates) = explode(',',$cell['size']);
+ if($cell['relative_dates']) $relative_dates = true;
+
+ // Fallback, so there's something there...
+ if(!is_array($fields))
+ {
+ $cell['type'] = 'label';
+ $cell['label'] = 'No fields';
+ return True;
+ }
+
+
+ // making the cell an empty grid
+ $cell['type'] = 'grid';
+ $cell['data'] = array(array());
+ $cell['rows'] = $cell['cols'] = 0;
+ $cell['size'] = '';
+
+ $n = 1;
+ foreach($fields as $lname => $field)
+ {
+ $new_row = null; boetemplate::add_child($cell,$new_row);
+ $row_class = 'row';
+ boetemplate::add_child($cell,$label =& boetemplate::empty_cell('label','',array(
+ 'label' => $field['label'],
+ 'no_lang' => substr(lang($field['label']),-1) == '*' ? 2 : 0,
+ 'span' => $field['type'] === 'label' ? '2' : '',
+ )));
+
+ switch($field['type'])
+ {
+ case 'date':
+ case 'date-time':
+ // Need a range here
+ $options = '';
+ if($relative_dates)
+ {
+ $input = self::do_relative_date($lname, $value, $options, $readonly);
+ }
+ else
+ {
+ $input = self::do_absolute_date($lname, $value, $options, $readonly);
+ }
+ 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 = boetemplate::empty_cell('ajax_select', $lname, array(
+ 'readonly' => $readonly,
+ 'no_lang' => True,
+ 'size' => $options
+ ));
+ break;
+
+ case 'link-entry':
+ $input =& boetemplate::empty_cell('link-entry',$this->prefix.$lname,array(
+ 'size' => $field['type'] == 'link-entry' ? '' : $field['type'],
+ ));
+ // register post-processing of link widget to get eg. needed/required validation
+ etemplate_old::$request->set_to_process(etemplate_old::form_name($form_name,$this->prefix.$lname), 'ext-link');
+ break;
+ case 'select':
+ default:
+ if(strpos($field['type'],'select') === 0)
+ {
+ if (count($field['values']) == 1 && isset($field['values']['@']))
+ {
+ $field['values'] = $this->_get_options_from_file($field['values']['@']);
+ }
+ foreach((array)$field['values'] as $key => $val)
+ {
+ if (substr($val = lang($val),-1) != '*')
+ {
+ $field['values'][$key] = $val;
+ }
+ }
+ $input =& boetemplate::empty_cell($field['type'],$lname,array(
+ 'sel_options' => $field['values'],
+ 'size' => $field['rows'],
+ 'enhance' => true,
+ 'no_lang' => True,
+ ));
+ }
+ elseif (in_array($field['type'], array_keys(egw_link::app_list())))
+ {
+ // Link entry to a specific app
+ $input =& boetemplate::empty_cell('link-entry',$lname,array(
+ 'size' => $field['type'] == 'link-entry' ? '' : $field['type'],
+ ));
+ // register post-processing of link widget to get eg. needed/required validation
+ etemplate_old::$request->set_to_process(etemplate_old::form_name($form_name,$lname), 'ext-link');
+
+ } else {
+error_log('Trying to filter with unsupported field type: ' . $field['type']);
+ $input =& boetemplate::empty_cell($field['type'],$lname,array(
+ 'sel_options' => $field['values'],
+ 'size' => $field['rows'],
+ 'no_lang' => True,
+ ));
+ }
+
+ }
+ $cell['data'][0]['c'.$n++] = $row_class.',top';
+
+ if (!is_null($input))
+ {
+ if ($readonly) $input['readonly'] = true;
+
+ $input['needed'] = $cell['needed'] || $field['needed'];
+
+ if (!empty($field['help']) && $row_class != 'th')
+ {
+ $input['help'] = $field['help'];
+ $input['no_lang'] = substr(lang($help),-1) == '*' ? 2 : 0;
+ }
+ boetemplate::add_child($cell,$input);
+ unset($input);
+ }
+ unset($label);
+ }
+ return false;
+ }
+
+ /**
+ * Create widgets to select a relative date range
+ *
+ * @param $lname Field name
+ * @param $options
+ * @param $readonly
+ *
+ * @return Array of widget info
+ */
+ protected static function do_relative_date($lname, Array &$value, $options, $readonly)
+ {
+ // Maybe this could be moved to date widget
+ $input = boetemplate::empty_cell('select',$lname, array(
+ 'readonly' => $readonly,
+ 'no_lang' => true,
+ 'options' => $options,
+ 'sel_options' => array('' => lang('all'))
+ ));
+ foreach(importexport_helper_functions::$relative_dates as $label => $values)
+ {
+ $input['sel_options'][$label] = lang($label);
+ }
+
+ return $input;
+ }
+
+ /**
+ * Create widgets to select an absolute date range
+ *
+ * @param $lname Field name
+ * @param $options
+ * @param $readonly
+ *
+ * @return Array of widget info
+ */
+ protected static function do_absolute_date($lname, Array &$value, $options, $readonly)
+ {
+ $input = boetemplate::empty_cell('hbox',$lname);
+
+ $type = 'date';
+ $from = boetemplate::empty_cell($type, $lname.'[from]',array(
+ 'readonly' => $readonly,
+ 'no_lang' => True,
+ 'size' => $options
+ ));
+
+ $to = boetemplate::empty_cell($type, $lname.'[to]', array(
+ 'readonly' => $readonly,
+ 'no_lang' => True,
+ 'size' => $options
+ ));
+ boetemplate::add_child($input, $from);
+ boetemplate::add_child($input,boetemplate::empty_cell('label','',array(
+ 'label' => lang('to'),
+ 'no_lang' => true
+ )));
+ boetemplate::add_child($input, $to);
+ return $input;
+ }
+}
diff --git a/importexport/inc/class.importexport_definition.inc.php b/importexport/inc/class.importexport_definition.inc.php
index 9f0ef58e65..dee6a9f84d 100644
--- a/importexport/inc/class.importexport_definition.inc.php
+++ b/importexport/inc/class.importexport_definition.inc.php
@@ -31,6 +31,7 @@ class importexport_definition implements importexport_iface_egw_record {
'type' => 'string',
'allowed_users' => 'array',
'plugin_options' => 'array',
+ 'filter' => 'array',
'owner' => 'int',
'description' => 'string',
'modified' => 'timestamp'
@@ -79,6 +80,8 @@ class importexport_definition implements importexport_iface_egw_record {
}
$options_data = importexport_arrayxml::xml2array( $this->definition['plugin_options'] );
$this->definition['plugin_options'] = $options_data['root'];
+ if($this->definition['filter']) $filter = importexport_arrayxml::xml2array( $this->definition['filter'] );
+ $this->definition['filter'] = $filter['root'];
}
}
@@ -110,6 +113,8 @@ class importexport_definition implements importexport_iface_egw_record {
return $this->get_allowed_users();
case 'plugin_options' :
return $this->get_options();
+ case 'filter':
+ return $this->get_filter();
default :
return $this->definition[$_attribute_name];
}
@@ -124,6 +129,8 @@ class importexport_definition implements importexport_iface_egw_record {
return $this->set_allowed_users($_data);
case 'plugin_options' :
return $this->set_options($_data);
+ case 'filter':
+ return $this->set_filter($_data);
default :
$this->definition[$_attribute_name] = $_data;
return;
@@ -166,6 +173,24 @@ class importexport_definition implements importexport_iface_egw_record {
$this->definition['plugin_options'] = $_plugin_options;
}
+ /**
+ * Get stored data filter
+ *
+ * @return array
+ */
+ private function get_filter() {
+ return $this->definition['filter'];
+ }
+
+ /**
+ * Set stored data filter
+ *
+ * @param filter array of field => settings
+ */
+ private function set_filter(Array $filter) {
+ $this->definition['filter'] = $filter;
+ }
+
/**
* converts this object to array.
* @abstract We need such a function cause PHP5
@@ -178,6 +203,7 @@ class importexport_definition implements importexport_iface_egw_record {
$definition = $this->definition;
$definition['allowed_users'] = $this->get_allowed_users();
$definition['plugin_options'] = $this->get_options();
+ $definition['filter'] = $this->get_filter();
return $definition;
}
@@ -211,6 +237,7 @@ class importexport_definition implements importexport_iface_egw_record {
// convert plugin_options into internal representation
$this->set_allowed_users( $this->definition['allowed_users'] );
$this->set_options( $this->definition['plugin_options'] ? $this->definition['plugin_options'] : array());
+ $this->set_filter( $this->definition['filter'] ? $this->definition['filter'] : array());
}
/**
@@ -235,6 +262,7 @@ class importexport_definition implements importexport_iface_egw_record {
$this->so_sql->data = $this->definition;
$this->so_sql->data['plugin_options'] = importexport_arrayxml::array2xml( $this->definition['plugin_options'] );
+ $this->so_sql->data['filter'] = importexport_arrayxml::array2xml( $this->definition['filter'] );
$this->so_sql->data['modified'] = time();
if ($this->so_sql->save( array( 'definition_id' => $_dst_identifier ))) {
throw new Exception('Error: so_sql was not able to save definition: '.$this->get_identifier());
diff --git a/importexport/inc/class.importexport_definitions_ui.inc.php b/importexport/inc/class.importexport_definitions_ui.inc.php
index bde76d81d4..30e9e55f8a 100644
--- a/importexport/inc/class.importexport_definitions_ui.inc.php
+++ b/importexport/inc/class.importexport_definitions_ui.inc.php
@@ -612,6 +612,7 @@ class importexport_definitions_ui
{
$this->response = new xajaxResponse();
+ egw_framework::include_css_js_response();
if ($content['closewindow'])
{
$this->response->addScript("opener.location.reload();");
@@ -639,6 +640,7 @@ class importexport_definitions_ui
{
$GLOBALS['egw']->js->set_onload("document.getElementById('picturebox').style.display = 'none';");
egw_framework::validate_file('.', 'etemplate', 'etemplate');
+ egw_framework::validate_file('.', 'etemplate', 'etemplate');
common::egw_header();
echo '
'."\n";
echo '
{Im|Ex}port Wizard
';
diff --git a/importexport/inc/class.importexport_export_ui.inc.php b/importexport/inc/class.importexport_export_ui.inc.php
index 927eb1c723..fa01e07523 100644
--- a/importexport/inc/class.importexport_export_ui.inc.php
+++ b/importexport/inc/class.importexport_export_ui.inc.php
@@ -173,13 +173,31 @@ class importexport_export_ui {
$content['plugin_options_template'] = $options;
}
}
+ $content['filter'] = $definition->filter;
+ $content['filter']['fields'] = importexport_helper_functions::get_filter_fields($_appname, $selected_plugin);
+ if(!$content['filter']['fields'])
+ {
+ $this->js->set_onload("\$j('input[value=\"filter\"]').parent().hide();");
+ $content['no_filter'] = true;
+ }
+ else
+ {
+ // Process relative dates into the current absolute date
+ foreach($content['filter']['fields'] as $field => $settings)
+ {
+ if($content['filter'][$field] && strpos($settings['type'],'date') === 0)
+ {
+ $content['filter'][$field] = importexport_helper_functions::date_rel2abs($content['filter'][$field]);
+ }
+ }
+ }
}
// fill selection tab
if($definition && $definition->plugin_options['selection'] && !$content['selection_passed']) {
$_selection = $definition->plugin_options['selection'];
}
-
+
if ($_selection && ($content['old_definition'] == $content['definition'] || $content['selection_passed'])) {
$readonlys[$tabs]['selection_tab'] = true;
$content['selection'] = $_selection;
@@ -209,9 +227,18 @@ class importexport_export_ui {
disable_button('exec[export]');
");
}
+
+ // Disable / hide definition filter if not selected
+ if($content['selection'] !== 'filter')
+ {
+ $this->js->set_onload("
+ \$j('div.filters').hide();
+ ");
+ }
+
$preserv['old_definition'] = $content['definition'];
if (($prefs = $GLOBALS['egw_info']['user']['preferences']['importexport'][$definition->definition_id]) &&
- ($prefs = unserialize($prefs)) && !$content['selection']['plugin_override'])
+ ($prefs = unserialize($prefs)) && is_array($content['selection']) && !$content['selection']['plugin_override'])
{
$selection = $content['selection'];
$content = array_merge_recursive($content,$prefs);
@@ -260,6 +287,26 @@ class importexport_export_ui {
'mapping' => array()
);
}
+
+ // Set filter
+ // Note that because not all dates are DB dates, the plugin has to handle them
+ $filter = $definition->filter;
+ foreach($_content['filter'] as $key => $value)
+ {
+ // Handle multiple values
+ if(!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value);
+
+ $filter[$key] = $value;
+
+ // Skip empty values or empty ranges
+ if(!$value || is_array($value) && array_key_exists('from',$value) && !$value['from'] && !$value['to'] )
+ {
+ unset($filter[$key]);
+ }
+ }
+ unset($_content['filter']);
+ $definition->filter = $filter;
+
$definition->plugin_options = array_merge(
$definition->plugin_options,
$_content
diff --git a/importexport/inc/class.importexport_helper_functions.inc.php b/importexport/inc/class.importexport_helper_functions.inc.php
index 5c0a9eb4d0..7bdb3ba7d9 100755
--- a/importexport/inc/class.importexport_helper_functions.inc.php
+++ b/importexport/inc/class.importexport_helper_functions.inc.php
@@ -26,6 +26,25 @@ class importexport_helper_functions {
*/
public static $dry_run = false;
+ /**
+ * Relative date ranges for filtering
+ */
+ public static $relative_dates = array( // Start: year,month,day,week, End: year,month,day,week
+ 'Today' => array(0,0,0,0, 0,0,1,0),
+ 'Yesterday' => array(0,0,-1,0, 0,0,0,0),
+ 'This week' => array(0,0,0,0, 0,0,0,1),
+ 'Last week' => array(0,0,0,-1, 0,0,0,0),
+ 'This month' => array(0,0,0,0, 0,1,0,0),
+ 'Last month' => array(0,-1,0,0, 0,0,0,0),
+ 'Last 3 months' => array(0,-3,0,0, 0,1,0,0),
+ 'This quarter'=> array(0,0,0,0, 0,0,0,0), // Just a marker, needs special handling
+ 'Last quarter'=> array(0,-4,0,0, 0,-4,0,0), // Just a marker
+ 'This year' => array(0,0,0,0, 1,0,0,0),
+ 'Last year' => array(-1,0,0,0, 0,0,0,0),
+ '2 years ago' => array(-2,0,0,0, -1,0,0,0),
+ '3 years ago' => array(-3,0,0,0, -2,0,0,0),
+ );
+
/**
* Files known to cause problems, and will be skipped in a plugin scan
* If you put appname => true, the whole app will be skipped.
@@ -515,4 +534,181 @@ class importexport_helper_functions {
}
return $list;
}
+
+ /**
+ * Get a list of filterable fields, and options for those fields
+ *
+ * It tries to automatically pull filterable fields from the list of fields in the wizard,
+ * and sets widget properties. The plugin can edit / set the fields by implementing
+ * get_filter_fields(Array &$fields).
+ *
+ * Currently only supports select,select-cat,select-account,date,date-time
+ *
+ * @param $app_name String name of app
+ * @param $plugin_name Name of the plugin
+ *
+ * @return Array ([fieldname] => array(widget settings), ...)
+ */
+ public static function get_filter_fields($app_name, $plugin_name, $wizard_plugin = null, $record_classname = null)
+ {
+ $fields = array();
+ try {
+ if($record_classname == null) $record_classname = $app_name . '_egw_record';
+ if(!class_exists($record_classname)) throw new Exception('Bad class name ' . $record_classname);
+
+ $plugin = is_object($plugin_name) ? $plugin_name : new $plugin_name();
+ $plugin_name = get_class($plugin);
+
+ if(!$wizard_plugin)
+ {
+ $wizard_name = $app_name . '_wizard_' . str_replace($app_name . '_', '', $plugin_name);
+ if(!class_exists($wizard_name)) throw new Exception('Bad wizard name ' . $wizard_name);
+ $wizard_plugin = new $wizard_name;
+ }
+ }
+ catch (Exception $e)
+ {
+ error_log($e->getMessage());
+ return array();
+ }
+
+ // Get field -> label map and initialize fields using wizard field order
+ $fields = $export_fields = $wizard_plugin->get_export_fields();
+
+ foreach($record_classname::$types as $type => $type_fields)
+ {
+ // Only these for now, until filter methods for others are figured out
+ if(!in_array($type, array('select','select-cat','select-account','date','date-time'))) continue;
+ foreach($type_fields as $field_name)
+ {
+ $fields[$field_name] = array(
+ 'name' => $field_name,
+ 'label' => $export_fields[$field_name] ? $export_fields[$field_name] : $field_name,
+ 'type' => $type
+ );
+ }
+ }
+ // Add custom fields
+ $custom = config::get_customfields($app_name);
+ foreach($custom as $field_name => $settings)
+ {
+ $settings['name'] = '#'.$field_name;
+ $fields['#'.$field_name] = $settings;
+ }
+
+ foreach($fields as $field_name => &$settings) {
+ // Can't really filter on these (or at least no generic, sane way figured out yet)
+ if(!is_array($settings) || in_array($settings['type'], array('text','button', 'label','url','url-email','url-phone','htmlarea')))
+ {
+ unset($fields[$field_name]);
+ continue;
+ }
+ if($settings['type'] == 'radio') $settings['type'] = 'select';
+ switch($settings['type'])
+ {
+ case 'checkbox':
+ // This isn't quite right - there's only 2 options and you can select both
+ $settings['type'] = 'select-bool';
+ $settings['rows'] = 1;
+ $settings['enhance'] = true;
+ break;
+ case 'select-cat':
+ $settings['rows'] = "5,,,$app_name";
+ $settings['enhance'] = true;
+ break;
+ case 'select-account':
+ $settings['rows'] = '5,both';
+ $settings['enhance'] = true;
+ break;
+ case 'select':
+ $settings['rows'] = 5;
+ $settings['enhance'] = true;
+ break;
+ }
+ }
+
+ if(method_exists($plugin, 'get_filter_fields'))
+ {
+ $plugin->get_filter_fields($fields);
+ }
+ return $fields;
+ }
+
+ /**
+ * Parse a relative date (Yesterday) into absolute (2012-12-31) date
+ *
+ * @param $value String description of date matching $relative_dates
+ *
+ * @return Array([from] => timestamp, [to]=> timestamp), inclusive
+ */
+ public static function date_rel2abs($value)
+ {
+ if(is_array($value))
+ {
+ $abs = array();
+ foreach($value as $key => $val)
+ {
+ $abs[$key] = self::date_rel2abs($val);
+ }
+ return $abs;
+ }
+ if($date = self::$relative_dates[$value])
+ {
+ $year = (int) date('Y');
+ $month = (int) date('m');
+ $day = (int) date('d');
+ $today = mktime(0,0,0,date('m'),date('d'),date('Y'));
+
+ list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) = $date;
+
+ if(stripos($value, 'quarter') !== false)
+ {
+ // Handle quarters
+ $start = mktime(0,0,0,((int)floor(($smonth+$month) / 3.1)) * 3 + 1, 1, $year);
+ $end = mktime(0,0,0,((int)floor(($emonth+$month) / 3.1)+1) * 3 + 1, 1, $year);
+ }
+ elseif ($syear || $eyear)
+ {
+ $start = mktime(0,0,0,1,1,$syear+$year);
+ $end = mktime(0,0,0,1,1,$eyear+$year);
+ }
+ elseif ($smonth || $emonth)
+ {
+ $start = mktime(0,0,0,$smonth+$month,1,$year);
+ $end = mktime(0,0,0,$emonth+$month,1,$year);
+ }
+ elseif ($sday || $eday)
+ {
+ $start = mktime(0,0,0,$month,$sday+$day,$year);
+ $end = mktime(0,0,0,$month,$eday+$day,$year);
+ }
+ elseif ($sweek || $eweek)
+ {
+ $wday = (int) date('w'); // 0=sun, ..., 6=sat
+ switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
+ {
+ case 'Sunday':
+ $weekstart = $today - $wday * 24*60*60;
+ break;
+ case 'Saturday':
+ $weekstart = $today - (6-$wday) * 24*60*60;
+ break;
+ case 'Moday':
+ default:
+ $weekstart = $today - ($wday ? $wday-1 : 6) * 24*60*60;
+ break;
+ }
+ $start = $weekstart + $sweek*7*24*60*60;
+ $end = $weekstart + $eweek*7*24*60*60;
+ }
+ $end_param = $end - 24*60*60;
+
+ // Take 1 second off end to provide an inclusive range.for filtering
+ $end -= 1;
+
+ //echo __METHOD__."($value,$start,$end) today=".date('l, Y-m-d H:i',$today)." ==>
".date('l, Y-m-d H:i:s',$start)." <= date <= ".date('l, Y-m-d H:i:s',$end)."\n";
+ return array('from' => $start, 'to' => $end);
+ }
+ return null;
+ }
} // end of importexport_helper_functions
diff --git a/importexport/inc/class.importexport_schedule_ui.inc.php b/importexport/inc/class.importexport_schedule_ui.inc.php
index a1caf2766b..ee06b56804 100644
--- a/importexport/inc/class.importexport_schedule_ui.inc.php
+++ b/importexport/inc/class.importexport_schedule_ui.inc.php
@@ -460,8 +460,30 @@
if($type == 'export')
{
- // Set to export all
- $definition->plugin_options = array_merge($definition->plugin_options, array('selection' => 'all'));
+ // Set to export all or filter, if set
+ $selection = array('selection' => 'all');
+ if($definition->filter)
+ {
+ $fields = importexport_helper_functions::get_filter_fields($definition->application, $po);
+ $selection = array('selection' => 'filter');
+ $filters = array();
+ foreach($definition->filter as $field => $value)
+ {
+ // Handle multiple values
+ if(!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value);
+
+ $filters[$field] = $value;
+
+ // Process relative dates into the current absolute date
+ if($filters[$field] && strpos($fields[$field]['type'],'date') === 0)
+ {
+ $filters[$field] = importexport_helper_functions::date_rel2abs($value);
+ }
+ }
+ // Update filter to use current absolute dates
+ $definition->filter = $filters;
+ }
+ $definition->plugin_options = array_merge($definition->plugin_options, $selection);
}
foreach($targets as $target)
diff --git a/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php b/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php
index e554ba1ed5..e81e2b27ab 100644
--- a/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php
+++ b/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php
@@ -1,12 +1,12 @@
steps appropriately. The key is the function, the value is the title.
* Don't go past 80, as that's where the wizard picks it back up again to finish it off.
- *
+ *
* For the field list to work properly, you'll have to populate $export_fields with the fields available
- *
+ *
* NB: Your wizard class must be in
/inc/class.appname_wizard_.inc.php
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@@ -15,7 +15,7 @@
* @author Nathan Gray
*/
-class importexport_wizard_basic_export_csv
+class importexport_wizard_basic_export_csv
{
const TEMPLATE_MARKER = '-eTemplate-';
@@ -31,6 +31,7 @@ class importexport_wizard_basic_export_csv
protected $step_templates = array(
'wizard_step30' => 'importexport.wizard_basic_export_csv.choose_fields',
'wizard_step40' => 'importexport.wizard_basic_export_csv.choosesepncharset',
+ 'wizard_step50' => 'importexport.wizard_basic_export_csv.filter',
);
@@ -58,6 +59,7 @@ class importexport_wizard_basic_export_csv
$this->steps = array(
'wizard_step30' => lang('Choose fields to export'),
'wizard_step40' => lang('Choose seperator and charset'),
+ 'wizard_step50' => lang('Filters'),
);
list($appname, $part2) = explode('_', get_class($this));
if(!$GLOBALS['egw_info']['apps'][$appname]) $appname .= '_'.$part2; // Handle apps with _ in the name
@@ -222,6 +224,73 @@ class importexport_wizard_basic_export_csv
}
+ /**
+ * Set export filters
+ *
+ * @param array $content
+ * @param array $sel_options
+ * @param array $readonlys
+ * @param array $preserv
+ * @return string template name
+ */
+ function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv)
+ {
+ if($this->debug) error_log(get_class($this) . '::' . __METHOD__ .'->$content '.print_r($content,true));
+ // return from submit
+ if ($content['step'] == 'wizard_step50') {
+ // Process submitted
+ unset($content['filter']);
+ unset($content['set_filter']['fields']);
+ foreach($content['set_filter'] as $key => $value)
+ {
+ if($value) {
+ $content['filter'][$key] = $value;
+ }
+ }
+ unset($content['set_filter']);
+
+ // Next step
+ switch (array_search('pressed', $content['button']))
+ {
+ case 'next':
+ return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1);
+ case 'previous' :
+ return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],-1);
+ case 'finish':
+ return 'wizard_finish';
+ default :
+ return $this->wizard_step50($content,$sel_options,$readonlys,$preserv);
+ }
+ } else {
+
+ // Step 50 - filters
+ $content['msg'] = $this->steps['wizard_step50'];
+ $content['step'] = 'wizard_step50';
+
+ // Find filterable fields
+ if(!$content['set_filter'] && $content['filter']) {
+ $load = true;
+ }
+ $content['set_filter']['fields'] = importexport_helper_functions::get_filter_fields(
+ $content['application'],$content['plugin'],$this
+ );
+ // Load existing filter from either content or definition
+ if($load)
+ {
+ foreach($content['set_filter']['fields'] as $field => $settings)
+ {
+ $content['set_filter'][$field] = $content['filter'][$field];
+ }
+ }
+
+ $sel_options = array();
+
+ $preserv = $content;
+ unset ($preserv['button']);
+ return $this->step_templates[$content['step']];
+ }
+ }
+
/**
* Expose export fields for use elsewhere
*/
diff --git a/importexport/js/importexport.js b/importexport/js/importexport.js
index e10216b1c3..de423b5de4 100644
--- a/importexport/js/importexport.js
+++ b/importexport/js/importexport.js
@@ -10,5 +10,8 @@ function clear_options(id) {
for(var count = list.options.length - 1; count >= 0; count--) {
list.options[count] = null;
}
+ if($j().chosen && list) {
+ $j(list).trigger("liszt:updated");
+ }
}
diff --git a/importexport/setup/etemplates.inc.php b/importexport/setup/etemplates.inc.php
index 2a0112f1be..8141ebf5d9 100644
--- a/importexport/setup/etemplates.inc.php
+++ b/importexport/setup/etemplates.inc.php
@@ -2,7 +2,7 @@
/**
* EGroupware - eTemplates for Application importexport
* http://www.egroupware.org
- * generated by soetemplate::dump4setup() 2012-12-17 16:23
+ * generated by soetemplate::dump4setup() 2012-12-31 13:19
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package importexport
@@ -89,7 +89,14 @@ $templ_data[] = array('name' => 'importexport.export_dialog.options_tab','templa
display: none;
}','modified' => '1286482130',);
-$templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:4:",top";s:2:"h1";s:27:",@plugin_selectors_template";}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"name";s:21:"plugin_selectors_html";s:7:"no_lang";s:1:"1";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:26:"@plugin_selectors_template";}}}s:4:"rows";i:2;s:4:"cols";i:1;s:4:"size";s:6:",200px";s:7:"options";a:1:{i:1;s:5:"200px";}}}','size' => ',200px','style' => '','modified' => '1158223796',);
+$templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:10:{s:2:"h3";s:30:"20,!@plugin_selectors_template";s:2:"h2";s:27:",@plugin_selectors_template";s:2:"c2";s:4:",top";s:2:"h4";s:28:",!@plugin_selectors_template";s:2:"c3";s:2:"th";s:2:"h1";s:29:"20,@plugin_selectors_template";s:2:"c1";s:2:"th";s:2:"c4";s:4:",top";s:1:"B";s:14:"300,@no_filter";s:1:"A";s:3:"150";}i:1;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Definition filter";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"name";s:21:"plugin_selectors_html";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"span";s:8:",filters";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:6:"filter";s:4:"name";s:6:"filter";}}}i:3;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Definition filter";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:26:"@plugin_selectors_template";}s:1:"B";a:5:{s:4:"type";s:3:"box";s:4:"span";s:8:",filters";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:6:"filter";s:4:"name";s:6:"filter";}s:7:"onclick";s:105:"\\$j(\'input[value=\\\'filter\\\']\').not(\':checked\').attr(\'checked\',true).parent().effect(\'highlight\',{},2000);";}}}s:4:"rows";i:4;s:4:"cols";i:2;s:4:"size";s:10:"100%,200px";s:7:"options";a:2:{i:0;s:4:"100%";i:1;s:5:"200px";}}}','size' => '100%,200px','style' => 'select[multiple] {
+ width: 400px;
+}
+.filters {
+ max-height: 300px;
+ min-height: 150px;
+ overflow-y: auto;
+}','modified' => '1158223796',);
$templ_data[] = array('name' => 'importexport.import_definition','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:92:"Import definitions (Attension: Existing definitions with equal names will be overwritten!!!)";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:4:"file";s:4:"name";s:11:"import_file";}}i:3;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Import";s:4:"name";s:6:"import";}i:2;a:3:{s:4:"type";s:6:"button";s:4:"name";s:6:"update";s:5:"label";s:26:"Update default-definitions";}}}}s:4:"rows";i:3;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1306253183',);
@@ -122,6 +129,10 @@ $templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.choosesepn
$templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.choose_fields','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:4:"name";s:3:"msg";}}i:2;a:1:{s:1:"A";a:7:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c1";s:2:"th";}i:1;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Field";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Export";}i:2;a:7:{s:4:"type";s:10:"buttononly";s:4:"size";s:5:"check";s:5:"label";s:9:"Check all";s:4:"name";s:9:"check_all";s:4:"help";s:9:"Check all";s:7:"onclick";s:98:"jQuery(\'input:checkbox\').attr(\'checked\', !jQuery(\'input:checkbox\').attr(\'checked\')); return false;";s:6:"needed";s:1:"1";}}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"name";s:12:"${row}[name]";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:8:"checkbox";s:7:"no_lang";s:1:"1";s:4:"name";s:14:"export[${row}]";s:4:"size";s:18:"{$row_cont[field]}";}}}s:4:"rows";i:2;s:4:"cols";i:2;s:4:"size";s:10:",,,,,,auto";s:4:"name";s:6:"fields";s:7:"options";a:1:{i:6;s:4:"auto";}}}}s:4:"rows";i:2;s:4:"cols";i:1;s:7:"options";a:0:{}}}','size' => '','style' => '','modified' => '1286466690',);
+$templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.filter','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:6:{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:6:"filter";s:4:"name";s:10:"set_filter";s:4:"size";s:1:"1";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => 'select {
+ width: 200px;
+}','modified' => '1356969972',);
+
$templ_data[] = array('name' => 'importexport.wizard_basic_import_csv.choosesepncharset','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:7:{i:0;a:2:{s:1:"B";s:5:"180px";s:2:"h5";s:9:",@no_cats";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:3:"msg";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Fieldseperator";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:7:"no_lang";s:1:"1";s:4:"name";s:8:"fieldsep";s:4:"size";s:1:"1";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:15:"Charset of file";}s:1:"B";a:4:{s:4:"type";s:6:"select";s:7:"no_lang";s:1:"1";s:4:"name";s:7:"charset";s:4:"span";s:9:",width180";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:20:"Header lines to skip";}s:1:"B";a:3:{s:4:"type";s:3:"int";s:4:"name";s:16:"num_header_lines";s:4:"size";s:1:"0";}}i:5;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Update categories";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:11:"update_cats";}}i:6;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Import data is";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:7:"convert";}}}s:4:"rows";i:6;s:4:"cols";i:2;}}','size' => '','style' => '.width180 select { width:150px;}','modified' => '1287425796',);
$templ_data[] = array('name' => 'importexport.wizard_basic_import_csv.conditions','template' => '','lang' => '','group' => '0','version' => '1.9.002','data' => 'a:1:{i:0;a:8:{s:4:"type";s:4:"vbox";s:4:"data";a:2:{i:0;a:0:{}i:1;a:4:{s:1:"A";a:2:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[string]";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[type]";}i:2;a:2:{s:4:"type";s:4:"text";s:4:"name";s:12:"${row}[op_2]";}}s:1:"C";a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[true]";}s:1:"D";a:2:{s:4:"type";s:6:"select";s:4:"name";s:13:"${row}[false]";}}}s:4:"rows";i:1;s:4:"cols";i:4;s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:142:"How to merge with existing data? For each record, all conditions are evaluated from top to bottom, or stop. For blind insert, leave blank. ";}i:2;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c1";s:2:"th";}i:1;a:6:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Field";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:9:"Condition";}s:1:"C";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:4:"span";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:4:"span";s:1:"2";s:5:"label";s:4:"True";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,2,0";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";}i:2;a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Stop";s:5:"align";s:5:"right";}}}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:4:"span";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:4:"span";s:1:"2";s:5:"label";s:5:"False";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,2,0";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";}i:2;a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Stop";s:5:"align";s:5:"right";}}}s:1:"F";a:1:{s:4:"type";s:5:"label";}}i:2;a:6:{s:1:"A";a:4:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[string]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:3:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[type]";s:7:"no_lang";s:1:"1";}i:2;a:3:{s:4:"type";s:4:"text";s:4:"name";s:12:"${row}[op_2]";s:7:"no_lang";s:1:"1";}}s:1:"C";a:4:{s:4:"type";s:6:"select";s:4:"name";s:20:"${row}[true][action]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:8:"checkbox";s:5:"align";s:6:"center";s:4:"name";s:18:"${row}[true][stop]";}s:1:"E";a:4:{s:4:"type";s:6:"select";s:4:"name";s:21:"${row}[false][action]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"F";a:4:{s:4:"type";s:8:"checkbox";s:5:"align";s:6:"center";s:4:"name";s:19:"${row}[false][stop]";s:4:"size";s:7:"1,false";}}}s:4:"rows";i:2;s:4:"cols";i:6;s:4:"name";s:10:"conditions";s:7:"options";a:0:{}}i:3;a:5:{s:4:"type";s:6:"button";s:4:"name";s:11:"button[add]";s:5:"label";s:3:"add";s:4:"help";s:27:"Add an additional condition";s:7:"onclick";s:37:"xajax_eT_wrapper(this); return false;";}}}','size' => '','style' => '','modified' => '1320350666',);
diff --git a/importexport/setup/setup.inc.php b/importexport/setup/setup.inc.php
index 539251976e..a461586bbc 100644
--- a/importexport/setup/setup.inc.php
+++ b/importexport/setup/setup.inc.php
@@ -10,7 +10,7 @@
*/
$setup_info['importexport']['name'] = 'importexport';
-$setup_info['importexport']['version'] = '1.9.003';
+$setup_info['importexport']['version'] = '1.9.004';
$setup_info['importexport']['app_order'] = 2;
$setup_info['importexport']['enable'] = 2;
$setup_info['importexport']['tables'] = array('egw_importexport_definitions');
@@ -57,3 +57,4 @@ $setup_info['importexport']['check_install'] = array(
),
);
+
diff --git a/importexport/setup/tables_current.inc.php b/importexport/setup/tables_current.inc.php
index a8b983ee37..feed482a46 100644
--- a/importexport/setup/tables_current.inc.php
+++ b/importexport/setup/tables_current.inc.php
@@ -25,7 +25,8 @@ $phpgw_baseline = array(
'plugin_options' => array('type' => 'longtext'),
'owner' => array('type' => 'int','precision' => '20'),
'description' => array('type' => 'varchar','precision' => '255'),
- 'modified' => array('type' => 'timestamp')
+ 'modified' => array('type' => 'timestamp'),
+ 'filter' => array('type' => 'longtext')
),
'pk' => array('definition_id'),
'fk' => array(),
diff --git a/importexport/setup/tables_update.inc.php b/importexport/setup/tables_update.inc.php
index 50744ade67..a9b935a13b 100755
--- a/importexport/setup/tables_update.inc.php
+++ b/importexport/setup/tables_update.inc.php
@@ -100,3 +100,13 @@ function importexport_upgrade1_9_002()
return $GLOBALS['setup_info']['importexport']['currentver'] = '1.9.003';
}
+
+function importexport_upgrade1_9_003()
+{
+ $GLOBALS['egw_setup']->oProc->AddColumn('egw_importexport_definitions','filter',array(
+ 'type' => 'longtext'
+ ));
+
+ return $GLOBALS['setup_info']['importexport']['currentver'] = '1.9.004';
+}
+
diff --git a/importexport/templates/default/export_dialog.xet b/importexport/templates/default/export_dialog.xet
index 828a71aaa1..16585e8746 100644
--- a/importexport/templates/default/export_dialog.xet
+++ b/importexport/templates/default/export_dialog.xet
@@ -52,19 +52,44 @@
-
+
-
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+ select[multiple] {
+ width: 400px;
+}
+.filters {
+ max-height: 300px;
+ min-height: 150px;
+ overflow-y: auto;
+}
+
diff --git a/importexport/templates/default/wizard_basic_export_csv.choose_fields.xet b/importexport/templates/default/wizard_basic_export_csv.choose_fields.xet
new file mode 100644
index 0000000000..0b7e0f40cd
--- /dev/null
+++ b/importexport/templates/default/wizard_basic_export_csv.choose_fields.xet
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/importexport/templates/default/wizard_basic_export_csv.filter.xet b/importexport/templates/default/wizard_basic_export_csv.filter.xet
new file mode 100644
index 0000000000..41d6616014
--- /dev/null
+++ b/importexport/templates/default/wizard_basic_export_csv.filter.xet
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select {
+ width: 200px;
+}
+
+
\ No newline at end of file