]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/PageType.php
generally more PHPDOC docs
[SourceForge/phpwiki.git] / lib / PageType.php
1 <?php // -*-php-*-
2 rcs_id('$Id: PageType.php,v 1.21 2004-02-28 21:14:08 rurban Exp $');
3 /*
4  Copyright 1999,2000,2001,2002,2003,2004 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
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.
12
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.
17
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
21  */
22
23 require_once('lib/CachedMarkup.php');
24
25 /** A cacheable formatted wiki page.
26  */
27 class TransformedText extends CacheableMarkup {
28     /** Constructor.
29      *
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.
35      */
36     function TransformedText($page, $text, $meta, $type_override=false) {
37         @$pagetype = $meta['pagetype'];
38         if ($type_override)
39             $pagetype = $type_override;
40         $this->_type = PageType::GetPageType($pagetype);
41         $this->CacheableMarkup($this->_type->transform($page, $text, $meta),
42                                $page->getName());
43     }
44
45     function getType() {
46         return $this->_type;
47     }
48 }
49
50 /**
51  * A page type descriptor.
52  *
53  * Encapsulate information about page types.
54  *
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 
59  * pure HTML.
60  *
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.)
64  */
65 class PageType {
66     /**
67      * Get a page type descriptor.
68      *
69      * This is a static member function.
70      *
71      * @param string $pagetype  Name of the page type.
72      * @return PageType  An object which is a subclass of PageType.
73      */
74     function GetPageType ($name=false) {
75         if (!$name)
76             $name = 'wikitext';
77         if ($name) {
78             $class = "PageType_" . (string)$name;
79             if (class_exists($class))
80                 return new $class;
81             trigger_error(sprintf("PageType '%s' unknown", (string)$name),
82                           E_USER_WARNING);
83         }
84         return new PageType_wikitext;
85     }
86
87     /**
88      * Get the name of this page type.
89      *
90      * @return string  Page type name.
91      */
92     function getName() {
93         if (!preg_match('/^PageType_(.+)$/i', get_class($this), $m))
94             trigger_error("Bad class name for formatter(?)", E_USER_ERROR);
95         return $m[1];
96     }
97
98     /**
99      * Transform page text.
100      *
101      * @param WikiDB_Page $page
102      * @param string $text
103      * @param hash $meta Version meta-data
104      * @return XmlContent The transformed page text.
105      */
106     function transform($page, $text, $meta) {
107         $fmt_class = 'PageFormatter_' . $this->getName();
108         $formatter = new $fmt_class($page, $meta);
109         return $formatter->format($text);
110     }
111 }
112
113 class PageType_wikitext extends PageType {}
114 class PageType_wikiblog extends PageType {}
115 class PageType_interwikimap extends PageType
116 {
117     function PageType_interwikimap() {
118         global $request;
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);
123
124         $this->_map = $this->_parseMap($intermap);
125         $this->_regexp = $this->_getRegexp();
126     }
127
128     function GetMap ($request = false) {
129         if (empty($this->_map)) {
130             $map = new PageType_interwikimap();
131             return $map;
132         } else {
133             return $this;
134         }
135     }
136
137     function getRegexp() {
138         return $this->_regexp;
139     }
140
141     function link ($link, $linktext = false) {
142
143         list ($moniker, $page) = split (":", $link, 2);
144         
145         if (!isset($this->_map[$moniker])) {
146             return HTML::span(array('class' => 'bad-interwiki'),
147                               $linktext ? $linktext : $link);
148         }
149
150         $url = $this->_map[$moniker];
151         
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;
155
156         if (strstr($url, '%s'))
157             $url = sprintf($url, $page_enc);
158         else
159             $url .= $page_enc;
160
161         $link = HTML::a(array('href' => $url));
162
163         if (!$linktext) {
164             $link->pushContent(PossiblyGlueIconToText('interwiki', "$moniker:"),
165                                HTML::span(array('class' => 'wikipage'), $page));
166             $link->setAttr('class', 'interwiki');
167         }
168         else {
169             $link->pushContent(PossiblyGlueIconToText('interwiki', $linktext));
170             $link->setAttr('class', 'named-interwiki');
171         }
172         
173         return $link;
174     }
175
176
177     function _parseMap ($text) {
178         global $AllowedProtocols;
179         if (!preg_match_all("/^\s*(\S+)\s+(\S+)/m",
180                             $text, $matches, PREG_SET_ORDER))
181             return false;
182         foreach ($matches as $m) {
183             $map[$m[1]] = $m[2];
184         }
185         if (empty($map['Upload']))
186             $map['Upload'] = SERVER_URL . ((substr(DATA_PATH,0,1)=='/') ? '' : "/") . DATA_PATH . '/uploads/';
187         return $map;
188     }
189
190     function _getMapFromWikiPage ($page) {
191         if (! $page->get('locked'))
192             return false;
193         
194         $current = $page->getCurrentRevision();
195         
196         if (preg_match('|^<verbatim>\n(.*)^</verbatim>|ms',
197                        $current->getPackedContent(), $m)) {
198             return $m[1];
199         }
200         return false;
201     }
202
203     // Fixme!
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 );
208         }
209         if (!file_exists($filename)) {
210             $finder = new FileFinder();
211             $filename = $finder->findFile(INTERWIKI_MAP_FILE);
212         }
213         @$fd = fopen ($filename, "rb");
214         @$data = fread ($fd, filesize($filename));
215         @fclose ($fd);
216
217         return $data;
218     }
219
220     function _getRegexp () {
221         if (!$this->_map)
222             return '(?:(?!a)a)'; //  Never matches.
223         
224         foreach (array_keys($this->_map) as $moniker)
225             $qkeys[] = preg_quote($moniker, '/');
226         return "(?:" . join("|", $qkeys) . ")";
227     }
228 }
229
230
231 /** How to transform text.
232  */
233 class PageFormatter {
234     /** Constructor.
235      *
236      * @param WikiDB_Page $page
237      * @param hash $meta Version meta-data.
238      */
239     function PageFormatter($page, $meta) {
240         $this->_page = $page;
241         $this->_meta = $meta;
242         if (!empty($meta['markup']))
243             $this->_markup = $meta['markup'];
244         else
245             $this->_markup = 1;
246     }
247
248     function _transform($text) {
249         include_once('lib/BlockParser.php');
250         return TransformText($text, $this->_markup);
251     }
252
253     /** Transform the page text.
254      *
255      * @param string $text  The raw page content (e.g. wiki-text).
256      * @return XmlContent   Transformed content.
257      */
258     function format($text) {
259         trigger_error("pure virtual", E_USER_ERROR);
260     }
261 }
262
263 class PageFormatter_wikitext extends PageFormatter 
264 {
265     function format($text) {
266         return HTML::div(array('class' => 'wikitext'),
267                          $this->_transform($text));
268     }
269 }
270
271 class PageFormatter_interwikimap extends PageFormatter
272 {
273     function format($text) {
274         return HTML::div(array('class' => 'wikitext'),
275                          $this->_transform($this->_getHeader($text)),
276                          $this->_formatMap(),
277                          $this->_transform($this->_getFooter($text)));
278     }
279
280     function _getHeader($text) {
281         return preg_replace('/<verbatim>.*/s', '', $text);
282     }
283
284     function _getFooter($text) {
285         return preg_replace('@.*?(</verbatim>|\Z)@s', '', $text, 1);
286     }
287     
288     function _getMap() {
289         $map = PageType_interwikimap::getMap();
290         return $map->_map;
291     }
292     
293     function _formatMap() {
294         $map = $this->_getMap();
295         if (!$map)
296             return HTML::p("<No map found>"); // Shouldn't happen.
297
298         global $request;
299         $dbi = $request->getDbh();
300
301         $mon_attr = array('class' => 'interwiki-moniker');
302         $url_attr = array('class' => 'interwiki-url');
303         
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)));
309         }
310         
311         return HTML::table(array('class' => 'interwiki-map'),
312                            $thead,
313                            HTML::tbody(false, $rows));
314     }
315 }
316
317 class FakePageRevision {
318     function FakePageRevision($meta) {
319         $this->_meta = $meta;
320     }
321
322     function get($key) {
323         if (empty($this->_meta[$key]))
324             return false;
325         return $this->_meta[$key];
326     }
327 }
328
329         
330 class PageFormatter_wikiblog extends PageFormatter
331 {
332     // Display templated contents:
333     function format($text) {
334         include_once('lib/Template.php');
335         global $request;
336         $tokens['CONTENT'] = $this->_transform($text);
337         $tokens['page'] = $this->_page;
338         $tokens['rev'] = new FakePageRevision($this->_meta);
339
340         $name = new WikiPageName($this->_page->getName());
341         $tokens['BLOG_PARENT'] = $name->getParent();
342
343         $blog_meta = $this->_meta['wikiblog'];
344         foreach(array('ctime', 'creator', 'creator_id') as $key)
345             $tokens["BLOG_" . strtoupper($key)] = $blog_meta[$key];
346         
347         return new Template('wikiblog', $request, $tokens);
348     }
349 }
350
351 class PageFormatter_wikiforum extends PageFormatter
352 {
353     // Display templated contents:
354     function format($text) {
355         include_once('lib/Template.php');
356         global $request;
357         $tokens['CONTENT'] = $this->_transform($text);
358         $tokens['page'] = $this->_page;
359         $tokens['rev'] = new FakePageRevision($this->_meta);
360
361         $name = new WikiPageName($this->_page->getName());
362         $tokens['FORUM_PARENT'] = $name->getParent();
363
364         $topic_meta = $this->_meta['wikiforum'];
365         foreach(array('ctime', 'creator', 'creator_id') as $key)
366             $tokens["FORUM_" . strtoupper($key)] = $topic_meta[$key];
367
368         return new Template('wikiforum', $request, $tokens);
369     }
370 }
371
372 class PageFormatter_pdf extends PageFormatter
373 {
374
375     function _transform($text) {
376         include_once('lib/BlockParser.php');
377         return TransformText($text, $this->_markup);
378     }
379
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');
384         global $request;
385         $tokens['page'] = $this->_page;
386         $tokens['CONTENT'] = $this->_transform($text);
387         // this is a XmlElement tree, which must be converted to PDF
388
389         require_once('lib/fpdf.php');
390         $pdf = new FPDF();
391         $pdf->AddPage();
392         //$pdf->SetFont('Arial','B',16);
393         //$pdf->Cell(40,10,'Hello World!');
394         //$pdf->Output();
395         //$tokens['rev'] = new FakePageRevision($this->_meta);
396         //$name = new WikiPageName($this->_page->getName());
397         //$tokens['PARENT'] = $name->getParent();
398
399         //TODO: define fonts, pagelayout
400         $template = new Template('pdf', $request, $tokens);
401         // catch $pdf->Output()
402         // Output([string name [, string dest]])
403         return $pdf;
404     }
405 }
406
407 // Local Variables:
408 // mode: php
409 // tab-width: 8
410 // c-basic-offset: 4
411 // c-hanging-comment-ender-p: nil
412 // indent-tabs-mode: nil
413 // End:
414 ?>