From 0a30bcffc8c37c86f77090ed3121ff2279e47f74 Mon Sep 17 00:00:00 2001
From: mattpiwik <matthieu.aubry@gmail.com>
Date: Mon, 3 Sep 2007 19:38:09 +0000
Subject: [PATCH] DataTable ajax rendering, 30% done

git-svn-id: http://dev.piwik.org/svn/trunk@57 59fd770c-687e-43c8-a1e3-f5a4ff64c105
---
 MVC specification.php                         |   6 -
 config/config.ini.php                         |   1 +
 index.php                                     |  24 ----
 modules/API/Request.php                       |  88 +++++++++++---
 modules/Common.php                            |   4 +
 modules/DataTable/Filter/ColumnCallback.php   |   4 +-
 modules/DataTable/Renderer/PHP.php            |  17 ++-
 modules/FrontController.php                   |  29 ++++-
 plugins/ExamplePlugin/Controller.php          |  16 +++
 plugins/Home/Controller.php                   |   3 +-
 .../SitesManager/templates/SitesManager.js    |  67 +++++++++-
 .../SitesManager/templates/SitesManager.tpl   |   1 +
 plugins/UserSettings/Controller.php           |  59 +++++++++
 plugins/UserSettings/templates/datatable.tpl  |  36 ++++++
 plugins/UserSettings/templates/index.tpl      |  96 +++++++++++++++
 .../UsersManager/templates/UsersManager.js    | 114 ------------------
 .../UsersManager/templates/UsersManager.tpl   |   1 +
 themes/default/common.js                      |  52 ++++++++
 18 files changed, 447 insertions(+), 171 deletions(-)
 create mode 100644 plugins/ExamplePlugin/Controller.php
 create mode 100644 plugins/UserSettings/Controller.php
 create mode 100644 plugins/UserSettings/templates/datatable.tpl
 create mode 100644 plugins/UserSettings/templates/index.tpl
 create mode 100644 themes/default/common.js

diff --git a/MVC specification.php b/MVC specification.php
index 57684da146..7b4467c4a3 100644
--- a/MVC specification.php	
+++ b/MVC specification.php	
@@ -35,9 +35,3 @@ Use cases
 7 - Plugin that add a selection for every user
 ------------------------------------------------------------------------------------
 
-
-
-
-
-
-
diff --git a/config/config.ini.php b/config/config.ini.php
index d1ebc77470..ee0ae9750d 100755
--- a/config/config.ini.php
+++ b/config/config.ini.php
@@ -44,6 +44,7 @@ time_before_archive_considered_outdated = 3
 
 action_category_delimiter = /
 
+dataTable_default_limit = 10
 
 [LogStats]
 ; set to 0 if you want to stop tracking the visitors. Useful if you need to stop all the connections on the DB.
diff --git a/index.php b/index.php
index a8c5bbf893..0d5fbb2f94 100755
--- a/index.php
+++ b/index.php
@@ -26,30 +26,6 @@ require_once PIWIK_INCLUDE_PATH . "/modules/ExceptionHandler.php";
 set_error_handler('Piwik_ErrorHandler');
 set_exception_handler('Piwik_ExceptionHandler');
 
-/**
- * Zend classes
- */
-include "Zend/Exception.php";
-include "Zend/Loader.php";
-require_once "Zend/Debug.php";
-require_once "Zend/Auth.php";
-require_once "Zend/Auth/Adapter/DbTable.php";
-
-/**
- * Piwik classes
- */
-require_once "Timer.php";
-
-require_once "Piwik.php";
-
-require_once "API/APIable.php";
-require_once "Access.php";
-require_once "Auth.php";
-require_once "API/Proxy.php";
-require_once "Site.php";
-require_once "Translate.php";
-require_once "Url.php";
-require_once "Controller.php";
 require_once "FrontController.php";
 
 $controller = new Piwik_FrontController;
diff --git a/modules/API/Request.php b/modules/API/Request.php
index e13be15ae9..ee4a668fb6 100644
--- a/modules/API/Request.php
+++ b/modules/API/Request.php
@@ -30,12 +30,18 @@ class Piwik_API_Request
 	{
 		$requestArray = $_REQUEST;
 		
+		// If an array is specified we use it
 		if(!is_null($request))
 		{
 			$request = trim($request);
 			$request = str_replace(array("\n","\t"),'', $request);
 			parse_str($request, $requestArray);
+				
+			// but we handle the case when an array is specified but we also want
+			// to look for the value in the _REQUEST
+			$requestArray = array_merge( $_REQUEST, $requestArray);
 		}
+		
 		$this->requestToUse = $requestArray;
 	}
 	
@@ -131,7 +137,9 @@ class Piwik_API_Request
 				
 			}
 			
-			if(empty($toReturn))
+			
+			if(!is_array($toReturn) // an empty array is not considered as "nothing has been returned"
+				&& empty($toReturn))
 			{
 				$format = Piwik_Common::getRequestVar('format', 'xml', 'string', $this->requestToUse);
 				$toReturn = $this->getStandardSuccessOutput($format);
@@ -164,7 +172,11 @@ class Piwik_API_Request
 				$return = '{"result":"success", "message":"ok"}';
 			break;
 			case 'php':
-				$return = serialize(array('result' => 'success', 'message' => 'ok'));
+				$return = array('result' => 'success', 'message' => 'ok');
+				if($this->caseRendererPHPSerialize())
+				{
+					$return = serialize($return);
+				}
 			break;
 			default:
 				$return = 'Success:ok';
@@ -191,7 +203,11 @@ class Piwik_API_Request
 				$return = '{"result":"error", "message":"'.htmlentities($message).'"}';
 			break;
 			case 'php':
-				$return = serialize(array('result' => 'error', 'message' => $message));
+				$return = array('result' => 'error', 'message' => $message);
+				if($this->caseRendererPHPSerialize())
+				{
+					$return = serialize($return);
+				}
 			break;
 			default:
 				$return = 'Error:'.$message;
@@ -209,29 +225,38 @@ class Piwik_API_Request
 	{
 		// Renderer
 		$format = Piwik_Common::getRequestVar('format', 'php', 'string', $this->requestToUse);
+		
 		$renderer = Piwik_DataTable_Renderer::factory($format);
 		$renderer->setTable($dataTable);
 		
-		$toReturn = (string)$renderer;
+		
+		if($format == 'php')
+		{
+			$renderer->setSerialize( $this->caseRendererPHPSerialize());
+		}
+		
+		$toReturn = $renderer->render();
 		return $toReturn;
 	}
 	
-	/**
-	 * Applys generic filters to the DataTable object resulting from the API Call.
-	 * @return void
-	 */
-	protected function applyDataTableGenericFilters($dataTable)
+	
+	function caseRendererPHPSerialize()
+	{
+		$serialize = Piwik_Common::getRequestVar('serialize', 1, 'int', $this->requestToUse);
+		if($serialize)
+		{
+			return true;
+		}
+		else
+		{
+			return false;		
+		}
+	}
+	
+	public static function getGenericFiltersInformation()
 	{
-		
-		// Generic filters
-		// PatternFileName => Parameter names to match to constructor parameters
-		/*
-		 * Order to apply the filters:
-		 * 1 - Filter that remove filtered rows
-		 * 2 - Filter that sort the remaining rows
-		 * 3 - Filter that keep only a subset of the results
-		 */
 		$genericFilters = array(
+			
 			'Pattern' => array(
 								'filter_column' 			=> array('string'), 
 								'filter_pattern' 			=> array('string'),
@@ -245,11 +270,32 @@ class Piwik_API_Request
 								'filter_sort_order' 		=> array('string', 'desc'),
 						),
 			'Limit' => array(
-								'filter_offset' 			=> array('integer'),
-								'filter_limit' 				=> array('integer'),
+								'filter_offset' 			=> array('integer', '0'),
+								'filter_limit' 				=> array('integer', Zend_Registry::get('config')->General->dataTable_default_limit),
 						),
 		);
 		
+		return $genericFilters;
+	}
+	
+	
+	/**
+	 * Applys generic filters to the DataTable object resulting from the API Call.
+	 * @return void
+	 */
+	protected function applyDataTableGenericFilters($dataTable)
+	{
+		
+		// Generic filters
+		// PatternFileName => Parameter names to match to constructor parameters
+		/*
+		 * Order to apply the filters:
+		 * 1 - Filter that remove filtered rows
+		 * 2 - Filter that sort the remaining rows
+		 * 3 - Filter that keep only a subset of the results
+		 */
+		$genericFilters = Piwik_API_Request::getGenericFiltersInformation();
+		
 		foreach($genericFilters as $filterName => $parameters)
 		{
 			$filterParameters = array();
@@ -274,6 +320,7 @@ class Piwik_API_Request
 				}
 				catch(Exception $e)
 				{
+//					print($e->getMessage());
 					$exceptionRaised = true;
 					break;
 				}
@@ -281,6 +328,7 @@ class Piwik_API_Request
 			
 			if(!$exceptionRaised)
 			{
+//				var_dump($filterParameters);
 				assert(count($filterParameters)==count($parameters));
 				
 				// a generic filter class name must follow this pattern
diff --git a/modules/Common.php b/modules/Common.php
index 278a1dc878..ed12510905 100644
--- a/modules/Common.php
+++ b/modules/Common.php
@@ -181,6 +181,10 @@ class Piwik_Common
 			{
 					if(is_int($value) || $value==(int)$value) $ok = true;
 			}
+			elseif($varType == 'float')
+			{
+					if(is_float($value) || $value==(float)$value) $ok = true;
+			}
 			elseif($varType == 'array')
 			{
 					if(is_array($value)) $ok = true;
diff --git a/modules/DataTable/Filter/ColumnCallback.php b/modules/DataTable/Filter/ColumnCallback.php
index 6c2bb12c82..f01660d38b 100644
--- a/modules/DataTable/Filter/ColumnCallback.php
+++ b/modules/DataTable/Filter/ColumnCallback.php
@@ -22,7 +22,9 @@ class Piwik_DataTable_Filter_ColumnCallback extends Piwik_DataTable_Filter
 	{
 		foreach($this->table->getRows() as $key => $row)
 		{
-			if( !call_user_func( $this->function, $row->getColumn($this->columnToFilter)))
+			$columnValue = $row->getColumn($this->columnToFilter);
+			if( $columnValue !== false 
+				&& !call_user_func( $this->function, $columnValue))
 			{
 				$this->table->deleteRow($key);
 			}
diff --git a/modules/DataTable/Renderer/PHP.php b/modules/DataTable/Renderer/PHP.php
index 3708431fe2..96ffd534fb 100644
--- a/modules/DataTable/Renderer/PHP.php
+++ b/modules/DataTable/Renderer/PHP.php
@@ -13,7 +13,22 @@ class Piwik_DataTable_Renderer_PHP extends Piwik_DataTable_Renderer
 	function __construct($table = null, $serialize = true)
 	{
 		parent::__construct($table);
-		$this->serialize = $serialize;
+		$this->setSerialize($serialize);
+	}
+	
+	function setSerialize( $bool )
+	{
+		$this->serialize = $bool;
+	}
+	
+	function __toString()
+	{
+		$data = $this->render();
+		if(!is_string($data))
+		{
+			$data = serialize($data);
+		}
+		return $data;
 	}
 	
 	function render()
diff --git a/modules/FrontController.php b/modules/FrontController.php
index 6bacad7ac0..32f92b5e07 100644
--- a/modules/FrontController.php
+++ b/modules/FrontController.php
@@ -1,5 +1,30 @@
 <?php
 
+/**
+ * Zend classes
+ */
+include "Zend/Exception.php";
+include "Zend/Loader.php";
+require_once "Zend/Debug.php";
+require_once "Zend/Auth.php";
+require_once "Zend/Auth/Adapter/DbTable.php";
+
+/**
+ * Piwik classes
+ */
+require_once "Timer.php";
+
+require_once "Piwik.php";
+
+require_once "API/APIable.php";
+require_once "Access.php";
+require_once "Auth.php";
+require_once "API/Proxy.php";
+require_once "Site.php";
+require_once "Translate.php";
+require_once "Url.php";
+require_once "Controller.php";
+
 class Piwik_FrontController
 {
 	function dispatch()
@@ -27,6 +52,7 @@ class Piwik_FrontController
 					$controller->$action();
 				} catch(Piwik_Access_NoAccessException $e) {
 					Piwik::log("NO ACCESS EXCEPTION =>");
+					
 					Piwik_PostEvent('FrontController.NoAccessException', $e);					
 				}
 			}
@@ -37,9 +63,8 @@ class Piwik_FrontController
 		}
 		else
 		{
-			throw new Exception("Invalid module name");
+			throw new Exception("Invalid module name '$module'");
 		}
-		
 	}
 	
 	function end()
diff --git a/plugins/ExamplePlugin/Controller.php b/plugins/ExamplePlugin/Controller.php
new file mode 100644
index 0000000000..131f3767d8
--- /dev/null
+++ b/plugins/ExamplePlugin/Controller.php
@@ -0,0 +1,16 @@
+<?php
+
+class Piwik_ExamplePlugin_Controller extends Piwik_Controller
+{
+	function getDefaultAction()
+	{
+		return 'homepage';
+	}
+	
+	function homepage()
+	{
+		// invoke view
+		// render view
+		// do stuff...
+	}
+}
diff --git a/plugins/Home/Controller.php b/plugins/Home/Controller.php
index 9d79081f93..7e171b2e9c 100644
--- a/plugins/Home/Controller.php
+++ b/plugins/Home/Controller.php
@@ -434,8 +434,7 @@ function main()
 		&filter_limit=10
 		&filter_offset=0
 		&idSubtable=3090
-	'
-	);
+	');
 	dump(htmlentities($request->process()));
 	
 	
diff --git a/plugins/SitesManager/templates/SitesManager.js b/plugins/SitesManager/templates/SitesManager.js
index 5441680e88..26eb5e02f8 100644
--- a/plugins/SitesManager/templates/SitesManager.js
+++ b/plugins/SitesManager/templates/SitesManager.js
@@ -1,4 +1,70 @@
 
+function getDeleteSiteAJAX( idsite )
+{
+	var ajaxRequest = getStandardAjaxConf();
+	toggleAjaxLoading();
+		
+	// prepare the API parameters to update the user
+	var parameters = new Object;
+	parameters.module = 'API';
+	parameters.format = 'json';
+ 	parameters.method =  'SitesManager.deleteSite';
+ 	parameters.idSite = idsite;
+	
+	ajaxRequest.data = parameters;
+	
+	return ajaxRequest;
+}
+
+function getAddSiteAJAX( row )
+{
+	var ajaxRequest = getStandardAjaxConf();
+	toggleAjaxLoading();
+	
+	// prepare the API parameters to add the user
+	var parameters = new Object;
+	
+ 	var name = $(row).find('input[@id=siteadd_name]').val();
+ 	var urls =  $(row).find('textarea[@id=siteadd_urls]').val();
+	var aUrls = urls.trim().split("\n");
+ 	
+	var request = '';
+	request += '&module=API';
+	request += '&format=json';
+	request += '&method=SitesManager.addSite';
+	request += '&name='+escape(name);
+	
+	$.each(aUrls, function (key,value){ request+= '&aUrls[]='+escape(value);} );
+
+	ajaxRequest.data = request;
+ 	
+	return ajaxRequest;
+}
+
+function getUpdateSiteAJAX( row )
+{
+	var ajaxRequest = getStandardAjaxConf();
+	toggleAjaxLoading();
+	
+	var name = $(row).find('input[@id=name]').val();
+	var idSite = $(row).children('#idSite').html();
+	var aUrls = $(row).find('textarea[@id=aUrls]').val().trim().split("\n");
+	
+	var request = '';
+	request += '&module=API';
+	request += '&format=json';
+	request += '&method=SitesManager.updateSite';
+	request += '&name='+escape(name);
+	request += '&idSite='+idSite;
+	$.each(aUrls, function (key,value){ if(value.length>1) request+= '&aUrls[]='+value;} );
+
+	ajaxRequest.data = request;
+	
+	return ajaxRequest;
+
+}
+
+
 $('#addRowSite').click( function() {
 	ajaxHideError();
 	$(this).toggle();
@@ -94,7 +160,6 @@ function submitSiteOnEnter(e)
 	var key=e.keyCode || e.which;
 	if (key==13)
 	{
-	alert('ok');
 		$(this).parent().find('#updateSite').click();
 		$(this).find('#addsite').click();
 	}
diff --git a/plugins/SitesManager/templates/SitesManager.tpl b/plugins/SitesManager/templates/SitesManager.tpl
index 8e605078f5..1a464da140 100644
--- a/plugins/SitesManager/templates/SitesManager.tpl
+++ b/plugins/SitesManager/templates/SitesManager.tpl
@@ -16,6 +16,7 @@ textarea{
 </style>
 {/literal}
 <script type="text/javascript" src="libs/jquery/jquery.js"></script>
+<script type="text/javascript" src="themes/default/common.js"></script>
 
 <h2>Sites</h2>
 <div id="ajaxError" style="display:none"></div>
diff --git a/plugins/UserSettings/Controller.php b/plugins/UserSettings/Controller.php
new file mode 100644
index 0000000000..0b2cde80d4
--- /dev/null
+++ b/plugins/UserSettings/Controller.php
@@ -0,0 +1,59 @@
+<?php
+require_once "API/Request.php";
+class Piwik_UserSettings_Controller extends Piwik_Controller
+{	
+	function index()
+	{
+		$view = new Piwik_View('UserSettings/templates/index.tpl');
+		
+		$view->dataTableResolution = $this->getResolution(true);
+		
+		echo $view->render();		
+	}
+	
+	function getResolution( $fetch = false)
+	{
+		$request = new Piwik_API_Request('
+			method=UserSettings.getResolution
+			&format=php
+			&serialize=0
+		');
+		$data = $request->process();
+//		var_dump( $data );exit;
+		$view = new Piwik_View('UserSettings/templates/datatable.tpl');
+		$view->id 			= 'UserSettingsResolution';
+		$view->dataTable 	= $data;
+		
+		
+		$javascriptVariablesToSet = array();
+		
+		$genericFilters = Piwik_API_Request::getGenericFiltersInformation();
+		foreach($genericFilters as $filter)
+		{
+			foreach($filter as $filterVariableName => $filterInfo)
+			{
+				// if there is a default value for this filter variable we set it 
+				// so that it is propagated to the javascript
+				if(isset($filterInfo[1]))
+				{
+					$javascriptVariablesToSet[$filterVariableName] = $filterInfo[1];
+				}
+			}
+		}
+		
+		foreach($_GET as $name => $value)
+		{
+			$javascriptVariablesToSet[$name] = Piwik_Common::getRequestVar($name);
+		}
+		$javascriptVariablesToSet['action'] = substr(__METHOD__, strrpos(__METHOD__,':') + 1);
+		
+		$view->javascriptVariablesToSet = $javascriptVariablesToSet;
+		$rendered = $view->render();
+		
+		if($fetch)
+		{
+			return $rendered;
+		}
+		echo $rendered;
+	}
+}
diff --git a/plugins/UserSettings/templates/datatable.tpl b/plugins/UserSettings/templates/datatable.tpl
new file mode 100644
index 0000000000..a777a08d12
--- /dev/null
+++ b/plugins/UserSettings/templates/datatable.tpl
@@ -0,0 +1,36 @@
+<div id="{$id}" class="parentDiv">
+{if isset($dataTable.result) and $dataTable.result == 'error'}
+	{$dataTable.message} 
+{else}
+	<table border=1> 
+	<tr>
+		<td>Label</td>
+		<td>Visits</td>
+	</tr>
+	{foreach from=$dataTable item=row}
+	<tr>
+		<td>{$row.columns.label}</td>
+		<td>{$row.columns.nb_visits}</td>
+	</tr>
+	{/foreach}
+	</table>
+	
+	<a href="#" id="dataTablePrevious">&lt;</a>  <a href="#" id="dataTableNext">&gt;</a>
+	<br><a href="#" id="dataTableExcludeLowPopulation">Exclude low population</a>
+	
+	<script>
+	// to throw the ajax query we need
+	//- the API module+method
+	//- the offset / limit
+	//- the exclude filter
+	//- the sort filter
+	//- the pattern filter
+	
+	var requestVariables = new Object;
+	
+	{foreach from=$javascriptVariablesToSet key=name item=value}
+	requestVariables.{$name} 		= "{$value}";
+	{/foreach}
+	</script>
+{/if}
+</div>
\ No newline at end of file
diff --git a/plugins/UserSettings/templates/index.tpl b/plugins/UserSettings/templates/index.tpl
new file mode 100644
index 0000000000..e457d6694e
--- /dev/null
+++ b/plugins/UserSettings/templates/index.tpl
@@ -0,0 +1,96 @@
+
+<script type="text/javascript" src="libs/jquery/jquery.js"></script>
+<script type="text/javascript" src="themes/default/common.js"></script>
+{literal}
+<script>
+
+$(document).ready( bindDataTableEvent );
+
+function bindDataTableEvent()
+{ 
+	$('#dataTableExcludeLowPopulation').click(
+		function(){
+			addFilter('filter_excludelowpop', 2); // add filter on the visits column
+			addFilter('filter_excludelowpop_value', 400.0);
+			reloadAjaxDataTable();
+		}
+	);
+		
+//			'filter_column' 			=> array('string'), 
+//			'filter_pattern' 			=> array('string'),
+
+//			'filter_sort_column' 		=> array('string', Piwik_Archive::INDEX_NB_VISITS),
+//			'filter_sort_order' 		=> array('string', 'desc'),
+
+//			'filter_offset' 			=> array('integer'),
+//			'filter_limit' 				=> array('integer'),
+
+		
+	$('#dataTableNext').click(
+		function(){
+			addFilter('filter_offset', requestVariables.filter_offset + requestVariables.filter_limit); 
+			reloadAjaxDataTable();
+		}
+	);
+	$('#dataTablePrevious').click(
+		function(){
+			var offset = requestVariables.filter_offset - requestVariables.filter_limit;
+			if(offset < 0) { offset = 0; }
+			addFilter('filter_offset', offset); 
+			reloadAjaxDataTable();
+		}
+	);
+}
+function addFilter( nameVariable, value )
+{
+	requestVariables[nameVariable] = value;	
+}
+
+function dataTableLoaded( response )
+{
+	var idToReplace = $(response).attr('id');
+	$('#'+idToReplace).html(response);
+	
+	bindDataTableEvent();
+}
+function ajaxHandleError()
+{
+	alert('error!');
+}
+
+function getAjaxRequest()
+{
+	var ajaxRequest = new Object;
+
+	//prepare the ajax request
+	ajaxRequest.type = 'GET';
+	ajaxRequest.url = 'index.php';
+	ajaxRequest.dataType = 'html';
+	ajaxRequest.error = ajaxHandleError;
+	ajaxRequest.success = dataTableLoaded;
+
+//	$.each(requestVariables, function (key,value){ alert(key+' = '+value);  } );
+	ajaxRequest.data = requestVariables;
+	
+	return ajaxRequest;
+}
+function reloadAjaxDataTable()
+{
+	var request = getAjaxRequest();
+	$.ajax(request);
+}
+
+function toString( object )
+{
+	var str='';
+	$.each(object, function (key,value){ alert(key+' = '+value);  } );
+	return str; 
+}
+</script>
+{/literal}
+<h1>User Settings<h1>
+
+<h2>Resolutions</h2>
+{$dataTableResolution}
+<h2>Browsers</h2>
+{* ataTableBrowsers} *}
\ No newline at end of file
diff --git a/plugins/UsersManager/templates/UsersManager.js b/plugins/UsersManager/templates/UsersManager.js
index 98304a9c30..27e0c34c48 100644
--- a/plugins/UsersManager/templates/UsersManager.js
+++ b/plugins/UsersManager/templates/UsersManager.js
@@ -1,51 +1,5 @@
-function ajaxHandleError()
-{
-	alert('Transfer error, please reload the page or try again later.');
-}
-
-function ajaxShowError( string )
-{
-	$('#ajaxError').html(string).show();
-}
-function ajaxHideError()
-{
-	$('#ajaxError').hide();
-}
 
-function ajaxToggleLoading()
-{
-	$('#ajaxLoading').toggle();
-}
-function ajaxHandleResponse(response)
-{
-	if(response.result == "error") 
-	{
-		ajaxShowError(response.message);
-	}
-	else
-	{
-		window.location.reload();
-	}
-	ajaxToggleLoading();
-}
 
-function getStandardAjaxConf()
-{
-	var ajaxRequest = new Object;
-
-	//prepare the ajax request
-	ajaxRequest.type = 'GET';
-	ajaxRequest.url = 'index.php';
-	ajaxRequest.dataType = 'json';
-	ajaxRequest.error = ajaxHandleError;
-	ajaxRequest.success = ajaxHandleResponse;
-
-	return ajaxRequest;
-}
-function toggleAjaxLoading()
-{
-	$('#ajaxLoading').toggle();
-}
 function getUpdateUserAJAX( row )
 {
 	var ajaxRequest = getStandardAjaxConf();
@@ -172,74 +126,6 @@ function bindUpdateAccess()
 }
 
 
-function getDeleteSiteAJAX( idsite )
-{
-	var ajaxRequest = getStandardAjaxConf();
-	toggleAjaxLoading();
-		
-	// prepare the API parameters to update the user
-	var parameters = new Object;
-	parameters.module = 'API';
-	parameters.format = 'json';
- 	parameters.method =  'SitesManager.deleteSite';
- 	parameters.idSite = idsite;
-	
-	ajaxRequest.data = parameters;
-	
-	return ajaxRequest;
-}
-String.prototype.trim = function() {
-	return this.replace(/^\s+|\s+$/g,"");
-}
-
-function getAddSiteAJAX( row )
-{
-	var ajaxRequest = getStandardAjaxConf();
-	toggleAjaxLoading();
-	
-	// prepare the API parameters to add the user
-	var parameters = new Object;
-	
- 	var name = $(row).find('input[@id=siteadd_name]').val();
- 	var urls =  $(row).find('textarea[@id=siteadd_urls]').val();
-	var aUrls = urls.trim().split("\n");
- 	
-	var request = '';
-	request += '&module=API';
-	request += '&format=json';
-	request += '&method=SitesManager.addSite';
-	request += '&name='+escape(name);
-	
-	$.each(aUrls, function (key,value){ request+= '&aUrls[]='+escape(value);} );
-
-	ajaxRequest.data = request;
- 	
-	return ajaxRequest;
-}
-
-function getUpdateSiteAJAX( row )
-{
-	var ajaxRequest = getStandardAjaxConf();
-	toggleAjaxLoading();
-	
-	var name = $(row).find('input[@id=name]').val();
-	var idSite = $(row).children('#idSite').html();
-	var aUrls = $(row).find('textarea[@id=aUrls]').val().trim().split("\n");
-	
-	var request = '';
-	request += '&module=API';
-	request += '&format=json';
-	request += '&method=SitesManager.updateSite';
-	request += '&name='+escape(name);
-	request += '&idSite='+idSite;
-	$.each(aUrls, function (key,value){ request+= '&aUrls[]='+value;} );
-
-	ajaxRequest.data = request;
-	
-	return ajaxRequest;
-
-}
-
 var alreadyEdited = new Array;
 // when click on edituser, the cells become editable
 $('.edituser')
diff --git a/plugins/UsersManager/templates/UsersManager.tpl b/plugins/UsersManager/templates/UsersManager.tpl
index f8b43eb71b..727274d15b 100644
--- a/plugins/UsersManager/templates/UsersManager.tpl
+++ b/plugins/UsersManager/templates/UsersManager.tpl
@@ -1,4 +1,5 @@
 <script type="text/javascript" src="libs/jquery/jquery.js"></script>
+<script type="text/javascript" src="themes/default/common.js"></script>
 
 {literal}
 
diff --git a/themes/default/common.js b/themes/default/common.js
new file mode 100644
index 0000000000..162f637329
--- /dev/null
+++ b/themes/default/common.js
@@ -0,0 +1,52 @@
+function ajaxHandleError()
+{
+	alert('Transfer error, please reload the page or try again later.');
+}
+
+function ajaxShowError( string )
+{
+	$('#ajaxError').html(string).show();
+}
+function ajaxHideError()
+{
+	$('#ajaxError').hide();
+}
+
+function ajaxToggleLoading()
+{
+	$('#ajaxLoading').toggle();
+}
+function ajaxHandleResponse(response)
+{
+	if(response.result == "error") 
+	{
+		ajaxShowError(response.message);
+	}
+	else
+	{
+		window.location.reload();
+	}
+	ajaxToggleLoading();
+}
+function toggleAjaxLoading()
+{
+	$('#ajaxLoading').toggle();
+}
+
+String.prototype.trim = function() {
+	return this.replace(/^\s+|\s+$/g,"");
+}
+
+function getStandardAjaxConf()
+{
+	var ajaxRequest = new Object;
+
+	//prepare the ajax request
+	ajaxRequest.type = 'GET';
+	ajaxRequest.url = 'index.php';
+	ajaxRequest.dataType = 'json';
+	ajaxRequest.error = ajaxHandleError;
+	ajaxRequest.success = ajaxHandleResponse;
+
+	return ajaxRequest;
+}
\ No newline at end of file
-- 
GitLab