/**********************************************************************
*
* browsetools.cpp --
* Copyright (C) 1999 The New Zealand Digital Library Project
*
* A component of the Greenstone digital library software
* from the New Zealand Digital Library Project at the
* University of Waikato, New Zealand.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: browsetools.cpp 533 1999-09-07 04:57:01Z sjboddie $
*
*********************************************************************/
/*
$Log$
Revision 1.21 1999/09/07 04:56:52 sjboddie
added GPL notice
Revision 1.20 1999/08/25 04:46:58 sjboddie
fixed bug
Revision 1.19 1999/08/13 04:18:04 sjboddie
fixed some typos
Revision 1.18 1999/08/10 22:42:21 sjboddie
added more format options to document tocs - there are now just two
types of toc - standard (Hierarchical) and document (as in books)
Revision 1.17 1999/08/09 02:12:07 sjboddie
made it so dates may be only 4 digits (i.e. year only)
Revision 1.16 1999/07/30 02:16:10 sjboddie
-added ability to display nested classifications (expanded versions
of nested classifications has yet to be done).
-changed set_arrow_macros slightly to fit in with new showtoppage
format option
Revision 1.15 1999/07/21 05:01:56 sjboddie
wrote handler for DateList classification
Revision 1.14 1999/07/20 02:58:15 sjboddie
got List and AZList classifications using format strings - tidied
up a bit
Revision 1.13 1999/07/07 05:44:25 sjboddie
Made some changes to allow for new way classifiers work (i.e. you can
now have classifiers containing other classifiers). At present there's
only a special case for dealing with the hdl 'magazine' section. A bit
of a redesign is needed to get it completely flexible
Revision 1.12 1999/07/01 03:47:49 rjmcnab
Fixed a small warning.
Revision 1.11 1999/06/27 21:49:01 sjboddie
fixed a couple of version conflicts - tidied up some small things
Revision 1.10 1999/06/26 01:07:21 rjmcnab
Fixed a small "bug" -- well I probably just covered another one...
Revision 1.9 1999/06/24 05:12:15 sjboddie
lots of small changes
Revision 1.8 1999/06/17 03:06:53 sjboddie
got detach button working properly - the close book icon is now disabled
when page is detached as the javascript close() function I was using is
too unreliable over different browsers
note that in my last comment I meant the "cl" arg (not the "c" arg).
Revision 1.7 1999/06/16 23:53:14 sjboddie
tidied a few things up. documentaction::define_external_macros now
resets the "c" arg if it's set to something stupid by the .xx suffixes
Revision 1.6 1999/06/16 04:03:47 sjboddie
Now sets "cl" arg to "search" when going to a document from a search
results page. This allows the close book icon (in hierarchy toc) to
take you back to the results page if that's where you came from.
If you got to the document page somehow other than from a
classification or a search (i.e. if "cl" isn't set) then the close
book icon is disabled
Revision 1.5 1999/06/16 03:11:25 sjboddie
get_info() now takes a getParents argument
Revision 1.4 1999/05/10 03:40:26 sjboddie
lots of changes - slowly getting document action sorted out
Revision 1.3 1999/04/30 01:59:39 sjboddie
lots of stuff - getting documentaction working (documentaction replaces
old browseaction)
Revision 1.2 1999/03/29 02:14:29 sjboddie
More changes to browseaction
Revision 1.1 1999/03/25 03:10:15 sjboddie
new library for browse stuff
*/
#include "browsetools.h"
#include "OIDtools.h"
// simply checks to see if formatstring begins with a
tag
static bool is_table_content (const text_t &formatstring) {
text_t::const_iterator here = formatstring.begin();
text_t::const_iterator end = formatstring.end();
while (here != end) {
if (*here != ' ') {
if (*here == '<') {
if ((*(here+1) == 't' || *(here+1) == 'T') &&
(*(here+2) == 'd' || *(here+2) == 'D') &&
(*(here+3) == '>' || *(here+3) == ' '))
return true;
} else return false;
}
here ++;
}
return false;
}
static bool is_table_content (const format_t *formatlistptr) {
if (formatlistptr == NULL) return false;
if (formatlistptr->command == comText)
return is_table_content (formatlistptr->text);
return false;
}
// output_controls displays the detach, expand/contract contents,
// expand/contract text and highlighting/no highlighting buttons
static void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
recptproto */*collectproto*/, displayclass &disp,
outconvertclass &outconvert, ostream &textout,
ostream &/*logout*/) {
if (args["u"] != "1") {
FilterResponse_t response;
text_tarray metadata;
text_tarray buttons;
text_tarray::const_iterator here = ibuttons.begin();
text_tarray::const_iterator end = ibuttons.end();
while (here != end) {
if (*here == "Detach")
buttons.push_back ("_document:imagedetach_");
else if (*here == "Highlight") {
if (args["hl"] == "1")
buttons.push_back ("_document:imagenohighlight_");
else
buttons.push_back ("_document:imagehighlight_");
} else if (*here == "Expand Contents") {
if (args["gc"] == "1")
buttons.push_back ("_document:imagecontracttoc_");
else
buttons.push_back ("_document:imageexpandtoc_");
} else if (*here == "Expand Text") {
if (args.getintarg("gt"))
buttons.push_back ("_document:imagecontracttext_");
else
buttons.push_back ("_document:imageexpandtext_");
}
here ++;
}
here = buttons.begin();
end = buttons.end();
int count = 0;
while (here != end) {
if ((count != 0) && ((count % 3) == 0)) textout << " \n";
textout << outconvert << disp << *here;
count ++;
here ++;
}
}
}
// at the moment this just writes out the html to display
// the cover image (assuming it's called cover.jpg)
// this whole thing should be done with a call to the collection
// server which would send a link to the cover image if there
// was one otherwise send title, author and stuff
static void output_cover_image (cgiargsclass &args, recptproto */*collectproto*/,
displayclass &disp, outconvertclass &outconvert,
ostream &textout, ostream &/*logout*/) {
if (args["d"].empty()) return;
textout << outconvert << disp <<
" \n";
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Functions for generating a document type tables of contents. These aren't really tables of
contents at all, just a title, some navigation buttons and arrows and maybe a page ? of ?
type thing. These should only be called for document level tocs (i.e. when the "d" argument
is set) as I don't think it makes sense to display top level classifications in this way.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
void output_document_toc (cgiargsclass &args, const formatinfo_t &formatinfo,
recptproto *collectproto, displayclass &disp,
outconvertclass &outconvert, ostream &textout,
ostream &logout) {
text_t &arg_d = args["d"];
if (arg_d.empty()) return;
text_tarray metadata;
FilterResponse_t response;
bool getParents = false;
ResultDocInfo_t docinfo;
text_t &collection = args["c"];
int gt = args.getintarg("gt");
bool istop = is_top (arg_d);
format_t *formatlistptr = new format_t();
parse_formatstring (formatinfo.DocumentHeading, formatlistptr, metadata, getParents);
text_tarray OIDs;
OIDs.push_back (arg_d);
if (formatinfo.DocumentArrowsTop && !gt && !istop)
OIDs.push_back (arg_d + ".pr.lc");
metadata.push_back ("Title");
int metasize = metadata.size();
if (get_info (OIDs, collection, metadata, getParents, collectproto, response, logout)) {
text_t &thistitle = response.docInfo[0].metadata[metasize-1].values.back();
text_t last_sib_title;
if (formatinfo.DocumentArrowsTop && !gt && !istop) {
if (response.docInfo.size() == 1)
last_sib_title = response.docInfo[0].metadata[metasize-1].values.back();
else
last_sib_title = response.docInfo[1].metadata[metasize-1].values.back();
}
textout
<< "\n\n\n";
textout << outconvert << disp
<< "\n"
<< "\n"
<< "\n";
// top arrows and page ? of ? title
if (formatinfo.DocumentArrowsTop && !gt) {
// previous arrow
textout << outconvert << disp << "\n"
<< "_document:prevarrow_ | \n";
// page ? of ? text
textout << "\n";
if (!istop && is_number (thistitle) && is_number (last_sib_title))
textout << outconvert << disp << "_document:page_" << thistitle
<< "_document:of_" << last_sib_title;
else
textout << outconvert << thistitle;
// next arrow
textout << outconvert << disp << " | \n_document:nextarrow_ | \n \n";
}
// goto line
if (formatinfo.DocumentGoTo)
textout << outconvert << disp << "_document:gotoform_";
// control buttons
output_controls (args, formatinfo.DocumentButtons, collectproto,
disp, outconvert, textout, logout);
textout << " | \n";
// heading
textout << outconvert << "\n\n"
<< get_formatted_string (response.docInfo[0], formatlistptr);
textout << " | \n";
textout << "\n\n";
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Functions for generating a "Hierarchy" type table of contents. These can be used either
at top classification level or at document level (the difference being that a cover
image and control buttons may be displayed at document level).
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
// prototypes
static void output_contracted_hierarchy_toc (const text_t &classifytype, text_t &formatstring,
cgiargsclass &args, recptproto *collectproto,
displayclass &disp, outconvertclass &outconvert,
ostream &textout, ostream &logout);
static void output_expanded_hierarchy_toc (cgiargsclass &args, recptproto *collectproto,
displayclass &disp, outconvertclass &outconvert,
ostream &textout, ostream &logout);
static void output_parents_toc (cgiargsclass &args, const FilterResponse_t &parents,
int &tabcount, displayclass &disp,
format_t *formatlistptr, outconvertclass &outconvert,
ostream &textout, ostream &logout);
static void output_siblings_toc (const text_t &classifytype, cgiargsclass &args,
const FilterResponse_t &siblings, int &tabcount,
displayclass &disp, format_t *formatlistptr,
outconvertclass &outconvert, ostream &textout,
ostream &logout);
static void output_stdlist (cgiargsclass &args, ResultDocInfo_tarray::const_iterator &here,
ResultDocInfo_tarray::const_iterator &end, bool intable,
displayclass &disp, format_t *formatlistptr,
outconvertclass &outconvert, ostream &textout);
static void output_datelist (cgiargsclass &args, ResultDocInfo_tarray::const_iterator &here,
ResultDocInfo_tarray::const_iterator &end, bool intable,
displayclass &disp, format_t *formatlistptr,
outconvertclass &outconvert, ostream &textout);
void output_standard_toc (const text_t &classifytype, const formatinfo_t &formatinfo,
text_t &formatstring, cgiargsclass &args,
recptproto *collectproto, displayclass &disp,
outconvertclass &outconvert, ostream &textout,
ostream &logout) {
bool havecontrols = false;
textout << "\n\n\n";
// get the cover image (if there is one) and the control buttons
// if we're inside a book
if (!args["d"].empty()) {
textout << "\n";
textout << "\n";
if (formatinfo.DocumentImages)
output_cover_image (args, collectproto, disp, outconvert, textout, logout);
output_controls (args, formatinfo.DocumentButtons, collectproto, disp,
outconvert, textout, logout);
textout << " | \n";
havecontrols = true;
}
// get table of contents
textout << "\n";
if (args.getintarg("gc"))
output_expanded_hierarchy_toc(args, collectproto, disp, outconvert, textout, logout);
else
output_contracted_hierarchy_toc(classifytype, formatstring, args, collectproto,
disp, outconvert, textout, logout);
textout << " \n";
if (havecontrols) textout << " | \n";
textout << "\n\n";
}
void output_contracted_hierarchy_toc (const text_t &classifytype, text_t &formatstring,
cgiargsclass &args, recptproto *collectproto,
displayclass &disp, outconvertclass &outconvert,
ostream &textout, ostream &logout) {
int tabcount = 0;
text_tarray parents, metadata;
FilterResponse_t fsiblings, fparents;
bool getParents = false;
text_t &arg_d = args["d"];
text_t OID = arg_d;
if (OID.empty()) OID = args["cl"];
text_t &collection = args["c"];
// if format string is empty use the default
if (formatstring.empty())
formatstring = " | [link][icon][/link] | {Or}{[Title],Untitled} | ";
format_t *formatlistptr = new format_t();
parse_formatstring (formatstring, formatlistptr, metadata, getParents);
metadata.push_back ("Date");
metadata.push_back ("hastxt");
metadata.push_back ("haschildren");
metadata.push_back ("doctype");
metadata.push_back ("classifytype");
if (has_children (OID, collection, collectproto, logout)) {
get_parents_array (OID + ".fc", parents);
if (!get_children (OID, collection, metadata, getParents,
collectproto, fsiblings, logout))
return;
} else {
get_parents_array (OID, parents);
if (!get_children (OID + ".pr", collection, metadata,
getParents, collectproto, fsiblings, logout))
return;
}
if (!get_info (parents, collection, metadata, false, collectproto, fparents, logout)) return;
if (!fparents.docInfo.empty())
output_parents_toc(args, fparents, tabcount, disp,
formatlistptr, outconvert, textout, logout);
if (!fsiblings.docInfo.empty())
output_siblings_toc (classifytype, args, fsiblings, tabcount, disp,
formatlistptr, outconvert, textout, logout);
}
void output_parents_toc (cgiargsclass &args, const FilterResponse_t &parents,
int &tabcount, displayclass &disp,
format_t *formatlistptr, outconvertclass &outconvert,
ostream &textout, ostream &/*logout*/) {
text_t tab, icon;
text_t &arg_cl = args["cl"];
text_t &arg_d = args["d"];
int numcols = parents.docInfo.size() + 1;
bool intable = is_table_content (formatlistptr);
ResultDocInfo_tarray::const_iterator thisparent = parents.docInfo.begin();
ResultDocInfo_tarray::const_iterator end = parents.docInfo.end();
int len = (*thisparent).metadata.size();
const text_t &classifytype = (*thisparent).metadata[len-1].values[0];
// don't want top level of any classifications to be displayed
if (arg_d.empty() && thisparent != end) {thisparent ++; numcols --;}
// don't want second level of classifications using classification links
if ((classifytype == "AZList" || classifytype == "DateList") && (thisparent != end))
{thisparent ++; numcols --;}
// the tab line
if (thisparent != end) {
text_t coltabs;
for (int i = 0; i < numcols; i ++) coltabs += "_document:tab_";
textout << outconvert << disp << "" << coltabs << " |
\n";
}
while (thisparent != end) {
const text_t &doctype = (*thisparent).metadata[len-2].values.back();
// set up icon and pointer
icon = "_document:icon";
if ((doctype != "classify") && ((*thisparent).OID == arg_d))
icon += "arrow";
if (doctype == "classify") icon += "openbookshelf_";
else if (is_top((*thisparent).OID)) icon += "openbook_";
else icon += "openfolder_";
if (tabcount == 1) textout << " | \n";
else if (tabcount > 1) textout << " | ";
// set up the link
text_t link = "";
else
if (is_top ((*thisparent).OID))
if (arg_cl.empty())
link = "";
else if (arg_cl == "search")
link = "";
else
link += "&cl=" + arg_cl + "\">";
else link += "&cl=" + arg_cl + "&d=" + (*thisparent).OID + ".pr\">";
if ((numcols-tabcount) == 1) textout << "";
else if ((numcols-tabcount) > 1) textout << " | ";
if (intable) textout << "";
textout << outconvert << disp
<< get_formatted_string (*thisparent, formatlistptr, link, icon);
if (intable) textout << " ";
textout << " | \n";
tabcount ++;
thisparent ++;
}
}
void output_siblings_toc (const text_t &classifytype, cgiargsclass &args,
const FilterResponse_t &siblings, int &tabcount,
displayclass &disp, format_t *formatlistptr,
outconvertclass &outconvert, ostream &textout,
ostream &/*logout*/) {
bool intable = is_table_content (formatlistptr);
ResultDocInfo_tarray::const_iterator thissibling = siblings.docInfo.begin();
ResultDocInfo_tarray::const_iterator sibend = siblings.docInfo.end();
if (thissibling == sibend) return;
// tabbing
if (tabcount) {
if (tabcount == 1) textout << " | \n";
else if (tabcount > 1) textout << "
| ";
textout << "\n";
}
if (!intable) textout << "\n";
if (classifytype == "DateList")
output_datelist (args, thissibling, sibend, intable, disp,
formatlistptr, outconvert, textout);
else
output_stdlist (args, thissibling, sibend, intable, disp,
formatlistptr, outconvert, textout);
if (!intable) textout << " | \n";
if (tabcount) textout << " |
\n";
}
void output_stdlist (cgiargsclass &args, ResultDocInfo_tarray::const_iterator &here,
ResultDocInfo_tarray::const_iterator &end, bool intable,
displayclass &disp, format_t *formatlistptr,
outconvertclass &outconvert, ostream &textout) {
text_t icon;
int count = 1;
int gt = args.getintarg("gt");
text_t &arg_cl = args["cl"];
text_t &arg_d = args["d"];
while (here != end) {
int len = (*here).metadata.size();
const text_t &doctype = (*here).metadata[len-2].values.back();
const text_t &hastxt = (*here).metadata[len-4].values.back();
const text_t &haschildren = (*here).metadata[len-3].values.back();
// set up icon and pointer
icon = "_document:icon";
if (doctype == "classify") {
if (((*here).OID == arg_cl) && (hastxt == "1"))
icon += "arrow";
} else if ((*here).OID == arg_d) icon += "arrow";
if (haschildren == "0") icon += "smalltext_";
else if (doctype == "classify") icon += "closedbookshelf_";
else if (is_top((*here).OID)) icon += "closedbook_";
else icon += "closedfolder_";
// set up link
text_t link = "";
else link += "&cl=" + arg_cl + "&d=" + (*here).OID + "\">";
if (gt) {
link = "";
count ++;
}
if (intable) textout << "";
textout << outconvert << disp
<< get_formatted_string (*here, formatlistptr, link, icon) << "\n";
if (intable) textout << "
";
here ++;
}
}
void output_datelist (cgiargsclass &args, ResultDocInfo_tarray::const_iterator &here,
ResultDocInfo_tarray::const_iterator &end, bool intable,
displayclass &disp, format_t *formatlistptr,
outconvertclass &outconvert, ostream &textout) {
text_t lastyear = "0000";
text_t lastmonth = "00";
while (here != end) {
int len = (*here).metadata.size();
const text_t &doctype = (*here).metadata[len-2].values.back();
const text_t &date = (*here).metadata[len-5].values.back();
// bail on this document if it has no date
if (date.empty()) continue;
text_t::const_iterator datebegin = date.begin();
int datesize = date.size();
if (datesize < 4) continue;
text_t thisyear = substr (datebegin, datebegin+4);
text_t thismonth = "00";
if (datesize >= 6)
thismonth = substr (datebegin+4, datebegin+6);
text_t link = "";
} else link += args["cl"] + "&d=" + (*here).OID + "\">";
textout << "\n";
if (thisyear != lastyear) {
textout << outconvert << "" << thisyear << " | ";
lastyear = thisyear;
} else
textout << " | ";
if (thismonth != lastmonth) {
textout << outconvert << disp << ("_textmonth" + thismonth + "_ | ");
lastmonth = thismonth;
} else
textout << " | ";
if (!intable) textout << "\n";
textout << outconvert << disp
<< get_formatted_string (*here, formatlistptr, link, icon) << "\n";
if (!intable) textout << " | ";
textout << "
\n";
here ++;
}
}
void output_expanded_hierarchy_toc (cgiargsclass &args, recptproto *collectproto,
displayclass &disp, outconvertclass &outconvert,
ostream &textout, ostream &logout) {
text_t OID, topOID, classifytype, icon;
FilterResponse_t response;
int tabcols=0, totalcols=0, lasttabcols=0;
int gt = args.getintarg("gt");
text_t doclink = " 0) {
tab = " 1) tab += " colspan=" + text_t(tabcols);
tab += ">" + icontabs + pointer + " | ";
}
textout << outconvert << disp << "" << tab << "";
if ((classifytype == "Document") && (is_top((*thissection).OID)) &&
(args.getintarg("x")))
textout << outconvert << disp << icon << " | ";
else
if (arg_cl.empty())
link.clear();
else if (arg_cl == "search")
link = "";
else
link = doclink + arg_cl + "\">";
else
if (haschildren)
if (classifytype == "classify")
link = doclink + thisOID + ".pr\">";
else
link = doclink + arg_cl + "&d=" + thisOID + ".pr\">";
else
if (classifytype == "classify")
link = doclink + thisOID + "\">";
else
link = doclink + arg_cl + "&d=" + thisOID + "\">";
textout << outconvert << disp << link;
} else {
textout << "";
count ++;
}
textout << outconvert << disp << icon << " | 1) textout << " colspan=" << colsremaining;
textout << outconvert << disp << ">" << title << " |
\n";
thissection ++;
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
// set_arrow_macros sets the _httpprevarrow_ and _httpnextarrow_ macros
// it shouldn't be called if OID is the top level of a book
// as the "hasprevious" and "hasnext" metadata won't be set
// when the filter can't get OIDs parent info - one day I'll
// fix this ;-)
void set_arrow_macros (const text_t &OID, const text_t &classifytype,
bool showtoppage, displayclass &disp,
recptproto *collectproto, const text_t &collection,
ostream &logout) {
if (OID.empty()) return;
text_tarray metadata;
FilterResponse_t response;
metadata.push_back ("haschildren");
metadata.push_back ("hasnext");
metadata.push_back ("hasprevious");
// get "haschildren", "hasnext" and "hasprevious" metadata for OID
if (get_info (OID, collection, metadata, false, collectproto, response, logout)) {
text_t haschildren = response.docInfo[0].metadata[0].values[0];
text_t hasnext = response.docInfo[0].metadata[1].values[0];
text_t hasprevious = response.docInfo[0].metadata[2].values[0];
if ((classifytype == "Hierarchy") || (classifytype == "Book")) {
if (haschildren == "1")
disp.setmacro ("httpnextarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.fc,_httpdocument_&cl=_cgiargcl_.fc)");
else if (hasnext == "1")
disp.setmacro ("httpnextarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.ns,_httpdocument_&cl=_cgiargcl_.ns)");
else {
// see if parent has younger siblings
if (get_info (OID + ".pr", collection, metadata, false, collectproto, response, logout)) {
if (!response.docInfo[0].metadata.empty() &&
response.docInfo[0].metadata[1].values[0] == "1")
disp.setmacro ("httpnextarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.pr.ns,_httpdocument_&cl=_cgiargcl_.pr.ns)");
}
}
if (hasprevious == "1") {
// see if OIDs older sibling has children
if (get_info (OID + ".ps", collection, metadata, false, collectproto, response, logout)) {
if (response.docInfo[0].metadata[0].values[0] == "1")
disp.setmacro ("httpprevarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.ps.lc,_httpdocument_&cl=_cgiargcl_.ps.lc)");
else
disp.setmacro ("httpprevarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.ps,_httpdocument_&cl=_cgiargcl_.ps)");
}
} else if (showtoppage && !is_top (OID))
disp.setmacro ("httpprevarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.pr,_httpdocument_&cl=_cgiargcl_.pr)");
}
else {
if (hasnext == "1")
disp.setmacro ("httpnextarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.ns,_httpdocument_&cl=_cgiargcl_.ns)");
if (hasprevious == "1")
disp.setmacro ("httpprevarrow", "document",
"_If_(_cgiargd_,_httpdocument_&cl=_cgiargcl_&d=_cgiargd_.ps,_httpdocument_&cl=_cgiargcl_.ps)");
}
}
}