1 <?php rcs_id('$Id: Template.php,v 1.19 2002-01-15 21:41:10 carstenklapp Exp $');
3 require_once("lib/ErrorManager.php");
4 require_once("lib/WikiPlugin.php");
5 require_once("lib/Toolbar.php");
7 //FIXME: This is a mess and needs to be refactored.
8 // (In other words: this is all in a state of flux, so don't count on any
9 // of this being the same tomorrow...)
13 function Template($tmpl) {
14 //$this->_tmpl = $this->_munge_input($tmpl);
16 $this->_vars = array();
19 function _munge_input($template) {
20 // Expand "< ?plugin-* ...? >"
21 preg_match_all('/<\?plugin.*?\?>/s', $template, $m);
22 global $dbi, $request; // FIXME: no globals?
23 $pluginLoader = new WikiPluginLoader;
24 foreach (array_unique($m[0]) as $plugin_pi) {
25 $orig[] = '/' . preg_quote($plugin_pi, '/') . '/s';
26 // Plugin args like 'description=_("Get backlinks")' get
28 // FIXME: move this to WikiPlugin.php.
29 $translated_pi = preg_replace('/(\s\w+=)_\("((?:[^"\\\\]|\\.)*)"\)/xse',
30 '"\1\"" . gettext("\2") . "\""',
32 $repl[] = $pluginLoader->expandPI($translated_pi, $dbi, $request);
35 // Convert ${VAR} to < ?php echo "$VAR"; ? >
36 //$orig[] = '/\${(\w[\w\d]*)}/';
37 //$repl[] = '<?php echo "$\1"; ? >';
38 $orig[] = '/\${(\w[\w\d]*)}/e';
39 $repl[] = '$this->_getReplacement("\1")';
41 // Convert $VAR[ind] to < ?php echo "$VAR[ind]"; ? >
42 $orig[] = '/\$(\w[\w\d]*)\[([\w\d]+)\]/e';
43 $repl[] = '$this->_getReplacement("\1", "\2")';
45 // Convert $_("String") to < ?php echo htmlspecialchars(gettext("String")); ? >
46 $orig[] = '/\$_\(("(?:[^"\\\\]|\\.)*")\)/xs';
47 $repl[] = "<?php echo htmlspecialchars(gettext(\\1)); ?>";
49 // Convert tag attributes like foo=_("String") to foo="String" (with gettext mapping).
50 $orig[] = '/( < \w [^>]* \w=)_\("((?:[^"\\\\]|\\.)*)"\)/xse';
51 $repl[] = '"\1\"" . htmlspecialchars(gettext("\2")) . "\""';
53 return preg_replace($orig, $repl, $template);
55 $ret = preg_replace($orig, $repl, $template);
56 echo QElement('pre', $ret);
62 function _getReplacement($varname, $index = false) {
63 // FIXME: report missing vars.
64 $vars = &$this->_vars;
65 if (isset($vars[$varname])) {
66 $value = $vars[$varname];
68 @$value = (string) $value[$index];
69 return str_replace('?', '?', $value);
75 * Substitute HTML replacement text for tokens in template.
77 * Constructs a new WikiTemplate based upon the named template.
81 * @param $token string Name of token to substitute for.
83 * @param $replacement string Replacement HTML text.
85 function replace($varname, $value) {
86 $this->_vars[$varname] = $value;
90 * Substitute text for tokens in template.
94 * @param $token string Name of token to substitute for.
96 * @param $replacement string Replacement text.
97 * The replacement text is run through htmlspecialchars()
98 * to escape any special characters.
100 function qreplace($varname, $value) {
101 $this->_vars[$varname] = htmlspecialchars($value);
106 * Include/remove conditional text in template.
110 * @param $token string Conditional token name.
111 * The text within any matching if blocks (or single line ifs) will
112 * be included in the template expansion, while the text in matching
113 * negated if blocks will be excluded.
116 function setConditional($token, $value = true) {
117 $this->_iftoken[$token] = $value;
121 function getExpansion($varhash = false) {
122 $savevars = $this->_vars;
123 if (is_array($varhash)) {
124 foreach ($varhash as $key => $val)
125 $this->_vars[$key] = $val;
127 extract($this->_vars);
128 if (isset($this->_iftoken))
129 $_iftoken = $this->_iftoken;
133 //$this->_dump_template();
135 global $ErrorManager;
136 $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
137 eval('?>' . $this->_munge_input($this->_tmpl));
138 $ErrorManager->popErrorHandler();
140 $html = ob_get_contents();
146 function printExpansion($args = false) {
147 echo $this->getExpansion($args);
151 function _dump_template () {
152 $lines = explode("\n", $this->_munge_input($this->_tmpl));
155 foreach ($lines as $line)
156 printf("%4d %s\n", $n++, htmlspecialchars($line));
160 function _errorHandler($error) {
161 if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
163 $error->errfile = "In template";
164 $lines = explode("\n", $this->_tmpl);
165 if (isset($lines[$error->errline - 1]))
166 $error->errstr .= ":\n\t" . $lines[$error->errline - 1];
174 function TemplateFile($filename) {
175 $this->_template_file = $filename;
176 $fp = fopen($filename, "rb");
177 $data = fread($fp, filesize($filename));
179 $this->Template($data);
189 * Constructs a new WikiTemplate based upon the named template.
193 * @param $template string Which template.
195 function WikiTemplate($template, $page_revision = false) {
198 $this->TemplateFile(FindFile($templates[$template]));
200 $this->_template_name = $template;
202 $this->setGlobalTokens();
204 $this->setPageRevisionTokens($page_revision);
208 function setPageTokens(&$page) {
210 if ($page->get('locked'))
211 $this->setConditional('LOCK');
212 // HACK: note that EDITABLE may also be set in setWikiUserTokens.
213 if (!$page->get('locked'))
214 $this->setConditional('EDITABLE');
217 $pagename = $page->getName();
218 $this->replace('NAVIGATION', toolbar_action_Navigation($pagename));
219 $this->replace('SEARCH', toolbar_action_SearchActions($pagename,CHARSET));
221 $this->replace('page', $page);
222 $this->qreplace('CHARSET', CHARSET);
223 $this->qreplace('PAGE', $pagename);
224 $this->qreplace('PAGEURL', rawurlencode($pagename));
225 $this->qreplace('SPLIT_PAGE', split_pagename($pagename));
226 $this->qreplace('BROWSE_PAGE', WikiURL($pagename));
228 $this->replace('EDIT_TIPS', toolbar_Info_EditTips());
230 // FIXME: this is a bit of dangerous hackage.
231 $this->qreplace('ACTION', WikiURL($pagename, array('action' => '')));
234 //$this->replace_callback('HITS', array($page, 'getHitCount'));
235 //$this->replace_callback('RELATEDPAGES', array($page, 'getHitCount'));
236 //_dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
239 function setPageRevisionTokens(&$revision) {
240 $page = & $revision->getPage();
242 $current = & $page->getCurrentRevision();
243 $previous = & $page->getRevisionBefore($revision->getVersion());
245 $this->replace('VIEW_WARNINGS',
246 toolbar_Warnings_View($current->getVersion() == $revision->getVersion(),$page->getName()));
247 $this->replace('IS_CURRENT',
248 $current->getVersion() == $revision->getVersion());
249 // $this->replace('EDIT_WARNINGS',
250 // toolbar_Warnings_Edit(!empty($PREVIEW_CONTENT),
251 // $current->getVersion() == $revision->getVersion()));
253 if ($previous && $previous->getVersion() != 0)
254 $this->setConditional('COPY'); // FIXME: should rename HAVE_COPY?
257 global $datetimeformat;
259 $this->replace('LASTMODIFIED',
260 toolbar_Info_LastModified(
261 ($current->getVersion() == $revision->getVersion()),
262 strftime($datetimeformat, $revision->get('mtime')),
263 $revision->getVersion() ));
264 // $this->qreplace('LASTMODIFIED',
265 // strftime($datetimeformat, $revision->get('mtime')));
267 $this->qreplace('LASTAUTHOR', $revision->get('author'));
268 $this->qreplace('VERSION', $revision->getVersion());
269 $this->qreplace('CURRENT_VERSION', $current->getVersion());
271 $this->setPageTokens($page);
274 function setWikiUserTokens(&$user) {
276 if ( $user->is_admin() ) {
277 $this->setConditional('ADMIN');
278 $this->setConditional('EDITABLE');
280 if ( ! $user->is_authenticated() )
281 $this->setConditional('ANONYMOUS');
283 $this->replace('user', $user);
284 $this->qreplace('USERID', $user->id());
286 //WARNING: hackage! $pagename is not available here
288 $this->replace('SIGNIN', toolbar_User_UserSignInOut($user->is_authenticated(), $user->id(), $pagename, $user->is_admin()));
290 $prefs = $user->getPreferences();
291 $this->qreplace('EDIT_AREA_WIDTH', $prefs['edit_area.width']);
292 $this->qreplace('EDIT_AREA_HEIGHT', $prefs['edit_area.height']);
295 function setGlobalTokens () {
296 global $user, $logo, $RCS_IDS;
298 // FIXME: This a a bit of dangerous hackage.
299 $this->qreplace('BROWSE', WikiURL(''));
300 $this->replace('CSS', WikiTemplate::__css_links());
301 $this->qreplace('WIKI_NAME', WIKI_NAME);
304 $this->setWikiUserTokens($user);
306 $this->replace('LOGO', toolbar_action_Logo(WIKI_NAME, $logo));
307 // $this->qreplace('LOGO', DataURL($logo));
309 $this->qreplace('RCS_IDS', $RCS_IDS);
311 $this->qreplace('BASE_URL',
313 //WikiURL($GLOBALS['pagename'], false, 'absolute_url')
319 function __css_links () {
320 global $CSS_URLS, $CSS_DEFAULT;
323 foreach ($CSS_URLS as $key => $val) {
324 $link = array('rel' => 'stylesheet',
326 'href' => DataURL($val),
327 'type' => 'text/css',
328 'charset' => CHARSET);
329 // FIXME: why the charset? Is a style-sheet really ever going to
330 // be other than US-ASCII?
332 // The next line is also used by xgettext to localise the word
333 // "Printer" used in the stylesheet's 'title' (see above).
334 if ($key == _("Printer")) {
335 $link['media'] = 'print, screen';
338 if ($key != $CSS_DEFAULT) {
339 $link['rel'] = 'alternate stylesheet';
340 $html[] = Element('link', $link);
343 // Default CSS should be listed first, otherwise some
344 // browsers (incl. Galeon) don't seem to treat it as
345 // default (regardless of whether rel="stylesheet" or
346 // rel="alternate stylesheet".)
347 array_unshift($html, Element('link', $link));
350 return join("\n", $html);
356 * Generate page contents using a template.
358 * This is a convenience function for backwards compatibility with the old
361 * @param $template string name of the template (see config.php for list of names)
363 * @param $content string html content to put into the page
365 * @param $title string page title
367 * @param $page_revision object Current WikiDB_PageRevision, if available.
369 * @return string HTML expansion of template.
371 function GeneratePage($template, $content, $title, $page_revision = false) {
372 // require_once("lib/template.php");
373 $t = new WikiTemplate($template);
375 $t->setPageRevisionTokens($page_revision);
376 $t->replace('CONTENT', $content);
377 $t->replace('TITLE', $title);
378 return $t->getExpansion();
385 // c-hanging-comment-ender-p: nil
386 // indent-tabs-mode: nil