Initial implementation of javascript live project search
Initial implementation of javascript live project search

 Binary files /dev/null and b/images/search-loader.gif differ
--- a/include/controller/Controller_ProjectList.class.php
+++ b/include/controller/Controller_ProjectList.class.php
@@ -158,6 +158,11 @@
 			if ($projectList->Count() > 0)
 				$this->tpl->assign('projectlist', $projectList);
 		}
+
+		if ((empty($this->params['opml']) || ($this->params['opml'] !== true)) &&
+		    (empty($this->params['txt']) || ($this->params['txt'] !== true))) {
+			$this->tpl->assign('extrascripts', array('js/projectsearch.js'));
+		}
 	}
 
 }

--- /dev/null
+++ b/js/projectsearch.js
@@ -1,1 +1,132 @@
+/*
+ * GitPHP javascript project search
+ *
+ * Live search of project list
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2010 Christopher Han
+ * @package GitPHP
+ * @subpackage Javascript
+ */
 
+var oldSearchValue = '';
+
+function runSearch() {
+	var search = $('input.projectSearchBox').val();
+	oldSearchValue = search;
+	
+	$('img.searchSpinner').show();
+
+	if (search.length == 0) {
+		$('a.clearSearch').hide();
+	} else {
+		$('a.clearSearch').show();
+	}
+
+	var visibleCats = [];
+
+	$('table.projectList tr.projectRow').each(function() {
+		if (search.length < 1) {
+			$(this).show();
+			return;
+		}
+
+		var category = '';
+
+		var projectName = $(this).find('td.projectName a').text();
+		if (projectName.length > 0) {
+			if (projectName.indexOf(search) != -1) {
+				$(this).show();
+				category = $(this).data('category');
+				if (category) {
+					if (jQuery.inArray(category, visibleCats) == -1) {
+						visibleCats.push(category);
+					}
+				}
+				return;
+			}
+		}
+		var projectDesc = $(this).find('td.projectDescription a').text();
+		if (projectDesc.length > 0) {
+			if (projectDesc.indexOf(search) != -1) {
+				$(this).show();
+				category = $(this).data('category');
+				if (category) {
+					if (jQuery.inArray(category, visibleCats) == -1) {
+						visibleCats.push(category);
+					}
+				}
+				return;
+			}
+		}
+		var projectOwner = $(this).find('td.projectOwner em').text();
+		if (projectOwner.length > 0) {
+			if (projectOwner.indexOf(search) != -1) {
+				$(this).show();
+				category = $(this).data('category');
+				if (category) {
+					if (jQuery.inArray(category, visibleCats) == -1) {
+						visibleCats.push(category);
+					}
+				}
+				return;
+			}
+		}
+		$(this).hide();
+	});
+
+	$('table.projectList tr.categoryRow').each(function() {
+		if (search.length < 1) {
+			$(this).show();
+			return;
+		}
+
+		var category = $(this).children('th.categoryName').text();
+		if (category.length > 0) {
+			if (jQuery.inArray(category, visibleCats) !== -1) {
+				$(this).show();
+			} else {
+				$(this).hide();
+			}
+		}
+	});
+
+	$('img.searchSpinner').hide();
+}
+
+function initProjectSearch() {
+	$('#projectSearchForm').keypress(function(e) {
+		if (e.which == 13) {
+			return false;
+		}
+	});
+
+	// Store project categories
+	var category = '';
+	$('table.projectList tr').each(function() {
+		if ($(this).hasClass('categoryRow')) {
+			category = $(this).children('th.categoryName').text();
+		} else if ($(this).hasClass('projectRow')) {
+			if (category.length > 0) {
+				$(this).data('category', category);
+			}
+		}
+	});
+
+	$('a.clearSearch').click(function() {
+		$('input.projectSearchBox').val('');
+		oldSearchValue = '';
+		runSearch();
+		return false;
+	});
+
+	$('input.projectSearchBox').keyup(function() {
+		if ($('input.projectSearchBox').val() != oldSearchValue)
+			runSearch();
+	});
+}
+
+$(document).ready(function() {
+	initProjectSearch();
+});
+

--- a/templates/projectlist.tpl
+++ b/templates/projectlist.tpl
@@ -19,12 +19,12 @@
 </div>
 
 <div class="projectSearch">
-<form method="get" action="index.php" enctype="application/x-www-form-urlencoded">
-{t}Search projects{/t}: <input type="text" name="s" {if $search}value="{$search}"{/if} /> <a href="index.php" {if !$search}style="display: none;"{/if}>X</a>
+<form method="get" action="index.php" id="projectSearchForm" enctype="application/x-www-form-urlencoded">
+{t}Search projects{/t}: <input type="text" name="s" class="projectSearchBox" {if $search}value="{$search}"{/if} /> <a href="index.php" class="clearSearch" {if !$search}style="display: none;"{/if}>X</a> {if $javascript}<img src="images/search-loader.gif" class="searchSpinner" style="display: none;" />{/if}
 </form>
 </div>
 
-<table cellspacing="0">
+<table cellspacing="0" class="projectList">
   {foreach name=projects from=$projectlist item=proj}
     {if $smarty.foreach.projects.first}
       {* Header *}
@@ -56,8 +56,8 @@
     {if $currentcategory != $proj->GetCategory()}
       {assign var=currentcategory value=$proj->GetCategory()}
       {if $currentcategory != ''}
-        <tr class="light">
-          <th>{$currentcategory}</th>
+        <tr class="light categoryRow">
+          <th class="categoryName">{$currentcategory}</th>
           <th></th>
           <th></th>
           <th></th>
@@ -66,13 +66,13 @@
       {/if}
     {/if}
 
-    <tr class="{cycle values="light,dark"}">
-      <td>
+    <tr class="{cycle values="light,dark"} projectRow">
+      <td class="projectName">
         <a href="{$SCRIPT_NAME}?p={$proj->GetProject()|urlencode}&amp;a=summary" class="list {if $currentcategory != ''}indent{/if}">{$proj->GetProject()}</a>
       </td>
-      <td><a href="{$SCRIPT_NAME}?p={$proj->GetProject()|urlencode}&amp;a=summary" class="list">{$proj->GetDescription()}</a></td>
-      <td><em>{$proj->GetOwner()}</em></td>
-      <td>
+      <td class="projectDescription"><a href="{$SCRIPT_NAME}?p={$proj->GetProject()|urlencode}&amp;a=summary" class="list">{$proj->GetDescription()}</a></td>
+      <td class="projectOwner"><em>{$proj->GetOwner()}</em></td>
+      <td class="projectAge">
         {assign var=projecthead value=$proj->GetHeadCommit()}
 	{if $projecthead}
           {if $projecthead->GetAge() < 7200}   {* 60*60*2, or 2 hours *}

comments