Index: plugins/aboutConfig/admtpl/index.html.twig
===================================================================
--- plugins/aboutConfig/admtpl/index.html.twig	(revision 1070)
+++ plugins/aboutConfig/admtpl/index.html.twig	(revision 1089)
@@ -42,5 +42,5 @@
 	</tbody></table>
     {% endfor %}
-	<p>{{ form_field('local_submit') }} </p>
+	<p>{{ form_field('local_submit') }}</p>
     {% endform %}
 	</div>
@@ -75,5 +75,5 @@
 	</tbody></table>
     {% endfor %}
-	<p>{{ form_field('global_submit') }} </p>
+	<p>{{ form_field('global_submit') }}</p>
     {% endform %}
   </div>
Index: plugins/aboutConfig/index.php
===================================================================
--- plugins/aboutConfig/index.php	(revision 1070)
+++ plugins/aboutConfig/index.php	(revision 1089)
@@ -137,11 +137,11 @@
 # Commons
 if (!empty($_GET['upd'])) {
-	$_ctx->setMessage(__('Configuration successfully updated'));
+	$_ctx->setAlert(__('Configuration successfully updated'));
 }
 if (!empty($_GET['upda'])) {
-	$_ctx->setMessage(__('Settings definition successfully updated'));
+	$_ctx->setAlert(__('Settings definition successfully updated'));
 }
 $_ctx->default_tab = !empty($_GET['part']) && $_GET['part'] == 'global' ? 'global' : 'local';
-$_ctx->setPageTitle('about:config');
+$_ctx->fillPageTitle('about:config');
 $core->tpl->display('@aboutConfig/index.html.twig');
 ?>
Index: plugins/aboutConfig/js/aboutConfig.js
===================================================================
--- plugins/aboutConfig/js/aboutConfig.js	(revision 1070)
+++ plugins/aboutConfig/js/aboutConfig.js	(revision 1089)
@@ -1,5 +1,5 @@
 $(function() {
-	$("#global_submit").hide();
-	$("#local_submit").hide();
+	$("#global_nav_submit").hide();
+	$("#local_nav_submit").hide();
 	$("#global_nav").change(function() {
 		window.location = $("#global_nav option:selected").val();
Index: plugins/antispam/_admin.php
===================================================================
--- plugins/antispam/_admin.php	(revision 324)
+++ plugins/antispam/_admin.php	(revision 1052)
@@ -49,8 +49,19 @@
 	$core->addBehavior('adminBlogPreferencesForm',array('antispamBehaviors','adminBlogPreferencesForm'));
 	$core->addBehavior('adminBeforeBlogSettingsUpdate',array('antispamBehaviors','adminBeforeBlogSettingsUpdate'));
+	$core->addBehavior('adminCommentsSpamForm',array('antispamBehaviors','adminCommentsSpamForm'));
 }
 
 class antispamBehaviors
 {
+	public static function adminCommentsSpamForm($core)
+	{
+		$ttl = $core->blog->settings->antispam->antispam_moderation_ttl;
+		if ($ttl != null && $ttl >=0) {
+			echo '<p>'.sprintf(__('All spam comments older than %s day(s) will be automatically deleted.'), $ttl).' '.
+			sprintf(__('You can modify this duration in the %s'),'<a href="blog_pref.php"> '.__('Blog preferences').'</a>').
+			'</p>';
+		}
+	}
+
 	public static function adminBlogPreferencesForm($core,$settings)
 	{
Index: plugins/antispam/antispam.js
===================================================================
--- plugins/antispam/antispam.js	(revision 0)
+++ plugins/antispam/antispam.js	(revision 1052)
@@ -3,4 +3,7 @@
 	$("#filters-list").each(function() {
 		dragsort.makeTableSortable(this,dotclear.sortable.setHandle, dotclear.sortable.saveOrder);
+	});
+	$('form input[type=submit][name=delete_all]').click(function(){
+		return window.confirm(dotclear.msg.confirm_spam_delete);
 	});
 });
Index: plugins/antispam/index.php
===================================================================
--- plugins/antispam/index.php	(revision 907)
+++ plugins/antispam/index.php	(revision 1052)
@@ -100,4 +100,11 @@
 <head>
   <title><?php echo ($filter_gui !== false ? sprintf(__('%s configuration'),$filter->name).' - ' : '').$page_name; ?></title>
+  <script type="text/javascript">
+  //<![CDATA[
+  <?php
+  echo dcPage::jsVar('dotclear.msg.confirm_spam_delete',__('Are you sure you want to delete all spams?'));
+  ?>
+  //]]>
+  </script>
   <?php
   echo
Index: plugins/blogroll/_public.php
===================================================================
--- plugins/blogroll/_public.php	(revision 945)
+++ plugins/blogroll/_public.php	(revision 1063)
@@ -152,8 +152,8 @@
 		
 		return
-		'<div class="links'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="links'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		$links.
-		'</div>';
+		($w->content_only ? '' : '</div>');
 	}
 }
Index: plugins/blogroll/_widgets.php
===================================================================
--- plugins/blogroll/_widgets.php	(revision 954)
+++ plugins/blogroll/_widgets.php	(revision 1063)
@@ -41,4 +41,5 @@
 				)
 		);
+		$w->links->setting('content_only',__('Content only'),0,'check');
 		$w->links->setting('class',__('CSS class:'),'');
 	}
Index: plugins/blowupConfig/index.php
===================================================================
--- plugins/blowupConfig/index.php	(revision 907)
+++ plugins/blowupConfig/index.php	(revision 994)
@@ -431,5 +431,7 @@
 echo
 '<fieldset><legend>'.__('Additional CSS').'</legend>'.
-'<p>'.form::textarea('extra_css',72,5,html::escapeHTML($blowup_user['extra_css']),'maximal','',false,'title="'.__('Additional CSS').'"').'</p>'.
+'<p><label for="extra_css">'.__('Any additional CSS styles (must be written using the CSS syntax):').' '.
+form::textarea('extra_css',72,5,html::escapeHTML($blowup_user['extra_css']),'maximal','',false,'title="'.__('Additional CSS').'"').
+'</label></p>'.
 '</fieldset>';
 
Index: plugins/daInstaller/_admin.php
===================================================================
--- plugins/daInstaller/_admin.php	(revision 1046)
+++ plugins/daInstaller/_admin.php	(revision 1046)
@@ -0,0 +1,58 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+if (!defined('DC_CONTEXT_ADMIN')) { return; }
+
+/**
+ * Callback to add an icon on Dotclear2's dashboard. Trying to do so the "smart way".
+ * If updates are available, let's notify that fact !
+ *
+ */
+function adminDashboardFavs($core,$favs)
+{
+	if ($core->auth->isSuperAdmin())
+	{
+		$id = 'dainstaller';
+		$title = __('DotAddict.org Installer');
+		$link  = 'plugin.php?p=daInstaller';
+		$icon  = 'index.php?pf=daInstaller/icon.png';
+		$icon_big  = 'index.php?pf=daInstaller/icon-big.png';
+		$favs[$id] = new ArrayObject(array($id,$title,$link,$icon,$icon_big,null,null,null));
+	}
+}
+function adminDashboardFavsIcon($core,$name,$icon)
+{
+	if ($name === 'dainstaller') {
+		$daInstaller = new daInstaller($core);
+		if ($daInstaller->check()) {
+			$upd_plugins = $daInstaller->getModules('plugins',true);
+			$upd_themes = $daInstaller->getModules('themes',true);
+			if (
+				(is_array($upd_plugins) && count($upd_plugins)) ||
+				(is_array($upd_themes) && count($upd_themes))
+			) {
+				$icon[0] .= '<br />'.__('Updates are available');
+				$icon[1] .= '&amp;tab=update';
+				$icon[2] = 'index.php?pf=daInstaller/icon-big-update.png';
+			}
+		}
+	}
+}
+
+$core->addBehavior('adminDashboardFavs','adminDashboardFavs');
+$core->addBehavior('adminDashboardFavsIcon','adminDashboardFavsIcon');
+
+$_menu['System']->addItem(
+	__('DotAddict.org Installer'),
+	'plugin.php?p=daInstaller',
+	'index.php?pf=daInstaller/icon.png',
+	preg_match('/plugin.php\?p=daInstaller(&.*)?$/',
+	$_SERVER['REQUEST_URI']),
+	$core->auth->isSuperAdmin()
+);
+
+?>
Index: plugins/daInstaller/_define.php
===================================================================
--- plugins/daInstaller/_define.php	(revision 1046)
+++ plugins/daInstaller/_define.php	(revision 1046)
@@ -0,0 +1,19 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+if (!defined('DC_RC_PATH')) { return; }
+
+$this->registerModule(
+	'daInstaller',
+	'Install and update your extensions live from DotAddict.org',
+	'Tomtom / DotAddict.org',
+	'1.0.3',
+	null,
+	10000
+);
+
+?>
Index: plugins/daInstaller/_install.php
===================================================================
--- plugins/daInstaller/_install.php	(revision 1046)
+++ plugins/daInstaller/_install.php	(revision 1046)
@@ -0,0 +1,50 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+if (!defined('DC_CONTEXT_ADMIN')) { return; }
+
+$m_version = $core->plugins->moduleInfo('daInstaller','version');
+$i_version = $core->getVersion('daInstaller');
+if (version_compare($i_version,$m_version,'>=')) {
+	return;
+}
+
+# Settings compatibility test
+if (!version_compare(DC_VERSION,'2.2-x','<')) {
+	$core->blog->settings->addNamespace('dainstaller');
+	$s = $core->blog->settings->dainstaller;
+}
+else {
+	$core->blog->settings->setNamespace('dainstaller');
+	$s = $core->blog->settings;
+}
+
+# Création du setting
+$s->put(
+	'dainstaller_plugins_xml',
+	'http://update.dotaddict.org/dc2/plugins.xml',
+	'string','Plugins XML feed location',true,true
+);
+$s->put(
+	'dainstaller_themes_xml',
+	'http://update.dotaddict.org/dc2/themes.xml',
+	'string','Themes XML feed location',true,true
+);
+$s->put(
+	'dainstaller_allow_multi_install',
+	false,
+	'boolean','Allow the multi-installation',true,true
+);
+
+$daInstaller = new daInstaller($core);
+$daInstaller->check(true);
+unset($daInstaller);
+
+$core->setVersion('daInstaller',$m_version);
+return true;
+
+?>
Index: plugins/daInstaller/_prepend.php
===================================================================
--- plugins/daInstaller/_prepend.php	(revision 1046)
+++ plugins/daInstaller/_prepend.php	(revision 1046)
@@ -0,0 +1,15 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+
+$__autoload['daInstaller']	 	= dirname(__FILE__).'/inc/class.da.installer.php';
+$__autoload['daModulesReader'] 	= dirname(__FILE__).'/inc/class.da.modules.reader.php';
+$__autoload['daModulesParser'] 	= dirname(__FILE__).'/inc/class.da.modules.parser.php';
+$__autoload['daModulesList']		= dirname(__FILE__).'/inc/lib.da.installer.ui.php';
+$__autoload['daModulesUpdateList']	= dirname(__FILE__).'/inc/lib.da.installer.ui.php';
+
+?>
Index: plugins/daInstaller/inc/class.da.installer.php
===================================================================
--- plugins/daInstaller/inc/class.da.installer.php	(revision 1046)
+++ plugins/daInstaller/inc/class.da.installer.php	(revision 1046)
@@ -0,0 +1,317 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+
+class daInstaller
+{
+	protected $core;
+	
+	# Set via plugin's settings
+	protected $themes_xml;
+	protected $plugins_xml;
+
+	# Raw datas
+	protected $modules;
+	
+	/**
+	 * "Look, Ma ! That's what we call a constructor."
+	 * Nothing more to say about it for now. :-)
+	 *
+	 */
+	public function __construct($core)
+	{
+		$this->core = $core;
+		
+		# Settings compatibility test
+		$s = !version_compare(DC_VERSION,'2.2-x','<') ? $core->blog->settings->dainstaller : $core->blog->settings;
+		$this->themes_xml 	=  $s->dainstaller_themes_xml;
+		$this->plugins_xml 	=  $s->dainstaller_plugins_xml;
+		$this->modules = array(
+			'plugins'	=> array(
+				'new' 	=> array(),
+				'update' 	=> array()
+			),
+			'themes'	=> array(
+				'new' 	=> array(),
+				'update' 	=> array()
+			)
+		);
+	}
+	
+	/**
+	 * Check new/updated plugins availability
+	 * Plugins already installed but marked as disabled will be ignored.
+	 * Results of this method are stored as two subarrays 'new' and 'update' in $modules['plugins'].
+	 *
+	 * @param		boolean	$force	Forces datas refresh if true (default to false)
+	 * 	 	 
+	 * @return	boolean	Reports operatio status :
+	 *					- true if operation was successful,
+	 *					- false otherwise, you may check internal error trace.
+	 *
+	 */
+	protected function checkPlugins($force = false)
+	{
+		if (!$this->plugins_xml) {
+			return false;
+		}
+		if (($parser = daModulesReader::quickParse($this->plugins_xml,DC_TPL_CACHE,$force)) === false) {
+			return false;
+		}
+		
+		$raw_datas = $parser->getModules();
+		
+		uasort($raw_datas,array('self','sort'));
+		
+		# On se débarasse des plugins désactivés.
+		$skipped = array_keys($this->core->plugins->getDisabledModules());
+		foreach ($skipped as $p_id) {
+			if (isset($raw_datas[$p_id])) {
+				unset($raw_datas[$p_id]);
+			}
+		}
+		
+		# On vérifie les mises à jour
+		$updates = array();
+		$current = $this->core->plugins->getModules();
+		foreach ($current as $p_id => $p_infos) {
+			if (isset($raw_datas[$p_id])) {
+				if (self::da_version_compare($raw_datas[$p_id]['version'],$p_infos['version'],'>')) {
+					$updates[$p_id] = $raw_datas[$p_id];
+					$updates[$p_id]['root'] = $p_infos['root'];
+					$updates[$p_id]['root_writable'] = $p_infos['root_writable'];
+					$updates[$p_id]['current_version'] = $p_infos['version'];
+				}
+				unset($raw_datas[$p_id]);
+			}
+		}
+		
+		$this->modules['plugins'] = array(
+			'new'	=> $raw_datas,
+			'update'	=> $updates
+		);
+
+		return true;
+	}
+	
+	/**
+	 * Check new/updated themes availability
+	 * Results of this method are stored as two subarrays 'new' and 'update' in $modules['themes'].
+	 *
+	 * @param		boolean	$force	Forces datas refresh if true (default to false)
+	 * 	 	 
+	 * @return	boolean	Reports operatio status :
+	 *					- true if operation was successful,
+	 *					- false otherwise, you may check internal error trace.
+	 *
+	 */
+	protected function checkThemes($force = false)
+	{
+		if (!$this->themes_xml) {
+			return false;
+		}
+		if (($parser = daModulesReader::quickParse($this->themes_xml,DC_TPL_CACHE,$force)) === false) {
+			return false;
+		}
+		
+		$raw_datas = $parser->getModules();
+		
+		uasort($raw_datas,array('self','sort'));
+		
+		# On vérifie les mises à jour
+		$updates = array();
+		$core_themes = new dcModules($this->core);
+		$core_themes->loadModules($this->core->blog->themes_path,null);
+		$current = $core_themes->getModules();
+		foreach ($current as $p_id => $p_infos) {
+			if (isset($raw_datas[$p_id])) {
+				if (self::da_version_compare($raw_datas[$p_id]['version'],$p_infos['version'],'>')) {
+					$updates[$p_id] = $raw_datas[$p_id];
+					$updates[$p_id]['root'] = $p_infos['root'];
+					$updates[$p_id]['root_writable'] = $p_infos['root_writable'];
+					$updates[$p_id]['current_version'] = $p_infos['version'];
+				}
+				unset($raw_datas[$p_id]);
+			}
+		}
+		
+		$this->modules['themes'] = array(
+			'new'	=> $raw_datas,
+			'update'	=> $updates
+		);
+		
+		return true;
+	}
+	
+	/**
+	 * Get informations about available new//updated themes/plugins.
+	 * Probably the first method to invoke after instanciation.
+	 * 
+	 * @param		boolean	$force	Forces datas refresh if true (default to false)
+	 * @param		boolean	$verbose	Display exceptions when exists (default to false)
+	 * 
+	 * @return	boolean	Returns if the check is completed or not
+	 *
+	 */
+	public function check($force = false, $verbose = false)
+	{
+		$ret = true;
+		
+		try {
+			if (!$this->checkPlugins($force)) {
+				$ret = false;
+			}
+			if (!$this->checkThemes($force)) {
+				$ret = false;
+			}
+		}
+		catch (daModuleParserException $e) {
+			if ($verbose) {
+				$this->core->error->add(sprintf(
+					__('Oops, something went wrong with %s, we are working on it. %s'),
+					sprintf('<a href="%1$s">%2$s</a>','http://dotaddict.org',__('dotaddict.org website')),
+					sprintf('<a href="%1$s">%2$s</a>','http://dotclear.org/donate',__('Wanna help too?'))
+				));
+			}
+			$ret = false;
+		}
+		catch (Exception $e) {
+			# Probablement à compléter.
+			$ret = false;
+		}
+		
+		return $ret;
+	}
+	
+	/**
+	 * Retrieve a specific module list
+	 *
+	 * @param		string	$type	The type of modules wanted ('plugins' or 'themes')
+	 * @param		boolean	$update	Flag to choose between new or updated modules (default to false - new modules list)
+	 *
+	 * @return	mixed 	The matching modules entries as an array, if any. Or a boolean set to false.
+	 *
+	 */
+	public function getModules($type, $update = false)
+	{
+		$type = ($type == 'themes') ? 'themes' : 'plugins';
+		$what = ($update) ? 'update' : 'new';
+		if (isset($this->modules[$type][$what])) {
+			return $this->modules[$type][$what];
+		}
+		return false;
+	}
+	
+	/**
+	 * Search a string in module id, label and description.
+	 * Search is case-insensitive and can be apply to available themes or plugins
+	 *
+	 * @param		string	$search	The search string
+	 * @param		string	$type	The type of targeted modules ('plugins' or 'themes')
+	 *
+	 * @return 	array 	An array of matching modules entries
+	 *
+	 */
+	public function search($search,$type = 'plugins')
+	{
+		$type = ($type == 'themes') ? 'themes' : 'plugins';
+		$result = array();
+		
+		foreach ($this->modules[$type]['new'] as $module)
+		{
+			if ( preg_match('/'.$search.'/i',$module['id']) ||
+				preg_match('/'.$search.'/i',$module['label']) ||
+				preg_match('/'.$search.'/i',$module['desc']))
+			{
+				$result[] = $module;
+			}
+		}
+		return $result;
+	}
+	
+	/**
+	 * Helper method to fetch and install a ZIP package.
+	 *
+	 * @param		string	$url			Source file URL
+	 * @param		string	$dest		Target file destination
+	 * @param		dcModules	$coreModules	Target modules stack
+	 *
+	 * @return	integer	Basic operation status code : 
+	 *					- 1 : everything's all right,
+	 *					- 2 : tempfile couldn't be deleted.
+	 *
+	 */
+	public function processPackage($url,$dest,dcModules $coreModules)
+	{
+		try {
+			$client = netHttp::initClient($url,$path);
+			$client->setUserAgent(self::getUserAgent());
+			$client->useGzip(false);
+			$client->setPersistReferers(false);
+			$client->setOutput($dest);
+			$client->get($path);
+		}
+		catch (Exception $e) {
+			throw new Exception(__('An error occurred while downloading the file.'));
+		}
+		
+		unset($client);
+		$ret_code = dcModules::installPackage($dest,$coreModules);
+		
+		return $ret_code;
+	}
+	
+	/**
+	 * Helper method to get user agent according to DC and daInstaller version
+	 *
+	 * @return	string	daInstaller user agent
+	 *
+	 */
+	public static function getUserAgent()
+	{
+		$m_version = $GLOBALS['core']->plugins->moduleInfo('daInstaller','version');
+		return sprintf('daInstaller/%s (Dotclear/%s)',$m_version,DC_VERSION);
+	}
+	
+	/**
+	 * Helper method to compare correctly version.
+	 *
+	 * @param		string	$v1			Version of first module
+	 * @param		string	$v2			Version of second module
+	 * @param		string	$op			Operator
+	 *
+	 * @return	boolean	True if test of version is correct according to operator
+	 *
+	 */
+	private static function da_version_compare($v1,$v2,$op)
+	{
+		$v1 = preg_replace('!-r(\d+)$!','-p$1',$v1);
+		$v2 = preg_replace('!-r(\d+)$!','-p$1',$v2);
+		return version_compare($v1,$v2,$op);
+	}
+	
+	/**
+	 * Helper method to sort module list.
+	 *
+	 * @param		array	$a			First module
+	 * @param		array	$b			Second module
+	 *
+	 * @return	integer
+	 *
+	 */
+	private static function sort($a,$b)
+	{
+		$c = strtolower($a['id']); 
+		$d = strtolower($b['id']); 
+		if ($c == $d) { 
+			return 0; 
+		} 
+		return ($c < $d) ? -1 : 1; 
+	}
+}
+
+?>
Index: plugins/daInstaller/inc/class.da.modules.parser.php
===================================================================
--- plugins/daInstaller/inc/class.da.modules.parser.php	(revision 1046)
+++ plugins/daInstaller/inc/class.da.modules.parser.php	(revision 1046)
@@ -0,0 +1,81 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2010 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+
+/**
+ * Class daModuleParserException
+ */ 
+class daModuleParserException extends Exception {}
+
+/**
+ * Class daModulesParser
+ */
+class daModulesParser
+{
+	protected $xml;
+	protected $items;
+	
+	public function __construct($data)
+	{
+		if (!is_string($data)) {
+			throw new daModuleParserException(__('Impossible to read data feed'));
+		}
+		
+		$this->xml = simplexml_load_string($data);
+		$this->items = array();
+		
+		if ($this->xml === false) {
+			throw new daModuleParserException(__('Wrong data feed'));
+		}
+		
+		$this->_parse();
+		
+		unset($data);
+		unset($this->xml);
+	}
+	
+	protected function _parse()
+	{
+		if (empty($this->xml->module)) {
+			return;
+		}
+		
+		foreach ($this->xml->module as $i)
+		{
+			$attrs = $i->attributes();
+			
+			$item = array();
+			
+			# DC/DA shared markers
+			$item['id']		= (string) $attrs['id'];
+			$item['file']		= (string) $i->file;
+			$item['label']		= (string) $i->name;
+			$item['version']	= (string) $i->version;
+			$item['author']	= (string) $i->author;
+			$item['desc']		= (string) $i->desc;
+			
+			# DA specific markers
+			$item['dc_min'] 	= (string) $i->children('http://dotaddict.org/da/')->dcmin;
+			$item['details'] 	= (string) $i->children('http://dotaddict.org/da/')->details;
+			/*$item['section'] 	= (string) $i->children('http://dotaddict.org/da/')->section;*/
+			$item['support'] 	= (string) $i->children('http://dotaddict.org/da/')->support;
+			$item['sshot']		= (string) $i->children('http://dotaddict.org/da/')->sshot;
+			
+			# First filter right now
+			if (version_compare(DC_VERSION,$item['dc_min'],'>=')) {
+				$this->items[$item['id']] = $item;
+			}
+		}
+	}
+	
+	public function getModules()
+	{
+		return $this->items;
+	}
+}
+
+?>
Index: plugins/daInstaller/inc/class.da.modules.reader.php
===================================================================
--- plugins/daInstaller/inc/class.da.modules.reader.php	(revision 1046)
+++ plugins/daInstaller/inc/class.da.modules.reader.php	(revision 1046)
@@ -0,0 +1,196 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+
+class daModulesReader extends netHttp
+{
+	protected $user_agent 		= 'DotAddict.org RepoBrowser/0.1';
+	protected $timeout 			= 5;
+	protected $validators 		= null;				///< <b>array</b>	HTTP Cache validators
+	protected $cache_dir 		= null;				///< <b>string</b>	Cache temporary directory
+	protected $cache_file_prefix 	= 'daorg';			///< <b>string</b>	Cache file prefix
+	protected $cache_ttl 		= '-30 minutes';		///< <b>string</b>	Cache TTL
+	protected $force			= false;
+	
+	public function __construct()
+	{
+		parent::__construct('');
+		$this->setUserAgent(daInstaller::getUserAgent());
+	}
+	
+	public function parse($url)
+	{
+		$this->validators = array();
+		if ($this->cache_dir)
+		{
+			return $this->withCache($url);
+		}
+		else
+		{
+			if (!$this->getModulesXML($url)) {
+				return false;
+			}
+			
+			if ($this->getStatus() != '200') {
+				return false;
+			}
+			
+			return new daModulesParser($this->getContent());
+		}
+	}
+	
+	public static function quickParse($url,$cache_dir = null,$force = false)
+	{
+		$parser = new self();
+		if ($cache_dir) {
+			$parser->setCacheDir($cache_dir);
+		}
+		if ($force) {
+			$parser->setForce($force);
+		}
+		
+		return $parser->parse($url);
+	}
+	
+	public function setCacheDir($dir)
+	{
+		$this->cache_dir = null;
+		
+		if (!empty($dir) && is_dir($dir) && is_writeable($dir))
+		{
+			$this->cache_dir = $dir;
+			return true;
+		}
+		
+		return false;
+	}
+	
+	public function setCacheTTL($str)
+	{
+		$str = trim($str);
+		if (!empty($str))
+		{
+			if (substr($str,0,1) != '-') {
+				$str = '-'.$str;
+			}
+			$this->cache_ttl = $str;
+		}
+	}
+	
+	public function setForce($force)
+	{
+		$this->force = $force;
+	}
+	
+	protected function getModulesXML($url)
+	{
+		if (!self::readURL($url,$ssl,$host,$port,$path,$user,$pass)) {
+			return false;
+		}
+		$this->setHost($host,$port);
+		$this->useSSL($ssl);
+		$this->setAuthorization($user,$pass);
+		
+		return $this->get($path);
+	}
+	
+	protected function withCache($url)
+	{
+		$url_md5 = md5($url);
+		$cached_file = sprintf('%s/%s/%s/%s/%s.ser',
+			$this->cache_dir,
+			$this->cache_file_prefix,
+			substr($url_md5,0,2),
+			substr($url_md5,2,2),
+			$url_md5
+		);
+		
+		$may_use_cached = false;
+		
+		if (@file_exists($cached_file) && !$this->force)
+		{
+			$may_use_cached = true;
+			$ts = @filemtime($cached_file);
+			if ($ts > strtotime($this->cache_ttl))
+			{
+				# Direct cache
+				return unserialize(file_get_contents($cached_file));
+			}
+			$this->setValidator('IfModifiedSince', $ts);
+		}
+		
+		if (!$this->getModulesXML($url))
+		{
+			if ($may_use_cached)
+			{
+				# connection failed - fetched from cache
+				return unserialize(file_get_contents($cached_file));
+			}
+			return false;
+		}
+		
+		switch ($this->getStatus())
+		{
+			case '304':
+				@files::touch($cached_file);
+				return unserialize(file_get_contents($cached_file));
+			case '200':
+				if ($modules = new daModulesParser($this->getContent()))
+				{
+					try {
+						files::makeDir(dirname($cached_file),true);
+					} catch (Exception $e) {
+						return $modules;
+					}
+					
+					if (($fp = @fopen($cached_file, 'wb')))
+					{
+						fwrite($fp, serialize($modules));
+						fclose($fp);
+						files::inheritChmod($cached_file);
+					}
+					return $modules;
+				}
+		}
+		
+		return false;
+	}
+	
+	protected function buildRequest()
+	{
+		$headers = parent::buildRequest();
+		
+		# Cache validators
+		if (!empty($this->validators))
+		{
+			if (isset($this->validators['IfModifiedSince'])) {
+				$headers[] = 'If-Modified-Since: '.$this->validators['IfModifiedSince'];
+			}
+			if (isset($this->validators['IfNoneMatch'])) {
+				if (is_array($this->validators['IfNoneMatch'])) {
+					$etags = implode(',',$this->validators['IfNoneMatch']);
+				} else {
+					$etags = $this->validators['IfNoneMatch'];
+				}
+				$headers[] = '';
+			}
+		}
+		
+		return $headers;
+	}
+	
+	private function setValidator($key,$value)
+	{
+		if ($key == 'IfModifiedSince') {
+			$value = gmdate('D, d M Y H:i:s',$value).' GMT';
+		}
+		
+		$this->validators[$key] = $value;
+	}
+}
+
+?>
Index: plugins/daInstaller/inc/lib.da.installer.ui.php
===================================================================
--- plugins/daInstaller/inc/lib.da.installer.ui.php	(revision 1046)
+++ plugins/daInstaller/inc/lib.da.installer.ui.php	(revision 1046)
@@ -0,0 +1,310 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+
+/**
+ * Class daModulesList
+ */
+class daModulesList extends adminGenericList
+{
+	/**
+	 * Display data table for plugins and themes lists
+	 *
+	 * @param	int		page
+	 * @param	int		nb_per_page
+	 * @param	string	type
+	 * @param	string	url
+	 */
+	public function display($page,$nb_per_page,$type,$url)
+	{
+		$search = false;
+		if (strpos($type,'search-') === 0) {
+			$search = true;
+			$type = str_replace('search-','',$type);
+		}
+		$type = ($type == 'themes') ? 'themes' : 'plugins';
+		if ($type == 'themes') {
+			$msg_no_entry = __('No theme');
+			$msg_th_label = __('Themes');
+			$lineMethod   = 'themeLine';
+		}
+		else {
+			$msg_no_entry = __('No extension');
+			$msg_th_label = __('Plugins');
+			$lineMethod   = 'pluginLine';
+		}
+		
+		if ($this->rs->isEmpty()) {
+			echo '<p><strong>'.$msg_no_entry.'</strong></p>';
+		}
+		else {
+			$pager = new pager($page,$this->rs_count,$nb_per_page,10);
+			if (!$search) {
+				$pager->base_url = $url.'&amp;tab='.$type.'&amp;page=%s';
+			}
+			else {
+				$pager->var_pager = 'page';
+			}
+			
+			$html_block =
+				'<table summary="modules" class="maximal">'.
+				'<thead>'.
+				'<tr>'.
+				'<th>'.$msg_th_label.'</th>'.
+				'<th class="nowrap">'.__('Lastest Version').'</th>'.
+				'<th>'.__('Quick description').'</th>'.
+				'<th>'.__('Actions').'</th>'.
+				'</tr>'.
+				'</thead>'.
+				'<tbody>%s</tbody>'.
+				'</table>';
+			
+			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+			$blocks = explode('%s',$html_block);
+			echo $blocks[0];
+			
+			$this->rs->index(((integer)$page - 1) * $nb_per_page);
+			$iter = 0;
+			while ($iter < $nb_per_page) {
+				echo $this->{$lineMethod}($url);
+				if ($this->rs->isEnd()) {
+					break;
+				}
+				else {
+					$this->rs->moveNext();
+					$iter++;
+				}
+			}
+			echo $blocks[1];
+			echo '<p>'.__('Page(s)').' : '.$pager->getLinks().'</p>';
+		}
+	}
+	
+	/**
+	 * Return a generic plugin row
+	 *
+	 * @param	string	url
+	 *
+	 * @return	string
+	 */
+	private function pluginLine($url)
+	{
+		return
+			'<tr class="line wide" id="ext_'.$this->rs->id.'">'."\n".
+			# Extension
+			'<td class="minimal nowrap">'.
+				'<strong>'.html::escapeHTML($this->rs->id).'</strong>'.
+			"</td>\n".
+			# Version
+			'<td class="minimal nowrap">'.
+				html::escapeHTML($this->rs->version).
+			"</td>\n".
+			# Quick description
+			'<td>'.
+				'<p><strong>'.html::escapeHTML($this->rs->label).'</strong><br />'.
+				'<em>'.html::escapeHTML($this->rs->desc).'</em></p>'.
+				__('by').' '.html::escapeHTML($this->rs->author).'<br />'.
+				'( <a href="'.$this->rs->details.'" class="learnmore modal">'.__('More details').'</a> )'.
+			"</td>\n".
+			# Action
+			'<td class="minimal">'.
+				'<form action="'.$url.'" method="post">'.
+				'<p><input name="package_url" value="'.$this->rs->file.'" type="hidden" />'.
+				$this->core->formNonce().
+				'<input class="install" name="add_plugin" value="'.
+				__('Install').'" type="submit" /></p>'.
+				'</form>'.
+			"</td>\n".
+			'</tr>'."\n";
+	}
+	
+	/**
+	 * Return a generic theme row
+	 *
+	 * @param	string	url
+	 *
+	 * @return	string
+	 */
+	private function themeLine($url)
+	{
+		return
+			'<tr class="line wide" id="ext_'.$this->rs->id.'">'."\n".
+			# Extension
+			'<td class="minimal nowrap">'.
+				'<strong>'.html::escapeHTML($this->rs->id).'</strong>'.
+				'<p class="sshot"><img src="'.html::escapeHTML($this->rs->sshot).'" alt="" /></p>'.
+			"</td>\n".
+			# Version
+			'<td class="minimal nowrap">'.
+				html::escapeHTML($this->rs->version).
+			"</td>\n".
+			# Quick description
+			'<td>'.
+				'<p><strong>'.html::escapeHTML($this->rs->label).'</strong><br />'.
+				'<em>'.html::escapeHTML($this->rs->desc).'</em></p>'.
+				__('by').' '.html::escapeHTML($this->rs->author).'<br />'.
+				'( <a href="'.$this->rs->details.'" class="learnmore modal">'.__('More details').'</a> )'.
+			"</td>\n".
+			# Action
+			'<td class="minimal">'.
+				'<form action="'.$url.'" method="post">'.
+				'<p><input name="package_url" value="'.$this->rs->file.'" type="hidden" />'.
+				$this->core->formNonce().
+				'<input class="install" name="add_theme" value="'.
+				__('Install').'" type="submit" /></p>'.
+				'</form>'.
+			"</td>\n".
+			'</tr>'."\n";
+	} 
+}
+
+/**
+ * Class daModulesUpdateList
+ */
+class daModulesUpdateList
+{
+	protected $rs;
+	protected $nb;
+	
+	/**
+	 * Class constructor
+	 */
+	public function __construct($core,$rs,$nb)
+	{
+		$this->core	= $core;
+		$this->rs		=  $rs;
+		$this->nb		=  $nb;
+		$this->p_link	= '<a href="%s" class="%s">%s</a>';
+	}
+	
+	/**
+	 * Display data table for plugins and themes update lists
+	 *
+	 * @param	string	type
+	 * @param	string	url
+	 *
+	 * @return	string
+	 */
+	public function display($type,$url)
+	{
+		$type = ($type == 'themes') ? 'themes' : 'plugins';
+		if ($type == 'themes') {
+			$msg_th_label = __('Theme');
+			$lineMethod   = 'themeLine';
+		}
+		else {
+			$msg_th_label = __('Plugins');
+			$lineMethod   = 'pluginLine';
+		}
+		
+		$iter = 0;
+		$items = '';
+		$html_block =
+			'<form action="'.$url.'" method="post">'.
+			'<table summary="upd-%1$s" class="maximal">'.
+			'<thead>'.
+			'<tr>'.
+			'<th>'.$msg_th_label.'</th>'.
+			'<th class="nowrap">'.__('Lastest Version').'</th>'.
+			'<th>'.__('Quick description').'</th>'.
+			'</tr>'.
+			'</thead>'.
+			'<tbody>%2$s</tbody>'.
+			'</table>'.
+			'<div class="two-cols">'.
+			'<p class="col checkboxes-helpers"></p>'.
+			'<p class="col right">'.
+			$this->core->formNonce().
+			'<input type="submit" value="'.__('Update selected modules').'" name="upd_'.$type.'" /></p>'.
+			'</div>'.
+			'</form>';
+			
+		while ($iter < $this->rs->count()) {
+			$items .= $this->{$lineMethod}($url);
+			$this->rs->moveNext();
+			$iter++;
+		}
+		
+		echo $this->nb > 0 ? sprintf($html_block,$type,$items) : '';
+		
+	}
+
+	/**
+	 * Return a update plugin row
+	 *
+	 * @param	string	url
+	 *
+	 * @return	string
+	 */
+	private function pluginLine($url)
+	{
+		$support =
+		strlen($this->rs->support) > 0 ?
+		sprintf($this->p_link,$this->rs->support,'support modal',__('Support')) :
+		'<span class="support">'.__('No support available').'</span>';
+		
+		return
+			'<tr class="line wide" id="ext_'.$this->rs->id.'">'."\n".
+			# Extension
+			'<td class="minimal nowrap">'.
+				form::checkbox(array('plugins_id[]'),$this->rs->id).
+				'<strong>'.html::escapeHTML($this->rs->id).'</strong>'.
+			"</td>\n".
+			# Version
+			'<td class="minimal nowrap">'.
+				html::escapeHTML($this->rs->version).
+			"</td>\n".
+			# Quick description
+			'<td>'.
+				'<p><strong>'.html::escapeHTML($this->rs->label).'</strong><br />'.
+				'<em>'.html::escapeHTML($this->rs->desc).'</em></p>'.
+				__('by').' '.html::escapeHTML($this->rs->author).'<br />'.
+				'( <a href="'.$this->rs->details.'" class="learnmore modal">'.
+				__('More details').'</a> - '.$support.'</a> )'.
+			"</td>\n".
+			'</tr>'."\n";
+	}
+	
+	/**
+	 * Return a update theme row
+	 *
+	 * @param	string	url
+	 *
+	 * @return	string
+	 */
+	private function themeLine($url)
+	{
+		$support =
+		strlen($this->rs->support) > 0 ?
+		sprintf($this->p_link,$this->rs->support,'support modal',__('Support')) :
+		'<span class="support">'.__('No support available').'</span>';
+		
+		return
+			'<tr class="line wide" id="ext_'.$this->rs->id.'">'."\n".
+			# Themes
+			'<td class="minimal nowrap">'.
+				form::checkbox(array('themes_id[]'),$this->rs->id).
+				'<strong>'.html::escapeHTML($this->rs->id).'</strong>'.
+				'<p class="sshot"><img src="'.html::escapeHTML($this->rs->sshot).'" alt="" /></p>'.
+			"</td>\n".
+			# Version
+			'<td class="minimal nowrap">'.
+				html::escapeHTML($this->rs->version).
+			"</td>\n".
+			# Quick description
+			'<td>'.
+				'<p><strong>'.html::escapeHTML($this->rs->label).'</strong><br />'.
+				'<em>'.html::escapeHTML($this->rs->desc).'</em></p>'.
+				__('by').' '.html::escapeHTML($this->rs->author).'<br />'.
+				'( <a href="'.$this->rs->details.'" class="learnmore modal">'.
+				__('More details').'</a> - '.$support.'</a> )'.
+			"</td>\n".
+			'</tr>'."\n";
+	}
+}
+
+?>
Index: plugins/daInstaller/index.php
===================================================================
--- plugins/daInstaller/index.php	(revision 1046)
+++ plugins/daInstaller/index.php	(revision 1046)
@@ -0,0 +1,321 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+if (!defined('DC_CONTEXT_ADMIN')) { return; }
+
+# Settings compatibility test
+if (!version_compare(DC_VERSION,'2.2-x','<')) {
+	$core->blog->settings->addNamespace('dainstaller');
+	$s = $core->blog->settings->dainstaller;
+}
+else {
+	$core->blog->settings->setNamespace('dainstaller');
+	$s = $core->blog->settings;
+}
+
+# Initialisation des variables
+$p_url 		= 'plugin.php?p=daInstaller';
+$default_tab 	= !empty($_GET['tab']) ? html::escapeHTML($_GET['tab']) : 'plugins';
+$page		= !empty($_GET['page']) ? (integer)$_GET['page'] : 1;
+$nb_per_page 	= 10;
+$q			= !empty($_GET['q']) ? trim(html::escapeHTML($_GET['q'])) : '';
+$default_tab 	= !empty($q) ? 'search' : $default_tab;
+$mode 		= isset($_GET['mode']) ? html::escapeHTML($_GET['mode']) : 'plugins';
+$ppaths 		= explode(PATH_SEPARATOR, DC_PLUGINS_ROOT);
+$plugins_path	= array_pop($ppaths);
+$daInstaller 	= new daInstaller($core);
+unset($ppaths);
+
+$pages['plugins'] = $pages['themes'] = $pages['search'] = 1;
+$pages[$default_tab] = $page;
+
+# Ajout d'un plugin
+if (!empty($_POST['add_plugin']) && !empty($_POST['package_url'])) {
+	try {
+		$url = html::escapeHTML($_POST['package_url']);
+		$dest = $plugins_path.'/'.basename($url);
+
+		$ret_code = $daInstaller->processPackage($url,$dest,$core->plugins);
+		http::redirect($p_url.'&p_added='.$ret_code);
+	}
+	catch (Exception $e) {
+		$core->error->add($e->getMessage());
+		$default_tab = 'plugins';
+	}
+}
+# Mise à jour de plugins
+elseif (!empty($_POST['upd_plugins']) && !empty($_POST['plugins_id'])) {
+	try {
+		$daInstaller->check();
+		$ids = $_POST['plugins_id'];
+		$modules = $daInstaller->getModules('plugins',true);
+
+		foreach ($modules as $module) {
+			if (in_array($module['id'],$ids)) {
+				if (!$s->dainstaller_allow_multi_install) {
+					$dest = $module['root'].'/../'.basename($module['file']);
+				}
+				else {
+					$dest = $plugins_path.'/'.basename($module['file']);
+					if ($module['root'] != $dest) @file_put_contents($module['root'].'/_disabled','');
+				}
+				$ret_code[] = $daInstaller->processPackage($module['file'],$dest,$core->plugins);
+			}
+		}
+		
+		$arg = 'p_updated='.implode('|',$ids).'&p_status='.implode('|',$ret_code);
+
+		http::redirect($p_url.'&tab=update&'.$arg);
+		
+	}
+	catch (Exception $e) {
+		$core->error->add($e->getMessage());
+		$default_tab = 'update';
+	}
+}
+# Ajout d'un thème
+elseif (!empty($_POST['add_theme']) && !empty($_POST['package_url'])) {
+	try {
+		$url = html::escapeHTML($_POST['package_url']);
+		$dest = $core->blog->themes_path.'/'.basename($url);
+
+		$core_themes = new dcModules($core);
+		$core_themes->loadModules($core->blog->themes_path,null);
+		$ret_code = $daInstaller->processPackage($url,$dest,$core_themes);
+		http::redirect($p_url.'&tab=themes&t_added='.$ret_code);
+	}
+	catch (Exception $e) {
+		unset($core_themes);
+		$core->error->add($e->getMessage());
+		$default_tab = 'themes';
+	}
+}
+# Mise à jour de thèmes
+elseif (!empty($_POST['upd_themes']) && !empty($_POST['themes_id'])) {
+	try {
+		$daInstaller->check();
+		$core_themes = new dcModules($core);
+		$core_themes->loadModules($core->blog->themes_path,null);
+		$ids = $_POST['themes_id'];
+		$modules = $daInstaller->getModules('themes',true);
+
+		foreach ($modules as $module) {
+			if (in_array($module['id'],$ids)) {
+				$dest = $core->blog->themes_path.'/'.basename($module['file']);
+				$ret_code[] = $daInstaller->processPackage($module['file'],$dest,$core_themes);
+			}
+		}
+
+		$arg = 't_updated='.implode('|',$ids).'&t_status='.implode('|',$ret_code);
+
+		http::redirect($p_url.'&tab=update&'.$arg);
+
+	}
+	catch (Exception $e) {
+		unset($core_themes);
+		$core->error->add($e->getMessage());
+		$default_tab = 'update';
+	}
+}
+
+# Et c'est parti !
+$plugins_install = $core->plugins->installModules();
+$daInstaller->check(false,true);
+
+/**
+ * This function returns all error / success messages
+ *
+ * @return string
+ */
+function infoMessages()
+{
+	$res = '';
+	$p_msg = '<p class="message">%s</p>';
+	$p_err = '<p class="error">%s</p>';
+	
+	# Plugins install message
+	if (!empty($_GET['p_added']) && $_GET['p_added'] != 2) {
+		$res .= sprintf($p_msg,__('The plugin has been successfully installed.'));
+	}
+	# Themes install message
+	if (!empty($_GET['t_added']) && $_GET['t_added'] != 2) {
+		$res .= sprintf($p_msg,__('The theme has been successfully installed.'));
+	}
+	# Plugins update message
+	if (!empty($_GET['p_updated'])) {
+		$err = $upd = '';
+		$ids = explode('|',html::escapeHTML($_GET['p_updated']));
+		$status = explode('|',html::escapeHTML($_GET['p_status']));
+		foreach ($ids as $k => $v) {
+			if ($status[$k] != 2) {
+				$err .= '<li>'.$v.'</li>';
+			}
+			else {
+				$upd .= '<li>'.$v.'</li>';
+			}
+		}
+		if (!empty($err)) {
+			$res .= '<div class="error">'.__('Following plugins have not been updated:').'<ul>'.$err.'</ul></div>';
+		}
+		else {
+			$res .= '<div class="static-msg">'.__('Following plugins have been updated:').'<ul>'.$upd.'</ul></div>';
+		}
+	}
+	# Themes update message
+	if (!empty($_GET['t_updated'])) {
+		$err = $upd = '';
+		$ids = explode('|',html::escapeHTML($_GET['t_updated']));
+		$status = explode('|',html::escapeHTML($_GET['t_status']));
+		foreach ($ids as $k => $v) {
+			if ($status[$k] != 2) {
+				$err .= '<li>'.$v.'</li>';
+			}
+			else {
+				$upd .= '<li>'.$v.'</li>';
+			}
+		}
+		if (!empty($err)) {
+			$res .= '<div class="error">'.__('Following themes have not been updated:').'<ul>'.$err.'</ul></div>';
+		}
+		else {
+			$res .= '<div class="static-msg">'.__('Following themes have been updated:').'<ul>'.$upd.'</ul></div>';
+		}
+	}
+	# Plugins install settings messages
+	if (!empty($plugins_install['success'])) {
+		$res .= '<div class="static-msg">'.__('Following plugins have been installed:').'<ul>';
+		foreach ($plugins_install['success'] as $k => $v) {
+			$res .= '<li>'.$k.'</li>';
+		}
+		$res .= '</ul></div>';
+	}
+	if (!empty($plugins_install['failure'])) {
+		$res .= '<div class="error">'.__('Following plugins have not been installed:').'<ul>';
+		foreach ($plugins_install['failure'] as $k => $v) {
+			$res .= '<li>'.$k.' ('.$v.')</li>';
+		}
+		$res .= '</ul></div>';
+	}
+	
+	return $res;
+}
+
+# Récupération de la liste des mises à jour des plugins
+# et préparation de l'objet d'affichage
+$u_p_rs = $daInstaller->getModules('plugins',true);
+$u_p_nb = count($u_p_rs);
+$u_p_rs = staticRecord::newFromArray($u_p_rs);
+$u_p_list = new daModulesUpdateList($core,$u_p_rs,$u_p_nb);
+
+# Récupération de la liste des mises à jour des thèmes
+# et préparation de l'objet d'affichage
+$u_t_rs = $daInstaller->getModules('themes',true);
+$u_t_nb = count($u_t_rs);
+$u_t_rs = staticRecord::newFromArray($u_t_rs);
+$u_t_list = new daModulesUpdateList($core,$u_t_rs,$u_t_nb);
+
+# Récupération de la liste des plugins disponibles
+# et préparation de l'objet d'affichage
+$avail_plugins = $daInstaller->getModules('plugins');
+$a_p_nb = count($avail_plugins);
+$a_p_rs = staticRecord::newFromArray($avail_plugins);
+$a_p_list = new daModulesList($core,$a_p_rs,$a_p_nb);
+
+# Récupération de la liste des thèmes disponibles
+# et préparation de l'objet d'affichage
+$avail_themes = $daInstaller->getModules('themes');
+$a_t_nb = count($avail_themes);
+$a_t_rs = staticRecord::newFromArray($avail_themes);
+$a_t_list = new daModulesList($core,$a_t_rs,$a_t_nb);
+
+# Récupération de la liste des plugins recherchés
+if (!empty($q))
+{
+	$default_tab = 'search';
+	$search_modules = $daInstaller->search($q,$mode);
+	$s_m_nb = count($search_modules);
+	$s_m_rs = staticRecord::newFromArray($search_modules);
+	$s_m_list = new daModulesList($core,$s_m_rs,$s_m_nb);
+}
+
+# DISPLAY
+# -------
+echo
+'<html>'.
+'<head>'.
+	'<title>'.__('DotAddict.org Installer').'</title>'.
+	dcPage::jsModal().
+	dcPage::jsPageTabs($default_tab).
+	dcPage::jsLoad('index.php?pf=daInstaller/js/_dainstaller.js').
+	'<link rel="stylesheet" href="index.php?pf=daInstaller/style.css" type="text/css" />'.
+'</head>'.
+'<body>'.
+infoMessages().
+'<h2>'.__('DotAddict.org Installer').'</h2>'.
+'<p>'.__('Install and update your extensions live from DotAddict.org').'</p>';
+
+echo
+'<!-- Available updates -->'.
+'<div class="multi-part" id="update" title="'.__('Available updates').'">';
+if ($u_p_nb > 0 || $u_t_nb > 0) {
+	echo
+	'<p><strong>'.__('Detected updates for your system').'</strong></p>'.
+	'<p class="form-note warn">'.
+		__('Changes can be required after installation of updates. Click on a support link before to be aware about').
+	'</p>';
+}
+else {
+	echo '<p><strong>'.__('No update available').'</strong></p>';
+}
+	$u_p_list->display('plugins',$p_url);
+	$u_t_list->display('themes',$p_url);
+echo
+'</div>'.
+'<!-- Get more plugins -->'.
+'<div class="multi-part" id="plugins" title="'.__('Get more plugins').'">'.
+	'<p><strong>'.($a_p_nb > 0 ? sprintf(__('Available plugins (%s)'),$a_p_nb) : '').'</strong></p>';
+	$a_p_list->display($pages['plugins'],$nb_per_page,'plugins',$p_url);
+echo
+'</div>'.
+'<!-- Get more themes -->'.
+'<div class="multi-part" id="themes" title="'.__('Get more themes').'">'.
+	'<p><strong>'.($a_t_nb > 0 ? sprintf(__('Available themes (%s)'),$a_t_nb) : '').'</strong></p>';
+	$a_t_list->display($pages['themes'],5,'themes',$p_url);
+echo
+'</div>'.
+'<!-- Search -->'.
+'<div class="multi-part" id="search" title="'.__('Search').'">'.
+	'<fieldset><legend>'.__('Search options').
+	'</legend>'.
+	'<form method="get" action="'.$p_url.'">'.
+	'<p>'.form::hidden('p','daInstaller').
+	'<label for="q" class="classic">'.__('Query:').'&nbsp; '.
+	form::field('q',30,255,html::escapeHTML($q)).
+	'</label> '.
+	'<label for="mode" class="classic">'.
+	form::radio(array('mode','mode'),'plugins',$mode == 'plugins').
+	' '.__('Plugins').'&nbsp;</label> '.
+	'<label for="mode2" class="classic">'.
+	form::radio(array('mode','mode2'),'themes',$mode == 'themes')
+	.' '.__('Themes').'&nbsp;</label> '.
+	'<input type="submit" value="'.__('Search').'" /></p>'.
+	'</form>'.
+	'</fieldset>';
+if (!empty($q)) {
+	echo '<p><strong>'.sprintf(__('%u %s found'),$s_m_nb,__($mode)).'</strong></p>';
+	if ($s_m_nb > 0) {
+		$s_m_list->display($pages['search'],$nb_per_page,'search-'.$mode,$p_url);
+	}
+}
+echo
+'</div>';
+
+dcPage::helpBlock('da_installer');
+
+echo
+'</body>'.
+'</html>';
Index: plugins/daInstaller/js/_dainstaller.js
===================================================================
--- plugins/daInstaller/js/_dainstaller.js	(revision 1046)
+++ plugins/daInstaller/js/_dainstaller.js	(revision 1046)
@@ -0,0 +1,17 @@
+/*
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+*/
+$(function() {
+	$('a.modal').modalWeb($(window).width()-60,$(window).height()-60);
+});
+$(function() {
+	$('.checkboxes-helpers').each(function() {
+		dotclear.checkboxesHelpers(this);
+	});
+	dotclear.commentsActionsHelper();
+});
Index: plugins/daInstaller/locales/en/help/da_installer.html
===================================================================
--- plugins/daInstaller/locales/en/help/da_installer.html	(revision 1046)
+++ plugins/daInstaller/locales/en/help/da_installer.html	(revision 1046)
@@ -0,0 +1,30 @@
+<html>
+<head>
+  <title>Extension update</title>
+</head>
+
+<body>
+
+<h3>Update of extensions</h3>
+
+<dl>
+  <dd>It is possible, in Dotclear 2, to specify in the configuration <em>(PATH)</em>
+  many paths of folders containing plugins. But, the extension update are done only in
+  the <strong>last folder specify</strong> in <em>PATH</em>.
+  You may have, for several reasons, in other folders, an older extension than currently 
+  available on DotAddict. <strong>In this case</strong>, you have two choices: <ul>
+
+  <li><strong>Autorize</strong> multi-installation: the newer version of the
+  extension will be download and installed in the last folder of <em>PATH</em>
+  and the older one will be disabled (a _disabled file will be created in his folder). This 
+  old version <strong>will not be deleted</strong></li>
+  <li><strong>Not autorize</strong> multi-installation : the newer version will overwrite
+  the older one.</li></ul>
+
+  By default, <strong>multi-installation is disabled</strong> but you can change
+  this behaviour by modifying the <em>dainstaller_allow_multi_install</em> variable
+  in <a href="?p=aboutConfig">about:config</a></dd>
+</dl>
+
+</body>
+</html>
Index: plugins/daInstaller/locales/en/main.po
===================================================================
--- plugins/daInstaller/locales/en/main.po	(revision 1046)
+++ plugins/daInstaller/locales/en/main.po	(revision 1046)
@@ -0,0 +1,123 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Dotclear 2 daInstaller module\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-11-13 19:22+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "DotAddict.org Installer"
+msgstr ""
+
+msgid "Updates are available"
+msgstr ""
+
+#, php-format
+msgid "Oops, something went wrong with %s, we are working on it. %s"
+msgstr ""
+
+msgid "dotaddict.org website"
+msgstr ""
+
+msgid "Wanna help too?"
+msgstr ""
+
+msgid "Impossible to read data feed"
+msgstr ""
+
+msgid "Wrong data feed"
+msgstr ""
+
+msgid "No theme"
+msgstr ""
+
+msgid "No extension"
+msgstr ""
+
+msgid "Lastest Version"
+msgstr ""
+
+msgid "Quick description"
+msgstr ""
+
+msgid "Actions"
+msgstr ""
+
+msgid "More details"
+msgstr ""
+
+msgid "Install"
+msgstr ""
+
+msgid "Theme"
+msgstr ""
+
+msgid "Update selected modules"
+msgstr ""
+
+msgid "Support"
+msgstr ""
+
+msgid "No support available"
+msgstr ""
+
+msgid "The plugin has been successfully installed."
+msgstr ""
+
+msgid "The theme has been successfully installed."
+msgstr ""
+
+msgid "Following plugins have not been updated:"
+msgstr ""
+
+msgid "Following plugins have been updated:"
+msgstr ""
+
+msgid "Following themes have not been updated:"
+msgstr ""
+
+msgid "Following themes have been updated:"
+msgstr ""
+
+msgid "Install and update your extensions live from DotAddict.org"
+msgstr ""
+
+msgid "Available updates"
+msgstr ""
+
+msgid "Detected updates for your system"
+msgstr ""
+
+msgid "Changes can be required after installation of updates. Click on a support link before to be aware about"
+msgstr ""
+
+msgid "No update available"
+msgstr ""
+
+msgid "Get more plugins"
+msgstr ""
+
+#, php-format
+msgid "Available plugins (%s)"
+msgstr ""
+
+msgid "Get more themes"
+msgstr ""
+
+#, php-format
+msgid "Available themes (%s)"
+msgstr ""
+
+#, php-format
+msgid "%u %s found"
+msgstr ""
Index: plugins/daInstaller/locales/en/resources.php
===================================================================
--- plugins/daInstaller/locales/en/resources.php	(revision 1046)
+++ plugins/daInstaller/locales/en/resources.php	(revision 1046)
@@ -0,0 +1,14 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+if (!defined('DC_RC_PATH')) { return; }
+
+if (!isset($__resources['help']['da_installer'])) {
+	$__resources['help']['da_installer'] = dirname(__FILE__).'/help/da_installer.html';
+}
+
+?>
Index: plugins/daInstaller/locales/fr/help/da_installer.html
===================================================================
--- plugins/daInstaller/locales/fr/help/da_installer.html	(revision 1046)
+++ plugins/daInstaller/locales/fr/help/da_installer.html	(revision 1046)
@@ -0,0 +1,30 @@
+<html>
+<head>
+  <title>Mise à jour d'extension(s)</title>
+</head>
+
+<body>
+
+<h3>Mise à jour d'extension(s)</h3>
+
+<dl>
+  <dd>Il est possible dans Dotclear 2 de spécifier dans sa configuration <em>(PATH)</em>
+  plusieurs chemins de dossiers contenant des extensions. Or, les mises à jour des
+  extensions se font dans <strong>le dernier répertoire</strong> du <em>PATH</em>.
+  Il se peut, pour des raisons variées, que dans un des premiers, il existe une
+  extension avec une version inférieure à celle présente sur DotAddict. <strong>Dans
+  ce cas préçis</strong>, vous avez deux choix possibles : <ul>
+  <li><strong>Autoriser</strong> la multi-installation : la nouvelle version de
+  l’extension sera téléchargée puis installée dans le dernier répertoire du <em>PATH</em>
+  et l’ancienne extension recevera un fichier _disabled afin de la désactiver. L’ancienne
+  version <strong>ne sera pas supprimée</strong></li>
+  <li><strong>Ne pas autoriser</strong> la multi-installation : la nouvelle version
+  ira écraser l’ancienne dans le bon répertoire.</li></ul>
+
+  Par défaut, <strong>la multi-installation est désactivée</strong> mais vous pouvez
+  changer ce comportement en modifiant la variable <em>dainstaller_allow_multi_install</em>
+  dans <a href="?p=aboutConfig">about:config</a></dd>
+</dl>
+
+</body>
+</html>
Index: plugins/daInstaller/locales/fr/main.po
===================================================================
--- plugins/daInstaller/locales/fr/main.po	(revision 1046)
+++ plugins/daInstaller/locales/fr/main.po	(revision 1046)
@@ -0,0 +1,122 @@
+# Language: Français
+# Module: daInstaller - 1.0.3
+# Date: 2011-05-16 11:47:48
+# Translated with translater 1.5
+msgid ""
+msgstr ""
+"Project-Id-Version: daInstaller 1.0.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-11-13 19:22+0100\n"
+"PO-Revision-Date: 2011-05-16T11:47:48+00:00\n"
+"Last-Translator: Thomas Bouron\n"
+"Language-Team: \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "DotAddict.org Installer"
+msgstr "Installateur DotAddict.org"
+
+msgid "Updates are available"
+msgstr "Des mises à jour sont disponibles"
+
+#, php-format
+msgid "Oops, something went wrong with %s, we are working on it. %s"
+msgstr "Oops, il semble y avoir un problème avec %s, nous travaillons actuellement à sa résolution. %s"
+
+msgid "dotaddict.org website"
+msgstr "le site dotaddict.org"
+
+msgid "Wanna help too?"
+msgstr "Vous voulez nous aider aussi?"
+
+msgid "Impossible to read data feed"
+msgstr "Impossible de lire le flux de données"
+
+msgid "Wrong data feed"
+msgstr "Flux de données incorrect"
+
+msgid "No theme"
+msgstr "Aucun thème disponible"
+
+msgid "No extension"
+msgstr "Aucune extension disponible"
+
+msgid "Lastest Version"
+msgstr "Dernière version"
+
+msgid "Quick description"
+msgstr "Description rapide"
+
+msgid "Actions"
+msgstr "Actions"
+
+msgid "More details"
+msgstr "En savoir plus"
+
+msgid "Install"
+msgstr "Installer"
+
+msgid "Theme"
+msgstr "Thèmes"
+
+msgid "Update selected modules"
+msgstr "Mettre à jour les modules sélectionnés"
+
+msgid "Support"
+msgstr "Support"
+
+msgid "No support available"
+msgstr "Aucun support disponible"
+
+msgid "The plugin has been successfully installed."
+msgstr "Le plugin a été installé avec succès"
+
+msgid "The theme has been successfully installed."
+msgstr "Le thème a été installé avec succès"
+
+msgid "Following plugins have not been updated:"
+msgstr "Les extensions suivantes n'ont pas été mises à jour :"
+
+msgid "Following plugins have been updated:"
+msgstr "Les extensions suivantes ont été mises à jour :"
+
+msgid "Following themes have not been updated:"
+msgstr "Les thèmes suivants n'ont pas été mis à jour :"
+
+msgid "Following themes have been updated:"
+msgstr "Les thèmes suivants ont été mis à jour :"
+
+msgid "Install and update your extensions live from DotAddict.org"
+msgstr "Installez et mettez à jour vos extensions en direct depuis DotAddict.org"
+
+msgid "Available updates"
+msgstr "Mises à jour disponibles"
+
+msgid "Detected updates for your system"
+msgstr "Mises à jour détectées pour votre système"
+
+msgid "Changes can be required after installation of updates. Click on a support link before to be aware about"
+msgstr "Des changements sont peut être nécessaires après la mise à jour. Pensez à vérifier en cliquant sur le lien de support"
+
+msgid "No update available"
+msgstr "Aucune mise à jour détectée pour votre système"
+
+msgid "Get more plugins"
+msgstr "Obtenir plus d'extensions"
+
+#, php-format
+msgid "Available plugins (%s)"
+msgstr "Plugins disponibles (%s)"
+
+msgid "Get more themes"
+msgstr "Obtenir plus de thèmes"
+
+#, php-format
+msgid "Available themes (%s)"
+msgstr "Thèmes disponibles (%s)"
+
+#, php-format
+msgid "%u %s found"
+msgstr "%u %s trouvé(s)"
Index: plugins/daInstaller/locales/fr/resources.php
===================================================================
--- plugins/daInstaller/locales/fr/resources.php	(revision 1046)
+++ plugins/daInstaller/locales/fr/resources.php	(revision 1046)
@@ -0,0 +1,14 @@
+<?php
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+if (!defined('DC_RC_PATH')) { return; }
+
+if (!isset($__resources['help']['da_installer'])) {
+	$__resources['help']['da_installer'] = dirname(__FILE__).'/help/da_installer.html';
+}
+
+?>
Index: plugins/daInstaller/style.css
===================================================================
--- plugins/daInstaller/style.css	(revision 1046)
+++ plugins/daInstaller/style.css	(revision 1046)
@@ -0,0 +1,29 @@
+/*
+# ***** BEGIN LICENSE BLOCK *****
+# This file is part of daInstaller, a plugin for DotClear2.
+# Copyright (c) 2008-2011 Tomtom, Pep and contributors, for DotAddict.org.
+# All rights reserved.
+#
+# ***** END LICENSE BLOCK *****
+*/
+#themes {
+	border: none;
+	margin: 0;
+}
+.learnmore {
+	background: transparent url(index.php?pf=daInstaller/img/help.png) no-repeat top right;
+	padding-right: 20px;
+}
+.support {
+	background: transparent url(index.php?pf=daInstaller/img/support.png) no-repeat top right;
+	padding-right: 20px;
+}
+.sshot img {
+	margin:4px 0;
+	width:160px;
+	height:140px;
+	border:1px solid #999;
+}
+form {
+	clear:both;
+}
Index: plugins/importExport/style.css
===================================================================
--- plugins/importExport/style.css	(revision 951)
+++ plugins/importExport/style.css	(revision 1065)
@@ -23,6 +23,3 @@
 	font-weight: bold;
 	border-radius: 2px;
-	-o-border-radius: 2px;
-	-moz-border-radius: 2px;
-	-webkit-border-radius: 2px;
 }
Index: plugins/pages/_public.php
===================================================================
--- plugins/pages/_public.php	(revision 945)
+++ plugins/pages/_public.php	(revision 1063)
@@ -249,5 +249,5 @@
 		
 		$res =
-		'<div class="pages'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="pages'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -262,5 +262,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
Index: plugins/pages/_widgets.php
===================================================================
--- plugins/pages/_widgets.php	(revision 954)
+++ plugins/pages/_widgets.php	(revision 1063)
@@ -38,4 +38,5 @@
 			array(__('Ascending') => 'asc', __('Descending') => 'desc')
 		);
+		$w->pages->setting('content_only',__('Content only'),0,'check');
 		$w->pages->setting('class',__('CSS class:'),'');
 	}
Index: plugins/pages/page.php
===================================================================
--- plugins/pages/page.php	(revision 986)
+++ plugins/pages/page.php	(revision 1068)
@@ -193,5 +193,18 @@
 }
 
-# Create or update post
+# Delete page
+if (!empty($_POST['delete']) && $can_delete)
+{
+	try {
+		# --BEHAVIOR-- adminBeforePageDelete
+		$core->callBehavior('adminBeforePageDelete',$post_id);
+		$core->blog->delPost($post_id);
+		http::redirect($p_url);
+	} catch (Exception $e) {
+		$core->error->add($e->getMessage());
+	}
+}
+
+# Create or update page
 if (!empty($_POST) && !empty($_POST['save']) && $can_edit_page && !$bad_dt)
 {
@@ -263,16 +276,4 @@
 			$core->error->add($e->getMessage());
 		}
-	}
-}
-
-if (!empty($_POST['delete']) && $can_delete)
-{
-	try {
-		# --BEHAVIOR-- adminBeforePageDelete
-		$core->callBehavior('adminBeforePageDelete',$post_id);
-		$core->blog->delPost($post_id);
-		http::redirect($p_url);
-	} catch (Exception $e) {
-		$core->error->add($e->getMessage());
 	}
 }
Index: plugins/simpleMenu/_public.php
===================================================================
--- plugins/simpleMenu/_public.php	(revision 945)
+++ plugins/simpleMenu/_public.php	(revision 1063)
@@ -52,11 +52,14 @@
 		}
 
-		return '<div class="simple-menu'.
-			($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
-			($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').$menu.'</div>';
+		return
+			($w->content_only ? '' : '<div class="simple-menu'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
+			($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').$menu.
+			($w->content_only ? '' : '</div>');
 	}
 	
 	public static function displayMenu($class='',$id='',$description='')
 	{
+		global $core;
+
 		$ret = '';
 
@@ -98,10 +101,24 @@
 					}
 				}
+
+				$item = new ArrayObject(array(
+					'url' => $href,					// URL
+					'label' => __($m['label']),		// <a> link label
+					'title' => $title,				// <a> link title (optional)
+					'span' => $span,				// description (will be displayed after <a> link)
+					'active' => $active,			// status (true/false)
+					'class' => ''					// additional <li> class (optional)
+					));
+
+				# --BEHAVIOR-- publicSimpleMenuItem
+				$core->callBehavior('publicSimpleMenuItem',$i,$item);
+
 				$ret .= '<li class="li'.($i+1).
-							($active ? ' active' : '').
+							($item['active'] ? ' active' : '').
 							($i == 0 ? ' li-first' : '').
 							($i == count($menu)-1 ? ' li-last' : '').
+							($item['class'] ? $item['class'] : '').
 						'">'.
-						'<a href="'.$href.'"'.$title.'>'.__($m['label']).$span.'</a>'.
+						'<a href="'.$href.'"'.$item['title'].'>'.$item['label'].$item['span'].'</a>'.
 						'</li>';
 			}
Index: plugins/simpleMenu/_widgets.php
===================================================================
--- plugins/simpleMenu/_widgets.php	(revision 954)
+++ plugins/simpleMenu/_widgets.php	(revision 1063)
@@ -27,4 +27,5 @@
 				)
 		);
+		$w->simplemenu->setting('content_only',__('Content only'),0,'check');
 		$w->simplemenu->setting('class',__('CSS class:'),'');
 	}
Index: plugins/simpleMenu/index.php
===================================================================
--- plugins/simpleMenu/index.php	(revision 907)
+++ plugins/simpleMenu/index.php	(revision 1011)
@@ -434,5 +434,5 @@
 			echo '<form id="additem" action="'.$p_url.'&add=2" method="post">';
 			echo '<fieldset><legend>'.__('Select type').'</legend>';
-			echo '<p class="field"><label for"item_type" class="classic">'.__('Type of item menu:').'</label>'.form::combo('item_type',$items_combo,'').'</p>';
+			echo '<p class="field"><label for="item_type" class="classic">'.__('Type of item menu:').'</label>'.form::combo('item_type',$items_combo,'').'</p>';
 			echo '<p>'.$core->formNonce().'<input type="submit" name="appendaction" value="'.__('Continue...').'" />'.'</p>';
 			echo '</fieldset>';
@@ -446,21 +446,21 @@
 				switch ($item_type) {
 					case 'lang':
-						echo '<p class="field"><label for"item_select" class="classic">'.__('Select language:').'</label>'.
+						echo '<p class="field"><label for="item_select" class="classic">'.__('Select language:').'</label>'.
 							form::combo('item_select',$langs_combo,'');
 						break;
 					case 'category':
-						echo '<p class="field"><label for"item_select" class="classic">'.__('Select category:').'</label>'.
+						echo '<p class="field"><label for="item_select" class="classic">'.__('Select category:').'</label>'.
 							form::combo('item_select',$categories_combo,'');
 						break;
 					case 'archive':
-						echo '<p class="field"><label for"item_select" class="classic">'.__('Select month (if necessary):').'</label>'.
+						echo '<p class="field"><label for="item_select" class="classic">'.__('Select month (if necessary):').'</label>'.
 							form::combo('item_select',$months_combo,'');
 						break;
 					case 'pages':
-						echo '<p class="field"><label for"item_select" class="classic">'.__('Select page:').'</label>'.
+						echo '<p class="field"><label for="item_select" class="classic">'.__('Select page:').'</label>'.
 							form::combo('item_select',$pages_combo,'');
 						break;
 					case 'tags':
-						echo '<p class="field"><label for"item_select" class="classic">'.__('Select tag (if necessary):').'</label>'.
+						echo '<p class="field"><label for="item_select" class="classic">'.__('Select tag (if necessary):').'</label>'.
 							form::combo('item_select',$tags_combo,'');
 						break;
@@ -481,9 +481,9 @@
 			echo '<form id="additem" action="'.$p_url.'&add=4" method="post">';
 			echo '<fieldset><legend>'.$item_type_label.($item_select_label != '' ? ' ('.$item_select_label.')' : '').'</legend>';
-			echo '<p class="field"><label for"item_label" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.
+			echo '<p class="field"><label for="item_label" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.
 				__('Label of item menu:').'</label>'.form::field('item_label',20,255,$item_label).'</p>';
-			echo '<p class="field"><label for"item_descr" class="classic">'.
+			echo '<p class="field"><label for="item_descr" class="classic">'.
 				__('Description of item menu:').'</label>'.form::field('item_descr',30,255,$item_descr).'</p>';
-			echo '<p class="field"><label for"item_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.
+			echo '<p class="field"><label for="item_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.
 				__('URL of item menu:').'</label>'.form::field('item_url',40,255,$item_url).'</p>';
 			echo form::hidden('item_type',$item_type).form::hidden('item_select',$item_select);
Index: plugins/tags/_public.php
===================================================================
--- plugins/tags/_public.php	(revision 945)
+++ plugins/tags/_public.php	(revision 1063)
@@ -256,5 +256,5 @@
 		
 		$res =
-		'<div class="tags'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="tags'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -277,5 +277,5 @@
 		}
 		
-		$res .= '</div>';
+		$res .= ($w->content_only ? '' : '</div>');
 		
 		return $res;
Index: plugins/tags/_widgets.php
===================================================================
--- plugins/tags/_widgets.php	(revision 954)
+++ plugins/tags/_widgets.php	(revision 1063)
@@ -36,4 +36,5 @@
 				)
 		);
+		$w->tags->setting('content_only',__('Content only'),0,'check');
 		$w->tags->setting('class',__('CSS class:'),'');
 	}
Index: plugins/themeEditor/_admin.php
===================================================================
--- plugins/themeEditor/_admin.php	(revision 966)
+++ plugins/themeEditor/_admin.php	(revision 998)
@@ -53,5 +53,5 @@
 		'<fieldset><legend>'.__('Theme Editor').'</legend>'.
 		
-		'<p><label for"colorsyntax" class="classic">'.
+		'<p><label for="colorsyntax" class="classic">'.
 		form::checkbox('colorsyntax',1,$core->auth->user_prefs->interface->colorsyntax).' '.
 		__('Syntax color').'</label></p>'.
Index: plugins/themeEditor/class.themeEditor.php
===================================================================
--- plugins/themeEditor/class.themeEditor.php	(revision 270)
+++ plugins/themeEditor/class.themeEditor.php	(revision 1037)
@@ -24,4 +24,5 @@
 	public $css = array();
 	public $js  = array();
+	public $po  = array();
 	
 	public function __construct($core)
@@ -39,4 +40,5 @@
 		$this->findStyles();
 		$this->findScripts();
+		$this->findLocales();
 	}
 	
@@ -106,4 +108,8 @@
 			}
 			
+			if ($type == 'po' && !is_dir(dirname($dest))) {
+				files::makeDir(dirname($dest));
+			}
+			
 			$fp = @fopen($dest,'wb');
 			if (!$fp) {
@@ -130,4 +136,6 @@
 		if ($type == 'tpl') {
 			$dest = $this->user_theme.'/tpl/'.$f;
+		} elseif ($type == 'po') {
+			$dest = $this->user_theme.'/locales/'.$f;
 		} else {
 			$dest = $this->user_theme.'/'.$f;
@@ -143,5 +151,11 @@
 			}
 		}
-		
+
+		if ($type == 'po' && !is_dir(dirname($dest))) {
+			if (is_writable($this->user_theme)) {
+				return $dest;
+			}
+		}
+
 		if (is_writable(dirname($dest))) {
 			return $dest;
@@ -161,4 +175,6 @@
 			case 'js':
 				return $this->js;
+			case 'po':
+				return $this->po;
 			default:
 				return array();
@@ -178,4 +194,7 @@
 			case 'js':
 				$list =& $this->js;
+				break;
+			case 'po':
+				$list =& $this->po;
 				break;
 			default:
@@ -219,5 +238,16 @@
 	}
 	
-	protected function getFilesInDir($dir,$ext=null,$prefix='')
+	protected function findLocales()
+	{
+		$langs = l10n::getISOcodes(1,1);
+		foreach ($langs as $k => $v) {
+			if ($this->parent_theme) {
+				$this->po = array_merge($this->po,$this->getFilesInDir($this->parent_theme.'/locales/'.$v,'po',$v.'/','main.po'));
+			}
+			$this->po = array_merge($this->po,$this->getFilesInDir($this->user_theme.'/locales/'.$v,'po',$v.'/','main.po'));
+		}
+	}
+	
+	protected function getFilesInDir($dir,$ext=null,$prefix='',$model=null)
 	{
 		$dir = path::real($dir);
@@ -231,5 +261,7 @@
 		{
 			if (is_file($dir.'/'.$f) && !preg_match('/^\./',$f) && (!$ext || preg_match('/\.'.preg_quote($ext).'$/i',$f))) {
-				$res[$prefix.$f] = $dir.'/'.$f;
+				if (!$model || preg_match('/^'.preg_quote($model).'$/i', $f)) {
+					$res[$prefix.$f] = $dir.'/'.$f;
+				}
 			}
 		}
Index: plugins/themeEditor/codemirror/multiplex.js
===================================================================
--- plugins/themeEditor/codemirror/multiplex.js	(revision 997)
+++ plugins/themeEditor/codemirror/multiplex.js	(revision 997)
@@ -0,0 +1,77 @@
+CodeMirror.multiplexingMode = function(outer /*, others */) {
+  // Others should be {open, close, mode [, delimStyle]} objects
+  var others = Array.prototype.slice.call(arguments, 1);
+  var n_others = others.length;
+
+  function indexOf(string, pattern, from) {
+    if (typeof pattern == "string") return string.indexOf(pattern, from);
+    var m = pattern.exec(from ? string.slice(from) : string);
+    return m ? m.index + from : -1;
+  }
+
+  return {
+    startState: function() {
+      return {
+        outer: CodeMirror.startState(outer),
+        innerActive: null,
+        inner: null
+      };
+    },
+
+    copyState: function(state) {
+      return {
+        outer: CodeMirror.copyState(outer, state.outer),
+        innerActive: state.innerActive,
+        inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
+      };
+    },
+
+    token: function(stream, state) {
+      if (!state.innerActive) {
+        var cutOff = Infinity, oldContent = stream.string;
+        for (var i = 0; i < n_others; ++i) {
+          var other = others[i];
+          var found = indexOf(oldContent, other.open, stream.pos);
+          if (found == stream.pos) {
+            stream.match(other.open);
+            state.innerActive = other;
+            state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
+            return other.delimStyle;
+          } else if (found != -1 && found < cutOff) {
+            cutOff = found;
+          }
+        }
+        if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
+        var outerToken = outer.token(stream, state.outer);
+        if (cutOff != Infinity) stream.string = oldContent;
+        return outerToken;
+      } else {
+        var curInner = state.innerActive, oldContent = stream.string;
+        var found = indexOf(oldContent, curInner.close, stream.pos);
+        if (found == stream.pos) {
+          stream.match(curInner.close);
+          state.innerActive = state.inner = null;
+          return curInner.delimStyle;
+        }
+        if (found > -1) stream.string = oldContent.slice(0, found);
+        var innerToken = curInner.mode.token(stream, state.inner);
+        if (found > -1) stream.string = oldContent;
+        var cur = stream.current(), found = cur.indexOf(curInner.close);
+        if (found > -1) stream.backUp(cur.length - found);
+        return innerToken;
+      }
+    },
+    
+    indent: function(state, textAfter) {
+      var mode = state.innerActive ? state.innerActive.mode : outer;
+      if (!mode.indent) return CodeMirror.Pass;
+      return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
+    },
+
+    electricChars: outer.electricChars,
+
+    innerMode: function(state) {
+      return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
+    }
+  };
+};
Index: plugins/themeEditor/help.html
===================================================================
--- plugins/themeEditor/help.html	(revision 100)
+++ plugins/themeEditor/help.html	(revision 989)
@@ -25,4 +25,6 @@
 <p>To help modify your templates, you may consult the <a href="http://doc.dotclear.net/2.0/resources/templates">template tag list</a>.</p>
 
+<p>Note: You can activate syntax coloration in your preferences (“My options” tab).</p>
+
 </body>
 </html>
Index: plugins/themeEditor/index.php
===================================================================
--- plugins/themeEditor/index.php	(revision 948)
+++ plugins/themeEditor/index.php	(revision 1036)
@@ -36,4 +36,6 @@
 		} elseif (!empty($_REQUEST['js'])) {
 			$file = $o->getFileContent('js',$_REQUEST['js']);
+		} elseif (!empty($_REQUEST['po'])) {
+			$file = $o->getFileContent('po',$_REQUEST['po']);
 		}
 	}
@@ -74,4 +76,5 @@
   <link rel="stylesheet" type="text/css" href="index.php?pf=themeEditor/codemirror.css" />
   <script type="text/JavaScript" src="index.php?pf=themeEditor/codemirror/codemirror.js"></script>
+  <script type="text/JavaScript" src="index.php?pf=themeEditor/codemirror/multiplex.js"></script>
   <script type="text/JavaScript" src="index.php?pf=themeEditor/codemirror/xml.js"></script>
   <script type="text/JavaScript" src="index.php?pf=themeEditor/codemirror/javascript.js"></script>
@@ -125,9 +128,26 @@
 
 	if ($user_ui_colorsyntax) {
-		$editorMode = (!empty($_REQUEST['css']) ? "css" : (!empty($_REQUEST['js']) ? "javascript" : "text/html"));
+		$editorMode = 
+			(!empty($_REQUEST['css']) ? "css" :
+			(!empty($_REQUEST['js']) ? "javascript" :
+			(!empty($_REQUEST['po']) ? "text/plain" : "text/html")));
 		echo 
 		'<script>
+			window.CodeMirror.defineMode("dotclear", function(config) {
+				return CodeMirror.multiplexingMode(
+					CodeMirror.getMode(config, "'.$editorMode.'"),
+					{open: "{{tpl:", close: "}}",
+					 mode: CodeMirror.getMode(config, "text/plain"),
+					 delimStyle: "delimit"},
+					{open: "<tpl:", close: ">",
+					 mode: CodeMirror.getMode(config, "text/plain"),
+					 delimStyle: "delimit"},
+					{open: "</tpl:", close: ">",
+					 mode: CodeMirror.getMode(config, "text/plain"),
+					 delimStyle: "delimit"}
+					);
+			});
 	    	var editor = CodeMirror.fromTextArea(document.getElementById("file_content"), {
-	    		mode: "'.$editorMode.'",
+	    		mode: "dotclear",
 	       		tabMode: "indent",
 	       		lineWrapping: "true",
@@ -151,4 +171,7 @@
 <h3><?php echo __('JavaScript files'); ?></h3>
 <?php echo $o->filesList('js','<a href="'.$p_url.'&amp;js=%2$s" class="js-link">%1$s</a>'); ?>
+
+<h3><?php echo __('Locales files'); ?></h3>
+<?php echo $o->filesList('po','<a href="'.$p_url.'&amp;po=%2$s" class="po-link">%1$s</a>'); ?>
 </div>
 
Index: plugins/widgets/_default_widgets.php
===================================================================
--- plugins/widgets/_default_widgets.php	(revision 954)
+++ plugins/widgets/_default_widgets.php	(revision 1063)
@@ -22,4 +22,5 @@
 $__widgets->search->setting('homeonly',__('Display on:'),0,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->search->setting('content_only',__('Content only'),0,'check');
 $__widgets->search->setting('class',__('CSS class:'),'');
 
@@ -28,4 +29,5 @@
 $__widgets->navigation->setting('homeonly',__('Display on:'),0,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->navigation->setting('content_only',__('Content only'),0,'check');
 $__widgets->navigation->setting('class',__('CSS class:'),'');
 
@@ -35,4 +37,5 @@
 $__widgets->bestof->setting('homeonly',__('Display on:'),1,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->bestof->setting('content_only',__('Content only'),0,'check');
 $__widgets->bestof->setting('class',__('CSS class:'),'');
 
@@ -41,4 +44,5 @@
 $__widgets->langs->setting('homeonly',__('Display on:'),1,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->langs->setting('content_only',__('Content only'),0,'check');
 $__widgets->langs->setting('class',__('CSS class:'),'');
 
@@ -48,4 +52,5 @@
 $__widgets->categories->setting('homeonly',__('Display on:'),0,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->categories->setting('content_only',__('Content only'),0,'check');
 $__widgets->categories->setting('class',__('CSS class:'),'');
 
@@ -55,4 +60,5 @@
 $__widgets->subscribe->setting('homeonly',__('Display on:'),1,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->subscribe->setting('content_only',__('Content only'),0,'check');
 $__widgets->subscribe->setting('class',__('CSS class:'),'');
 
@@ -63,4 +69,5 @@
 $__widgets->feed->setting('homeonly',__('Display on:'),1,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->feed->setting('content_only',__('Content only'),0,'check');
 $__widgets->feed->setting('class',__('CSS class:'),'');
 
@@ -70,4 +77,5 @@
 $__widgets->text->setting('homeonly',__('Display on:'),0,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->text->setting('content_only',__('Content only'),0,'check');
 $__widgets->text->setting('class',__('CSS class:'),'');
 
@@ -87,4 +95,5 @@
 $__widgets->lastposts->setting('homeonly',__('Display on:'),1,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->lastposts->setting('content_only',__('Content only'),0,'check');
 $__widgets->lastposts->setting('class',__('CSS class:'),'');
 
@@ -94,4 +103,5 @@
 $__widgets->lastcomments->setting('homeonly',__('Display on:'),1,'combo',
 	array(__('All pages') => 0, __('Home page only') => 1, __('Except on home page') => 2));
+$__widgets->lastcomments->setting('content_only',__('Content only'),0,'check');
 $__widgets->lastcomments->setting('class',__('CSS class:'),'');
 
Index: plugins/widgets/_widgets_functions.php
===================================================================
--- plugins/widgets/_widgets_functions.php	(revision 945)
+++ plugins/widgets/_widgets_functions.php	(revision 1063)
@@ -26,5 +26,5 @@
 		
 		return
-		'<div id="search"'.($w->class ? ' class="'.html::escapeHTML($w->class).'"' : '').'>'.
+		($w->content_only ? '' : '<div id="search"'.($w->class ? ' class="'.html::escapeHTML($w->class).'"' : '').'>').
 		($w->title ? '<h2><label for="q">'.html::escapeHTML($w->title).'</label></h2>' : '').
 		'<form action="'.$core->blog->url.'" method="get">'.
@@ -34,5 +34,5 @@
 		'</fieldset>'.
 		'</form>'.
-		'</div>';
+		($w->content_only ? '' : '</div>');
 	}
 	
@@ -47,5 +47,5 @@
 
 		$res =
-		'<div id="topnav"'.($w->class ? ' class="'.html::escapeHTML($w->class).'"' : '').'>'.
+		($w->content_only ? '' : '<div id="topnav"'.($w->class ? ' class="'.html::escapeHTML($w->class).'"' : '').'>').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -63,5 +63,5 @@
 		__('Archives').'</a></li>'.
 		'</ul>'.
-		'</div>';
+		($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -83,5 +83,5 @@
 		
 		$res =
-		'<div class="categories'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="categories'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '');
 		
@@ -117,5 +117,5 @@
 			$res .= str_repeat('</li></ul>',-($ref_level - $level));
 		}
-		$res .= '</div>';
+		$res .= ($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -144,5 +144,5 @@
 		
 		$res =
-		'<div class="selected'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="selected'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -152,5 +152,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -174,5 +174,5 @@
 		$langs = l10n::getISOcodes();
 		$res =
-		'<div class="langs'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="langs'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -193,5 +193,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -214,5 +214,5 @@
 		
 		$res =
-		'<div class="syndicate'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="syndicate'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -233,5 +233,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -263,5 +263,5 @@
 		
 		$res =
-		'<div class="feed'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="feed'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -288,5 +288,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -303,8 +303,8 @@
 		
 		$res =
-		'<div class="text'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="text'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		$w->text.
-		'</div>';
+		($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -350,5 +350,5 @@
 		
 		$res =
-		'<div class="lastposts'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		($w->content_only ? '' : '<div class="lastposts'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -359,5 +359,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
@@ -381,5 +381,5 @@
 		}
 		
-		$res = '<div class="lastcomments'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">'.
+		$res = ($w->content_only ? '' : '<div class="lastcomments'.($w->class ? ' '.html::escapeHTML($w->class) : '').'">').
 		($w->title ? '<h2>'.html::escapeHTML($w->title).'</h2>' : '').
 		'<ul>';
@@ -395,5 +395,5 @@
 		}
 		
-		$res .= '</ul></div>';
+		$res .= '</ul>'.($w->content_only ? '' : '</div>');
 		
 		return $res;
