]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Template.php
Fix-up/restore <base href=""> usage.
[SourceForge/phpwiki.git] / lib / Template.php
1 <?php rcs_id('$Id: Template.php,v 1.22 2002-01-17 23:14:21 dairiki Exp $');
2
3 require_once("lib/ErrorManager.php");
4 require_once("lib/WikiPlugin.php");
5
6 //FIXME: This is a mess and needs to be refactored.
7 //  (In other words: this is all in a state of flux, so don't count on any
8 //   of this being the same tomorrow...)
9
10 class Template
11 {
12     function Template($tmpl) {
13         //$this->_tmpl = $this->_munge_input($tmpl);
14         $this->_tmpl = $tmpl;
15         $this->_vars = array();
16     }
17
18     function _munge_input($template) {
19         // Expand "< ?plugin-* ...? >"
20         preg_match_all('/<\?plugin.*?\?>/s', $template, $m);
21         global $dbi, $request;  // FIXME: no globals?
22         $pluginLoader = new WikiPluginLoader;
23         foreach (array_unique($m[0]) as $plugin_pi) {
24             $orig[] = '/' . preg_quote($plugin_pi, '/') . '/s';
25             // Plugin args like 'description=_("Get backlinks")' get
26             // gettexted.
27             // FIXME: move this to WikiPlugin.php.
28             $translated_pi = preg_replace('/(\s\w+=)_\("((?:[^"\\\\]|\\.)*)"\)/xse',
29                                           '"\1\"" . gettext("\2") . "\""',
30                                           $plugin_pi);
31             $repl[] = $pluginLoader->expandPI($translated_pi, $dbi, $request);
32         }
33
34         // Convert < ?= expr ? > to < ?php $this->_print(expr); ? >
35         $orig[] = '/<\?=(.*?)\?>/s';
36         $repl[] = '<?php $this->_print(\1);?>';
37         
38         // Convert tag attributes like foo=_("String") to foo="String" (with gettext mapping).
39         $orig[] = '/( < \w [^>]* \w=)_\("((?:[^"\\\\]|\\.)*)"\)/xse';
40         $repl[] = '"\1\"" . htmlspecialchars(gettext("\2")) . "\""';
41         
42         return preg_replace($orig, $repl, $template);
43
44         //$ret = preg_replace($orig, $repl, $template);
45         //echo QElement('pre', $ret);
46         //return $ret;
47     }
48
49     function _getReplacement($varname, $index = false) {
50         // FIXME: report missing vars.
51
52         echo "GET: $varname<br>\n";
53         
54         $vars = &$this->_vars;
55         if (!isset($vars[$varname]))
56             return false;
57
58         $value = $vars[$varname];
59         if ($index !== false)
60             @$value = $value[$index];
61
62         if (!is_string($value))
63             $value = $this->_toString($value);
64
65         // Quote '?' to avoid inadvertently inserting "<? php", "? >", or similar...
66         return str_replace('?', '&#63;', $value);
67     }
68     
69     function _print ($val) {
70         $string_val = '';
71
72         if (is_array($val)) {
73             $n = 0;
74             foreach ($val as $item) {
75                 if ($n++)
76                     echo "\n";
77                 $this->_print($item);
78             }
79         }
80         elseif (is_object($val)) {
81             if (isa($val, 'Template')) {
82                 // Expand sub-template with defaults from this template.
83                 $val->printExpansion($this->_vars);
84             }
85             elseif (method_exists($val, 'printhtml')) {
86                 $val->printHTML();
87             }
88             elseif (method_exists($val, 'ashtml')) {
89                 echo $val->asHTML();
90             }
91             elseif (method_exists($val, 'asstring')) {
92                 return htmlspecialchars($val->asString());
93             }
94         }
95         else {
96             echo (string) $val;
97         }
98     }
99     
100     /**
101      * Substitute HTML replacement text for tokens in template. 
102      *
103      * Constructs a new WikiTemplate based upon the named template.
104      *
105      * @access public
106      *
107      * @param $token string Name of token to substitute for.
108      *
109      * @param $replacement string Replacement HTML text.
110      */
111     function replace($varname, $value) {
112         $this->_vars[$varname] = $value;
113     }
114
115     /**
116      * Substitute text for tokens in template. 
117      *
118      * @access public
119      *
120      * @param $token string Name of token to substitute for.
121      *
122      * @param $replacement string Replacement text.
123      * The replacement text is run through htmlspecialchars()
124      * to escape any special characters.
125      */
126     function qreplace($varname, $value) {
127         $this->_vars[$varname] = htmlspecialchars($value);
128     }
129     
130
131     /**
132      * Include/remove conditional text in template.
133      *
134      * @access public
135      *
136      * @param $token string Conditional token name.
137      * The text within any matching if blocks (or single line ifs) will
138      * be included in the template expansion, while the text in matching
139      * negated if blocks will be excluded. 
140      */
141     /*
142     function setConditional($token, $value = true) {
143         $this->_iftoken[$token] = $value;
144     }
145     */
146     
147     function printExpansion ($defaults = false) {
148         $vars = &$this->_vars;
149         if ($defaults !== false) {
150             $save_vars = $vars;
151             if (!is_array($defaults)) {
152                 if (!isset($vars['CONTENT']))
153                     $vars['CONTENT'] = $defaults;
154             }
155             else {
156                 foreach ($defaults as $key => $val)
157                     if (!isset($vars[$key]))
158                         $vars[$key] = $val;
159             }
160         }
161         extract($vars);
162         
163         //$this->_dump_template();
164
165         global $ErrorManager;
166         $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
167
168         eval('?>' . $this->_munge_input($this->_tmpl));
169
170         $ErrorManager->popErrorHandler();
171
172         if (isset($save_vars))
173             $vars = $save_vars;
174     }
175
176     function getExpansion ($defaults = false) {
177         ob_start();
178         $this->printExpansion($defaults);
179         $html = ob_get_contents();
180         ob_end_clean();
181         return $html;
182     }
183
184     // Debugging:
185     function _dump_template () {
186         $lines = explode("\n", $this->_munge_input($this->_tmpl));
187         echo "<pre>\n";
188         $n = 1;
189         foreach ($lines as $line)
190             printf("%4d  %s\n", $n++, htmlspecialchars($line));
191         echo "</pre>\n";
192     }
193
194     function _errorHandler($error) {
195         if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
196             return false;
197
198         // Hack alert: Ignore 'undefined variable' messages for variables
199         //  whose names are ALL_CAPS.
200         if (preg_match('/Undefined variable:\s*[_A-Z]+\s*$/', $error->errstr))
201             return true;
202         
203         $error->errfile = "In template";
204         $lines = explode("\n", $this->_tmpl);
205         if (isset($lines[$error->errline - 1]))
206             $error->errstr .= ":\n\t" . $lines[$error->errline - 1];
207         return $error;
208     }
209 };
210
211 class TemplateFile
212 extends Template
213 {
214     function TemplateFile($filename) {
215         $this->_template_file = $filename;
216         $fp = fopen($filename, "rb");
217         $data = fread($fp, filesize($filename));
218         fclose($fp);
219         $this->Template($data);
220     }
221
222 }
223
224 class WikiTemplate
225 extends TemplateFile
226 {
227     /**
228      * Constructor.
229      *
230      * Constructs a new WikiTemplate based upon the named template.
231      *
232      * @access public
233      *
234      * @param $template string Which template.
235      */
236     function WikiTemplate($template, $page_revision = false) {
237         global $Theme;
238         $this->TemplateFile($Theme->findTemplate($template));
239         $this->_template_name = $template;
240         $this->setGlobalTokens();
241         if ($page_revision)
242             $this->setPageRevisionTokens($page_revision);
243     }
244
245     
246     function setPageTokens(&$page) {
247         /*
248         if ($page->get('locked'))
249             $this->setConditional('LOCK');
250         // HACK: note that EDITABLE may also be set in setWikiUserTokens.
251         if (!$page->get('locked'))
252             $this->setConditional('EDITABLE');
253         */
254         
255         $pagename = $page->getName();
256
257         $this->replace('page', $page);
258         $this->qreplace('PAGE', $pagename);
259         $this->qreplace('PAGEURL', rawurlencode($pagename));
260         $this->qreplace('SPLIT_PAGE', split_pagename($pagename));
261         $this->qreplace('BROWSE_PAGE', WikiURL($pagename));
262
263         // FIXME: this is a bit of dangerous hackage.
264         $this->qreplace('ACTION', WikiURL($pagename, array('action' => '')));
265
266         // FIXME:?
267         //$this->replace_callback('HITS', array($page, 'getHitCount'));
268         //$this->replace_callback('RELATEDPAGES', array($page, 'getHitCount'));
269         //_dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
270     }
271
272     function setPageRevisionTokens(&$revision) {
273         $page = & $revision->getPage();
274         
275         $current = & $page->getCurrentRevision();
276         $previous = & $page->getRevisionBefore($revision->getVersion());
277
278         $this->replace('IS_CURRENT',
279                        $current->getVersion() == $revision->getVersion());
280         
281         global $datetimeformat;
282         
283         //$this->qreplace('LASTMODIFIED',
284         //              strftime($datetimeformat, $revision->get('mtime')));
285
286         $this->qreplace('LASTAUTHOR', $revision->get('author'));
287         $this->qreplace('VERSION', $revision->getVersion());
288         $this->qreplace('CURRENT_VERSION', $current->getVersion());
289
290         $this->replace('revision', $revision);
291         
292         $this->setPageTokens($page);
293     }
294
295     function setWikiUserTokens(&$user) {
296         /*
297         if ( $user->is_admin() ) {
298             $this->setConditional('ADMIN');
299             $this->setConditional('EDITABLE');
300         }
301         if ( ! $user->is_authenticated() )
302             $this->setConditional('ANONYMOUS');
303         */
304         $this->replace('user', $user);
305         $this->qreplace('USERID', $user->id());
306
307         $prefs = $user->getPreferences();
308         $this->qreplace('EDIT_AREA_WIDTH', $prefs['edit_area.width']);
309         $this->qreplace('EDIT_AREA_HEIGHT', $prefs['edit_area.height']);
310     }
311
312     function setGlobalTokens () {
313         global $user, $RCS_IDS, $Theme;
314         
315         // FIXME: This a a bit of dangerous hackage.
316         $this->replace('Theme', $Theme);
317         $this->qreplace('BROWSE', WikiURL(''));
318         $this->qreplace('WIKI_NAME', WIKI_NAME);
319
320         if (isset($user))
321             $this->setWikiUserTokens($user);
322         if (isset($RCS_IDS))
323             $this->qreplace('RCS_IDS', $RCS_IDS);
324
325         require_once('lib/ButtonFactory.php');
326         $this->replace('ButtonFactory', new ButtonFactory);
327     }
328 };
329
330
331 /**
332  * Generate page contents using a template.
333  *
334  * This is a convenience function for backwards compatibility with the old
335  * GeneratePage().
336  *
337  * @param $template string name of the template (see config.php for list of names)
338  *
339  * @param $content string html content to put into the page
340  *
341  * @param $title string page title
342  *
343  * @param $page_revision object Current WikiDB_PageRevision, if available.
344  *
345  * @return string HTML expansion of template.
346  */
347 function GeneratePage($template, $content, $title, $page_revision = false) {
348     // require_once("lib/template.php");
349     // FIXME: More hackage.  Really GeneratePage should go away, at some point.
350     assert($template == 'MESSAGE');
351     $t = new WikiTemplate('top');
352     $t->qreplace('TITLE', $title);
353     $t->qreplace('HEADER', $title);
354     if ($page_revision)
355         $t->setPageRevisionTokens($page_revision);
356     $t->replace('CONTENT', $content);
357     return $t->getExpansion();
358 }
359
360 // Local Variables:
361 // mode: php
362 // tab-width: 8
363 // c-basic-offset: 4
364 // c-hanging-comment-ender-p: nil
365 // indent-tabs-mode: nil
366 // End:   
367 ?>