Index: admin/js/_posts_actions.js
===================================================================
--- admin/js/_posts_actions.js	(revision 1638)
+++ admin/js/_posts_actions.js	(revision 1806)
@@ -1,9 +1,12 @@
 $(function() {
-	$('#new_auth_id').autocomplete(usersList,
-	{
-		delay: 1000,
-		matchSubset: true,
-		matchContains: true
-	});
+	new_auth_id = $('#new_auth_id');
+	if (new_auth_id.length) {
+		new_auth_id.autocomplete(usersList,
+		{
+			delay: 1000,
+			matchSubset: true,
+			matchContains: true
+		});
+	}
 	$('#new_cat').toggleWithLegend($('#new_cat').parent().children().not('#new_cat'), {
 		// no cookie on new category as we don't use this every day
Index: admin/js/common.js
===================================================================
--- admin/js/common.js	(revision 1871)
+++ admin/js/common.js	(revision 1862)
@@ -352,5 +352,5 @@
 	$('#wrapper').contents().each(function() {
 		if (this.nodeType==8) {
-			$('#footer a[href!="help.php"]').attr('title', $('#footer a[href!="help.php"]').attr('title') + this.data );
+			$('#footer a').attr('title', $('#footer a').attr('title') + this.data );
 		}
 	});
Index: admin/posts.php
===================================================================
--- admin/posts.php	(revision 1792)
+++ admin/posts.php	(revision 1806)
@@ -103,33 +103,8 @@
 
 # Actions combo box
-$combo_action = array();
-if ($core->auth->check('publish,contentadmin',$core->blog->id))
-{
-	$combo_action[__('Status')] = array(
-		__('Publish') => 'publish',
-		__('Unpublish') => 'unpublish',
-		__('Schedule') => 'schedule',
-		__('Mark as pending') => 'pending'
-	);
-}
-$combo_action[__('Mark')] = array(
-	__('Mark as selected') => 'selected',
-	__('Mark as unselected') => 'unselected'
-);
-$combo_action[__('Change')] = array(
-	__('Change category') => 'category',
-	__('Change language') => 'lang');
-if ($core->auth->check('admin',$core->blog->id))
-{
-	$combo_action[__('Change')] = array_merge($combo_action[__('Change')],
-		array(__('Change author') => 'author'));
-}
-if ($core->auth->check('delete,contentadmin',$core->blog->id))
-{
-	$combo_action[__('Delete')] = array(__('Delete') => 'delete');
-}
-
-# --BEHAVIOR-- adminPostsActionsCombo
-$core->callBehavior('adminPostsActionsCombo',array(&$combo_action));
+
+$posts_actions_page = new dcPostsActionsPage($core,'posts.php');
+
+$posts_actions_page->process();
 
 /* Get posts
@@ -304,5 +279,5 @@
 	# Show posts
 	$post_list->display($page,$nb_per_page,
-	'<form action="posts_actions.php" method="post" id="form-entries">'.
+	'<form action="posts.php" method="post" id="form-entries">'.
 	
 	'%s'.
@@ -312,5 +287,5 @@
 	
 	'<p class="col right"><label for="action" class="classic">'.__('Selected entries action:').'</label> '.
-	form::combo('action',$combo_action).
+	form::combo('action',$posts_actions_page->getCombo()).
 	'<input type="submit" value="'.__('ok').'" /></p>'.
 	form::hidden(array('user_id'),$user_id).
Index: admin/posts_actions.php
===================================================================
--- admin/posts_actions.php	(revision 1719)
+++ admin/posts_actions.php	(revision 1806)
@@ -11,490 +11,14 @@
 # -- END LICENSE BLOCK -----------------------------------------
 
+/* ### THIS FILE IS DEPRECATED 					### */
+/* ### IT IS ONLY USED FOR PLUGINS COMPATIBILITY ### */
+
 require dirname(__FILE__).'/../inc/admin/prepend.php';
 
 dcPage::check('usage,contentadmin');
 
-$params = array();
+$posts_actions_page = new dcPostsActionsPage($core,'posts.php');
 
-/**
-* FieldsList - Compatibility class for hidden fields & entries[] fields
-*
-*/
-class FieldsList {
-	/** @var array list of hidden fields */
-	protected $hidden;
-	/** @var array list of selected entries */
-	protected $entries;
+$posts_actions_page->process();
 
-
-   /**
-     * Class constructor
-	*/
-	public function __construct() {
-		$this->hidden=array();
-		$this->entries =array();
-	}
-
-    /**
-     * addHidden - adds a hidden field
-     * 
-     * @param string $name the field name.
-     * @param mixed $value the field value.
-     *
-     * @access public
-	 * @return the FieldsList instance, enabling to chain requests
-     */	
-	 public function addHidden($name,$value) {
-		$this->hidden[] = form::hidden($name,$value);
-		return $this;
-	}
-
-    /**
-     * addEntry - adds a antry field
-     * 
-     * @param string $id the entry id.
-     * @param mixed $title the entry title.
-     *
-     * @access public
-	 * @return the FieldsList instance, enabling to chain requests
-     */	
-	 public function addEntry($id,$title) {
-		$this->entries[$id]=$title;
-		return $this;
-	}
-
-    /**
-     * getHidden - returns the list of hidden fields, html encoded
-     *
-     * @access public
-	 * @return the list of hidden fields, html encoded
-     */
-	 public function getHidden() {
-		return join('',$this->hidden);
-	}
-	
-    /**
-     * getEntries - returns the list of entry fields, html encoded
-     *
-	 * @param boolean $hidden if set to true, returns entries as a list of hidden field
-	 *                if set to false, returns html code displaying the list of entries
-	 *                with a list of checkboxes to enable to select/deselect entries
-     * @access public
-	 * @return the list of entry fields, html encoded
-     */
-	public function getEntries ($hidden=false) {
-		$ret = '';
-		if ($hidden) {
-			foreach ($this->entries as $id=> $e) {
-				$ret .= form::hidden('entries[]',$id);
-			}
-		} else {
-			$ret = 
-				'<table class="posts-list"><tr>'.
-				'<th colspan="2">'.__('Title').'</th>'.
-				'</tr>';
-			foreach ($this->entries as $id=>$title) {
-				$ret .= 
-					'<tr><td>'.
-					form::checkbox(array('entries[]'),$id,true,'','').'</td>'.
-					'<td>'.	$title.'</td></tr>';
-			}
-			$ret .= '</table>';
-		}
-		return $ret;
-	}
-	
-    /**
-     * getEntriesQS - returns the list of entry fields as query string
-     *
-     * @access public
-	 * @return the list of entry fields, html encoded
-     */
-	public function getEntriesQS() {
-		$ret=array();
-		foreach ($this->entries as $id=>$title) {
-			$ret[] = 'entries[]='.$id;
-		}
-		return join('&',$ret);
-	}
-	
-    /**
-     * __toString - magic method. -- DEPRECATED here
-	 *              This method is only used to preserve compatibility with plugins 
-	 *				relying on previous versions of adminPostsActionsContent behavior, 
-	 *
-     * @access public
-	 * @return the list of hidden fields and entries (as hidden fields too), html encoded
-     */
-	public function __toString() {
-		return join('',$this->hidden).$this->getEntries(true);
-	}
-}
-
-$fields = new FieldsList();
-$posts_ids = array();
-
-if (isset($_POST['redir']) && strpos($_POST['redir'],'://') === false)
-{
-	$redir = $_POST['redir'];
-}
-else
-{
-	$redir =
-	'posts.php?user_id='.$_POST['user_id'].
-	'&cat_id='.$_POST['cat_id'].
-	'&status='.$_POST['status'].
-	'&selected='.$_POST['selected'].
-	'&month='.$_POST['month'].
-	'&lang='.$_POST['lang'].
-	'&sortby='.$_POST['sortby'].
-	'&order='.$_POST['order'].
-	'&page='.$_POST['page'].
-	'&nb='.$_POST['nb'];
-}
-$redir_sel = $redir;
-
-if (!empty($_POST['entries']))
-{
-	$entries = $_POST['entries'];
-	
-	foreach ($entries as $k => $v) {
-		$entries[$k] = (integer) $v;
-	}
-	
-	$params['sql'] = 'AND P.post_id IN('.implode(',',$entries).') ';
-	
-	if (!isset($_POST['full_content']) || empty($_POST['full_content'])) {
-		$params['no_content'] = true;
-	}
-	
-	if (isset($_POST['post_type'])) {
-		$params['post_type'] = $_POST['post_type'];
-	}
-	
-	$posts = $core->blog->getPosts($params);
-	while ($posts->fetch())	{
-		$posts_ids[] = $posts->post_id;
-		$fields->addEntry($posts->post_id,$posts->post_title);
-	}
-	// Redirection including selected entries
-	$redir_sel = $redir.'&'.$fields->getEntriesQS();
-
-} else {
-	$posts = $core->con->select("SELECT blog_id FROM ".$core->prefix."blog WHERE false");;
-}
-
-/* Actions
--------------------------------------------------------- */
-if (!empty($_POST['action']))
-{
-	$action = $_POST['action'];
-} 
-else
-{
-	$core->error->add(__('No action specified.'));
-	dcPage::open(
-		__('Entries'),'',dcPage::breadcrumb(
-		array(
-			html::escapeHTML($core->blog->name) => '',
-			__('Entries') => 'posts.php',
-			'<span class="page-title">'.__('Entries actions').'</span>' => ''
-		))
-	);
-	
-	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
-
-	dcPage::close();
-	exit;
-}
-
-# --BEHAVIOR-- adminPostsActions
-$core->callBehavior('adminPostsActions',$core,$posts,$action,$redir);
-
-if (preg_match('/^(publish|unpublish|schedule|pending)$/',$action))
-{
-	switch ($action) {
-		case 'unpublish' : $status = 0; break;
-		case 'schedule' : $status = -1; break;
-		case 'pending' : $status = -2; break;
-		default : $status = 1; break;
-	}
-	
-	try
-	{
-		$core->blog->updPostsStatus($posts_ids,$status);
-		
-		http::redirect($redir_sel.'&upd=1');
-	}
-	catch (Exception $e)
-	{
-		$core->error->add($e->getMessage());
-	}
-}
-elseif ($action == 'selected' || $action == 'unselected')
-{
-	try
-	{
-		$core->blog->updPostsSelected($posts_ids,$action == 'selected');
-		
-		http::redirect($redir_sel."&upd=1");
-	}
-	catch (Exception $e)
-	{
-		$core->error->add($e->getMessage());
-	}
-}
-elseif ($action == 'delete')
-{
-	try
-	{
-		// Backward compatibility
-		foreach($posts_ids as $post_id)
-		{
-			# --BEHAVIOR-- adminBeforePostDelete
-			$core->callBehavior('adminBeforePostDelete',(integer) $post_id);
-		}
-		
-		# --BEHAVIOR-- adminBeforePostsDelete
-		$core->callBehavior('adminBeforePostsDelete',$posts_ids);
-		
-		$core->blog->delPosts($posts_ids);
-		
-		http::redirect($redir."&del=1");
-	}
-	catch (Exception $e)
-	{
-		$core->error->add($e->getMessage());
-	}
-	
-}
-elseif ($action == 'category' && isset($_POST['new_cat_id']))
-{
-	$new_cat_id = $_POST['new_cat_id'];
-	
-	try
-	{
-		if (!empty($_POST['new_cat_title']) && $core->auth->check('categories', $core->blog->id))
-		{
-			$cur_cat = $core->con->openCursor($core->prefix.'category');
-			$cur_cat->cat_title = $_POST['new_cat_title'];
-			$cur_cat->cat_url = '';
-			
-			$parent_cat = !empty($_POST['new_cat_parent']) ? $_POST['new_cat_parent'] : '';
-			
-			# --BEHAVIOR-- adminBeforeCategoryCreate
-			$core->callBehavior('adminBeforeCategoryCreate', $cur_cat);
-			
-			$new_cat_id = $core->blog->addCategory($cur_cat, (integer) $parent_cat);
-			
-			# --BEHAVIOR-- adminAfterCategoryCreate
-			$core->callBehavior('adminAfterCategoryCreate', $cur_cat, $new_cat_id);
-		}
-		
-		$core->blog->updPostsCategory($posts_ids, $new_cat_id);
-		
-		http::redirect($redir_sel."&upd=1");
-	}
-	catch (Exception $e)
-	{
-		$core->error->add($e->getMessage());
-	}
-}
-elseif ($action == 'author' && isset($_POST['new_auth_id'])
-&& $core->auth->check('admin',$core->blog->id))
-{
-	$new_user_id = $_POST['new_auth_id'];
-	
-	try
-	{
-		if ($core->getUser($new_user_id)->isEmpty()) {
-			throw new Exception(__('This user does not exist'));
-		}
-		
-		$cur = $core->con->openCursor($core->prefix.'post');
-		$cur->user_id = $new_user_id;
-		$cur->update('WHERE post_id '.$core->con->in($posts_ids));
-		
-		http::redirect($redir_sel."&upd=1");
-	}
-	catch (Exception $e)
-	{
-		$core->error->add($e->getMessage());
-	}
-}
-elseif ($action == 'lang' && isset($_POST['new_lang']))
-{
-	$new_lang = $_POST['new_lang'];
-	try
-	{
-		$cur = $core->con->openCursor($core->prefix.'post');
-		$cur->post_lang = $new_lang;
-		$cur->update('WHERE post_id '.$core->con->in($posts_ids));
-		
-		http::redirect($redir_sel."&upd=1");
-	}
-	catch (Exception $e)
-	{
-		$core->error->add($e->getMessages());
-	}
-}
-
-/* DISPLAY
--------------------------------------------------------- */
-// Get current users list
-$usersList = '';
-if ($action == 'author' && $core->auth->check('admin',$core->blog->id)) {
-	$params = array(
-		'limit' => 100,
-		'order' => 'nb_post DESC'
-		);
-	$rs = $core->getUsers($params);
-	while ($rs->fetch())
-	{
-		$usersList .= ($usersList != '' ? ',' : '').'"'.$rs->user_id.'"';
-	}
-}
-dcPage::open(
-	__('Entries'),
-	'<script type="text/javascript">'."\n".
-	"//<![CDATA[\n".
-	'usersList = ['.$usersList.']'."\n".
-	"\n//]]>\n".
-	"</script>\n".
-	dcPage::jsLoad('js/jquery/jquery.autocomplete.js').
-	dcPage::jsLoad('js/_posts_actions.js').
-	dcPage::jsMetaEditor().
-	# --BEHAVIOR-- adminBeforePostDelete
-	$core->callBehavior('adminPostsActionsHeaders')
-);
-
-if (!isset($action)) {
-	dcPage::close();
-	exit;
-}
-
-if (isset($_POST['redir']) && strpos($_POST['redir'],'://') === false)
-{
-	$fields->addHidden(array('redir'),html::escapeURL($_POST['redir']));
-}
-else
-{
-	$fields
-		->addHidden(array('user_id'),$_POST['user_id'])
-		->addHidden(array('cat_id'),$_POST['cat_id'])
-		->addHidden(array('status'),$_POST['status'])
-		->addHidden(array('selected'),$_POST['selected'])
-		->addHidden(array('month'),$_POST['month'])
-		->addHidden(array('lang'),$_POST['lang'])
-		->addHidden(array('sortby'),$_POST['sortby'])
-		->addHidden(array('order'),$_POST['order'])
-		->addHidden(array('page'),$_POST['page'])
-		->addHidden(array('nb'),$_POST['nb'])
-	;
-}
-
-if (isset($_POST['post_type'])) {
-	$fields->addHidden(array('post_type'),$_POST['post_type']);
-}
-
-# --BEHAVIOR-- adminPostsActionsContent
-$core->callBehavior('adminPostsActionsContent',$core,$action,$fields);
-
-if ($action == 'category')
-{
-	echo dcPage::breadcrumb(
-		array(
-			html::escapeHTML($core->blog->name) => '',
-			__('Entries') => 'posts.php',
-			'<span class="page-title">'.__('Change category for this selection').'</span>' => ''
-	));
-	
-	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
-
-	# categories list
-	# Getting categories
-	$categories_combo = dcAdminCombos::getCategoriesCombo(
-		$core->blog->getCategories(array('post_type'=>'post'))
-	);
-	
-	echo
-	'<form action="posts_actions.php" method="post">'.
-	$fields->getEntries().
-	'<p><label for="new_cat_id" class="classic">'.__('Category:').'</label> '.
-	form::combo('new_cat_id',$categories_combo,'');
-	
-	if ($core->auth->check('categories', $core->blog->id)) {
-		echo 
-		'<div>'.
-		'<p id="new_cat">'.__('Create a new category for the post(s)').'</p>'.
-		'<p><label for="new_cat_title">'.__('Title:').'</label> '.
-		form::field('new_cat_title',30,255,'','').'</p>'.
-		'<p><label for="new_cat_parent">'.__('Parent:').'</label> '.
-		form::combo('new_cat_parent',$categories_combo,'','').
-		'</p>'.
-		'</div>';
-	}
-	
-	echo
-	$fields->getHidden().
-	$core->formNonce().
-	form::hidden(array('action'),'category').
-	'<input type="submit" value="'.__('Save').'" /></p>'.
-	'</form>';
-}
-elseif ($action == 'lang')
-{
-	echo dcPage::breadcrumb(
-		array(
-			html::escapeHTML($core->blog->name) => '',
-			__('Entries') => 'posts.php',
-			'<span class="page-title">'.__('Change language for this selection').'</span>' => ''
-	));
-	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
-
-	# lang list
-	# Languages combo
-	$rs = $core->blog->getLangs(array('order'=>'asc'));
-	$lang_combo = dcAdminCombos::getLangsCombo($rs,true);
-	
-	echo
-	'<form action="posts_actions.php" method="post">'.
-	$fields->getEntries().
-	
-	'<p><label for="new_lang" class="classic">'.__('Entry lang:').'</label> '.
-	form::combo('new_lang',$lang_combo,'');
-	
-	echo
-	$fields->getHidden().
-	$core->formNonce().
-	form::hidden(array('action'),'lang').
-	'<input type="submit" value="'.__('Save').'" /></p>'.
-	'</form>';
-
-}
-elseif ($action == 'author' && $core->auth->check('admin',$core->blog->id))
-{
-	echo dcPage::breadcrumb(
-		array(
-			html::escapeHTML($core->blog->name) => '',
-			__('Entries') => 'posts.php',
-			'<span class="page-title">'.__('Change author for this selection').'</span>' => ''
-	));
-	echo '<p><a class="back" href="'.html::escapeURL($redir_sel).'">'.__('Back to entries list').'</a></p>';
-
-	echo
-	'<form action="posts_actions.php" method="post">'.
-	$fields->getEntries().
-	'<p><label for="new_auth_id" class="classic">'.__('New author (author ID):').'</label> '.
-	form::field('new_auth_id',20,255);
-	
-	echo
-	$fields->getHidden().
-	$core->formNonce().
-	form::hidden(array('action'),'author').
-	'<input type="submit" value="'.__('Save').'" /></p>'.
-	'</form>';
-}
-
-dcPage::close();
 ?>
Index: admin/style/default.css
===================================================================
--- admin/style/default.css	(revision 1873)
+++ admin/style/default.css	(revision 1869)
@@ -67,5 +67,5 @@
 	text-align: left;
 	overflow: hidden;
-	padding-top: 16px;
+	padding-top: 22px;
 	}
 .expand-mm {
@@ -272,5 +272,5 @@
 	font-size: 1.2rem;
 	line-height: 1.5;
-	font-family: Arial,"Helvetica Neue",Helvetica,sans-serif;
+	font-family: Arial,Helvetica,sans-serif;
 	color: #333;
 	background: #fff;
@@ -313,5 +313,6 @@
 	color: #D33800;
 	font-weight: normal;
-	font-size: 1.34em;
+	font-size: 16px; /* ie < 9 sucks */
+	font-size: 1.6rem;
 	}
 	#main-menu h3 {
@@ -325,9 +326,11 @@
 	.fieldset h3, .fieldset h4, .pretty-title { /* variante */
 		color: #D33800;
-		font-size: 1em;
+		font-size: 12px;
+		font-size: 1.2rem;
 		font-weight: bold;
 		}
 		.fieldset h3 {
-			font-size: 1.17em;
+			font-size: 14px;
+			font-size: 1.4rem;
 			}
 	.fieldset h3.smart-title, .fieldset h4.smart-title, .smart-title { /* variante */
@@ -598,14 +601,16 @@
 input[type=submit] {
 	border: 1px solid #ccc;
-	font-family: "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif;
+	font-family: arial, helvetica, sans-serif;
 	padding: 4px 10px;
 	line-height: normal !important;
 	display: inline-block;
 	vertical-align: middle;
-	font-size: 100%;
+	font-size: 12px; /* ie < 9 sucks */
+	font-size: 1.2rem;
 	text-align: center;
 	text-decoration: none;
 	border-radius: 3px;
 	cursor: pointer;
+	font: 100% "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif;
 	}
 button,
@@ -766,5 +771,5 @@
 		color: #fff;
 		}
-		.message a, .static-msg a, .message h3, .static-msg h3 {
+		.message a, .static-msg a {
 			color: #fff;
 			}
Index: admin/users_actions.php
===================================================================
--- admin/users_actions.php	(revision 1870)
+++ admin/users_actions.php	(revision 1620)
@@ -287,5 +287,5 @@
 	'<div class="fieldset">'.
 	'<h3>'.__('Validate permissions').'</h3>'.
-	'<p><label for="your_pwd" class="required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label>'.
+	'<p><label for="your_pwd">'.__('Your password:').'</label>'.
 	form::password('your_pwd',20,255).'</p>'.
 	'<p><input type="submit" accesskey="s" value="'.__('Save').'" />'.
Index: inc/admin/actions/class.dcaction.php
===================================================================
--- inc/admin/actions/class.dcaction.php	(revision 1807)
+++ inc/admin/actions/class.dcaction.php	(revision 1807)
@@ -0,0 +1,314 @@
+<?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+if (!defined('DC_RC_PATH')) { return; }
+
+/**
+* dcActionsPage -- handler for action page on selected entries
+*
+*/
+abstract class dcActionsPage
+{
+	/** @var string form submit uri */
+	protected $uri;
+	/** @var dcCore dotclear core instance */
+	protected $core;
+	/** @var array action combo box */
+	protected $combo;
+	/** @var array list of defined actions (callbacks) */
+	protected $actions;
+	/** @var array selected entries (each key is the entry id, value contains the entry description) */
+	protected $entries;
+	/** @var record record that challenges ids against permissions */
+	protected $rs;
+	/** @var array redirection $_GET arguments, if any (does not contain ids by default, ids may be merged to it) */
+	protected $redir_args;
+	/** @var array list of $_POST fields used to build the redirection  */
+	protected $redirect_fields;
+	/** @var string current action, if any */
+	protected $action;
+	/** @var array list of url parameters (usually $_POST) */
+	protected $from;
+	
+	/** @var string title for checkboxes list, if displayed */
+	protected $cb_title;
+	
+    /**
+     * Class constructor
+     * 
+     * @param mixed  $core   dotclear core
+     * @param mixed  $uri   form uri
+     *
+     * @access public
+     *
+     * @return mixed Value.
+     */
+	public function __construct($core,$uri) {
+		$this->core = $core;
+		$this->actions = new ArrayObject();
+		$this->combo = array();
+		$this->uri = $uri;
+		$this->redir_args = array();
+		$this->redirect_fields = array();
+		$this->action = '';
+		$this->cb_title = __('Title');
+		$this->from = new ArrayObject($_POST);
+	}
+	
+    /**
+     * addAction - adds an action
+     *
+     * @param string $actions the actions names as if it was a standalone combo array.
+	 * 						  It will be merged with other actions.
+	 * 						  Can be bound to multiple values, if the same callback is to be called
+     * @param callback $callback the callback for the action.
+     *
+     * @access public
+	 *
+     * @return dcActionsPage the actions page itself, enabling to chain addAction().
+     */
+	public function addAction ($actions,$callback) {
+		foreach ($actions as $k => $a) {
+			// Check each case of combo definition
+			// Store form values in $values
+			if (is_array($a)) {
+				$values = array_values($a);
+				if (!isset($this->combo[$k])) {
+					$this->combo[$k]=array();
+				}
+				$this->combo[$k] = array_merge ($this->combo[$k],$a);
+			} elseif ($a instanceof formSelectOption) {
+				$values = $a->value;
+				$this->combo[$k] = $a->value;
+			} else {
+				$values = $a;
+				$this->combo[$k] = $a;
+			}
+			// Associate each potential value to the callback
+			foreach ($values as $v) {
+				$this->actions[$v]=$callback;
+			}
+		}
+		return $this;
+	}
+	
+    /**
+     * getCombo - returns the actions combo, useable through form::combo
+     *
+     * @access public
+	 *
+     * @return array the actions combo
+     */
+	public function getCombo() {
+		return $this->combo;
+	}
+	
+	
+    /**
+     * getIDS() - returns the list of selected entries
+     *
+     * @access public
+	 *
+     * @return array the list
+     */
+	public function getIDs() {
+		return array_keys($this->entries);
+	}
+	
+    /**
+     * getIDS() - returns the list of selected entries as HTML hidden fields string
+     *
+     * @access public
+	 *
+     * @return string the HTML code for hidden fields
+     */
+	 public function getIDsHidden() {
+		$ret = '';
+		foreach  ($this->entries as $id->$v) {
+			$ret .= form::hidden('entries[]',$id);
+		}
+		return $ret;
+	}
+	
+    /**
+     * getHiddenFields() - returns all redirection parameters as HTML hidden fields
+     *
+     * @param boolean $with_ids if true, also include ids in HTML code
+	 *
+     * @access public
+	 *
+     * @return string the HTML code for hidden fields
+     */	
+	public function getHiddenFields($with_ids = false) {
+		$ret = '';
+		foreach ($this->redir_args as $k => $v) {
+			$ret .= form::hidden(array($k),$v);
+		}
+		if ($with_ids) {
+			$ret .= $this->getIDsHidden();
+		}
+		return $ret;
+	}
+	
+	
+	/**
+     * getRS() - get record from DB Query containing requested IDs
+     *
+     * @param boolean $with_ids if true, also include ids in HTML code
+	 *
+     * @access public
+	 *
+     * @return string the HTML code for hidden fields
+     */
+	public function getRS() {
+		return $this->rs;
+	}
+	
+	/**
+     * setupRedir - setup redirection arguments
+	 *  by default, $_POST fields as defined in redirect_fields attributes
+	 *  are set into redirect_args.
+     *
+     * @param array $from input to parse fields from (usually $_POST)
+	 *
+     * @access protected
+     */
+	protected function setupRedir($from) {
+		foreach ($this->redirect_fields as $p) {
+			if (isset($from[$p])) {
+				$redir_args[$p] = $from[$p];
+			}
+		}
+	}
+
+	/**
+     * getRedirection - returns redirection URL
+     *
+     * @param array $params extra parameters to append to redirection
+	 *						must be an array : each key is the name, 
+	 *						each value is the wanted value
+     * @param boolean $with_selected_entries if true, add selected entries in url
+	 *
+     * @access public
+	 *
+     * @return string the redirection url
+     */
+	public function getRedirection($params=array(),$with_selected_entries=false) {
+		$redir_args = array_merge($params,$this->redir_args);
+		if ($with_selected_entries) {
+			$redir_args['entries'] = array_keys($this->entries);
+		}
+		return $this->uri.'?'.http_build_query($redir_args);
+	}
+
+	/**
+     * redirect - redirects to redirection page
+     *
+	 * @see getRedirection for arguments details
+	 *
+     * @access public
+     */
+	public function redirect($params=array(),$with_selected_entries=false) {
+		http::redirect($this->getRedirection($params,$with_selected_entries));
+	}	
+	
+	/**
+     * getAction - returns current action, if any
+     *
+	 * @see getRedirection for arguments details
+	 *
+     * @access public
+	 *
+     * @return string the action
+     */
+	public function getAction() {
+		return $this->action;
+	}
+
+	/**
+     * process - proceeds action handling, if any
+	 * 			this method may issue an exit() if
+	 *			an action is being processed. If it
+	 *			returns, no action has been performed
+     *
+     * @access public
+     */
+	public function process() {
+
+		$this->setupRedir($this->from);
+		$this->fetchEntries($this->from);	
+		if (isset($this->from['action'])) {
+			$this->action = $this->from['action'];
+			try {
+				$performed=false;
+				foreach ($this->actions as $k=>$v) {
+					if ($this->from['action']==$k) {
+						$performed = true;
+						call_user_func($v,$this->core,$this,$this->from);
+					}
+				}
+				if ($performed) {
+					exit;
+				}
+			} catch (Exception $e) {
+				$this->error($e);
+			}
+		}
+	}
+
+	/**
+     * getcheckboxes -returns html code for selected entries
+	 * 			as a table containing entries checkboxes
+     *
+     * @access public
+	 *
+     * @return string the html code for checkboxes
+     */
+	public function getCheckboxes() {
+		$ret = 
+			'<table class="posts-list"><tr>'.
+			'<th colspan="2">'.$this->cb_title.'</th>'.
+			'</tr>';
+		foreach ($this->entries as $id=>$title) {
+			$ret .= 
+				'<tr><td>'.
+				form::checkbox(array('entries[]'),$id,true,'','').'</td>'.
+				'<td>'.	$title.'</td></tr>';
+		}
+		$ret .= '</table>';
+		return $ret;
+	}
+	
+	/**
+     * beginPage, endPage - displays the beginning/ending of a page, if action does not redirects dirtectly
+     *
+	 * These methods are called from the actions themselves.
+	 *
+     * @param string $breadcrumb breadcrumb to display
+     * @param string $head	page header to include
+	 *
+     * @access public
+     */
+	abstract public function beginPage($breadcrumb='',$head='');
+	abstract public function endPage();
+
+	/**
+     * fetchEntries - fills-in information by requesting into db
+	 * 	this method may setup the following attributes
+	 *   * entries : list of entries (checked against permissions)
+	 *      entries ids are array keys, values contain entry description (if relevant)
+     *   * rs : record given by db request
+     * @access protected
+     */
+	 abstract protected function fetchEntries($from);
+
+}
+
Index: inc/admin/actions/class.dcactionposts.php
===================================================================
--- inc/admin/actions/class.dcactionposts.php	(revision 1808)
+++ inc/admin/actions/class.dcactionposts.php	(revision 1808)
@@ -0,0 +1,358 @@
+<?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+if (!defined('DC_RC_PATH')) { return; }
+
+class dcPostsActionsPage extends dcActionsPage
+{
+	public function __construct($core,$uri) {
+		parent::__construct($core,$uri);
+		$this->redirect_fields = array('user_id','cat_id','status',
+		'selected','month','lang','sortby','order','page','nb');
+		// We could have added a behavior here, but we want default action
+		// to be setup first
+		dcDefaultPostActions::adminPostsActionsPage($core,$this);
+		$core->callBehavior('adminPostsActionsPage',$core,$this);
+
+	}
+
+	public function beginPage($breadcrumb='',$head='') {
+		dcPage::open(
+			__('Entries'),
+			
+			dcPage::jsLoad('js/_posts_actions.js').
+			$head,
+			$breadcrumb
+		);	
+		echo '<p><a class="back" href="'.$this->getRedirection(array(),true).'">'.__('Back to entries list').'</a></p>';
+	}
+	
+	public function endPage() {
+		dcPage::close();
+	}
+	
+	public function error(Exception $e) {
+		$this->core->error->add($e->getMessage());
+		$this->beginPage(dcPage::breadcrumb(
+			array(
+				html::escapeHTML($this->core->blog->name) => '',
+				__('Entries') => 'posts.php',
+				'<span class="page-title">'.__('Entries actions').'</span>' => ''
+			))
+		);
+		$this->endPage();
+	}
+	
+	protected function fetchEntries($from) {
+		if (!empty($from['entries']))
+		{
+			$entries = $from['entries'];
+			
+			foreach ($entries as $k => $v) {
+				$entries[$k] = (integer) $v;
+			}
+			
+			$params['sql'] = 'AND P.post_id IN('.implode(',',$entries).') ';
+			
+			if (!isset($from['full_content']) || empty($from['full_content'])) {
+				$params['no_content'] = true;
+			}
+			
+			if (isset($from['post_type'])) {
+				$params['post_type'] = $from['post_type'];
+			}
+			
+			$posts = $this->core->blog->getPosts($params);
+			while ($posts->fetch())	{
+				$this->entries[$posts->post_id] = $posts->post_title;
+			}
+			$this->rs = $posts;			
+		} else {
+			$this->rs = $this->core->con->select("SELECT blog_id FROM ".$this->core->prefix."blog WHERE false");;
+		}
+	}
+}
+
+class dcDefaultPostActions 
+{
+	public static function adminPostsActionsPage($core, dcPostsActionsPage $ap) {
+		if ($core->auth->check('publish,contentadmin',$core->blog->id)) {
+			$ap->addAction(
+				array(__('Status') => array(
+					__('Publish') => 'publish',
+					__('Unpublish') => 'unpublish',
+					__('Schedule') => 'schedule',
+					__('Mark as pending') => 'pending'
+				)),
+				array('dcDefaultPostActions','doChangePostStatus')
+			);
+		}
+		$ap->addAction(
+			array(__('Mark')=> array(
+				__('Mark as selected') => 'selected',
+				__('Mark as unselected') => 'unselected'
+			)),
+			array('dcDefaultPostActions','doUpdateSelectedPost')
+		);
+		$ap->addAction(
+			array(__('Change') => array(
+				__('Change category') => 'category',
+			)),
+			array('dcDefaultPostActions','doChangePostCategory')
+		);
+		$ap->addAction(
+			array(__('Change') => array(
+				__('Change language') => 'lang',
+			)),
+			array('dcDefaultPostActions','doChangePostLang')
+		);
+		if ($core->auth->check('admin',$core->blog->id))
+		{
+			$ap->addAction(
+				array(__('Change') => array(
+					__('Change author') => 'author')),
+				array('dcDefaultPostActions','doChangePostAuthor')
+			);
+		}
+		if ($core->auth->check('delete,contentadmin',$core->blog->id)) {
+			$ap->addAction(
+				array(__('Delete') => array(
+					__('Delete') => 'delete')),
+				array('dcDefaultPostActions','doDeletePost')
+			);
+		}
+	}
+
+	public static function doChangePostStatus($core, dcPostsActionsPage $ap, $post) {
+		switch ($ap->getAction()) {
+			case 'unpublish' : $status = 0; break;
+			case 'schedule' : $status = -1; break;
+			case 'pending' : $status = -2; break;
+			default : $status = 1; break;
+		}
+		$posts_ids = $ap->getIDs();
+		if (empty($posts_ids)) {
+			throw new Exception(__('No entry selected'));
+		}
+		$core->blog->updPostsStatus($posts_ids,$status);
+		
+		$ap->redirect(array('upd' => 1),true);
+	}
+	
+	public static function doUpdateSelectedPost($core, dcPostsActionsPage $ap, $post) {
+		$posts_ids = $ap->getIDs();
+		if (empty($posts_ids)) {
+			throw new Exception(__('No entry selected'));
+		}
+		$action = $ap->getAction();
+		$core->blog->updPostsSelected($posts_ids,$action == 'selected');
+		
+		$ap->redirect(array('upd' => 1),true);
+	}
+	
+	public static function doDeletePost($core, dcPostsActionsPage $ap, $post) {
+
+		$posts_ids = $ap->getIDs();
+		if (empty($posts_ids)) {
+			throw new Exception(__('No entry selected'));
+		}
+		// Backward compatibility
+		foreach($posts_ids as $post_id)
+		{
+			# --BEHAVIOR-- adminBeforePostDelete
+			$core->callBehavior('adminBeforePostDelete',(integer) $post_id);
+		}
+		
+		# --BEHAVIOR-- adminBeforePostsDelete
+		$core->callBehavior('adminBeforePostsDelete',$posts_ids);
+		
+		$core->blog->delPosts($posts_ids);
+		
+		$ap->redirect(array('del',1),false);
+	}
+
+	public static function doChangePostCategory($core, dcPostsActionsPage $ap, $post) {
+		if (isset($post['new_cat_id'])) {
+			$posts_ids = $ap->getIDs();
+			if (empty($posts_ids)) {
+				throw new Exception(__('No entry selected'));
+			}
+			$new_cat_id = $post['new_cat_id'];
+			if (!empty($post['new_cat_title']) && $core->auth->check('categories', $core->blog->id))
+			{
+				$cur_cat = $core->con->openCursor($core->prefix.'category');
+				$cur_cat->cat_title = $post['new_cat_title'];
+				$cur_cat->cat_url = '';
+				
+				$parent_cat = !empty($post['new_cat_parent']) ? $post['new_cat_parent'] : '';
+				
+				# --BEHAVIOR-- adminBeforeCategoryCreate
+				$core->callBehavior('adminBeforeCategoryCreate', $cur_cat);
+				
+				$new_cat_id = $core->blog->addCategory($cur_cat, (integer) $parent_cat);
+				
+				# --BEHAVIOR-- adminAfterCategoryCreate
+				$core->callBehavior('adminAfterCategoryCreate', $cur_cat, $new_cat_id);
+			}
+			
+			$core->blog->updPostsCategory($posts_ids, $new_cat_id);
+			
+			$ap->redirect(array('upd'=>1),true);
+		} else {
+			$ap->beginPage(
+				dcPage::breadcrumb(
+					array(
+						html::escapeHTML($core->blog->name) => '',
+						__('Entries') => 'posts.php',
+						'<span class="page-title">'.__('Change category for entries').'</span>' => ''
+			)));
+			
+			# categories list
+			# Getting categories
+			$categories_combo = dcAdminCombos::getCategoriesCombo(
+				$core->blog->getCategories(array('post_type'=>'post'))
+			);			
+			echo
+			'<form action="posts.php" method="post">'.
+			$ap->getCheckboxes().
+			'<p><label for="new_cat_id" class="classic">'.__('Category:').'</label> '.
+			form::combo('new_cat_id',$categories_combo,'');
+			
+			if ($core->auth->check('categories', $core->blog->id)) {
+				echo 
+				'<div>'.
+				'<p id="new_cat">'.__('Create a new category for the post(s)').'</p>'.
+				'<p><label for="new_cat_title">'.__('Title:').'</label> '.
+				form::field('new_cat_title',30,255,'','').'</p>'.
+				'<p><label for="new_cat_parent">'.__('Parent:').'</label> '.
+				form::combo('new_cat_parent',$categories_combo,'','').
+				'</p>'.
+				'</div>';
+			}
+			
+			echo
+			$core->formNonce().
+			form::hidden(array('action'),'category').
+			'<input type="submit" value="'.__('Save').'" /></p>'.
+			'</form>';
+			$ap->endPage();
+
+		}
+	
+	}
+	public static function doChangePostAuthor($core, dcPostsActionsPage $ap, $post) {
+		if (isset($post['new_auth_id']) && $core->auth->check('admin',$core->blog->id)) {
+			$new_user_id = $post['new_auth_id'];
+			$posts_ids = $ap->getIDs();
+			if (empty($posts_ids)) {
+				throw new Exception(__('No entry selected'));
+			}
+			if ($core->getUser($new_user_id)->isEmpty()) {
+				throw new Exception(__('This user does not exist'));
+			}
+			
+			$cur = $core->con->openCursor($core->prefix.'post');
+			$cur->user_id = $new_user_id;
+			$cur->update('WHERE post_id '.$core->con->in($posts_ids));
+			
+			$ap->redirect(array('upd' => 1),true);
+		} else {
+			$usersList = '';
+			if ($core->auth->check('admin',$core->blog->id)) {
+				$params = array(
+					'limit' => 100,
+					'order' => 'nb_post DESC'
+					);
+				$rs = $core->getUsers($params);
+				while ($rs->fetch())
+				{
+					$usersList .= ($usersList != '' ? ',' : '').'"'.$rs->user_id.'"';
+				}
+			}
+			$ap->beginPage(
+				dcPage::breadcrumb(
+					array(
+						html::escapeHTML($core->blog->name) => '',
+						__('Entries') => 'posts.php',
+						'<span class="page-title">'.__('Change author for entries').'</span>' => '')),
+					dcPage::jsLoad('js/jquery/jquery.autocomplete.js').
+					'<script type="text/javascript">'."\n".
+					"//<![CDATA[\n".
+					'usersList = ['.$usersList.']'."\n".
+					"\n//]]>\n".
+					"</script>\n"
+			);
+
+			echo
+			'<form action="posts_actions.php" method="post">'.
+			$ap->getCheckboxes().
+			'<p><label for="new_auth_id" class="classic">'.__('New author (author ID):').'</label> '.
+			form::field('new_auth_id',20,255);
+			
+			echo
+				$core->formNonce().
+				form::hidden(array('action'),'author').
+				'<input type="submit" value="'.__('Save').'" /></p>'.
+				'</form>';
+			$ap->endPage();
+		}
+	}
+	public static function doChangePostLang($core, dcPostsActionsPage $ap, $post) {
+		$posts_ids = $ap->getIDs();
+		if (empty($posts_ids)) {
+			throw new Exception(__('No entry selected'));
+		}
+		if (isset($post['new_lang'])) {
+			$new_lang = $post['new_lang'];
+			$cur = $core->con->openCursor($core->prefix.'post');
+			$cur->post_lang = $new_lang;
+			$cur->update('WHERE post_id '.$core->con->in($posts_ids));
+			
+			$ap->redirect(array('upd' => 1),true);
+		} else {
+			$ap->beginPage(
+				dcPage::breadcrumb(
+					array(
+						html::escapeHTML($core->blog->name) => '',
+						__('Entries') => 'posts.php',
+						'<span class="page-title">'.__('Change language for entries').'</span>' => ''
+			)));
+			# lang list
+			# Languages combo
+			$rs = $core->blog->getLangs(array('order'=>'asc'));
+			$all_langs = l10n::getISOcodes(0,1);
+			$lang_combo = array('' => '', __('Most used') => array(), __('Available') => l10n::getISOcodes(1,1));
+			while ($rs->fetch()) {
+				if (isset($all_langs[$rs->post_lang])) {
+					$lang_combo[__('Most used')][$all_langs[$rs->post_lang]] = $rs->post_lang;
+					unset($lang_combo[__('Available')][$all_langs[$rs->post_lang]]);
+				} else {
+					$lang_combo[__('Most used')][$rs->post_lang] = $rs->post_lang;
+				}
+			}
+			unset($all_langs);
+			unset($rs);
+			
+			echo
+			'<form action="posts_actions.php" method="post">'.
+			$ap->getCheckboxes().
+			
+			'<p><label for="new_lang" class="classic">'.__('Entry lang:').'</label> '.
+			form::combo('new_lang',$lang_combo,'');
+			
+			echo
+				$core->formNonce().
+				form::hidden(array('action'),'lang').
+				'<input type="submit" value="'.__('Save').'" /></p>'.
+				'</form>';
+		}
+	}
+}
Index: inc/prepend.php
===================================================================
--- inc/prepend.php	(revision 1719)
+++ inc/prepend.php	(revision 1806)
@@ -64,4 +64,6 @@
 $__autoload['context']				= dirname(__FILE__).'/public/lib.tpl.context.php';
 $__autoload['dcUrlHandlers']			= dirname(__FILE__).'/public/lib.urlhandlers.php';
+$__autoload['dcPostsActionsPage']			= dirname(__FILE__).'/admin/actions/class.dcactionposts.php';
+$__autoload['dcActionsPage']			= dirname(__FILE__).'/admin/actions/class.dcaction.php';
 
 # Clearbricks extensions
Index: locales/fr/help/index.html
===================================================================
--- locales/fr/help/index.html	(revision 1873)
+++ locales/fr/help/index.html	(revision 1869)
@@ -8,41 +8,25 @@
 <div class="multi-part legible" id="first-step" title="Premiers pas">
 	<h3>Découverte de l'interface</h3>
-	<div class="fieldset">
-		<h4>Aides contextuelles</h4>
-		<p>Outre les présentes pages d'aide générale, de nombreuses pages de l'administration disposent d'une aide contextuelle. Si javascript est disponible sur votre navigateur, elle se présente sur le côté de la page après avoir cliqué sur le lien <img src="images/menu/help.png" alt="" /> <strong>Besoin d'aide&nbsp;?</strong> (en haut à droite) ; si javascript n'est pas activé elle s'affiche en bas de la page concernée.</p>
-	</div>
+	<h4 class="pretty-title">Aides contextuelles</h4>
+	<p>Outre les présentes pages d'aide générale, de nombreuses pages de l'administration disposent d'une aide contextuelle. Si javascript est disponible sur votre navigateur, elle se présente sur le côté de la page après avoir cliqué sur le lien <img src="images/menu/help.png" alt="" /> <strong>Aide pour cette page</strong> (en haut à droite) ; si javascript n'est pas activé elle s'affiche en bas de la page concernée.</p>
 
-	<p>Sur chaque page de l'administration, vous retrouverez les mêmes bandeau haut, menu principal et pied de page. <em>(Les emplacements de chacun de ces éléments sont indiqués ici pour une consultation sur ordinateur&nbsp;; sur un mobile ou une tablette, leur emplacement varie selon la place disponible.)</em></p>
+	<h4 class="pretty-title">Réglages personnels</h4>
+	<p>Le lien vers les réglages de <a href="preferences.php">vos préférences</a> est disponible en haut de toutes les pages d'administration.</p>
+	<p><strong>Mon tableau de bord.</strong> Le tableau de bord est l'accueil de votre interface d'administration. Les grandes icônes de la partie centrale permettent un accès rapide aux pages favorites de l'administration. Sous ces icônes, figurent des modules d'information. Lors de votre première installation, les deux modules proposés sont les dernières nouvelles de Dotclear et des liens vers la documentation et le support. Pour organiser vos favoris et vos modules, allez sur l'onglet «&nbsp;Mon tableau de bord&nbsp;».</p>
+	<p><strong>Mon profil.</strong> Les deux autres onglets de la page Mes préférences permettent de modifier ou compléter vos informations personnelles.</p>
+	<p class="info"><strong>Astuce.</strong> Si le thème que vous utilisez le prévoit (c'est le cas de la plupart d'entre eux), indiquez la même <em>URL du blog</em> dans votre page de profil et dans le formulaire de commentaire sur votre blog pour obtenir une mise en valeur de vos propres commentaires.</p>
+	<p><strong>Mes options</strong>. Activez ou désactivez des fonctionnalités selon vos goûts ou votre contexte de navigation.</p>
 
-	<h4 class="pretty-title">Bandeau haut</h4>
-	<p>Le bandeau en haut de chaque page est composé de trois éléments :</p>
-	<h5>Le logo</h5>
-	<p>Par défaut, ce logo est celui de Dotclear et son lien conduit vers l'accueil de l'administration. Toutefois, un gestionnaire de plate-forme peut choisir un autre logo et diriger le lien vers autre chose que l'accueil (en général la page d'accueil du service).</p>
+	<h4 class="pretty-title">Réglages du blog</h4>
+	<p><strong>Paramètres du blog</strong> (section «&nbsp;Blog&nbsp;» du menu). C'est ici que vous pouvez notamment changer le nom du blog, ajuster le fuseau horaire du blog, décider de la présentation des dates…</p>
 
-	<h5>« Blog(s) »</h5>
-	<p>Le premier élément situé après le logo indique le bloc dit <em>actif</em>, c'est-à-dire celui sur lequel vous êtes en train d'agir. Si vous avez plusieurs blogs sur la même installation, cette information figure dans un menu déroulant qui permet de permuter sur un autre blog.</p>
-	<p>Le lien suivant le nom du blog permet d'aller voir le blog dans une autre fenêtre ou un autre onglet.</p>
+	<p><strong>Apparence du blog.</strong> Sélectionnez l'habillage (le <em>thème</em>) du blog. Certains thèmes offrent un configurateur de personnalisation. C'est le cas par exemple de Ductile ou Blowup. Dans ce cas, une fois le thème activé, cliquez sur le bouton "Configurer le thème" pour accéder à ses réglages. Outre les thèmes disponibles lors de l'installation, vous pouvez ajouter d'autres thèmes depuis l'onglet «&nbsp;Ajouter un thème&nbsp;» de cette page. </p>
 
-	<h5>Utilisateur</h5>
-	<p>À l'extrême droite du bandeau haut, le lien <em>Mon tableau de bord</em> permet de revenir à l'accueil du blog.</p>
-	<p>Le lien suivant, <em>Mes préférences</em> dirige vers la page où vous pourrez modifier vos informations personnelles, configurer votre tableau de bord et choisir vos options d'interface et d'édition.</p>
-	<p>Étonnamment, le lien <em>Déconnecter [votre login]</em> permet de… se déconnecter, si si. (Chez Dotclear, on est trop forts en ergo.)</p>
+	<p><strong>Menu simple.</strong> Si le thème de votre blog a prévu son intégration, le menu principal du blog peut être renseigné sur cette page. Dans la plupart des thèmes il se présente sous forme d'une barre latérale sous l'entête du blog, comme sur Ductile par exemple.</p>
 
-	<h4 class="pretty-title">Menu principal</h4>
-	<p>Le menu principal est situé à gauche de l'écran. Il peut être rétracté en cliquant sur sa bordure droite (puis déployé en cliquant sur cette même bordure).</p>
-	<p>Il conduit vers les différentes pages d'administration correspondant à vos permissions sur le blog actif. Quatre blocs le composent&nbsp;</p>
-	<ul class="nice">
-		<li><strong>Mes Favoris</strong> liste les pages que vous avez désignées comme telles dans l'onglet <em>Mon tableau de bord</em> de <em>Mes préférences</em>. Si vous n'avez encore choisi aucun favori, cette liste correspond au set par défaut de Dotclear ou celui du gestionnaire de la plate-forme. Si vous ne souhaitez pas afficher ce bloc, décochez la case correspondante dans vos options de tableau de bord.</li>
-		<li><strong>Blog</strong> regroupe la liste de toutes les pages permettant l'alimentation et les réglages du blog actif, de la rédaction d'un article à la gestion de la médiathèque en passant par le choix de la présentation et autres paramétrages.<br />
-		<em>Si vous ne possédez pas de droits d'administration sur le blog actif, il n'y a pas d'autre bloc après celui-ci dans le menu principal.</em></li>
-		<li><strong>Réglages système</strong> offre l'accès aux pages permettant d'administrer l'installation Dotclear : gestion des blogs, utilisateurs et langues disponibles, installation d'extensions, réglages système. Si vous possédez des droits sur plusieurs blogs mais ne disposez pas du statut de super administrateur, il est constitué du seul item <em>Blogs</em>.</li>
-		<li><strong>Plugins</strong> permet d'effectuer les paramétrages des plugins installés. Si les réglages d'un plugin n'impactent qu'un blog à la fois, sa page d'administration est disponible depuis le bloc <em>Blog</em>, mais si les réglages ont des répercussions sur toutes les pages de l'installation ils figurent ici et ne sont accessibles qu'aux utilisateurs disposant des droits de super admin.</li>
-	</ul>
+	<p><strong>Widgets de présentation.</strong> Le menu du blog (souvent une barre latérale à droite ou à gauche du contenu principal) rassemble les widgets enregistrés sur cette page. Après avoir glissé le ou les widgets de votre choix dans leur zone d'accueil, vous pouvez les ouvrir en cliquant sur le triangle et compléter les champs et options.</p>
 
-	<h4 class="pretty-title">Pied de page</h4>
-	<p>Une version gratuite de Dotclear est offerte à tout utilisateur découvrant le secret du pied de page.</p>
-
-	<h3>Aide aux grands débutants</h3>
-	<p>Si vous n'êtes pas familier avec l'univers des blogs, nous vous recommandons notre documentation (sommaire complet dans les onglets Documentation de cette page) ainsi que les tutoriels qui vous sont spécialement dédiés sur le blog <a href="http://abc.dotaddict.org">abc Dotclear</a>. Par exemple&nbsp;:</p>
+	<h4 class="pretty-title">Aide aux grands débutants</h4>
+	<p>Si vous n'êtes pas familier avec l'univers des blogs, nous vous recommandons notre documentation (sommaire complet dans l'onglet Documentation de cette page) et les tutoriels qui vous sont spécialement dédiés sur le blog <a href="http://abc.dotaddict.org">abc Dotclear</a>. Vous serez peut-être intéressés par exemple par :</p>
 	<ul>
 		<li><a href="http://fr.dotclear.org/documentation/2.0/usage/beginners">Mon premier billet pas à pas</a></li>
@@ -50,49 +34,31 @@
 		<li><a href="http://abc.dotaddict.org/post/1970/01/01/Choisir-un-theme">Choisir un thème</a></li>
 	</ul>
-	<p>Le <a href="http://forum.dotclear.net/">forum</a> est un lieu d'entraide convivial où aucune question n'est considérée comme stupide. N'hésitez pas à y participer pour demander de l'aide et – pourquoi pas – aider d'autres utilisateurs à votre tour.</p>
-	<p class="info">Nous nous efforçons d'utiliser un vocabulaire compréhensible sans connaissances préalables. Toutefois si nous nous sommes laissés aller à employer un terme de jargon, vous en trouverez sans doute l'explication dans le <a href="http://fr.dotclear.org/documentation/glossary">glossaire</a> de notre documentation en ligne.</p>
 </div>
 
-<div class="multi-part" id="users-doc" title="Documentation utilisateurs">
-	<h3>Documentation pour les utilisateurs</h3>
+<div class="multi-part" id="doc" title="Documentation et tutoriels">
+	<h3>Documentation et tutoriels en ligne</h3>
 	<div class="three-boxes first-child">
-		<h4 class="pretty-title">Alimentation du blog</h4>
-			<ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/entries">Billets</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/entries#creation-et-edition">Création et édition</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/entries#informations-du-billet">Informations du billet</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/entries#actions-sur-le-billet">Actions sur le billet</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/entries#commentaires-et-retroliens-d-un-billet">Commentaires et rétroliens d&#039;un billet</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/entries#traitement-par-lots-des-billets">Traitement par lots des billets</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/comments-trackbacks">Commentaires et rétroliens</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/comments-trackbacks#suivi">Suivi</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/comments-trackbacks#gestion">Gestion</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/categories">Catégories</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/categories#creer-une-categorie">Créer une catégorie</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/categories#editer-une-categorie">Éditer une catégorie</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/categories#supprimer-une-categorie">Supprimer une catégorie</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/categories#ordonner-la-liste-des-categories">Ordonner la liste des catégories</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/tags">Mots-clés (Tags)</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/tags#ajouter-des-mots-cles">Ajouter des mots-clés</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/tags#gestion-des-mots-cles">Gestion des mots-clés</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/tags#supprimer-des-mots-cles">Supprimer des mots-clés</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media">Médias et pièces jointes</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#creer-un-sous-repertoire">Créer un sous-répertoire</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#ajouter-des-fichiers">Ajouter des fichiers</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#telecharger-une-archive-zip-du-dossier-courant">Télécharger une archive zip du dossier courant</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#modifier-ou-completer-les-informations-d-un-fichier">Modifier ou compléter les informations d&#039;un fichier</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#ajout-direct-de-fichiers">Ajout direct de fichiers</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#types-de-fichier-particuliers">Types de fichier particuliers</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/media#pieces-jointes">Pièces jointes</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/widgets">Contenu du menu du blog (widgets)</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/widgets#bandeau-de-navigation-bandeau-d-extra">Bandeau de navigation, bandeau d&#039;extra</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/widgets#les-widgets-par-defaut">Les widgets par défaut</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/widgets#ajoutersupprimer-un-widget">Ajouter/Supprimer un widget</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/widgets#parametrage-des-widgets">Paramétrage des widgets</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blogroll">Blogroll</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blogroll#liste-des-liens">Liste des liens</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blogroll#ajouter-un-lien">Ajouter un lien</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blogroll#ajouter-une-categorie">Ajouter une catégorie</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blogroll#xfn">XFN</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blogroll#importer-depuis-un-fichier-opml-ou-xbel">Importer depuis un fichier OPML ou XBEL</a></li></ul></li></ul>
+		<h4>Alimentation du blog</h4>
+			<ul><li><a href="/documentation/2.0/usage/entries">Billets</a><ul><li><a href="/documentation/2.0/usage/entries#creation-et-edition">Création et édition</a></li><li><a href="/documentation/2.0/usage/entries#informations-du-billet">Informations du billet</a></li><li><a href="/documentation/2.0/usage/entries#actions-sur-le-billet">Actions sur le billet</a></li><li><a href="/documentation/2.0/usage/entries#commentaires-et-retroliens-d-un-billet">Commentaires et rétroliens d&#039;un billet</a></li><li><a href="/documentation/2.0/usage/entries#traitement-par-lots-des-billets">Traitement par lots des billets</a></li></ul></li><li><a href="/documentation/2.0/usage/comments-trackbacks">Commentaires et rétroliens</a><ul><li><a href="/documentation/2.0/usage/comments-trackbacks#suivi">Suivi</a></li><li><a href="/documentation/2.0/usage/comments-trackbacks#gestion">Gestion</a></li></ul></li><li><a href="/documentation/2.0/usage/categories">Catégories</a><ul><li><a href="/documentation/2.0/usage/categories#creer-une-categorie">Créer une catégorie</a></li><li><a href="/documentation/2.0/usage/categories#editer-une-categorie">Éditer une catégorie</a></li><li><a href="/documentation/2.0/usage/categories#supprimer-une-categorie">Supprimer une catégorie</a></li><li><a href="/documentation/2.0/usage/categories#ordonner-la-liste-des-categories">Ordonner la liste des catégories</a></li></ul></li><li><a href="/documentation/2.0/usage/tags">Mots-clés (Tags)</a><ul><li><a href="/documentation/2.0/usage/tags#ajouter-des-mots-cles">Ajouter des mots-clés</a></li><li><a href="/documentation/2.0/usage/tags#gestion-des-mots-cles">Gestion des mots-clés</a></li><li><a href="/documentation/2.0/usage/tags#supprimer-des-mots-cles">Supprimer des mots-clés</a></li></ul></li><li><a href="/documentation/2.0/usage/media">Médias et pièces jointes</a><ul><li><a href="/documentation/2.0/usage/media#creer-un-sous-repertoire">Créer un sous-répertoire</a></li><li><a href="/documentation/2.0/usage/media#ajouter-des-fichiers">Ajouter des fichiers</a></li><li><a href="/documentation/2.0/usage/media#telecharger-une-archive-zip-du-dossier-courant">Télécharger une archive zip du dossier courant</a></li><li><a href="/documentation/2.0/usage/media#modifier-ou-completer-les-informations-d-un-fichier">Modifier ou compléter les informations d&#039;un fichier</a></li><li><a href="/documentation/2.0/usage/media#ajout-direct-de-fichiers">Ajout direct de fichiers</a></li><li><a href="/documentation/2.0/usage/media#types-de-fichier-particuliers">Types de fichier particuliers</a></li><li><a href="/documentation/2.0/usage/media#pieces-jointes">Pièces jointes</a></li></ul></li><li><a href="/documentation/2.0/usage/widgets">Contenu du menu du blog (widgets)</a><ul><li><a href="/documentation/2.0/usage/widgets#bandeau-de-navigation-bandeau-d-extra">Bandeau de navigation, bandeau d&#039;extra</a></li><li><a href="/documentation/2.0/usage/widgets#les-widgets-par-defaut">Les widgets par défaut</a></li><li><a href="/documentation/2.0/usage/widgets#ajoutersupprimer-un-widget">Ajouter/Supprimer un widget</a></li><li><a href="/documentation/2.0/usage/widgets#parametrage-des-widgets">Paramétrage des widgets</a></li></ul></li><li><a href="/documentation/2.0/usage/blogroll">Blogroll</a><ul><li><a href="/documentation/2.0/usage/blogroll#liste-des-liens">Liste des liens</a></li><li><a href="/documentation/2.0/usage/blogroll#ajouter-un-lien">Ajouter un lien</a></li><li><a href="/documentation/2.0/usage/blogroll#ajouter-une-categorie">Ajouter une catégorie</a></li><li><a href="/documentation/2.0/usage/blogroll#xfn">XFN</a></li><li><a href="/documentation/2.0/usage/blogroll#importer-depuis-un-fichier-opml-ou-xbel">Importer depuis un fichier OPML ou XBEL</a></li></ul></li></ul>
 	</div>
 	<div class="three-boxes">
-		<h4 class="pretty-title">Paramétrage et personnalisations</h4>
-			<ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters" title="2.0:usage:blog-parameters">Paramètres du blog</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#informations-du-blog">Informations du blog</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#configuration-du-blog">Configuration du blog</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#commentaires-et-retroliens">Commentaires et rétroliens</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#presentation-du-blog">Présentation du blog</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#medias-et-images">Médias et images</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#parametres-d-indexation">Paramètres d&#039;indexation</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#antispam">Antispam</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#lightbox">LightBox</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#enregistrer">Enregistrer</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters#configuration-avancee">Configuration avancée</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/user-preferences">Mes préférences</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/user-preferences#mon-profil">Mon profil</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/user-preferences#mes-options">Mes options</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/user-preferences#mes-favoris">Mes favoris</a></li></ul></li><li><a href="http://fr.dotclear.org/documentation/2.0/admin/themes">Apparence du blog</a><ul><li><a href="http://fr.dotclear.org/documentation/2.0/admin/themes#choisir-un-theme">Choisir un thème</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/admin/themes#installer-un-theme">Installer un thème</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/admin/themes#personnaliser-un-theme">Personnaliser un thème</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/admin/themes#editeur-de-theme">Éditeur de thème</a></li></ul></li></ul>
+		<h4>Paramétrage et personnalisations</h4>
+		<h4>Annexes utilisation</h4>
 	</div>
 	<div class="three-boxes last-child">
-		<div class="box fieldset">
-			<h4 class="smart-title">Lectures complémentaires</h4>
-				<h5>Glossaire</h5>
-				<ul><li><a href="http://fr.dotclear.org/documentation/glossary">Tous ces mots mystérieux utilisés dans le web et pour Dotclear</a></li></ul>
-				<h5>Syntaxes de saisie</h5>
-					<ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/syntaxes">Syntaxe wiki et correspondances xhtml</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/syntaxes#aller-plus-loin">Aller plus loin</a></li></ul>
-				<h5>Syndication RSS, Atom</h5>
-					<ul><li><a href="http://fr.dotclear.org/documentation/2.0/usage/feeds">Kesako ?</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/feeds#comment-les-mettre-a-disposition">Comment les mettre à disposition ?</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/feeds#comment-s-abonner">Comment s&#039;abonner ?</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/usage/feeds#en-savoir-plus">En savoir plus</a></li></ul>
-			<h4 class="smart-title">Tutoriels</h4>
-				<ul><li><a href="http://abc.dotaddict.org/archive">abc dotclear</a>, un blog spécialement dédié aux grands débutants.</li>
-				<li><a href="http://tips.dotaddict.org">Tips</a>, des tutoriels pour vous aider à personnaliser votre blog.</li></ul>
-			<h4 class="smart-title">Entraide</h4>
-			<ul><li><a href="http://forum.dotclear.net">Le forum de Dotclear</a></li><li><a href="http://fr.dotclear.org/documentation/2.0/faq#utilisation">Les questions fréquentes</a></li></ul>
-		</div>
+		<h4>Administration, gestion et maintenance</h4>
 	</div>
 </div>
 
-	<div class="multi-part" id="admin-doc" title="Documentation administrateurs">
-	<h3>Documentation pour les administrateurs</h3>
+	<div class="multi-part" id="a11y-ergo" title="Accessibilité et ergonomie">
+	<h3>Accessibilité et ergonomie</h3>
 	</div>
 
-	<div class="multi-part" id="guide-dev" title="Documentation développeurs">
-	<h3>Documentation et ressources pour les développeurs</h3>
+	<div class="multi-part" id="guide-dev" title="Pour les développeurs">
+	<h3>Développeurs : charte de l'administration</h3>
 	<ul>
 		<li><a href="_charte.php">Charte des pages de l'administration</a></li>
 	</ul>
 	</div>
-	<div class="multi-part" id="a11y-ergo" title="Accessibilité et ergonomie">
-	<h3>Accessibilité et ergonomie</h3>
-	</div>
 
 </body>
Index: plugins/dclegacy/_admin.php
===================================================================
--- plugins/dclegacy/_admin.php	(revision 1806)
+++ plugins/dclegacy/_admin.php	(revision 1806)
@@ -0,0 +1,42 @@
+<?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+if (!defined('DC_CONTEXT_ADMIN')) { return; }
+
+$GLOBALS['core']->addBehavior('adminPostsActionsPage',array('dcLegacyPosts','adminPostsActionsPage'));
+
+/* Handle deprecated behaviors : 
+    * adminPostsActionsCombo
+	* adminPostsActionsHeaders
+	* adminPostsActionsContent
+*/
+class dcLegacyPosts
+{
+	public static function adminPostsActionsPage($core, dcPostsActionsPage $as) {
+		$stub_actions = new ArrayObject();
+		$core->callBehavior('adminPostsActionsCombo',array($stub_actions));
+		if (!empty($stub_actions)) {
+			$as->addAction($stub_actions,array('dcLegacyPosts','onActionLegacy'));
+		}
+	}
+	
+	public static function onActionLegacy($core, dcPostsActionsPage $as, $post) {
+		$core->callBehavior('adminPostsActions',$core,$as->getRS(),$as->getAction(),$as->getRedirection());
+		$as->beginPage('',
+			dcPage::jsLoad('js/jquery/jquery.autocomplete.js').
+			dcPage::jsMetaEditor().
+			$core->callBehavior('adminPostsActionsHeaders'),'');
+		$core->callBehavior('adminPostsActionsContent',$core,$as->getAction(),$as->getHiddenFields(true));
+		$as->endPage();
+	
+	}
+}
+?>
Index: plugins/dclegacy/_define.php
===================================================================
--- plugins/dclegacy/_define.php	(revision 1806)
+++ plugins/dclegacy/_define.php	(revision 1806)
@@ -0,0 +1,23 @@
+<?php
+# -- BEGIN LICENSE BLOCK ---------------------------------------
+#
+# This file is part of Dotclear 2.
+#
+# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
+# Licensed under the GPL version 2.0 license.
+# See LICENSE file or
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+#
+# -- END LICENSE BLOCK -----------------------------------------
+if (!defined('DC_RC_PATH')) { return; }
+
+$this->registerModule(
+	/* Name */			"dcLegacy",
+	/* Description*/		"Legacy modules for dotclear",
+	/* Author */			"dc Team",
+	/* Version */			'1.0',
+	array(
+		'priority' =>		500
+	)
+);
+?>
Index: plugins/tags/_admin.php
===================================================================
--- plugins/tags/_admin.php	(revision 1844)
+++ plugins/tags/_admin.php	(revision 1874)
@@ -236,9 +236,9 @@
 			)).
 			'<form action="'.$form_uri.'" method="post">'.
-			$hidden_fields->getEntries().
+			//$hidden_fields->getEntries().
 			'<div><label for="new_tags" class="area">'.__('Tags to add:').'</label> '.
 			form::textarea('new_tags',60,3).
 			'</div>'.
-			$hidden_fields->getHidden().
+			$hidden_fields.
 			$core->formNonce().
 			form::hidden(array('action'),'tags').
Index: plugins/tags/js/post.js
===================================================================
--- plugins/tags/js/post.js	(revision 1871)
+++ plugins/tags/js/post.js	(revision 1753)
@@ -61,5 +61,5 @@
 	$('h5 .s-tags').toggleWithLegend($('.s-tags').not('label'),{
 		user_pref: 'post_tags',
-		legend_click: true
+		legend_clik: true
 	});
 
