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