[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 = ' 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('&included_tags=', @included_tag_ids)) if(scalar(@included_tag_ids));
+$query_string .= '&' if(scalar(@included_tag_ids) && scalar(@excluded_tag_ids));
+$query_string .= 'excluded_tags='.(join('&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 %]&page=1"><<</a>
+<a class="previous-page ajax" href="[% pager.url %]?[% pager.query_string %]&page=[% pager.current_page - 1 %]"><</a>
+[% FOR p IN pager.previous_pages %]
+<a class="previous-page-number ajax" href="[% pager.url %]?[% pager.query_string %]&page=[% p %]">[% p %]</a>
+[% END %]
+[% ELSE %]
+<span class="first-page-disabled"><<</span>
+<span class="previous-page-disabled"><</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 %]&page=[% p %]">[% p %]</a>
+[% END %]
+<a class="next-page ajax" href="[% pager.url %]?[% pager.query_string %]&page=[% pager.current_page + 1 %]">></a>
+<a class="last-page ajax" href="[% pager.url %]?[% pager.query_string %]&page=[% pager.last_page %]">>></a>
+[% ELSE %]
+<span class="next-page-disabled">></span>
+<span class="last-page-disabled">>></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 %] <a href="?[% query_string %]&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 %] <a href="?[% query_string %]&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> <a class="include" href="?[% query_string %]&included_tags=[% t.tag_id %]">+</a>/<a class="exclude" href="?[% query_string %]&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
}