Index: inc/admin/class.dc.filter.php
===================================================================
--- inc/admin/class.dc.filter.php	(revision 242)
+++ inc/admin/class.dc.filter.php	(revision 242)
@@ -0,0 +1,273 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of DotClear "MyPostTypes" plugin.
+# Copyright (c) 2010 Bruno Hondelatte, and contributors. 
+# Many, many thanks to Olivier Meunier and the Dotclear Team.
+# All rights reserved.
+#
+# MyPostTypes plugin for DC2 is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# DotClear is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with DotClear; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ***** END LICENSE BLOCK *****
+
+class dcFilterSet {
+
+	protected $filters;
+	protected $form_prefix;
+	protected $action;
+	protected $hideform;
+	protected $columns_form;
+	
+	public function __construct($action,$form_prefix="f_") {
+		$this->form_prefix=$form_prefix;
+		$this->filters = array();
+		$this->action = $action;
+	}
+
+	public function addFilter (Filter $filter) {
+		$filter->setFormPrefix($this->form_prefix);
+		$this->filters[$filter->id] = $filter;
+		return $this;
+	}
+
+	// Retrieves filter values from context
+	public function setValues ($form_data) {
+		$this->hideform = true;
+		if (isset($form_data['clear_filters']))
+			return;
+		foreach ($this->filters as $filter) {
+			$filter->setValues ($form_data);
+			if ($filter->isEnabled())
+				$this->hideform=false;
+		}
+		if (isset($form_data['add_filter']) && isset($this->filters[$form_data['add_filter']])) {
+			$this->filters[$form_data['add_filter']]->add();
+		}
+	}
+	
+	public function setColumnsForm($html)
+	{
+		$this->columns_form = $html;
+	}
+	
+	public function getFormFieldsAsHidden() {
+		$ret='';
+		foreach ($this->filters as $filter) {
+			$ret.= $filter->getFormFieldAsHidden();
+		}
+		return $ret;
+	}
+
+	public function getForm($action,$extra_content,$method="get",$nb_cols=3) {
+		$ret = '';
+		/*if ($this->hideform) {
+			$ret .= '<p><a id="filter-control" class="form-control" href="#">'.
+			__('Filters').'</a></p>';
+		}*/
+		$ret .= '<p><img alt="" src="minus.png"/> <a href="#" id="toggle-filters">'.__('Toggle filters and display options').'</a></p>';
+		$ret .=
+			'<div class="two-cols">'.
+			'<form id="filters" action="'.$this->action.'" method="get" id="filters-form">'.
+			'<div class="col70">'.
+			'<h3>'.__('Entries filters').'</h3>';
+			
+		$count=0;
+		$form_combo=array();
+		$form_combo['-']='';
+		foreach ($this->filters as $filter) {
+			if ($filter->isEnabled()) {
+				$ret .= $filter->getFormLine();
+			}
+			$form_combo[$filter->desc]=$filter->id;
+			$count++;
+		}
+		$ret .= 
+			'<p class="clear"><input class="delete" type="submit" value="'.__('Delete all filters').'" name="clear_filters"></p>'.
+			'<h3 class="margintop">'.__('Add a filter').'</h3>'.
+			'<p id="available_filters">'.
+			form::combo("add_filter",$form_combo).
+			'<input type="submit" value=" + " title="'.__('Add this filter').'" name="apply">'.
+			'</p>'.
+			'</div>'.
+			'<div class="col30">'.
+			$this->columns_form.
+			'</div>'.
+			'<p class="clear margintop"><input type="submit" value="'.__('Apply filters and display options').'" name="apply"></p>'.
+
+			'</form></div>';
+		return $ret;
+	}
+
+	public function header() {
+		return dcPage::jsLoad('js/filters.js');
+	}
+	public function display() {
+		echo $this->getForm("#","");
+	}
+
+	public function applyFilters($params) {
+		$filtered = false;
+		foreach ($this->filters as $filter) {
+			if ($filter->isEnabled()) {
+				$filter->applyFilter($params);
+				$filtered = true;
+			}
+		}
+		return $filtered;
+	}
+	
+}
+
+
+abstract class Filter {
+	public $id;
+	public $desc;
+	protected $request_param;
+	protected $enabled;
+	protected $values;
+	public $field_id;
+	
+	
+	public function __construct ($id,$desc,$request_param) {
+		$this->id = $id;
+		$this->desc = $desc;
+		$this->request_param = $request_param;
+		$this->enabled=false;
+		$this->values = array();
+		$this->field_id = $this->id;
+	}
+	
+	protected function getFieldId($pos=0) {
+		if ($pos == 0) {
+			return $this->field_id;
+		} else {
+			return $this->field_id.'_'.$pos;
+		}
+	}
+	
+	public function isEnabled() {
+		return $this->enabled;
+	}
+	
+	public function add() {
+		$this->enabled = true;
+	}
+	
+	public function setFormPrefix($prefix) {
+		$this->field_id = $prefix.$this->id;
+	}
+	
+	public abstract function getType();
+	
+	public function getFormFields() {
+		return '';
+	}
+
+	public function setValues($form_data) {
+/*		if (isset($form_data['c_'.$this->field_id])) {
+			$this->enabled = true;
+		}*/
+		$count=0;
+		while (isset($form_data[$this->getFieldId($count)])) {
+			if (!isset($form_data['del_'.$this->getFieldId($count)])) {
+				$this->values[] = $form_data[$this->getFieldId($count)];
+				$this->enabled = true;
+			}
+			$count++;
+		}
+	}
+	
+	public function getFormFieldAsHidden () {
+		$ret='';
+		for ($cur=0; $cur < count($this->values); $cur++) {
+			$ret .= form::hidden($this->getFieldId($cur), $this->values[$cur]);
+		}
+	}
+	public function getFormLine() {
+		$ret="";
+		for ($cur=0; $cur < count($this->values); $cur++) {
+			$ret .= '<p id="'.$this->getFieldId($cur).'" class="line" title="'.$this->desc.'">'.
+				$this->getFormFields($cur).
+				'<input id="del_'.$this->getFieldId($cur).'" class="delete" '.
+				'type="submit" title="Delete this filter" value=" - " name="del_'.$this->getFieldId($cur).'"/>'.
+				'</p>';
+		}
+		return $ret;
+	}
+	
+	public function applyFilter($params) {
+	}
+	
+}
+
+class comboFilter extends Filter {
+	protected $options;
+	protected $default;
+	protected $no_value;
+	protected $verb;
+	protected $extra;
+	
+	public function __construct($id,$desc,$request_param,$options,$extra=array()) {
+		parent::__construct($id,$desc,$request_param);
+		$this->options = $options;
+		$this->extra = $extra;
+		$this->desc = $desc;
+		$this->verb = "is";
+		$this->values=array();
+	}
+	
+	public function add() {
+		parent::add();
+		if (isset($this->extra['singleval']) && (count($this->values) > 0))
+			return;
+		$this->values[]=current($this->options);
+	}
+	
+	public function getType() {
+		return "combo";
+	}
+	
+	public function setValues($form_data) {
+		parent::setValues($form_data);
+		if (isset($form_data[$this->field_id."_v"])) {
+			$this->verb = $form_data[$this->field_id."_v"] == 'is' ? 'is' : 'isnot';
+		}
+	}
+
+	public function getFormFieldAsHidden () {
+		return parent::getFormFieldAsHidden().form::hidden($this->field_id."_v",$this->verb);
+	}
+
+	public function getFormFields($pos=0) {
+		
+		if ($pos == 0) {
+			$desc = $this->desc.' : ';
+			$labelclass="";
+		} else {
+			$desc = __('or');
+			$labelclass = ' class="or"';
+		};
+		return '<label for="'.$this->getFieldId($pos).'"'.$labelclass.'>'.$desc.'</label>'.
+			(($pos == 0) ?form::combo($this->field_id.'_v',array(__('is')=>'is',__('is not')=>'isnot'),$this->verb) : '').
+			form::combo($this->getFieldId($pos),$this->options,$this->values[$pos]);
+	}
+	
+	public function applyFilter($params) {
+		if (isset($this->extra['singleval']))
+			$params[$this->request_param]=$this->values[0];
+		else
+			$params[$this->request_param]=$this->values;
+	}
+}
+?>
Index: inc/admin/lib.dc.page.php
===================================================================
--- inc/admin/lib.dc.page.php	(revision 244)
+++ inc/admin/lib.dc.page.php	(revision 224)
@@ -101,10 +101,4 @@
 		if (l10n::getTextDirection($GLOBALS['_lang']) == 'rtl') {
 			echo '  <style type="text/css">'."\n".'  @import "style/default-rtl.css";'."\n"."  </style>\n";
-		}
-
-		$core->auth->user_prefs->addWorkspace('interface');
-		$user_ui_hide_std_favicon = $core->auth->user_prefs->interface->hide_std_favicon;
-		if (!$user_ui_hide_std_favicon) {
-			echo '<link rel="icon" type="image/png" href="images/favicon.png" />';
 		}
 		
Index: inc/admin/lib.pager.php
===================================================================
--- inc/admin/lib.pager.php	(revision 0)
+++ inc/admin/lib.pager.php	(revision 246)
@@ -12,4 +12,77 @@
 if (!defined('DC_RC_PATH')) { return; }
 
+class adminGenericColumn
+{
+	protected $core;
+	protected $rs;
+	protected $id;
+	protected $title;
+	protected $callback;
+	protected $html;
+	protected $order;
+	protected $visibility;
+	
+	public function __construct($id,$title,$callback,$html = null,$order = null)
+	{
+		if (!is_string($id) || $id === '') {
+			throw new Exception(__('Invalid column ID'));
+		}
+		
+		if (!is_string($title)) {
+			throw new Exception(__('Invalid column title'));
+		}
+		
+		if (is_null($html) || !is_string($html)) {
+			$html = '';
+		}
+		if (!empty($html)) {
+			$html = ' '.$html;
+		}
+		
+		if (!is_int($order)) {
+			$order = null;
+		}
+		
+		try {
+			if (!is_array($callback) || count($callback) < 2) {
+				throw new Exception(__('Callback parameter should be an array'));
+			}
+			$r = new ReflectionClass($callback[0]);
+			$f = $r->getMethod($callback[1]);
+			$p = $r->getParentClass();
+			if (!$p || $p->name != 'adminGenericList') {
+				throw new Exception(__('Callback class should be inherited of adminGenericList class'));
+			}
+		}
+		catch (Exception $e) {
+			throw new Exception(sprintf(__('Invalid column callback: %s'),$e->getMessage()));
+		}
+		
+		$this->id = $id;
+		$this->title = $title;
+		$this->callback = $callback;
+		$this->html = $html;
+		$this->order = $order;
+		$this->visibility = true;
+	}
+	
+	public function getInfo($k)
+	{
+		return property_exists(get_class($this),$k) ? $this->{$k} : null;
+	}
+	
+	public function setVisibility($visibility)
+	{
+		if (is_bool($visibility)) {
+			$this->visibility = $visibility;
+		}
+	}
+	
+	public function isVisible()
+	{
+		return $this->visibility;
+	}
+}
+
 class adminGenericList
 {
@@ -17,4 +90,5 @@
 	protected $rs;
 	protected $rs_count;
+	protected $columns;
 	
 	public function __construct($core,$rs,$rs_count)
@@ -23,11 +97,104 @@
 		$this->rs =& $rs;
 		$this->rs_count = $rs_count;
+		$this->context = get_class($this);
+		$this->columns = array();
+		$this->form_prefix = 'col_%s';
+		$this->form_trigger = 'add_filter';
+		
 		$this->html_prev = __('&#171;prev.');
 		$this->html_next = __('next&#187;');
-	}
-}
-
-class adminPostList extends adminGenericList
-{
+		
+		# Post columns
+		$this->addColumn('adminPostList','title',__('Title'),array('adminPostList','getTitle'));
+		$this->addColumn('adminPostList','date',__('Date'),array('adminPostList','getDate'));
+		$this->addColumn('adminPostList','category',__('Category'),array('adminPostList','getCategory'));
+		$this->addColumn('adminPostList','author',__('Author'),array('adminPostList','getAuthor'));
+		$this->addColumn('adminPostList','comment',__('Comments'),array('adminPostList','getComments'));
+		$this->addColumn('adminPostList','trackback',__('Trackbacks'),array('adminPostList','getTrackbacks'));
+		$this->addColumn('adminPostList','status',__('Status'),array('adminPostList','getStatus'));
+		
+		# Post (mini list) columns
+		$this->addColumn('adminPostMiniList','title',__('Title'),array('adminPostList','getTitle'));
+		$this->addColumn('adminPostMiniList','date',__('Date'),array('adminPostList','getDate'));
+		$this->addColumn('adminPostMiniList','author',__('Author'),array('adminPostList','getAuthor'));
+		$this->addColumn('adminPostMiniList','status',__('Status'),array('adminPostList','getStatus'));
+		
+		# Comment columns
+		$this->addColumn('adminCommentList','title',__('Title'),array('adminCommentList','getTitle'));
+		$this->addColumn('adminCommentList','date',__('Date'),array('adminCommentList','getDate'));
+		$this->addColumn('adminCommentList','author',__('Author'),array('adminCommentList','getAuthor'));
+		$this->addColumn('adminCommentList','type',__('Type'),array('adminCommentList','getType'));
+		$this->addColumn('adminCommentList','status',__('Status'),array('adminCommentList','getStatus'));
+		$this->addColumn('adminCommentList','edit','',array('adminCommentList','getEdit'));
+		
+		# User columns
+		$this->addColumn('adminUserList','username',__('Username'),array('adminUserList','getUserName'));
+		$this->addColumn('adminUserList','firstname',__('First name'),array('adminUserList','getFirstName'));
+		$this->addColumn('adminUserList','lastname',__('Last name'),array('adminUserList','getLastName'));
+		$this->addColumn('adminUserList','displayname',__('Display name'),array('adminUserList','getDisplayName'));
+		$this->addColumn('adminUserList','entries',__('Entries'),array('adminUserList','getEntries'));
+		
+		$this->setColumnsVisibility();
+		
+		$core->callBehavior('adminGenericListConstruct',$this);
+	}
+	
+	public function addColumn($context,$id,$title,$callback,$html = null,$order = null)
+	{
+		try {
+			if (!array_key_exists($context,$this->columns)) {
+				$this->columns[$context] = array();
+			}
+			
+			$c = new adminGenericColumn($id,$title,$callback,$html,$order);
+			$this->columns[$context][$c->getInfo('id')] = $c;
+		}
+		catch (Exception $e) {
+			if (DC_DEBUG) {
+				$this->core->error->add($e->getMessage());
+			}
+		}
+	}
+	
+	public function setColumnsVisibility()
+	{
+		$ws = $this->core->auth->user_prefs->addWorkspace('lists');
+		
+		$user_pref = !is_null($ws->{$this->context}) ? unserialize($ws->{$this->context}) : array();
+		
+		foreach ($this->columns[$this->context] as $k => $v) {
+			$visibility =  array_key_exists($k,$user_pref) ? $user_pref[$k] : true;
+			if (array_key_exists($this->form_trigger,$_REQUEST)) {
+				$key = sprintf($this->form_prefix,$k);
+				$visibility = !array_key_exists($key,$_REQUEST) ? false : true;
+			}
+			$v->setVisibility($visibility);
+			$user_pref[$k] = $visibility;
+		}
+		
+		if (array_key_exists($this->form_trigger,$_REQUEST)) {
+			$this->core->auth->user_prefs->lists->put($this->context,serialize($user_pref),'string');
+		}
+	}
+	
+	public function getColumnsForm()
+	{
+		$block = 
+		'<h3>'.__('Displayed information').'</h3>'.
+		'<ul>%s</ul>';
+		
+		$list = array();
+		
+		foreach ($this->columns[$this->context] as $k => $v) {
+			$col_id = sprintf($this->form_prefix,$k);
+			$col_label = sprintf('<label for="%s">%s</label>',$col_id,$v->getInfo('title'));
+			$col_html = sprintf('<li class="line">%s</li>',$col_label.form::checkbox($col_id,1,$v->isVisible()));
+			
+			array_push($list,$col_html);
+		}
+		
+		return !empty($list) ? sprintf($block,implode('',$list)) : '';
+	}
+	
 	public function display($page,$nb_per_page,$enclose_block='')
 	{
@@ -43,14 +210,13 @@
 			$pager->var_page = 'page';
 			
-			$html_block =
-			'<table class="clear"><tr>'.
-			'<th colspan="2">'.__('Title').'</th>'.
-			'<th>'.__('Date').'</th>'.
-			'<th>'.__('Category').'</th>'.
-			'<th>'.__('Author').'</th>'.
-			'<th>'.__('Comments').'</th>'.
-			'<th>'.__('Trackbacks').'</th>'.
-			'<th>'.__('Status').'</th>'.
-			'</tr>%s</table>';
+			$html_block = '<table class="clear"><tr>';
+			
+			foreach ($this->columns[$this->context] as $k => $v) {
+				if ($v->isVisible()) {
+					$html_block .= sprintf('<th%s>%s</th>',$v->getInfo('html'),$v->getInfo('title'));
+				}
+			}
+			
+			$html_block .= '</tr>%s</table>';
 			
 			if ($enclose_block) {
@@ -66,5 +232,5 @@
 			while ($this->rs->fetch())
 			{
-				echo $this->postLine();
+				echo $this->displayLine();
 			}
 			
@@ -75,5 +241,49 @@
 	}
 	
-	private function postLine()
+	private function displayLine()
+	{
+		$res = '';
+		
+		foreach ($this->columns[$this->context] as $k => $v) {
+			if ($v->isVisible()) {
+				$c = $v->getInfo('callback');
+				$func = $c[1];
+				$res .= $this->{$c[1]}();
+			}
+		}
+		
+		return sprintf($this->getDefaultLine(),$res);
+	}
+	
+	protected function getDefaultLine()
+	{
+		return '<tr class="line">%s</tr>';
+	}
+}
+
+class adminPostList extends adminGenericList
+{
+	protected function getDefaultLine()
+	{
+		return
+		'<tr class="line'.($this->rs->post_status != 1 ? ' offline' : '').'"'.
+		' id="p'.$this->rs->post_id.'">%s</tr>';
+	}
+	
+	protected function getTitle()
+	{
+		return
+		'<td class="maximal">'.
+		form::checkbox(array('entries[]'),$this->rs->post_id,'','','',!$this->rs->isEditable()).'&nbsp'.
+		'<a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'">'.
+		html::escapeHTML($this->rs->post_title).'</a></td>';
+	}
+	
+	protected function getDate()
+	{
+		return '<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>';
+	}
+	
+	protected function getCategory()
 	{
 		if ($this->core->auth->check('categories',$this->core->blog->id)) {
@@ -90,4 +300,24 @@
 		}
 		
+		return '<td class="nowrap">'.$cat_title.'</td>';
+	}
+	
+	protected function getAuthor()
+	{
+		return '<td class="nowrap">'.$this->rs->user_id.'</td>';
+	}
+	
+	protected function getComments()
+	{
+		return '<td class="nowrap">'.$this->rs->nb_comment.'</td>';
+	}
+	
+	protected function getTrackbacks()
+	{
+		return '<td class="nowrap">'.$this->rs->nb_trackback.'</td>';
+	}
+	
+	protected function getStatus()
+	{
 		$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
 		switch ($this->rs->post_status) {
@@ -123,166 +353,37 @@
 		}
 		
-		$res = '<tr class="line'.($this->rs->post_status != 1 ? ' offline' : '').'"'.
-		' id="p'.$this->rs->post_id.'">';
-		
-		$res .=
-		'<td class="nowrap">'.
-		form::checkbox(array('entries[]'),$this->rs->post_id,'','','',!$this->rs->isEditable()).'</td>'.
-		'<td class="maximal"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'">'.
-		html::escapeHTML($this->rs->post_title).'</a></td>'.
-		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>'.
-		'<td class="nowrap">'.$cat_title.'</td>'.
-		'<td class="nowrap">'.$this->rs->user_id.'</td>'.
-		'<td class="nowrap">'.$this->rs->nb_comment.'</td>'.
-		'<td class="nowrap">'.$this->rs->nb_trackback.'</td>'.
-		'<td class="nowrap status">'.$img_status.' '.$selected.' '.$protected.' '.$attach.'</td>'.
-		'</tr>';
-		
-		return $res;
+		return '<td class="nowrap status">'.$img_status.' '.$selected.' '.$protected.' '.$attach.'</td>';
 	}
 }
 
-class adminPostMiniList extends adminGenericList
-{
-	public function display($page,$nb_per_page,$enclose_block='')
-	{
-		if ($this->rs->isEmpty())
-		{
-			echo '<p><strong>'.__('No entry').'</strong></p>';
-		}
-		else
-		{
-			$pager = new pager($page,$this->rs_count,$nb_per_page,10);
-			$pager->html_prev = $this->html_prev;
-			$pager->html_next = $this->html_next;
-			$pager->var_page = 'page';
-			
-			$html_block =
-			'<table class="clear"><tr>'.
-			'<th>'.__('Title').'</th>'.
-			'<th>'.__('Date').'</th>'.
-			'<th>'.__('Author').'</th>'.
-			'<th>'.__('Status').'</th>'.
-			'</tr>%s</table>';
-			
-			if ($enclose_block) {
-				$html_block = sprintf($enclose_block,$html_block);
-			}
-			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
-			
-			$blocks = explode('%s',$html_block);
-			
-			echo $blocks[0];
-			
-			while ($this->rs->fetch())
-			{
-				echo $this->postLine();
-			}
-			
-			echo $blocks[1];
-			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
-		}
-	}
-	
-	private function postLine()
-	{
-		$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
-		switch ($this->rs->post_status) {
-			case 1:
-				$img_status = sprintf($img,__('published'),'check-on.png');
-				break;
-			case 0:
-				$img_status = sprintf($img,__('unpublished'),'check-off.png');
-				break;
-			case -1:
-				$img_status = sprintf($img,__('scheduled'),'scheduled.png');
-				break;
-			case -2:
-				$img_status = sprintf($img,__('pending'),'check-wrn.png');
-				break;
-		}
-		
-		$protected = '';
-		if ($this->rs->post_password) {
-			$protected = sprintf($img,__('protected'),'locker.png');
-		}
-		
-		$selected = '';
-		if ($this->rs->post_selected) {
-			$selected = sprintf($img,__('selected'),'selected.png');
-		}
-		
-		$attach = '';
-		$nb_media = $this->rs->countMedia();
-		if ($nb_media > 0) {
-			$attach_str = $nb_media == 1 ? __('%d attachment') : __('%d attachments');
-			$attach = sprintf($img,sprintf($attach_str,$nb_media),'attach.png');
-		}
-		
-		$res = '<tr class="line'.($this->rs->post_status != 1 ? ' offline' : '').'"'.
-		' id="p'.$this->rs->post_id.'">';
-		
-		$res .=
-		'<td class="maximal"><a href="'.$this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id).'" '.
-		'title="'.html::escapeHTML($this->rs->getURL()).'">'.
-		html::escapeHTML($this->rs->post_title).'</a></td>'.
-		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->post_dt).'</td>'.
-		'<td class="nowrap">'.$this->rs->user_id.'</td>'.
-		'<td class="nowrap status">'.$img_status.' '.$selected.' '.$protected.' '.$attach.'</td>'.
-		'</tr>';
-		
-		return $res;
-	}
-}
+class adminPostMiniList extends adminPostList{}
 
 class adminCommentList extends adminGenericList
 {
-	public function display($page,$nb_per_page,$enclose_block='')
-	{
-		if ($this->rs->isEmpty())
-		{
-			echo '<p><strong>'.__('No comment').'</strong></p>';
-		}
-		else
-		{
-			$pager = new pager($page,$this->rs_count,$nb_per_page,10);
-			$pager->html_prev = $this->html_prev;
-			$pager->html_next = $this->html_next;
-			$pager->var_page = 'page';
-			
-			$html_block =
-			'<table><tr>'.
-			'<th colspan="2">'.__('Title').'</th>'.
-			'<th>'.__('Date').'</th>'.
-			'<th>'.__('Author').'</th>'.
-			'<th>'.__('Type').'</th>'.
-			'<th>'.__('Status').'</th>'.
-			'<th>&nbsp;</th>'.
-			'</tr>%s</table>';
-			
-			if ($enclose_block) {
-				$html_block = sprintf($enclose_block,$html_block);
-			}
-			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
-			
-			$blocks = explode('%s',$html_block);
-			
-			echo $blocks[0];
-			
-			while ($this->rs->fetch())
-			{
-				echo $this->commentLine();
-			}
-			
-			echo $blocks[1];
-			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
-		}
-	}
-	
-	private function commentLine()
+	protected function getDefaultLine()
+	{
+		return
+		'<tr class="line'.($this->rs->comment_status != 1 ? ' offline' : '').'"'.
+		' id="c'.$this->rs->comment_id.'">%s</tr>';
+	}
+	
+	protected function getTitle()
+	{
+		$post_url = $this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id);
+		
+		return
+		'<td class="maximal">'.
+		form::checkbox(array('comments[]'),$this->rs->comment_id,'','','',0).'&nbsp'.
+		'<a href="'.$post_url.'">'.
+		html::escapeHTML($this->rs->post_title).'</a>'.
+		($this->rs->post_type != 'post' ? ' ('.html::escapeHTML($this->rs->post_type).')' : '').'</td>';
+	}
+	
+	protected function getDate()
+	{
+		return '<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->comment_dt).'</td>';
+	}
+	
+	protected function getAuthor()
 	{
 		global $author, $status, $sortby, $order, $nb_per_page;
@@ -295,12 +396,19 @@
 		'&amp;author='.rawurlencode($this->rs->comment_author);
 		
-		$post_url = $this->core->getPostAdminURL($this->rs->post_type,$this->rs->post_id);
-		
-		$comment_url = 'comment.php?id='.$this->rs->comment_id;
-		
-		$comment_dt =
-		dt::dt2str($this->core->blog->settings->system->date_format.' - '.
-		$this->core->blog->settings->system->time_format,$this->rs->comment_dt);
-		
+		$comment_author = html::escapeHTML($this->rs->comment_author);
+		if (mb_strlen($comment_author) > 20) {
+			$comment_author = mb_strcut($comment_author,0,17).'...';
+		}
+		
+		return '<td class="nowrap"><a href="'.$author_url.'">'.$comment_author.'</a></td>';
+	}
+	
+	protected function getType()
+	{
+		return '<td class="nowrap">'.($this->rs->comment_trackback ? __('trackback') : __('comment')).'</td>';
+	}
+	
+	protected function getStatus()
+	{
 		$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
 		switch ($this->rs->comment_status) {
@@ -319,28 +427,14 @@
 		}
 		
-		$comment_author = html::escapeHTML($this->rs->comment_author);
-		if (mb_strlen($comment_author) > 20) {
-			$comment_author = mb_strcut($comment_author,0,17).'...';
-		}
-		
-		$res = '<tr class="line'.($this->rs->comment_status != 1 ? ' offline' : '').'"'.
-		' id="c'.$this->rs->comment_id.'">';
-		
-		$res .=
-		'<td class="nowrap">'.
-		form::checkbox(array('comments[]'),$this->rs->comment_id,'','','',0).'</td>'.
-		'<td class="maximal"><a href="'.$post_url.'">'.
-		html::escapeHTML($this->rs->post_title).'</a>'.
-		($this->rs->post_type != 'post' ? ' ('.html::escapeHTML($this->rs->post_type).')' : '').'</td>'.
-		'<td class="nowrap">'.dt::dt2str(__('%Y-%m-%d %H:%M'),$this->rs->comment_dt).'</td>'.
-		'<td class="nowrap"><a href="'.$author_url.'">'.$comment_author.'</a></td>'.
-		'<td class="nowrap">'.($this->rs->comment_trackback ? __('trackback') : __('comment')).'</td>'.
-		'<td class="nowrap status">'.$img_status.'</td>'.
+		return '<td class="nowrap status">'.$img_status.'</td>';
+	}
+	
+	protected function getEdit()
+	{
+		$comment_url = 'comment.php?id='.$this->rs->comment_id;
+		
+		return
 		'<td class="nowrap status"><a href="'.$comment_url.'">'.
 		'<img src="images/edit-mini.png" alt="" title="'.__('Edit this comment').'" /></a></td>';
-		
-		$res .= '</tr>';
-		
-		return $res;
 	}
 }
@@ -348,48 +442,5 @@
 class adminUserList extends adminGenericList
 {
-	public function display($page,$nb_per_page,$enclose_block='')
-	{
-		if ($this->rs->isEmpty())
-		{
-			echo '<p><strong>'.__('No user').'</strong></p>';
-		}
-		else
-		{
-			$pager = new pager($page,$this->rs_count,$nb_per_page,10);
-			$pager->html_prev = $this->html_prev;
-			$pager->html_next = $this->html_next;
-			$pager->var_page = 'page';
-			
-			$html_block =
-			'<table class="clear"><tr>'.
-			'<th colspan="2">'.__('Username').'</th>'.
-			'<th>'.__('First Name').'</th>'.
-			'<th>'.__('Last Name').'</th>'.
-			'<th>'.__('Display name').'</th>'.
-			'<th class="nowrap">'.__('Entries').'</th>'.
-			'</tr>%s</table>';
-			
-			if ($enclose_block) {
-				$html_block = sprintf($enclose_block,$html_block);
-			}
-			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
-			
-			$blocks = explode('%s',$html_block);
-			
-			echo $blocks[0];
-			
-			while ($this->rs->fetch())
-			{
-				echo $this->userLine();
-			}
-			
-			echo $blocks[1];
-			
-			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
-		}
-	}
-	
-	private function userLine()
+	protected function getUserName()
 	{
 		$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
@@ -404,17 +455,34 @@
 			$img_status = sprintf($img,__('superadmin'),'superadmin.png');
 		}
-		return
-		'<tr class="line">'.
-		'<td class="nowrap">'.form::hidden(array('nb_post[]'),(integer) $this->rs->nb_post).
-		form::checkbox(array('user_id[]'),$this->rs->user_id).'</td>'.
-		'<td class="maximal"><a href="user.php?id='.$this->rs->user_id.'">'.
-		$this->rs->user_id.'</a>&nbsp;'.$img_status.'</td>'.
-		'<td class="nowrap">'.$this->rs->user_firstname.'</td>'.
-		'<td class="nowrap">'.$this->rs->user_name.'</td>'.
-		'<td class="nowrap">'.$this->rs->user_displayname.'</td>'.
+		
+		return
+		'<td class="maximal">'.form::hidden(array('nb_post[]'),(integer) $this->rs->nb_post).
+		form::checkbox(array('user_id[]'),$this->rs->user_id).'&nbsp;'.
+		'<a href="user.php?id='.$this->rs->user_id.'">'.
+		$this->rs->user_id.'</a>&nbsp;'.$img_status.'</td>';
+	}
+	
+	protected function getFirstName()
+	{
+		return '<td class="nowrap">'.$this->rs->user_firstname.'</td>';
+	}
+	
+	protected function getLastName()
+	{
+		return '<td class="nowrap">'.$this->rs->user_name.'</td>';
+	}
+	
+	protected function getDisplayName()
+	{
+		return '<td class="nowrap">'.$this->rs->user_displayname.'</td>';
+	}
+	
+	protected function getEntries()
+	{
+		return
 		'<td class="nowrap"><a href="posts.php?user_id='.$this->rs->user_id.'">'.
-		$this->rs->nb_post.'</a></td>'.
-		'</tr>';
+		$this->rs->nb_post.'</a></td>';
 	}
 }
+
 ?>
Index: inc/prepend.php
===================================================================
--- inc/prepend.php	(revision 9)
+++ inc/prepend.php	(revision 225)
@@ -41,5 +41,7 @@
 $__autoload['dcCategories']			= dirname(__FILE__).'/core/class.dc.categories.php';
 $__autoload['dcError']				= dirname(__FILE__).'/core/class.dc.error.php';
+$__autoload['dcGenericMeta']		= dirname(__FILE__).'/core/class.dc.genmeta.php';
 $__autoload['dcMeta']				= dirname(__FILE__).'/core/class.dc.meta.php';
+$__autoload['dcUserMeta']				= dirname(__FILE__).'/core/class.dc.usermeta.php';
 $__autoload['dcMedia']				= dirname(__FILE__).'/core/class.dc.media.php';
 $__autoload['dcModules']				= dirname(__FILE__).'/core/class.dc.modules.php';
@@ -68,4 +70,6 @@
 $__autoload['adminCommentList']		= dirname(__FILE__).'/admin/lib.pager.php';
 $__autoload['adminUserList']			= dirname(__FILE__).'/admin/lib.pager.php';
+$__autoload['dcFilterSet'] =  dirname(__FILE__).'/admin/class.dc.filter.php';
+$__autoload['dcFilter'] =  dirname(__FILE__).'/admin/class.dc.filter.php';
 
 $__autoload['dcTemplate']			= dirname(__FILE__).'/public/class.dc.template.php';
@@ -118,5 +122,5 @@
 # Constants
 define('DC_ROOT',path::real(dirname(__FILE__).'/..'));
-define('DC_VERSION','2.3.0-dev');
+define('DC_VERSION','2.3.1');
 define('DC_DIGESTS',dirname(__FILE__).'/digests');
 define('DC_L10N_ROOT',dirname(__FILE__).'/../locales');
