2 // display.php: fetch page or get default content
3 rcs_id('$Id: display.php,v 1.70 2007-01-22 23:43:06 rurban Exp $');
5 require_once('lib/Template.php');
8 * Extract keywords from Category* links on page.
10 function GleanKeywords ($page) {
11 if (!defined('KEYWORDS')) return '';
12 include_once("lib/TextSearchQuery.php");
13 $search = new TextSearchQuery(KEYWORDS, true);
14 $KeywordLinkRegexp = $search->asRegexp();
15 // iterate over the pagelinks (could be a large number) [15ms on PluginManager]
16 // or do a titleSearch and check the categories if they are linked?
17 $links = $page->getPageLinks();
18 $keywords[] = SplitPagename($page->getName());
19 while ($link = $links->next()) {
20 if (preg_match($KeywordLinkRegexp, $link->getName(), $m))
21 $keywords[] = SplitPagename($m[0]);
23 $keywords[] = WIKI_NAME;
24 return join(', ', $keywords);
27 /** Make a link back to redirecting page.
29 * @param $pagename string Name of redirecting page.
30 * @return XmlContent Link to the redirecting page.
32 function RedirectorLink($pagename) {
33 $url = WikiURL($pagename, array('redirectfrom' => ''));
34 return HTML::a(array('class' => 'redirectfrom wiki',
40 function actionPage(&$request, $action) {
43 $pagename = $request->getArg('pagename');
44 $version = $request->getArg('version');
46 $page = $request->getPage();
47 $revision = $page->getCurrentRevision();
49 $dbi = $request->getDbh();
50 $actionpage = $dbi->getPage($action);
51 $actionrev = $actionpage->getCurrentRevision();
53 $pagetitle = HTML(fmt("%s: %s",
54 $actionpage->getName(),
55 $WikiTheme->linkExistingWikiWord($pagename, false, $version)));
57 $validators = new HTTP_ValidatorSet(array('pageversion' => $revision->getVersion(),
58 '%mtime' => $revision->get('mtime')));
60 $request->appendValidators(array('pagerev' => $revision->getVersion(),
61 '%mtime' => $revision->get('mtime')));
62 $request->appendValidators(array('actionpagerev' => $actionrev->getVersion(),
63 '%mtime' => $actionrev->get('mtime')));
65 $transformedContent = $actionrev->getTransformedContent();
67 /* Optionally tell google (and others) not to take notice of action pages.
68 RecentChanges or AllPages might be an exception.
71 if (GOOGLE_LINKS_NOFOLLOW)
72 $args = array('ROBOTS_META' => "noindex,nofollow");
74 /* Handle other formats: So far we had html only.
75 xml is requested by loaddump, rss is handled by recentchanges,
76 pdf is a special action, but should be a format to dump multiple pages
77 if the actionpage plugin returns a pagelist.
78 rdf and owl are handled by SemanticWeb.
80 $format = $request->getArg('format');
81 /* At first the single page formats: html, xml */
82 if (!$format or $format == 'html' or $format == 'sidebar') {
83 $template = Template('browse', array('CONTENT' => $transformedContent));
84 GeneratePage($template, $pagetitle, $revision, $args);
85 } elseif ($format == 'xml') {
86 $template = Template('browse', array('CONTENT' => $transformedContent));
87 GeneratePageAsXML($template, $pagetitle, $revision, $args);
90 // Then the multi-page formats
91 // rss (if not already handled by RecentChanges)
92 // Need the pagelist from the first plugin
93 foreach($transformedContent->_content as $cached_element) {
94 if (is_a($cached_element, "Cached_PluginInvocation")) {
95 include_once('lib/WikiPlugin.php');
96 $loader = new WikiPluginLoader;
98 // return the first found pagelist
99 $pagelist = $loader->expandPI($cached_element->_pi, $request, $markup, $pagename);
100 if (is_a($pagelist, 'PageList'))
104 if (!$pagelist or !is_a($pagelist, 'PageList')) {
105 if (!in_array($format, array("atom","rss","rdf")))
106 trigger_error(sprintf("Format %s requires an actionpage returning a pagelist.", $format)
107 ."\n".("Fall back to single page mode"), E_USER_WARNING);
108 $pagelist = new PageList();
109 $pagelist->addPage($page);
111 if ($format == 'pdf') {
112 include_once("lib/pdf.php");
113 ConvertAndDisplayPdfPageList($request, $pagelist);
114 } elseif ($format == 'rss') {
115 include_once("lib/plugin/RecentChanges.php");
116 $rdf = new RssWriter($request, $pagelist);
118 } elseif ($format == 'rss91') {
119 include_once("lib/plugin/RecentChanges.php");
120 $rdf = new RSS91Writer($request, $pagelist);
122 } elseif ($format == 'rss2') {
123 include_once("lib/RssWriter2.php");
124 $rdf = new RssWriter2($request, $pagelist);
126 } elseif ($format == 'atom') {
127 include_once("lib/plugin/RssWriter.php");
128 $rdf = new AtomWriter($request, $pagelist);
130 } elseif ($format == 'rdf') { // all semantic relations and attributes
131 include_once("lib/SemanticWeb.php");
132 $rdf = new RdfWriter($request, $pagelist);
134 } elseif ($format == 'owl') {
135 include_once("lib/SemanticWeb.php");
136 $rdf = new OwlWriter($request, $pagelist);
138 } elseif ($format == 'kbmodel') {
139 include_once("lib/SemanticWeb.php");
140 $model = new ModelWriter($request, $pagelist);
143 trigger_error(sprintf("Unhandled format %s. Reverting to html", $format), E_USER_WARNING);
144 $template = Template('browse', array('CONTENT' => $transformedContent));
145 GeneratePage($template, $pagetitle, $revision, $args);
148 $request->checkValidators();
152 function displayPage(&$request, $template=false) {
154 $pagename = $request->getArg('pagename');
155 $version = $request->getArg('version');
156 $page = $request->getPage();
158 $revision = $page->getRevision($version);
160 NoSuchRevision($request, $page, $version);
161 /* Tell Google (and others) to ignore old versions of pages */
162 $toks['ROBOTS_META'] = "noindex,nofollow";
165 $revision = $page->getCurrentRevision();
168 if (isSubPage($pagename)) {
169 $pages = explode(SUBPAGE_SEPARATOR, $pagename);
170 $last_page = array_pop($pages); // deletes last element from array as side-effect
171 $pageheader = HTML::span(HTML::a(array('href' => WikiURL($pages[0]),
172 'class' => 'pagetitle'
174 $WikiTheme->maybeSplitWikiWord($pages[0] . SUBPAGE_SEPARATOR)));
175 $first_pages = $pages[0] . SUBPAGE_SEPARATOR;
177 foreach ($pages as $p) {
178 $pageheader->pushContent(HTML::a(array('href' => WikiURL($first_pages . $p),
179 'class' => 'backlinks'),
180 $WikiTheme->maybeSplitWikiWord($p . SUBPAGE_SEPARATOR)));
181 $first_pages .= $p . SUBPAGE_SEPARATOR;
183 $backlink = HTML::a(array('href' => WikiURL($pagename,
184 array('action' => _("BackLinks"))),
185 'class' => 'backlinks'),
186 $WikiTheme->maybeSplitWikiWord($last_page));
187 $backlink->addTooltip(sprintf(_("BackLinks for %s"), $pagename));
188 $pageheader->pushContent($backlink);
190 $pageheader = HTML::a(array('href' => WikiURL($pagename,
191 array('action' => _("BackLinks"))),
192 'class' => 'backlinks'),
193 $WikiTheme->maybeSplitWikiWord($pagename));
194 $pageheader->addTooltip(sprintf(_("BackLinks for %s"), $pagename));
195 if ($request->getArg('frame'))
196 $pageheader->setAttr('target', '_top');
199 $pagetitle = SplitPagename($pagename);
200 if (($redirect_from = $request->getArg('redirectfrom'))) {
201 $redirect_message = HTML::span(array('class' => 'redirectfrom'),
202 fmt("(Redirected from %s)",
203 RedirectorLink($redirect_from)));
204 // abuse the $redirected template var for some status update notice
205 } elseif ($request->getArg('errormsg')) {
206 $redirect_message = $request->getArg('errormsg');
207 $request->setArg('errormsg', false);
210 $request->appendValidators(array('pagerev' => $revision->getVersion(),
211 '%mtime' => $revision->get('mtime')));
213 // FIXME: This is also in the template...
214 if ($request->getArg('action') != 'pdf' and !headers_sent()) {
215 // FIXME: enable MathML/SVG/... support
218 and strstr($request->get('HTTP_ACCEPT'),'application/xhtml+xml')))
219 header("Content-Type: application/xhtml+xml; charset=" . $GLOBALS['charset']);
221 header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
225 $toks['TITLE'] = $pagetitle; // <title> tag
226 $toks['HEADER'] = $pageheader; // h1 with backlink
227 $toks['revision'] = $revision;
229 // On external searchengine (google) referrer, highlight the searchterm and
230 // pass through the Searchhighlight actionpage.
231 if ($result = isExternalReferrer($request)) {
232 if (!empty($result['query'])) {
233 if (ENABLE_SEARCHHIGHLIGHT) {
234 $request->_searchhighlight = $result;
235 $request->appendValidators(array('%mtime' => time())); // force no cache(?)
236 // Should be changed to check the engine and search term only
237 // $request->setArg('nocache', 1);
238 $page_content = new TransformedText($revision->getPage(),
239 $revision->getPackedContent(),
240 $revision->getMetaData());
241 /* Now add the SearchHighlight plugin to the top of the page, in memory only.
242 You can parametrize this by changing the SearchHighlight action page.
244 if ($actionpage = $request->findActionPage('SearchHighlight')) {
245 $actionpage = $request->getPage($actionpage);
246 $actionrev = $actionpage->getCurrentRevision();
247 $pagetitle = HTML(fmt("%s: %s",
248 $actionpage->getName(),
249 $WikiTheme->linkExistingWikiWord($pagename, false, $version)));
250 $request->appendValidators(array('actionpagerev' => $actionrev->getVersion(),
251 '%mtime' => $actionrev->get('mtime')));
252 $toks['SEARCH_ENGINE'] = $result['engine'];
253 $toks['SEARCH_ENGINE_URL'] = $result['engine_url'];
254 $toks['SEARCH_TERM'] = $result['query'];
255 //$toks['HEADER'] = HTML($actionpage->getName(),": ",$pageheader); // h1 with backlink
256 $actioncontent = new TransformedText($actionrev->getPage(),
257 $actionrev->getPackedContent(),
258 $actionrev->getMetaData());
259 // prepend the actionpage in front of the hightlighted content
260 $toks['CONTENT'] = HTML($actioncontent, $page_content);
264 $page_content = $revision->getTransformedContent();
267 $page_content = $revision->getTransformedContent();
270 /* Check for special pagenames, which are no actionpages. */
272 if ( $pagename == _("RecentVisitors")) {
273 $toks['ROBOTS_META']="noindex,follow";
276 if ($pagename == _("SandBox")) {
277 $toks['ROBOTS_META']="noindex,nofollow";
278 } else if (!isset($toks['ROBOTS_META'])) {
279 $toks['ROBOTS_META'] = "index,follow";
281 if (!isset($toks['CONTENT']))
282 $toks['CONTENT'] = new Template('browse', $request, $page_content);
283 if (!empty($redirect_message))
284 $toks['redirected'] = $redirect_message;
286 $toks['PAGE_DESCRIPTION'] = $page_content->getDescription();
287 $toks['PAGE_KEYWORDS'] = GleanKeywords($page);
289 $template = new Template('html', $request);
291 // Handle other formats: So far we had html only.
292 // xml is requested by loaddump, rss is handled by RecentChanges,
293 // pdf is a special action, but should be a format to dump multiple pages
294 // if the actionpage plugin returns a pagelist.
295 // rdf, owl, kbmodel, daml, ... are handled by SemanticWeb.
296 $format = $request->getArg('format');
297 /* Only single page versions. rss only if not already handled by RecentChanges.
299 if (!$format or $format == 'html' or $format == 'sidebar') {
300 $template->printExpansion($toks);
301 } elseif ($format == 'xml') {
302 $template = new Template('htmldump', $request);
303 $template->printExpansion($toks);
305 // No pagelist here. Single page version only
306 include_once("lib/PageList.php");
307 $pagelist = new PageList();
308 $pagelist->addPage($page);
309 if ($format == 'pdf') {
310 include_once("lib/pdf.php");
311 ConvertAndDisplayPdfPageList($request, $pagelist);
312 } elseif ($format == 'rss') {
313 include_once("lib/plugin/RecentChanges.php");
314 $rdf = new RssWriter($request, $pagelist);
316 } elseif ($format == 'rss91') {
317 include_once("lib/plugin/RecentChanges.php");
318 $rdf = new RSS91Writer($request, $pagelist);
320 } elseif ($format == 'rss2') {
321 include_once("lib/RssWriter2.php");
322 $rdf = new RssWriter2($request, $pagelist);
324 } elseif ($format == 'atom') {
325 include_once("lib/plugin/RssWriter.php");
326 $rdf = new AtomWriter($request, $pagelist);
328 } elseif ($format == 'rdf') { // all semantic relations and attributes
329 include_once("lib/SemanticWeb.php");
330 $rdf = new RdfWriter($request, $pagelist);
332 } elseif ($format == 'owl') {
333 include_once("lib/SemanticWeb.php");
334 $rdf = new OwlWriter($request, $pagelist);
336 } elseif ($format == 'kbmodel') {
337 include_once("lib/SemanticWeb.php");
338 $model = new ModelWriter($request, $pagelist);
341 trigger_error(sprintf("Unhandled format %s. Reverting to html", $format), E_USER_WARNING);
342 $template->printExpansion($toks);
346 $page->increaseHitCount();
348 if ($request->getArg('action') != 'pdf')
349 $request->checkValidators();
353 // $Log: not supported by cvs2svn $
354 // Revision 1.69 2007/01/20 15:53:51 rurban
355 // Rewrite of SearchHighlight: through ActionPage and InlineParser
357 // Revision 1.68 2007/01/20 11:25:19 rurban
358 // actionPage: request is already global
360 // Revision 1.67 2007/01/07 18:44:20 rurban
361 // Support format handlers for single- and multi-page: pagelists from actionpage plugins. Use USE_SEARCHHIGHLIGHT. Fix InlineHighlight (still experimental).
363 // Revision 1.66 2006/03/19 14:26:29 rurban
364 // sf.net patch by Matt Brown: Add rel=nofollow to more actions
366 // Revision 1.65 2005/05/05 08:54:40 rurban
367 // fix pagename split for title and header
369 // Revision 1.64 2005/04/23 11:21:55 rurban
370 // honor theme-specific SplitWikiWord in the HEADER
372 // Revision 1.63 2004/11/30 17:48:38 rurban
375 // Revision 1.62 2004/11/30 09:51:35 rurban
376 // changed KEYWORDS from pageprefix to search term. added installer detection.
378 // Revision 1.61 2004/11/21 11:59:19 rurban
379 // remove final \n to be ob_cache independent
381 // Revision 1.60 2004/11/19 19:22:03 rurban
382 // ModeratePage part1: change status
384 // Revision 1.59 2004/11/17 20:03:58 rurban
385 // Typo: call SearchHighlight not SearchHighLight
387 // Revision 1.58 2004/11/09 17:11:16 rurban
388 // * revert to the wikidb ref passing. there's no memory abuse there.
389 // * use new wikidb->_cache->_id_cache[] instead of wikidb->_iwpcache, to effectively
390 // store page ids with getPageLinks (GleanDescription) of all existing pages, which
391 // are also needed at the rendering for linkExistingWikiWord().
392 // pass options to pageiterator.
393 // use this cache also for _get_pageid()
394 // This saves about 8 SELECT count per page (num all pagelinks).
395 // * fix passing of all page fields to the pageiterator.
396 // * fix overlarge session data which got broken with the latest ACCESS_LOG_SQL changes
398 // Revision 1.57 2004/11/01 10:43:57 rurban
399 // seperate PassUser methods into seperate dir (memory usage)
400 // fix WikiUser (old) overlarge data session
401 // remove wikidb arg from various page class methods, use global ->_dbi instead
404 // Revision 1.56 2004/10/14 13:44:14 rurban
405 // fix lib/display.php:159: Warning[2]: Argument to array_reverse() should be an array
407 // Revision 1.55 2004/09/26 14:58:35 rurban
408 // naive SearchHighLight implementation
410 // Revision 1.54 2004/09/17 14:19:41 rurban
411 // disable Content-Type header for now, until it is fixed
413 // Revision 1.53 2004/06/25 14:29:20 rurban
414 // WikiGroup refactoring:
415 // global group attached to user, code for not_current user.
416 // improved helpers for special groups (avoid double invocations)
417 // new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
418 // fixed a XHTML validation error on userprefs.tmpl
420 // Revision 1.52 2004/06/14 11:31:37 rurban
421 // renamed global $Theme to $WikiTheme (gforge nameclash)
422 // inherit PageList default options from PageList
423 // default sortby=pagename
424 // use options in PageList_Selectable (limit, sortby, ...)
425 // added action revert, with button at action=diff
426 // added option regex to WikiAdminSearchReplace
428 // Revision 1.51 2004/05/18 16:23:39 rurban
429 // rename split_pagename to SplitPagename
431 // Revision 1.50 2004/05/04 22:34:25 rurban
434 // Revision 1.49 2004/04/18 01:11:52 rurban
435 // more numeric pagename fixes.
436 // fixed action=upload with merge conflict warnings.
437 // charset changed from constant to global (dynamic utf-8 switching)
445 // c-hanging-comment-ender-p: nil
446 // indent-tabs-mode: nil