1 <?php rcs_id('$Id: Template.php,v 1.22 2002-01-17 23:14:21 dairiki Exp $');
3 require_once("lib/ErrorManager.php");
4 require_once("lib/WikiPlugin.php");
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...)
12 function Template($tmpl) {
13 //$this->_tmpl = $this->_munge_input($tmpl);
15 $this->_vars = array();
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
27 // FIXME: move this to WikiPlugin.php.
28 $translated_pi = preg_replace('/(\s\w+=)_\("((?:[^"\\\\]|\\.)*)"\)/xse',
29 '"\1\"" . gettext("\2") . "\""',
31 $repl[] = $pluginLoader->expandPI($translated_pi, $dbi, $request);
34 // Convert < ?= expr ? > to < ?php $this->_print(expr); ? >
35 $orig[] = '/<\?=(.*?)\?>/s';
36 $repl[] = '<?php $this->_print(\1);?>';
38 // Convert tag attributes like foo=_("String") to foo="String" (with gettext mapping).
39 $orig[] = '/( < \w [^>]* \w=)_\("((?:[^"\\\\]|\\.)*)"\)/xse';
40 $repl[] = '"\1\"" . htmlspecialchars(gettext("\2")) . "\""';
42 return preg_replace($orig, $repl, $template);
44 //$ret = preg_replace($orig, $repl, $template);
45 //echo QElement('pre', $ret);
49 function _getReplacement($varname, $index = false) {
50 // FIXME: report missing vars.
52 echo "GET: $varname<br>\n";
54 $vars = &$this->_vars;
55 if (!isset($vars[$varname]))
58 $value = $vars[$varname];
60 @$value = $value[$index];
62 if (!is_string($value))
63 $value = $this->_toString($value);
65 // Quote '?' to avoid inadvertently inserting "<? php", "? >", or similar...
66 return str_replace('?', '?', $value);
69 function _print ($val) {
74 foreach ($val as $item) {
80 elseif (is_object($val)) {
81 if (isa($val, 'Template')) {
82 // Expand sub-template with defaults from this template.
83 $val->printExpansion($this->_vars);
85 elseif (method_exists($val, 'printhtml')) {
88 elseif (method_exists($val, 'ashtml')) {
91 elseif (method_exists($val, 'asstring')) {
92 return htmlspecialchars($val->asString());
101 * Substitute HTML replacement text for tokens in template.
103 * Constructs a new WikiTemplate based upon the named template.
107 * @param $token string Name of token to substitute for.
109 * @param $replacement string Replacement HTML text.
111 function replace($varname, $value) {
112 $this->_vars[$varname] = $value;
116 * Substitute text for tokens in template.
120 * @param $token string Name of token to substitute for.
122 * @param $replacement string Replacement text.
123 * The replacement text is run through htmlspecialchars()
124 * to escape any special characters.
126 function qreplace($varname, $value) {
127 $this->_vars[$varname] = htmlspecialchars($value);
132 * Include/remove conditional text in template.
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.
142 function setConditional($token, $value = true) {
143 $this->_iftoken[$token] = $value;
147 function printExpansion ($defaults = false) {
148 $vars = &$this->_vars;
149 if ($defaults !== false) {
151 if (!is_array($defaults)) {
152 if (!isset($vars['CONTENT']))
153 $vars['CONTENT'] = $defaults;
156 foreach ($defaults as $key => $val)
157 if (!isset($vars[$key]))
163 //$this->_dump_template();
165 global $ErrorManager;
166 $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
168 eval('?>' . $this->_munge_input($this->_tmpl));
170 $ErrorManager->popErrorHandler();
172 if (isset($save_vars))
176 function getExpansion ($defaults = false) {
178 $this->printExpansion($defaults);
179 $html = ob_get_contents();
185 function _dump_template () {
186 $lines = explode("\n", $this->_munge_input($this->_tmpl));
189 foreach ($lines as $line)
190 printf("%4d %s\n", $n++, htmlspecialchars($line));
194 function _errorHandler($error) {
195 if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
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))
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];
214 function TemplateFile($filename) {
215 $this->_template_file = $filename;
216 $fp = fopen($filename, "rb");
217 $data = fread($fp, filesize($filename));
219 $this->Template($data);
230 * Constructs a new WikiTemplate based upon the named template.
234 * @param $template string Which template.
236 function WikiTemplate($template, $page_revision = false) {
238 $this->TemplateFile($Theme->findTemplate($template));
239 $this->_template_name = $template;
240 $this->setGlobalTokens();
242 $this->setPageRevisionTokens($page_revision);
246 function setPageTokens(&$page) {
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');
255 $pagename = $page->getName();
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));
263 // FIXME: this is a bit of dangerous hackage.
264 $this->qreplace('ACTION', WikiURL($pagename, array('action' => '')));
267 //$this->replace_callback('HITS', array($page, 'getHitCount'));
268 //$this->replace_callback('RELATEDPAGES', array($page, 'getHitCount'));
269 //_dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
272 function setPageRevisionTokens(&$revision) {
273 $page = & $revision->getPage();
275 $current = & $page->getCurrentRevision();
276 $previous = & $page->getRevisionBefore($revision->getVersion());
278 $this->replace('IS_CURRENT',
279 $current->getVersion() == $revision->getVersion());
281 global $datetimeformat;
283 //$this->qreplace('LASTMODIFIED',
284 // strftime($datetimeformat, $revision->get('mtime')));
286 $this->qreplace('LASTAUTHOR', $revision->get('author'));
287 $this->qreplace('VERSION', $revision->getVersion());
288 $this->qreplace('CURRENT_VERSION', $current->getVersion());
290 $this->replace('revision', $revision);
292 $this->setPageTokens($page);
295 function setWikiUserTokens(&$user) {
297 if ( $user->is_admin() ) {
298 $this->setConditional('ADMIN');
299 $this->setConditional('EDITABLE');
301 if ( ! $user->is_authenticated() )
302 $this->setConditional('ANONYMOUS');
304 $this->replace('user', $user);
305 $this->qreplace('USERID', $user->id());
307 $prefs = $user->getPreferences();
308 $this->qreplace('EDIT_AREA_WIDTH', $prefs['edit_area.width']);
309 $this->qreplace('EDIT_AREA_HEIGHT', $prefs['edit_area.height']);
312 function setGlobalTokens () {
313 global $user, $RCS_IDS, $Theme;
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);
321 $this->setWikiUserTokens($user);
323 $this->qreplace('RCS_IDS', $RCS_IDS);
325 require_once('lib/ButtonFactory.php');
326 $this->replace('ButtonFactory', new ButtonFactory);
332 * Generate page contents using a template.
334 * This is a convenience function for backwards compatibility with the old
337 * @param $template string name of the template (see config.php for list of names)
339 * @param $content string html content to put into the page
341 * @param $title string page title
343 * @param $page_revision object Current WikiDB_PageRevision, if available.
345 * @return string HTML expansion of template.
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);
355 $t->setPageRevisionTokens($page_revision);
356 $t->replace('CONTENT', $content);
357 return $t->getExpansion();
364 // c-hanging-comment-ender-p: nil
365 // indent-tabs-mode: nil