From 4c28d9c34f5f3e5ccbbed6dbb0ba08bc5235b53b Mon Sep 17 00:00:00 2001
From: ftimme <ft@falkotimme.com>
Date: Thu, 10 May 2012 16:24:12 +0000
Subject: [PATCH] - Added global search (FS#2210, FS#2146).

---
 interface/lib/classes/functions.inc.php       |  40 ++++
 interface/web/capp.php                        |  11 +-
 interface/web/client/form/client.tform.php    |  44 ++--
 interface/web/dashboard/ajax_get_json.php     | 197 ++++++++++++++++++
 interface/web/dns/form/dns_slave.tform.php    |  11 +-
 interface/web/dns/form/dns_soa.tform.php      |  14 +-
 interface/web/js/jquery.ispconfigsearch.js    | 156 ++++++++++++++
 interface/web/js/scrigo.js.php                |   4 +-
 interface/web/mail/form/mail_domain.tform.php |   8 +-
 interface/web/mail/form/mail_user.tform.php   |  11 +-
 interface/web/sites/ajax_get_json.php         |   2 +-
 interface/web/sites/form/database.tform.php   |  14 +-
 interface/web/sites/form/ftp_user.tform.php   |   8 +-
 interface/web/sites/form/shell_user.tform.php |   8 +-
 interface/web/sites/form/web_domain.tform.php |  17 +-
 .../default/css/screen/content_ispc.css       | 130 +++++++++++-
 .../web/themes/default/icons/x16/loading.gif  | Bin 0 -> 1460 bytes
 .../web/themes/default/templates/main.tpl.htm |   7 +
 interface/web/vm/form/openvz_ip.tform.php     |   8 +-
 .../web/vm/form/openvz_ostemplate.tform.php   |  14 +-
 .../web/vm/form/openvz_template.tform.php     |  11 +-
 interface/web/vm/form/openvz_vm.tform.php     |  14 +-
 22 files changed, 685 insertions(+), 44 deletions(-)
 create mode 100644 interface/web/dashboard/ajax_get_json.php
 create mode 100644 interface/web/js/jquery.ispconfigsearch.js
 create mode 100644 interface/web/themes/default/icons/x16/loading.gif

diff --git a/interface/lib/classes/functions.inc.php b/interface/lib/classes/functions.inc.php
index b744e35688..2fe7191181 100644
--- a/interface/lib/classes/functions.inc.php
+++ b/interface/lib/classes/functions.inc.php
@@ -109,6 +109,46 @@ class functions {
 		return $url;
 	}
 	
+    function json_encode($data) {
+		if(!function_exists('json_encode')){
+			switch ($type = gettype($data)){
+				case 'NULL':
+					return 'null';
+				case 'boolean':
+					return ($data ? 'true' : 'false');
+				case 'integer':
+				case 'double':
+				case 'float':
+					return $data;
+				case 'string':
+					return '"' . addslashes($data) . '"';
+				case 'object':
+					$data = get_object_vars($data);
+				case 'array':
+					$output_index_count = 0;
+					$output_indexed = array();
+					$output_associative = array();
+					foreach($data as $key => $value){
+						$output_indexed[] = $this->json_encode($value);
+						$output_associative[] = $this->json_encode($key) . ':' . $this->json_encode($value);
+						if($output_index_count !== NULL && $output_index_count++ !== $key){
+							$output_index_count = NULL;
+						}
+					}
+					if($output_index_count !== NULL){
+						return '[' . implode(',', $output_indexed) . ']';
+					} else {
+						return '{' . implode(',', $output_associative) . '}';
+					}
+				default:
+					return ''; // Not supported
+			}
+		} else {
+			return json_encode($data);
+		}
+    }
+
+	
 		
 }
 
diff --git a/interface/web/capp.php b/interface/web/capp.php
index 63177341d1..4512391988 100644
--- a/interface/web/capp.php
+++ b/interface/web/capp.php
@@ -33,6 +33,8 @@ require_once('../lib/app.inc.php');
 
 //* Import module variable
 $mod = $_REQUEST["mod"];
+//* If we click on a search result, load that one instead of the module's start page
+$redirect = (isset($_REQUEST["redirect"]) ? $_REQUEST["redirect"] : '');
 
 //* Check if user is logged in
 if($_SESSION["s"]["user"]['active'] != 1) {
@@ -40,6 +42,8 @@ if($_SESSION["s"]["user"]['active'] != 1) {
 	//die();
 }
 
+if(!preg_match("/^[a-z]{2,20}$/i", $mod)) die('module name contains unallowed chars.');
+
 //* Check if user may use the module.
 $user_modules = explode(",",$_SESSION["s"]["user"]["modules"]);
 
@@ -50,7 +54,12 @@ if(is_file($mod."/lib/module.conf.php")) {
 	include_once($mod."/lib/module.conf.php");
 	$_SESSION["s"]["module"] = $module;
 	session_write_close();
-	echo "HEADER_REDIRECT:".$_SESSION["s"]["module"]["startpage"];
+	if($redirect == ''){
+		echo "HEADER_REDIRECT:".$_SESSION["s"]["module"]["startpage"];
+	} else {
+		//* If we click on a search result, load that one instead of the module's start page
+		echo "HEADER_REDIRECT:".$redirect;
+	}
 } else {
 	$app->error($app->lng(302));
 }
diff --git a/interface/web/client/form/client.tform.php b/interface/web/client/form/client.tform.php
index 85b867104f..3fca605ef9 100644
--- a/interface/web/client/form/client.tform.php
+++ b/interface/web/client/form/client.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -90,7 +95,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'contact_name' => array (
 			'datatype'	=> 'VARCHAR',
@@ -104,7 +110,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 1
 		),
 		'customer_no' => array (
 			'datatype'	=> 'VARCHAR',
@@ -115,7 +122,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'username' => array (
 			'datatype'	=> 'VARCHAR',
@@ -136,7 +144,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'password' => array (
 			'datatype'	=> 'VARCHAR',
@@ -181,7 +190,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'zip' => array (
 			'datatype'	=> 'VARCHAR',
@@ -192,7 +202,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '10',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'city' => array (
 			'datatype'	=> 'VARCHAR',
@@ -203,7 +214,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'state' => array (
 			'datatype'	=> 'VARCHAR',
@@ -214,7 +226,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'country' => array (
 			'datatype'	=> 'VARCHAR',
@@ -237,7 +250,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'mobile' => array (
 			'datatype'	=> 'VARCHAR',
@@ -248,7 +262,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'fax' => array (
 			'datatype'	=> 'VARCHAR',
@@ -259,7 +274,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'email' => array (
 			'datatype'	=> 'VARCHAR',
@@ -270,7 +286,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'internet' => array (
 			'datatype'	=> 'VARCHAR',
@@ -281,7 +298,8 @@ $form["tabs"]['address'] = array (
 			'width'		=> '30',
 			'maxlength'	=> '255',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 2
 		),
 		'icq' => array (
 			'datatype'	=> 'VARCHAR',
diff --git a/interface/web/dashboard/ajax_get_json.php b/interface/web/dashboard/ajax_get_json.php
new file mode 100644
index 0000000000..18cd1e45e8
--- /dev/null
+++ b/interface/web/dashboard/ajax_get_json.php
@@ -0,0 +1,197 @@
+<?php
+
+/*
+Copyright (c) 2012, ISPConfig UG
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once('../../lib/config.inc.php');
+require_once('../../lib/app.inc.php');
+
+//* Check permissions for module
+$app->auth->check_module_permissions('dashboard');
+
+$app->uses('tform');
+
+$type = $_GET["type"];
+
+//if($_SESSION["s"]["user"]["typ"] == 'admin') {
+
+	
+	if($type == 'globalsearch'){
+		$q = $app->db->quote($_GET["q"]);
+		$authsql = " AND ".$app->tform->getAuthSQL('r');
+		$modules = explode(',', $_SESSION['s']['user']['modules']);
+		
+		// clients
+		$result_clients = _search('client', 'client');
+		
+		// web sites
+		$result_webs = _search('sites', 'web_domain');
+		
+		// FTP users
+		$result_ftp_users = _search('sites', 'ftp_user');
+		
+		// shell users
+		$result_shell_users = _search('sites', 'shell_user');
+		
+		// databases
+		/*
+		$result_databases = array('cheader' => array(), 'cdata' => array());
+		if(in_array('sites', $modules)){
+			$sql = "SELECT * FROM web_database WHERE database_name LIKE '%".$q."%' OR database_user LIKE '%".$q."%' OR remote_ips LIKE '%".$q."%'".$authsql." ORDER BY database_name";
+			$results = $app->db->queryAllRecords($sql);
+
+			if(is_array($results) && !empty($results)){	
+				$result_databases['cheader'] = array('title' => 'Databases',
+														'total' => count($results),
+														'limit' => count($results)
+													);
+				foreach($results as $result){
+					$description = 'Database User: '.$result['database_user'].' - Remote IPs: '.$result['remote_ips'];
+					$result_databases['cdata'][] = array('title' => $result['database_name'],
+												'description' => $description,
+												'onclick' => 'capp(\'sites\',\'sites/database_edit.php?id='.$result['database_id'].'\');',
+												'fill_text' => strtolower($result['database_name'])
+												);
+				}	
+			}
+		}
+		*/
+		$result_databases = _search('sites', 'database');
+		
+		// email domains
+		$result_email_domains = _search('mail', 'mail_domain');
+		
+		// email mailboxes
+		$result_email_mailboxes = _search('mail', 'mail_user');
+		
+		// dns zones
+		$result_dns_zones = _search('dns', 'dns_soa');
+		
+		// secondary dns zones
+		$result_secondary_dns_zones = _search('dns', 'dns_slave');
+		
+		// virtual machines
+		$result_vms = _search('vm', 'openvz_vm');
+		
+		// virtual machines os templates
+		$result_vm_ostemplates = _search('vm', 'openvz_ostemplate');
+		
+		// virtual machines vm templates
+		$result_vm_vmtemplates = _search('vm', 'openvz_template');
+		
+		// virtual machines ip addresses
+		$result_vm_ip_addresses = _search('vm', 'openvz_ip');
+
+		$json = $app->functions->json_encode(array($result_clients, $result_webs, $result_ftp_users, $result_shell_users, $result_databases, $result_email_domains, $result_email_mailboxes, $result_dns_zones, $result_secondary_dns_zones, $result_vms, $result_vm_ostemplates, $result_vm_vmtemplates, $result_vm_ip_addresses));
+	}
+
+//}
+
+function _search($module, $section){
+	global $app, $q, $authsql, $modules;
+	//$q = $app->db->quote($_GET["q"]);
+	//$authsql = " AND ".$app->tform->getAuthSQL('r');
+	//$user_modules = explode(',', $_SESSION['s']['user']['modules']);
+
+	$result_array = array('cheader' => array(), 'cdata' => array());
+	if(in_array($module, $modules)){
+		$search_fields = array();
+		$desc_fields = array();
+		if(is_file('../'.$module.'/form/'.$section.'.tform.php')){
+			include_once('../'.$module.'/form/'.$section.'.tform.php');
+			
+			$category_title = $form["title"];
+			$form_file = $form["action"];
+			$db_table = $form["db_table"];
+			$db_table_idx = $form["db_table_idx"];
+			$order_by = $db_table_idx;
+			
+			if(is_array($form["tabs"]) && !empty($form["tabs"])){
+				foreach($form["tabs"] as $tab){
+					if(is_array($tab['fields']) && !empty($tab['fields'])){
+						foreach($tab['fields'] as $key => $val){
+							if(isset($val['searchable']) && $val['searchable'] > 0){
+								$search_fields[] = $key." LIKE '%".$q."%'";
+								if($val['searchable'] == 1){
+									$order_by = $key;
+									$title_key = $key;
+								}
+								if($val['searchable'] == 2){
+									$desc_fields[] = $key;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		unset($form);
+		
+		$where_clause = '';
+		if(!empty($search_fields)){
+			$where_clause = implode(' OR ', $search_fields);
+		} else {
+			// valid SQL query which returns an empty result set
+			$where_clause = '1 = 0';
+		}
+		$order_clause = '';
+		if($order_by != '') $order_clause = ' ORDER BY '.$order_by;
+		
+		$results = $app->db->queryAllRecords("SELECT * FROM ".$db_table." WHERE ".$where_clause.$authsql.$order_clause);
+		
+		if(is_array($results) && !empty($results)){	
+			$lng_file = '../'.$module.'/lib/lang/'.$_SESSION['s']['language'].'_'.$section.'.lng';
+			if(is_file($lng_file)) include($lng_file);
+			$result_array['cheader'] = array('title' => $category_title,
+											'total' => count($results),
+											'limit' => count($results)
+											);
+			foreach($results as $result){
+				$description = '';
+				if(!empty($desc_fields)){
+					$desc_items = array();
+					foreach($desc_fields as $desc_field){
+						if($result[$desc_field] != '') $desc_items[] = $wb[$desc_field.'_txt'].': '.$result[$desc_field];
+					}
+					if(!empty($desc_items)) $description = implode(' - ', $desc_items);
+				}
+				
+				$result_array['cdata'][] = array('title' => $wb[$title_key.'_txt'].': '.$result[$title_key],
+												'description' => $description,
+												'onclick' => "capp('".$module."','".$module."/".$form_file."?id=".$result[$db_table_idx]."');",
+												'fill_text' => strtolower($result[$title_key])
+												);
+			}	
+		}
+	}
+	return $result_array;
+}
+		
+header('Content-type: application/json');
+echo $json;
+?>
\ No newline at end of file
diff --git a/interface/web/dns/form/dns_slave.tform.php b/interface/web/dns/form/dns_slave.tform.php
index 097602e8e5..a1dea941fc 100644
--- a/interface/web/dns/form/dns_slave.tform.php
+++ b/interface/web/dns/form/dns_slave.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -88,7 +93,8 @@ $form["tabs"]['dns_slave'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'ns' => array (
 			'datatype'	=> 'VARCHAR',
@@ -100,7 +106,8 @@ $form["tabs"]['dns_slave'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
                 'xfer' => array (
                         'datatype'      => 'VARCHAR',
diff --git a/interface/web/dns/form/dns_soa.tform.php b/interface/web/dns/form/dns_soa.tform.php
index 53b408ef3a..c102e126fc 100644
--- a/interface/web/dns/form/dns_soa.tform.php
+++ b/interface/web/dns/form/dns_soa.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -88,7 +93,8 @@ $form["tabs"]['dns_soa'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'ns' => array (
 			'datatype'	=> 'VARCHAR',
@@ -100,7 +106,8 @@ $form["tabs"]['dns_soa'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
 		'mbox' => array (
 			'datatype'	=> 'VARCHAR',
@@ -114,7 +121,8 @@ $form["tabs"]['dns_soa'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
 		'serial' => array (
 			'datatype'	=> 'INTEGER',
diff --git a/interface/web/js/jquery.ispconfigsearch.js b/interface/web/js/jquery.ispconfigsearch.js
new file mode 100644
index 0000000000..211dcd76dc
--- /dev/null
+++ b/interface/web/js/jquery.ispconfigsearch.js
@@ -0,0 +1,156 @@
+/*
+Copyright (c) 2012, ISPConfig UG
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+(function($) {
+	$.fn.ispconfigSearch = function(settings){
+
+		var defaultSettings = {
+			dataSrc: '',
+			timeout: 500,
+			minChars: 2,
+			resultBox: '-resultbox',
+			cssPrefix: 'gs-',
+			fillSearchField: false,
+			fillSearchFieldWith: 'title',
+			resultsText: '$ of % results',
+			noResultsText: 'No results.',
+			displayEmptyCategories: false,
+			runJS: true
+		};
+		
+		var previousQ = '';
+		var data;
+		var settings = $.extend(defaultSettings, settings);
+		settings.resultBox = $(this).attr('id')+settings.resultBox;
+		
+		$(this).attr('autocomplete', 'off');
+		$(this).wrap('<div class="'+settings.cssPrefix+'container" />');
+		$(this).after('<ul id="'+settings.resultBox+'" class="'+settings.cssPrefix+'resultbox" style="display:none;"></ul>');
+		var searchField = $(this);
+		var resultBox = $('#'+settings.resultBox);
+
+		var timeout = null;
+		searchField.keyup(function(event) {
+			// 13 = enter, 9 = tab
+			if (event.keyCode != 13 && event.keyCode != 9){
+				// query value
+				var q = searchField.val();
+				
+				if (settings.minChars > q.length || q == ''){
+					resultBox.fadeOut();
+					resetTimer(timeout);
+				} else {
+					if (timeout != null){
+						resetTimer(timeout);
+					}
+					
+					timeout = setTimeout(function(){
+						searchField.addClass(settings.cssPrefix+'loading');
+
+						// we don't have to perform a new search if the query equals the previous query
+						previousQ = q;
+						var queryStringCombinator = '?';
+						if(settings.dataSrc.indexOf('?') != -1){
+							queryStringCombinator = '&';
+						}
+						$.getJSON(settings.dataSrc+queryStringCombinator+"q="+q, function(data, textStatus){
+							if (textStatus == 'success'){
+								var output = '';
+								var resultsFound = false;
+
+								if($.isEmptyObject(data) === false){
+									$.each(data, function(i, category){
+										if (category['cdata'].length > 0){
+											resultsFound = true;
+										}
+									});
+								}
+
+								if (!resultsFound){
+									output += '<li class="'+settings.cssPrefix+'cheader"><p class="'+settings.cssPrefix+'cheader-title">'+settings.noResultsText+'</p><p class="'+settings.cssPrefix+'cheader-limit">0 results</p></li>';
+								} else {
+								
+									$.each(data, function(i, category){
+										
+										if (settings.displayEmptyCategories || (!settings.displayEmptyCategories && category['cdata'].length != 0)){
+											var limit = category['cheader']['limit'];
+											var cnt = 0;
+
+											output += '<li class="'+settings.cssPrefix+'cheader"><p class="'+settings.cssPrefix+'cheader-title">'+category['cheader']['title']+'</p><p class="'+settings.cssPrefix+'cheader-limit">'+settings.resultsText.replace("%", category['cheader']['total']).replace("$", (category['cheader']['limit'] < category['cdata'].length ? category['cheader']['limit'] : category['cdata'].length))+'</p></li>';
+
+											var fillSearchFieldCode = (settings.fillSearchField) ? 'document.getElementById(\''+searchField.attr('id')+'\').value = \'%\';' : '';
+											//var fillSearchFieldCode = 'document.getElementById(\''+searchField.attr('id')+'\').value = \'%\';';
+											
+											$.each(category['cdata'], function (j, item){
+												if (cnt < limit){
+													//var link = '<a href="'+((item['url'] != undefined) ? item['url'] : 'javascript:void(0);')+'" '+((item['onclick'] != undefined) ? ' onclick="'+fillSearchFieldCode.replace("%", ((settings.fillSearchField) ? item[settings.fillSearchFieldWith] : ''))+(settings.runJS ? item['onclick'] : '')+'"' : '')+((item['target'] != undefined) ? ' target="'+item['target']+'"' : '')+'>';
+													var link = '<a href="'+((item['url'] != undefined) ? item['url'] : 'javascript:void(0);')+'" '+((item['onclick'] != undefined) ? ' onclick="'+fillSearchFieldCode.replace("%", item[settings.fillSearchFieldWith])+(settings.runJS ? item['onclick'] : '')+'"' : '')+((item['target'] != undefined) ? ' target="'+item['target']+'"' : '')+'>';
+
+													output += '<li class="'+settings.cssPrefix+'cdata">'+link+"\n";
+													output += '<table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>';
+													output += '<p>';
+													output += (item['title'] != undefined) ? '<span class="'+settings.cssPrefix+'cdata-title">'+item['title']+"</span><br />\n" : '';
+													output += (item['description'] != undefined) ? ''+item['description']+''+"\n" : '';
+													output += '</p>'+"\n";
+													output += '</td></tr></table>';
+													output += '</a></li>'+"\n";
+												}
+												cnt++;
+											});
+										}
+									});
+								}
+
+								resultBox.html(output).css({'position' : 'absolute', 'top' : searchField.position().top+searchField.outerHeight(), 'right' : '0'}).fadeIn();
+
+								searchField.removeClass(settings.cssPrefix+'loading');
+							}
+						});
+					}, settings.timeout);
+				}
+			}		
+		});
+		
+		searchField.blur(function(){
+			resultBox.fadeOut();
+		});
+
+		searchField.focus(function(){
+			if (searchField.val() == previousQ && searchField.val() != ''){
+				resultBox.fadeIn();
+			} else if (searchField.val() != ''){
+				searchField.trigger('keyup');
+			}
+		});
+
+	};
+	
+	function resetTimer(timeout){
+		clearTimeout(timeout);
+		timeout = null;
+	};
+})(jQuery);
\ No newline at end of file
diff --git a/interface/web/js/scrigo.js.php b/interface/web/js/scrigo.js.php
index 25e2128ec3..f8120e8372 100644
--- a/interface/web/js/scrigo.js.php
+++ b/interface/web/js/scrigo.js.php
@@ -33,10 +33,10 @@ function loadContentRefresh(pagename) {
   }
 }
 
-function capp(module) {
+function capp(module, redirect) {
 	var submitFormObj = jQuery.ajax({		type: "GET", 
 											url: "capp.php", 
-											data: "mod="+module,
+											data: "mod="+module+((redirect != undefined) ? '&redirect='+redirect : ''),
 											dataType: "html",
 											success: function(data, textStatus, jqXHR) {
 												if(jqXHR.responseText != '') {
diff --git a/interface/web/mail/form/mail_domain.tform.php b/interface/web/mail/form/mail_domain.tform.php
index 7bebe7e730..fd0c28794b 100644
--- a/interface/web/mail/form/mail_domain.tform.php
+++ b/interface/web/mail/form/mail_domain.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -83,7 +88,8 @@ $form["tabs"]['domain'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'active' => array (
 			'datatype'	=> 'VARCHAR',
diff --git a/interface/web/mail/form/mail_user.tform.php b/interface/web/mail/form/mail_user.tform.php
index b70d656d1f..c9353edb34 100644
--- a/interface/web/mail/form/mail_user.tform.php
+++ b/interface/web/mail/form/mail_user.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -77,7 +82,8 @@ $form["tabs"]['mailuser'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
     'login' => array (
       'datatype'  => 'VARCHAR',
@@ -109,7 +115,8 @@ $form["tabs"]['mailuser'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
 		'quota' => array (
 			'datatype'	=> 'INTEGER',
diff --git a/interface/web/sites/ajax_get_json.php b/interface/web/sites/ajax_get_json.php
index 8c7b738b2e..887f5dae26 100644
--- a/interface/web/sites/ajax_get_json.php
+++ b/interface/web/sites/ajax_get_json.php
@@ -101,6 +101,6 @@ $type = $_GET["type"];
 	}
 
 //}
-
+header('Content-type: application/json');
 echo $json;
 ?>
\ No newline at end of file
diff --git a/interface/web/sites/form/database.tform.php b/interface/web/sites/form/database.tform.php
index 9bef109391..b26a1e4d53 100644
--- a/interface/web/sites/form/database.tform.php
+++ b/interface/web/sites/form/database.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -98,7 +103,8 @@ $form["tabs"]['database'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'database_user' => array (
 			'datatype'	=> 'VARCHAR',
@@ -114,7 +120,8 @@ $form["tabs"]['database'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
 		'database_password' => array (
 			'datatype'	=> 'VARCHAR',
@@ -153,7 +160,8 @@ $form["tabs"]['database'] = array (
 	                             ),
 	      'default' => '',
 	      'value'   => '',
-	      'width'   => '60'
+	      'width'   => '60',
+		  'searchable' => 2
 	    ),
 	##################################
 	# ENDE Datatable fields
diff --git a/interface/web/sites/form/ftp_user.tform.php b/interface/web/sites/form/ftp_user.tform.php
index 3450764ff5..3f71828dbc 100644
--- a/interface/web/sites/form/ftp_user.tform.php
+++ b/interface/web/sites/form/ftp_user.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -92,7 +97,8 @@ $form["tabs"]['ftp'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'password' => array (
 			'datatype'	=> 'VARCHAR',
diff --git a/interface/web/sites/form/shell_user.tform.php b/interface/web/sites/form/shell_user.tform.php
index ec7b612761..061dd29d91 100644
--- a/interface/web/sites/form/shell_user.tform.php
+++ b/interface/web/sites/form/shell_user.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -92,7 +97,8 @@ $form["tabs"]['shell'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'password' => array (
 			'datatype'	=> 'VARCHAR',
diff --git a/interface/web/sites/form/web_domain.tform.php b/interface/web/sites/form/web_domain.tform.php
index ce835a94b3..d97d78b5d9 100644
--- a/interface/web/sites/form/web_domain.tform.php
+++ b/interface/web/sites/form/web_domain.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -87,7 +92,8 @@ $form["tabs"]['domain'] = array (
 										'keyfield'=> 'ip_address',
 										'valuefield'=> 'ip_address'
 									 ),*/
-			'value'		=> ''
+			'value'		=> '',
+			'searchable' => 2
 		),
 		'ipv6_address' => array (
 			'datatype'	=> 'VARCHAR',
@@ -98,7 +104,8 @@ $form["tabs"]['domain'] = array (
 										'keyfield'=> 'ip_address',
 										'valuefield'=> 'ip_address'
 									 ),*/
-			'value'		=> ''
+			'value'		=> '',
+			'searchable' => 2
 		),
 		'domain' => array (
 			'datatype'	=> 'VARCHAR',
@@ -114,7 +121,8 @@ $form["tabs"]['domain'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'type' => array (
 			'datatype'	=> 'VARCHAR',
@@ -208,7 +216,8 @@ $form["tabs"]['domain'] = array (
 			'formtype'	=> 'SELECT',
 			'default'	=> 'fast-cgi',
 			'valuelimit' => 'client:web_php_options',
-			'value'		=> array('no' => 'disabled_txt', 'fast-cgi' => 'Fast-CGI', 'cgi' => 'CGI', 'mod' => 'Mod-PHP', 'suphp' => 'SuPHP', 'php-fpm' => 'PHP-FPM')
+			'value'		=> array('no' => 'disabled_txt', 'fast-cgi' => 'Fast-CGI', 'cgi' => 'CGI', 'mod' => 'Mod-PHP', 'suphp' => 'SuPHP', 'php-fpm' => 'PHP-FPM'),
+			'searchable' => 2
 		),
 		'fastcgi_php_version' => array (
 			'datatype'	=> 'VARCHAR',
diff --git a/interface/web/themes/default/css/screen/content_ispc.css b/interface/web/themes/default/css/screen/content_ispc.css
index 796cd57114..bb8b836814 100644
--- a/interface/web/themes/default/css/screen/content_ispc.css
+++ b/interface/web/themes/default/css/screen/content_ispc.css
@@ -993,6 +993,134 @@
 		-ms-transform:rotate(90deg);
 		transform:rotate(90deg);
 	}
-
+	
+	div.gs-container{
+		margin-top:10px;
+	}
+	div.gs-container *{
+		margin: 0;
+		padding: 0;
+		background-position: 0 0;
+		text-decoration: none;
+		font-size: 1em;
+	}
+	input.gs-loading{
+		background-image: url(../../icons/x16/loading.gif);
+		background-repeat: no-repeat;
+		background-position: center right;
+	}
+	ul.gs-resultbox{
+		margin: 0 !important;
+		padding: 0 !important;
+		width: 300px;
+		z-index: 999999;
+		border: 1px solid #aaa;
+		font-size: 11px;
+		background: #fff;
+		-moz-box-shadow: 2px 2px 5px 0 #c5c5c5;
+		-webkit-box-shadow: 2px 2px 5px 0 #c5c5c5;
+		-khtml-box-shadow: 2px 2px 5px 0 #c5c5c5;
+		-o-box-shadow: 2px 2px 5px 0 #c5c5c5;
+		-ms-box-shadow: 2px 2px 5px 0 #c5c5c5;
+		box-shadow: 2px 2px 5px 0 #c5c5c5;
+		list-style: none;
+		/*
+		-moz-border-radius-bottomleft:10px;
+		-webkit-border-bottom-left-radius:10px;
+		-khtml-border-bottom-left-radius:10px;
+		-o-border-bottom-left-radius:10px;
+		-ms-border-bottom-left-radius:10px;
+		border-bottom-left-radius:10px;	
+		-moz-border-radius-bottomright:10px;
+		-webkit-border-bottom-right-radius:10px;
+		-khtml-border-bottom-right-radius:10px;
+		-o-border-bottom-right-radius:10px;
+		-ms-border-bottom-right-radius:10px;
+		border-bottom-right-radius:10px;
+		*/
+	}
+	ul.gs-resultbox li{
+		float: left;
+		width: 100%;
+		clear: both;
+		cursor: pointer;
+	}
+	/*
+	ul.gs-resultbox li:last-child{
+		-moz-border-radius-bottomleft:10px;
+		-webkit-border-bottom-left-radius:10px;
+		-khtml-border-bottom-left-radius:10px;
+		-o-border-bottom-left-radius:10px;
+		-ms-border-bottom-left-radius:10px;
+		border-bottom-left-radius:10px;	
+		-moz-border-radius-bottomright:10px;
+		-webkit-border-bottom-right-radius:10px;
+		-khtml-border-bottom-right-radius:10px;
+		-o-border-bottom-right-radius:10px;
+		-ms-border-bottom-right-radius:10px;
+		border-bottom-right-radius:10px;
+	}
+	*/
+	ul.gs-resultbox li.gs-cheader{
+		height: 13px;
+		overflow: hidden;
+		padding: 5px 0;
+		color: #fff;
+		background: #6ea6d1;
+		cursor:default;
+		padding-bottom:10px;
+	}
+	ul.gs-resultbox li.gs-cheader p.gs-cheader-title{
+		margin: 0 !important;
+		padding: 0 0 0 10px !important;
+		float: left;
+		font-size: 12px;
+		font-weight: bold;
+	}
+	ul.gs-resultbox li.gs-cheader p.gs-cheader-limit{
+		margin: 0 !important;
+		padding: 0 10px 0 0 !important;
+		float: right;
+		font-size: 11px;
+		font-weight: normal;
+	}
+	ul.gs-resultbox li.gs-cdata{
+		margin: 0 !important;
+		padding: 0 !important;
+		border-bottom: 1px solid #c5c5c5;
+	}
+	ul.gs-resultbox li.gs-cdata:last-child{
+		border-bottom: none;
+	}
+	ul.gs-resultbox li.gs-cdata:hover{
+		background: #eaf4fd;
+	}
+	ul.gs-resultbox li.gs-cdata a{
+		display: block;
+		padding: 5px 10px;
+		text-decoration: none !important;
+		background: #fff;
+	}
+	ul.gs-resultbox li.gs-cdata a:hover{
+		background: #cde0ff;
+	}
+	ul.gs-resultbox li.gs-cdata img{
+		margin-right: 12px;
+	}
+	ul.gs-resultbox li.gs-cdata p{
+		margin: 0 !important;
+		padding: 0 !important;
+		color: #444;
+		font-size: 10px;
+		min-height:30px;
+	}
+	ul.gs-resultbox li.gs-cdata p span.gs-cdata-title{
+		display: inline !important;
+		margin: 0 !important;
+		padding: 0 !important;
+		font-size: 11px;
+		font-weight: bold;
+		color: #000;
+	}
 }
 
diff --git a/interface/web/themes/default/icons/x16/loading.gif b/interface/web/themes/default/icons/x16/loading.gif
new file mode 100644
index 0000000000000000000000000000000000000000..19afda1a39b4543b4745fe34a973988b77787f4d
GIT binary patch
literal 1460
zcmZ9LYfuws7=^#xY+w^2ECJ)98QhSI!A1xeYZ%(;5<*BQNI+95RGV-SO0^TJRysrN
z=0Ywu2vRSolp&xMZDjzR798zt5D|J2tkzM+YGBkVc3P%R75!sZXr`Bc-=FV2@AIB>
zvJE<Qngs(GcoYRDCMI_5*Z}}AnM?x%12Hi%EiEl7m1=r=+U0U-wOX-QeC*h<ii!#r
zi#0ntD|#NWCTrc=%nV~zYLb!#F+W955rhk#0|oPDhGGC9H8Z2`swLZ}!v&-r7!M<8
z#FS^G3o1*Hywqy&q&hAs>ptg^zYzUaQfRMHPpLTdW5y1myP)1)d}iZGC%vL8L&D`&
zey8Rrc=r$<-QJTXrfswm+{uqYSx{8iI$)IoNbKe#Wl{t&MZegB%>_~OTSU!mv0-NP
zspeD98tDOq-DwE#Q_~4pXSt$YWW9okFIYI5{RUP5Qi`yW)7KoAQKaZww`IJF>|A>O
z{%VUntb|VXn+YC|dM3Z70>~p%%=oZ$t53A`W8uDP@&6PtMj9Z+jACv_(aXmLnrvAb
z>qn8pvktzJ5<}_(0V=0i2sfdx=7|=r1ng5Be{Uf-iEqCIM(VnK)Eh$|(P#GRI&Q2&
zP!xW4qFDm02<1!pJ{Xnu<dd<r3I7G0KQjZExZqqWp}HE6JQfzaRe0(`Z8j>0^#&G^
zW5#z;xZOS-P5dl#)_ZCp`aRTc3t+3b?C`3}mJN&TGd6xTd?}M0?9+ZwaqF(~Ox#zT
zQ+Xv*KmERJ=b{iG8ZtJL0n}lmUQK&ZWFj(l^O}e)XTz7{G=>Fi8|uDm>XdCRT888C
z_mmL6yWNqzX`r0@&0&Nph)$tTH0}x>s*6jmCt455LZc%?qhDlZ^Z4ik)PG&%GIBS7
zay>2ee(j4J2XdnX4}dlcJ6xmSdXqEAT#T{>>1KfA&cX2qpj+p&D2<Zt>pn}bTqVE3
z37S0{6Z36^e8`l}&L}kMD{+{`Hx|T3z>6d}fVado?hGyPcU<PL`8H!7XfNVBeUmy_
z92l%~CFFPw%Xyn>c$T<^BX{`b%7#JU=r=Fs?QRyAsunx;_Z?RY;V(uB??^Rb*R7AO
zQXn2zuxB~Shri5sT9-6zbJJ6vlNc+!EH<RcKtljx;xZSQaRY^k_KmJET-2VgAs|(o
zqiabJ&ZR(R;SUdSVW4HJ_iB|M#aErrt1`ZxgLO^vW)KB(ZV%a{mkT^j5*kVpg#Cu~
zuw%KN%w`dNwlc!<?n=FGu9yEbVjj`VAYvUw#Rw%`f3GIq?8LJZI89rW0ljz6QC->X
zmdQVGvJ`Cv@W?@D4`D8jr8LC#yx4l@ut*J%2v(<`#03ky0YkbFH;p#-k^RxE@Uh7^
zg%a*7BK_)rF#?8hz7%gU#x`Y9)$d4eO#Hcp-VPls^96?_NXOCGhpMbwRBpb|-VT>5
znRaK|WGSbGy_}93YmUGkR_ebm4MPVB!ZOZdvHf%x73onWSV6Rae_>|$ri4#~1m}zl
z2{N@XEIm=1V1zExSsabMwabYu&EVcfdQ61!Gx>_T#~4Y|1#%>n91af{&DMQTqRgOb
zZ*&lpkw>{)5_1zKah0?~>e+ZUyR<>6&Ui8$+*bD*uLA#{;=GL;XAFhZ*;#&X-vI|*
zSNH_jgV4ypk>OgAVv}0y`c?nFe3#Q51`vVX-#s!B9oBYJLC9-y&S27BQUzzZY=ZPW
et`q6Ee0W;o$?RN2DyQ3A+H)(LB)n8cGW{>_T-+J}

literal 0
HcmV?d00001

diff --git a/interface/web/themes/default/templates/main.tpl.htm b/interface/web/themes/default/templates/main.tpl.htm
index 1854b507d0..b012c068b6 100644
--- a/interface/web/themes/default/templates/main.tpl.htm
+++ b/interface/web/themes/default/templates/main.tpl.htm
@@ -60,6 +60,7 @@
 	<script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js"></script>
     <script type="text/javascript" src="js/scrigo.js.php"></script>
     <script type="text/javascript" src="js/uni-form/uni-form.jquery.js"></script>
+	<script type="text/javascript" src="js/jquery.ispconfigsearch.js"></script>
 	<script language="JavaScript" type="text/javascript">
 		var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
 		if(!is_chrome && getInternetExplorerVersion() > 8.0) {
@@ -81,6 +82,11 @@
 			jQuery('.subsectiontoggle').live("click", function(){
 				jQuery(this).children().toggleClass('showing').end().next().slideToggle();
 			});
+			
+			jQuery('#globalsearch').ispconfigSearch({
+				dataSrc: '/dashboard/ajax_get_json.php?type=globalsearch'
+			});
+
 		});
 		
 		
@@ -109,6 +115,7 @@
                     <!-- end: skip link navigation -->
 			        <tmpl_if name="cpuser">
                     <span><a href="#logout" onclick="loadContent('login/logout.php');"><tmpl_var name="logout_txt"> <tmpl_var format="strtoupper" name="cpuser"></a><!-- | <a href="#" onclick="capp('help')">Help</a> | <a href="#">Imprint</a>--></span>
+					<input type="text" id="globalsearch" size="30" value="" />
 			        </tmpl_if>
                 </div>
                 <h1 id="ir-HeaderLogo" class="swap" style="background-image:url('{tmpl_var name='app_logo'}');"><span>ISPConfig 3</span></h1>
diff --git a/interface/web/vm/form/openvz_ip.tform.php b/interface/web/vm/form/openvz_ip.tform.php
index 78b9d944aa..ca958b3f39 100644
--- a/interface/web/vm/form/openvz_ip.tform.php
+++ b/interface/web/vm/form/openvz_ip.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -83,7 +88,8 @@ $form["tabs"]['main'] = array (
 			'width'		=> '15',
 			'maxlength'	=> '15',
 			'rows'		=> '',
-			'cols'		=> ''
+			'cols'		=> '',
+			'searchable' => 1
 		),
 		'vm_id' => array (
 			'datatype'	=> 'INTEGER',
diff --git a/interface/web/vm/form/openvz_ostemplate.tform.php b/interface/web/vm/form/openvz_ostemplate.tform.php
index 6b9be3f3e5..0224ffae8b 100644
--- a/interface/web/vm/form/openvz_ostemplate.tform.php
+++ b/interface/web/vm/form/openvz_ostemplate.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -67,7 +72,8 @@ $form["tabs"]['main'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'template_file' => array (
 			'datatype'	=> 'VARCHAR',
@@ -78,7 +84,8 @@ $form["tabs"]['main'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
 		'server_id' => array (
 			'datatype'	=> 'INTEGER',
@@ -112,7 +119,8 @@ $form["tabs"]['main'] = array (
 			'width'		=> '',
 			'maxlength'	=> '',
 			'rows'		=> '10',
-			'cols'		=> '30'
+			'cols'		=> '30',
+			'searchable' => 2
 		),
 	##################################
 	# ENDE Datatable fields
diff --git a/interface/web/vm/form/openvz_template.tform.php b/interface/web/vm/form/openvz_template.tform.php
index 845d2bcfec..39cd3ae7ab 100644
--- a/interface/web/vm/form/openvz_template.tform.php
+++ b/interface/web/vm/form/openvz_template.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -67,7 +72,8 @@ $form["tabs"]['main'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'diskspace' => array (
 			'datatype'	=> 'INTEGER',
@@ -169,7 +175,8 @@ $form["tabs"]['main'] = array (
 			'default'	=> '8.8.8.8 8.8.4.4',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 2
 		),
 		'active' => array (
 			'datatype'	=> 'VARCHAR',
diff --git a/interface/web/vm/form/openvz_vm.tform.php b/interface/web/vm/form/openvz_vm.tform.php
index 3d75e8464b..ac7e8ef068 100644
--- a/interface/web/vm/form/openvz_vm.tform.php
+++ b/interface/web/vm/form/openvz_vm.tform.php
@@ -29,6 +29,11 @@
 	Hint:
 	The ID field of the database table is not part of the datafield definition.
 	The ID field must be always auto incement (int or bigint).
+	
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
 
 
 */
@@ -105,7 +110,8 @@ $form["tabs"]['main'] = array (
 										'keyfield'=> 'ip_address',
 										'valuefield'=> 'ip_address'
 									 ),
-			'value'		=> ''
+			'value'		=> '',
+			'searchable' => 2
 		),
 		'hostname' => array (
 			'datatype'	=> 'VARCHAR',
@@ -116,7 +122,8 @@ $form["tabs"]['main'] = array (
 			'default'	=> '',
 			'value'		=> '',
 			'width'		=> '30',
-			'maxlength'	=> '255'
+			'maxlength'	=> '255',
+			'searchable' => 1
 		),
 		'vm_password' => array (
 			'datatype'	=> 'VARCHAR',
@@ -158,7 +165,8 @@ $form["tabs"]['main'] = array (
 			'width'		=> '',
 			'maxlength'	=> '',
 			'rows'		=> '10',
-			'cols'		=> '30'
+			'cols'		=> '30',
+			'searchable' => 2
 		),
 	##################################
 	# ENDE Datatable fields
-- 
GitLab