search completed
This commit is contained in:
parent
1f3a97235b
commit
0cd851d779
3 changed files with 195 additions and 5 deletions
|
|
@ -6,8 +6,10 @@ use Moose;
|
||||||
use JSON qw( from_json to_json );
|
use JSON qw( from_json to_json );
|
||||||
use namespace::autoclean;
|
use namespace::autoclean;
|
||||||
use Scalar::Util;
|
use Scalar::Util;
|
||||||
|
use Search::QueryParser;
|
||||||
use WebGUI::Pluggable;
|
use WebGUI::Pluggable;
|
||||||
use WebGUI::Macro;
|
use WebGUI::Macro;
|
||||||
|
use WebGUI::Search;
|
||||||
|
|
||||||
has 'session' => (
|
has 'session' => (
|
||||||
is => 'ro',
|
is => 'ro',
|
||||||
|
|
@ -133,6 +135,42 @@ sub getAssetTypes {
|
||||||
|
|
||||||
return %assetList;
|
return %assetList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 getKeywordString ( keywordString )
|
||||||
|
|
||||||
|
Munge the keyword string from the user into something mysql will Do The
|
||||||
|
Right Thing with
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# Stolen from WebGUI::Search->search
|
||||||
|
sub getKeywordString {
|
||||||
|
my ( $self, $keywords ) = @_;
|
||||||
|
|
||||||
|
# do wildcards for people like they'd expect unless they are doing it themselves
|
||||||
|
unless ($keywords =~ m/"|\*/) {
|
||||||
|
# split into 'words'. Ideographic characters (such as Chinese) are
|
||||||
|
# treated as distinct words. Everything else is space delimited.
|
||||||
|
my @terms = grep { $_ ne q{} } split /\s+|(\p{Ideographic})/, $keywords;
|
||||||
|
for my $term (@terms) {
|
||||||
|
# we add padding to ideographic characters to avoid minimum word length limits on indexing
|
||||||
|
if ($term =~ /\p{Ideographic}/) {
|
||||||
|
$term = q{''}.$term.q{''};
|
||||||
|
}
|
||||||
|
$term .= q{*};
|
||||||
|
next if WebGUI::Search->_isStopword( $term );
|
||||||
|
next
|
||||||
|
if $term =~ /^[+-]/;
|
||||||
|
$term = q{+} . $term;
|
||||||
|
}
|
||||||
|
$keywords = join q{ }, @terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $keywords;
|
||||||
|
}
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 getNewContentTemplateVars
|
=head2 getNewContentTemplateVars
|
||||||
|
|
@ -260,6 +298,80 @@ sub getNewContentTemplateVars {
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 getSearchPaginator ( queryString )
|
||||||
|
|
||||||
|
Get a paginator for searching with the given queryString.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub getSearchPaginator {
|
||||||
|
my ( $self, $queryString ) = @_;
|
||||||
|
my $session = $self->session;
|
||||||
|
|
||||||
|
my $sql = 'SELECT assetId FROM assetIndex JOIN asset USING (assetId) WHERE '
|
||||||
|
. ' ( ' . $self->getSqlFromQueryString( $queryString ) . ' ) '
|
||||||
|
;
|
||||||
|
|
||||||
|
my $p = WebGUI::Paginator->new( $session );
|
||||||
|
$p->setDataByQuery( $sql );
|
||||||
|
return $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 getSqlFromQueryString ( queryString )
|
||||||
|
|
||||||
|
Parse the query string and return a SQL boolean clause suitable to be used
|
||||||
|
as a WHERE clause. Does not return WHERE, as you could also use it for HAVING
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub getSqlFromQueryString {
|
||||||
|
my ( $self, $queryString ) = @_;
|
||||||
|
|
||||||
|
my $sqp = Search::QueryParser->new( defField => 'keywords' );
|
||||||
|
my $query = $sqp->parse( $queryString );
|
||||||
|
|
||||||
|
# Recursion is recursive
|
||||||
|
my $part = sub {
|
||||||
|
my ( $query, $conj ) = @_;
|
||||||
|
my @parts;
|
||||||
|
for my $part ( @$query ) {
|
||||||
|
if ( ref $part->{value} ) {
|
||||||
|
push @parts, $self->getSqlFromQueryString( $_ );
|
||||||
|
}
|
||||||
|
elsif ( $part->{field} eq 'keywords' ) {
|
||||||
|
push @parts, "MATCH ($part->{field}) AGAINST ('"
|
||||||
|
. $self->getKeywordString( $part->{value} )
|
||||||
|
. "')";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# TODO: Add op validation
|
||||||
|
# TODO: Add field quoting
|
||||||
|
# TODO: Add value quoting
|
||||||
|
if ( $part->{op} eq ':' ) {
|
||||||
|
my $value = '%' . $part->{value} . '%';
|
||||||
|
push @parts, "$part->{field} LIKE '$value'";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
push @parts, "$part->{field} $part->{op} '$part->{value}'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return join " $conj ", @parts;
|
||||||
|
};
|
||||||
|
my $must = $query->{'+'} ? '(' . $part->( $query->{'+'}, 'AND' ) . ')' : undef;
|
||||||
|
my $mustNot = $query->{'-'} ? 'NOT ( ' . $part->( $query->{'-'}, 'OR' ) . ')' : undef;
|
||||||
|
my $may = $query->{''} ? $part->( $query->{''}, 'OR' ) : undef;
|
||||||
|
|
||||||
|
my $sql = $must . ( $must && $mustNot ? " AND " : '' ) . $mustNot
|
||||||
|
. ( $must || $mustNot ? " OR " : '' ) . $may
|
||||||
|
;
|
||||||
|
return $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 getTreePaginator ( $asset )
|
=head2 getTreePaginator ( $asset )
|
||||||
|
|
||||||
Get a page for the Asset Tree view. Returns a WebGUI::Paginator object
|
Get a page for the Asset Tree view. Returns a WebGUI::Paginator object
|
||||||
|
|
@ -518,6 +630,64 @@ sub www_processAssetHelper {
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_searchAssets ( )
|
||||||
|
|
||||||
|
Search the asset tree for the given keywords and filters
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_searchAssets {
|
||||||
|
my ( $self ) = @_;
|
||||||
|
my $session = $self->session;
|
||||||
|
my ( $user, $form ) = $session->quick(qw{ user form });
|
||||||
|
|
||||||
|
# Get the search
|
||||||
|
my $queryString = $form->get('query');
|
||||||
|
return to_json( {} ) unless $queryString;
|
||||||
|
|
||||||
|
my $i18n = WebGUI::International->new( $session, "Asset" );
|
||||||
|
my $assetInfo = { assets => [] };
|
||||||
|
my $p = $self->getSearchPaginator( $queryString );
|
||||||
|
|
||||||
|
for my $result ( @{ $p->getPageData } ) {
|
||||||
|
my $assetId = $result->{assetId};
|
||||||
|
my $asset = WebGUI::Asset->newById( $session, $assetId );
|
||||||
|
|
||||||
|
# Populate the required fields to fill in
|
||||||
|
my %fields = (
|
||||||
|
assetId => $asset->getId,
|
||||||
|
url => $asset->getUrl,
|
||||||
|
lineage => $asset->lineage,
|
||||||
|
title => $asset->menuTitle,
|
||||||
|
revisionDate => $asset->revisionDate,
|
||||||
|
childCount => $asset->getChildCount,
|
||||||
|
assetSize => $asset->assetSize,
|
||||||
|
lockedBy => ($asset->isLockedBy ? $asset->lockedBy->username : ''),
|
||||||
|
canEdit => $asset->canEdit && $asset->canEditIfLocked,
|
||||||
|
helpers => $asset->getHelpers,
|
||||||
|
);
|
||||||
|
|
||||||
|
$fields{ className } = {};
|
||||||
|
# The asset icon
|
||||||
|
$fields{ icon } = $asset->getIcon("small");
|
||||||
|
|
||||||
|
# The asset type (i18n name)
|
||||||
|
$fields{ className } = $asset->getName;
|
||||||
|
|
||||||
|
push @{ $assetInfo->{ assets } }, \%fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
$assetInfo->{ totalAssets } = $p->getRowCount;
|
||||||
|
$assetInfo->{ sort } = $session->form->get( 'orderByColumn' );
|
||||||
|
$assetInfo->{ dir } = lc $session->form->get( 'orderByDirection' );
|
||||||
|
|
||||||
|
$session->http->setMimeType( 'application/json' );
|
||||||
|
|
||||||
|
return to_json( $assetInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 www_view ( session )
|
=head2 www_view ( session )
|
||||||
|
|
||||||
Show the main Admin console wrapper
|
Show the main Admin console wrapper
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,10 @@ input.disabled {
|
||||||
margin: 1em 8% 0;
|
margin: 1em 8% 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.searchResults table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.searchKeywords {
|
.searchKeywords {
|
||||||
display: block;
|
display: block;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,10 @@ WebGUI.Admin.prototype.editAsset
|
||||||
*/
|
*/
|
||||||
WebGUI.Admin.prototype.gotoAsset
|
WebGUI.Admin.prototype.gotoAsset
|
||||||
= function ( url ) {
|
= function ( url ) {
|
||||||
|
if ( this.tabBar.get('activeIndex') > 1 ) {
|
||||||
|
this.tabBar.selectTab( 0 );
|
||||||
|
this.currentTab = "view";
|
||||||
|
}
|
||||||
if ( this.currentTab == "view" ) {
|
if ( this.currentTab == "view" ) {
|
||||||
window.frames[ "view" ].location.href = url;
|
window.frames[ "view" ].location.href = url;
|
||||||
this.treeDirty = 1;
|
this.treeDirty = 1;
|
||||||
|
|
@ -1268,7 +1272,7 @@ WebGUI.Admin.AssetTable.prototype.showHelperMenu
|
||||||
// destroy the old helper menu!
|
// destroy the old helper menu!
|
||||||
this.helperMenu.destroy();
|
this.helperMenu.destroy();
|
||||||
}
|
}
|
||||||
this.helperMenu = new YAHOO.widget.Menu( {
|
this.helperMenu = new YAHOO.widget.Menu( document.createElement('div'), {
|
||||||
position : "dynamic",
|
position : "dynamic",
|
||||||
clicktohide : true,
|
clicktohide : true,
|
||||||
constraintoviewport : true,
|
constraintoviewport : true,
|
||||||
|
|
@ -1939,11 +1943,13 @@ WebGUI.Admin.Search
|
||||||
|
|
||||||
// Create a container for the datatable
|
// Create a container for the datatable
|
||||||
this.dataTableContainer = document.createElement('div');
|
this.dataTableContainer = document.createElement('div');
|
||||||
|
this.dataTableContainer.style.display = "none";
|
||||||
|
this.dataTableContainer.className = "searchResults";
|
||||||
this.dataTableContainer.id = YAHOO.util.Dom.generateId();
|
this.dataTableContainer.id = YAHOO.util.Dom.generateId();
|
||||||
this.formContainer.appendChild( this.dataTableContainer );
|
this.formContainer.appendChild( this.dataTableContainer );
|
||||||
|
|
||||||
// Create a container for the paginator
|
// Create a container for the paginator
|
||||||
// ...
|
// TODO
|
||||||
WebGUI.Admin.Search.superclass.constructor.call( this, admin, {
|
WebGUI.Admin.Search.superclass.constructor.call( this, admin, {
|
||||||
dataSourceUrl : '?op=admin;method=searchAssets;',
|
dataSourceUrl : '?op=admin;method=searchAssets;',
|
||||||
dataTableId : this.dataTableContainer.id,
|
dataTableId : this.dataTableContainer.id,
|
||||||
|
|
@ -2141,9 +2147,9 @@ WebGUI.Admin.Search.prototype.buildQueryString
|
||||||
WebGUI.Admin.Search.prototype.requestSearch
|
WebGUI.Admin.Search.prototype.requestSearch
|
||||||
= function ( ) {
|
= function ( ) {
|
||||||
// Build the new search URL
|
// Build the new search URL
|
||||||
var searchUrl = ';keywords=' + encodeURIComponent( this.searchKeywords.value );
|
var query = 'query=' + encodeURIComponent( this.searchKeywords.value );
|
||||||
for ( var i = 0; i < this.filters.length; i++ ) {
|
for ( var i = 0; i < this.filters.length; i++ ) {
|
||||||
searchUrl += ';' + filter.type + '=' + filter.getValue();
|
query += ' ' + encodeURIComponent( filter.type + ':' + filter.getValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
var callback = {
|
var callback = {
|
||||||
|
|
@ -2157,10 +2163,20 @@ WebGUI.Admin.Search.prototype.requestSearch
|
||||||
this.buildQueryString(
|
this.buildQueryString(
|
||||||
this.dataTable.getState(),
|
this.dataTable.getState(),
|
||||||
this.dataTable,
|
this.dataTable,
|
||||||
searchUrl
|
query
|
||||||
),
|
),
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onDataReturnInitializeTable ( sRequest, oResponse, oPayload )
|
||||||
|
* Initialize the table with a new response from the server
|
||||||
|
*/
|
||||||
|
WebGUI.Admin.Search.prototype.onDataReturnInitializeTable
|
||||||
|
= function ( sRequest, oResponse, oPayload ) {
|
||||||
|
this.dataTableContainer.style.display = "block";
|
||||||
|
WebGUI.Admin.Tree.superclass.onDataReturnInitializeTable.call( this, sRequest, oResponse, oPayload );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue