]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/CachedMarkup.php
Remove gzcompress because of single quote bug
[SourceForge/phpwiki.git] / lib / CachedMarkup.php
1 <?php 
2 rcs_id('$Id$');
3 /* Copyright (C) 2002 Geoffrey T. Dairiki <dairiki@dairiki.org>
4  * Copyright (C) 2004-2008 $ThePhpWikiProgrammingTeam
5  * Copyright (C) 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  * 
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with PhpWiki; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 require_once("lib/Units.php");
25
26 class CacheableMarkup extends XmlContent {
27
28     function CacheableMarkup($content, $basepage) {
29         $this->_basepage = $basepage;
30         $this->_buf = '';
31         $this->_content = array();
32         $this->_append($content);
33         if ($this->_buf != '')
34             $this->_content[] = $this->_buf;
35         unset($this->_buf);
36     }
37
38     function pack() {
39         // This causes a strange bug when a comment containing
40         // a single quote is entered in the Summary box:
41         // - the history is wrong (user and comment missing)
42         // - the table of contents plugin no longer works
43         // if (function_exists('gzcompress'))
44         //     return gzcompress(serialize($this), 9);
45         return serialize($this);
46
47         // FIXME: probably should implement some sort of "compression"
48         //   when no gzcompress is available.
49     }
50
51     function unpack($packed) {
52         if (!$packed)
53             return false;
54
55         // ZLIB format has a five bit checksum in it's header.
56         // Lets check for sanity.
57         if (((ord($packed[0]) * 256 + ord($packed[1])) % 31 == 0)
58              and (substr($packed,0,2) == "\037\213") 
59                   or (substr($packed,0,2) == "x\332"))   // 120, 218
60         {
61             if (function_exists('gzuncompress')) {
62                 // Looks like ZLIB.
63                 $data = gzuncompress($packed);
64                 return unserialize($data);
65             } else {
66                 // user our php lib. TESTME
67                 include_once("ziplib.php");
68                 $zip = new ZipReader($packed);
69                 list(,$data,$attrib) = $zip->readFile();
70                 return unserialize($data);
71             }
72         }
73         if (substr($packed,0,2) == "O:") {
74             // Looks like a serialized object
75             return unserialize($packed);
76         }
77         if (preg_match("/^\w+$/", $packed))
78             return $packed;
79         // happened with _BackendInfo problem also.
80         trigger_error("Can't unpack bad cached markup. Probably php_zlib extension not loaded.", 
81                       E_USER_WARNING);
82         return false;
83     }
84     
85     /** Get names of wikipages linked to.
86      *
87      * @return array of hashes { linkto=>pagename, relation=>pagename }
88      */
89     function getWikiPageLinks() {
90         $links = array();
91         foreach ($this->_content as $item) {
92             if (!isa($item, 'Cached_DynamicContent'))
93                 continue;
94             if (!($item_links = $item->getWikiPageLinks($this->_basepage)))
95                 continue;
96             $links = array_merge($links, $item_links);
97         }
98         // array_unique has a bug with hashes! 
99         // set_links checks for duplicates, array_merge does not
100         //return array_unique($links);
101         return $links;
102     }
103
104     /** Get link info.
105      *
106      * This is here to support the XML-RPC listLinks() method.
107      *
108      * @return array
109      * Returns an array of hashes.
110      */
111     function getLinkInfo() {
112         $link = array();
113         foreach ($this->_content as $link) {
114             if (! isa($link, 'Cached_Link'))
115                 continue;
116             $info = $link->getLinkInfo($this->_basepage);
117             $links[$info->href] = $info;
118         }
119         return array_values($links);
120     }
121
122     function _append($item) {
123         if (is_array($item)) {
124             foreach ($item as $subitem)
125                 $this->_append($subitem);
126         }
127         elseif (!is_object($item)) {
128             $this->_buf .= $this->_quote((string) $item);
129         }
130         elseif (isa($item, 'Cached_DynamicContent')) {
131             if ($this->_buf) {
132                 $this->_content[] = $this->_buf;
133                 $this->_buf = '';
134             }
135             $this->_content[] = $item;
136         }
137         elseif (isa($item, 'XmlElement')) {
138             if ($item->isEmpty()) {
139                 $this->_buf .= $item->emptyTag();
140             }
141             else {
142                 $this->_buf .= $item->startTag();
143                 foreach ($item->getContent() as $subitem)
144                     $this->_append($subitem);
145                 $this->_buf .= "</$item->_tag>";
146
147                 if (!$this->getDescription() and $item->getTag() == 'p') {
148                     // performance: when is this really needed?
149                     $this->_glean_description($item->asString());
150                 }
151             }
152             if (!$item->isInlineElement())
153                 $this->_buf .= "\n";
154         }
155         elseif (isa($item, 'XmlContent')) {
156             foreach ($item->getContent() as $item)
157                 $this->_append($item);
158         }
159         elseif (method_exists($item, 'asXML')) {
160             $this->_buf .= $item->asXML();
161         }
162         elseif (method_exists($item, 'asString')) {
163             $this->_buf .= $this->_quote($item->asString());
164         }
165         else {
166             $this->_buf .= sprintf("==Object(%s)==", get_class($item));
167         }
168     }
169
170     function _glean_description($text) {
171         static $two_sentences;
172         if (!$two_sentences) {
173             $two_sentences = pcre_fix_posix_classes("[.?!][\")]*\s+[\"(]*[[:upper:])]"
174                                                     . ".*"
175                                                     . "[.?!][\")]*\s*[\"(]*([[:upper:])]|$)");
176         }
177         
178         if (!isset($this->_description) and preg_match("/$two_sentences/sx", $text))
179             $this->_description = preg_replace("/\s*\n\s*/", " ", trim($text));
180     }
181
182     /**
183      * Guess a short description of the page.
184      *
185      * Algorithm:
186      *
187      * This algorithm was suggested on MeatballWiki by
188      * Alex Schroeder <kensanata@yahoo.com>.
189      *
190      * Use the first paragraph in the page which contains at least two
191      * sentences.
192      *
193      * @see http://www.usemod.com/cgi-bin/mb.pl?MeatballWikiSuggestions
194      *
195      * @return string
196      */
197     function getDescription () {
198         return isset($this->_description) ? $this->_description : '';
199     }
200     
201     function asXML () {
202         $xml = '';
203         $basepage = $this->_basepage;
204         
205         foreach ($this->_content as $item) {
206             if (is_string($item)) {
207                 $xml .= $item;
208             }
209             elseif (is_subclass_of($item, 
210                                    check_php_version(5) 
211                                      ? 'Cached_DynamicContent' 
212                                      : 'cached_dynamiccontent'))
213             {
214                 $val = $item->expand($basepage, $this);
215                 $xml .= $val->asXML();
216             }
217             else {
218                 $xml .= $item->asXML();
219             }
220         }
221         return $xml;
222     }
223
224     function printXML () {
225         $basepage = $this->_basepage;
226         // _content might be changed from a plugin (CreateToc)
227         for ($i=0; $i < count($this->_content); $i++) {
228             $item = $this->_content[$i];
229             if (is_string($item)) {
230                 print $item;
231             }
232             elseif (is_subclass_of($item, 
233                                    check_php_version(5) 
234                                      ? 'Cached_DynamicContent' 
235                                      : 'cached_dynamiccontent')) 
236             {   // give the content the chance to know about itself or even 
237                 // to change itself
238                 $val = $item->expand($basepage, $this);
239                 $val->printXML();
240             }
241             else {
242                 $item->printXML();
243             }
244         }
245     }
246 }       
247
248 /**
249  * The base class for all dynamic content.
250  *
251  * Dynamic content is anything that can change even when the original
252  * wiki-text from which it was parsed is unchanged.
253  */
254 class Cached_DynamicContent {
255
256     function cache(&$cache) {
257         $cache[] = $this;
258     }
259
260     function expand($basepage, &$obj) {
261         trigger_error("Pure virtual", E_USER_ERROR);
262     }
263
264     function getWikiPageLinks($basepage) {
265         return false;
266     }
267 }
268
269 class XmlRpc_LinkInfo {
270     function XmlRpc_LinkInfo($page, $type, $href, $relation = '') {
271         $this->page = $page;
272         $this->type = $type;
273         $this->href = $href;
274         $this->relation = $relation;
275         //$this->pageref = str_replace("/RPC2.php", "/index.php", $href);
276     }
277 }
278
279 class Cached_Link extends Cached_DynamicContent {
280
281     function isInlineElement() {
282         return true;
283     }
284
285     /** Get link info (for XML-RPC support)
286      *
287      * This is here to support the XML-RPC listLinks method.
288      * (See http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=WikiRPCInterface)
289      */
290     function getLinkInfo($basepage) {
291         return new XmlRpc_LinkInfo($this->_getName($basepage),
292                                    $this->_getType(),
293                                    $this->_getURL($basepage),
294                                    $this->_getRelation($basepage));
295     }
296     
297     function _getURL($basepage) {
298         return $this->_url;
299     }
300     function __getRelation($basepage) {
301         return $this->_relation;
302     }
303 }
304 /*
305  * Defer interwiki inline links. img src=upload:xx.png
306  * LinkImage($url, $alt = false)
307  */
308 class Cached_InlinedImage extends Cached_DynamicContent {
309     function isInlineElement() {
310         return true;
311     }
312     function _getURL($basepage) {
313         return $this->_url;
314     }
315     // TODO: fix interwiki inline links in case of static dumps
316     function expand($basepage, &$markup) {
317         global $WikiTheme;
318         $this->_basepage = $basepage;
319         $label = isset($this->_label) ? $this->_label : false;
320         if ($WikiTheme->DUMP_MODE) {
321             // In case of static dumps we need to check if we should
322             // inline the image or not: external: keep link, internal: copy locally
323             return LinkImage($label);
324         } else {
325             return LinkImage($label);
326         }
327     }
328 }
329
330 class Cached_WikiLink extends Cached_Link {
331
332     function Cached_WikiLink ($page, $label = false, $anchor = false) {
333         $this->_page = $page;
334         /* ":DontStoreLink" */
335         if (substr($this->_page,0,1) == ':') {
336             $this->_page = substr($this->_page,1);
337             $this->_nolink = true;
338         }    
339         if ($anchor)
340             $this->_anchor = $anchor;
341         if ($label and $label != $page)
342             $this->_label = $label;
343         $this->_basepage = false;    
344     }
345
346     function _getType() {
347         return 'internal';
348     }
349     
350     function getPagename($basepage) {
351         $page = new WikiPageName($this->_page, $basepage);
352         if ($page->isValid()) return $page->name;
353         else return false;
354     }
355
356     function getWikiPageLinks($basepage) {
357         if ($basepage == '') return false;
358         if (isset($this->_nolink)) return false;
359         if ($link = $this->getPagename($basepage)) 
360             return array(array('linkto' => $link, 'relation' => 0));
361         else 
362             return false;
363     }
364
365     function _getName($basepage) {
366         return $this->getPagename($basepage);
367     }
368
369     function _getURL($basepage) {
370         return WikiURL($this->getPagename($basepage));
371         //return WikiURL($this->getPagename($basepage), false, 'abs_url');
372     }
373
374     function expand($basepage, &$markup) {
375         global $WikiTheme;
376         $this->_basepage = $basepage;
377         $label = isset($this->_label) ? $this->_label : false;
378         $anchor = isset($this->_anchor) ? (string)$this->_anchor : '';
379         $page = new WikiPageName($this->_page, $basepage, $anchor);
380         if ($WikiTheme->DUMP_MODE and !empty($WikiTheme->VALID_LINKS)) {
381             if (!in_array($this->_page, $WikiTheme->VALID_LINKS))
382                 return HTML($label ? $label : $page->getName());
383         }
384         if ($page->isValid()) return WikiLink($page, 'auto', $label);
385         else return HTML($label);
386     }
387
388     function asXML() {
389         global $WikiTheme;
390         $label = isset($this->_label) ? $this->_label : false;
391         $anchor = isset($this->_anchor) ? (string)$this->_anchor : '';
392         //TODO: need basepage for subpages like /Remove (within CreateTOC)
393         $page = new WikiPageName($this->_page, $this->_basepage, $anchor);
394         if ($WikiTheme->DUMP_MODE and $WikiTheme->VALID_LINKS) {
395             if (!in_array($this->_page, $WikiTheme->VALID_LINKS))
396                 return $label ? $label : $page->getName();
397         }
398         $link = WikiLink($page, 'auto', $label);
399         return $link->asXML();
400     }
401
402     function asString() {
403         if (isset($this->_label))
404             return $this->_label;
405         return $this->_page;
406     }
407 }
408
409 class Cached_WikiLinkIfKnown extends Cached_WikiLink
410 {
411     function Cached_WikiLinkIfKnown ($moniker) {
412         $this->_page = $moniker;
413     }
414
415     function expand($basepage, &$markup) {
416         global $WikiTheme;
417         if ($WikiTheme->DUMP_MODE and $WikiTheme->VALID_LINKS) {
418             if (!in_array($this->_page, $WikiTheme->VALID_LINKS))
419                 return HTML($label ? $label : $page->getName());
420         }
421         return WikiLink($this->_page, 'if_known');
422     }
423 }    
424
425 class Cached_SpellCheck extends Cached_WikiLink
426 {
427     function Cached_SpellCheck ($word, $suggs) {
428         $this->_page = $word;
429         $this->suggestions = $suggs;
430     }
431
432     function expand($basepage, &$markup) {
433         $link = HTML::a(array('class' => 'spell-wrong', 
434                               'title' => 'SpellCheck: '.join(', ', $this->suggestions),
435                               'name' => $this->_page), 
436                         $this->_page);
437         return $link;
438     }
439 }    
440     
441 class Cached_PhpwikiURL extends Cached_DynamicContent
442 {
443     function Cached_PhpwikiURL ($url, $label) {
444         $this->_url = $url;
445         if ($label)
446             $this->_label = $label;
447     }
448
449     function isInlineElement() {
450         return true;
451     }
452
453     function expand($basepage, &$markup) {
454         global $WikiTheme;
455         $label = isset($this->_label) ? $this->_label : false;
456         if ($WikiTheme->DUMP_MODE and $WikiTheme->VALID_LINKS) {
457             if (!in_array($this->_page, $WikiTheme->VALID_LINKS))
458                 return HTML($label ? $label : $page->getName());
459         }
460         return LinkPhpwikiURL($this->_url, $label, $basepage);
461     }
462
463     function asXML() {
464         $label = isset($this->_label) ? $this->_label : false;
465         $link = LinkPhpwikiURL($this->_url, $label);
466         return $link->asXML();
467     }
468
469     function asString() {
470         if (isset($this->_label))
471             return $this->_label;
472         return $this->_url;
473     }
474 }    
475
476 /*
477  * Relations (::) are named links to pages.
478  * Attributes (:=) are named metadata per page, "named links to numbers with units". 
479  * We don't want to exhaust the linktable with numbers,
480  * since this would create empty pages per each value, 
481  * so we don't store the attributes as full relationlink. 
482  * But we do store the attribute name as relation with an empty pagename 
483  * to denote that this is an attribute, 
484  * and to enable a fast listRelations mode=attributes
485  */
486 class Cached_SemanticLink extends Cached_WikiLink {
487
488     function Cached_SemanticLink ($url, $label=false) {
489         $this->_url = $url;
490         if ($label && $label != $url)
491             $this->_label = $label;
492         $this->_expandurl($this->_url);
493     }
494
495     function isInlineElement() {
496         return true;
497     }
498
499     function getPagename($basepage) {
500         if (!isset($this->_page)) return false;
501         $page = new WikiPageName($this->_page, $basepage);
502         if ($page->isValid()) return $page->name;
503         else return false;
504     }
505
506     /* Add relation to the link table.
507      * attributes have the _relation, but not the _page set.
508      */
509     function getWikiPageLinks($basepage) {
510         if ($basepage == '') return false;
511         if (!isset($this->_page) and isset($this->_attribute)) {
512             // An attribute: we store it in the basepage now, to fill the cache for page->save
513             // TODO: side-effect free query
514             $page = $GLOBALS['request']->getPage($basepage); 
515             $page->setAttribute($this->_relation, $this->_attribute);
516             $this->_page = $basepage;
517             return array(array('linkto' => '', 'relation' => $this->_relation));
518         }
519         if ($link = $this->getPagename($basepage)) 
520             return array(array('linkto' => $link, 'relation' => $this->_relation));
521         else
522             return false;
523     }
524
525     function _expandurl($url) {
526         $m = array();
527         if (!preg_match('/^ ([^:]+) (:[:=]) (.+) $/x', $url, $m)) {
528             return HTML::strong(array('class' => 'rawurl'),
529                                 HTML::u(array('class' => 'baduri'),
530                                         _("BAD semantic relation link")));
531         }
532         $this->_relation = urldecode($m[1]);
533         $is_attribute = ($m[2] == ':=');
534         if ($is_attribute) {
535             $this->_attribute = urldecode($m[3]);
536             // since this stored in the markup cache, we are extra sensible 
537             // not to store false empty stuff.
538             $units = new Units();
539             if (!DISABLE_UNITS and !$units->errcode) 
540             {
541                 $this->_attribute_base = $units->Definition($this->_attribute);
542                 $this->_unit = $units->baseunit($this->_attribute);
543             }
544         } else {
545             $this->_page = urldecode($m[3]);
546         }
547         return $m;
548     }
549
550     function _expand($url, $label = false) {
551         global $WikiTheme;
552         $m = $this->_expandurl($url);
553         $class = 'wiki';
554         // do not link to the attribute value, but to the attribute
555         $is_attribute = ($m[2] == ':=');
556         if ($WikiTheme->DUMP_MODE and $WikiTheme->VALID_LINKS) {
557             if (isset($this->_page) and !in_array($this->_page, $WikiTheme->VALID_LINKS))
558                 return HTML($label ? $label : ($is_attribute ? $this->_relation : $this->_page));
559         }
560         if ($is_attribute)
561             $title = isset($this->_attribute_base)
562                 ? sprintf(_("Attribute %s, base value: %s"), $this->_relation, $this->_attribute_base)
563                 : sprintf(_("Attribute %s, value: %s"), $this->_relation, $this->_attribute);
564         if ($label) {
565             return HTML::span
566                 (
567                  HTML::a(array('href'  => WikiURL($is_attribute ? $this->_relation : $this->_page),
568                                'class' => "wiki ".($is_attribute ? "attribute" : "relation"),
569                                'title' => $is_attribute 
570                                ? $title 
571                                : sprintf(_("Relation %s to page %s"), $this->_relation, $this->_page)),
572                          $label)
573                  );
574         } elseif ($is_attribute) {
575             return HTML::span
576                 (
577                  HTML::a(array('href'  => WikiURL($this->_relation),
578                                'class' => "wiki attribute",
579                                'title' => $title),
580                          $url)
581                  );
582         } else {
583             return HTML::span
584                 (
585                  HTML::a(array('href'  => WikiURL($this->_relation),
586                                'class' => "wiki relation"),
587                          $this->_relation),
588                  HTML::span(array('class'=>'relation-symbol'), $m[2]),
589                  HTML::a(array('href'  => WikiURL($this->_page),
590                                'class' => "wiki"),
591                          $this->_page)
592                  );
593         }
594     }
595
596     function expand($basepage, &$markup) {
597         $label = isset($this->_label) ? $this->_label : false;
598         return $this->_expand($this->_url, $label);
599     }
600
601     function asXML() {
602         $label = isset($this->_label) ? $this->_label : false;
603         $link = $this->_expand($this->_url, $label);
604         return $link->asXML();
605     }
606
607     function asString() {
608         if (isset($this->_label))
609             return $this->_label;
610         return $this->_url;
611     }
612 }
613
614 /** 
615  * Highlight found search engine terms
616  */
617 class Cached_SearchHighlight extends Cached_DynamicContent
618 {
619     function Cached_SearchHighlight ($word, $engine) {
620         $this->_word = $word;
621         $this->engine = $engine;
622     }
623
624     function expand($basepage, &$markup) {
625         return HTML::span(array('class' => 'search-term',
626                                 'title' => _("Found by ") . $this->engine),
627                           $this->_word);
628     }
629 }    
630     
631 class Cached_ExternalLink extends Cached_Link {
632
633     function Cached_ExternalLink($url, $label=false) {
634         $this->_url = $url;
635         if ($label && $label != $url)
636             $this->_label = $label;
637     }
638
639     function _getType() {
640         return 'external';
641     }
642     
643     function _getName($basepage) {
644         $label = isset($this->_label) ? $this->_label : false;
645         return ($label and is_string($label)) ? $label : $this->_url;
646     }
647
648     function expand($basepage, &$markup) {
649         global $request;
650
651         $label = isset($this->_label) ? $this->_label : false;
652         $link = LinkURL($this->_url, $label);
653
654         if (GOOGLE_LINKS_NOFOLLOW) {
655             // Ignores nofollow when the user who saved the page was authenticated. 
656             $page = $request->getPage($basepage);
657             $current = $page->getCurrentRevision(false);
658             if (!$current->get('author_id'))
659                 $link->setAttr('rel', 'nofollow');
660         }
661         return $link;
662     }
663
664     function asString() {
665         if (isset($this->_label) and is_string($this->_label))
666             return $this->_label;
667         return $this->_url;
668     }
669 }
670
671 class Cached_InterwikiLink extends Cached_ExternalLink {
672     
673     function Cached_InterwikiLink($link, $label=false) {
674         $this->_link = $link;
675         if ($label)
676             $this->_label = $label;
677     }
678
679     function getPagename($basepage) {
680         list ($moniker, $page) = split (":", $this->_link, 2);
681         $page = new WikiPageName($page, $basepage);
682         if ($page->isValid()) return $page->name;
683         else return false;
684     }
685
686     function getWikiPageLinks($basepage) {
687         if ($basepage == '') return false;
688         /* ":DontStoreLink" */
689         if (substr($this->_link,0,1) == ':') return false;
690         /* store only links to valid pagenames */
691         if ($link = $this->getPagename($basepage)) 
692             return array(array('linkto' => $link, 'relation' => 0));
693         else return false; // dont store external links
694     }
695
696     function _getName($basepage) {
697         $label = isset($this->_label) ? $this->_label : false;
698         return ($label and is_string($label)) ? $label : $this->_link;
699     }
700     
701     /* there may be internal interwiki links also */
702     function _getType() {
703         return $this->getPagename(false) ? 'internal' : 'external';
704     }
705
706     function _getURL($basepage) {
707         $link = $this->expand($basepage, $this);
708         return $link->getAttr('href');
709     }
710
711     function expand($basepage, &$markup) {
712         global $WikiTheme;
713         $intermap = getInterwikiMap();
714         $label = isset($this->_label) ? $this->_label : false;
715         //FIXME: check Upload: inlined images
716         if ($WikiTheme->DUMP_MODE and !empty($WikiTheme->VALID_LINKS)) {
717             if (!in_array($this->_link, $WikiTheme->VALID_LINKS))
718                 return HTML($label ? $label : $this->_link);
719         }
720         return $intermap->link($this->_link, $label);
721     }
722
723     function asString() {
724         if (isset($this->_label))
725             return $this->_label;
726         return $this->_link;
727     }
728 }
729
730 // Needed to put UserPages to backlinks. Special method to markup userpages with icons
731 // Thanks to PhpWiki:DanFr for finding this bug. 
732 // Fixed since 1.3.8, prev. versions had no userpages in backlinks
733 class Cached_UserLink extends Cached_WikiLink {
734     function expand($basepage, &$markup) {
735         $label = isset($this->_label) ? $this->_label : false;
736         $anchor = isset($this->_anchor) ? (string)$this->_anchor : '';
737         $page = new WikiPageName($this->_page, $basepage, $anchor);
738         $link = WikiLink($page, 'auto', $label);
739         // $link = HTML::a(array('href' => $PageName));
740         $link->setContent(PossiblyGlueIconToText('wikiuser', $this->_page));
741         $link->setAttr('class', 'wikiuser');
742         return $link;
743     }
744 }
745
746 /**
747  * 1.3.13: Previously stored was only _pi. 
748  * A fresh generated cache has now ->name and ->args also.
749  * main::isActionPage only checks the raw content.
750  */
751 class Cached_PluginInvocation extends Cached_DynamicContent {
752
753     function Cached_PluginInvocation ($pi) {
754         $this->_pi = $pi;
755         $loader = $this->_getLoader();
756         if (is_array($plugin_cmdline = $loader->parsePI($pi)) and $plugin_cmdline[1]) {
757             $this->pi_name = $plugin_cmdline[0]; // plugin, plugin-form, plugin-list, plugin-link
758             $this->name = $plugin_cmdline[1]->getName();
759             $this->args = $plugin_cmdline[2];
760         }
761     }
762
763     function isInlineElement() {
764         return false;
765     }
766
767     function expand($basepage, &$markup) {
768         $loader = $this->_getLoader();
769         $xml = $loader->expandPI($this->_pi, $GLOBALS['request'], $markup, $basepage);
770         return $xml;
771     }
772
773     function asString() {
774         return $this->_pi;
775     }
776
777     function getWikiPageLinks($basepage) {
778         $loader = $this->_getLoader();
779
780         return $loader->getWikiPageLinks($this->_pi, $basepage);
781     }
782
783     function & _getLoader() {
784         static $loader = false;
785
786         if (!$loader) {
787             include_once('lib/WikiPlugin.php');
788             $loader = new WikiPluginLoader;
789         }
790         return $loader;
791     }
792 }
793
794 // (c-file-style: "gnu")
795 // Local Variables:
796 // mode: php
797 // tab-width: 8
798 // c-basic-offset: 4
799 // c-hanging-comment-ender-p: nil
800 // indent-tabs-mode: nil
801 // End:   
802 ?>