added wiki assets

added accordion javascript object
This commit is contained in:
JT Smith 2006-11-27 18:59:24 +00:00
parent b42e213888
commit d67a28fee2
14 changed files with 1354 additions and 9 deletions

View file

@ -0,0 +1,15 @@
#WikiFrontTmpl000000001
#create
#namespace:WikiMaster_front
#url:default-wiki-front-page
#title:Default Wiki Front Page
#menuTitle:Default Wiki Front Page
<tmpl_var description>
<h3>Search</h3>
<tmpl_var search.formHeader>Search: <tmpl_var search.query><tmpl_var search.submit><tmpl_var search.formFooter>
<h3>Recent changes (<a href="<tmpl_var recentChanges.url>">more</a>)</h3>
<ul><tmpl_loop rc.entries>
<li><tmpl_var date> <tmpl_var time>: <a href="<tmpl_var viewLatest>"><tmpl_var title></a>
<tmpl_var actionNL> by <tmpl_var username></li>
</tmpl_loop></ul>

View file

@ -0,0 +1,18 @@
#WikiMasterTmpl00000001
#create
#namespace:WikiMaster
#url:default-wiki-master
#title:Default Wiki Master
#menuTitle:Default Wiki Master
<tmpl_if session.var.adminOn><p><tmpl_var controls></p></tmpl_if>
<tmpl_if displayTitle><h2><tmpl_var title></h2></tmpl_if>
<tmpl_var content>
<h3>Other actions</h3>
<ul>
<tmpl_if canEdit><li><a href="<tmpl_var addPage.url>"><tmpl_var addPage.text></a></li></tmpl_if>
<li><a href="<tmpl_var listPages.url>"><tmpl_var listPages.text></a></li>
<li><a href="<tmpl_var recentChanges.url>"><tmpl_var recentChanges.text></a></li>
<li><a href="<tmpl_var search.url>"><tmpl_var search.text></a></li>
<li><a href="<tmpl_var view.url>"><tmpl_var view.text></a></li>
</ul>

View file

@ -0,0 +1,12 @@
#WikiPageEditTmpl000001
#create
#namespace:WikiPage_edit
#url:default-wiki-page-edit
#title:Default Wiki Page Edit
#menuTitle:Default Wiki Page Edit
<tmpl_var form.header>
<p>Title: <tmpl_var form.title><br />
Content:<br /><tmpl_var form.content></p>
<tmpl_var form.submit>
<tmpl_var form.footer>

View file

@ -0,0 +1,13 @@
#WikiPHTmpl000000000001
#create
#namespace:WikiPage_pageHistory
#url:default-wiki-page-history
#title:Default Page History
#menuTitle:Default Page History
<ul><tmpl_loop ph.entries>
<li><tmpl_var actionN> at <tmpl_var date>
(<tmpl_var interval><tmpl_if isCreateOrEdit>; <a href="<tmpl_var viewRevision>">view</a>,
<a href="<tmpl_var editRevision>">edit</a></tmpl_if>)
by <tmpl_var username></li>
</tmpl_loop></ul>

View file

@ -0,0 +1,13 @@
#WikiPLTmpl000000000001
#create
#namespace:WikiMaster_pageList
#url:default-wiki-page-list
#title:Default Page List
#menuTitle:Default Page List
<h2><tmpl_var pl.title></h2>
<ul>
<tmpl_loop pl.entries>
<li><a href="<tmpl_var viewLatest>"><tmpl_var title></a></li>
</tmpl_loop>
</ul>

View file

@ -0,0 +1,29 @@
#WikiPageTmpl0000000001
#create
#namespace:WikiPage
#url:default-wiki-page
#title:Default Wiki Page
#menuTitle:Default Wiki Page
<tmpl_var content>
<tmpl_unless nonexistentPage><h3>This page</h3><ul>
<tmpl_unless inView><li><a href="<tmpl_var view.url>"><tmpl_var view.text></a></li></tmpl_unless>
<tmpl_unless inEdit>
<tmpl_if canEdit><li><a href="<tmpl_var edit.url>"><tmpl_var edit.text></a></li>
<tmpl_else><tmpl_if couldEdit><li>(Protected page)</li></tmpl_if></tmpl_if>
</tmpl_unless>
<tmpl_unless inHistory>
<li><a href="<tmpl_var pageHistory.url>"><tmpl_var pageHistory.text></a></li>
</tmpl_unless>
<tmpl_if canProtect>
<tmpl_if isProtected>
<li><a href="<tmpl_var unprotect.url>"><tmpl_var unprotect.text></a></li>
<tmpl_else>
<li><a href="<tmpl_var protect.url>"><tmpl_var protect.text></a></li>
</tmpl_if>
</tmpl_if>
<tmpl_if canDelete>
<li><a href="<tmpl_var delete.url>" onclick="<tmpl_var delete.confirm>"><tmpl_var delete.text></a></li>
<li><a href="<tmpl_var wikiPurgeRevision.url>" onclick="<tmpl_var wikiPurgeRevision.confirm>"><tmpl_var wikiPurgeRevision.text></a></li>
</tmpl_if>
</ul></tmpl_unless>

View file

@ -0,0 +1,14 @@
#WikiRCTmpl000000000001
#create
#namespace:WikiMaster_recentChanges
#url:default-wiki-recent-changes
#title:Default Recent Changes
#menuTitle:Default Recent Changes
<tmpl_loop rc.days>
<h3><tmpl_var day.date></h3>
<ul><tmpl_loop day.entries>
<li><tmpl_var date> <tmpl_var time>: <a href="<tmpl_var viewLatest>"><tmpl_var title></a>
<tmpl_var actionNL> by <tmpl_var username></li>
</tmpl_loop></ul>
</tmpl_loop>

View file

@ -0,0 +1,11 @@
#WikiSearchTmpl00000001
#create
#namespace:WikiMaster_search
#url:default-wiki-search
#title:Default Wiki Search
#menuTitle:Default Wiki Search
<tmpl_var search.formHeader>Search: <tmpl_var search.query><tmpl_var search.submit><tmpl_var search.formFooter>
<tmpl_if search.results><h3>Results</h3>
<ul><tmpl_loop search.results><li><a href="<tmpl_var viewLatest>"><tmpl_var title></a></li></tmpl_loop></ul>
</tmpl_if>

View file

@ -19,20 +19,96 @@ my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
addWikiAssets($session);
deleteOldFiles($session);
finish($session); # this line required
##-------------------------------------------------
#sub exampleFunction {
# my $session = shift;
# print "\tWe're doing some stuff here that you should know about.\n" unless ($quiet);
# # and here's our code
#}
#-------------------------------------------------
sub deleteOldFiles {
my $session = shift;
print "\tDeleting old unneeded files.\n" unless $quiet;
unlink "../../www/extras/assets/wiki.gif";
unlink "../../www/extras/assets/wikiPost.gif";
unlink "../../www/extras/assets/small/wiki.gif";
unlink "../../www/extras/assets/small/wikiPost.gif";
}
#-------------------------------------------------
sub addWikiAssets {
my $session = shift;
print "\tAdding wiki assets.\n" unless $quiet;
$session->db->write($_) for(<<'EOT',
CREATE TABLE `WikiMaster` (
`assetId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`revisionDate` bigint(20) NOT NULL,
`groupToEditPages` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`groupToAdminister` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`richEditor` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'PBrichedit000000000002',
`masterTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiMasterTmpl00000001',
`frontPageTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiFrontTmpl000000001',
`pageTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiPageTmpl0000000001',
`pageEditTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiPageEditTmpl000001',
`recentChangesTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiRCTmpl000000000001',
`pageHistoryTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiPHTmpl000000000001',
`pageListTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiPLTmpl000000000001',
`searchTemplateId` varchar(22) character set utf8 collate utf8_bin NOT NULL
default 'WikiSearchTmpl00000001',
`recentChangesCount` int(11) NOT NULL default 50,
`recentChangesCountFront` int(11) NOT NULL default 10,
PRIMARY KEY (`assetId`, `revisionDate`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOT
<<'EOT',
CREATE TABLE `WikiPage` (
`assetId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`revisionDate` bigint(20) NOT NULL,
`content` mediumtext,
`storageId` varchar(22) character set utf8 collate utf8_bin NULL,
`views` bigint(20) NOT NULL default 0,
PRIMARY KEY (`assetId`, `revisionDate`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOT
<<'EOT',
CREATE TABLE `WikiMaster_titleIndex` (
`assetId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`pageId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`assetId`, `pageId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOT
# Don't want protection to be versioned, so put it in a
# separate table.
<<'EOT',
CREATE TABLE `WikiPage_protected` (
`assetId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
PRIMARY KEY (`assetId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOT
<<'EOT',
CREATE TABLE `WikiPage_extraHistory` (
`assetId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`userId` varchar(22) character set utf8 collate utf8_bin NOT NULL,
`dateStamp` bigint(20) NOT NULL,
`actionTaken` varchar(255) NOT NULL,
`url` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOT
);
my $config = $session->config;
$config->addToArray('assetContainers', 'WebGUI::Asset::Wobject::WikiMaster');
}
# ---- DO NOT EDIT BELOW THIS LINE ----

View file

@ -0,0 +1,364 @@
package WebGUI::Asset::WikiPage;
# -------------------------------------------------------------------
# WebGUI is Copyright 2001-2006 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 base 'WebGUI::Asset';
use strict;
use Tie::IxHash;
use WebGUI::International;
use WebGUI::Utility;
#-------------------------------------------------------------------
# Buggo, semi-duplication with WikiMaster; move this into a common utility routine somewhere
sub _appendFuncTemplateVars {
my $self = shift;
my $var = shift;
my @funcs = @_;
my $i18n = WebGUI::International->new($self->session, 'Asset_WikiPage');
my %specialFuncs = ();
my $revision = $self->session->form->process('revision');
my $revisionSuffix = defined($revision)? ";revision=$revision" : '';
@funcs = (qw/view edit pageHistory protect unprotect delete wikiPurgeRevision/) unless @funcs;
foreach my $func (@funcs) {
$var->{$func.'.url'} = $self->getUrl($specialFuncs{$func}
|| "func=$func$revisionSuffix");
$var->{$func.'.text'} = $i18n->get("func $func link text");
my $confirmation = $i18n->get("func $func link confirm");
if (length $confirmation) {
$confirmation =~ s/\'/\\\'/g;
$var->{$func.'.confirm'} = "return confirm('$confirmation')";
}
}
}
#-------------------------------------------------------------------
sub canDelete {
my $self = shift;
my $userId = shift || $self->session->user->userId;
return $self->getWiki->canAdminister($userId);
}
#-------------------------------------------------------------------
sub canEdit {
my $self = shift;
my $userId = shift || $self->session->user->userId;
return 0 if $self->isProtected and not $self->getWiki->canAdminister($userId);
return $self->couldEdit($userId);
}
#-------------------------------------------------------------------
sub canProtect {
my $self = shift;
my $userId = shift || $self->session->user->userId;
return $self->getWiki->canAdminister($userId);
}
#-------------------------------------------------------------------
sub couldEdit {
my $self = shift;
my $userId = shift || $self->session->user->userId;
return 0 unless $self->getWiki->canEditPages($userId);
return 1;
}
#-------------------------------------------------------------------
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, "Asset_WikiPage");
my %properties;
tie %properties, 'Tie::IxHash';
%properties =
(
storageId => { fieldType => 'image',
defaultValue => undef },
content => { fieldType => "HTMLArea",
defaultValue => undef },
);
push @$definition,
{
assetName => $i18n->get('assetName'),
icon => 'wikiPage.gif',
autoGenerateForms => 1,
tableName => 'WikiPage',
className => 'WebGUI::Asset::WikiPage',
properties => \%properties,
};
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
# BUGGO: how to handle this?
sub duplicate {
my $self = shift;
my $newAsset = $self->SUPER::duplicate(@_);
return $newAsset;
}
#-------------------------------------------------------------------
sub getWiki {
my $self = shift;
my $parent = $self->getParent;
return undef unless defined $parent and $parent->isa('WebGUI::Asset::Wobject::WikiMaster');
return $parent;
}
#-------------------------------------------------------------------
sub indexContent {
my $self = shift;
my $indexer = $self->SUPER::indexContent;
$indexer->addKeywords($self->get('content'));
return $indexer;
}
#-------------------------------------------------------------------
sub purge {
my $self = shift;
$self->getWiki->updateTitleIndex([$self], from => 'purge');
$self->session->db->write("DELETE FROM WikiPage_protected WHERE assetId = ?", [$self->getId]);
$self->session->db->write("DELETE FROM WikiPage_extraHistory WHERE assetId = ?", [$self->getId]);
return $self->SUPER::purge;
}
#-------------------------------------------------------------------
sub purgeRevision {
my $self = shift;
$self->getWiki->updateTitleIndex([$self], from => 'purgeRevision');
return $self->SUPER::purgeRevision;
}
#-------------------------------------------------------------------
sub preparePageTemplate {
my $self = shift;
return $self->{_pageTemplate} if $self->{_pageTemplate};
$self->{_pageTemplate} =
WebGUI::Asset::Template->new($self->session, $self->getWiki->get('pageTemplateId'));
$self->{_pageTemplate}->prepare;
return $self->{_pageTemplate};
}
#-------------------------------------------------------------------
sub processPageTemplate {
my $self = shift;
my $content = shift;
my $func = shift || $self->session->form->process('func');
my $var = {};
my $template = $self->preparePageTemplate;
$var->{content} = $content;
$var->{canEdit} = $self->canEdit;
$var->{couldEdit} = $self->couldEdit;
$var->{canProtect} = $self->canProtect;
$var->{canDelete} = $self->canDelete;
$var->{isProtected} = $self->isProtected;
$var->{inEdit} = isIn($func, qw/edit add/);
$var->{inView} = isIn($func, qw/view/) || !defined $func;
$var->{inHistory} = isIn($func, qw/pageHistory/);
$self->_appendFuncTemplateVars($var);
return $self->processTemplate($var, undef, $template);
}
#-------------------------------------------------------------------
sub prepareView {
my $self = shift;
$self->SUPER::prepareView;
$self->preparePageTemplate;
}
#-------------------------------------------------------------------
sub view {
my $self = shift;
my $var = {};
my $title = $self->get('title');
my $content = $self->getWiki->autolinkHtml($self->get('content'));
return $self->getWiki->processMasterTemplate($title, $self->processPageTemplate($content, 'view'));
}
#-------------------------------------------------------------------
sub isProtected {
my $self = shift;
return $self->{_isProtected} if exists $self->{_isProtected};
($self->{_isProtected}) = $self->session->db->quickArray("SELECT COUNT(assetId) FROM WikiPage_protected WHERE assetId = ?", [$self->getId]);
return $self->{_isProtected};
}
#-------------------------------------------------------------------
sub processPropertiesFromFormPost {
my $self = shift;
my $ret = $self->SUPER::processPropertiesFromFormPost(@_);
$self->update({ groupIdView => $self->getWiki->get('groupIdView'),
groupIdEdit => $self->getWiki->get('groupIdEdit') });
$self->getWiki->updateTitleIndex([$self], from => 'edit');
return $ret;
}
#-------------------------------------------------------------------
sub updateWikiHistory {
my $self = shift;
my $action = shift;
my $userId = shift || $self->session->user->userId;
$self->session->db->write("INSERT INTO WikiPage_extraHistory (assetId, userId, dateStamp, actionTaken, url, title) VALUES (?, ?, ?, ?, ?, ?)", [$self->getId, $userId, $self->session->datetime->time, $action, $self->getUrl, $self->get('title')]);
}
#-------------------------------------------------------------------
sub www_delete {
my $self = shift;
return $self->session->privilege->insufficient unless $self->canDelete;
$self->trash;
$self->session->asset($self->getParent);
return $self->getParent->www_view;
}
#-------------------------------------------------------------------
sub www_edit {
my $self = shift;
return $self->session->privilege->insufficient unless $self->canEdit;
my $template = WebGUI::Asset::Template->new($self->session, $self->getWiki->get('pageEditTemplateId'));
my $var = {};
my $newPage = 0;
$template->prepare;
if ($self->session->form->process('func') eq 'add') {
# New page.
$newPage = 1;
$var->{'form.header'} = join '',
(WebGUI::Form::formHeader($self->session,
{ action => $self->getWiki->getUrl('func=addPageSave') }),
WebGUI::Form::hidden($self->session, { name => 'class', value => ref $self }));
} else {
# Editing a page.
$newPage = 0;
$var->{'form.header'} = join '',
(WebGUI::Form::formHeader($self->session,
{ action => $self->getUrl('func=editSave') }));
}
$var->{'form.title'} = WebGUI::Form::text
($self->session, { name => 'title', maxlength => 255,
size => 40, value => $self->get('title') });
$var->{'form.content'} = WebGUI::Form::HTMLArea
($self->session, { name => 'content', richEditId => $self->getWiki->get('richEditor'),
value => $self->get('content') });
$var->{'form.submit'} = WebGUI::Form::submit
($self->session, { value => 'Save' });
$var->{'form.footer'} = WebGUI::Form::formFooter($self->session);
$self->_appendFuncTemplateVars($var);
my $title = "Editing ".(defined($self->get('title'))? $self->get('title') : 'new page');
return $self->getWiki->processStyle($self->getWiki->processMasterTemplate($title, $self->processPageTemplate($self->processTemplate($var, undef, $template), 'edit')));
}
#-------------------------------------------------------------------
sub www_editSave {
my $self = shift;
return $self->session->privilege->insufficient unless $self->canEdit;
# TODO: refactor: duplication with A::W::Matrix::www_editListingSave
my $oldTag = WebGUI::VersionTag->getWorking($self->session, 1);
my $newTag = WebGUI::VersionTag->create
($self->session, { name => (sprintf "%s edit of %s - %s",
$self->getWiki->get('title'), $self->get('title'),
$self->session->user->username),
workflowId => 'pbworkflow000000000003' });
$newTag->setWorking;
my $newSelf = $self->addRevision;
my $error = $newSelf->processPropertiesFromFormPost;
if (ref $error eq 'ARRAY') {
$self->session->stow->set('editFormErrors', $error);
$newTag->rollback;
$oldTag->setWorking if defined $oldTag;
return $self->www_edit;
}
$newSelf->updateHistory('edited');
$newTag->requestCommit;
$newTag->clearWorking;
$oldTag->setWorking if defined $oldTag;
return $newSelf->www_view;
}
#-------------------------------------------------------------------
sub www_pageHistory {
my $self = shift;
my $title = sprintf(WebGUI::International->new($self->session, 'Asset_WikiPage')->get('pageHistory title'),
$self->get('title'));
my $template = WebGUI::Asset::Template->new($self->session, $self->getWiki->get('pageHistoryTemplateId'));
$template->prepare;
# Buggo: hardcoded count
my $var = {};
$self->getWiki->_appendPageHistoryVars($var, [0, 50], $self);
return $self->getWiki->processStyle($self->getWiki->processMasterTemplate($title, $self->processPageTemplate($self->processTemplate($var, undef, $template), 'pageHistory')));
}
#-------------------------------------------------------------------
sub www_protect {
my $self = shift;
return $self->session->privilege->insufficient unless $self->canProtect;
return $self->www_view if $self->isProtected;
$self->session->db->write("DELETE FROM WikiPage_protected WHERE assetId = ?", [$self->getId]);
$self->session->db->write("INSERT INTO WikiPage_protected (assetId) VALUES (?)", [$self->getId]);
$self->{_isProtected} = 1;
$self->updateWikiHistory('protected');
return $self->www_view;
}
#-------------------------------------------------------------------
sub www_unprotect {
my $self = shift;
return $self->session->privilege->insufficient unless $self->canProtect;
return $self->www_view if !$self->isProtected;
$self->session->db->write("DELETE FROM WikiPage_protected WHERE assetId = ?", [$self->getId]);
$self->{_isProtected} = 0;
$self->updateWikiHistory('unprotected');
return $self->www_view;
}
#-------------------------------------------------------------------
sub www_view {
my $self = shift;
return $self->session->privilege->noAccess unless $self->canView;
$self->update({ views => $self->get('views')+1 });
# TODO: This should probably exist, as the CS has one.
# $self->session->http->setCacheControl($self->getWiki->get('visitorCacheTimeout'))
# if ($self->session->user->userId eq '1');
$self->session->http->sendHeader;
$self->prepareView;
return $self->getWiki->processStyle($self->view);
}
#-------------------------------------------------------------------
sub www_wikiPurgeRevision {
my $self = shift;
return $self->session->privilege->insufficient unless $self->canDelete;
$self->purgeRevision;
$self->session->asset($self->getParent);
return $self->getParent->www_view;
}
1;

View file

@ -0,0 +1,604 @@
package WebGUI::Asset::Wobject::WikiMaster;
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2006 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 base 'WebGUI::Asset::Wobject';
use strict;
use Tie::IxHash;
use WebGUI::International;
use WebGUI::Utility;
use HTML::Parser;
use URI::Escape;
#-------------------------------------------------------------------
sub _appendFuncTemplateVars {
my $self = shift;
my $var = shift;
my @funcs = @_;
my $i18n = WebGUI::International->new($self->session, 'Asset_WikiMaster');
my %specialFuncs =
(addPage => 'func=add;class=WebGUI::Asset::WikiPage');
foreach my $func (@funcs) {
$var->{$func.'.url'} = $self->getUrl($specialFuncs{$func} || "func=$func");
$var->{$func.'.text'} = $i18n->get("func $func link text");
}
}
#-------------------------------------------------------------------
sub _appendPageHistoryVars {
my $self = shift;
my $var = shift;
my $limit = shift;
my $page = shift;
my $time = $self->session->datetime->time;
my $entries = $self->_templateSubvarsRefOfEdits($self->_editsRefOfPageHistory($page, $limit), $time);
my $days = $self->_daysRefOfTemplateSubvars($entries);
$var->{'ph.entries'} = $entries;
$var->{'ph.days'} = $days;
return $self;
}
#-------------------------------------------------------------------
sub _appendRecentChangesVars {
my $self = shift;
my $var = shift;
my $limit = shift;
my $time = $self->session->datetime->time;
my $entries = $self->_templateSubvarsRefOfEdits($self->_editsRefOfRecentChanges($limit), $time);
my $days = $self->_daysRefOfTemplateSubvars($entries);
$var->{'rc.entries'} = $entries;
$var->{'rc.days'} = $days;
return $self;
}
#-------------------------------------------------------------------
sub _appendSearchBoxVars {
my $self = shift;
my $var = shift;
my $queryText = shift;
my $submitText = WebGUI::International->new($self->session, 'Asset_WikiMaster')->get('search submit');
$var->{'search.formHeader'} = join '',
(WebGUI::Form::formHeader($self->session, { action => $self->getUrl, method => 'GET' }),
WebGUI::Form::hidden($self->session, { name => 'func', value => 'search' }));
$var->{'search.query'} = WebGUI::Form::text($self->session, { name => 'query', value => $queryText });
$var->{'search.submit'} = WebGUI::Form::submit($self->session, { value => $submitText });
$var->{'search.formFooter'} = WebGUI::Form::formFooter($self->session);
return $self;
}
#-------------------------------------------------------------------
sub _appendSearchResultVars {
my $self = shift;
my $var = shift;
my $rs = shift;
my @results = ();
my $dt = $self->session->datetime;
while (defined(my $row = $rs->hashRef)) {
push @results, $self->_templateSubvarOfPage($row->{assetId});
}
$var->{'search.results'} = \@results;
return $self;
}
#-------------------------------------------------------------------
sub _appendVarsOfDate {
my $self = shift;
my $var = shift;
my $date = shift;
my $prefix = shift;
my $relativeTo = shift;
my $dt = $self->session->datetime;
$var->{$prefix . (length($prefix)? 'Date':'date')} = $dt->epochToHuman($date, '%z');
$var->{$prefix . (length($prefix)? 'Time':'time')} = $dt->epochToHuman($date, '%Z');
if (defined $relativeTo) {
my $ago = WebGUI::International->new($self->session, 'Asset')->get('ago');
$var->{$prefix . (length($prefix)? 'Interval':'interval')} = sprintf '%s %s %s',
($dt->secondsToInterval($relativeTo - $date), $ago);
}
return $self;
}
#-------------------------------------------------------------------
sub _daysRefOfTemplateSubvars {
my $self = shift;
my $subvars = shift;
my @days = ();
foreach my $subvar (@$subvars) {
if (!@days or $subvar->{date} ne $days[-1][0]{date}) {
push @days, [$subvar];
} else {
push @{$days[-1]}, $subvar;
}
}
return [map { {'day.date' => $$_[0]{date}, 'day.entries' => $_} } @days];
}
#-------------------------------------------------------------------
sub _editsRefOfPageHistory {
my $self = shift;
my $page = shift;
my $limit = shift;
$self->_editsRefOfQuery("a.assetId = ?", [$page->getId], undef, $limit);
}
#-------------------------------------------------------------------
sub _editsRefOfQuery {
my $self = shift;
my $queryPiece = shift || 'true';
my $placeholders = shift || [];
my $allowedActions = shift || [qw/edited trashed protected unprotected/];
my $allowedActionsPredicate = "IN (".join(', ', ('?') x @$allowedActions).")";
my $limit = shift;
my $limitClause = $limit? sprintf("LIMIT %d,%d", @$limit[0..1]) : "";
# Ick. Apparently assetHistory.dateStamp isn't always equivalent to assetData.revisionDate.
# It looks like the relationship between them is in fact semi-arbitrary. Then there's also that
# it doesn't seem to be safe to add extra possible values to assetHistory. So we have to do this.
# Bleagh.
$self->session->db->buildArrayRefOfHashRefs(<<"EOT", [(@$placeholders, @$allowedActions) x 3]);
SELECT h.userId AS userId, u.username AS username, h.dateStamp AS dateStamp,
h.actionTaken AS action, CONCAT('/', d.url) AS url, d.title AS title, a.assetId AS assetId
FROM assetHistory AS h LEFT JOIN users AS u ON h.userId = u.userId
INNER JOIN asset AS a ON h.assetId = a.assetId
INNER JOIN assetData AS d ON a.assetId = d.assetId AND h.dateStamp = d.revisionDate
WHERE $queryPiece AND h.actionTaken $allowedActionsPredicate
UNION
SELECT eh.userId AS userId, u.username AS username, eh.dateStamp AS dateStamp,
eh.actionTaken AS action, CONCAT('/', eh.url) AS url, eh.title AS title, a.assetId AS assetId
FROM WikiPage_extraHistory AS eh LEFT JOIN users AS u ON eh.userId = u.userId
INNER JOIN asset AS a ON eh.assetId = a.assetId
WHERE $queryPiece AND eh.actionTaken $allowedActionsPredicate
UNION
SELECT d.revisedBy AS userId, u.username AS username, d.revisionDate AS dateStamp,
'edited' AS action, CONCAT('/', d.url) AS url, d.title AS title, a.assetId AS assetId
FROM assetData AS d LEFT JOIN users AS u on d.revisedBy = u.userId
INNER JOIN asset AS a ON d.assetId = a.assetId
WHERE $queryPiece AND 'edited' $allowedActionsPredicate
ORDER BY dateStamp DESC
$limitClause
EOT
}
#-------------------------------------------------------------------
sub _editsRefOfRecentChanges {
my $self = shift;
my $limit = shift;
$self->_editsRefOfQuery("a.lineage LIKE CONCAT(?, '%') AND a.assetId <> ?", [$self->get('lineage'), $self->getId], [qw/edited trashed/], $limit);
}
#-------------------------------------------------------------------
sub _templateSubvarOfEdit {
my $self = shift;
my $edit = shift;
my $time = shift;
my $i18n = WebGUI::International->new($self->session, 'Asset_WikiMaster');
my $subvar = +{%$edit};
$self->_appendVarsOfDate($subvar, $subvar->{dateStamp}, '', $time);
# If only HTML::Template::Expr were standard.
$subvar->{isDelete} = ($subvar->{action} eq 'trashed');
$subvar->{isEdit} = ($subvar->{action} eq 'edited');
$subvar->{isProtect} = ($subvar->{action} eq 'protected');
$subvar->{isUnprotect} = ($subvar->{action} eq 'unprotected');
$subvar->{isCreateOrEdit} = $subvar->{isEdit};
$subvar->{viewLatest} = $subvar->{url};
$subvar->{editLatest} = $subvar->{url}.'?func=edit';
if ($subvar->{isEdit}) {
$subvar->{viewRevision} = $subvar->{url}.'?func=view;revision='.$subvar->{dateStamp};
$subvar->{editRevision} = $subvar->{url}.'?func=edit;revision='.$subvar->{dateStamp};
}
if ($subvar->{isEdit} and ($self->session->db->quickArray("SELECT MIN(revisionDate) FROM assetData WHERE assetId = ?", [$subvar->{assetId}]))[0] == $subvar->{dateStamp}) {
$subvar->{action} = 'created';
$subvar->{isEdit} = 0;
$subvar->{isCreate} = 1;
}
$subvar->{actionN} = $i18n->get('actionN '.$subvar->{action});
$subvar->{actionNL} = lc $subvar->{actionN};
return $subvar;
}
#-------------------------------------------------------------------
sub _templateSubvarOfPage {
my $self = shift;
my $page = shift;
my $subvar = {};
$page = WebGUI::Asset->newByDynamicClass($self->session, $page) unless ref $page;
$subvar->{title} = $page->get('title');
$subvar->{assetId} = $page->getId;
$subvar->{viewLatest} = $page->getUrl;
$subvar->{editLatest} = $page->getUrl('func=edit');
return $subvar;
}
#-------------------------------------------------------------------
sub _templateSubvarsRefOfEdits {
my $self = shift;
my $edits = shift;
my $time = shift;
return [map { $self->_templateSubvarOfEdit($_, $time) } @$edits];
}
#-------------------------------------------------------------------
sub _templateSubvarsRefOfPages {
my $self = shift;
my $pages = shift;
return [map { $self->_templateSubvarOfPage($_) } @$pages];
}
#-------------------------------------------------------------------
sub autolinkHtml {
my $self = shift;
my $html = shift;
# TODO: ignore caching for now, but maybe do it later.
my %mapping = $self->session->db->buildHash("SELECT LOWER(i.title), d.url FROM WikiMaster_titleIndex AS i INNER JOIN assetData AS d ON i.pageId = d.assetId WHERE i.assetId = ?", [$self->getId]);
return $html unless %mapping;
foreach my $key (keys %mapping) {
$mapping{$key} = WebGUI::HTML::format('/'.$mapping{$key}, 'text');
}
my $matchString = join('|', map{quotemeta} keys %mapping);
my $regexp = qr/\b($matchString)\b/i;
my @acc = ();
my $in_a = 0;
my $p = HTML::Parser->new;
$p->case_sensitive(1);
$p->marked_sections(1);
$p->unbroken_text(1);
$p->handler(start => sub { push @acc, $_[2]; if ($_[0] eq 'a' and exists $_[1]{href}) { $in_a++ } },
'tagname, attr, text');
$p->handler(end => sub { push @acc, $_[2]; if ($_[0] eq 'a' and exists $_[1]{href}) { $in_a-- } },
'tagname, attr, text');
$p->handler(text => sub {
my $text = $_[0];
unless ($in_a) {
while ($text =~ s#^(.*?)$regexp##i) {
push @acc, sprintf '%s<a href="%s">%s</a>',
($1, $mapping{lc $2}, $2);
}
}
push @acc, $text;
}, 'text');
$p->handler(default => sub { push @acc, $_[0] }, 'text');
$p->parse($html);
$p->eof;
undef $p; # Just in case there might be reference loops.
return join '', @acc;
}
#-------------------------------------------------------------------
sub canAdminister {
my $self = shift;
my $userId = shift || $self->session->user->userId;
my $user = WebGUI::User->new($self->session, $userId);
return $self->canView($userId) && $user->isInGroup($self->get('groupToAdminister'));
}
#-------------------------------------------------------------------
sub canEditPages {
my $self = shift;
return $self->session->user->isInGroup($self->get("groupToEditPages")) || $self->canAdminister;
}
#-------------------------------------------------------------------
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, 'Asset_WikiMaster');
# BUGGO: duplication with Collaboration; move this into WebGUI::Asset::RichEdit
my $richEditorOptions = $session->db->buildHashRef("select distinct(assetData.assetId), assetData.title from asset, assetData where asset.className='WebGUI::Asset::RichEdit' and asset.assetId=assetData.assetId order by assetData.title");
my %properties;
tie %properties, 'Tie::IxHash';
%properties =
(
groupToEditPages => { fieldType => 'group',
defaultValue => ['7'],
tab => 'security',
hoverHelp => $i18n->get('groupToEditPages hoverHelp'),
label => $i18n->get('groupToEditPages label') },
groupToAdminister => { fieldType => 'group',
defaultValue => ['3'],
tab => 'security',
hoverHelp => $i18n->get('groupToAdminister hoverHelp'),
label => $i18n->get('groupToAdminister label') },
richEditor => { fieldType => 'selectBox',
options => $richEditorOptions,
defaultValue => 'PBrichedit000000000001',
tab => 'display',
hoverHelp => $i18n->get('richEditor hoverHelp'),
label => $i18n->get('richEditor label') },
masterTemplateId => { fieldType => 'template',
namespace => 'WikiMaster',
defaultValue => 'WikiMasterTmpl00000001',
tab => 'display',
hoverHelp => $i18n->get('masterTemplateId hoverHelp'),
label => $i18n->get('masterTemplateId label') },
frontPageTemplateId => { fieldType => 'template',
namespace => 'WikiMaster_front',
defaultValue => 'WikiFrontTmpl000000001',
tab => 'display',
hoverHelp => $i18n->get('frontPageTemplateId hoverHelp'),
label => $i18n->get('frontPageTemplateId label') },
pageTemplateId => { fieldType => 'template',
namespace => 'WikiPage',
defaultValue => 'WikiPageTmpl0000000001',
tab => 'display',
hoverHelp => $i18n->get('pageTemplateId hoverHelp'),
label => $i18n->get('pageTemplateId label') },
pageHistoryTemplateId => { fieldType => 'template',
namespace => 'WikiPage_pageHistory',
defaultValue => 'WikiPHTmpl000000000001',
tab => 'display',
hoverHelp => $i18n->get('pageHistoryTemplateId hoverHelp'),
label => $i18n->get('pageHistoryTemplateId label') },
recentChangesTemplateId => { fieldType => 'template',
namespace => 'WikiMaster_recentChanges',
defaultValue => 'WikiRCTmpl000000000001',
tab => 'display',
hoverHelp => $i18n->get('recentChangesTemplateId hoverHelp'),
label => $i18n->get('recentChangesTemplateId label') },
pageListTemplateId => { fieldType => 'template',
namespace => 'WikiMaster_pageList',
defaultValue => 'WikiPLTmpl000000000001',
tab => 'display',
hoverHelp => $i18n->get('pageListTemplateId hoverHelp'),
label => $i18n->get('pageListTemplateId label') },
searchTemplateId => { fieldType => 'template',
namespace => 'WikiMaster_search',
defaultValue => 'WikiSearchTmpl00000001',
tab => 'display',
hoverHelp => $i18n->get('searchTemplateId hoverHelp'),
label => $i18n->get('searchTemplateId label') },
recentChangesCount => { fieldType => 'integer',
defaultValue => 50,
tab => 'display',
hoverHelp => $i18n->get('recentChangesCount hoverHelp'),
label => $i18n->get('recentChangesCount label') },
recentChangesCountFront => { fieldType => 'integer',
defaultValue => 10,
tab => 'display',
hoverHelp => $i18n->get('recentChangesCountFront hoverHelp'),
label => $i18n->get('recentChangesCountFront label') },
);
push @$definition,
{
assetName => $i18n->get('assetName'),
icon => 'wikiMaster.gif',
autoGenerateForms => 1,
tableName => 'WikiMaster',
className => 'WebGUI::Asset::Wobject::WikiMaster',
properties => \%properties,
};
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
sub getContentLastModified {
my $self = shift;
my ($lastModified) = $self->session->db->quickArray("SELECT MAX(d.revisionDate) FROM assetData AS d INNER JOIN asset AS a ON a.assetId = d.assetId WHERE a.lineage LIKE CONCAT(?, '%')", [$self->get('lineage')]);
return $lastModified;
}
#-------------------------------------------------------------------
sub prepareMasterTemplate {
my $self = shift;
return $self->{_masterTemplate} if $self->{_masterTemplate};
$self->{_masterTemplate} =
WebGUI::Asset::Template->new($self->session, $self->get('masterTemplateId'));
$self->{_masterTemplate}->prepare;
return $self->{_masterTemplate};
}
#-------------------------------------------------------------------
sub processMasterTemplate {
my $self = shift;
my $title = shift;
my $content = shift;
my $var = {};
my $template = $self->prepareMasterTemplate;
$var->{title} = $title;
$var->{content} = $content;
$var->{displayTitle} = $self->get('displayTitle');
$var->{canEdit} = $self->canEditPages;
$self->_appendFuncTemplateVars($var, qw/addPage listPages recentChanges view search/);
return $self->processTemplate($var, undef, $template);
}
#-------------------------------------------------------------------
sub prepareView {
my $self = shift;
$self->SUPER::prepareView;
$self->prepareMasterTemplate;
$self->{_frontPageTemplate} =
WebGUI::Asset::Template->new($self->session, $self->get('frontPageTemplateId'));
$self->{_frontPageTemplate}->prepare;
}
#-------------------------------------------------------------------
sub processPropertiesFromFormPost {
my $self = shift;
my $groupsChanged =
(($self->session->form->process('groupIdView') ne $self->get('groupIdView'))
or ($self->session->form->process('groupIdEdit') ne $self->get('groupIdEdit')));
my $ret = $self->SUPER::processPropertiesFromFormPost(@_);
if ($groupsChanged) {
foreach my $child (@{$self->getLineage(['children'], {returnObjects => 1})}) {
$child->update({ groupIdView => $self->get('groupIdView'),
groupIdEdit => $self->get('groupIdEdit') });
}
}
return $ret;
}
#-------------------------------------------------------------------
sub purge {
my $self = shift;
$self->session->db->write('DELETE FROM WikiMaster_titleIndex WHERE assetId = ?', [$self->getId]);
return $self->SUPER::purge;
}
#-------------------------------------------------------------------
sub updateTitleIndex {
my $self = shift;
my @pages = @{+shift};
my %opts = @_;
return unless @pages;
$self->session->db->write("DELETE FROM WikiMaster_titleIndex WHERE assetId = ? AND pageId IN (".join(', ', ('?') x @pages).")", [$self->getId, map{$_->getId} @pages]);
foreach my $page (@pages) {
my ($pageId, $title) = ($page->getId, $page->get('title'));
$self->session->db->write("INSERT INTO WikiMaster_titleIndex (assetId, pageId, title) VALUES (?, ?, ?)", [$self->getId, $pageId, $title]);
}
}
#-------------------------------------------------------------------
sub view {
my $self = shift;
my $var = {};
my $template = $self->{_frontPageTemplate};
$var->{'description'} = $self->autolinkHtml($self->get('description'));
$self->_appendSearchBoxVars($var);
$self->_appendRecentChangesVars($var, [0, $self->get('recentChangesCountFront')]);
$self->_appendFuncTemplateVars($var, qw/recentChanges/);
return $self->processMasterTemplate($self->get('title'), $self->processTemplate($var, undef, $template));
}
#-------------------------------------------------------------------
sub www_addPageSave {
my $self = shift;
my $pageClass = $self->session->form->process('class');
return $self->session->privilege->insufficient unless
$self->canEditPages and UNIVERSAL::isa($pageClass, 'WebGUI::Asset::WikiPage');
# Refactor: duplication with A::W::Matrix::www_editListingSave
my $oldTag = WebGUI::VersionTag->getWorking($self->session, 1);
my $newTag = WebGUI::VersionTag->create
($self->session, { name => (sprintf "%s create of %s - %s",
$self->get('title'), $self->session->form->process('title'),
$self->session->user->username),
workflowId => 'pbworkflow000000000003' });
$newTag->setWorking;
# Hrm. Duplication with Asset::www_editSave. How to fix that?
my $page = $self->addChild({ className => $pageClass });
$page->{_parent} = $self;
my $error = $page->processPropertiesFromFormPost;
if (ref $error eq 'ARRAY') {
$self->session->stow->set('editFormErrors', $error);
$page->purge;
return $self->www_add;
}
$page->updateHistory('edited');
$newTag->requestCommit;
$newTag->clearWorking;
$oldTag->setWorking if defined $oldTag;
return $page->www_view;
}
#-------------------------------------------------------------------
sub www_listPages {
my $self = shift;
my $i18n = WebGUI::International->new($self->session, 'Asset_WikiMaster');
my $title = $i18n->get('listPages title');
my $template = WebGUI::Asset::Template->new($self->session, $self->get('pageListTemplateId'));
$template->prepare;
my @pages = sort { lc($a->get('title')) <=> lc($b->get('title')) }
@{$self->getLineage(['children'], {returnObjects => 1})};
my $var = {};
$var->{'pl.entries'} = $self->_templateSubvarsRefOfPages(\@pages);
return $self->processStyle($self->processMasterTemplate($title, $self->processTemplate($var, undef, $template)));
}
#-------------------------------------------------------------------
sub www_recentChanges {
my $self = shift;
my $title = WebGUI::International->new($self->session, 'Asset_WikiMaster')->get('recentChanges title');
my $template = WebGUI::Asset::Template->new($self->session, $self->get('recentChangesTemplateId'));
$template->prepare;
my $var = {};
$self->_appendRecentChangesVars($var, [0, $self->get('recentChangesCount')]);
return $self->processStyle($self->processMasterTemplate($title, $self->processTemplate($var, undef, $template)));
}
#-------------------------------------------------------------------
sub www_search {
my $self = shift;
my $var = {};
my $queryString = $self->session->form->process('query', 'text');
$self->_appendSearchBoxVars($var, $queryString);
if (length $queryString) {
my $search = WebGUI::Search->new($self->session);
$search->search({ keywords => $queryString,
lineage => [$self->get('lineage')],
classes => ['WebGUI::Asset::WikiPage'] });
my $rs = $search->getResultSet;
$self->_appendSearchResultVars($var, $rs);
}
my $title = WebGUI::International->new($self->session, 'Asset_WikiMaster')->get('search title');
my $template = WebGUI::Asset::Template->new($self->session, $self->get('searchTemplateId'));
$template->prepare;
return $self->processStyle($self->processMasterTemplate($title, $self->processTemplate($var, undef, $template)));
}
1;

79
www/extras/yui-webgui/accordion.js vendored Normal file
View file

@ -0,0 +1,79 @@
// This is a modified version of the accordion tutorial from www.webthreads.de
/*
var myAccordion = new Accordion(id [, height]);
id: The id of the div that contains the accordion structure.
height: An integer representing the height that the accordion should be drawn in pixels. Defaults to the viewport height minus one header width.
*/
function Accordion(id, accordionHeight) {
// pointer to the accordion container
this.accContainer = document.getElementById(id);
// all items with class = accordionItem
this.accItems = YAHOO.util.Dom.getElementsByClassName("accordionItem", "div", this.accContainer);
// scale the acccordion to the appropriate height
this.accordionHeight = 0;
var headerHeight = YAHOO.util.Dom.getElementsByClassName("accordionHeader", "div", this.accItems[0])[0].offsetHeight;
if (accordionHeight > 0) {
this.accordionHeight = accordionHeight;
} else {
this.accordionHeight = YAHOO.util.Dom.getViewportHeight() - headerHeight;
}
this.accContainer.style.height = this.accordionHeight + "px";
var bodyHeight = this.accordionHeight - (headerHeight * this.accItems.length);
YAHOO.util.Dom.getElementsByClassName("accordionBody", "div", this.accItems[0])[0].style.height = bodyHeight + "px";
// set the default accordion body height
this.accItemBodyHeight = 0;
// iterate over all the accordian elements and store them in an array
for (var i=0; i<this.accItems.length; i++) {
// set current accordion element as parent to header and body
this.accItems[i].parent = this;
// set current accordion element's header and body
this.accItems[i].header = YAHOO.util.Dom.getElementsByClassName("accordionHeader", "div", this.accItems[i])[0];
this.accItems[i].body = YAHOO.util.Dom.getElementsByClassName("accordionBody", "div", this.accItems[i])[0];
// determine and set the active accordion element
if (this.accItems[i].body.offsetHeight > this.accItemBodyHeight) {
this.accItemBodyHeight = this.accItems[i].body.offsetHeight;
this.activeItem = this.accItems[i];
this.activeItem.body.style.height = this.accItemBodyHeight + "px";
}
// register the click event on the header for changing the active element in the accordion
YAHOO.util.Event.addListener(this.accItems[i].header, "click", function(){
// do nothing if they click on the active header
if(this.parent.activeItem == this){
return;
}
// shrink animation
var shrinkLastAccAnim = new YAHOO.util.Anim(this.parent.activeItem.body, {height:{from:this.parent.accItemBodyHeight, to:0}}, 0.1);
// expand animation
var expandNewActiveAccAnim = new YAHOO.util.Anim(this.body, {height:{from:0, to:this.parent.accItemBodyHeight}}, 0.1);
// set the selected element as active
expandNewActiveAccAnim.onStart.subscribe(function() { this.parent.activeItem = this; }, this, true);
// execute the animation
shrinkLastAccAnim.animate();
expandNewActiveAccAnim.animate();
}, this.accItems[i], true);
}
// only the active element remains expanded
for(var i=0; i<this.accItems.length; i++){
if(this.activeItem != this.accItems[i]){
this.accItems[i].body.style.height = 0 + "px";
}
}
};

View file

@ -0,0 +1,86 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Accordion Example</title>
<script type="text/javascript" src="/extras/yui/build/yahoo/yahoo-min.js"></script>
<script type="text/javascript" src="/extras/yui/build/event/event-min.js"></script>
<script type="text/javascript" src="/extras/yui/build/dom/dom-min.js"></script>
<script type="text/javascript" src="/extras/yui/build/animation/animation-min.js"></script>
<script type="text/javascript" src="/extras/yui-webgui/accordion.js"></script>
<link type="text/css" rel="stylesheet" href="/extras/yui-webgui/resources/css/accordion.css" />
<script type="text/javascript">
YAHOO.util.Event.addListener(window, 'load', function () {var myAccordion = new Accordion("myAccordion");} );
</script>
<style type="text/css" media="screen">
.accordion {
width: 300px;
border: 1px solid #999999;
font-family: Helvetica,Arial,sans-serif;
font-size: 12px;
color: #000000;
}
.accordionHeader {
height: 16px;
background-color: #CFD8E4;
border: 1px solid #999999;
font-size: 14px;
padding: 1px 0px 1px 3px;
}
.accordionBody {
padding: 0px 2px;
background-color: #EEEEEE;
}
</style>
</head>
<body>
<div id="myAccordion" class="accordion">
<div class="accordionItem">
<div class="accordionHeader">accordion header 1</div>
<div class="accordionBody">
accordion 1 accordion 1 accordion 1 accordion 1
accordion 1 accordion 1 accordion 1 accordion 1
accordion 1 accordion 1 accordion 1 accordion 1
accordion 1 accordion 1 accordion 1 accordion 1
accordion 1 accordion 1 accordion 1 accordion 1
accordion 1 accordion 1 accordion 1 accordion 1
</div>
</div>
<div class="accordionItem">
<div class="accordionHeader">accordion header 2</div>
<div class="accordionBody">
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
accordion 2 accordion 2 accordion 2 accordion 2
</div>
</div>
<div class="accordionItem">
<div class="accordionHeader">accordion header 3</div>
<div class="accordionBody">accordion body 3</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,11 @@
.accordion { }
.accordionHeader {
cursor: pointer;
}
.accordionBody {
height: 0px;
overflow: auto;
}