Add top-level keywords, which allows for hierarchial categorization of wiki pages.

This commit is contained in:
Colin Kuskie 2010-04-16 20:46:55 -07:00
parent 1a77fce843
commit 55d2e510d6
8 changed files with 489 additions and 1 deletions

View file

@ -5,6 +5,8 @@
- fixed #11520: Wiki Locked
- fixed Missing Template variables for the Wiki Page view template.
- added #10944: Wiki Keyword Page
- added #10946: Wiki - Hierarchical Keyword Report
- added #10945: Wiki - Top-level keyword list
7.9.2
- added: Workflow to extend recurring Calendar events 2 years from the

View file

@ -31,6 +31,7 @@ my $quiet; # this line required
my $session = start(); # this line required
reindexSiteForDefaultSynopsis( $session );
addTopLevelWikiKeywords( $session );
finish($session); # this line required
@ -44,6 +45,24 @@ finish($session); # this line required
# print "DONE!\n" unless $quiet;
#}
#----------------------------------------------------------------------------
sub addTopLevelWikiKeywords {
my $session = shift;
print "\tAdding top level keywords page to WikiMaster... " unless $quiet;
my $sth = $session->db->read('DESCRIBE `WikiMaster`');
while (my ($col) = $sth->array) {
if ($col eq 'topLevelKeywords') {
print "Skipped.\n" unless $quiet;
return;
}
}
$session->db->write('ALTER TABLE WikiMaster ADD COLUMN topLevelKeywords LONGTEXT');
print "Done.\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Reindex the site to clear out default synopsis
sub reindexSiteForDefaultSynopsis {

View file

@ -22,6 +22,8 @@ use WebGUI::International;
use WebGUI::Utility;
use HTML::Parser;
use URI::Escape;
use WebGUI::Form;
use Clone qw/clone/;
#-------------------------------------------------------------------
@ -43,12 +45,29 @@ sub appendFeaturedPageVars {
#-------------------------------------------------------------------
=head2 appendKeywordPageVars ( var )
Append the template variables to C<var> for keyword (catagory) pages.
=cut
sub appendKeywordPageVars {
my ( $self, $var ) = @_;
my $session = $self->session;
my $topKeywords = $self->getTopLevelKeywordsList;
my $keywordHierarchy = $self->getKeywordHierarchy( $topKeywords, );
$var->{keywords_loop} = $self->getKeywordVariables( $keywordHierarchy );
return $var;
}
#-------------------------------------------------------------------
=head2 appendMostPopular ($var, [ $limit ])
=head3 $var
A hash reference of template variables. An array reference containing the most popular wiki pages
in order of popularity.
in order of popularity will be appended to it.
=head3 $limit
@ -425,6 +444,13 @@ sub definition {
label=>$i18n->get('filter code'),
hoverHelp=>$i18n->get('filter code description'),
},
topLevelKeywords =>{
fieldType => "keywords",
defaultValue => '',
tab => 'properties',
label => $i18n->get('top level keywords'),
hoverHelp => $i18n->get('top level keywords description'),
},
);
push @$definition,
@ -461,6 +487,108 @@ sub getFeaturedPageIds {
#-------------------------------------------------------------------
=head2 getKeywordHierarchy ( $keywords, $seen )
Starting with the top level keywords, return the hierarchy of keywords as a recursive arrayref of hashrefs.
The traversal is left-most, depth first.
The hierarchy data structure that looks like this:
[
{
title => 'title', # same as the keyword, since this is a keyword (category) page
url => 'url', # url from the keyword page, via getUrl so it contains the gateway URL
# If a keyword page does not exist for the keyword, this key/value pair will not be present.
children => [ # Array reference of sub-categories referenced by this category
{ # If there are no children, this key/value pair will not be present
...
}
]
}
]
=head3 $keywords
An array reference of keywords. If this is blank, then it will use the top level keywords from
itself as a default.
=head3 $seen
A hash reference that keeps track of which keywords have already been seen. This prevents
infinite loops from happening during the traversal.
=cut
sub getKeywordHierarchy {
my ( $self, $keywords, $seen ) = @_;
my $session = $self->session;
my $hierarchy = [];
$keywords ||= $self->getTopLevelKeywordsList;
$seen ||= {};
KEYWORD: foreach my $keyword (sort @{ $keywords }) {
my $page = $self->getLineage(['children'], {
returnObjects => 1,
whereClause => 'assetData.title = '.$session->db->quote($keyword),
limit => 1,
includeOnlyClasses => [qw/WebGUI::Asset::WikiPage/],
})->[0];
if (! $page) {
push @{ $hierarchy }, { title => $keyword, url => '', };
next KEYWORD;
}
my $datum = {
title => $keyword, ##Note, same as keyword
url => $page->getUrl,
};
##Prevent recursion if seen again
if (! $seen->{$keyword}++) {
my $children = $self->getKeywordHierarchy(WebGUI::Keyword::string2list($page->get('keywords')), $seen, );
if (@{ $children } ) {
$datum->{children} = $children;
}
}
push @{ $hierarchy }, $datum;
}
return $hierarchy;
}
#-------------------------------------------------------------------
=head2 getKeywordVariables ( $hierarchy, $level )
Take a data structure representing a hierarchy of keywords, and append template variables
to them similar to a Navigation so you can build useful things with them.
=head3 $hierarchy
A data structure similar to that produced by getKeywordHierarchy
=head3 $level
The current level in any part of the hierarchy.
=cut
sub getKeywordVariables {
my ( $self, $hierarchy, $level ) = @_;
$level ||= 0;
my $variables = [];
KEYWORD: foreach my $member (@{ $hierarchy }) {
my $varBlock = clone $member;
$varBlock->{level} = $level;
$varBlock->{indent_loop} = [ map { { indent => $_ } } 1..$level ];
delete $varBlock->{children};
push @{$variables}, $varBlock;
if ( exists $member->{children} ) {
push @{$variables}, @{ $self->getKeywordVariables($member->{children}, $level+1) };
}
}
return $variables;
}
#-------------------------------------------------------------------
=head2 getRssFeedItems ()
Returns an array reference of hash references. Each hash reference has a title,
@ -520,6 +648,19 @@ sub getTemplateVars {
return $var;
}
#----------------------------------------------------------------------------
=head2 getTopLevelKeywordsList ( )
Return the top level keywords as an array reference.
=cut
sub getTopLevelKeywordsList {
my ( $self ) = @_;
return WebGUI::Keyword::string2list($self->get('topLevelKeywords'));
}
#-------------------------------------------------------------------
=head2 prepareView
@ -610,6 +751,7 @@ sub view {
$self->appendSearchBoxVars($var);
$self->appendRecentChanges($var, $self->get('recentChangesCountFront'));
$self->appendMostPopular($var, $self->get('mostPopularCountFront'));
$self->appendKeywordPageVars($var);
return $self->processTemplate($var, undef, $template);
}

View file

@ -102,6 +102,26 @@ our $HELP = {
{ 'name' => 'recentChangesLabel variable', },
{ 'name' => 'addPageUrl', },
{ 'name' => 'addPageLabel', },
{ 'name' => 'keywords_loop',
'variables' => [
{ 'name' => 'title',
'description' => 'keyword title',
},
{ 'name' => 'url',
'description' => 'keyword url',
},
{ 'name' => 'level',
'description' => 'keyword level',
},
{ 'name' => 'indent_loop',
'variables' => [
{ 'name' => 'indent',
'description' => 'keyword indent',
},
],
},
],
},
],
fields => [],
related => [],

View file

@ -42,6 +42,18 @@ our $I18N = {
context => q|Hover help for edit wobject screen|,
},
'top level keywords' => {
message => q|Top Level Keywords|,
lastUpdated => 0,
context => q|Label for edit wobject screen|,
},
'top level keywords description' => {
message => q|These keywords provide the root for the hierarchial keyword display.|,
lastUpdated => 0,
context => q|Hover help for edit wobject screen|,
},
'content filter' => {
message => q|Use Content Filter?|,
lastUpdated => 0,
@ -523,6 +535,43 @@ listing of pages that are related to a specific keyword?| },
lastUpdated => 0,
context => q{Label for link to unsubscribe from e-mail notifications},
},
'keywords_loop' => {
message => q{A loop containing all the top level keywords, links to their keyword pages, and all sub pages below them.},
lastUpdated => 0,
context => q{Help for template variable},
},
'keyword title' => {
message => q{The name of a keyword.},
lastUpdated => 0,
context => q{Help for template variable},
},
'keyword url' => {
message => q{The URL to the keyword page for that keyword. If no page exists, this variable will be empty.},
lastUpdated => 0,
context => q{Help for template variable},
},
'keyword level' => {
message => q{The depth of this keyword. Top-level keywords for the wiki are level 0.},
lastUpdated => 0,
context => q{Help for template variable},
},
'indent_loop' => {
message => q{A loop that runs 1 time for each level.},
lastUpdated => 0,
context => q{Help for template variable},
},
'keyword indent' => {
message => q{The loop iterator for the indent_loop.},
lastUpdated => 0,
context => q{Help for template variable},
},
};
1;

View file

@ -4676,6 +4676,12 @@ Users may override this setting in their profile.
context => 'Message shown to the user when data is being loaded, typically via AJAX, like in the Survey.'
},
'Go' => {
message => 'Go',
lastUpdated => 0,
context => 'Label for buttons that take you someplace else'
},
};
1;

View file

@ -0,0 +1,250 @@
# vim:syntax=perl
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#------------------------------------------------------------------
# Test the featured page of the Wiki
#
#
use FindBin;
use strict;
use lib "$FindBin::Bin/../../lib";
use Test::More;
use Test::Differences;
use Test::Deep;
use Data::Dumper;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
my $import = WebGUI::Asset->getImportNode( $session );
my @childCoda = (undef, undef, { skipAutoCommitWorkflows => 1, skipNotification => 1, } );
my @revCoda = (undef, { skipAutoCommitWorkflows => 1, skipNotification => 1, } );
my $wiki
= $import->addChild( {
className => 'WebGUI::Asset::Wobject::WikiMaster',
topLevelKeywords => 'criminals,inmates,staff',
url => 'testwiki',
title => 'testwiki',
}, @childCoda );
my $wikitag = WebGUI::VersionTag->getWorking( $session );
$wikitag->commit;
WebGUI::Test->addToCleanup($wikitag);
$wiki = $wiki->cloneFromDb;
my %page_set = ();
foreach my $keywords (qw/staff inmates criminals/) {
$page_set{$keywords} = $wiki->addChild({
className => 'WebGUI::Asset::WikiPage',
title => $keywords,
}, @childCoda);
}
my $tag_set1 = WebGUI::VersionTag->getWorking($session);
$tag_set1->commit;
WebGUI::Test->addToCleanup($tag_set1);
#----------------------------------------------------------------------------
# Tests
plan tests => 11; # Increment this number for each test you create
#----------------------------------------------------------------------------
#
is $wiki->get('topLevelKeywords'), 'criminals,inmates,staff', 'checking wiki setup';
cmp_deeply($wiki->getTopLevelKeywordsList, [qw/criminals inmates staff/], 'getTopLevelKeywordList returns keywords');
cmp_deeply(
$wiki->getKeywordHierarchy(),
[
superhashof({ title => 'criminals', }),
superhashof({ title => 'inmates', }),
superhashof({ title => 'staff', }),
],
"getKeywordHierarchy, simple setup",
);
my $hierarchy = $wiki->getKeywordHierarchy();
my $variables = $wiki->getKeywordVariables($hierarchy);
cmp_deeply(
$hierarchy->[0],
{
title => 'criminals',
url => '/testwiki/criminals',
},
"getKeywordVariables, does not alter the original hierarchy passed in",
);
cmp_deeply(
$variables,
[
{
title => 'criminals',
url => '/testwiki/criminals',
level => 0,
indent_loop => [],
},
{
title => 'inmates',
url => '/testwiki/inmates',
level => 0,
indent_loop => [],
},
{
title => 'staff',
url => '/testwiki/staff',
level => 0,
indent_loop => [],
},
],
"... variables",
);
$wiki->update({topLevelKeywords => 'criminals,criminals,inmates,staff'});
is $wiki->get('topLevelKeywords'), 'criminals,criminals,inmates,staff', 'checking wiki setup 2';
cmp_deeply($wiki->getTopLevelKeywordsList, [qw/criminals criminals inmates staff/], 'getTopLevelKeywordList returns keywords, even with duplicates');
cmp_deeply(
$wiki->getKeywordHierarchy(),
[
superhashof({ title => 'criminals', }),
superhashof({ title => 'criminals', }),
superhashof({ title => 'inmates', }),
superhashof({ title => 'staff', }),
],
"getKeywordHierarchy, simple setup, duplicates listed",
);
$wiki->update({topLevelKeywords => 'criminals,inmates,staff'});
$page_set{criminals}->update({keywords => 'red,andy'});
$page_set{inmates}->update({keywords => 'brooks,heywood'});
$page_set{staff}->update({keywords => 'norton,hadley'});
foreach my $title (qw/red andy brooks heywood norton hadley/) {
$page_set{$title} = $wiki->addChild({
className => 'WebGUI::Asset::WikiPage',
title => $title,
}, @childCoda);
}
my $tag_set2 = WebGUI::VersionTag->getWorking($session);
$tag_set2->commit;
WebGUI::Test->addToCleanup($tag_set2);
cmp_bag(
$wiki->getKeywordHierarchy(),
[
{
title => 'criminals', url => '/testwiki/criminals',
children => bag(
superhashof({ title => 'red', }),
superhashof({ title => 'andy', }),
),
},
{
title => 'inmates', url => '/testwiki/inmates',
children => bag(
superhashof({ title => 'heywood', }),
superhashof({ title => 'brooks', }),
),
},
{
title => 'staff', url => '/testwiki/staff',
children => bag(
superhashof({ title => 'norton', }),
superhashof({ title => 'hadley', }),
),
},
],
"getKeywordHierarchy: simple hierarchy",
);
##Check depth-first display, and try to make a keyword loop
$page_set{andy}->update({keywords => 'criminals,inmates'});
$page_set{brooks}->update({keywords => 'criminals'});
my $tag_set3 = WebGUI::VersionTag->getWorking($session);
$tag_set3->commit;
WebGUI::Test->addToCleanup($tag_set3);
cmp_bag(
$wiki->getKeywordHierarchy(),
[
superhashof({
title => 'criminals',
children => bag(
superhashof({
title => 'andy',
children => bag(
superhashof({
title => 'inmates',
children => bag(
superhashof({ title => 'heywood', }),
superhashof({
title => 'brooks',
children => bag(
superhashof({ title => 'criminals', }),
),
}),
),
}),
superhashof({ title => 'criminals', }),
),
}),
superhashof({ title => 'red', }),
),
}),
superhashof({
title => 'inmates',
}),
superhashof({
title => 'staff',
children => bag(
superhashof({ title => 'norton', }),
superhashof({ title => 'hadley', }),
),
}),
],
"getKeywordHierarchy: complex hierarcy, depth-first display and loop handling",
);
cmp_deeply(
$wiki->getKeywordVariables([
{
title => 'title 0', url => 'url 0',
children => [ {
title => 'title 1', url => 'url 1',
children => [ {
title => 'title 2', url => 'url 2',
}, ],
}, ],
},
]),
[
{ title => 'title 0', url => 'url 0', level => 0, indent_loop => [], },
{ title => 'title 1', url => 'url 1', level => 1, indent_loop => [{indent => 1}], },
{ title => 'title 2', url => 'url 2', level => 2, indent_loop => [{indent => 1,}, {indent => 2,},], },
],
'getKeywordVariables: checking deeply'
);
$page_set{criminals}->update({keywords => 'red,andy,tommy'});
#vim:ft=perl