diff --git a/core/ViewDataTable/HtmlTable.php b/core/ViewDataTable/HtmlTable.php
index 1be90bb670e71743698fdbbf87b7891fa00f752c..0301efd5e3deba78f59ab390953a5d665d6175a4 100644
--- a/core/ViewDataTable/HtmlTable.php
+++ b/core/ViewDataTable/HtmlTable.php
@@ -223,6 +223,6 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
 	 */
 	public function disableRowEvolution()
 	{
-		$this->viewProperties['disable_row_evolution'] = true;
+		$this->variablesDefault['disable_row_evolution'] = true;
 	}
 }
diff --git a/plugins/CoreHome/templates/datatable.css b/plugins/CoreHome/templates/datatable.css
index 67a44de37bcc47debd2f9a90858e433b278bdd5a..dec1aa899ecdfb9cb6e9401a87a4284794d47f24 100644
--- a/plugins/CoreHome/templates/datatable.css
+++ b/plugins/CoreHome/templates/datatable.css
@@ -584,7 +584,6 @@ table.dataTable .dataTableRowActions {
 	display: none;
 	overflow: hidden;
 	margin-top: -5px;
-	width: 40px;
 }
 *+html table.dataTable .dataTableRowActions {
 	margin-top: -7px;
@@ -601,6 +600,8 @@ table.dataTable .dataTableRowActions a img {
 	margin: 0;
 	padding: 0;
 	border: 0;
+	width: 20px;
+	height: 17px;
 }
 
 
diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js
index 4d28d5fb4221d0f56902dad3aa24d465f043aa23..1355d86cee6ec480f0d2ee049a086daf28bb60c4 100644
--- a/plugins/CoreHome/templates/datatable.js
+++ b/plugins/CoreHome/templates/datatable.js
@@ -1244,61 +1244,83 @@ dataTable.prototype =
 		trs.each(function()
 		{
 			var tr = $(this);
-			var actions = tr.find('div.dataTableRowActions');
-			if (actions.size() == 0)
+			var td = tr.find('td:first');
+			
+			// load available actions for this row
+			var availableActions = DataTable_RowActions_Registry.getAvailableActions(self.param, tr);
+			if (availableActions.length == 0)
 			{
-				return true;
+				return;
 			}
 			
-			// move before image in actions data table
-			if (actions.prev().size() > 0)
+			// call initTr on all available actions
+			for (var i = 0; i < availableActions.length; i++)
 			{
-				actions.prev().before(actions);
+				var action = availableActions[i];
+				if (typeof actionInstances[action.name] == "undefined")
+				{
+					actionInstances[action.name] = action.createInstance(self);
+				}
+				var actionInstance = actionInstances[action.name];
+				actionInstance.initTr(tr);
 			}
 			
 			// show actions on hover
+			var actionsDom = null;
 			tr.hover(function()
 			{
-				self.repositionRowActions($(this));
-				actions.show();
+				if (actionsDom === null)
+				{
+					// create dom nodes on the fly
+					actionsDom = self.createRowActions(availableActions, tr, actionInstances);
+					td.prepend(actionsDom);
+				}
+				// reposition and show the actions
+				self.repositionRowActions(tr);
+				actionsDom.show();
 			},
 			function()
 			{
-				actions.hide();
+				if (actionsDom !== null)
+				{
+					actionsDom.hide();
+				}
 			});
+		});
+	},
+	
+	createRowActions: function(availableActions, tr, actionInstances)
+	{
+		var container = $(document.createElement('div')).addClass('dataTableRowActions');
+		
+		for (var i = 0; i < availableActions.length; i++)
+		{
+			var action = availableActions[i];
+			
+			var actionEl = $(document.createElement('a')).attr({href: '#'}).addClass('action' + action.name);
+			actionEl.append($(document.createElement('img')).attr({src: action.dataTableIcon}));
+			container.append(actionEl);
 			
-			// handle the individual actions
-			actions.find('> a').each(function()
+			actionEl.click((function(action)
 			{
-				var a = $(this);
-				var className = a.attr('class');
-				if (className.substring(0, 6) == 'action')
+				return function(e)
 				{
-					var actionName = className.substring(6, className.length);
-					if (typeof actionInstances[actionName] == "undefined")
-					{
-						actionInstances[actionName] = DataTable_RowActions_Factory(actionName, self);
-					}
-					var action = actionInstances[actionName];
-					action.initTr(tr);
-					
-					a.click(function(e)
-					{
-						$(this).blur();
-						actions.hide();
-						action.trigger(tr, e);
-						return false;
-					});
+					$(this).blur();
+					container.hide();
+					actionInstances[action.name].trigger(tr, e);
+					return false;
 				}
-			});
-		});
+			})(action));
+		}
+		
+		return container;
 	},
 	
 	repositionRowActions: function(tr) {
 		var td = tr.find('td:first');
 		var actions = tr.find('div.dataTableRowActions');
-		actions.height(tr.innerHeight() - 2)
-			.css('marginLeft', (td.width() + 5 - actions.outerWidth())+'px');
+		actions.height(tr.innerHeight() - 2);
+		actions.css('marginLeft', (td.width() + 5 - actions.outerWidth()) + 'px');
 	},
 	
 	_findReportHeader: function(domElem) {
@@ -1356,6 +1378,7 @@ actionDataTable.prototype =
 	handleColumnDocumentation: dataTable.prototype.handleColumnDocumentation,
 	handleReportDocumentation: dataTable.prototype.handleReportDocumentation,
 	doHandleRowActions: dataTable.prototype.doHandleRowActions,
+	createRowActions: dataTable.prototype.createRowActions,
 	repositionRowActions: dataTable.prototype.repositionRowActions,
 	onClickSort: dataTable.prototype.onClickSort,
 	truncate: dataTable.prototype.truncate,
diff --git a/plugins/CoreHome/templates/datatable_cell.tpl b/plugins/CoreHome/templates/datatable_cell.tpl
index a4f335a0a111f983872c96f6701775c6b9b36383..bde9569505b8805b4088196f29cfc6309d25ad89 100644
--- a/plugins/CoreHome/templates/datatable_cell.tpl
+++ b/plugins/CoreHome/templates/datatable_cell.tpl
@@ -1,12 +1,3 @@
-{if $column=='label'}
-	<div class="dataTableRowActions">
-		{if (!isset($properties.disable_row_evolution) || $properties.disable_row_evolution === false)
-				&& !(isset($javascriptVariablesToSet.flat) && $javascriptVariablesToSet.flat == 1)}
-			<a href="#" class="actionRowEvolution"><img src="themes/default/images/row_evolution.png" alt="" /></a>
-		{/if}
-	</div>
-{/if}
-
 {if !$row.idsubdatatable && $column=='label' && !empty($row.metadata.url)}
 <a target="_blank" href='{if !in_array(substr($row.metadata.url,0,4), array('http','ftp:'))}http://{/if}{$row.metadata.url|escape:'html'}'>
 	{if empty($row.metadata.logo)}
diff --git a/plugins/CoreHome/templates/datatable_rowactions.js b/plugins/CoreHome/templates/datatable_rowactions.js
index 15c635fe4206157690c86d0ec13efcb7f1905093..57d2b2dc78298aee8728162a7e00501b3e82aacb 100644
--- a/plugins/CoreHome/templates/datatable_rowactions.js
+++ b/plugins/CoreHome/templates/datatable_rowactions.js
@@ -1,5 +1,63 @@
 /**
- * DataTable RowActions
+ * Registry for row actions
+ * 
+ * Plugins can call DataTable_RowActions_Registry.register() from their JS
+ * files in order to add new actions to arbitrary data tables. The register()
+ * method takes an object containing:
+ * - name: string identifying the action. must be short, no spaces.
+ * - dataTableIcon: path to the icon for the action
+ * - createInstance: a factory method to create an instance of the appropriate
+ *                   subclass of DataTable_RowAction
+ * - isAvailable: a method to determine whether the action is available in a
+ *                given row of a data table
+ */
+var DataTable_RowActions_Registry = {
+	
+	registry: [],
+	
+	register: function(action) {
+		this.registry.push(action);
+	},
+	
+	getAvailableActions: function(dataTableParams, tr) {
+		var available = [];
+		for (var i = 0; i < this.registry.length; i++) {
+			if (this.registry[i].isAvailable(dataTableParams, tr)) {
+				available.push(this.registry[i]);
+			}
+		}
+		return available;
+	}
+	
+};
+
+// Register Row Evolution (also servers as example)
+DataTable_RowActions_Registry.register({
+	
+	name: 'RowEvolution',
+	
+	dataTableIcon: 'themes/default/images/row_evolution.png',
+	
+	createInstance: function(dataTable) {
+		return new DataTable_RowActions_RowEvolution(dataTable);
+	},
+	
+	isAvailable: function(dataTableParams, tr) {
+		return (
+			typeof dataTableParams.disable_row_evolution == 'undefined'
+			|| dataTableParams.disable_row_evolution == "0"
+		) && (
+			typeof dataTableParams.flat == 'undefined'
+			|| dataTableParams.flat == "0"
+		);
+	}
+
+});
+
+
+
+/**
+ * DataTable Row Actions
  *
  * The lifecycle of an action is as follows:
  * - for each data table, a new instance of the action is created using the factory
@@ -13,19 +71,6 @@
  */
 
 
-/**
- * Factory function for creating action instances dynamically.
- * It's designed to decouple the row actions from the data table code.
- * Also, custom actions can be added more easily this way.
- */
-function DataTable_RowActions_Factory(actionName, dataTable) {
-	var className = 'DataTable_RowActions_' + actionName;
-	eval('if (typeof ' + className + ' == "undefined") alert("Invalid action: ' + className + '");' +
-		'var instance = new ' + className + '(dataTable)');
-	return instance;
-}
-
-
 //
 // BASE CLASS
 //