- Added keyword tagging to Wiki.

This commit is contained in:
JT Smith 2007-07-07 21:09:39 +00:00
parent 23fa0283b3
commit f36ba1b268
17 changed files with 323 additions and 213 deletions

View file

@ -5,6 +5,7 @@
WebGUI::Operation::Workflow::www_activityHelper for details.
- Added pagination to purchase history in commerce.
- Added keyword tagging api.
- Added keyword tagging to Wiki.
- improved performance of EMS
- upgraded YUI to 2.2.2 and YUI-ext to 1.0.1a
- Improved error handling in Spectre when WebGUI hands it bad data.

View file

@ -1,58 +0,0 @@
#PBtmpl0000000000000207
#title: Article with Files
#url: article-with-files
#menutitle:
<a name="id<tmpl_var assetId>" id="id<tmpl_var assetId>"></a>
<tmpl_if session.var.adminOn>
<p><tmpl_var controls></p>
</tmpl_if>
<tmpl_if displayTitle>
<h2><tmpl_var title></h2>
</tmpl_if>
<tmpl_if pagination.isFirstPage>
</tmpl_if>
<tmpl_if description>
<tmpl_var description>
</tmpl_if>
<tmpl_if pagination.isLastPage>
<tmpl_if linkUrl>
<tmpl_if linkTitle>
<p />
<a href="<tmpl_var linkUrl>"><tmpl_var linkTitle></a>
</tmpl_if>
</tmpl_if>
<tmpl_loop attachment_loop>
<p style="display:inline;vertical-align:middle;"><a href="<tmpl_var url>"><img src="<tmpl_var iconUrl>" style="vertical-align:middle;border: 0px;" alt="<tmpl_var filename>" /> <tmpl_var filename></a></p><br />
</tmpl_loop>
</tmpl_if>
<tmpl_if pagination.pageCount.isMultiple>
<tmpl_var pagination.previousPage>
&#183;
<tmpl_var pagination.pageList.upTo20>
&#183;
<tmpl_var pagination.nextPage>
</tmpl_if>
<tmpl_if pagination.isFirstPage>
</tmpl_if>
<tmpl_if pagination.isLastPage>
<tmpl_if allowDiscussion>
<p>
<table width="100%" cellspacing="2" cellpadding="1" border="0">
<tr>
<td align="center" width="50%" class="tableMenu"><a href="<tmpl_var replies.URL>"><tmpl_var replies.label> (<tmpl_var replies.count>)</a></td>
<td align="center" width="50%" class="tableMenu"><a href="<tmpl_var post.url>"><tmpl_var post.label></a></td>
</tr>
</table>
</tmpl_if>
</tmpl_if>

View file

@ -0,0 +1,15 @@
#WikiKeyword00000000001
#url: wiki-master-by-keyword-template.tmpl
#title: Wiki Pages By Keyword (default)
#menuTitle: Wiki Pages By Keyword
#namespace:WikiMaster_byKeyword
#create
<h1><tmpl_var keyword></h1>
<ul>
<tmpl_loop pagesLoop>
<li><a href="<tmpl_var url>"><tmpl_var title></a></li>
</tmpl_loop>
</ul>

View file

@ -0,0 +1,33 @@
#WikiFrontTmpl000000001
<tmpl_if session.var.adminOn><p><tmpl_var controls></p></tmpl_if>
<tmpl_if displayTitle><h2><tmpl_var title></h2></tmpl_if>
<tmpl_var description>
<h3><tmpl_var searchLabel></h3>
<tmpl_var searchFormHeader><tmpl_var searchQuery><tmpl_var searchSubmit><tmpl_var searchFormFooter>
<br />
<div style="float: left; width: 50%;">
<h3><a href="<tmpl_var recentChangesUrl>"><tmpl_var recentChangesLabel></a></h3>
<ul><tmpl_loop recentChanges>
<li>
<tmpl_if isAvailable>
<a href="<tmpl_var url>"><tmpl_var title></a>
<tmpl_else>
<tmpl_var title> (<tmpl_var actionTaken>)
</tmpl_if>
</li>
</tmpl_loop></ul>
</div>
<div style="float: left;">
<h3><a href="<tmpl_var mostPopularUrl>"><tmpl_var mostPopularLabel></a></h3>
<ol><tmpl_loop mostPopular>
<li><a href="<tmpl_var url>"><tmpl_var title></a></li>
</tmpl_loop></ol>
</div>
<div style="clear: both;"></div>
<div><tmpl_var keywordCloud></div>

View file

@ -0,0 +1,110 @@
#WikiPageTmpl0000000001
<tmpl_if session.var.adminOn><p><tmpl_var controls></p></tmpl_if>
<h2><tmpl_var title></h2>
<div id="wikipage" class="yui-navset">
<ul class="yui-nav">
<li class="selected"><a href="#wikipagecontent"><em><tmpl_var viewLabel></em></a></li>
<li><a href="#wikipageedit"><em><tmpl_var editLabel></em></a></li>
</ul>
<div class="yui-content">
<div id="wikipagecontent">
<tmpl_var content>
<p>^International("keywords","Asset");: <tmpl_loop keywordsLoop><a href="<tmpl_var url>"><tmpl_var keyword></a> </tmpl_loop></p>
</div>
<div id="wikipageedit">
<tmpl_var editContent>
</div>
</div>
</div>
<script type="text/javascript">
initWikiTabs = function() {
var tabView = new YAHOO.widget.TabView('wikipage');
tabView.addTab(new YAHOO.widget.Tab({
label: '<tmpl_var historyLabel>',
dataSrc: '<tmpl_var historyUrl>',
cacheData: true
}));
};
initWikiTabs();
</script>
<div style="padding: 8px;"><a href="<tmpl_var searchUrl>"><tmpl_var searchLabel></a> | <a href="<tmpl_var
mostPopularUrl>"><tmpl_var mostPopularLabel></a> | <a href="<tmpl_var recentChangesUrl>"><tmpl_var
recentChangesLabel></a> | <a href="<tmpl_var wikiHomeUrl>"><tmpl_var wikiHomeLabel></a></div>
~~~
<link rel="stylesheet" type="text/css" href="^Extras(yui/build/tabview/assets/tabs.css);">
<script type="text/javascript" src="^Extras(yui/build/yahoo/yahoo.js);"></script>
<script type="text/javascript" src="^Extras(yui/build/event/event.js);"></script>
<script type="text/javascript" src="^Extras(yui/build/dom/dom.js);"></script>
<script type="text/javascript" src="^Extras(yui/build/connection/connection.js);"></script>
<script type="text/javascript" src="^Extras(yui/build/tabview/tabview.js);"></script>
<style type="text/css">
#wikipage.yui-navset .yui-nav li a {
border:1px solid #000; /* label and content borders */
}
#wikipage.yui-navset .yui-content {
border-top: 1px solid #000;
border-bottom: 1px solid #000;
}
background-color:#f6f7ee; /* active tab, tab hover, and content bgcolor */
}
#wikipage.yui-navset .yui-nav .selected a {
background-color:black; /* active tab, tab hover, and content bgcolor */
color: white;
}
#wikipage.yui-navset-top .yui-nav .selected a {
border-bottom:0; /* no bottom border for active tab */
padding-bottom:1px; /* to match height of other tabs */
}
#wikipage.yui-navset-top .yui-content {
margin-top:-1px; /* for active tab overlap */
}
#wikipage.yui-navset-bottom .yui-nav .selected a {
border-top:0; /* no bottom border for active tab */
padding-top:1px; /* to match height of other tabs */
}
#wikipage.yui-navset-bottom .yui-content {
margin-bottom:-1px; /* for active tab overlap */
}
#wikipage.yui-navset-left .yui-nav li.selected a {
border-right:0; /* no bottom border for active tab */
padding-right:1px; /* to match height of other tabs */
}
#wikipage.yui-navset-left .yui-content {
margin-left:-1px; /* for active tab overlap */
}
#wikipage.yui-navset-right .yui-nav li.selected a {
border-left:0; /* no bottom border for active tab */
padding-left:1px; /* to match height of other tabs */
}
#wikipage.yui-navset-right .yui-content {
margin-right:-1px; /* for active tab overlap */
*margin-right:0; /* except IE */
}
#wikipage .yui-content {
padding-top:1em;
padding-bottom:1em;
}
#wikipage .loading {
background-image:url(^Extras(yui/build/tabview/img/loading.gif););
background-position:center center;
background-repeat:no-repeat;
}
#wikipage .loading * {
display:none;
}
</style>

View file

@ -0,0 +1,28 @@
#WikiPageEditTmpl000001
<tmpl_var formHeader>
<table>
<tbody>
<tr><td><label for="title_formId"><tmpl_var titleLabel></label></td><td><tmpl_var formTitle></td></tr>
<tr><td><label for="content_formId"><tmpl_var contentLabel></label></td><td><tmpl_var formContent></td></tr>
<tr><td><label for="keywords_formId">^International("keywords","Asset");</label></td><td><tmpl_var formKeywords></td></tr>
<tmpl_if canAdminister>
<tr><td><label for="isProtected_formId"><tmpl_var protectQuestionLabel></label></td><td><tmpl_var
formProtect></td></tr>
</tmpl_if>
<tmpl_if allowsAttachments>
<tr><td><label for="storageId_formId"><tmpl_var attachmentLabel></label></td><td><tmpl_var
formAttachment></td></tr>
</tmpl_if>
</tbody>
</table>
<tmpl_var formSubmit>
<tmpl_var formFooter>
<tmpl_if canAdminister><tmpl_unless isNew>
<ul>
<li><a href="<tmpl_var deleteUrl>" onclick="return confirm('<tmpl_var deleteConfirm
ESCAPE="JS">');"><tmpl_var deleteLabel></a></li>
</ul>
</tmpl_unless></tmpl_if>
~~~

View file

@ -1,146 +0,0 @@
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2007 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
#-------------------------------------------------------------------
use lib "../../lib";
use strict;
use Getopt::Long;
use WebGUI::Session;
use WebGUI::Asset;
use WebGUI::Workflow;
my $toVersion = "7.3.19"; # make this match what version you're going to
my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
fixAssetSizes($session);
resequenceWorkflowActivities($session);
finish($session); # this line required
#-------------------------------------------------
sub fixAssetSizes {
my $session = shift;
print "\tFix the sizes of ALL Image and Size assets. This will take a while.\n" unless ($quiet);
my $root = WebGUI::Asset->getRoot($session);
foreach my $fileAsset ( @{ $root->getLineage(["self","descendants"],{returnObjects=>1,includeOnlyClasses=>['WebGUI::Asset::File','WebGUI::Asset::Image']}) } ) {
$fileAsset->setSize();
}
}
#-------------------------------------------------
sub resequenceWorkflowActivities {
my $session = shift;
print "\tFix sequencing problems in Workflow Activities. This will take a while.\n" unless ($quiet);
my $workflows = WebGUI::Workflow->getList($session, undef, 1); ##Hack to get around non-existant mode column
my ($workflowId, $title);
while ( ($workflowId, $title) = each %{ $workflows } ) {
my $workflow = WebGUI::Workflow->new($session, $workflowId);
next unless defined $workflow;
$workflow->reorderActivities;
}
}
# ---- DO NOT EDIT BELOW THIS LINE ----
#-------------------------------------------------
sub start {
my $configFile;
$|=1; #disable output buffering
GetOptions(
'configFile=s'=>\$configFile,
'quiet'=>\$quiet
);
my $session = WebGUI::Session->open("../..",$configFile);
$session->user({userId=>3});
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Upgrade to ".$toVersion});
$session->db->write("insert into webguiVersion values (".$session->db->quote($toVersion).",'upgrade',".$session->datetime->time().")");
updateTemplates($session);
return $session;
}
#-------------------------------------------------
sub finish {
my $session = shift;
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->commit;
$session->close();
}
#-------------------------------------------------
sub updateTemplates {
my $session = shift;
return undef unless (-d "templates-".$toVersion);
print "\tUpdating templates.\n" unless ($quiet);
opendir(DIR,"templates-".$toVersion);
my @files = readdir(DIR);
closedir(DIR);
my $importNode = WebGUI::Asset->getImportNode($session);
my $newFolder = undef;
foreach my $file (@files) {
next unless ($file =~ /\.tmpl$/);
open(FILE,"<templates-".$toVersion."/".$file);
my $first = 1;
my $create = 0;
my $head = 0;
my %properties = (className=>"WebGUI::Asset::Template");
while (my $line = <FILE>) {
if ($first) {
$line =~ m/^\#(.*)$/;
$properties{id} = $1;
$first = 0;
} elsif ($line =~ m/^\#create$/) {
$create = 1;
} elsif ($line =~ m/^\#(.*):(.*)$/) {
$properties{$1} = $2;
} elsif ($line =~ m/^~~~$/) {
$head = 1;
} elsif ($head) {
$properties{headBlock} .= $line;
} else {
$properties{template} .= $line;
}
}
close(FILE);
if ($create) {
$newFolder = createNewTemplatesFolder($importNode) unless (defined $newFolder);
my $template = $newFolder->addChild(\%properties, $properties{id});
} else {
my $template = WebGUI::Asset->new($session,$properties{id}, "WebGUI::Asset::Template");
if (defined $template) {
my $newRevision = $template->addRevision(\%properties);
}
}
}
}
#-------------------------------------------------
sub createNewTemplatesFolder {
my $importNode = shift;
my $newFolder = $importNode->addChild({
className=>"WebGUI::Asset::Wobject::Folder",
title => $toVersion." New Templates",
menuTitle => $toVersion." New Templates",
url=> $toVersion."_new_templates",
groupIdView=>"12"
});
return $newFolder;
}

View file

@ -45,6 +45,8 @@ sub addKeywordTagging {
index keyword (keyword),
index assetId (assetId)
)");
$session->db->write("alter table WikiMaster add column byKeywordTemplateId varchar(22) binary
not null default 'WikiKeyword00000000001'");
}
#-------------------------------------------------

View file

@ -1787,6 +1787,9 @@ sub processPropertiesFromFormPost {
);
}
}
if ($form->process("keywords")) {
$data{keywords} = $form->process("keywords");
}
if ($self->session->setting->get("metaDataEnabled")) {
my $meta = $self->getMetaDataFields;
foreach my $field (keys %{$meta}) {

View file

@ -158,7 +158,7 @@ sub getEditForm {
formKeywords => WebGUI::Form::text($session, {
name => "keywords",
value => WebGUI::Keyword->new($session)->getKeywordsForAsset({asset=>$self}),
});
}),
allowsAttachments => $wiki->get("maxAttachments"),
formFooter => WebGUI::Form::formFooter($session),
isNew => ($self->getId eq "new"),
@ -319,7 +319,20 @@ sub update {
sub view {
my $self = shift;
my $i18n = WebGUI::International->new($self->session, "Asset_WikiPage");
my $keywords = WebGUI::Keyword->new($self->session)->getKeywordsForAsset({
asset=>$self,
asArrayRef=>1,
});
my $wiki = $self->getWiki;
my @keywordsLoop = ();
foreach my $word (@{$keywords}) {
push(@keywordsLoop, {
keyword=>$word,
url=>$wiki->getUrl("func=byKeyword;keyword=".$word),
});
}
my $var = {
keywordsLoop => \@keywordsLoop,
viewLabel => $i18n->get("viewLabel"),
editLabel => $i18n->get("editLabel"),
historyLabel => $i18n->get("historyLabel"),

View file

@ -233,6 +233,13 @@ sub definition {
hoverHelp => $i18n->get('recentChangesTemplateId hoverHelp'),
label => $i18n->get('recentChangesTemplateId label') },
byKeywordTemplateId => { fieldType => 'template',
namespace => 'WikiMaster_byKeyword',
defaultValue => 'WikiKeyword00000000001',
tab => 'display',
hoverHelp => $i18n->get('byKeywordTemplateId hoverHelp'),
label => $i18n->get('byKeywordTemplateId label') },
searchTemplateId => { fieldType => 'template',
namespace => 'WikiMaster_search',
defaultValue => 'WikiSearchTmpl00000001',
@ -361,6 +368,10 @@ sub view {
recentChangesLabel=>$i18n->get("recentChangesLabel"),
restoreLabel => $i18n->get("restoreLabel"),
canAdminister => $self->canAdminister,
keywordCloud => WebGUI::Keyword->new($self->session)->generateCloud({
startAsset=>$self,
displayFunc=>"byKeyword",
}),
};
my $template = $self->{_frontPageTemplate};
$self->appendSearchBoxVars($var);
@ -370,6 +381,35 @@ sub view {
}
#-------------------------------------------------------------------
sub www_byKeyword {
my $self = shift;
my $keyword = $self->session->form->process("keyword");
my @pages = ();
my $p = WebGUI::Keyword->new($self->session)->getMatchingAssets({
startAsset => $self,
keyword => $keyword,
usePaginator => 1,
});
$p->setBaseUrl($self->getUrl("func=byKeyword"));
foreach my $assetData (@{$p->getPageData}) {
$self->session->errorHandler->warn($assetData->{assetId});
my $asset = WebGUI::Asset->newByDynamicClass($self->session, $assetData->{assetId});
next unless defined $asset;
push(@pages, {
title => $asset->getTitle,
url => $asset->getUrl,
});
}
my $var = {
keyword => $keyword,
pagesLoop => \@pages,
};
$p->appendTemplateVars($var);
return $self->processStyle($self->processTemplate($var, $self->get('byKeywordTemplateId')));
}
#-------------------------------------------------------------------
sub www_mostPopular {
my $self = shift;

View file

@ -17,6 +17,7 @@ package WebGUI::Keyword;
use strict;
use Class::InsideOut qw(public register id);
use HTML::TagCloud;
use WebGUI::Paginator;
=head1 NAME
@ -104,7 +105,7 @@ The www func that will be called on the displayAsset to display the list of asse
=head3 cloudLevels
How many levels of keyword sizes should there be displayed in the cloud. Defaults to 10.
How many levels of keyword sizes should there be displayed in the cloud. Defaults to 24. Range between 2 and 24.
=head3 startAsset
@ -124,7 +125,7 @@ sub generateCloud {
my $sth = $self->session->db->read("select count(*) as keywordTotal, keyword from assetKeyword
left join asset using (assetId) where lineage like ? group by keyword order by keywordTotal limit 50",
[ $options->{startAsset}->get("lineage").'%' ]);
my $cloud = HTML::TagCloud->new(levels=>$options->{cloudLevels} || 10);
my $cloud = HTML::TagCloud->new(levels=>$options->{cloudLevels} || 24);
while (my ($count, $keyword) = $sth->array) {
$cloud->add($keyword, $display->getUrl("func=".$options->{displayFunc}.";keyword=".$keyword), $count);
}
@ -148,8 +149,7 @@ A boolean, that if set to 1 will return the keywords as an array reference rathe
=cut
sub getKeywordsForAsset {
my $self = shift;
my $options = shift;
my ($self, $options) = @_;
my @keywords = $self->session->db->buildArray("select keyword from assetKeyword where assetId=?",
[$options->{asset}->getId]);
if ($options->{asArrayRef}) {
@ -163,7 +163,43 @@ sub getKeywordsForAsset {
#-------------------------------------------------------------------
=head2 new ( session )
=head2 getMatchingAssets ( { startAsset => $asset, keyword => $keyword } )
Returns an array reference of asset ids matching the start point + keyword.
=head3 startAsset
An asset object where you'd like to start searching for matching keywords.
=head3 keyword
The keyword to match.
=head3 usePaginator
Instead of returning an array reference of assetId's, return a paginator object.
=cut
sub getMatchingAssets {
my ($self, $options) = @_;
my $query = "select assetKeyword.assetId from assetKeyword left join asset using (assetId)
where lineage like ? and keyword=? order by creationDate desc";
my $params = [$options->{startAsset}->get("lineage").'%', $options->{keyword}];
if ($options->{usePaginator}) {
my $p = WebGUI::Paginator->new($self->session);
$p->setDataByQuery($query, undef, undef, $params);
return $p;
}
else {
return $self->session->db->buildArrayRef($query, $params);
}
}
#-------------------------------------------------------------------
=head2 new ( $session )
Constructor.

View file

@ -549,7 +549,7 @@ sub getRowCount {
#-------------------------------------------------------------------
=head2 new ( session, currentURL [, paginateAfter, formVar, pageNumber ] )
=head2 new ( session, baseUrl [, paginateAfter, formVar, pageNumber ] )
Constructor.
@ -557,7 +557,7 @@ Constructor.
A reference to the current session.
=head3 currentURL
=head3 baseUrl
The URL of the current page including attributes. The page number will be appended to this in all links generated by the paginator.
@ -599,6 +599,24 @@ sub session {
}
#-------------------------------------------------------------------
=head2 setBaseUrl ( url )
Override the baseUrl set in the constructor.
=head3 url
The new URL.
=cut
sub setBaseUrl {
my ($self, $url) = @_;
$self->{_url} = $url;
}
#-------------------------------------------------------------------
=head2 setDataByArrayRef ( arrayRef )

View file

@ -7,6 +7,12 @@ our $I18N = {
context => q|A button added to all asset properties pages when save and commit mode is enabled.|
},
'keywords' => {
message => q|Keywords|,
lastUpdated => 0,
context => q|A label for the property that relates assets to keywords.|
},
'add the missing page' => {
message => q|Add the missing page.|,
lastUpdated => 0,

View file

@ -132,6 +132,10 @@ our $I18N = {
lastUpdated => 1160157064,
},
'byKeywordTemplateId hoverHelp' => { lastUpdated => 1160157064, message => q|Which template to use to display a
listing of pages that are related to a specific keyword?| },
'byKeywordTemplateId label' => { lastUpdated => 1160157064, message => q|By Keyword Template| },
'pageTemplateId hoverHelp' => { lastUpdated => 1160157064, message => q|Which template to use to display pages?| },
'pageTemplateId label' => { lastUpdated => 1160157064, message => q|Page Template| },

View file

@ -325,6 +325,10 @@ if ($notRun) {
UPGRADES COMPLETE
Please restart your web server and test your sites.
WARNING: If you saw any errors in the output during the upgrade, restore
your install and databases from backup immediately. Do not continue using
your site EVEN IF IT SEEMS TO WORK.
NOTE: If you have not already done so, please consult
docs/gotcha.txt for possible upgrade complications.

View file

@ -48,5 +48,6 @@ unlike($keyword->getKeywordsForAsset({asset=>$home }), qr/owns/, "getLatestVersi
$keyword->deleteKeywordsForAsset($home);
is(scalar(@{$keyword->getKeywordsForAsset({ asset=>$home, asArrayRef=>1})}), 0, "getKeywordsForAsset()");
undef $keyword;
undef $home;