[vhffs-dev] [1297] Added AJAX group search with new design.

[ Thread Index | Date Index | More vhffs.org/vhffs-dev Archives ]


Revision: 1297
Author:   beuss
Date:     2008-10-30 08:15:19 +0100 (Thu, 30 Oct 2008)

Log Message:
-----------
Added AJAX group search with new design.

Modified Paths:
--------------
    branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Commons.pm
    branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Group.pm
    branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Main.pm
    branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Public.pm
    branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Tag.pm
    branches/vhffs-design/vhffs-panel/Makefile.am
    branches/vhffs-design/vhffs-panel/js/public.js
    branches/vhffs-design/vhffs-panel/js/vhffs/Menu.js
    branches/vhffs-design/vhffs-public/Makefile.am
    branches/vhffs-design/vhffs-public/groupsearch.pl
    branches/vhffs-design/vhffs-public/templates/Makefile.am
    branches/vhffs-design/vhffs-public/templates/content/last-groups.tt
    branches/vhffs-design/vhffs-public/templates/layouts/public.tt
    branches/vhffs-design/vhffs-public/templates/parts/left-menu.tt
    branches/vhffs-design/vhffs-public/templates/parts/tags-cloud.tt
    branches/vhffs-design/vhffs-themes/light-grey/main.css

Added Paths:
-----------
    branches/vhffs-design/vhffs-panel/js/vhffs/Common.js
    branches/vhffs-design/vhffs-public/groupsearch_form.pl
    branches/vhffs-design/vhffs-public/templates/common/
    branches/vhffs-design/vhffs-public/templates/common/pager.tt
    branches/vhffs-design/vhffs-public/templates/content/groupsearch-form.tt
    branches/vhffs-design/vhffs-public/templates/content/groupsearch-results.tt
    branches/vhffs-design/vhffs-public/templates/parts/group-general.tt


Modified: branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Commons.pm
===================================================================
--- branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Commons.pm	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Commons.pm	2008-10-30 07:15:19 UTC (rev 1297)
@@ -136,6 +136,42 @@
     }
 }
 
+sub get_pager {
+	my ($current_page, $total, $ipp, $slider_size, $url, $url_params) = @_;
+	my $last_page = int( ($total + $ipp - 1 ) / $ipp);
+	my $pager = {};
+	
+	if($last_page > 1) {
+		$pager->{last_page} = $last_page;
+		$pager->{current_page} = $current_page;
+		$pager->{url} = $url;
+	
+		my @params = ();	
+		foreach my $key (keys %$url_params) {
+            my $value = $url_params->{$key};
+            if(ref($value) eq 'ARRAY') {
+            	push @params, $key.'='.$_ foreach(@$value);
+            } else {
+            	push @params, $key.'='.$value unless($value =~ /^\s*$/);
+            }
+        }
+        $pager->{query_string} = join('&', @params);
+        my $pages = [];
+        for( ( ($current_page - $slider_size > 0) ? $current_page - $slider_size : 1 )..($current_page - 1) ) {
+        	push @$pages, $_;
+        }
+        $pager->{previous_pages} = $pages;
+        
+        $pages = [];
+        for( ($current_page + 1)..(($current_page + $slider_size <= $last_page) ? $current_page + $slider_size : $last_page ) ) {
+        	push @$pages, $_;
+        }
+        $pager->{next_pages} = $pages;
+	}
+	
+	return $pager;
+}
+
 =head2
 
     fetch_slice_and_count($main, $select, $conditions, $order, $start, $count, $params, $select_callback);

Modified: branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Group.pm
===================================================================
--- branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Group.pm	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Group.pm	2008-10-30 07:15:19 UTC (rev 1297)
@@ -113,26 +113,58 @@
 
 
 sub public_search {
-    my ($main, $groupname, $description, $start, $count) = @_;
+    my ($main, $groupname, $description, $included_tags, $excluded_tags, $start) = @_;
 
-    my $select_clause = 'SELECT g.gid, g.groupname, g.realname, o.description';
-    my $restriction = ' FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname INNER JOIN vhffs_object o ON o.object_id=g.object_id WHERE o.state = ? AND u.username IS NULL';
-    my @params;
+    my $sql =
+' FROM vhffs_groups g 
+	LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname
+	INNER JOIN vhffs_object o ON o.object_id=g.object_id
+	INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid
+	WHERE o.state=? AND u.username IS NULL';
+
+	my @params;
     push @params, Vhffs::Constants::ACTIVATED;
-
-    if(defined $groupname) {
-        # groupnames are enforced in lowercase
-        $restriction .= ' AND g.groupname LIKE ?';
-        push @params, '%'.lc($groupname).'%';
-    }
-
-    if(defined $description) {
-        $restriction .= ' AND UPPER(description) LIKE UPPER(?)';
-        push @params, '%'.$description.'%';
-    }
-
-    return Vhffs::Panel::Commons::fetch_slice_and_count($main, $select_clause, $restriction, 
-        ' ORDER BY g.groupname', $start, $count, \@params, \&Vhffs::Panel::Group::fetch_groups_and_users);
+    
+	if($groupname =~ /\S/) {
+		$sql .= ' AND g.groupname LIKE ?';
+		push @params, '%'.lc($groupname).'%';
+	}
+	
+	if($description =~ /\S/) {
+		$sql .= ' AND o.description LIKE ? ';
+		push @params, '%'.lc($description).'%';
+	}
+	
+	if(scalar(@$included_tags)) {
+		$sql .= ' AND o.object_id IN (SELECT ot.object_id from vhffs_object_tag ot WHERE ot.tag_id IN(?';
+		$sql .= ', ?' x (scalar(@$included_tags) - 1);
+		$sql .= '))';
+		push @params, @$included_tags;
+	}
+	
+	if(scalar(@$excluded_tags)) {
+		$sql .= ' AND o.object_id NOT IN (SELECT ot.object_id from vhffs_object_tag ot WHERE ot.tag_id IN(?';
+		$sql .= ', ?' x (scalar(@$excluded_tags) - 1);
+		$sql .= '))';
+		push @params, @$excluded_tags;
+	}
+	
+	my $limit = ' LIMIT 10';
+	$limit .= ' OFFSET '.($start * 10) if(defined $start);
+	
+	my $dbh = $main->get_db_object();
+	my $sth = $dbh->prepare('SELECT g.gid, g.groupname, g.realname, o.description, owner.username AS owner_name'.$sql.$limit);
+	
+	return undef unless ( $sth->execute(@params) );
+	
+	my $groups = $sth->fetchall_arrayref({});
+	
+	$sth = $dbh->prepare('SELECT COUNT(*)'.$sql);
+	return undef unless ( $sth->execute(@params) );
+	
+	my ($count) = $sth->fetchrow_array();
+	
+	return ($groups, $count);
 }
 
 sub getall_groups_per_user

Modified: branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Main.pm
===================================================================
--- branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Main.pm	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Main.pm	2008-10-30 07:15:19 UTC (rev 1297)
@@ -272,6 +272,7 @@
 	my $cgi = new CGI;
 	$cgi->charset('UTF-8');
 	$this->{cgi} = $cgi;
+	$this->{url} = CGI::url();
 
 	my $vhffs = init Vhffs::Main;
 	$this->{vhffs} = $vhffs;
@@ -329,6 +330,9 @@
 		$this->display;
 		exit 0;
 	}
+	
+	$this->{is_ajax_request} = (defined $this->{cgi}->http('X-Requested-With')
+		and $this->{cgi}->http('X-Requested-With') eq 'XMLHttpRequest');
 
 	return $this;
 }

Modified: branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Public.pm
===================================================================
--- branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Public.pm	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Public.pm	2008-10-30 07:15:19 UTC (rev 1297)
@@ -72,17 +72,19 @@
 	$vars->{top} = 'parts/top-menu.tt' unless(defined $vars->{top});
 	
 	# Handling ajax stuff
-	$create_vars->{PROCESS} = 'layouts/public.tt' unless(0); #TODO unless(requested with ajax)
+	if($self->{is_ajax_request}) {
+		
+	} else {
+		$create_vars->{PROCESS} = 'layouts/public.tt';
+		$vars->{popular_tags} = Vhffs::Tag::get_most_popular_tags($self->{vhffs});
+		$vars->{random_tags} = Vhffs::Tag::get_random_tags($self->{vhffs});
+	}
 	
-	# Fill layout stuff (only if !ajax)
-	$vars->{popular_tags} = Vhffs::Tag::get_most_popular_tags($self->{vhffs});
-	$vars->{random_tags} = Vhffs::Tag::get_random_tags($self->{vhffs});
-	
 	my $template = new Template($create_vars);
 
 	binmode STDOUT , ':utf8';	
 	
-	print "Content-type: text/html\n\n";
+	print CGI::header( -type=>'text/html', -charset=>'utf-8' );
 	
 
 	# TODO Only do a full layout process if we aren't in the ajax case

Modified: branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Tag.pm
===================================================================
--- branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Tag.pm	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-api/src/Vhffs/Panel/Tag.pm	2008-10-30 07:15:19 UTC (rev 1297)
@@ -54,6 +54,15 @@
 
 =cut
 
+=head2 get_groups
+
+	Vhffs::Panel::Tag::get_groups($main, $tag_id, $start, $count)
+
+Fetches C<$count> groups associated to tag #C<$tag_id> starting
+at index C<$start>
+
+=cut
+
 sub get_groups {
     my ($main, $tag_id, $start, $count) = @_;
 
@@ -71,4 +80,40 @@
         ' ORDER BY g.groupname', $start, $count, \@params, \&Vhffs::Panel::Group::fetch_groups_and_users);
 }
 
+sub get_by_tag_ids {
+	
+	my $main = shift;
+	my @ids = @_;
+	return _get_by_tag_ids($main, 0, @ids);
+}
+
+sub get_all_excluding {
+	my $main = shift;
+	my @ids = @_;
+	return _get_by_tag_ids($main, 1, @ids);
+}
+
+sub _get_by_tag_ids {
+	my $main = shift;
+	my $exclude = shift;
+	my @ids = @_;
+	
+	# There can be no ID if we are in exclude mode (meaning
+	# that we want all tags)
+	
+	return undef unless($exclude ||  scalar(@ids) > 0);
+	
+	my $sql = 'SELECT c.tag_category_id AS category_id, c.label AS category_label, t.tag_id, t.label AS tag_label '.
+		'FROM vhffs_tag t INNER JOIN vhffs_tag_category c ON c.tag_category_id = t.category_id ';
+	
+	if(scalar(@ids)) {
+		$sql .= 'WHERE tag_id '.($exclude ? 'NOT ' : '').'IN(?';
+		$sql .= ', ?' x (scalar(@ids) - 1);
+		$sql .= ') ORDER BY c.label, t.label';
+	}
+	
+	my $dbh = $main->get_db_object;
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @ids);
+}
+
 1;

Modified: branches/vhffs-design/vhffs-panel/Makefile.am
===================================================================
--- branches/vhffs-design/vhffs-panel/Makefile.am	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-panel/Makefile.am	2008-10-30 07:15:19 UTC (rev 1297)
@@ -1,5 +1,6 @@
 javascripts = js/prototype.js \
 	js/commons.js \
+	js/dijit/dijit-all.js \
 	js/dojo/dnd/Moveable.js \
 	js/dojo/dnd/Manager.js \
 	js/dojo/dnd/Selector.js \
@@ -175,6 +176,7 @@
 	js/dojo/cldr/LICENSE \
 	js/public.js \
 	js/tooltip.js \
+	js/vhffs/Common.js \
 	js/vhffs/Menu.js
 
 if INSTALL_PANEL

Modified: branches/vhffs-design/vhffs-panel/js/public.js
===================================================================
--- branches/vhffs-design/vhffs-panel/js/public.js	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-panel/js/public.js	2008-10-30 07:15:19 UTC (rev 1297)
@@ -35,9 +35,144 @@
  */
 
 dojo.require('vhffs.Menu');
+dojo.require('vhffs.Common');
 
 
 
 dojo.addOnLoad(function() {
 	new vhffs.Menu(dojo.byId('left-menu'));
+	vhffs.Common.ajaxizeLinks(dojo.byId('public-content'));
 });
+
+var Public = {};
+
+Public.SearchGroup = {};
+
+Public.SearchGroup.onLoad = function() {
+	Public.SearchGroup.setUpTagsList();
+	Public.SearchGroup.ajaxizeForm();
+}
+
+Public.SearchGroup.ajaxizeForm = function() {
+	var form = dojo.byId('AdvancedSearchGroupForm');
+	dojo.connect(form, 'onsubmit', function(e) {
+		dojo.stopEvent(e);
+		dojo.xhrPost({
+			url: dojo.attr(form, 'action'),
+			'form': form,
+			load: function(response) {
+				vhffs.Common.loadContent(dojo.byId('public-content'), response);
+				vhffs.Common.ajaxizeLinks(dojo.byId('public-content'));
+			}
+		});
+	});
+}
+
+/**
+ * Adds the event listeners on +/- beside each tags.
+ */
+Public.SearchGroup.setUpTagsList = function() {
+	dojo.forEach(dojo.query('#searchTagsList span'), function(el, index) {
+		var id = dojo.attr(el, 'id');
+		if(!id) return;
+		
+		// We're only interrested in tag container's spans
+		if(/^tag\d+$/.test(id) == false) return;
+		
+		// Strips tag part (tag1 => 1)
+		var tagId = id.substring(3);
+		var include = dojo.query('a.include', el);
+		if(include.length > 0) {
+			include = include[0];
+			dojo.connect(include, 'onclick', function(e) { dojo.stopEvent(e); Public.SearchGroup.includeTag(tagId); });
+		}
+		var exclude = dojo.query('a.exclude', el);
+		if(exclude.length > 0) {
+			exclude = exclude[0];
+			dojo.connect(exclude, 'onclick', function(e) { dojo.stopEvent(e); Public.SearchGroup.excludeTag(tagId); });
+		}
+	});
+}
+
+/**
+ * Adds a tag to the exclusion list. Put the tag in
+ * the "Doesn't matches" section and add an hidden field
+ * to reflect this.
+ */
+Public.SearchGroup.excludeTag = function(tagId) {
+	Public.SearchGroup.addToList(tagId, 'searchTagExclude');
+	Public.SearchGroup.addHiddenField('excluded_tags', tagId);
+}
+
+/**
+ * Adds a tag to the inclusion list. Put the tag in
+ * the "Matches" section and add an hidden field
+ * to reflect this.
+ */
+Public.SearchGroup.includeTag = function(tagId) {
+	Public.SearchGroup.addToList(tagId, 'searchTagInclude');
+	Public.SearchGroup.addHiddenField('included_tags', tagId);
+}
+
+/**
+ * Adds an hidden field to the search form to reflect tag's
+ * inclusion/exclusion.
+ * @param name Name of the hidden field (included_tags or
+ * excluded_tags.
+ * @param tagId The hidden field will have tagId as its value
+ * and hidden[tagId] as its ID.
+ */
+Public.SearchGroup.addHiddenField = function(name, tagId) {
+	var h = document.createElement('input');
+	dojo.attr(h, {
+		type: 'hidden',
+		name: name,
+		value: tagId,
+		id: 'hidden' + tagId
+	});
+	dojo.place(h, 'AdvancedSearchGroupForm', 'first');
+}
+
+/**
+ * Removes the hidden field including or excluding
+ * 
+ */
+Public.SearchGroup.removeHiddenField = function(tagId) {
+	var h = dojo.byId('hidden' + tagId);
+	h.parentNode.removeChild(h);
+}
+
+Public.SearchGroup.removeTag = function(tagId, span) {
+	span.parentNode.removeChild(span);
+	Public.SearchGroup.removeHiddenField(tagId);
+	dojo.style(dojo.byId('tag' + tagId), 'display', '');
+}
+
+Public.SearchGroup.addToList = function(tagId, list) {
+	var tagContainer = dojo.byId('tag' + tagId);
+	if(tagContainer == null) return;
+	var list = dojo.byId(list);
+	var label = dojo.query('span.label', tagContainer);
+	if(label.length > 0) {
+		label = dojo.string.trim(label[0].innerHTML);
+	} else {
+		label = dojo.string.trim(tagContainer.innerHTML);
+	}
+	var span = document.createElement('span');
+	span.innerHTML = (label + ' ');
+	var remove = document.createElement('a');
+	dojo.attr(remove, 'href', '#');
+	remove.innerHTML = '&nbsp;X';
+	
+	dojo.place(remove, span, 'last');
+	// Don't use += ' ' since remove will be lost...
+	dojo.place(document.createTextNode(' '), span, 'last');
+	dojo.place(span, list, 'last');
+	
+	dojo.connect(remove, 'onclick', function(e) {
+		dojo.stopEvent(e); Public.SearchGroup.removeTag(tagId, span);
+	});
+	
+	dojo.style(tagContainer, 'display', 'none');
+}
+

Added: branches/vhffs-design/vhffs-panel/js/vhffs/Common.js
===================================================================
--- branches/vhffs-design/vhffs-panel/js/vhffs/Common.js	                        (rev 0)
+++ branches/vhffs-design/vhffs-panel/js/vhffs/Common.js	2008-10-30 07:15:19 UTC (rev 1297)
@@ -0,0 +1,108 @@
+/*
+ *  Copyright (c) vhffs project and its contributors
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ * 
+ *  1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of vhffs 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.
+ */
+ 
+dojo.provide('vhffs.Common');
+
+dojo.declare('vhffs.Common', null, {});
+
+dojo.mixin(vhffs.Common, {
+	ajaxizeLinks: function(contentTarget, rootNode) {
+		dojo.forEach(dojo.query('a.ajax', rootNode), function(link) {
+			dojo.connect(link, 'onclick', function(e) {
+				dojo.stopEvent(e);
+				var href = dojo.attr(link, 'href');
+				if(href != '#') {
+					dojo.xhrGet({
+						url: href,
+						load: function(response) {
+							vhffs.Common.loadContent(contentTarget, response);
+						}
+					});
+				}
+			});
+		});
+	},
+	
+	loadContent: function(contentTarget, xhrResponse) {
+		var parsed = vhffs.Common.extractScripts(xhrResponse);
+		contentTarget.innerHTML = parsed[0];
+		dojo.eval(parsed[1]);
+		vhffs.Common.ajaxizeLinks(contentTarget, contentTarget);
+	},
+	
+	extractScripts: function(html) {
+		var _t = this, code, byRef = {
+			downloadRemote: true,
+			errBack:function(e){
+				_t._onError.call(_t, 'Exec', 'Error downloading remote script in "'+_t.id+'"', e);
+			}
+		};
+		var cleanedHtml = vhffs.Common.snarfScripts(html, byRef);
+		byRef.code = byRef.code.replace(/(<!--|(?:\/\/)?-->|<!\[CDATA\[|\]\]>)/g, '');
+		return [cleanedHtml, byRef.code];
+	},
+	
+	snarfScripts: function(cont, byRef){
+		// summary
+		//		strips out script tags from cont
+		// invoke with 
+		//	byRef = {errBack:function(){/*add your download error code here*/, downloadRemote: true(default false)}}
+		//	byRef will have {code: 'jscode'} when this scope leaves
+		byRef.code = "";
+
+		function download(src){
+			if(byRef.downloadRemote){
+				// console.debug('downloading',src);
+				dojo.xhrGet({
+					url: src,
+					sync: true,
+					load: function(code){
+						byRef.code += code+";";
+					},
+					error: byRef.errBack
+				});
+			}
+		}
+		
+		// match <script>, <script type="text/..., but not <script type="dojo(/method)...
+		return cont.replace(/<script\s*(?![^>]*type=['"]?dojo)(?:[^>]*?(?:src=(['"]?)([^>]*?)\1[^>]*)?)*>([\s\S]*?)<\/script>/gi,
+			function(ignore, delim, src, code){
+				if(src){
+					download(src);
+				}else{
+					byRef.code += code;
+				}
+				return "";
+			}
+		);
+	}
+});

Modified: branches/vhffs-design/vhffs-panel/js/vhffs/Menu.js
===================================================================
--- branches/vhffs-design/vhffs-panel/js/vhffs/Menu.js	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-panel/js/vhffs/Menu.js	2008-10-30 07:15:19 UTC (rev 1297)
@@ -47,11 +47,7 @@
 		if(!expandedIndex) expandedIndex = 0;
 		
 		dojo.forEach(this.items, function(submenu, index) {
-			if(index == expandedIndex) {
-				dojo.style(submenu, 'display', '');
-			} else {
-				dojo.style(submenu, 'display', 'none');
-			}
+			dojo.style(submenu, 'display', 'none');
 		}, this);
 		
 		dojo.forEach(this.titles, function(title) {

Modified: branches/vhffs-design/vhffs-public/Makefile.am
===================================================================
--- branches/vhffs-design/vhffs-public/Makefile.am	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/Makefile.am	2008-10-30 07:15:19 UTC (rev 1297)
@@ -8,6 +8,7 @@
 	getavatar.pl \
 	group.pl \
 	groupsearch.pl \
+	groupsearch_form.pl \
 	index.pl \
 	lastgroups.pl \
 	lastusers.pl \

Modified: branches/vhffs-design/vhffs-public/groupsearch.pl
===================================================================
--- branches/vhffs-design/vhffs-public/groupsearch.pl	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/groupsearch.pl	2008-10-30 07:15:19 UTC (rev 1297)
@@ -29,57 +29,52 @@
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 # POSSIBILITY OF SUCH DAMAGE.
 
+# Public search page for groups.
+# Parameters:
+# either
+#  - included_tags:	ID of the tags that should be matched
+#					by results (logical OR)
+#  - excluded_tags: ID of the tags that shouldn't be matched
+#					by results (logical AND)
+#  - groupname: (partial) name of the group
+#  - description: (partial) description of the group
+#  - start (optional): start page of the search
+
 use strict;
 use utf8;
 
 use POSIX qw(locale_h);
 use locale;
 use Locale::gettext;
-use CGI;
-use Encode;
 
 use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Commons;
+
 use Vhffs::Panel::Group;
-use Vhffs::Panel::Main;
-use Vhffs::Panel::Template;
+use Vhffs::Panel::Public;
+use Vhffs::Panel::Commons;
 
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
+my $panel = new Vhffs::Panel::Public();
 
-my $vhffs = $panel->{'vhffs'};
-my $templatedir = $panel->{'templatedir'};
-my $cgi = $panel->{'cgi'};
+my $cgi = $panel->{cgi};
 
-$panel->check_public();
+# Tags in "matches" section
+my @included_tags_ids = map{ int($_); } $cgi->param('included_tags');
+# Tags in "does not match" section
+my @excluded_tags_ids = map{ int($_); } $cgi->param('excluded_tags');
 
-my $template = new Vhffs::Panel::Template( filename => $templatedir.'/public/groupslist.tmpl', die_on_bad_params => 0 );
-my $groupname = $cgi->param('groupname') || '';
-my $description = Encode::decode_utf8( $cgi->param('description') ) || '';
-my $page = $cgi->param('page');
-my $per_page_count = 5;
-$page = 1 unless(defined $page && int($page) > 0);
+my $groupname = $cgi->param('groupname');
+my $description = $cgi->param('description');
 
-my $result = Vhffs::Panel::Group::public_search(
-    $vhffs,
-    ( $groupname =~ /^\s*$/ ? undef : $groupname ),
-    ( $description =~ /^\s*$/ ? undef : $description ),
-    ($page -1) * $per_page_count,
-    $per_page_count
-);
+# current page
+my $page = defined($cgi->param('page')) ? int($cgi->param('page')) : 1;
 
-$template->param( URL_PANEL => $vhffs->get_config->get_panel->{'url'} );
+my ($groups, $count) = Vhffs::Panel::Group::public_search($panel->{vhffs}, $groupname, $description, \@included_tags_ids, \@excluded_tags_ids, $page - 1);
+my $pager = Vhffs::Panel::Commons::get_pager($page, $count, 10, 5, $panel->{url}, { groupname => $groupname, description => $description, included_tags => \@included_tags_ids, excluded_tags => \@excluded_tags_ids});
 
-if($result->{total_count} == 0) {
-    $template->param( TEXT_TITLE => gettext('No group found') );
-} else {
-    Vhffs::Panel::Commons::paginate($template, $page, $result->{total_count}, $per_page_count,
-        { groupname => $groupname, description => $description });
-    $template->param( USE_AVATAR => $panel->use_groups_avatars );
-    $template->param( TEXT_TITLE => sprintf( gettext('%d group(s) found'), $result->{total_count} ) );
-    $template->param( GROUPS => $result->{data} );
-}
+my $vars = {
+	groups => $groups,
+	gs_title => gettext( 'Search results' ),
+	gs_pager => $pager
+};
 
-$panel->light( $template );
-$panel->display;
-
+$panel->render('content/groupsearch-results.tt', $vars);

Added: branches/vhffs-design/vhffs-public/groupsearch_form.pl
===================================================================
--- branches/vhffs-design/vhffs-public/groupsearch_form.pl	                        (rev 0)
+++ branches/vhffs-design/vhffs-public/groupsearch_form.pl	2008-10-30 07:15:19 UTC (rev 1297)
@@ -0,0 +1,73 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without 
+# modification, are permitted provided that the following conditions 
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright 
+#   notice, this list of conditions and the following disclaimer.
+#2. 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.
+#3. Neither the name of vhffs 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.
+
+use strict;
+use utf8;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+
+use lib '%VHFFS_LIB_DIR%';
+
+use Vhffs::Panel::Public;
+use Vhffs::Panel::Tag;
+
+my $panel = new Vhffs::Panel::Public();
+
+my $cgi = $panel->{cgi};
+
+my @included_tag_ids = map { int($_); } $cgi->param('included_tags');
+my @excluded_tag_ids = map { int($_); } $cgi->param('excluded_tags');
+
+
+
+my $discard_excluded = $cgi->param('discard_ex');
+@excluded_tag_ids = grep { $_ != $discard_excluded } @excluded_tag_ids if(defined $discard_excluded);
+
+my $discard_included = $cgi->param('discard_inc');
+@included_tag_ids = grep { $_ != $discard_included } @included_tag_ids if(defined $discard_included);
+
+
+my $query_string = '';
+
+$query_string .= 'included_tags='.(join('&amp;included_tags=', @included_tag_ids)) if(scalar(@included_tag_ids));
+$query_string .= '&amp;' if(scalar(@included_tag_ids) && scalar(@excluded_tag_ids));
+$query_string .= 'excluded_tags='.(join('&amp;excluded_tags=', @excluded_tag_ids)) if(scalar(@excluded_tag_ids));
+
+my $vars = {
+	included_tags => Vhffs::Panel::Tag::get_by_tag_ids($panel->{vhffs}, @included_tag_ids),
+	excluded_tags => Vhffs::Panel::Tag::get_by_tag_ids($panel->{vhffs}, @excluded_tag_ids),
+	other_tags => Vhffs::Panel::Tag::get_all_excluding($panel->{vhffs}, @included_tag_ids, @excluded_tag_ids),
+	query_string => $query_string
+};
+
+$panel->render('content/groupsearch-form.tt', $vars);

Modified: branches/vhffs-design/vhffs-public/templates/Makefile.am
===================================================================
--- branches/vhffs-design/vhffs-public/templates/Makefile.am	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/templates/Makefile.am	2008-10-30 07:15:19 UTC (rev 1297)
@@ -1,7 +1,10 @@
 publictemplatesdir = @TEMPLATESDIR@/public
 nobase_dist_publictemplates_DATA = \
 	banner.tmpl \
+	common/pager.tt \
 	content/last-groups.tt \
+	content/groupsearch-form.tt \
+	content/groupsearch-results.tt \
 	group_part.tmpl \
 	group.tmpl \
 	groupslist.tmpl \
@@ -16,6 +19,7 @@
 	misc/git-part.tmpl \
 	misc/web-part.tmpl \
 	parts/footer.tt \
+	parts/group-general.tt \
 	parts/header.tt \
 	parts/left-menu.tt \
 	parts/tags-cloud.tt \

Added: branches/vhffs-design/vhffs-public/templates/common/pager.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/common/pager.tt	                        (rev 0)
+++ branches/vhffs-design/vhffs-public/templates/common/pager.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -0,0 +1,26 @@
+[%# TODO Use a pager name using include parameter ? (INCLUDE pager.tt pager_name="pager1") %]
+[% IF (pager.size) %]
+<div class="pager">
+[% IF (pager.current_page != 1) %]
+<a class="first-page ajax" href="[% pager.url %]?[% pager.query_string %]&amp;page=1">&lt;&lt;</a>
+<a class="previous-page ajax" href="[% pager.url %]?[% pager.query_string %]&amp;page=[% pager.current_page - 1 %]">&lt;</a>
+[% FOR p IN pager.previous_pages %]
+<a class="previous-page-number ajax" href="[% pager.url %]?[% pager.query_string %]&amp;page=[% p %]">[% p %]</a>
+[% END %]
+[% ELSE %]
+<span class="first-page-disabled">&lt;&lt;</span>
+<span class="previous-page-disabled">&lt;</span>
+[% END %]
+<span class="current-page">[% pager.current_page %]</span>
+[% IF (pager.current_page != pager.last_page) %]
+[% FOR p IN pager.next_pages %]
+<a class="next-page-number ajax" href="[% pager.url %]?[% pager.query_string %]&amp;page=[% p %]">[% p %]</a>
+[% END %]
+<a class="next-page ajax" href="[% pager.url %]?[% pager.query_string %]&amp;page=[% pager.current_page + 1 %]">&gt;</a>
+<a class="last-page ajax" href="[% pager.url %]?[% pager.query_string %]&amp;page=[% pager.last_page %]">&gt;&gt;</a>
+[% ELSE %]
+<span class="next-page-disabled">&gt;</span>
+<span class="last-page-disabled">&gt;&gt;</span>
+[% END %]
+</div>
+[% END %]
\ No newline at end of file

Added: branches/vhffs-design/vhffs-public/templates/content/groupsearch-form.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/content/groupsearch-form.tt	                        (rev 0)
+++ branches/vhffs-design/vhffs-public/templates/content/groupsearch-form.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -0,0 +1,38 @@
+<h1>[% 'Project search' | i18n%]</h1>
+<form action="groupsearch.pl" method="post" id="AdvancedSearchGroupForm">
+<h2>[% 'Tags' | i18n %]</h2>
+<p>[% 'Matches' | i18n %]:
+<span id="searchTagInclude">
+[% FOREACH t = included_tags %]
+<span>[% t.tag_label %]&nbsp;<a href="?[% query_string %]&amp;discard_inc=[% t.tag_id %]">X</a></span>
+<input type="hidden" name="included_tags" id="included_tags[% t.tag_id %]" value="[% t.tag_id %]"/>
+[% END %]
+</span></p>
+<p>[% "Doesn't matches" | i18n %]:
+<span id="searchTagExclude">
+[% FOREACH t = excluded_tags %]
+<span>[% t.tag_label %]&nbsp;<a href="?[% query_string %]&amp;discard_ex=[% t.tag_id %]">X</a></span>
+<input type="hidden" name="excluded_tags" id="excluded_tags[% t.tag_id %]" value="[% t.tag_id %]"/>
+[% END %]
+</span></p>
+<p>[% 'Other tags' | i18n %]:</p>
+<div id="searchTagsList">
+[% FOREACH t = other_tags %]
+<span id="tag[% t.tag_id %]">
+	<span class="label">[% t.tag_label %]</span>&nbsp;<a class="include" href="?[% query_string %]&amp;included_tags=[% t.tag_id %]">+</a>/<a class="exclude" href="?[% query_string %]&amp;excluded_tags=[% t.tag_id %]">-</a>
+</span>
+[% END %]
+</div>
+<h2>[% 'Advanced search' | i18n %]</h2>
+<p><label for="groupname">[% 'Groupname' | i18n %]:</label>
+<input type="text" maxlength="50" id="groupname" name="groupname"/></p>
+<p><label for="description">[% 'Description' | i18n %]:</label>
+<textarea name="description" id="description"></textarea></p>
+<p class="submit"><input type="submit" value="[% 'OK' | i18n %]" name="searchSubmit" id="AdvancedSearchGroupFormSubmit"/></p>
+</form>
+<script type="text/javascript">
+<!--
+dojo.addOnLoad(Public.SearchGroup.onLoad);
+//-->
+</script>
+

Added: branches/vhffs-design/vhffs-public/templates/content/groupsearch-results.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/content/groupsearch-results.tt	                        (rev 0)
+++ branches/vhffs-design/vhffs-public/templates/content/groupsearch-results.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -0,0 +1,8 @@
+<h1>[% gs_title %]</h1>
+[% INCLUDE common/pager.tt pager=gs_pager%]
+
+[% FOREACH g = groups %]
+[% INCLUDE 'parts/group-general.tt' %]
+[% END %]
+
+[% INCLUDE common/pager.tt  pager=gs_pager%]
\ No newline at end of file

Modified: branches/vhffs-design/vhffs-public/templates/content/last-groups.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/content/last-groups.tt	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/templates/content/last-groups.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -1,14 +1,5 @@
 <h1>[% lg_title %]</h1>
 
 [% FOREACH g = groups %]
-<h2 class="groupname">[% g.realname | html%]</h2>
-[% g.get_groupname %]
-<div class="group-info">
-<img class="group-avatar" src="/avatar.pl?oid=[% g.object_id %]"/>
-<p><span class="groupname">[% g.groupname %]</span> (<span class="owner">[% g.owner_name %]</span>)</p>
-<div class="description">
-[% g.description | html | html_para %]
-</div>
-<p class="more-group"><a href="/group.pl?groupname=[% g.groupname %]">[% 'More info...' | i18n %]</a></p>
-</div>
+[% INCLUDE 'parts/group-general.tt' %]
 [% END %]

Modified: branches/vhffs-design/vhffs-public/templates/layouts/public.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/layouts/public.tt	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/templates/layouts/public.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -8,6 +8,7 @@
 [%# TODO: Add a parameter to include extra-js %]
   
   <script type="text/javascript" src="/js/dojo/dojo.js"></script>
+  <script type="text/javascript" src="/js/dijit/dijit.js"></script>
   <script type="text/javascript" src="/js/public.js"></script>
   <title>Vhffs::Virtual hosting for free software</title>
 </head>
@@ -26,7 +27,7 @@
 	<div id="right-menu">
 	[% INCLUDE $right %]
 	</div>
-	<div class="public-content">
+	<div id="public-content">
 	[% PROCESS $template %]
 	</div>
 	<div id="footer">

Added: branches/vhffs-design/vhffs-public/templates/parts/group-general.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/parts/group-general.tt	                        (rev 0)
+++ branches/vhffs-design/vhffs-public/templates/parts/group-general.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -0,0 +1,10 @@
+<h2 class="groupname">[% g.realname | html%]</h2>
+[% g.get_groupname %]
+<div class="group-info">
+<img class="group-avatar" src="/avatar.pl?oid=[% g.object_id %]"/>
+<p><span class="groupname">[% g.groupname %]</span> (<span class="owner">[% g.owner_name %]</span>)</p>
+<div class="description">
+[% g.description | html | html_para %]
+</div>
+<p class="more-group"><a href="/group.pl?groupname=[% g.groupname %]">[% 'More info...' | i18n %]</a></p>
+</div>
\ No newline at end of file

Modified: branches/vhffs-design/vhffs-public/templates/parts/left-menu.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/parts/left-menu.tt	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/templates/parts/left-menu.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -2,9 +2,9 @@
 	<h1>[% 'Public' | i18n %]</h1>
 	<h2>[% 'Projects' | i18n %]</h2>
 	<div class="menu">
-		<a href="/groupsearch.pl">[% 'Search' | i18n %]</a>
-		<a href="/">[% 'Last projects' | i18n %]</a>
-		<a href="/allgroups.pl">[% 'All' | i18n %]</a>
+		<a href="/groupsearch_form.pl" class="ajax">[% 'Search' | i18n %]</a>
+		<a href="/" class="ajax">[% 'Last projects' | i18n %]</a>
+		<a href="/allgroups.pl" class="ajax">[% 'All' | i18n %]</a>
 	</div>
 	<h2>[% 'Webareas' | i18n %]</h2>
 	<div class="menu">

Modified: branches/vhffs-design/vhffs-public/templates/parts/tags-cloud.tt
===================================================================
--- branches/vhffs-design/vhffs-public/templates/parts/tags-cloud.tt	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-public/templates/parts/tags-cloud.tt	2008-10-30 07:15:19 UTC (rev 1297)
@@ -2,7 +2,7 @@
 <div class="menu tags-menu">
 	<p>
 [% FOREACH t = popular_tags %]
-	<a href="/tagsearch.pl?tag=[% t.tag_id %]" class="tag[%t.weight%]">
+	<a href="/tagsearch.pl?tag=[% t.tag_id %]" class="tag[%t.weight%] ajax">
 	[<span title="[% t.category_description | html %]">[% t.category_label | html %]</span>::<span title="[% t.tag_description | html %]">[% t.tag_label | html %]</span>] 
 	</a>
 [% END %]
@@ -14,7 +14,7 @@
 <div class="menu tags-menu">
 	<p>
 [% FOREACH t = random_tags %]
-	<a href="/tagsearch.pl?tag=[% t.tag_id %]" class="tag[%t.weight%]">
+	<a href="/tagsearch.pl?tag=[% t.tag_id %]" class="tag[%t.weight%] ajax">
 	[<span title="[% t.category_description | html %]">[% t.category_label | html %]</span>::<span title="[% t.tag_description | html %]">[% t.tag_label | html %]</span>]
 	</a>
 [% END %]

Modified: branches/vhffs-design/vhffs-themes/light-grey/main.css
===================================================================
--- branches/vhffs-design/vhffs-themes/light-grey/main.css	2008-10-30 07:14:41 UTC (rev 1296)
+++ branches/vhffs-design/vhffs-themes/light-grey/main.css	2008-10-30 07:15:19 UTC (rev 1297)
@@ -406,7 +406,7 @@
 	color: rgb(105, 105, 105)
 }
 
-div.tags-menu p.more-tags,div.public-content p.more-group {
+div.tags-menu p.more-tags,div#public-content p.more-group {
 	font-size: 12px;
 	text-align: center
 }
@@ -414,7 +414,7 @@
 /******************************************************************************/
 	/* SECTION 3 - SPECIFIC CLASSES FOR LAYOUT #1 (With navigation, with sidebar )*/
 	/******************************************************************************/
-.public-content {
+#public-content {
 	width: 410px;
 	min-height: 500px;
 	margin: 0px 0px 0px 0px;
@@ -423,15 +423,15 @@
 	font-size: 10px;
 }
 
-.public-content h2 {
+#public-content h2 {
 	margin: 10px 0px;
 }
 
-.public-content h1+h2 {
+#public-content h1+h2 {
 	margin: 5px 0px 10px;
 }
 
-.public-content p {
+#public-content p {
 	font-size: 120%
 }
 
@@ -972,7 +972,7 @@
 	height: 200px;
 }
 
-.public-content textarea {
+#public-content textarea {
 	width: 400px;
 	height: 150px;
 }
@@ -1348,11 +1348,11 @@
 	list-style-image: url('img/bullet.png');
 }
 
-.public-content ul li p {
+#public-content ul li p {
 	font-size: 12px
 }
 
-.public-content a.webarea-link {
+#public-content a.webarea-link {
 	text-decoration: none;
 	font-weight: bold
 }


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/