]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Template.php
Language independent templates.
[SourceForge/phpwiki.git] / lib / Template.php
1 <?php rcs_id('$Id: Template.php,v 1.4 2001-11-29 02:59: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 ${VAR} to < ?php echo "$VAR"; ? >
35         //$orig[] = '/\${(\w[\w\d]*)}/';
36         //$repl[] = '<?php echo "$\1"; ? >';
37         $orig[] = '/\${(\w[\w\d]*)}/e';
38         $repl[] = '$this->_getReplacement("\1")';
39
40         // Convert $VAR[ind] to < ?php echo "$VAR[ind]"; ? >
41         $orig[] = '/\$(\w[\w\d]*)\[([\w\d]+)\]/e';
42         $repl[] = '$this->_getReplacement("\1", "\2")';
43
44         // Convert $_("String") to < ?php echo htmlspecialchars(gettext("String")); ? >
45         $orig[] = '/\$_\(("(?:[^"\\\\]|\\.)*")\)/xs';
46         $repl[] = "<?php echo htmlspecialchars(gettext(\\1)); ?>";
47         
48         // Convert tag attributes like foo=_("String") to foo="String" (with gettext mapping).
49         $orig[] = '/( < \w [^>]* \w=)_\("((?:[^"\\\\]|\\.)*)"\)/xse';
50         $repl[] = '"\1\"" . htmlspecialchars(gettext("\2")) . "\""';
51         
52         return preg_replace($orig, $repl, $template);
53
54         $ret = preg_replace($orig, $repl, $template);
55         echo QElement('pre', $ret);
56         return $ret;
57         
58
59     }
60
61     function _getReplacement($varname, $index = false) {
62         // FIXME: report missing vars.
63         $vars = &$this->_vars;
64         if (isset($vars[$varname])) {
65             $value = $vars[$varname];
66             if ($index !== false)
67                 @$value = (string) $value[$index];
68             return str_replace('?', '&#63;', $value);
69         }
70         return false;
71     }
72     
73     /**
74      * Substitute HTML replacement text for tokens in template. 
75      *
76      * Constructs a new WikiTemplate based upon the named template.
77      *
78      * @access public
79      *
80      * @param $token string Name of token to substitute for.
81      *
82      * @param $replacement string Replacement HTML text.
83      */
84     function replace($varname, $value) {
85         $this->_vars[$varname] = $value;
86     }
87
88     /**
89      * Substitute text for tokens in template. 
90      *
91      * @access public
92      *
93      * @param $token string Name of token to substitute for.
94      *
95      * @param $replacement string Replacement text.
96      * The replacement text is run through htmlspecialchars()
97      * to escape any special characters.
98      */
99     function qreplace($varname, $value) {
100         $this->_vars[$varname] = htmlspecialchars($value);
101     }
102     
103
104     /**
105      * Include/remove conditional text in template.
106      *
107      * @access public
108      *
109      * @param $token string Conditional token name.
110      * The text within any matching if blocks (or single line ifs) will
111      * be included in the template expansion, while the text in matching
112      * negated if blocks will be excluded. 
113      */
114     /*
115     function setConditional($token, $value = true) {
116         $this->_iftoken[$token] = $value;
117     }
118     */
119     
120     function getExpansion($varhash = false) {
121         $savevars = $this->_vars;
122         if (is_array($varhash)) {
123             foreach ($varhash as $key => $val)
124                 $this->_vars[$key] = $val;
125         }
126         extract($this->_vars);
127         if (isset($this->_iftoken))
128             $_iftoken = $this->_iftoken;
129         
130         ob_start();
131
132         //$this->_dump_template();
133
134         global $ErrorManager;
135         $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
136         eval('?>' . $this->_munge_input($this->_tmpl));
137         $ErrorManager->popErrorHandler();
138
139         $html = ob_get_contents();
140         ob_end_clean();
141
142         return $html;
143     }
144
145     function printExpansion($args = false) {
146         echo $this->getExpansion($args);
147     }
148
149     // Debugging:
150     function _dump_template () {
151         $lines = explode("\n", $this->_munge_input($this->_tmpl));
152         echo "<pre>\n";
153         $n = 1;
154         foreach ($lines as $line)
155             printf("%4d  %s\n", $n++, htmlspecialchars($line));
156         echo "</pre>\n";
157     }
158
159     function _errorHandler($error) {
160         if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
161             return false;
162         $error->errfile = "In template";
163         $lines = explode("\n", $this->_tmpl);
164         if (isset($lines[$error->errline - 1]))
165             $error->errstr .= ":\n\t" . $lines[$error->errline - 1];
166         return $error;
167     }
168 };
169
170 class TemplateFile
171 extends Template
172 {
173     function TemplateFile($filename) {
174         $this->_template_file = $filename;
175         $fp = fopen($filename, "rb");
176         $data = fread($fp, filesize($filename));
177         fclose($fp);
178         $this->Template($data);
179     }
180 }
181
182 class WikiTemplate
183 extends TemplateFile
184 {
185     /**
186      * Constructor.
187      *
188      * Constructs a new WikiTemplate based upon the named template.
189      *
190      * @access public
191      *
192      * @param $template string Which template.
193      */
194     function WikiTemplate($template, $page_revision = false) {
195         global $templates;
196
197         $this->TemplateFile(FindFile($templates[$template]));
198
199         $this->_template_name = $template;
200
201         $this->setGlobalTokens();
202         if ($page_revision)
203             $this->setPageRevisionTokens($page_revision);
204     }
205     
206
207     function setPageTokens(&$page) {
208         /*
209         if ($page->get('locked'))
210             $this->setConditional('LOCK');
211         // HACK: note that EDITABLE may also be set in setWikiUserTokens.
212         if (!$page->get('locked'))
213             $this->setConditional('EDITABLE');
214         */
215         
216         $pagename = $page->getName();
217         $this->replace('page', $page);
218         $this->qreplace('PAGE', $pagename);
219         $this->qreplace('PAGEURL', rawurlencode($pagename));
220         $this->qreplace('SPLIT_PAGE', split_pagename($pagename));
221         $this->qreplace('BROWSE_PAGE', WikiURL($pagename));
222
223         // FIXME: this is a bit of dangerous hackage.
224         $this->qreplace('ACTION', WikiURL($pagename, array('action' => '')));
225
226         // FIXME:?
227         //$this->replace_callback('HITS', array($page, 'getHitCount'));
228         //$this->replace_callback('RELATEDPAGES', array($page, 'getHitCount'));
229         //_dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
230     }
231
232     function setPageRevisionTokens(&$revision) {
233         $page = & $revision->getPage();
234         
235         $current = & $page->getCurrentRevision();
236         $previous = & $page->getRevisionBefore($revision->getVersion());
237
238         $this->replace('IS_CURRENT',
239                        $current->getVersion() == $revision->getVersion());
240
241         /*
242         if ($previous && $previous->getVersion() != 0)
243             $this->setConditional('COPY'); // FIXME: should rename HAVE_COPY?
244         */
245         
246         global $datetimeformat;
247         
248         $this->qreplace('LASTMODIFIED',
249                         strftime($datetimeformat, $revision->get('mtime')));
250         $this->qreplace('LASTAUTHOR', $revision->get('author'));
251         $this->qreplace('VERSION', $revision->getVersion());
252         $this->qreplace('CURRENT_VERSION', $current->getVersion());
253
254         $this->setPageTokens($page);
255     }
256
257     function setWikiUserTokens(&$user) {
258         /*
259         if ( $user->is_admin() ) {
260             $this->setConditional('ADMIN');
261             $this->setConditional('EDITABLE');
262         }
263         if ( ! $user->is_authenticated() )
264             $this->setConditional('ANONYMOUS');
265         */
266         $this->replace('user', $user);
267         $this->qreplace('USERID', $user->id());
268         $prefs = $user->getPreferences();
269         $this->qreplace('EDIT_AREA_WIDTH', $prefs['edit_area.width']);
270         $this->qreplace('EDIT_AREA_HEIGHT', $prefs['edit_area.height']);
271     }
272
273     function setGlobalTokens () {
274         global $user, $logo, $RCS_IDS;
275         
276         // FIXME: This a a bit of dangerous hackage.
277         $this->qreplace('BROWSE', WikiURL(''));
278         $this->qreplace('CSS_URL', DataURL(CSS_URL));
279
280         if (isset($user))
281             $this->setWikiUserTokens($user);
282         if (isset($logo))
283             $this->qreplace('LOGO', DataURL($logo));
284         if (isset($RCS_IDS))
285             $this->qreplace('RCS_IDS', $RCS_IDS);
286
287         $this->qreplace('BASE_URL',
288                         // FIXME:
289                         WikiURL($GLOBALS['pagename'], false, 'absolute_url'));
290     }
291 };
292
293
294 /**
295  * Generate page contents using a template.
296  *
297  * This is a convenience function for backwards compatibility with the old
298  * GeneratePage().
299  *
300  * @param $template string name of the template (see config.php for list of names)
301  *
302  * @param $content string html content to put into the page
303  *
304  * @param $title string page title
305  *
306  * @param $page_revision object Current WikiDB_PageRevision, if available.
307  *
308  * @return string HTML expansion of template.
309  */
310 function GeneratePage($template, $content, $title, $page_revision = false) {
311     // require_once("lib/template.php");
312     $t = new WikiTemplate($template);
313     if ($page_revision)
314         $t->setPageRevisionTokens($page_revision);
315     $t->replace('CONTENT', $content);
316     $t->replace('TITLE', $title);
317     return $t->getExpansion();
318 }
319
320 // Local Variables:
321 // mode: php
322 // tab-width: 8
323 // c-basic-offset: 4
324 // c-hanging-comment-ender-p: nil
325 // indent-tabs-mode: nil
326 // End:   
327 ?>