2 rcs_id('$Id: PageType.php,v 1.21 2004-02-28 21:14:08 rurban Exp $');
4 Copyright 1999,2000,2001,2002,2003,2004 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
8 PhpWiki is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 PhpWiki is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with PhpWiki; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 require_once('lib/CachedMarkup.php');
25 /** A cacheable formatted wiki page.
27 class TransformedText extends CacheableMarkup {
30 * @param WikiDB_Page $page
31 * @param string $text The packed page revision content.
32 * @param hash $meta The version meta-data.
33 * @param string $type_override For markup of page using a different
34 * pagetype than that specified in its version meta-data.
36 function TransformedText($page, $text, $meta, $type_override=false) {
37 @$pagetype = $meta['pagetype'];
39 $pagetype = $type_override;
40 $this->_type = PageType::GetPageType($pagetype);
41 $this->CacheableMarkup($this->_type->transform($page, $text, $meta),
51 * A page type descriptor.
53 * Encapsulate information about page types.
55 * Currently the only information encapsulated is how to format
56 * the specific page type. In the future or capabilities may be
57 * added, e.g. the abilities to edit different page types (differently.)
58 * e.g. Support for the javascript htmlarea editor, which can only edit
61 * IMPORTANT NOTE: Since the whole PageType class gets stored (serialized)
62 * as of the cached marked-up page, it is important that the PageType classes
63 * not have large amounts of class data. (No class data is even better.)
67 * Get a page type descriptor.
69 * This is a static member function.
71 * @param string $pagetype Name of the page type.
72 * @return PageType An object which is a subclass of PageType.
74 function GetPageType ($name=false) {
78 $class = "PageType_" . (string)$name;
79 if (class_exists($class))
81 trigger_error(sprintf("PageType '%s' unknown", (string)$name),
84 return new PageType_wikitext;
88 * Get the name of this page type.
90 * @return string Page type name.
93 if (!preg_match('/^PageType_(.+)$/i', get_class($this), $m))
94 trigger_error("Bad class name for formatter(?)", E_USER_ERROR);
99 * Transform page text.
101 * @param WikiDB_Page $page
102 * @param string $text
103 * @param hash $meta Version meta-data
104 * @return XmlContent The transformed page text.
106 function transform($page, $text, $meta) {
107 $fmt_class = 'PageFormatter_' . $this->getName();
108 $formatter = new $fmt_class($page, $meta);
109 return $formatter->format($text);
113 class PageType_wikitext extends PageType {}
114 class PageType_wikiblog extends PageType {}
115 class PageType_interwikimap extends PageType
117 function PageType_interwikimap() {
119 $dbi = $request->getDbh();
120 $intermap = $this->_getMapFromWikiPage($dbi->getPage(_("InterWikiMap")));
121 if (!$intermap && defined('INTERWIKI_MAP_FILE'))
122 $intermap = $this->_getMapFromFile(INTERWIKI_MAP_FILE);
124 $this->_map = $this->_parseMap($intermap);
125 $this->_regexp = $this->_getRegexp();
128 function GetMap ($request = false) {
129 if (empty($this->_map)) {
130 $map = new PageType_interwikimap();
137 function getRegexp() {
138 return $this->_regexp;
141 function link ($link, $linktext = false) {
143 list ($moniker, $page) = split (":", $link, 2);
145 if (!isset($this->_map[$moniker])) {
146 return HTML::span(array('class' => 'bad-interwiki'),
147 $linktext ? $linktext : $link);
150 $url = $this->_map[$moniker];
152 // Urlencode page only if it's a query arg.
153 // FIXME: this is a somewhat broken heuristic.
154 $page_enc = strstr($url, '?') ? rawurlencode($page) : $page;
156 if (strstr($url, '%s'))
157 $url = sprintf($url, $page_enc);
161 $link = HTML::a(array('href' => $url));
164 $link->pushContent(PossiblyGlueIconToText('interwiki', "$moniker:"),
165 HTML::span(array('class' => 'wikipage'), $page));
166 $link->setAttr('class', 'interwiki');
169 $link->pushContent(PossiblyGlueIconToText('interwiki', $linktext));
170 $link->setAttr('class', 'named-interwiki');
177 function _parseMap ($text) {
178 global $AllowedProtocols;
179 if (!preg_match_all("/^\s*(\S+)\s+(\S+)/m",
180 $text, $matches, PREG_SET_ORDER))
182 foreach ($matches as $m) {
185 if (empty($map['Upload']))
186 $map['Upload'] = SERVER_URL . ((substr(DATA_PATH,0,1)=='/') ? '' : "/") . DATA_PATH . '/uploads/';
190 function _getMapFromWikiPage ($page) {
191 if (! $page->get('locked'))
194 $current = $page->getCurrentRevision();
196 if (preg_match('|^<verbatim>\n(.*)^</verbatim>|ms',
197 $current->getPackedContent(), $m)) {
204 function _getMapFromFile ($filename) {
205 if (defined('WARN_NONPUBLIC_INTERWIKIMAP') and WARN_NONPUBLIC_INTERWIKIMAP) {
206 $error_html = sprintf(_("Loading InterWikiMap from external file %s."), $filename);
207 trigger_error( $error_html, E_USER_NOTICE );
209 if (!file_exists($filename)) {
210 $finder = new FileFinder();
211 $filename = $finder->findFile(INTERWIKI_MAP_FILE);
213 @$fd = fopen ($filename, "rb");
214 @$data = fread ($fd, filesize($filename));
220 function _getRegexp () {
222 return '(?:(?!a)a)'; // Never matches.
224 foreach (array_keys($this->_map) as $moniker)
225 $qkeys[] = preg_quote($moniker, '/');
226 return "(?:" . join("|", $qkeys) . ")";
231 /** How to transform text.
233 class PageFormatter {
236 * @param WikiDB_Page $page
237 * @param hash $meta Version meta-data.
239 function PageFormatter($page, $meta) {
240 $this->_page = $page;
241 $this->_meta = $meta;
242 if (!empty($meta['markup']))
243 $this->_markup = $meta['markup'];
248 function _transform($text) {
249 include_once('lib/BlockParser.php');
250 return TransformText($text, $this->_markup);
253 /** Transform the page text.
255 * @param string $text The raw page content (e.g. wiki-text).
256 * @return XmlContent Transformed content.
258 function format($text) {
259 trigger_error("pure virtual", E_USER_ERROR);
263 class PageFormatter_wikitext extends PageFormatter
265 function format($text) {
266 return HTML::div(array('class' => 'wikitext'),
267 $this->_transform($text));
271 class PageFormatter_interwikimap extends PageFormatter
273 function format($text) {
274 return HTML::div(array('class' => 'wikitext'),
275 $this->_transform($this->_getHeader($text)),
277 $this->_transform($this->_getFooter($text)));
280 function _getHeader($text) {
281 return preg_replace('/<verbatim>.*/s', '', $text);
284 function _getFooter($text) {
285 return preg_replace('@.*?(</verbatim>|\Z)@s', '', $text, 1);
289 $map = PageType_interwikimap::getMap();
293 function _formatMap() {
294 $map = $this->_getMap();
296 return HTML::p("<No map found>"); // Shouldn't happen.
299 $dbi = $request->getDbh();
301 $mon_attr = array('class' => 'interwiki-moniker');
302 $url_attr = array('class' => 'interwiki-url');
304 $thead = HTML::thead(HTML::tr(HTML::th($mon_attr, _("Moniker")),
305 HTML::th($url_attr, _("InterWiki Address"))));
306 foreach ($map as $moniker => $interurl) {
307 $rows[] = HTML::tr(HTML::td($mon_attr, new Cached_WikiLinkIfKnown($moniker)),
308 HTML::td($url_attr, HTML::tt($interurl)));
311 return HTML::table(array('class' => 'interwiki-map'),
313 HTML::tbody(false, $rows));
317 class FakePageRevision {
318 function FakePageRevision($meta) {
319 $this->_meta = $meta;
323 if (empty($this->_meta[$key]))
325 return $this->_meta[$key];
330 class PageFormatter_wikiblog extends PageFormatter
332 // Display templated contents:
333 function format($text) {
334 include_once('lib/Template.php');
336 $tokens['CONTENT'] = $this->_transform($text);
337 $tokens['page'] = $this->_page;
338 $tokens['rev'] = new FakePageRevision($this->_meta);
340 $name = new WikiPageName($this->_page->getName());
341 $tokens['BLOG_PARENT'] = $name->getParent();
343 $blog_meta = $this->_meta['wikiblog'];
344 foreach(array('ctime', 'creator', 'creator_id') as $key)
345 $tokens["BLOG_" . strtoupper($key)] = $blog_meta[$key];
347 return new Template('wikiblog', $request, $tokens);
351 class PageFormatter_wikiforum extends PageFormatter
353 // Display templated contents:
354 function format($text) {
355 include_once('lib/Template.php');
357 $tokens['CONTENT'] = $this->_transform($text);
358 $tokens['page'] = $this->_page;
359 $tokens['rev'] = new FakePageRevision($this->_meta);
361 $name = new WikiPageName($this->_page->getName());
362 $tokens['FORUM_PARENT'] = $name->getParent();
364 $topic_meta = $this->_meta['wikiforum'];
365 foreach(array('ctime', 'creator', 'creator_id') as $key)
366 $tokens["FORUM_" . strtoupper($key)] = $topic_meta[$key];
368 return new Template('wikiforum', $request, $tokens);
372 class PageFormatter_pdf extends PageFormatter
375 function _transform($text) {
376 include_once('lib/BlockParser.php');
377 return TransformText($text, $this->_markup);
380 // one page or set of pages?
381 // here we format only a single page
382 function format($text) {
383 include_once('lib/Template.php');
385 $tokens['page'] = $this->_page;
386 $tokens['CONTENT'] = $this->_transform($text);
387 // this is a XmlElement tree, which must be converted to PDF
389 require_once('lib/fpdf.php');
392 //$pdf->SetFont('Arial','B',16);
393 //$pdf->Cell(40,10,'Hello World!');
395 //$tokens['rev'] = new FakePageRevision($this->_meta);
396 //$name = new WikiPageName($this->_page->getName());
397 //$tokens['PARENT'] = $name->getParent();
399 //TODO: define fonts, pagelayout
400 $template = new Template('pdf', $request, $tokens);
401 // catch $pdf->Output()
402 // Output([string name [, string dest]])
411 // c-hanging-comment-ender-p: nil
412 // indent-tabs-mode: nil