diff -r de56132c008d -r bdac73ed481e includes/template.php --- a/includes/template.php Sun Mar 28 21:49:26 2010 -0400 +++ b/includes/template.php Sun Mar 28 23:10:46 2010 -0400 @@ -13,1686 +13,1686 @@ class template { - var $tpl_strings, $tpl_bool, $vars_assign_history, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list, $default_theme, $default_style, $plugin_blocks, $plugin_blocks_content, $namespace_string, $style_list, $theme_loaded; - - var $theme_initted = false; - var $page_initted = false; - var $elements = false; - var $page_id = false; - var $namespace = false; - var $js_preload = array(); - var $js_append = ''; - - /** - * Page action conditions - * @var array - */ - - var $conds = array(); - - /** - * The PageProcessor for the current page - * @var object - */ - - var $page = false; - - /** - * The list of themes that are critical for Enano operation. This doesn't include oxygen which - * remains a user theme. By default this is admin and printable which have to be loaded on demand. - * @var array - */ - - var $system_themes = array('admin', 'printable'); - - /** - * Set to true if the site is disabled and thus a message needs to be shown. This should ONLY be changed by common.php. - * @var bool - * @access private - */ - - var $site_disabled = false; - - /** - * One of the absolute best parts of Enano :-P - * @var string - */ - - var $fading_button = ''; - - function __construct() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $cache; - - $this->tpl_bool = Array(); - $this->tpl_strings = Array(); - $this->sidebar_extra = ''; - $this->toolbar_menu = ''; - $this->additional_headers = ''; - $this->plugin_blocks = Array(); - $this->plugin_blocks_content = array(); - $this->theme_loaded = false; - - $this->theme_list = Array(); - $this->named_theme_list = Array(); - - $this->vars_assign_history = array( - 'strings' => array(), - 'bool' => array() - ); - - if ( defined('IN_ENANO_UPGRADE') ) - { - return $this->construct_compat(); - } - - if ( !$this->theme_list = $cache->fetch('themes') ) - { - $q = $db->sql_query('SELECT theme_id, theme_name, enabled, default_style, group_policy, group_list FROM ' . table_prefix . 'themes;'); - if ( !$q ) - $db->_die('template.php selecting theme list'); - - $i = 0; - while ( $row = $db->fetchrow() ) - { - $this->theme_list[$i] = $row; - $i++; - } - unset($theme); - $this->theme_list = array_values($this->theme_list); - $cache->store('themes', $this->theme_list, -1); - } - - // Create associative array of themes - foreach ( $this->theme_list as $i => &$theme ) - $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; - - unset($theme); - - $this->default_theme = ( $_ = getConfig('theme_default') ) ? $_ : $this->theme_list[0]['theme_id']; - $this->named_theme_list[ $this->default_theme ]['css'] = $this->get_theme_css_files($this->default_theme); - // Come up with the default style. If the CSS file specified in default_style exists, we're good, just - // use that. Otherwise, use the first stylesheet that comes to mind. - $df_data =& $this->named_theme_list[ $this->default_theme ]; - $this->default_style = ( in_array($df_data['default_style'], $df_data['css']) ) ? $df_data['default_style'] : $df_data['css'][0]; - } - - /** - * Gets the list of available CSS files (styles) for the specified theme. - * @param string Theme ID - * @return array - */ - - function get_theme_css_files($theme_id) - { - $css = array(); - $dir = ENANO_ROOT . "/themes/{$theme_id}/css"; - if ( $dh = @opendir($dir) ) - { - while ( ( $file = @readdir($dh) ) !== false ) - { - if ( preg_match('/\.css$/', $file) ) - $css[] = preg_replace('/\.css$/', '', $file); - } - closedir($dh); - } - // No CSS files? If so, nuke it. - if ( count($css) < 1 ) - { - unset($this->theme_list[$theme_id]); - } - return $css; - } - - /** - * Failsafe constructor for upgrades. - */ - - function construct_compat() - { - global $db, $session, $paths, $template, $plugins; // Common objects - $this->tpl_bool = Array(); - $this->tpl_strings = Array(); - $this->sidebar_extra = ''; - $this->toolbar_menu = ''; - $this->additional_headers = ''; - $this->plugin_blocks = Array(); - $this->theme_loaded = false; - - $this->fading_button = '
-  -
'; - - $this->theme_list = Array(); - $this->named_theme_list = Array(); - - $q = $db->sql_query('SELECT theme_id, theme_name, enabled, default_style FROM ' . table_prefix . 'themes;'); - if ( !$q ) - $db->_die('template.php selecting theme list'); - - $i = 0; - while ( $row = $db->fetchrow() ) - { - $this->theme_list[$i] = $row; - $i++; - } - // List out all CSS files for this theme - foreach ( $this->theme_list as $i => &$theme ) - { - $theme['css'] = array(); - $dir = ENANO_ROOT . "/themes/{$theme['theme_id']}/css"; - if ( $dh = @opendir($dir) ) - { - while ( ( $file = @readdir($dh) ) !== false ) - { - if ( preg_match('/\.css$/', $file) ) - $theme['css'][] = preg_replace('/\.css$/', '', $file); - } - closedir($dh); - } - // No CSS files? If so, nuke it. - if ( count($theme['css']) < 1 ) - { - unset($this->theme_list[$i]); - } - } - $this->theme_list = array_values($this->theme_list); - // Create associative array of themes - foreach ( $this->theme_list as $i => &$theme ) - $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; - - $this->default_theme = ( $_ = getConfig('theme_default') ) ? $_ : $this->theme_list[0]['theme_id']; - // Come up with the default style. If the CSS file specified in default_style exists, we're good, just - // use that. Otherwise, use the first stylesheet that comes to mind. - $df_data =& $this->named_theme_list[ $this->default_theme ]; - $this->default_style = ( in_array($df_data['default_style'], $df_data['css']) ) ? $df_data['default_style'] : $df_data['css'][0]; - } - - /** - * Systematically deletes themes from available list if they're blocked by theme security settings. Called when session->start() finishes. - */ - - function process_theme_acls() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - // generate the fading button - needs to be done after sessions are started - $admintitle = ( $session->user_level >= USER_LEVEL_ADMIN && is_object(@$lang) ) ? ' title="' . $lang->get('sidebar_btn_enanopowered_admin_tip') . '"' : ''; - $this->fading_button = '
-  -
'; - - // For each theme, check ACLs and delete from RAM if not authorized - foreach ( $this->theme_list as $i => $theme ) - { - if ( !@$theme['group_list'] ) - continue; - if ( $theme['theme_id'] === getConfig('theme_default') ) - continue; - switch ( $theme['group_policy'] ) - { - case 'allow_all': - // Unconditionally allowed - continue; - break; - case 'whitelist': - // If we're not on the list, off to the left please - $list = enano_json_decode($theme['group_list']); - $allowed = false; - foreach ( $list as $acl ) - { - if ( !preg_match('/^(u|g):([0-9]+)$/', $acl, $match) ) - // Invalid list entry, silently allow (maybe not a good idea but - // really, these things are checked before they're inserted) - continue 2; - $mode = $match[1]; - $id = intval($match[2]); - switch ( $mode ) - { - case 'u': - $allowed = ( $id == $session->user_id ); - if ( $allowed ) - break 2; - break; - case 'g': - $allowed = ( isset($session->groups[$id]) ); - if ( $allowed ) - break 2; - } - } - if ( !$allowed ) - { - unset($this->theme_list[$i]); - } - break; - case 'blacklist': - // If we're ON the list, off to the left please - $list = enano_json_decode($theme['group_list']); - $allowed = true; - foreach ( $list as $acl ) - { - if ( !preg_match('/^(u|g):([0-9]+)$/', $acl, $match) ) - // Invalid list entry, silently allow (maybe not a good idea but - // really, these things are checked before they're inserted) - continue 2; - $mode = $match[1]; - $id = intval($match[2]); - switch ( $mode ) - { - case 'u': - $allowed = ( $id != $session->user_id ); - if ( !$allowed ) - break 2; - break; - case 'g': - $allowed = ( !isset($session->groups[$id]) ); - if ( !$allowed ) - break 2; - } - } - if ( !$allowed ) - { - unset($this->theme_list[$i]); - } - break; - } - } - - $this->theme_list = array_values($this->theme_list); - - // Rebuild associative theme list - $this->named_theme_list = array(); - foreach ( $this->theme_list as $i => &$theme ) - $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; - } - - /** - * Register a new sidebar block. - * @param string Block title - * @param string Block HTML - * @param bool If true, the class of the block will be the same as the one used for blocks that are a list of links instead of HTML content. This can do some wacky things like make all your s block level. - */ - - function sidebar_widget($t, $h, $use_normal_section = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - if ( !$this->theme_loaded ) - { - $this->load_theme($session->theme, $session->style); - } - if(!$this->sidebar_widgets) - $this->sidebar_widgets = ''; - $tplvars = $this->extract_vars('elements.tpl'); - - if ( $use_normal_section ) - { - $parser = $this->makeParserText($tplvars['sidebar_section']); - } - else - { - $parser = $this->makeParserText($tplvars['sidebar_section_raw']); - } - - $parser->assign_vars(Array('TITLE' => '{TITLE}','CONTENT' => $h)); - $this->plugin_blocks[$t] = $parser->run(); - $this->plugin_blocks_content[$t] = $h; - $this->sidebar_widgets .= $parser->run(); - } - function add_header($html) - { - /* debug only ** - $bt = debug_backtrace(); - $bt = $bt[1]; - $this->additional_headers .= "\n \n " . $html; - */ - $this->additional_headers .= "\n " . $html; - } - function get_css($s = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $this->init_vars(); - - $path = ( $s ) ? 'css/'.$s : 'css/'.$this->style.'.css'; - - if ( !file_exists(ENANO_ROOT . '/themes/' . $this->theme . '/' . $path) ) - { - echo "/* WARNING: Falling back to default file because file $path does not exist */\n"; - $path = 'css/' . $this->style_list[0] . '.css'; - } - - return $this->process_template($path); - } - function load_theme($name = false, $css = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $this->theme = ( $name ) ? $name : $session->theme; - $this->style = ( $css ) ? $css : $session->style; - if ( !$this->theme ) - { - $this->theme = $this->theme_list[0]['theme_id']; - $this->style = preg_replace('/\.css$/', '', $this->theme_list[0]['default_style']); - } - // Make sure we're allowed to use this theme. - if ( ( - // If it was removed, it's probably blocked by an ACL, or it was uninstalled - !isset($this->named_theme_list[$this->theme]) || - // Check if the theme is disabled - ( isset($this->named_theme_list[$this->theme]) && isset($this->named_theme_list[$this->theme]['enabled']) && $this->named_theme_list[$this->theme]['enabled'] == 0 ) ) - // Above all, if it's a system theme, don't inhibit the loading process. - && !in_array($this->theme, $this->system_themes) - ) - { - // No, something is preventing it - fall back to site default - $this->theme = $this->default_theme; - - // Come up with the default style. If the CSS file specified in default_style exists, we're good, just - // use that. Otherwise, use the first stylesheet that comes to mind. - $df_data =& $this->named_theme_list[ $this->theme ]; - $this->style = ( in_array($df_data['default_style'], $df_data['css']) ) ? $df_data['default_style'] : $df_data['css'][0]; - } - // The list of styles for the currently selected theme - $this->style_list =& $this->named_theme_list[ $this->theme ]['css']; - $this->theme_loaded = true; - } - - /** - * Change the theme we're supposed to display. - * @param string Theme name - * @param string Style name; optional - */ - - function set_theme($theme = false, $style = false) - { - $this->theme_initted = false; - $this->load_theme($theme, $style); - } - - /** - * Change the page we're supposed to generate for - * @param mixed Page ID *or* PageProcessor. If a PageProcessor, pulls permission info and such from that; if not, starts a PageProcessor. YOU SHOULD USE A PageProcessor WHENEVER POSSIBLE! It improves efficiency. - * @param string Namespace; not required if including a PageProcessor. - */ - - function set_page($page_id_or_pp, $namespace = false) - { - if ( is_object($page_id_or_pp) && get_class($page_id_or_pp) === 'PageProcessor' ) - { - $this->page_initted = false; - $page =& $page_id_or_pp; - $this->page = $page; - $this->page_id = $page->page_id; - $this->namespace = $page->namespace; - } - else if ( is_string($page_id_or_pp) ) - { - if ( !is_string($namespace) ) - return false; - - if ( $page_id_or_pp === $this->page_id && $namespace === $this->namespace ) - return true; - - $this->page_initted = false; - $this->page = false; - $this->page_id = sanitize_page_id($page_id_or_pp); - $this->namespace = $namespace; - } - else - { - return false; - } - return true; - } - - /** - * Queue a Javascript file to be loaded with the page instead of on demand. - * @param mixed Javascript file string or array thereof, extensions are optional - * @example - - $template->preload_js(array('jquery', 'jquery-ui')); - $template->preload_js('admin-menu.js'); - - * @return null - */ - - function preload_js($filemixed) - { - if ( is_string($filemixed) ) - $files = array($filemixed); - else if ( is_array($filemixed) ) - $files = $filemixed; - else - // :-/ - return null; - - $this->js_preload = array_values(array_merge($this->js_preload, $files)); - } - - /** - * Queue some HTML to be inserted after the Javascript runtime. - * @param string HTML glob - */ - - function add_header_js($html) - { - $this->js_append .= "$html\n "; - } - - /** - * Global, only-called-once init. Goes to all themes. - */ - - function init_global_vars() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - global $email; - - $is_opera = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')) ? true : false; - $is_msie = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? true : false; - - $this->assign_bool(array( - 'auth_admin' => $session->user_level >= USER_LEVEL_ADMIN ? true : false, - 'user_logged_in' => $session->user_logged_in, - 'opera' => $is_opera, - 'msie' => $is_msie - )); - - if ( $session->sid_super ) - { - $ash = '&auth=' . $session->sid_super; - $asq = "?auth=" . $session->sid_super; - $asa = "&auth=" . $session->sid_super; - $as2 = htmlspecialchars(urlSeparator) . 'auth='.$session->sid_super; - } - else - { - $asq = ''; - $asa = ''; - $as2 = ''; - $ash = ''; - } - - // Append the Enano version to URLs to break the cache on upgrades - $enano_version = enano_version(); - - // Set up javascript includes - // these depend heavily on whether we have a CDN to work with or not - if ( getConfig('cdn_path') ) - { - // we're on a CDN, point to static includes - // CLI javascript compression script: includes/clientside/jscompress.php - $js_head = ''; - - if ( !empty($this->js_preload) ) - { - $loadlines = array(); - - // make unique - foreach ( $this->js_preload as &$script ) - { - $script = preg_replace('/\.js$/', '', $script) . '.js'; - } - unset($script); - $this->js_preload = array_unique($this->js_preload); - - foreach ( $this->js_preload as $script ) - { - $js_head .= "\n "; - // special case for l10n: also load strings - if ( $script == 'l10n.js' ) - { - global $lang; - $js_head .= "\n "; - } - $loadlines[] = "loaded_components['$script'] = true;"; - } - - // tell the system that this stuff is already loaded - $loadlines = implode("\n ", $loadlines); - $js_head .= "\n "; - } - - $js_foot = << - // This initializes the Javascript runtime when the DOM is ready - not when the page is - // done loading, because enano-lib-basic still has to load some 15 other script files - // check for the init function - this is a KHTML fix - // This doesn't seem to work properly in IE in 1.1.x - there are some problems with - // tinyMCE and l10n. - if ( typeof ( enano_init ) == 'function' && !IE ) - { - enano_init(); - window.onload = function(e) { }; - } - - $this->js_append + var $tpl_strings, $tpl_bool, $vars_assign_history, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list, $default_theme, $default_style, $plugin_blocks, $plugin_blocks_content, $namespace_string, $style_list, $theme_loaded; + + var $theme_initted = false; + var $page_initted = false; + var $elements = false; + var $page_id = false; + var $namespace = false; + var $js_preload = array(); + var $js_append = ''; + + /** + * Page action conditions + * @var array + */ + + var $conds = array(); + + /** + * The PageProcessor for the current page + * @var object + */ + + var $page = false; + + /** + * The list of themes that are critical for Enano operation. This doesn't include oxygen which + * remains a user theme. By default this is admin and printable which have to be loaded on demand. + * @var array + */ + + var $system_themes = array('admin', 'printable'); + + /** + * Set to true if the site is disabled and thus a message needs to be shown. This should ONLY be changed by common.php. + * @var bool + * @access private + */ + + var $site_disabled = false; + + /** + * One of the absolute best parts of Enano :-P + * @var string + */ + + var $fading_button = ''; + + function __construct() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; + + $this->tpl_bool = Array(); + $this->tpl_strings = Array(); + $this->sidebar_extra = ''; + $this->toolbar_menu = ''; + $this->additional_headers = ''; + $this->plugin_blocks = Array(); + $this->plugin_blocks_content = array(); + $this->theme_loaded = false; + + $this->theme_list = Array(); + $this->named_theme_list = Array(); + + $this->vars_assign_history = array( + 'strings' => array(), + 'bool' => array() + ); + + if ( defined('IN_ENANO_UPGRADE') ) + { + return $this->construct_compat(); + } + + if ( !$this->theme_list = $cache->fetch('themes') ) + { + $q = $db->sql_query('SELECT theme_id, theme_name, enabled, default_style, group_policy, group_list FROM ' . table_prefix . 'themes;'); + if ( !$q ) + $db->_die('template.php selecting theme list'); + + $i = 0; + while ( $row = $db->fetchrow() ) + { + $this->theme_list[$i] = $row; + $i++; + } + unset($theme); + $this->theme_list = array_values($this->theme_list); + $cache->store('themes', $this->theme_list, -1); + } + + // Create associative array of themes + foreach ( $this->theme_list as $i => &$theme ) + $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; + + unset($theme); + + $this->default_theme = ( $_ = getConfig('theme_default') ) ? $_ : $this->theme_list[0]['theme_id']; + $this->named_theme_list[ $this->default_theme ]['css'] = $this->get_theme_css_files($this->default_theme); + // Come up with the default style. If the CSS file specified in default_style exists, we're good, just + // use that. Otherwise, use the first stylesheet that comes to mind. + $df_data =& $this->named_theme_list[ $this->default_theme ]; + $this->default_style = ( in_array($df_data['default_style'], $df_data['css']) ) ? $df_data['default_style'] : $df_data['css'][0]; + } + + /** + * Gets the list of available CSS files (styles) for the specified theme. + * @param string Theme ID + * @return array + */ + + function get_theme_css_files($theme_id) + { + $css = array(); + $dir = ENANO_ROOT . "/themes/{$theme_id}/css"; + if ( $dh = @opendir($dir) ) + { + while ( ( $file = @readdir($dh) ) !== false ) + { + if ( preg_match('/\.css$/', $file) ) + $css[] = preg_replace('/\.css$/', '', $file); + } + closedir($dh); + } + // No CSS files? If so, nuke it. + if ( count($css) < 1 ) + { + unset($this->theme_list[$theme_id]); + } + return $css; + } + + /** + * Failsafe constructor for upgrades. + */ + + function construct_compat() + { + global $db, $session, $paths, $template, $plugins; // Common objects + $this->tpl_bool = Array(); + $this->tpl_strings = Array(); + $this->sidebar_extra = ''; + $this->toolbar_menu = ''; + $this->additional_headers = ''; + $this->plugin_blocks = Array(); + $this->theme_loaded = false; + + $this->fading_button = '
+  +
'; + + $this->theme_list = Array(); + $this->named_theme_list = Array(); + + $q = $db->sql_query('SELECT theme_id, theme_name, enabled, default_style FROM ' . table_prefix . 'themes;'); + if ( !$q ) + $db->_die('template.php selecting theme list'); + + $i = 0; + while ( $row = $db->fetchrow() ) + { + $this->theme_list[$i] = $row; + $i++; + } + // List out all CSS files for this theme + foreach ( $this->theme_list as $i => &$theme ) + { + $theme['css'] = array(); + $dir = ENANO_ROOT . "/themes/{$theme['theme_id']}/css"; + if ( $dh = @opendir($dir) ) + { + while ( ( $file = @readdir($dh) ) !== false ) + { + if ( preg_match('/\.css$/', $file) ) + $theme['css'][] = preg_replace('/\.css$/', '', $file); + } + closedir($dh); + } + // No CSS files? If so, nuke it. + if ( count($theme['css']) < 1 ) + { + unset($this->theme_list[$i]); + } + } + $this->theme_list = array_values($this->theme_list); + // Create associative array of themes + foreach ( $this->theme_list as $i => &$theme ) + $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; + + $this->default_theme = ( $_ = getConfig('theme_default') ) ? $_ : $this->theme_list[0]['theme_id']; + // Come up with the default style. If the CSS file specified in default_style exists, we're good, just + // use that. Otherwise, use the first stylesheet that comes to mind. + $df_data =& $this->named_theme_list[ $this->default_theme ]; + $this->default_style = ( in_array($df_data['default_style'], $df_data['css']) ) ? $df_data['default_style'] : $df_data['css'][0]; + } + + /** + * Systematically deletes themes from available list if they're blocked by theme security settings. Called when session->start() finishes. + */ + + function process_theme_acls() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + // generate the fading button - needs to be done after sessions are started + $admintitle = ( $session->user_level >= USER_LEVEL_ADMIN && is_object(@$lang) ) ? ' title="' . $lang->get('sidebar_btn_enanopowered_admin_tip') . '"' : ''; + $this->fading_button = '
+  +
'; + + // For each theme, check ACLs and delete from RAM if not authorized + foreach ( $this->theme_list as $i => $theme ) + { + if ( !@$theme['group_list'] ) + continue; + if ( $theme['theme_id'] === getConfig('theme_default') ) + continue; + switch ( $theme['group_policy'] ) + { + case 'allow_all': + // Unconditionally allowed + continue; + break; + case 'whitelist': + // If we're not on the list, off to the left please + $list = enano_json_decode($theme['group_list']); + $allowed = false; + foreach ( $list as $acl ) + { + if ( !preg_match('/^(u|g):([0-9]+)$/', $acl, $match) ) + // Invalid list entry, silently allow (maybe not a good idea but + // really, these things are checked before they're inserted) + continue 2; + $mode = $match[1]; + $id = intval($match[2]); + switch ( $mode ) + { + case 'u': + $allowed = ( $id == $session->user_id ); + if ( $allowed ) + break 2; + break; + case 'g': + $allowed = ( isset($session->groups[$id]) ); + if ( $allowed ) + break 2; + } + } + if ( !$allowed ) + { + unset($this->theme_list[$i]); + } + break; + case 'blacklist': + // If we're ON the list, off to the left please + $list = enano_json_decode($theme['group_list']); + $allowed = true; + foreach ( $list as $acl ) + { + if ( !preg_match('/^(u|g):([0-9]+)$/', $acl, $match) ) + // Invalid list entry, silently allow (maybe not a good idea but + // really, these things are checked before they're inserted) + continue 2; + $mode = $match[1]; + $id = intval($match[2]); + switch ( $mode ) + { + case 'u': + $allowed = ( $id != $session->user_id ); + if ( !$allowed ) + break 2; + break; + case 'g': + $allowed = ( !isset($session->groups[$id]) ); + if ( !$allowed ) + break 2; + } + } + if ( !$allowed ) + { + unset($this->theme_list[$i]); + } + break; + } + } + + $this->theme_list = array_values($this->theme_list); + + // Rebuild associative theme list + $this->named_theme_list = array(); + foreach ( $this->theme_list as $i => &$theme ) + $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; + } + + /** + * Register a new sidebar block. + * @param string Block title + * @param string Block HTML + * @param bool If true, the class of the block will be the same as the one used for blocks that are a list of links instead of HTML content. This can do some wacky things like make all your s block level. + */ + + function sidebar_widget($t, $h, $use_normal_section = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + if ( !$this->theme_loaded ) + { + $this->load_theme($session->theme, $session->style); + } + if(!$this->sidebar_widgets) + $this->sidebar_widgets = ''; + $tplvars = $this->extract_vars('elements.tpl'); + + if ( $use_normal_section ) + { + $parser = $this->makeParserText($tplvars['sidebar_section']); + } + else + { + $parser = $this->makeParserText($tplvars['sidebar_section_raw']); + } + + $parser->assign_vars(Array('TITLE' => '{TITLE}','CONTENT' => $h)); + $this->plugin_blocks[$t] = $parser->run(); + $this->plugin_blocks_content[$t] = $h; + $this->sidebar_widgets .= $parser->run(); + } + function add_header($html) + { + /* debug only ** + $bt = debug_backtrace(); + $bt = $bt[1]; + $this->additional_headers .= "\n \n " . $html; + */ + $this->additional_headers .= "\n " . $html; + } + function get_css($s = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $this->init_vars(); + + $path = ( $s ) ? 'css/'.$s : 'css/'.$this->style.'.css'; + + if ( !file_exists(ENANO_ROOT . '/themes/' . $this->theme . '/' . $path) ) + { + echo "/* WARNING: Falling back to default file because file $path does not exist */\n"; + $path = 'css/' . $this->style_list[0] . '.css'; + } + + return $this->process_template($path); + } + function load_theme($name = false, $css = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $this->theme = ( $name ) ? $name : $session->theme; + $this->style = ( $css ) ? $css : $session->style; + if ( !$this->theme ) + { + $this->theme = $this->theme_list[0]['theme_id']; + $this->style = preg_replace('/\.css$/', '', $this->theme_list[0]['default_style']); + } + // Make sure we're allowed to use this theme. + if ( ( + // If it was removed, it's probably blocked by an ACL, or it was uninstalled + !isset($this->named_theme_list[$this->theme]) || + // Check if the theme is disabled + ( isset($this->named_theme_list[$this->theme]) && isset($this->named_theme_list[$this->theme]['enabled']) && $this->named_theme_list[$this->theme]['enabled'] == 0 ) ) + // Above all, if it's a system theme, don't inhibit the loading process. + && !in_array($this->theme, $this->system_themes) + ) + { + // No, something is preventing it - fall back to site default + $this->theme = $this->default_theme; + + // Come up with the default style. If the CSS file specified in default_style exists, we're good, just + // use that. Otherwise, use the first stylesheet that comes to mind. + $df_data =& $this->named_theme_list[ $this->theme ]; + $this->style = ( in_array($df_data['default_style'], $df_data['css']) ) ? $df_data['default_style'] : $df_data['css'][0]; + } + // The list of styles for the currently selected theme + $this->style_list =& $this->named_theme_list[ $this->theme ]['css']; + $this->theme_loaded = true; + } + + /** + * Change the theme we're supposed to display. + * @param string Theme name + * @param string Style name; optional + */ + + function set_theme($theme = false, $style = false) + { + $this->theme_initted = false; + $this->load_theme($theme, $style); + } + + /** + * Change the page we're supposed to generate for + * @param mixed Page ID *or* PageProcessor. If a PageProcessor, pulls permission info and such from that; if not, starts a PageProcessor. YOU SHOULD USE A PageProcessor WHENEVER POSSIBLE! It improves efficiency. + * @param string Namespace; not required if including a PageProcessor. + */ + + function set_page($page_id_or_pp, $namespace = false) + { + if ( is_object($page_id_or_pp) && get_class($page_id_or_pp) === 'PageProcessor' ) + { + $this->page_initted = false; + $page =& $page_id_or_pp; + $this->page = $page; + $this->page_id = $page->page_id; + $this->namespace = $page->namespace; + } + else if ( is_string($page_id_or_pp) ) + { + if ( !is_string($namespace) ) + return false; + + if ( $page_id_or_pp === $this->page_id && $namespace === $this->namespace ) + return true; + + $this->page_initted = false; + $this->page = false; + $this->page_id = sanitize_page_id($page_id_or_pp); + $this->namespace = $namespace; + } + else + { + return false; + } + return true; + } + + /** + * Queue a Javascript file to be loaded with the page instead of on demand. + * @param mixed Javascript file string or array thereof, extensions are optional + * @example + + $template->preload_js(array('jquery', 'jquery-ui')); + $template->preload_js('admin-menu.js'); + + * @return null + */ + + function preload_js($filemixed) + { + if ( is_string($filemixed) ) + $files = array($filemixed); + else if ( is_array($filemixed) ) + $files = $filemixed; + else + // :-/ + return null; + + $this->js_preload = array_values(array_merge($this->js_preload, $files)); + } + + /** + * Queue some HTML to be inserted after the Javascript runtime. + * @param string HTML glob + */ + + function add_header_js($html) + { + $this->js_append .= "$html\n "; + } + + /** + * Global, only-called-once init. Goes to all themes. + */ + + function init_global_vars() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + global $email; + + $is_opera = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')) ? true : false; + $is_msie = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? true : false; + + $this->assign_bool(array( + 'auth_admin' => $session->user_level >= USER_LEVEL_ADMIN ? true : false, + 'user_logged_in' => $session->user_logged_in, + 'opera' => $is_opera, + 'msie' => $is_msie + )); + + if ( $session->sid_super ) + { + $ash = '&auth=' . $session->sid_super; + $asq = "?auth=" . $session->sid_super; + $asa = "&auth=" . $session->sid_super; + $as2 = htmlspecialchars(urlSeparator) . 'auth='.$session->sid_super; + } + else + { + $asq = ''; + $asa = ''; + $as2 = ''; + $ash = ''; + } + + // Append the Enano version to URLs to break the cache on upgrades + $enano_version = enano_version(); + + // Set up javascript includes + // these depend heavily on whether we have a CDN to work with or not + if ( getConfig('cdn_path') ) + { + // we're on a CDN, point to static includes + // CLI javascript compression script: includes/clientside/jscompress.php + $js_head = ''; + + if ( !empty($this->js_preload) ) + { + $loadlines = array(); + + // make unique + foreach ( $this->js_preload as &$script ) + { + $script = preg_replace('/\.js$/', '', $script) . '.js'; + } + unset($script); + $this->js_preload = array_unique($this->js_preload); + + foreach ( $this->js_preload as $script ) + { + $js_head .= "\n "; + // special case for l10n: also load strings + if ( $script == 'l10n.js' ) + { + global $lang; + $js_head .= "\n "; + } + $loadlines[] = "loaded_components['$script'] = true;"; + } + + // tell the system that this stuff is already loaded + $loadlines = implode("\n ", $loadlines); + $js_head .= "\n "; + } + + $js_foot = << + // This initializes the Javascript runtime when the DOM is ready - not when the page is + // done loading, because enano-lib-basic still has to load some 15 other script files + // check for the init function - this is a KHTML fix + // This doesn't seem to work properly in IE in 1.1.x - there are some problems with + // tinyMCE and l10n. + if ( typeof ( enano_init ) == 'function' && !IE ) + { + enano_init(); + window.onload = function(e) { }; + } + + $this->js_append JSEOF; - } - else - { - $cdnpath = cdnPath; - $js_head = ''; - - // point to jsres compressor - $js_head .= << - + } + else + { + $cdnpath = cdnPath; + $js_head = ''; + + // point to jsres compressor + $js_head .= << + JSEOF; - $js_foot = ''; - - if ( !empty($this->js_preload) ) - { - foreach ( $this->js_preload as &$script ) - { - $script = preg_replace('/\.js$/', '', $script) . '.js'; - } - $this->js_preload = array_unique($this->js_preload); - if ( in_array('l10n.js', $this->js_preload) ) - { - // special case for l10n: also load strings - global $lang; - $js_foot .= "\n "; - } - $scripts = implode(',', $this->js_preload); - $js_foot .= "\n "; - - } - - $js_foot .= << - - - $this->js_append + $js_foot = ''; + + if ( !empty($this->js_preload) ) + { + foreach ( $this->js_preload as &$script ) + { + $script = preg_replace('/\.js$/', '', $script) . '.js'; + } + $this->js_preload = array_unique($this->js_preload); + if ( in_array('l10n.js', $this->js_preload) ) + { + // special case for l10n: also load strings + global $lang; + $js_foot .= "\n "; + } + $scripts = implode(',', $this->js_preload); + $js_foot .= "\n "; + + } + + $js_foot .= << + + + $this->js_append JSEOF; - } - - - $this->assign_bool(array( - 'fixed_menus' => false, - 'export' => false, - 'right_sidebar' => true, - 'enable_uploads' => ( getConfig('enable_uploads') == '1' && $session->get_permissions('upload_files') ) ? true : false, - 'stupid_mode' => false, - )); - - // Add the e-mail address client code to the header - $this->add_header($email->jscode()); - - // Assign our main variables - $this->assign_vars(array( - 'SITE_NAME' => htmlspecialchars(getConfig('site_name')), - 'USERNAME' => $session->username, - 'SITE_DESC' => htmlspecialchars(getConfig('site_desc')), - 'SCRIPTPATH' => scriptPath, - 'CONTENTPATH' => contentPath, - 'CDNPATH' => cdnPath, - 'ADMIN_SID_QUES' => $asq, - 'ADMIN_SID_AMP' => $asa, - 'ADMIN_SID_AMP_HTML' => $ash, - 'ADMIN_SID_AUTO' => $as2, - 'ADMIN_SID_RAW' => ( is_string($session->sid_super) ? $session->sid_super : '' ), - 'CSRF_TOKEN' => $session->csrf_token, - 'COPYRIGHT' => RenderMan::parse_internal_links(getConfig('copyright_notice')), - 'REQUEST_URI' => ( defined('ENANO_CLI') ? '' : $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'] ), - 'SEARCH_ACTION' => makeUrlNS('Special', 'Search'), - 'INPUT_TITLE' => ( urlSeparator == '&' ? '' : ''), - 'INPUT_AUTH' => ( $session->sid_super ? '' : ''), - 'MAIN_PAGE' => get_main_page(), - 'UNREAD_PMS' => $session->unread_pms, - 'JS_HEADER' => $js_head, - 'JS_FOOTER' => $js_foot, - 'URL_ABOUT_ENANO' => makeUrlNS('Special', 'About_Enano', '', true), - 'ENANO_VERSION' => enano_version() - ), true); - - $tpl_strings = array(); - foreach ( $paths->nslist as $ns_id => $ns_prefix ) - { - $tpl_strings[ 'NS_' . strtoupper($ns_id) ] = $ns_prefix; - } - - $this->assign_vars($tpl_strings, true); - } - - /** - * Init theme vars, like sidebar, global JS, that kind of stuff. - */ - - function init_theme_vars() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - // allows conditional testing of the theme ID (a bit crude, came from my NSIS days) - $this->assign_bool(array( - "theme_is_{$this->theme}" => true - )); - - $this->elements = $this->extract_vars('elements.tpl'); - - // Generate the code for the Administration and Edit Sidebar buttons - // Once again, the new template parsing system can be used here - - $parser = $this->makeParserText($this->elements['sidebar_button']); - - $parser->assign_vars(Array( - 'HREF'=>makeUrlNS('Special', 'Administration'), - 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { void(ajaxStartAdminLogin()); return false; }"', - 'TEXT'=>$lang->get('sidebar_btn_administration'), - )); - - $admin_link = $parser->run(); - - $parser->assign_vars(Array( - 'HREF'=>makeUrlNS('Special', 'EditSidebar'), - 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { void(ajaxLoginNavTo(\'Special\', \'EditSidebar\', ' . USER_LEVEL_ADMIN . ')); return false; }"', - 'TEXT'=>$lang->get('sidebar_btn_editsidebar'), - )); - - $sidebar_link = $parser->run(); - - $this->assign_vars(array( - 'ADMIN_LINK' => $admin_link, - 'SIDEBAR_LINK' => $sidebar_link, - 'THEME_ID' => $this->theme, - 'STYLE_ID' => $this->style - )); - - // Add the site description sidebar block - $this->sidebar_widget($lang->get('sidebar_title_about'), '

' . htmlspecialchars(getConfig('site_desc')) . '

'); - - $this->theme_initted = true; - } - - /** - * Init page vars, like the toolbar, local JS, etc. - */ - - function init_page_vars() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if ( !$this->page ) - { - $this->page = new PageProcessor($this->page_id, $this->namespace); - } - - $conds = $this->page->ns->get_conds(); - - $this->assign_bool(array( - 'in_admin' => ( ( $this->page_id == 'Administration' && $this->namespace == 'Special' ) || $this->namespace == 'Admin' ), - 'auth_rename' => ( $conds['rename'] ) - )); - - // Get the "article" button text (depends on namespace) - switch ( $this->namespace ) - { - case "Article": - default: - $ns = $lang->get('onpage_lbl_page_article'); - break; - case "Admin": - $ns = $lang->get('onpage_lbl_page_admin'); - break; - case "System": - $ns = $lang->get('onpage_lbl_page_system'); - break; - case "File": - $ns = $lang->get('onpage_lbl_page_file'); - break; - case "Help": - $ns = $lang->get('onpage_lbl_page_help'); - break; - case "User": - $ns = $lang->get('onpage_lbl_page_user'); - break; - case "Special": - $ns = $lang->get('onpage_lbl_page_special'); - break; - case "Template": - $ns = $lang->get('onpage_lbl_page_template'); - break; - case "Project": - $ns = $lang->get('onpage_lbl_page_project'); - break; - case "Category": - $ns = $lang->get('onpage_lbl_page_category'); - break; - case "API": - $ns = $lang->get('onpage_lbl_page_external'); - break; - } - $this->namespace_string = $ns; - unset($ns); - // compatibility - $local_namespace =& $this->namespace; - $local_page_id =& $this->page_id; - $code = $plugins->setHook('page_type_string_set'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - $ns =& $this->namespace_string; - - // - // PAGE TOOLBAR (on-page controls/actions) - // - - $local_page = $paths->get_pathskey($this->page_id, $this->namespace); - $local_cdata = $this->page->ns->get_cdata(); - - // Initialize the toolbar - $tb = ''; - $this->toolbar_menu = ''; - - // Create "xx page" button - - $btn_selected = ( isset($this->elements['toolbar_button_selected'])) ? $this->elements['toolbar_button_selected'] : $this->elements['toolbar_button']; - $parser = $this->makeParserText($btn_selected); - - if ( $conds['article'] ) - { - $parser->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxReset()); return false; }" title="' . $lang->get('onpage_tip_article') . '" accesskey="a"', - 'PARENTFLAGS' => 'id="mdgToolbar_article"', - 'HREF' => makeUrl($local_page, null, true), - 'TEXT' => $this->namespace_string - )); - - $tb .= $parser->run(); - } - - $button = $this->makeParserText($this->elements['toolbar_button']); - - // Page toolbar - // Comments button - if ( $conds['comments'] ) - { - $cdata = $this->page->ns->get_cdata(); - if ( isset($cdata['comments_approved']) ) - { - $approval_counts = array( - COMMENT_APPROVED => $cdata['comments_approved'], - COMMENT_UNAPPROVED => $cdata['comments_unapproved'], - COMMENT_SPAM => $cdata['comments_spam'] - ); - $num_comments = $session->check_acl_scope('mod_comments', $this->namespace) && $this->page->perms->get_permissions('mod_comments') - ? array_sum($approval_counts) - : $approval_counts[COMMENT_APPROVED]; - } - else - { - $e = $db->sql_query('SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$this->page_id.'\' AND namespace=\''.$this->namespace.'\';'); - if ( !$e ) - { - $db->_die(); - } - $num_comments = $db->numrows(); - $approval_counts = array(COMMENT_UNAPPROVED => 0, COMMENT_APPROVED => 0, COMMENT_SPAM => 0); - - while ( $r = $db->fetchrow() ) - { - $approval_counts[$r['approved']]++; - } - } - - $db->free_result(); - // $n = ( $session->check_acl_scope('mod_comments', $this->namespace) && $perms->get_permissions('mod_comments') ) ? (string)$num_comments : (string)$na; - if ( $session->check_acl_scope('mod_comments', $this->namespace) && $this->page->perms->get_permissions('mod_comments') && ( $approval_counts[COMMENT_UNAPPROVED] + $approval_counts[COMMENT_SPAM] ) > 0 ) - { - $subst = array( - 'num_comments' => $num_comments, - 'num_app' => $approval_counts[COMMENT_APPROVED], - 'num_unapp' => $approval_counts[COMMENT_UNAPPROVED], - 'num_spam' => $approval_counts[COMMENT_SPAM] - ); - $btn_text = $lang->get('onpage_btn_discussion_unapp', $subst); - } - else - { - $subst = array( - 'num_comments' => $num_comments - ); - $btn_text = $lang->get('onpage_btn_discussion', $subst); - } - - $button->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxComments()); return false; }" title="' . $lang->get('onpage_tip_comments') . '" accesskey="c"', - 'PARENTFLAGS' => 'id="mdgToolbar_discussion"', - 'HREF' => makeUrl($local_page, 'do=comments', true), - 'TEXT' => $btn_text, - )); - - $tb .= $button->run(); - } - // Edit button - if( $conds['edit'] ) - { - $button->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxEditor()); return false; }" title="' . $lang->get('onpage_tip_edit') . '" accesskey="e"', - 'PARENTFLAGS' => 'id="mdgToolbar_edit"', - 'HREF' => makeUrl($local_page, 'do=edit', true), - 'TEXT' => $lang->get('onpage_btn_edit') - )); - $tb .= $button->run(); - // View source button - } - else if ( $conds['viewsource'] ) - { - $button->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxEditor()); return false; }" title="' . $lang->get('onpage_tip_viewsource') . '" accesskey="e"', - 'PARENTFLAGS' => 'id="mdgToolbar_edit"', - 'HREF' => makeUrl($local_page, 'do=viewsource', true), - 'TEXT' => $lang->get('onpage_btn_viewsource') - )); - $tb .= $button->run(); - } - // History button - if ( $conds['history'] ) - { - $button->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxHistory()); return false; }" title="' . $lang->get('onpage_tip_history') . '" accesskey="h"', - 'PARENTFLAGS' => 'id="mdgToolbar_history"', - 'HREF' => makeUrl($local_page, 'do=history', true), - 'TEXT' => $lang->get('onpage_btn_history') - )); - $tb .= $button->run(); - } - - $menubtn = $this->makeParserText($this->elements['toolbar_menu_button']); - - // Additional actions menu - // Rename button - if ( $conds['rename'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxRename()); return false; }" title="' . $lang->get('onpage_tip_rename') . '" accesskey="r"', - 'HREF' => makeUrl($local_page, 'do=rename', true), - 'TEXT' => $lang->get('onpage_btn_rename'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - // Vote-to-delete button - if ( $conds['delvote'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxDelVote()); return false; }" title="' . $lang->get('onpage_tip_delvote') . '" accesskey="d"', - 'HREF' => makeUrl($local_page, 'do=delvote', true), - 'TEXT' => $lang->get('onpage_btn_votedelete'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - // Clear-votes button - if ( $conds['resetvotes'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxResetDelVotes()); return false; }" title="' . $lang->get('onpage_tip_resetvotes') . '" accesskey="y"', - 'HREF' => makeUrl($local_page, 'do=resetvotes', true), - 'TEXT' => $lang->get('onpage_btn_votedelete_reset'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - // Printable page button - if ( $conds['printable'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'title="' . $lang->get('onpage_tip_printable') . '"', - 'HREF' => makeUrl($local_page, 'printable=yes', true), - 'TEXT' => $lang->get('onpage_btn_printable'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - // Protect button - if ( $conds['protect'] ) - { - switch($this->page->ns->cdata['protected']) - { - case PROTECT_FULL: $protect_status = $lang->get('onpage_btn_protect_on'); break; - case PROTECT_SEMI: $protect_status = $lang->get('onpage_btn_protect_semi'); break; - case PROTECT_NONE: $protect_status = $lang->get('onpage_btn_protect_off'); break; - } - - $label = $this->makeParserText($this->elements['toolbar_label']); - $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_protect') . ' ' . "$protect_status")); - $t0 = $label->run(); - - $menubtn->assign_vars(array( - 'FLAGS' => 'accesskey="p" onclick="ajaxProtect(' . $this->page->ns->cdata['protected'] . '); return false;" id="tb_ajax_protect_btn" title="' . $lang->get('onpage_tip_protect') . '"', - 'HREF' => makeUrl($local_page, 'do=protect', true), - 'TEXT' => $lang->get('onpage_btn_protect_change') - )); - $t1 = $menubtn->run(); - - $this->toolbar_menu .= ' - - - - -
'.$t0.''.$t1.'
'; - } - - // Wiki mode button - if ( $conds['setwikimode'] ) - { - // label at start - $label = $this->makeParserText($this->elements['toolbar_label']); - $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_wikimode'))); - $t0 = $label->run(); - - // on button - $ctmp = ''; - if ( $local_cdata['wiki_mode'] == 1 ) - { - $ctmp = ' style="text-decoration: underline;"'; - } - $menubtn->assign_vars(array( - 'FLAGS' => $ctmp, - 'HREF' => makeUrl($local_page, 'do=setwikimode&level=1', true), - 'TEXT' => $lang->get('onpage_btn_wikimode_on') - )); - $t1 = $menubtn->run(); - - // off button - $ctmp = ''; - if ( $local_cdata['wiki_mode'] == 0 ) - { - $ctmp=' style="text-decoration: underline;"'; - } - $menubtn->assign_vars(array( - 'FLAGS' => $ctmp, - 'HREF' => makeUrl($local_page, 'do=setwikimode&level=0', true), - 'TEXT' => $lang->get('onpage_btn_wikimode_off') - )); - $t2 = $menubtn->run(); - - // global button - $ctmp = ''; - if ( $local_cdata['wiki_mode'] == 2 ) - { - $ctmp=' style="text-decoration: underline;"'; - } - $menubtn->assign_vars(array( - 'FLAGS' => $ctmp, - 'HREF' => makeUrl($local_page, 'do=setwikimode&level=2', true), - 'TEXT' => $lang->get('onpage_btn_wikimode_global') - )); - $t3 = $menubtn->run(); - - // Tack it onto the list of buttons that are already there... - $this->toolbar_menu .= ' - - - - - - -
'.$t0.''.$t1.''.$t2.''.$t3.'
'; - } - - // Clear logs button - if ( $conds['clearlogs'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxClearLogs()); return false; }" title="' . $lang->get('onpage_tip_flushlogs') . '" accesskey="l"', - 'HREF' => makeUrl($local_page, 'do=flushlogs', true), - 'TEXT' => $lang->get('onpage_btn_clearlogs'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - // Delete page button - if ( $conds['delete'] ) - { - $s = $lang->get('onpage_btn_deletepage'); - if ( $this->page->ns->cdata['delvotes'] == 1 ) - { - $subst = array( - 'num_votes' => $this->page->ns->cdata['delvotes'], - 'plural' => '' - ); - $s .= $lang->get('onpage_btn_deletepage_votes', $subst); - } - else if ( $this->page->ns->cdata['delvotes'] > 1 ) - { - $subst = array( - 'num_votes' => $this->page->ns->cdata['delvotes'], - 'plural' => $lang->get('meta_plural') - ); - $s .= $lang->get('onpage_btn_deletepage_votes', $subst); - } - - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxDeletePage()); return false; }" title="' . $lang->get('onpage_tip_deletepage') . '" accesskey="k"', - 'HREF' => makeUrl($local_page, 'do=deletepage', true), - 'TEXT' => $s, - )); - $this->toolbar_menu .= $menubtn->run(); - - } - - // Password-protect button - if ( $conds['password'] ) - { - // label at start - $label = $this->makeParserText($this->elements['toolbar_label']); - $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_password'))); - $t0 = $label->run(); - - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxSetPassword()); return false; }" title="' . $lang->get('onpage_tip_password') . '"', - 'HREF' => '#', - 'TEXT' => $lang->get('onpage_btn_password_set'), - )); - $t = $menubtn->run(); - - $this->toolbar_menu .= '
'.$t0.''.$t.'
'; - } - - // Manage ACLs button - if ( $conds['acledit'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { var s = ajaxOpenACLManager(); console.debug(s); return false; }" title="' . $lang->get('onpage_tip_aclmanager') . '" accesskey="m"', - 'HREF' => makeUrl($local_page, 'do=aclmanager', true), - 'TEXT' => $lang->get('onpage_btn_acl'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - // Administer page button - if ( $conds['adminpage'] ) - { - $menubtn->assign_vars(array( - 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxAdminPage()); return false; }" title="' . $lang->get('onpage_tip_adminoptions') . '" accesskey="g"', - 'HREF' => makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'PageManager', true), - 'TEXT' => $lang->get('onpage_btn_admin'), - )); - $this->toolbar_menu .= $menubtn->run(); - } - - if ( strlen($this->toolbar_menu) > 0 ) - { - $button->assign_vars(array( - 'FLAGS' => 'id="mdgToolbar_moreoptions" onclick="if ( !KILL_SWITCH ) { return false; }" title="' . $lang->get('onpage_tip_moreoptions') . '"', - 'PARENTFLAGS' => '', - 'HREF' => makeUrl($local_page, 'do=moreoptions', true), - 'TEXT' => $lang->get('onpage_btn_moreoptions') - )); - $tb .= $button->run(); - } - - // Generate the code for the Log in, Log out, Change theme, Administration, and Edit Sidebar buttons - // Once again, the new template parsing system can be used here - - $parser = $this->makeParserText($this->elements['sidebar_button']); - - $parser->assign_vars(Array( - 'HREF'=>makeUrlNS('Special', "Logout/{$session->csrf_token}/{$local_page}"), - 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { mb_logout(); return false; }"', - 'TEXT'=>$lang->get('sidebar_btn_logout'), - )); - - $logout_link = $parser->run(); - - $parser->assign_vars(Array( - 'HREF'=>makeUrlNS('Special', 'Login/' . $local_page), - 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { ajaxStartLogin(); return false; }"' . ( $local_page_id == 'Login' && $local_namespace == 'Special' ? ' class="currentpage"' : '' ), - 'TEXT'=>$lang->get('sidebar_btn_login'), - )); - - $login_link = $parser->run(); - - $parser->assign_vars(Array( - 'HREF'=>makeUrlNS('Special', 'ChangeStyle/'.$local_page), - 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { ajaxChangeStyle(); return false; }"' . ( $local_page_id == 'ChangeStyle' && $local_namespace == 'Special' ? ' class="currentpage"' : '' ), - 'TEXT'=>$lang->get('sidebar_btn_changestyle'), - )); - - $theme_link = $parser->run(); - - // Run hooks - $code = $plugins->setHook('tpl_compile_toolbar'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - // - // ASSIGN VARIABLES - // - - $this->assign_vars(array( - 'PAGE_NAME' => htmlspecialchars($this->page->ns->cdata['name']), - 'PAGE_URLNAME' => $paths->nslist[$this->namespace] . sanitize_page_id($this->page_id), - 'TOOLBAR' => $tb, - 'TOOLBAR_EXTRAS' => $this->toolbar_menu, - 'STYLE_LINK' => makeUrlNS('Special', 'CSS', null, true), //contentPath.$paths->nslist['Special'].'CSS' . $p, - 'LOGIN_LINK' => $login_link, - 'LOGOUT_LINK' => $logout_link, - 'THEME_LINK' => $theme_link - ), true); - $this->page_initted = true; - } - - /** - * Generates and assigns the Javascript system variables - */ - - function generate_js_header() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $SID = ($session->sid_super) ? $session->sid_super : ''; - - $local_page = $paths->get_pathskey($this->page_id, $this->namespace); - $local_fullpage = $paths->get_pathskey($this->page_id, $this->namespace) . substr($paths->fullpage, strlen($paths->page)); - - $urlname_clean = str_replace('\'', '\\\'', str_replace('\\', '\\\\', dirtify_page_id($local_fullpage))); - $urlname_clean = strtr( $urlname_clean, array( '<' => '<', '>' => '>' ) ); - - $urlname_jssafe = sanitize_page_id($local_fullpage); - $physical_urlname_jssafe = sanitize_page_id($paths->fullpage); - - $protected = is_object($this->page) ? $this->page->ns->cdata['really_protected'] : false; - - // Generate the dynamic javascript vars - // Sorry. I know. This block is a mess. - $js_dynamic = ' "; - - $this->assign_vars(array( - 'JS_DYNAMIC_VARS' => $js_dynamic, - 'REPORT_URI' => makeUrl($local_fullpage, 'do=sql_report', true) - ), true); - } - - /** - * Fetches, parses, and assigns the sidebar. - */ - - function assign_sidebar() - { - // - // COMPILE THE SIDEBAR - // - - // This is done after the big assign_vars() so that sidebar code has access to the newly assigned variables - - list($this->tpl_strings['SIDEBAR_LEFT'], $this->tpl_strings['SIDEBAR_RIGHT'], $min) = $this->fetch_sidebar(); - $this->tpl_bool['sidebar_left'] = ( $this->tpl_strings['SIDEBAR_LEFT'] != $min) ? true : false; - $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != $min) ? true : false; - $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility - } - - /** - * Initializes all variables related to on-page content. This includes sidebars and what have you. - * @param object Optional PageProcessor object to use for passing metadata and permissions on. If omitted, uses information from $paths and $session. - * @param bool If true, re-inits even if already initted with this page_id and namespace - */ - - function init_vars($page = false, $force_init = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $need_shared_init = ( !$this->theme_initted || !$this->page_initted ); - - if ( $need_shared_init ) - { - if ( !$this->theme || !$this->style ) - { - $this->load_theme(); - } - $code = $plugins->setHook('compile_template', true); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - - if ( !$this->theme_loaded ) - $this->load_theme(); - - require(ENANO_ROOT . "/themes/{$this->theme}/theme.cfg"); - - if ( !$this->page_id || !$this->namespace ) - { - $this->page_id = $paths->page_id; - $this->namespace = $paths->namespace; - } - - profiler_log('template: prepped for var set (loaded theme, ran compile_template hook)'); - - $this->init_global_vars(); - profiler_log('template: global vars set'); - - if ( !$this->theme_initted ) - $this->init_theme_vars(); - - profiler_log('template: theme vars set'); - - if ( !$this->page_initted && !empty($this->namespace) ) - { - profiler_log('template: page vars set'); - $this->init_page_vars(); - } - else - { - profiler_message('template: skipped setting page vars'); - } - - // Perform shared init (combine javascript, etc.) - if ( $need_shared_init ) - { - $this->generate_js_header(); - $this->assign_sidebar(); - profiler_log('template: assigned sidebar and JS'); - } - - // and finally one string value that needs to be symlinked... - if ( !isset($this->tpl_strings['ADDITIONAL_HEADERS']) ) - { - $this->tpl_strings['ADDITIONAL_HEADERS'] =& $this->additional_headers; - } - - // done! - $code = $plugins->setHook('template_var_init_end'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - - function header($simple = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - define('ENANO_HEADERS_SENT', true); - - echo $this->getHeader($simple); - } - - function footer($simple = false) - { - echo $this->getFooter($simple); - } - - function getHeader($simple = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if ( !$this->theme_loaded ) - { - $this->load_theme($session->theme, $session->style); - } - - if ( !$this->page_initted || !$this->theme_initted ) - $this->init_vars(); - - // I feel awful doing this. - if ( preg_match('/^W3C_Validator/', @$_SERVER['HTTP_USER_AGENT']) ) - { - header('Content-type: application/xhtml+xml'); - } - - $header = ''; - - if ( !$this->no_headers ) - { - $header = ( $simple ) ? - $this->process_template('simple-header.tpl') : - $this->process_template('header.tpl'); - } - if ( !$simple && $session->user_logged_in && $session->unread_pms > 0 ) - { - $header .= $this->notify_unread_pms(); - } - if ( !$simple && $session->sw_timed_out ) - { - $login_link = makeUrlNS('Special', 'Login/' . $paths->fullpage, 'level=' . $session->user_level, true); - $header .= '
'; - $header .= $lang->get('user_msg_elev_timed_out', array( 'login_link' => $login_link )); - $header .= '
'; - } - if ( $this->site_disabled && $session->user_level >= USER_LEVEL_ADMIN && ( $paths->page != $paths->nslist['Special'] . 'Administration' ) ) - { - $admin_link = makeUrlNS('Special', 'Administration', 'module=' . $paths->nslist['Admin'] . 'GeneralConfig', true); - $header .= '
' . $lang->get('page_sitedisabled_admin_msg_title') . '
- ' . $lang->get('page_sitedisabled_admin_msg_body', array('admin_link' => $admin_link)) . ' -
'; - } - - return $header; - } - - function getFooter($simple = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - if ( !$this->no_headers ) - { - - global $_starttime; - if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc')) - { - echo '

' . $lang->get('page_heading_sql_list') . '

';
-        echo htmlspecialchars($db->sql_backtrace());
-        echo '
'; - } - - $t = ( $simple ) ? $this->process_template('simple-footer.tpl') : $this->process_template('footer.tpl'); - - $f = microtime_float(); - $f = $f - $_starttime; - $f = round($f, 2); - - $t_loc = $lang->get('page_msg_stats_gentime_short', array('time' => $f)); - $t_loc_long = $lang->get('page_msg_stats_gentime_long', array('time' => $f)); - $q_loc = '
' . $lang->get('page_msg_stats_sql', array('nq' => $db->num_queries)) . ''; - $dbg = $t_loc; - $dbg_long = $t_loc_long; - if ( $session->user_level >= USER_LEVEL_ADMIN || defined('ENANO_DEBUG') ) - { - $dbg .= "  |  $q_loc"; - $dbg_long .= "  |  $q_loc"; - } - - $t = str_replace('[[Stats]]', $dbg, $t); - $t = str_replace('[[StatsLong]]', $dbg_long, $t); - $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t); - $t = str_replace('[[GenTime]]', (string)$f, $t); - $t = str_replace('[[NumQueriesLoc]]', $q_loc, $t); - $t = str_replace('[[GenTimeLoc]]', $t_loc, $t); - $t = str_replace('[[EnanoPoweredLink]]', $lang->get('page_enano_powered', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); - $t = str_replace('[[EnanoPoweredLinkLong]]', $lang->get('page_enano_powered_long', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); - - if ( defined('ENANO_PROFILE') ) - { - $t = str_replace('', '
' . profiler_make_html() . '
', $t); - // ob_end_clean(); - // return profiler_make_html(); - } - - return $t; - } - else - { - return ''; - } - } - - /** - * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. - * @param $vars array - * @param $from_internal bool Internal switch, just omit (@todo document) - */ - - function assign_vars($vars, $from_internal = false) - { - foreach ( $vars as $key => $value ) - { - $replace = true; - if ( isset($this->vars_assign_history['strings'][$key]) ) - { - if ( $this->vars_assign_history['strings'][$key] == 'api' ) - { - $replace = false; - } - } - if ( $replace ) - { - $this->tpl_strings[$key] = $value; - $this->vars_assign_history['strings'][$key] = ( $from_internal ) ? 'internal' : 'api'; - } - } - } - - /** - * Assigns an array of boolean values to the template. These can be used for statements. - * @param $vars array - * @param $from_internal bool Internal switch, just omit (@todo document) - */ - - function assign_bool($vars, $from_internal = false) - { - foreach ( $vars as $key => $value ) - { - $replace = true; - if ( isset($this->vars_assign_history['bool'][$key]) ) - { - if ( $this->vars_assign_history['bool'][$key] == 'api' ) - { - $replace = false; - } - } - if ( $replace ) - { - $this->tpl_bool[$key] = $value; - $this->vars_assign_history['bool'][$key] = ( $from_internal ) ? 'internal' : 'api'; - } - } - } - - # - # COMPILER - # - - /** - * Compiles and executes a template based on the current variables and booleans. Loads - * the theme and initializes variables if needed. This mostly just calls child functions. - * @param string File to process - * @return string - */ - - function process_template($file) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - if ( !$this->theme_initted || !$this->page_initted ) - { - $this->init_vars(); - } - - $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $file) . '.php'; - if ( file_exists($cache_file) ) - { - // this is about the time of the breaking change to cache file format - if ( ($m = filemtime($cache_file)) > 1215038089 ) - { - $result = @include($cache_file); - if ( isset($md5) ) - { - if ( $m >= filemtime(ENANO_ROOT . "/themes/{$this->theme}/$file") ) - { - $result = $this->compile_template_text_post($result); - return $result; - } - } - } - } - - $compiled = $this->compile_template($file); - $result = eval($compiled); - - return $result; - } - - /** - * Loads variables from the specified template file. Returns an associative array containing the variables. - * @param string Template file to process (elements.tpl) - * @return array - */ - - function extract_vars($file) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - // Sometimes this function gets called before the theme is loaded - // This is a bad coding practice so this function will always be picky. - if ( !$this->theme ) - { - die('$template->extract_vars(): theme not yet loaded, so we can\'t open template files yet...this is a bug and should be reported.

Backtrace, most recent call first:
'.enano_debug_print_backtrace(true).'
'); - } - - // Full pathname of template file - $tpl_file_fullpath = ( strstr($file, '/') ) ? $file : ENANO_ROOT . '/themes/' . $this->theme . '/' . $file; - - // Make sure the template even exists - if ( !is_file($tpl_file_fullpath) ) - { - die_semicritical('Cannot find template file', - '

The template parser was asked to load the file "' . htmlspecialchars($tpl_file_fullpath) . '", but that file couldn\'t be found in the directory for - the current theme.

-

Additional debugging information:
- Theme currently in use: ' . $this->theme . '
- Requested file: ' . $file . ' -

'); - } - // Retrieve file contents - $text = file_get_contents($tpl_file_fullpath); - if ( !$text ) - { - return false; - } - - // Get variables, regular expressions FTW - preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches); - - // Initialize return values - $tplvars = Array(); - - // Loop through each match, setting $tplvars[ $first_subpattern ] to $second_subpattern - for ( $i = 0; $i < sizeof($matches[1]); $i++ ) - { - $tplvars[ $matches[1][$i] ] = $matches[2][$i]; - } - - // All done! - return $tplvars; - } - - /** - * Compiles a block of template code. - * @param string The text to process - * @return string - */ - - function compile_tpl_code($text) - { - return template_compiler_core($text); - } - - /** - * Compiles the contents of a given template file, possibly using a cached copy, and returns the compiled code. - * @param string Filename of template (header.tpl) - * @return string - */ - - function compile_template($filename) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - // Full path to template file - $tpl_file_fullpath = ENANO_ROOT . '/themes/' . $this->theme . '/' . $filename; - - // Make sure the file exists - if ( !is_file($tpl_file_fullpath) ) - { - die_semicritical('Cannot find template file', - '

The template parser was asked to load the file "' . htmlspecialchars($filename) . '", but that file couldn\'t be found in the directory for - the current theme.

-

Additional debugging information:
- Theme currently in use: ' . $this->theme . '
- Requested file: ' . $file . ' -

'); - } - - // We won't use the cached copy here. - $text = file_get_contents($tpl_file_fullpath); - - // This will be used later when writing the cached file - $md5 = md5($text); - - // Preprocessing and checks complete - compile the code - $text = $this->compile_tpl_code($text); - - // Generate cache filename - $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $filename) . '.php'; - - // Perhaps caching is enabled and the admin has changed the template? - if ( is_writable( ENANO_ROOT . '/cache/' ) && getConfig('cache_thumbs') == '1' ) - { - $h = fopen($cache_file, 'w'); - if ( !$h ) - { - // Couldn't open the file - silently ignore and return - return $text; - } - - // Final contents of cache file - $file_contents = <<assign_bool(array( + 'fixed_menus' => false, + 'export' => false, + 'right_sidebar' => true, + 'enable_uploads' => ( getConfig('enable_uploads') == '1' && $session->get_permissions('upload_files') ) ? true : false, + 'stupid_mode' => false, + )); + + // Add the e-mail address client code to the header + $this->add_header($email->jscode()); + + // Assign our main variables + $this->assign_vars(array( + 'SITE_NAME' => htmlspecialchars(getConfig('site_name')), + 'USERNAME' => $session->username, + 'SITE_DESC' => htmlspecialchars(getConfig('site_desc')), + 'SCRIPTPATH' => scriptPath, + 'CONTENTPATH' => contentPath, + 'CDNPATH' => cdnPath, + 'ADMIN_SID_QUES' => $asq, + 'ADMIN_SID_AMP' => $asa, + 'ADMIN_SID_AMP_HTML' => $ash, + 'ADMIN_SID_AUTO' => $as2, + 'ADMIN_SID_RAW' => ( is_string($session->sid_super) ? $session->sid_super : '' ), + 'CSRF_TOKEN' => $session->csrf_token, + 'COPYRIGHT' => RenderMan::parse_internal_links(getConfig('copyright_notice')), + 'REQUEST_URI' => ( defined('ENANO_CLI') ? '' : $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'] ), + 'SEARCH_ACTION' => makeUrlNS('Special', 'Search'), + 'INPUT_TITLE' => ( urlSeparator == '&' ? '' : ''), + 'INPUT_AUTH' => ( $session->sid_super ? '' : ''), + 'MAIN_PAGE' => get_main_page(), + 'UNREAD_PMS' => $session->unread_pms, + 'JS_HEADER' => $js_head, + 'JS_FOOTER' => $js_foot, + 'URL_ABOUT_ENANO' => makeUrlNS('Special', 'About_Enano', '', true), + 'ENANO_VERSION' => enano_version() + ), true); + + $tpl_strings = array(); + foreach ( $paths->nslist as $ns_id => $ns_prefix ) + { + $tpl_strings[ 'NS_' . strtoupper($ns_id) ] = $ns_prefix; + } + + $this->assign_vars($tpl_strings, true); + } + + /** + * Init theme vars, like sidebar, global JS, that kind of stuff. + */ + + function init_theme_vars() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + // allows conditional testing of the theme ID (a bit crude, came from my NSIS days) + $this->assign_bool(array( + "theme_is_{$this->theme}" => true + )); + + $this->elements = $this->extract_vars('elements.tpl'); + + // Generate the code for the Administration and Edit Sidebar buttons + // Once again, the new template parsing system can be used here + + $parser = $this->makeParserText($this->elements['sidebar_button']); + + $parser->assign_vars(Array( + 'HREF'=>makeUrlNS('Special', 'Administration'), + 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { void(ajaxStartAdminLogin()); return false; }"', + 'TEXT'=>$lang->get('sidebar_btn_administration'), + )); + + $admin_link = $parser->run(); + + $parser->assign_vars(Array( + 'HREF'=>makeUrlNS('Special', 'EditSidebar'), + 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { void(ajaxLoginNavTo(\'Special\', \'EditSidebar\', ' . USER_LEVEL_ADMIN . ')); return false; }"', + 'TEXT'=>$lang->get('sidebar_btn_editsidebar'), + )); + + $sidebar_link = $parser->run(); + + $this->assign_vars(array( + 'ADMIN_LINK' => $admin_link, + 'SIDEBAR_LINK' => $sidebar_link, + 'THEME_ID' => $this->theme, + 'STYLE_ID' => $this->style + )); + + // Add the site description sidebar block + $this->sidebar_widget($lang->get('sidebar_title_about'), '

' . htmlspecialchars(getConfig('site_desc')) . '

'); + + $this->theme_initted = true; + } + + /** + * Init page vars, like the toolbar, local JS, etc. + */ + + function init_page_vars() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if ( !$this->page ) + { + $this->page = new PageProcessor($this->page_id, $this->namespace); + } + + $conds = $this->page->ns->get_conds(); + + $this->assign_bool(array( + 'in_admin' => ( ( $this->page_id == 'Administration' && $this->namespace == 'Special' ) || $this->namespace == 'Admin' ), + 'auth_rename' => ( $conds['rename'] ) + )); + + // Get the "article" button text (depends on namespace) + switch ( $this->namespace ) + { + case "Article": + default: + $ns = $lang->get('onpage_lbl_page_article'); + break; + case "Admin": + $ns = $lang->get('onpage_lbl_page_admin'); + break; + case "System": + $ns = $lang->get('onpage_lbl_page_system'); + break; + case "File": + $ns = $lang->get('onpage_lbl_page_file'); + break; + case "Help": + $ns = $lang->get('onpage_lbl_page_help'); + break; + case "User": + $ns = $lang->get('onpage_lbl_page_user'); + break; + case "Special": + $ns = $lang->get('onpage_lbl_page_special'); + break; + case "Template": + $ns = $lang->get('onpage_lbl_page_template'); + break; + case "Project": + $ns = $lang->get('onpage_lbl_page_project'); + break; + case "Category": + $ns = $lang->get('onpage_lbl_page_category'); + break; + case "API": + $ns = $lang->get('onpage_lbl_page_external'); + break; + } + $this->namespace_string = $ns; + unset($ns); + // compatibility + $local_namespace =& $this->namespace; + $local_page_id =& $this->page_id; + $code = $plugins->setHook('page_type_string_set'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + $ns =& $this->namespace_string; + + // + // PAGE TOOLBAR (on-page controls/actions) + // + + $local_page = $paths->get_pathskey($this->page_id, $this->namespace); + $local_cdata = $this->page->ns->get_cdata(); + + // Initialize the toolbar + $tb = ''; + $this->toolbar_menu = ''; + + // Create "xx page" button + + $btn_selected = ( isset($this->elements['toolbar_button_selected'])) ? $this->elements['toolbar_button_selected'] : $this->elements['toolbar_button']; + $parser = $this->makeParserText($btn_selected); + + if ( $conds['article'] ) + { + $parser->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxReset()); return false; }" title="' . $lang->get('onpage_tip_article') . '" accesskey="a"', + 'PARENTFLAGS' => 'id="mdgToolbar_article"', + 'HREF' => makeUrl($local_page, null, true), + 'TEXT' => $this->namespace_string + )); + + $tb .= $parser->run(); + } + + $button = $this->makeParserText($this->elements['toolbar_button']); + + // Page toolbar + // Comments button + if ( $conds['comments'] ) + { + $cdata = $this->page->ns->get_cdata(); + if ( isset($cdata['comments_approved']) ) + { + $approval_counts = array( + COMMENT_APPROVED => $cdata['comments_approved'], + COMMENT_UNAPPROVED => $cdata['comments_unapproved'], + COMMENT_SPAM => $cdata['comments_spam'] + ); + $num_comments = $session->check_acl_scope('mod_comments', $this->namespace) && $this->page->perms->get_permissions('mod_comments') + ? array_sum($approval_counts) + : $approval_counts[COMMENT_APPROVED]; + } + else + { + $e = $db->sql_query('SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$this->page_id.'\' AND namespace=\''.$this->namespace.'\';'); + if ( !$e ) + { + $db->_die(); + } + $num_comments = $db->numrows(); + $approval_counts = array(COMMENT_UNAPPROVED => 0, COMMENT_APPROVED => 0, COMMENT_SPAM => 0); + + while ( $r = $db->fetchrow() ) + { + $approval_counts[$r['approved']]++; + } + } + + $db->free_result(); + // $n = ( $session->check_acl_scope('mod_comments', $this->namespace) && $perms->get_permissions('mod_comments') ) ? (string)$num_comments : (string)$na; + if ( $session->check_acl_scope('mod_comments', $this->namespace) && $this->page->perms->get_permissions('mod_comments') && ( $approval_counts[COMMENT_UNAPPROVED] + $approval_counts[COMMENT_SPAM] ) > 0 ) + { + $subst = array( + 'num_comments' => $num_comments, + 'num_app' => $approval_counts[COMMENT_APPROVED], + 'num_unapp' => $approval_counts[COMMENT_UNAPPROVED], + 'num_spam' => $approval_counts[COMMENT_SPAM] + ); + $btn_text = $lang->get('onpage_btn_discussion_unapp', $subst); + } + else + { + $subst = array( + 'num_comments' => $num_comments + ); + $btn_text = $lang->get('onpage_btn_discussion', $subst); + } + + $button->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxComments()); return false; }" title="' . $lang->get('onpage_tip_comments') . '" accesskey="c"', + 'PARENTFLAGS' => 'id="mdgToolbar_discussion"', + 'HREF' => makeUrl($local_page, 'do=comments', true), + 'TEXT' => $btn_text, + )); + + $tb .= $button->run(); + } + // Edit button + if( $conds['edit'] ) + { + $button->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxEditor()); return false; }" title="' . $lang->get('onpage_tip_edit') . '" accesskey="e"', + 'PARENTFLAGS' => 'id="mdgToolbar_edit"', + 'HREF' => makeUrl($local_page, 'do=edit', true), + 'TEXT' => $lang->get('onpage_btn_edit') + )); + $tb .= $button->run(); + // View source button + } + else if ( $conds['viewsource'] ) + { + $button->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxEditor()); return false; }" title="' . $lang->get('onpage_tip_viewsource') . '" accesskey="e"', + 'PARENTFLAGS' => 'id="mdgToolbar_edit"', + 'HREF' => makeUrl($local_page, 'do=viewsource', true), + 'TEXT' => $lang->get('onpage_btn_viewsource') + )); + $tb .= $button->run(); + } + // History button + if ( $conds['history'] ) + { + $button->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxHistory()); return false; }" title="' . $lang->get('onpage_tip_history') . '" accesskey="h"', + 'PARENTFLAGS' => 'id="mdgToolbar_history"', + 'HREF' => makeUrl($local_page, 'do=history', true), + 'TEXT' => $lang->get('onpage_btn_history') + )); + $tb .= $button->run(); + } + + $menubtn = $this->makeParserText($this->elements['toolbar_menu_button']); + + // Additional actions menu + // Rename button + if ( $conds['rename'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxRename()); return false; }" title="' . $lang->get('onpage_tip_rename') . '" accesskey="r"', + 'HREF' => makeUrl($local_page, 'do=rename', true), + 'TEXT' => $lang->get('onpage_btn_rename'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + // Vote-to-delete button + if ( $conds['delvote'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxDelVote()); return false; }" title="' . $lang->get('onpage_tip_delvote') . '" accesskey="d"', + 'HREF' => makeUrl($local_page, 'do=delvote', true), + 'TEXT' => $lang->get('onpage_btn_votedelete'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + // Clear-votes button + if ( $conds['resetvotes'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxResetDelVotes()); return false; }" title="' . $lang->get('onpage_tip_resetvotes') . '" accesskey="y"', + 'HREF' => makeUrl($local_page, 'do=resetvotes', true), + 'TEXT' => $lang->get('onpage_btn_votedelete_reset'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + // Printable page button + if ( $conds['printable'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'title="' . $lang->get('onpage_tip_printable') . '"', + 'HREF' => makeUrl($local_page, 'printable=yes', true), + 'TEXT' => $lang->get('onpage_btn_printable'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + // Protect button + if ( $conds['protect'] ) + { + switch($this->page->ns->cdata['protected']) + { + case PROTECT_FULL: $protect_status = $lang->get('onpage_btn_protect_on'); break; + case PROTECT_SEMI: $protect_status = $lang->get('onpage_btn_protect_semi'); break; + case PROTECT_NONE: $protect_status = $lang->get('onpage_btn_protect_off'); break; + } + + $label = $this->makeParserText($this->elements['toolbar_label']); + $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_protect') . ' ' . "$protect_status")); + $t0 = $label->run(); + + $menubtn->assign_vars(array( + 'FLAGS' => 'accesskey="p" onclick="ajaxProtect(' . $this->page->ns->cdata['protected'] . '); return false;" id="tb_ajax_protect_btn" title="' . $lang->get('onpage_tip_protect') . '"', + 'HREF' => makeUrl($local_page, 'do=protect', true), + 'TEXT' => $lang->get('onpage_btn_protect_change') + )); + $t1 = $menubtn->run(); + + $this->toolbar_menu .= ' + + + + +
'.$t0.''.$t1.'
'; + } + + // Wiki mode button + if ( $conds['setwikimode'] ) + { + // label at start + $label = $this->makeParserText($this->elements['toolbar_label']); + $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_wikimode'))); + $t0 = $label->run(); + + // on button + $ctmp = ''; + if ( $local_cdata['wiki_mode'] == 1 ) + { + $ctmp = ' style="text-decoration: underline;"'; + } + $menubtn->assign_vars(array( + 'FLAGS' => $ctmp, + 'HREF' => makeUrl($local_page, 'do=setwikimode&level=1', true), + 'TEXT' => $lang->get('onpage_btn_wikimode_on') + )); + $t1 = $menubtn->run(); + + // off button + $ctmp = ''; + if ( $local_cdata['wiki_mode'] == 0 ) + { + $ctmp=' style="text-decoration: underline;"'; + } + $menubtn->assign_vars(array( + 'FLAGS' => $ctmp, + 'HREF' => makeUrl($local_page, 'do=setwikimode&level=0', true), + 'TEXT' => $lang->get('onpage_btn_wikimode_off') + )); + $t2 = $menubtn->run(); + + // global button + $ctmp = ''; + if ( $local_cdata['wiki_mode'] == 2 ) + { + $ctmp=' style="text-decoration: underline;"'; + } + $menubtn->assign_vars(array( + 'FLAGS' => $ctmp, + 'HREF' => makeUrl($local_page, 'do=setwikimode&level=2', true), + 'TEXT' => $lang->get('onpage_btn_wikimode_global') + )); + $t3 = $menubtn->run(); + + // Tack it onto the list of buttons that are already there... + $this->toolbar_menu .= ' + + + + + + +
'.$t0.''.$t1.''.$t2.''.$t3.'
'; + } + + // Clear logs button + if ( $conds['clearlogs'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxClearLogs()); return false; }" title="' . $lang->get('onpage_tip_flushlogs') . '" accesskey="l"', + 'HREF' => makeUrl($local_page, 'do=flushlogs', true), + 'TEXT' => $lang->get('onpage_btn_clearlogs'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + // Delete page button + if ( $conds['delete'] ) + { + $s = $lang->get('onpage_btn_deletepage'); + if ( $this->page->ns->cdata['delvotes'] == 1 ) + { + $subst = array( + 'num_votes' => $this->page->ns->cdata['delvotes'], + 'plural' => '' + ); + $s .= $lang->get('onpage_btn_deletepage_votes', $subst); + } + else if ( $this->page->ns->cdata['delvotes'] > 1 ) + { + $subst = array( + 'num_votes' => $this->page->ns->cdata['delvotes'], + 'plural' => $lang->get('meta_plural') + ); + $s .= $lang->get('onpage_btn_deletepage_votes', $subst); + } + + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxDeletePage()); return false; }" title="' . $lang->get('onpage_tip_deletepage') . '" accesskey="k"', + 'HREF' => makeUrl($local_page, 'do=deletepage', true), + 'TEXT' => $s, + )); + $this->toolbar_menu .= $menubtn->run(); + + } + + // Password-protect button + if ( $conds['password'] ) + { + // label at start + $label = $this->makeParserText($this->elements['toolbar_label']); + $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_password'))); + $t0 = $label->run(); + + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxSetPassword()); return false; }" title="' . $lang->get('onpage_tip_password') . '"', + 'HREF' => '#', + 'TEXT' => $lang->get('onpage_btn_password_set'), + )); + $t = $menubtn->run(); + + $this->toolbar_menu .= '
'.$t0.''.$t.'
'; + } + + // Manage ACLs button + if ( $conds['acledit'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { var s = ajaxOpenACLManager(); console.debug(s); return false; }" title="' . $lang->get('onpage_tip_aclmanager') . '" accesskey="m"', + 'HREF' => makeUrl($local_page, 'do=aclmanager', true), + 'TEXT' => $lang->get('onpage_btn_acl'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + // Administer page button + if ( $conds['adminpage'] ) + { + $menubtn->assign_vars(array( + 'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxAdminPage()); return false; }" title="' . $lang->get('onpage_tip_adminoptions') . '" accesskey="g"', + 'HREF' => makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'PageManager', true), + 'TEXT' => $lang->get('onpage_btn_admin'), + )); + $this->toolbar_menu .= $menubtn->run(); + } + + if ( strlen($this->toolbar_menu) > 0 ) + { + $button->assign_vars(array( + 'FLAGS' => 'id="mdgToolbar_moreoptions" onclick="if ( !KILL_SWITCH ) { return false; }" title="' . $lang->get('onpage_tip_moreoptions') . '"', + 'PARENTFLAGS' => '', + 'HREF' => makeUrl($local_page, 'do=moreoptions', true), + 'TEXT' => $lang->get('onpage_btn_moreoptions') + )); + $tb .= $button->run(); + } + + // Generate the code for the Log in, Log out, Change theme, Administration, and Edit Sidebar buttons + // Once again, the new template parsing system can be used here + + $parser = $this->makeParserText($this->elements['sidebar_button']); + + $parser->assign_vars(Array( + 'HREF'=>makeUrlNS('Special', "Logout/{$session->csrf_token}/{$local_page}"), + 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { mb_logout(); return false; }"', + 'TEXT'=>$lang->get('sidebar_btn_logout'), + )); + + $logout_link = $parser->run(); + + $parser->assign_vars(Array( + 'HREF'=>makeUrlNS('Special', 'Login/' . $local_page), + 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { ajaxStartLogin(); return false; }"' . ( $local_page_id == 'Login' && $local_namespace == 'Special' ? ' class="currentpage"' : '' ), + 'TEXT'=>$lang->get('sidebar_btn_login'), + )); + + $login_link = $parser->run(); + + $parser->assign_vars(Array( + 'HREF'=>makeUrlNS('Special', 'ChangeStyle/'.$local_page), + 'FLAGS'=>'onclick="if ( !KILL_SWITCH ) { ajaxChangeStyle(); return false; }"' . ( $local_page_id == 'ChangeStyle' && $local_namespace == 'Special' ? ' class="currentpage"' : '' ), + 'TEXT'=>$lang->get('sidebar_btn_changestyle'), + )); + + $theme_link = $parser->run(); + + // Run hooks + $code = $plugins->setHook('tpl_compile_toolbar'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + // + // ASSIGN VARIABLES + // + + $this->assign_vars(array( + 'PAGE_NAME' => htmlspecialchars($this->page->ns->cdata['name']), + 'PAGE_URLNAME' => $paths->nslist[$this->namespace] . sanitize_page_id($this->page_id), + 'TOOLBAR' => $tb, + 'TOOLBAR_EXTRAS' => $this->toolbar_menu, + 'STYLE_LINK' => makeUrlNS('Special', 'CSS', null, true), //contentPath.$paths->nslist['Special'].'CSS' . $p, + 'LOGIN_LINK' => $login_link, + 'LOGOUT_LINK' => $logout_link, + 'THEME_LINK' => $theme_link + ), true); + $this->page_initted = true; + } + + /** + * Generates and assigns the Javascript system variables + */ + + function generate_js_header() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $SID = ($session->sid_super) ? $session->sid_super : ''; + + $local_page = $paths->get_pathskey($this->page_id, $this->namespace); + $local_fullpage = $paths->get_pathskey($this->page_id, $this->namespace) . substr($paths->fullpage, strlen($paths->page)); + + $urlname_clean = str_replace('\'', '\\\'', str_replace('\\', '\\\\', dirtify_page_id($local_fullpage))); + $urlname_clean = strtr( $urlname_clean, array( '<' => '<', '>' => '>' ) ); + + $urlname_jssafe = sanitize_page_id($local_fullpage); + $physical_urlname_jssafe = sanitize_page_id($paths->fullpage); + + $protected = is_object($this->page) ? $this->page->ns->cdata['really_protected'] : false; + + // Generate the dynamic javascript vars + // Sorry. I know. This block is a mess. + $js_dynamic = ' "; + + $this->assign_vars(array( + 'JS_DYNAMIC_VARS' => $js_dynamic, + 'REPORT_URI' => makeUrl($local_fullpage, 'do=sql_report', true) + ), true); + } + + /** + * Fetches, parses, and assigns the sidebar. + */ + + function assign_sidebar() + { + // + // COMPILE THE SIDEBAR + // + + // This is done after the big assign_vars() so that sidebar code has access to the newly assigned variables + + list($this->tpl_strings['SIDEBAR_LEFT'], $this->tpl_strings['SIDEBAR_RIGHT'], $min) = $this->fetch_sidebar(); + $this->tpl_bool['sidebar_left'] = ( $this->tpl_strings['SIDEBAR_LEFT'] != $min) ? true : false; + $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != $min) ? true : false; + $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility + } + + /** + * Initializes all variables related to on-page content. This includes sidebars and what have you. + * @param object Optional PageProcessor object to use for passing metadata and permissions on. If omitted, uses information from $paths and $session. + * @param bool If true, re-inits even if already initted with this page_id and namespace + */ + + function init_vars($page = false, $force_init = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $need_shared_init = ( !$this->theme_initted || !$this->page_initted ); + + if ( $need_shared_init ) + { + if ( !$this->theme || !$this->style ) + { + $this->load_theme(); + } + $code = $plugins->setHook('compile_template', true); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + + if ( !$this->theme_loaded ) + $this->load_theme(); + + require(ENANO_ROOT . "/themes/{$this->theme}/theme.cfg"); + + if ( !$this->page_id || !$this->namespace ) + { + $this->page_id = $paths->page_id; + $this->namespace = $paths->namespace; + } + + profiler_log('template: prepped for var set (loaded theme, ran compile_template hook)'); + + $this->init_global_vars(); + profiler_log('template: global vars set'); + + if ( !$this->theme_initted ) + $this->init_theme_vars(); + + profiler_log('template: theme vars set'); + + if ( !$this->page_initted && !empty($this->namespace) ) + { + profiler_log('template: page vars set'); + $this->init_page_vars(); + } + else + { + profiler_message('template: skipped setting page vars'); + } + + // Perform shared init (combine javascript, etc.) + if ( $need_shared_init ) + { + $this->generate_js_header(); + $this->assign_sidebar(); + profiler_log('template: assigned sidebar and JS'); + } + + // and finally one string value that needs to be symlinked... + if ( !isset($this->tpl_strings['ADDITIONAL_HEADERS']) ) + { + $this->tpl_strings['ADDITIONAL_HEADERS'] =& $this->additional_headers; + } + + // done! + $code = $plugins->setHook('template_var_init_end'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + + function header($simple = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + define('ENANO_HEADERS_SENT', true); + + echo $this->getHeader($simple); + } + + function footer($simple = false) + { + echo $this->getFooter($simple); + } + + function getHeader($simple = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if ( !$this->theme_loaded ) + { + $this->load_theme($session->theme, $session->style); + } + + if ( !$this->page_initted || !$this->theme_initted ) + $this->init_vars(); + + // I feel awful doing this. + if ( preg_match('/^W3C_Validator/', @$_SERVER['HTTP_USER_AGENT']) ) + { + header('Content-type: application/xhtml+xml'); + } + + $header = ''; + + if ( !$this->no_headers ) + { + $header = ( $simple ) ? + $this->process_template('simple-header.tpl') : + $this->process_template('header.tpl'); + } + if ( !$simple && $session->user_logged_in && $session->unread_pms > 0 ) + { + $header .= $this->notify_unread_pms(); + } + if ( !$simple && $session->sw_timed_out ) + { + $login_link = makeUrlNS('Special', 'Login/' . $paths->fullpage, 'level=' . $session->user_level, true); + $header .= '
'; + $header .= $lang->get('user_msg_elev_timed_out', array( 'login_link' => $login_link )); + $header .= '
'; + } + if ( $this->site_disabled && $session->user_level >= USER_LEVEL_ADMIN && ( $paths->page != $paths->nslist['Special'] . 'Administration' ) ) + { + $admin_link = makeUrlNS('Special', 'Administration', 'module=' . $paths->nslist['Admin'] . 'GeneralConfig', true); + $header .= '
' . $lang->get('page_sitedisabled_admin_msg_title') . '
+ ' . $lang->get('page_sitedisabled_admin_msg_body', array('admin_link' => $admin_link)) . ' +
'; + } + + return $header; + } + + function getFooter($simple = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + if ( !$this->no_headers ) + { + + global $_starttime; + if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc')) + { + echo '

' . $lang->get('page_heading_sql_list') . '

';
+				echo htmlspecialchars($db->sql_backtrace());
+				echo '
'; + } + + $t = ( $simple ) ? $this->process_template('simple-footer.tpl') : $this->process_template('footer.tpl'); + + $f = microtime_float(); + $f = $f - $_starttime; + $f = round($f, 2); + + $t_loc = $lang->get('page_msg_stats_gentime_short', array('time' => $f)); + $t_loc_long = $lang->get('page_msg_stats_gentime_long', array('time' => $f)); + $q_loc = '' . $lang->get('page_msg_stats_sql', array('nq' => $db->num_queries)) . ''; + $dbg = $t_loc; + $dbg_long = $t_loc_long; + if ( $session->user_level >= USER_LEVEL_ADMIN || defined('ENANO_DEBUG') ) + { + $dbg .= "  |  $q_loc"; + $dbg_long .= "  |  $q_loc"; + } + + $t = str_replace('[[Stats]]', $dbg, $t); + $t = str_replace('[[StatsLong]]', $dbg_long, $t); + $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t); + $t = str_replace('[[GenTime]]', (string)$f, $t); + $t = str_replace('[[NumQueriesLoc]]', $q_loc, $t); + $t = str_replace('[[GenTimeLoc]]', $t_loc, $t); + $t = str_replace('[[EnanoPoweredLink]]', $lang->get('page_enano_powered', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); + $t = str_replace('[[EnanoPoweredLinkLong]]', $lang->get('page_enano_powered_long', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); + + if ( defined('ENANO_PROFILE') ) + { + $t = str_replace('', '
' . profiler_make_html() . '
', $t); + // ob_end_clean(); + // return profiler_make_html(); + } + + return $t; + } + else + { + return ''; + } + } + + /** + * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. + * @param $vars array + * @param $from_internal bool Internal switch, just omit (@todo document) + */ + + function assign_vars($vars, $from_internal = false) + { + foreach ( $vars as $key => $value ) + { + $replace = true; + if ( isset($this->vars_assign_history['strings'][$key]) ) + { + if ( $this->vars_assign_history['strings'][$key] == 'api' ) + { + $replace = false; + } + } + if ( $replace ) + { + $this->tpl_strings[$key] = $value; + $this->vars_assign_history['strings'][$key] = ( $from_internal ) ? 'internal' : 'api'; + } + } + } + + /** + * Assigns an array of boolean values to the template. These can be used for statements. + * @param $vars array + * @param $from_internal bool Internal switch, just omit (@todo document) + */ + + function assign_bool($vars, $from_internal = false) + { + foreach ( $vars as $key => $value ) + { + $replace = true; + if ( isset($this->vars_assign_history['bool'][$key]) ) + { + if ( $this->vars_assign_history['bool'][$key] == 'api' ) + { + $replace = false; + } + } + if ( $replace ) + { + $this->tpl_bool[$key] = $value; + $this->vars_assign_history['bool'][$key] = ( $from_internal ) ? 'internal' : 'api'; + } + } + } + + # + # COMPILER + # + + /** + * Compiles and executes a template based on the current variables and booleans. Loads + * the theme and initializes variables if needed. This mostly just calls child functions. + * @param string File to process + * @return string + */ + + function process_template($file) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if ( !$this->theme_initted || !$this->page_initted ) + { + $this->init_vars(); + } + + $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $file) . '.php'; + if ( file_exists($cache_file) ) + { + // this is about the time of the breaking change to cache file format + if ( ($m = filemtime($cache_file)) > 1215038089 ) + { + $result = @include($cache_file); + if ( isset($md5) ) + { + if ( $m >= filemtime(ENANO_ROOT . "/themes/{$this->theme}/$file") ) + { + $result = $this->compile_template_text_post($result); + return $result; + } + } + } + } + + $compiled = $this->compile_template($file); + $result = eval($compiled); + + return $result; + } + + /** + * Loads variables from the specified template file. Returns an associative array containing the variables. + * @param string Template file to process (elements.tpl) + * @return array + */ + + function extract_vars($file) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // Sometimes this function gets called before the theme is loaded + // This is a bad coding practice so this function will always be picky. + if ( !$this->theme ) + { + die('$template->extract_vars(): theme not yet loaded, so we can\'t open template files yet...this is a bug and should be reported.

Backtrace, most recent call first:
'.enano_debug_print_backtrace(true).'
'); + } + + // Full pathname of template file + $tpl_file_fullpath = ( strstr($file, '/') ) ? $file : ENANO_ROOT . '/themes/' . $this->theme . '/' . $file; + + // Make sure the template even exists + if ( !is_file($tpl_file_fullpath) ) + { + die_semicritical('Cannot find template file', + '

The template parser was asked to load the file "' . htmlspecialchars($tpl_file_fullpath) . '", but that file couldn\'t be found in the directory for + the current theme.

+

Additional debugging information:
+ Theme currently in use: ' . $this->theme . '
+ Requested file: ' . $file . ' +

'); + } + // Retrieve file contents + $text = file_get_contents($tpl_file_fullpath); + if ( !$text ) + { + return false; + } + + // Get variables, regular expressions FTW + preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches); + + // Initialize return values + $tplvars = Array(); + + // Loop through each match, setting $tplvars[ $first_subpattern ] to $second_subpattern + for ( $i = 0; $i < sizeof($matches[1]); $i++ ) + { + $tplvars[ $matches[1][$i] ] = $matches[2][$i]; + } + + // All done! + return $tplvars; + } + + /** + * Compiles a block of template code. + * @param string The text to process + * @return string + */ + + function compile_tpl_code($text) + { + return template_compiler_core($text); + } + + /** + * Compiles the contents of a given template file, possibly using a cached copy, and returns the compiled code. + * @param string Filename of template (header.tpl) + * @return string + */ + + function compile_template($filename) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // Full path to template file + $tpl_file_fullpath = ENANO_ROOT . '/themes/' . $this->theme . '/' . $filename; + + // Make sure the file exists + if ( !is_file($tpl_file_fullpath) ) + { + die_semicritical('Cannot find template file', + '

The template parser was asked to load the file "' . htmlspecialchars($filename) . '", but that file couldn\'t be found in the directory for + the current theme.

+

Additional debugging information:
+ Theme currently in use: ' . $this->theme . '
+ Requested file: ' . $file . ' +

'); + } + + // We won't use the cached copy here. + $text = file_get_contents($tpl_file_fullpath); + + // This will be used later when writing the cached file + $md5 = md5($text); + + // Preprocessing and checks complete - compile the code + $text = $this->compile_tpl_code($text); + + // Generate cache filename + $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $filename) . '.php'; + + // Perhaps caching is enabled and the admin has changed the template? + if ( is_writable( ENANO_ROOT . '/cache/' ) && getConfig('cache_thumbs') == '1' ) + { + $h = fopen($cache_file, 'w'); + if ( !$h ) + { + // Couldn't open the file - silently ignore and return + return $text; + } + + // Final contents of cache file + $file_contents = <<compile_template_text_post($text); //('
'.htmlspecialchars($text).'
'); - } - - - /** - * Compiles (parses) some template code with the current master set of variables and booleans. - * @param string Text to process - * @return string - */ - - function compile_template_text($text) - { - // this might do something else in the future, possibly cache large templates - return $this->compile_template_text_post($this->compile_tpl_code($text)); - } - - /** - * For convenience - compiles AND parses some template code. - * @param string Text to process - * @return string - */ - - function parse($text) - { - $text = $this->compile_template_text($text); - $text = $this->compile_template_text_post($text); - return eval($text); - } - - /** - * Post-processor for template code. Basically what this does is it localizes {lang:foo} blocks. - * @param string Mostly-processed TPL code - * @param bool Post-eval switch. If true, does not escape code. - * @return string - */ - - function compile_template_text_post($text, $post_eval = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - // Language strings - preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $text, $matches); - foreach ( $matches[1] as $i => $string_id ) - { - $string = $lang->get($string_id); - if ( !$post_eval ) - { - $string = str_replace('\\', '\\\\', $string); - $string = str_replace('\'', '\\\'', $string); - } - $text = str_replace_once($matches[0][$i], $string, $text); - } - - // URLs - preg_match_all('/\{url:([A-z0-9]+):([^\}]+?)(?:;([^\s\}]+?))?(?:\|(escape))?\}/i', $text, $matches); - foreach ( $matches[1] as $i => $string_id ) - { - $namespace =& $matches[1][$i]; - $page_id =& $matches[2][$i]; - $params =& $matches[3][$i]; - $escape =& $matches[4][$i]; - - if ( !$params ) - $params = false; - $escape = !empty($escape); - - $result = makeUrlNS($namespace, sanitize_page_id($page_id), $params, $escape); - - if ( !$post_eval ) - { - $result = str_replace('\\', '\\\\', $result); - $result = str_replace('\'', '\\\'', $result); - } - - $text = str_replace_once($matches[0][$i], $result, $text); - } - - $code = $plugins->setHook('compie_template_text_post'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - return $text; - } - - /** - * Returns the output of a theme hook - * @param string Hook name - * @return string - */ - - function get_theme_hook($hook) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - ob_start(); - $code = $plugins->setHook($hook); - foreach ( $code as $cmd ) - { - eval($cmd); - } - $out = ob_get_contents(); - ob_end_clean(); - - return $out; - } - - // n00bish comments removed from here. 2008-03-13 @ 12:02AM when I had nothing else to do. - - /** - * Takes a blob of HTML with the specially formatted template-oriented wikitext and formats it. Does not use eval(). - * This function butchers every coding standard in Enano and should eventually be rewritten. The fact is that the - * code _works_ and does a good job of checking for errors and cleanly complaining about them. - * @param string Text to process - * @param bool Ignored for backwards compatibility - * @param string File to get variables for sidebar data from - * @return string - */ - - function tplWikiFormat($message, $filter_links = false, $filename = 'elements.tpl') - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $START = microtime_float(); - - // localize the whole string first - preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $message, $matches); - foreach ( $matches[1] as $i => $string_id ) - { - $string = $lang->get($string_id); - $string = str_replace('\\', '\\\\', $string); - $string = str_replace('\'', '\\\'', $string); - $message = str_replace_once($matches[0][$i], $string, $message); - } - - // first: the hackish optimization - - // if it's only a bunch of letters, numbers and spaces, just skip this sh*t. - - if ( preg_match('/^[\w\s\.]*$/i', $message) ) - { - return $message; - } - - $filter_links = false; - $tplvars = $this->extract_vars($filename); - if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super; - else $as = ''; - error_reporting(E_ALL); - $random_id = sha1(microtime().''); // A temp value - - /* - * PREPROCESSOR - */ - - // Variables - - preg_match_all('#\$([A-Z_-]+)\$#', $message, $links); - $links = $links[1]; - - for($i=0;$itpl_strings[$links[$i]]) ) - { - $message = str_replace('$'.$links[$i].'$', $this->tpl_strings[$links[$i]], $message); - } - } - - // Conditionals - - $message = $this->twf_parse_conditionals($message); - - /* - * HTML RENDERER - */ - - // Images - $message = RenderMan::process_image_tags($message, $taglist); - $message = RenderMan::process_imgtags_stage2($message, $taglist); - - // Internal links - $message = RenderMan::parse_internal_links($message, $tplvars['sidebar_button'], false, $this->page_id, $this->namespace); - - // External links - - $url_regexp = <<compile_template_text_post($text); //('
'.htmlspecialchars($text).'
'); + } + + + /** + * Compiles (parses) some template code with the current master set of variables and booleans. + * @param string Text to process + * @return string + */ + + function compile_template_text($text) + { + // this might do something else in the future, possibly cache large templates + return $this->compile_template_text_post($this->compile_tpl_code($text)); + } + + /** + * For convenience - compiles AND parses some template code. + * @param string Text to process + * @return string + */ + + function parse($text) + { + $text = $this->compile_template_text($text); + $text = $this->compile_template_text_post($text); + return eval($text); + } + + /** + * Post-processor for template code. Basically what this does is it localizes {lang:foo} blocks. + * @param string Mostly-processed TPL code + * @param bool Post-eval switch. If true, does not escape code. + * @return string + */ + + function compile_template_text_post($text, $post_eval = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + // Language strings + preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $text, $matches); + foreach ( $matches[1] as $i => $string_id ) + { + $string = $lang->get($string_id); + if ( !$post_eval ) + { + $string = str_replace('\\', '\\\\', $string); + $string = str_replace('\'', '\\\'', $string); + } + $text = str_replace_once($matches[0][$i], $string, $text); + } + + // URLs + preg_match_all('/\{url:([A-z0-9]+):([^\}]+?)(?:;([^\s\}]+?))?(?:\|(escape))?\}/i', $text, $matches); + foreach ( $matches[1] as $i => $string_id ) + { + $namespace =& $matches[1][$i]; + $page_id =& $matches[2][$i]; + $params =& $matches[3][$i]; + $escape =& $matches[4][$i]; + + if ( !$params ) + $params = false; + $escape = !empty($escape); + + $result = makeUrlNS($namespace, sanitize_page_id($page_id), $params, $escape); + + if ( !$post_eval ) + { + $result = str_replace('\\', '\\\\', $result); + $result = str_replace('\'', '\\\'', $result); + } + + $text = str_replace_once($matches[0][$i], $result, $text); + } + + $code = $plugins->setHook('compie_template_text_post'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + return $text; + } + + /** + * Returns the output of a theme hook + * @param string Hook name + * @return string + */ + + function get_theme_hook($hook) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + ob_start(); + $code = $plugins->setHook($hook); + foreach ( $code as $cmd ) + { + eval($cmd); + } + $out = ob_get_contents(); + ob_end_clean(); + + return $out; + } + + // n00bish comments removed from here. 2008-03-13 @ 12:02AM when I had nothing else to do. + + /** + * Takes a blob of HTML with the specially formatted template-oriented wikitext and formats it. Does not use eval(). + * This function butchers every coding standard in Enano and should eventually be rewritten. The fact is that the + * code _works_ and does a good job of checking for errors and cleanly complaining about them. + * @param string Text to process + * @param bool Ignored for backwards compatibility + * @param string File to get variables for sidebar data from + * @return string + */ + + function tplWikiFormat($message, $filter_links = false, $filename = 'elements.tpl') + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $START = microtime_float(); + + // localize the whole string first + preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $message, $matches); + foreach ( $matches[1] as $i => $string_id ) + { + $string = $lang->get($string_id); + $string = str_replace('\\', '\\\\', $string); + $string = str_replace('\'', '\\\'', $string); + $message = str_replace_once($matches[0][$i], $string, $message); + } + + // first: the hackish optimization - + // if it's only a bunch of letters, numbers and spaces, just skip this sh*t. + + if ( preg_match('/^[\w\s\.]*$/i', $message) ) + { + return $message; + } + + $filter_links = false; + $tplvars = $this->extract_vars($filename); + if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super; + else $as = ''; + error_reporting(E_ALL); + $random_id = sha1(microtime().''); // A temp value + + /* + * PREPROCESSOR + */ + + // Variables + + preg_match_all('#\$([A-Z_-]+)\$#', $message, $links); + $links = $links[1]; + + for($i=0;$itpl_strings[$links[$i]]) ) + { + $message = str_replace('$'.$links[$i].'$', $this->tpl_strings[$links[$i]], $message); + } + } + + // Conditionals + + $message = $this->twf_parse_conditionals($message); + + /* + * HTML RENDERER + */ + + // Images + $message = RenderMan::process_image_tags($message, $taglist); + $message = RenderMan::process_imgtags_stage2($message, $taglist); + + // Internal links + $message = RenderMan::parse_internal_links($message, $tplvars['sidebar_button'], false, $this->page_id, $this->namespace); + + // External links + + $url_regexp = <<makeParserText($tplvars['sidebar_button']); + $text_parser = $this->makeParserText($tplvars['sidebar_button']); - preg_match_all('/\[' . $url_regexp . '[ ]([^\]]+)\]/isx', $message, $ext_link); - - for ( $i = 0; $i < count($ext_link[0]); $i++ ) - { - $text_parser->assign_vars(Array( - 'HREF' => $ext_link[1][$i], - 'FLAGS' => '', - 'TEXT' => $ext_link[2][$i] - )); - $message = str_replace($ext_link[0][$i], $text_parser->run(), $message); - } - - preg_match_all('/\[' . $url_regexp . '\]/is', $message, $ext_link); - - for ( $i = 0; $i < count($ext_link[0]); $i++ ) - { - $text_parser->assign_vars(Array( - 'HREF' => $ext_link[1][$i], - 'FLAGS' => '', - 'TEXT' => htmlspecialchars($ext_link[1][$i]) - )); - $message = str_replace($ext_link[0][$i], $text_parser->run(), $message); - } - - $TIME = microtime_float() - $START; - - /* - if ( $TIME > 0.02 ) - { - echo 'template: tplWikiFormat took a while for this one. string dump:
';
-      echo htmlspecialchars($message);
-      echo '
'; - } - */ - - return $message; - } - - /** - * Parses conditional {if} blocks in sidebars and other tplWikiFormatted things - * @param string A string potentially containing conditional blocks - * @return string Processed string - */ - - function twf_parse_conditionals($message) - { - if ( !preg_match_all('/\{(!?)if ([a-z0-9_\(\)\|&! ]+)\}(.*?)(?:\{else\}(.*?))?\{\/if\}/is', $message, $matches) ) - { - return $message; - } - foreach ( $matches[0] as $match_id => $full_block ) - { - // 1 = "not" flag - // 2 = condition - // 3 = if true - // 4 = else - $condresult = $this->process_condition($matches[2][$match_id]); - if ( !empty($matches[1][$match_id]) ) - { - if ( $condresult == 1 ) - $condresult = 2; - else if ( $condresult == 2 ) - $condresult = 1; - } - switch($condresult) - { - case 1: - // evaluated to false - $message = str_replace_once($full_block, $matches[4][$match_id], $message); - break; - case 2: - // evaluated to true - $message = str_replace_once($full_block, $matches[3][$match_id], $message); - break; - case 3: - $message = str_replace_once($full_block, "Syntax error: mismatched parentheses (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); - break; - case 4: - $message = str_replace_once($full_block, "Syntax error: illegal character (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); - break; - case 5: - $message = str_replace_once($full_block, "Syntax error: illegal sequence (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); - break; - } - } - return $message; - } - - /** - * Inner-loop parser for a conditional block. Verifies a string condition to make sure it's syntactically correct, then returns what it evaluates to. - * Return values: - * 1 - string evaluates to true - * 2 - string evaluates to false - * 3 - Syntax error - mismatched parentheses - * 4 - Syntax error - unknown token - * 5 - Syntax error - invalid sequence - * @param string - * @return int - * - */ - - function process_condition($condition) - { - // make sure parentheses are matched - $parentheses = preg_replace('/[^\(\)]/', '', $condition); - if ( !empty($parentheses) ) - { - $i = 0; - $parentheses = enano_str_split($parentheses); - foreach ( $parentheses as $chr ) - { - $inc = ( $chr == '(' ) ? 1 : -1; - $i += $inc; - } - if ( $i != 0 ) - { - // mismatched parentheses - return 3; - } - } - // sequencer check - // first, pad all sequences of characters with spaces - $seqcheck = preg_replace('/([a-z0-9_]+)/i', '\\1 ', $condition); - $seqcheck = preg_replace('/([&|()!])/i', '\\1 ', $seqcheck); - // now shrink all spaces to one space each - $seqcheck = preg_replace('/[ ]+/', ' ', $seqcheck); - - // explode it. the allowed sequences are: - // - TOKEN_NOT + TOKEN_VARIABLE - // - TOKEN_NOT + TOKEN_PARENTHLEFT - // - TOKEN_BOOLOP + TOKEN_NOT - // - TOKEN_PARENTHRIGHT + TOKEN_NOT - // - TOKEN_VARIABLE + TOKEN_BOOLOP - // - TOKEN_BOOLOP + TOKEN_PARENTHLEFT - // - TOKEN_PARENTHLEFT + TOKEN_VARIABLE - // - TOKEN_BOOLOP + TOKEN_VARIABLE - // - TOKEN_VARIABLE + TOKEN_PARENTHRIGHT - // - TOKEN_PARENTHRIGHT + TOKEN_BOOLOP - $seqcheck = explode(' ', trim($seqcheck)); - $last_item = TOKEN_BOOLOP; - foreach ( $seqcheck as $i => $token ) - { - // determine type - if ( $token == '(' ) - { - $type = TOKEN_PARENTHLEFT; - } - else if ( $token == ')' ) - { - $type = TOKEN_PARENTHRIGHT; - } - else if ( $token == '!' ) - { - $type = TOKEN_NOT; - } - else if ( strtolower($token) == 'and' || strtolower($token) == 'or' || $token == '&&' || $token == '||' ) - { - $type = TOKEN_BOOLOP; - } - else if ( preg_match('/^[a-z0-9_]+$/i', $token) ) - { - $type = TOKEN_VARIABLE; - // at this point it's considered safe to wrap it - $seqcheck[$i] = "( isset(\$this->tpl_bool['$token']) && \$this->tpl_bool['$token'] )"; - } - else - { - // syntax error - doesn't match known token types - return 4; - } - // inner sequence check - if ( - ( $last_item == TOKEN_BOOLOP && $type == TOKEN_NOT ) || - ( $last_item == TOKEN_PARENTHRIGHT && $type == TOKEN_NOT ) || - ( $last_item == TOKEN_NOT && $type == TOKEN_VARIABLE ) || - ( $last_item == TOKEN_NOT && $type == TOKEN_PARENTHLEFT ) || - ( $last_item == TOKEN_VARIABLE && $type == TOKEN_BOOLOP ) || - ( $last_item == TOKEN_BOOLOP && $type == TOKEN_PARENTHLEFT ) || - ( $last_item == TOKEN_PARENTHLEFT && $type == TOKEN_VARIABLE ) || - ( $last_item == TOKEN_BOOLOP && $type == TOKEN_VARIABLE ) || - ( $last_item == TOKEN_VARIABLE && $type == TOKEN_PARENTHRIGHT ) || - ( $last_item == TOKEN_PARENTHRIGHT && $type == TOKEN_BOOLOP ) - ) - { - // sequence is good, continue - } - else - { - // sequence is invalid, break out - return 5; - } - $last_item = $type; - } - // passed all checks - $seqcheck = implode(' ', $seqcheck); - $result = eval("return ( $seqcheck ) ? true : false;"); - return ( $result ) ? 2 : 1; - } - - /** - * Print a text field that auto-completes a username entered into it. - * @param string $name - the name of the form field - * @return string - */ - - function username_field($name, $value = false) - { - $randomid = md5( time() . microtime() . mt_rand() ); - $text = '' . $content . ''; - $html .= '
' . $lang->get('etc_tinymce_btn_text') . '  |  ' . $lang->get('etc_tinymce_btn_graphical') . '
'; - $html .= ''; - return $html; - } - - /** - * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;) - * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class. - * @param $filename the filename of the template to be parsed - * @return object - */ - - function makeParser($filename) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $filename = ENANO_ROOT.'/themes/'.$template->theme.'/'.$filename; - if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist'); - $code = file_get_contents($filename); - $parser = new templateIndividual($code); - return $parser; - } - - /** - * Same as $template->makeParser(), but takes a string instead of a filename. - * @param $text the text to parse - * @return object - */ - - function makeParserText($code) - { - $parser = new templateIndividual($code); - return $parser; - } - - /** - * Fetch the HTML for a plugin-added sidebar block - * @param $name the plugin name - * @return string - */ - - function fetch_block($id, $just_the_innards_maam = false) - { - if ( $just_the_innards_maam ) - { - $source =& $this->plugin_blocks_content; - } - else - { - $source =& $this->plugin_blocks; - } - return isset($source[$id]) ? $source[$id] : false; - } - - /** - * Fetches the contents of both sidebars. - * @return array - key 0 is left, key 1 is right, key 2 is the HTML that makes up an empty sidebar - * @example list($left, $right) = $template->fetch_sidebar(); - */ - - function fetch_sidebar() - { - global $db, $session, $paths, $template, $plugins; // Common objects - - // first, check the cache - if ( $result = $this->fetch_cached_sidebar() ) - { - return $result; - } - - require(ENANO_ROOT . "/themes/{$this->theme}/theme.cfg"); - - profiler_log('Started sidebar parsing'); - - // init our block contents - $left = ''; - $right = ''; - $min = ''; - - // also might want the links block - if ( !$this->fetch_block('Links') ) - $this->initLinksWidget(); - - // templates to work with - $vars = $this->extract_vars('elements.tpl'); - - // sidebar_top and sidebar_bottom are HTML that is prepended/appended to sidebar content. Themes can - // choose whether or not to display a sidebar depending on whether the sidebar is empty ( $left == $min ) - // or not using the sidebar_left and sidebar_right template booleans (the oxygen theme does this). - if ( isset($vars['sidebar_top']) ) - { - $top = $this->parse($vars['sidebar_top']); - $left .= $top; - $right .= $top; - $min .= $top; - } - - // grab the blocks from the DB - $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n" - . ' WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;'); - if ( !$q ) - $db->_die('The sidebar text data could not be selected.'); - - // explicitly specify $q in case a plugin or PHP block makes a query - while ( $row = $db->fetchrow($q) ) - { - // should we skip this block? - if ( - ( $row['item_id'] === 2 && !empty($theme['sb_hide_tools']) ) || - ( $row['item_id'] === 3 && !empty($theme['sb_hide_user']) ) || - ( $row['item_id'] === 4 && !empty($theme['sb_hide_search']) ) - ) - continue; - - // format the block - $block_content = $this->format_sidebar_block($row, $vars, $parser); - - // is there a {restrict} or {hideif} block? - if ( preg_match('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', $block_content, $match) ) - { - // we have one, check the condition - $type =& $match[1]; - $cond =& $match[2]; - $result = $this->process_condition($cond); - if ( ( $type == 'restrict' && $result == 1 ) || ( $type == 'hideif' && $result == 2 ) ) - { - // throw out this block, it's hidden for whatever reason by the sidebar script - continue; - } - // didn't get a match, so hide the conditional logic - // FIXME: this needs to be verbose about syntax errors - $block_content = str_replace_once($match[0], '', $block_content); - } - - // if we made it here, this block definitely needs to be displayed. send it to the - // parser (set by format_sidebar_block) and decide where to append it (but not in that order ;)) - $appender = false; - - if ( $row['sidebar_id'] == SIDEBAR_LEFT ) - { - $appender =& $left; - } - else if ( $row['sidebar_id'] == SIDEBAR_RIGHT ) - { - $appender =& $right; - } - else - { - // uhoh, block_id isn't valid. maybe a plugin wants to put this block somewhere else? - $code = $plugins->setHook('sidebar_block_id'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - // if $appender wasn't set by a plugin, don't parse this block to save some CPU cycles - if ( !$appender ) - { - continue; - } - } - - // assign variables to parser - $block_name = $this->tplWikiFormat($row['block_name']); - $parser->assign_vars(array( - // be nice and format the title (FIXME, does this use a lot of CPU time? still needs l10n in some cases though) - 'TITLE' => $block_name, - 'CONTENT' => $block_content - )); - $parsed = $parser->run(); - - // plugins are parsed earlier due to the way disabled/missing plugins that add sidebar blocks are - // handled, so the {TITLE} var won't be replaced until now. this allows completely eliminating a - // block if it's not available - if ( $row['block_type'] == BLOCK_PLUGIN ) - { - $parsed = str_replace('{TITLE}', $block_name, $parsed); - } - - // done parsing - append and continue - $appender .= $parsed; - - // we're done with this - unset it because it's a reference and we don't want it overwritten. - // also free the parser to get some RAM back - unset($appender, $parser); - } - - // lastly, append any footer HTML - if(isset($vars['sidebar_bottom'])) - { - $bottom = $this->parse($vars['sidebar_bottom']); - $left .= $bottom; - $right .= $bottom; - $min .= $bottom; - } - - $return = array($left, $right, $min); - - // allow any plugins to append what they want to the return - $code = $plugins->setHook('sidebar_fetch_return'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - // cache the result if appropriate - $this->cache_compiled_sidebar($return); - - profiler_log('Finished sidebar parsing'); - - return $return; - } - - /** - * Runs the appropriate formatting routine on a sidebar row. - * @param array Row in sidebar table - * @param array Template variable set from elements.tpl - * @param null Pass by reference, will be filled with the parser according to the block's type (sidebar_section or sidebar_section_raw) - * @return string HTML + directives like {restrict} or {hideif} - */ - - function format_sidebar_block($row, $vars, &$parser) - { - // import globals in case a PHP block wants to call the Enano API - global $db, $session, $paths, $template, $plugins; // Common objects - - $parser = null; - - switch($row['block_type']) - { - case BLOCK_WIKIFORMAT: - $parser = $this->makeParserText($vars['sidebar_section_raw']); - $c = RenderMan::render($row['block_content']); - break; - - case BLOCK_TEMPLATEFORMAT: - $parser = $this->makeParserText($vars['sidebar_section']); - $c = $this->tplWikiFormat($row['block_content']); - break; - - case BLOCK_HTML: - $parser = $this->makeParserText($vars['sidebar_section_raw']); - $c = $row['block_content']; - break; - - case BLOCK_PHP: - // PHP blocks need to be sent directly to eval() - $parser = $this->makeParserText($vars['sidebar_section_raw']); - ob_start(); - @eval($row['block_content']); - $c = ob_get_contents(); - ob_end_clean(); - break; - - case BLOCK_PLUGIN: - $parser = $this->makeParserText('{CONTENT}'); - $c = '' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? - $this->fetch_block($row['block_content']) : - // This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. - ''; - break; - default: - // unknown block type - can a plugin handle it? - $code = $plugins->setHook('format_sidebar_block'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - if ( !isset($c) ) - { - // default to wiki formatting (this was going to be straight HTML but this is done for backwards compatibility reasons) - $c = RenderMan::render($row['block_content']); - } - if ( !$parser ) - { - // no parser defined, use the "raw" section by default (plugins are more likely to want raw content - // rather than a list of links, and they can set the parser to use sidebar_section if they want) - $parser = $this->makeParserText($vars['sidebar_section_raw']); - } - - break; - } - - return $c; - } - - /** - * Returns the list of things that should not be cached (sorry, I was listening to "The Thing That Should Not Be" by Metallica when I - * wrote this routine. You should get a copy of Master of Puppets, it's a damn good album.) - * @return array - */ - - function get_cache_replacements() - { - global $db, $session, $paths, $template, $plugins; // Common objects - - return array( - '$LOGIN_LINK$' => $this->tpl_strings['LOGIN_LINK'], - '$MAIN_PAGE$' => $this->tpl_strings['MAIN_PAGE'], - '$USERNAME$' => $session->username - ); - } - - /** - * Attempts to load a cached compiled sidebar. - * @return array Same format as fetch_sidebar() - */ - - function fetch_cached_sidebar() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $cache; - - $cached = false; - if ( ($result = $cache->fetch('anon_sidebar')) && !$session->user_logged_in ) - { - if ( isset($result[$this->theme]) ) - { - $cached = $result[$this->theme]; - } - } - - // if we haven't been able to fetch yet, see if a plugin wants to give us something - if ( !$cached ) - { - $code = $plugins->setHook('fetch_cached_sidebar'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - - if ( is_array($cached) ) - { - // fetch certain variables that can't be stored in the cache and quickly substitute - $replace = $this->get_cache_replacements(); - foreach ( $cached as &$val ) - { - $val = strtr($val, $replace); - } - - // done processing, send it back - return $cached; - } - - return false; - } - - /** - * Caches a completely compiled sidebar, if appropriate - * @param array Effectively, return from fetch_sidebar() - */ - - function cache_compiled_sidebar($sidebar) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $cache; - - // check if conditions are right - if ( !$session->user_logged_in && getConfig('cache_thumbs') === '1' ) - { - // load any existing cache to make sure other themes' cached sidebars aren't discarded - $cached = ( $_ = $cache->fetch('anon_sidebar') ) ? $_ : array(); - - // replace variables - $replace = array_flip($this->get_cache_replacements()); - - foreach ( $sidebar as &$section ) - { - $section = strtr($section, $replace); - } - - // compile - $cached[$this->theme] = $sidebar; - - // store - $cache->store('anon_sidebar', $cached, 15); - } - } - - function initLinksWidget() - { - global $db, $session, $paths, $template, $plugins; // Common objects - - // SourceForge/W3C buttons - $ob = Array(); - if(getConfig('sflogo_enabled')=='1') - { - $sflogo_secure = ( isset($_SERVER['HTTPS']) ) ? 'https' : 'http'; - $ob[] = 'SourceForge.net Logo'; - } - if(getConfig('w3c_v32') =='1') $ob[] = 'Valid HTML 3.2'; - if(getConfig('w3c_v40') =='1') $ob[] = 'Valid HTML 4.0'; - if(getConfig('w3c_v401') =='1') $ob[] = 'Valid HTML 4.01'; - if(getConfig('w3c_vxhtml10')=='1') $ob[] = 'Valid XHTML 1.0'; - if(getConfig('w3c_vxhtml11')=='1') $ob[] = 'Valid XHTML 1.1'; - if(getConfig('w3c_vcss') =='1') $ob[] = 'Valid CSS'; - if(getConfig('dbd_button') =='1') $ob[] = 'DRM technology restricts what you can do with your computer
Protect your freedom >>
'; - - $code = $plugins->setHook('links_widget'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - if(count($ob) > 0 || getConfig('powered_btn', '1') == '1') $sb_links = '
'. ( ( getConfig('powered_btn', '1') == '1' ) ? $this->fading_button : '' ) . implode('
', $ob).'
'; - else $sb_links = ''; - - $this->sidebar_widget('Links', $sb_links); - } - - /** - * Builds a box showing unread private messages. - */ - - function notify_unread_pms() - { - global $db, $session, $paths, $template, $plugins; // Common objects - if ( ( $paths->page_id == 'PrivateMessages' || $paths->page_id == 'Preferences' ) && $paths->namespace == 'Special' ) - { - return ''; - } - $ob = '
'."\n"; - $s = ( $session->unread_pms == 1 ) ? '' : 's'; - $ob .= " You have $session->unread_pms unread private message$s.
\n Messages: "; - $q = $db->sql_query('SELECT message_id,message_from,subject,date FROM '.table_prefix.'privmsgs WHERE message_to=\'' . $session->username . '\' AND message_read=0 ORDER BY date DESC;'); - if ( !$q ) - $db->_die(); - $messages = array(); - while ( $row = $db->fetchrow() ) - { - $messages[] = '' . $row['subject'] . ''; - } - $ob .= implode(",\n " , $messages)."\n"; - $ob .= '
'."\n"; - return $ob; - } - - /** - * Parse a system message. - * @param string message - * @return string - */ - - function parse_system_message($text) - { - ob_start(); - eval( '?>' . $text ); - $result = ob_get_contents(); - ob_end_clean(); - return $this->parse($result); - } - - /** - * Return the wiki mode edit notice, rendered and addslashes()'ed. - * @return string - */ - - function get_wiki_edit_notice() - { - global $cache; - - if ( getConfig('wiki_edit_notice', 0) != 1 ) - return ''; - - $notice = RenderMan::render(getConfig('wiki_edit_notice_text')); - return $notice; - } - + preg_match_all('/\[' . $url_regexp . '[ ]([^\]]+)\]/isx', $message, $ext_link); + + for ( $i = 0; $i < count($ext_link[0]); $i++ ) + { + $text_parser->assign_vars(Array( + 'HREF' => $ext_link[1][$i], + 'FLAGS' => '', + 'TEXT' => $ext_link[2][$i] + )); + $message = str_replace($ext_link[0][$i], $text_parser->run(), $message); + } + + preg_match_all('/\[' . $url_regexp . '\]/is', $message, $ext_link); + + for ( $i = 0; $i < count($ext_link[0]); $i++ ) + { + $text_parser->assign_vars(Array( + 'HREF' => $ext_link[1][$i], + 'FLAGS' => '', + 'TEXT' => htmlspecialchars($ext_link[1][$i]) + )); + $message = str_replace($ext_link[0][$i], $text_parser->run(), $message); + } + + $TIME = microtime_float() - $START; + + /* + if ( $TIME > 0.02 ) + { + echo 'template: tplWikiFormat took a while for this one. string dump:
';
+			echo htmlspecialchars($message);
+			echo '
'; + } + */ + + return $message; + } + + /** + * Parses conditional {if} blocks in sidebars and other tplWikiFormatted things + * @param string A string potentially containing conditional blocks + * @return string Processed string + */ + + function twf_parse_conditionals($message) + { + if ( !preg_match_all('/\{(!?)if ([a-z0-9_\(\)\|&! ]+)\}(.*?)(?:\{else\}(.*?))?\{\/if\}/is', $message, $matches) ) + { + return $message; + } + foreach ( $matches[0] as $match_id => $full_block ) + { + // 1 = "not" flag + // 2 = condition + // 3 = if true + // 4 = else + $condresult = $this->process_condition($matches[2][$match_id]); + if ( !empty($matches[1][$match_id]) ) + { + if ( $condresult == 1 ) + $condresult = 2; + else if ( $condresult == 2 ) + $condresult = 1; + } + switch($condresult) + { + case 1: + // evaluated to false + $message = str_replace_once($full_block, $matches[4][$match_id], $message); + break; + case 2: + // evaluated to true + $message = str_replace_once($full_block, $matches[3][$match_id], $message); + break; + case 3: + $message = str_replace_once($full_block, "Syntax error: mismatched parentheses (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); + break; + case 4: + $message = str_replace_once($full_block, "Syntax error: illegal character (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); + break; + case 5: + $message = str_replace_once($full_block, "Syntax error: illegal sequence (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); + break; + } + } + return $message; + } + + /** + * Inner-loop parser for a conditional block. Verifies a string condition to make sure it's syntactically correct, then returns what it evaluates to. + * Return values: + * 1 - string evaluates to true + * 2 - string evaluates to false + * 3 - Syntax error - mismatched parentheses + * 4 - Syntax error - unknown token + * 5 - Syntax error - invalid sequence + * @param string + * @return int + * + */ + + function process_condition($condition) + { + // make sure parentheses are matched + $parentheses = preg_replace('/[^\(\)]/', '', $condition); + if ( !empty($parentheses) ) + { + $i = 0; + $parentheses = enano_str_split($parentheses); + foreach ( $parentheses as $chr ) + { + $inc = ( $chr == '(' ) ? 1 : -1; + $i += $inc; + } + if ( $i != 0 ) + { + // mismatched parentheses + return 3; + } + } + // sequencer check + // first, pad all sequences of characters with spaces + $seqcheck = preg_replace('/([a-z0-9_]+)/i', '\\1 ', $condition); + $seqcheck = preg_replace('/([&|()!])/i', '\\1 ', $seqcheck); + // now shrink all spaces to one space each + $seqcheck = preg_replace('/[ ]+/', ' ', $seqcheck); + + // explode it. the allowed sequences are: + // - TOKEN_NOT + TOKEN_VARIABLE + // - TOKEN_NOT + TOKEN_PARENTHLEFT + // - TOKEN_BOOLOP + TOKEN_NOT + // - TOKEN_PARENTHRIGHT + TOKEN_NOT + // - TOKEN_VARIABLE + TOKEN_BOOLOP + // - TOKEN_BOOLOP + TOKEN_PARENTHLEFT + // - TOKEN_PARENTHLEFT + TOKEN_VARIABLE + // - TOKEN_BOOLOP + TOKEN_VARIABLE + // - TOKEN_VARIABLE + TOKEN_PARENTHRIGHT + // - TOKEN_PARENTHRIGHT + TOKEN_BOOLOP + $seqcheck = explode(' ', trim($seqcheck)); + $last_item = TOKEN_BOOLOP; + foreach ( $seqcheck as $i => $token ) + { + // determine type + if ( $token == '(' ) + { + $type = TOKEN_PARENTHLEFT; + } + else if ( $token == ')' ) + { + $type = TOKEN_PARENTHRIGHT; + } + else if ( $token == '!' ) + { + $type = TOKEN_NOT; + } + else if ( strtolower($token) == 'and' || strtolower($token) == 'or' || $token == '&&' || $token == '||' ) + { + $type = TOKEN_BOOLOP; + } + else if ( preg_match('/^[a-z0-9_]+$/i', $token) ) + { + $type = TOKEN_VARIABLE; + // at this point it's considered safe to wrap it + $seqcheck[$i] = "( isset(\$this->tpl_bool['$token']) && \$this->tpl_bool['$token'] )"; + } + else + { + // syntax error - doesn't match known token types + return 4; + } + // inner sequence check + if ( + ( $last_item == TOKEN_BOOLOP && $type == TOKEN_NOT ) || + ( $last_item == TOKEN_PARENTHRIGHT && $type == TOKEN_NOT ) || + ( $last_item == TOKEN_NOT && $type == TOKEN_VARIABLE ) || + ( $last_item == TOKEN_NOT && $type == TOKEN_PARENTHLEFT ) || + ( $last_item == TOKEN_VARIABLE && $type == TOKEN_BOOLOP ) || + ( $last_item == TOKEN_BOOLOP && $type == TOKEN_PARENTHLEFT ) || + ( $last_item == TOKEN_PARENTHLEFT && $type == TOKEN_VARIABLE ) || + ( $last_item == TOKEN_BOOLOP && $type == TOKEN_VARIABLE ) || + ( $last_item == TOKEN_VARIABLE && $type == TOKEN_PARENTHRIGHT ) || + ( $last_item == TOKEN_PARENTHRIGHT && $type == TOKEN_BOOLOP ) + ) + { + // sequence is good, continue + } + else + { + // sequence is invalid, break out + return 5; + } + $last_item = $type; + } + // passed all checks + $seqcheck = implode(' ', $seqcheck); + $result = eval("return ( $seqcheck ) ? true : false;"); + return ( $result ) ? 2 : 1; + } + + /** + * Print a text field that auto-completes a username entered into it. + * @param string $name - the name of the form field + * @return string + */ + + function username_field($name, $value = false) + { + $randomid = md5( time() . microtime() . mt_rand() ); + $text = '' . $content . ''; + $html .= '
' . $lang->get('etc_tinymce_btn_text') . '  |  ' . $lang->get('etc_tinymce_btn_graphical') . '
'; + $html .= ''; + return $html; + } + + /** + * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;) + * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class. + * @param $filename the filename of the template to be parsed + * @return object + */ + + function makeParser($filename) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $filename = ENANO_ROOT.'/themes/'.$template->theme.'/'.$filename; + if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist'); + $code = file_get_contents($filename); + $parser = new templateIndividual($code); + return $parser; + } + + /** + * Same as $template->makeParser(), but takes a string instead of a filename. + * @param $text the text to parse + * @return object + */ + + function makeParserText($code) + { + $parser = new templateIndividual($code); + return $parser; + } + + /** + * Fetch the HTML for a plugin-added sidebar block + * @param $name the plugin name + * @return string + */ + + function fetch_block($id, $just_the_innards_maam = false) + { + if ( $just_the_innards_maam ) + { + $source =& $this->plugin_blocks_content; + } + else + { + $source =& $this->plugin_blocks; + } + return isset($source[$id]) ? $source[$id] : false; + } + + /** + * Fetches the contents of both sidebars. + * @return array - key 0 is left, key 1 is right, key 2 is the HTML that makes up an empty sidebar + * @example list($left, $right) = $template->fetch_sidebar(); + */ + + function fetch_sidebar() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // first, check the cache + if ( $result = $this->fetch_cached_sidebar() ) + { + return $result; + } + + require(ENANO_ROOT . "/themes/{$this->theme}/theme.cfg"); + + profiler_log('Started sidebar parsing'); + + // init our block contents + $left = ''; + $right = ''; + $min = ''; + + // also might want the links block + if ( !$this->fetch_block('Links') ) + $this->initLinksWidget(); + + // templates to work with + $vars = $this->extract_vars('elements.tpl'); + + // sidebar_top and sidebar_bottom are HTML that is prepended/appended to sidebar content. Themes can + // choose whether or not to display a sidebar depending on whether the sidebar is empty ( $left == $min ) + // or not using the sidebar_left and sidebar_right template booleans (the oxygen theme does this). + if ( isset($vars['sidebar_top']) ) + { + $top = $this->parse($vars['sidebar_top']); + $left .= $top; + $right .= $top; + $min .= $top; + } + + // grab the blocks from the DB + $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n" + . ' WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;'); + if ( !$q ) + $db->_die('The sidebar text data could not be selected.'); + + // explicitly specify $q in case a plugin or PHP block makes a query + while ( $row = $db->fetchrow($q) ) + { + // should we skip this block? + if ( + ( $row['item_id'] === 2 && !empty($theme['sb_hide_tools']) ) || + ( $row['item_id'] === 3 && !empty($theme['sb_hide_user']) ) || + ( $row['item_id'] === 4 && !empty($theme['sb_hide_search']) ) + ) + continue; + + // format the block + $block_content = $this->format_sidebar_block($row, $vars, $parser); + + // is there a {restrict} or {hideif} block? + if ( preg_match('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', $block_content, $match) ) + { + // we have one, check the condition + $type =& $match[1]; + $cond =& $match[2]; + $result = $this->process_condition($cond); + if ( ( $type == 'restrict' && $result == 1 ) || ( $type == 'hideif' && $result == 2 ) ) + { + // throw out this block, it's hidden for whatever reason by the sidebar script + continue; + } + // didn't get a match, so hide the conditional logic + // FIXME: this needs to be verbose about syntax errors + $block_content = str_replace_once($match[0], '', $block_content); + } + + // if we made it here, this block definitely needs to be displayed. send it to the + // parser (set by format_sidebar_block) and decide where to append it (but not in that order ;)) + $appender = false; + + if ( $row['sidebar_id'] == SIDEBAR_LEFT ) + { + $appender =& $left; + } + else if ( $row['sidebar_id'] == SIDEBAR_RIGHT ) + { + $appender =& $right; + } + else + { + // uhoh, block_id isn't valid. maybe a plugin wants to put this block somewhere else? + $code = $plugins->setHook('sidebar_block_id'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + // if $appender wasn't set by a plugin, don't parse this block to save some CPU cycles + if ( !$appender ) + { + continue; + } + } + + // assign variables to parser + $block_name = $this->tplWikiFormat($row['block_name']); + $parser->assign_vars(array( + // be nice and format the title (FIXME, does this use a lot of CPU time? still needs l10n in some cases though) + 'TITLE' => $block_name, + 'CONTENT' => $block_content + )); + $parsed = $parser->run(); + + // plugins are parsed earlier due to the way disabled/missing plugins that add sidebar blocks are + // handled, so the {TITLE} var won't be replaced until now. this allows completely eliminating a + // block if it's not available + if ( $row['block_type'] == BLOCK_PLUGIN ) + { + $parsed = str_replace('{TITLE}', $block_name, $parsed); + } + + // done parsing - append and continue + $appender .= $parsed; + + // we're done with this - unset it because it's a reference and we don't want it overwritten. + // also free the parser to get some RAM back + unset($appender, $parser); + } + + // lastly, append any footer HTML + if(isset($vars['sidebar_bottom'])) + { + $bottom = $this->parse($vars['sidebar_bottom']); + $left .= $bottom; + $right .= $bottom; + $min .= $bottom; + } + + $return = array($left, $right, $min); + + // allow any plugins to append what they want to the return + $code = $plugins->setHook('sidebar_fetch_return'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + // cache the result if appropriate + $this->cache_compiled_sidebar($return); + + profiler_log('Finished sidebar parsing'); + + return $return; + } + + /** + * Runs the appropriate formatting routine on a sidebar row. + * @param array Row in sidebar table + * @param array Template variable set from elements.tpl + * @param null Pass by reference, will be filled with the parser according to the block's type (sidebar_section or sidebar_section_raw) + * @return string HTML + directives like {restrict} or {hideif} + */ + + function format_sidebar_block($row, $vars, &$parser) + { + // import globals in case a PHP block wants to call the Enano API + global $db, $session, $paths, $template, $plugins; // Common objects + + $parser = null; + + switch($row['block_type']) + { + case BLOCK_WIKIFORMAT: + $parser = $this->makeParserText($vars['sidebar_section_raw']); + $c = RenderMan::render($row['block_content']); + break; + + case BLOCK_TEMPLATEFORMAT: + $parser = $this->makeParserText($vars['sidebar_section']); + $c = $this->tplWikiFormat($row['block_content']); + break; + + case BLOCK_HTML: + $parser = $this->makeParserText($vars['sidebar_section_raw']); + $c = $row['block_content']; + break; + + case BLOCK_PHP: + // PHP blocks need to be sent directly to eval() + $parser = $this->makeParserText($vars['sidebar_section_raw']); + ob_start(); + @eval($row['block_content']); + $c = ob_get_contents(); + ob_end_clean(); + break; + + case BLOCK_PLUGIN: + $parser = $this->makeParserText('{CONTENT}'); + $c = '' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? + $this->fetch_block($row['block_content']) : + // This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. + ''; + break; + default: + // unknown block type - can a plugin handle it? + $code = $plugins->setHook('format_sidebar_block'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + if ( !isset($c) ) + { + // default to wiki formatting (this was going to be straight HTML but this is done for backwards compatibility reasons) + $c = RenderMan::render($row['block_content']); + } + if ( !$parser ) + { + // no parser defined, use the "raw" section by default (plugins are more likely to want raw content + // rather than a list of links, and they can set the parser to use sidebar_section if they want) + $parser = $this->makeParserText($vars['sidebar_section_raw']); + } + + break; + } + + return $c; + } + + /** + * Returns the list of things that should not be cached (sorry, I was listening to "The Thing That Should Not Be" by Metallica when I + * wrote this routine. You should get a copy of Master of Puppets, it's a damn good album.) + * @return array + */ + + function get_cache_replacements() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + return array( + '$LOGIN_LINK$' => $this->tpl_strings['LOGIN_LINK'], + '$MAIN_PAGE$' => $this->tpl_strings['MAIN_PAGE'], + '$USERNAME$' => $session->username + ); + } + + /** + * Attempts to load a cached compiled sidebar. + * @return array Same format as fetch_sidebar() + */ + + function fetch_cached_sidebar() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; + + $cached = false; + if ( ($result = $cache->fetch('anon_sidebar')) && !$session->user_logged_in ) + { + if ( isset($result[$this->theme]) ) + { + $cached = $result[$this->theme]; + } + } + + // if we haven't been able to fetch yet, see if a plugin wants to give us something + if ( !$cached ) + { + $code = $plugins->setHook('fetch_cached_sidebar'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + + if ( is_array($cached) ) + { + // fetch certain variables that can't be stored in the cache and quickly substitute + $replace = $this->get_cache_replacements(); + foreach ( $cached as &$val ) + { + $val = strtr($val, $replace); + } + + // done processing, send it back + return $cached; + } + + return false; + } + + /** + * Caches a completely compiled sidebar, if appropriate + * @param array Effectively, return from fetch_sidebar() + */ + + function cache_compiled_sidebar($sidebar) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; + + // check if conditions are right + if ( !$session->user_logged_in && getConfig('cache_thumbs') === '1' ) + { + // load any existing cache to make sure other themes' cached sidebars aren't discarded + $cached = ( $_ = $cache->fetch('anon_sidebar') ) ? $_ : array(); + + // replace variables + $replace = array_flip($this->get_cache_replacements()); + + foreach ( $sidebar as &$section ) + { + $section = strtr($section, $replace); + } + + // compile + $cached[$this->theme] = $sidebar; + + // store + $cache->store('anon_sidebar', $cached, 15); + } + } + + function initLinksWidget() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // SourceForge/W3C buttons + $ob = Array(); + if(getConfig('sflogo_enabled')=='1') + { + $sflogo_secure = ( isset($_SERVER['HTTPS']) ) ? 'https' : 'http'; + $ob[] = 'SourceForge.net Logo'; + } + if(getConfig('w3c_v32') =='1') $ob[] = 'Valid HTML 3.2'; + if(getConfig('w3c_v40') =='1') $ob[] = 'Valid HTML 4.0'; + if(getConfig('w3c_v401') =='1') $ob[] = 'Valid HTML 4.01'; + if(getConfig('w3c_vxhtml10')=='1') $ob[] = 'Valid XHTML 1.0'; + if(getConfig('w3c_vxhtml11')=='1') $ob[] = 'Valid XHTML 1.1'; + if(getConfig('w3c_vcss') =='1') $ob[] = 'Valid CSS'; + if(getConfig('dbd_button') =='1') $ob[] = 'DRM technology restricts what you can do with your computer
Protect your freedom >>
'; + + $code = $plugins->setHook('links_widget'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + if(count($ob) > 0 || getConfig('powered_btn', '1') == '1') $sb_links = '
'. ( ( getConfig('powered_btn', '1') == '1' ) ? $this->fading_button : '' ) . implode('
', $ob).'
'; + else $sb_links = ''; + + $this->sidebar_widget('Links', $sb_links); + } + + /** + * Builds a box showing unread private messages. + */ + + function notify_unread_pms() + { + global $db, $session, $paths, $template, $plugins; // Common objects + if ( ( $paths->page_id == 'PrivateMessages' || $paths->page_id == 'Preferences' ) && $paths->namespace == 'Special' ) + { + return ''; + } + $ob = '
'."\n"; + $s = ( $session->unread_pms == 1 ) ? '' : 's'; + $ob .= " You have $session->unread_pms unread private message$s.
\n Messages: "; + $q = $db->sql_query('SELECT message_id,message_from,subject,date FROM '.table_prefix.'privmsgs WHERE message_to=\'' . $session->username . '\' AND message_read=0 ORDER BY date DESC;'); + if ( !$q ) + $db->_die(); + $messages = array(); + while ( $row = $db->fetchrow() ) + { + $messages[] = '' . $row['subject'] . ''; + } + $ob .= implode(",\n " , $messages)."\n"; + $ob .= '
'."\n"; + return $ob; + } + + /** + * Parse a system message. + * @param string message + * @return string + */ + + function parse_system_message($text) + { + ob_start(); + eval( '?>' . $text ); + $result = ob_get_contents(); + ob_end_clean(); + return $this->parse($result); + } + + /** + * Return the wiki mode edit notice, rendered and addslashes()'ed. + * @return string + */ + + function get_wiki_edit_notice() + { + global $cache; + + if ( getConfig('wiki_edit_notice', 0) != 1 ) + return ''; + + $notice = RenderMan::render(getConfig('wiki_edit_notice_text')); + return $notice; + } + } // class template /** @@ -2652,160 +2652,160 @@ function template_compiler_core($text) { - global $db, $session, $paths, $template, $plugins; // Common objects - // A random seed used to salt tags - $seed = md5 ( microtime() . mt_rand() ); - - // Strip out PHP sections - preg_match_all('/<\?php(.+?)\?>/is', $text, $php_matches); - - foreach ( $php_matches[0] as $i => $match ) - { - // Substitute the PHP section with a random tag - $tag = "{PHP:$i:$seed}"; - $text = str_replace_once($match, $tag, $text); - } - - // Escape slashes and single quotes in template code - $text = str_replace('\\', '\\\\', $text); - $text = str_replace('\'', '\\\'', $text); - - // Initialize the PHP compiled code - $text = 'ob_start(); global $paths, $template; echo \''.$text.'\'; $tpl_code = ob_get_contents(); ob_end_clean(); return $tpl_code;'; - - ## - ## Main rules - ## - - // - // Conditionals - // - - $keywords = array('BEGIN', 'BEGINNOT', 'IFSET', 'IFPLUGIN'); - - // only do this if the plugins API is loaded - if ( is_object(@$plugins) ) - { - $code = $plugins->setHook('template_compile_logic_keyword'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - - $keywords = implode('|', $keywords); - - // Matches - // 1 2 3 4 56 7 8 9 - $regexp = '/()([\w\W]*)(()([\w\W]*))?()/isU'; - - /* - The way this works is: match all blocks using the standard form with a different keyword in the block each time, - and replace them with appropriate PHP logic. Plugin-extensible now. :-) - */ - - // This is a workaround for what seems like a PCRE bug - while ( preg_match_all($regexp, $text, $matches) ) - { - - for ( $i = 0; $i < count($matches[0]); $i++ ) - { - $start_tag =& $matches[1][$i]; - $type =& $matches[2][$i]; - $test =& $matches[3][$i]; - $particle_true =& $matches[4][$i]; - $else_tag =& $matches[6][$i]; - $particle_else =& $matches[7][$i]; - $end_tag =& $matches[8][$i]; - - switch($type) - { - case 'BEGIN': - $cond = "isset(\$this->tpl_bool['$test']) && \$this->tpl_bool['$test']"; - break; - case 'BEGINNOT': - $cond = "!isset(\$this->tpl_bool['$test']) || ( isset(\$this->tpl_bool['$test']) && !\$this->tpl_bool['$test'] )"; - break; - case 'IFPLUGIN': - $cond = "getConfig('plugin_$test') == '1'"; - break; - case 'IFSET': - $cond = "isset(\$this->tpl_strings['$test'])"; - break; - default: - // only do this if the plugins API is loaded - if ( is_object(@$plugins) ) - { - $code = $plugins->setHook('template_compile_logic_cond'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - break; - } - - if ( !isset($cond) || ( isset($cond) && !is_string($cond) ) ) - continue; - - $tag_complete = <</is', $text, $php_matches); + + foreach ( $php_matches[0] as $i => $match ) + { + // Substitute the PHP section with a random tag + $tag = "{PHP:$i:$seed}"; + $text = str_replace_once($match, $tag, $text); + } + + // Escape slashes and single quotes in template code + $text = str_replace('\\', '\\\\', $text); + $text = str_replace('\'', '\\\'', $text); + + // Initialize the PHP compiled code + $text = 'ob_start(); global $paths, $template; echo \''.$text.'\'; $tpl_code = ob_get_contents(); ob_end_clean(); return $tpl_code;'; + + ## + ## Main rules + ## + + // + // Conditionals + // + + $keywords = array('BEGIN', 'BEGINNOT', 'IFSET', 'IFPLUGIN'); + + // only do this if the plugins API is loaded + if ( is_object(@$plugins) ) + { + $code = $plugins->setHook('template_compile_logic_keyword'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + + $keywords = implode('|', $keywords); + + // Matches + // 1 2 3 4 56 7 8 9 + $regexp = '/()([\w\W]*)(()([\w\W]*))?()/isU'; + + /* + The way this works is: match all blocks using the standard form with a different keyword in the block each time, + and replace them with appropriate PHP logic. Plugin-extensible now. :-) + */ + + // This is a workaround for what seems like a PCRE bug + while ( preg_match_all($regexp, $text, $matches) ) + { + + for ( $i = 0; $i < count($matches[0]); $i++ ) + { + $start_tag =& $matches[1][$i]; + $type =& $matches[2][$i]; + $test =& $matches[3][$i]; + $particle_true =& $matches[4][$i]; + $else_tag =& $matches[6][$i]; + $particle_else =& $matches[7][$i]; + $end_tag =& $matches[8][$i]; + + switch($type) + { + case 'BEGIN': + $cond = "isset(\$this->tpl_bool['$test']) && \$this->tpl_bool['$test']"; + break; + case 'BEGINNOT': + $cond = "!isset(\$this->tpl_bool['$test']) || ( isset(\$this->tpl_bool['$test']) && !\$this->tpl_bool['$test'] )"; + break; + case 'IFPLUGIN': + $cond = "getConfig('plugin_$test') == '1'"; + break; + case 'IFSET': + $cond = "isset(\$this->tpl_strings['$test'])"; + break; + default: + // only do this if the plugins API is loaded + if ( is_object(@$plugins) ) + { + $code = $plugins->setHook('template_compile_logic_cond'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + break; + } + + if ( !isset($cond) || ( isset($cond) && !is_string($cond) ) ) + continue; + + $tag_complete = <<<?php\n" . htmlspecialchars($text."\n\n".print_r($matches,true)) . "\n\n?>"); - - // - // Data substitution/variables - // - - // System messages - $text = preg_replace('//is', '\' . $this->parse_system_message($paths->sysMsg(\'\\1\')) . \'', $text); - - // Hooks - $text = preg_replace('//', '\' . $this->get_theme_hook(\'\\1\') . \'', $text); - - // only do this if the plugins API is loaded - if ( is_object(@$plugins) ) - { - $code = $plugins->setHook('template_compile_subst'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - - // Template variables - $text = preg_replace('/\{([A-z0-9_-]+?)\}/is', '\' . $this->tpl_strings[\'\\1\'] . \'', $text); - - // Reinsert PHP - - foreach ( $php_matches[1] as $i => $match ) - { - // Substitute the random tag with the "real" PHP code - $tag = "{PHP:$i:$seed}"; - $text = str_replace_once($tag, "'; $match echo '", $text); - } - - // echo('
' . htmlspecialchars($text) . '
'); - - return $text; + + $text = str_replace_once($matches[0][$i], $tag_complete, $text); + } + } + + // For debugging ;-) + // die("
<?php\n" . htmlspecialchars($text."\n\n".print_r($matches,true)) . "\n\n?>
"); + + // + // Data substitution/variables + // + + // System messages + $text = preg_replace('//is', '\' . $this->parse_system_message($paths->sysMsg(\'\\1\')) . \'', $text); + + // Hooks + $text = preg_replace('//', '\' . $this->get_theme_hook(\'\\1\') . \'', $text); + + // only do this if the plugins API is loaded + if ( is_object(@$plugins) ) + { + $code = $plugins->setHook('template_compile_subst'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + + // Template variables + $text = preg_replace('/\{([A-z0-9_-]+?)\}/is', '\' . $this->tpl_strings[\'\\1\'] . \'', $text); + + // Reinsert PHP + + foreach ( $php_matches[1] as $i => $match ) + { + // Substitute the random tag with the "real" PHP code + $tag = "{PHP:$i:$seed}"; + $text = str_replace_once($tag, "'; $match echo '", $text); + } + + // echo('
' . htmlspecialchars($text) . '
'); + + return $text; } /** @@ -2820,64 +2820,64 @@ class templateIndividual extends template { - var $tpl_strings, $tpl_bool, $tpl_code; - var $compiled = false; - /** - * Constructor. - */ - function __construct($text) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $this->tpl_code = $text; - $this->tpl_strings = $template->tpl_strings; - $this->tpl_bool = $template->tpl_bool; - } - /** - * PHP 4 constructor. Deprecated in 1.1.x. - */ - /* - function templateIndividual($text) - { - $this->__construct($text); - } - */ - - /** - * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. - * @param $vars array - */ - - // We add the unused variable $from_internal here to silence "declaration should be compatible" errors - function assign_vars($vars, $from_internal = false) - { - $this->tpl_strings = array_merge($this->tpl_strings, $vars); - } - - /** - * Assigns an array of boolean values to the template. These can be used for statements. - * @param $vars array - */ - - // We add the unused variable $from_internal here to silence "declaration should be compatible" errors - function assign_bool($vars, $from_internal = false) - { - $this->tpl_bool = array_merge($this->tpl_bool, $vars); - } - - /** - * Compiles and executes the template code. - * @return string - */ - function run() - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!$this->compiled) - { - $this->tpl_code = $this->compile_template_text($this->tpl_code); - $this->compiled = true; - } - return eval($this->tpl_code); - } + var $tpl_strings, $tpl_bool, $tpl_code; + var $compiled = false; + /** + * Constructor. + */ + function __construct($text) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $this->tpl_code = $text; + $this->tpl_strings = $template->tpl_strings; + $this->tpl_bool = $template->tpl_bool; + } + /** + * PHP 4 constructor. Deprecated in 1.1.x. + */ + /* + function templateIndividual($text) + { + $this->__construct($text); + } + */ + + /** + * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. + * @param $vars array + */ + + // We add the unused variable $from_internal here to silence "declaration should be compatible" errors + function assign_vars($vars, $from_internal = false) + { + $this->tpl_strings = array_merge($this->tpl_strings, $vars); + } + + /** + * Assigns an array of boolean values to the template. These can be used for statements. + * @param $vars array + */ + + // We add the unused variable $from_internal here to silence "declaration should be compatible" errors + function assign_bool($vars, $from_internal = false) + { + $this->tpl_bool = array_merge($this->tpl_bool, $vars); + } + + /** + * Compiles and executes the template code. + * @return string + */ + function run() + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!$this->compiled) + { + $this->tpl_code = $this->compile_template_text($this->tpl_code); + $this->compiled = true; + } + return eval($this->tpl_code); + } } /** @@ -2887,443 +2887,443 @@ class template_nodb { - var $fading_button, $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list; - function __construct() - { - $this->tpl_bool = Array(); - $this->tpl_strings = Array(); - $this->sidebar_extra = ''; - $this->sidebar_widgets = ''; - $this->toolbar_menu = ''; - $this->additional_headers = ''; - - $this->fading_button = '
-  -
'; - - // get list of themes - $this->theme_list = array(); - $this->named_theme_list = array(); - $order = 0; - - if ( $dir = @opendir( ENANO_ROOT . '/themes' ) ) - { - while ( $dh = @readdir($dir) ) - { - if ( $dh == '.' || $dh == '..' || !is_dir( ENANO_ROOT . "/themes/$dh" ) ) - continue; - $theme_dir = ENANO_ROOT . "/themes/$dh"; - if ( !file_exists("$theme_dir/theme.cfg") ) - continue; - $data = array( - 'theme_id' => $dh, - 'theme_name' => ucwords($dh), - 'enabled' => 1, - 'theme_order' => ++$order, - 'default_style' => $this->get_default_style($dh) - ); - $this->named_theme_list[$dh] = $data; - $this->theme_list[] =& $this->named_theme_list[$dh]; - } - @closedir($dir); - } - } - function template() { - $this->__construct(); - } - function get_default_style($theme_id) - { - if ( !is_dir( ENANO_ROOT . "/themes/$theme_id/css" ) ) - return false; - $ds = false; - if ( $dh = @opendir( ENANO_ROOT . "/themes/$theme_id/css" ) ) - { - while ( $dir = @readdir($dh) ) - { - if ( !preg_match('/\.css$/', $dir) ) - continue; - if ( $dir == '_printable.css' ) - continue; - $ds = preg_replace('/\.css$/', '', $dir); - break; - } - closedir($dh); - } - else - { - return false; - } - return $ds; - } - function get_css($s = false) - { - if ( $s ) - return $this->process_template('css/'.$s); - else - return $this->process_template('css/'.$this->style.'.css'); - } - function load_theme($name, $css, $auto_init = true) - { - if ( !isset($this->named_theme_list[$name]) ) - $name = $this->theme_list[0]['theme_id']; - - if ( !file_exists(ENANO_ROOT . "/themes/$name/css/$css.css") ) - $css = $this->named_theme_list[$name]['default_style']; - - $this->theme = $name; - $this->style = $css; - - $this->tpl_strings['SCRIPTPATH'] = scriptPath; - if ( $auto_init ) - $this->init_vars(); - } - function add_header($html) - { - $this->additional_headers .= "\n\n\n " . $html; - } - function init_vars() - { - global $sideinfo; - global $this_page; - global $lang; - global $db, $session, $paths, $template, $plugins; // Common objects - $tplvars = $this->extract_vars('elements.tpl'); - $tb = ''; - // Get the "article" button text (depends on namespace) - if(defined('IN_ENANO_INSTALL') && is_object($lang)) $ns = $lang->get('meta_btn_article'); - else if ( isset($GLOBALS['article_btn']) ) $ns = $GLOBALS['article_btn']; - else $ns = 'system error page'; - $t = str_replace('{FLAGS}', 'onclick="return false;" class="current" title="Hey! A button that doesn\'t do anything. Clever..." accesskey="a"', $tplvars['toolbar_button']); - $t = str_replace('{HREF}', '#', $t); - $t = str_replace('{TEXT}', $ns, $t); - $tb .= $t; - - // Page toolbar - - $this->tpl_bool = Array( - 'auth_admin'=>true, - 'user_logged_in'=>true, - 'right_sidebar'=>false, - ); - $this->tpl_bool['in_sidebar_admin'] = false; - - $this->tpl_bool['auth_rename'] = false; - - $asq = $asa = ''; - - $this->tpl_bool['fixed_menus'] = false; - $slink = defined('IN_ENANO_INSTALL') ? scriptPath.'/install.php?mode=css' : makeUrlNS('Special', 'CSS'); - - $title = ( is_object($paths) ) ? $paths->page : 'Critical error'; - - $headers = ''; - - $js_dynamic = ''; - if ( defined('IN_ENANO_INSTALL') ) - { - $js_dynamic .= ''; - } - $js_dynamic .= ''; - - global $site_name, $site_desc; - $site_default_name = ( !empty($site_name) ) ? $site_name : 'Critical error'; - $site_default_desc = ( !empty($site_desc) ) ? $site_desc : 'This site is experiencing a problem and cannot load.'; - - $site_name_final = ( defined('IN_ENANO_INSTALL') && is_object($lang) ) ? $lang->get('meta_site_name') : $site_default_name; - $site_desc_final = ( defined('IN_ENANO_INSTALL') && is_object($lang) ) ? $lang->get('meta_site_desc') : $site_default_desc; - - // The rewritten template engine will process all required vars during the load_template stage instead of (cough) re-processing everything each time around. - $tpl_strings = Array( - 'PAGE_NAME'=>$this_page, - 'PAGE_URLNAME'=>'Null', - 'SITE_NAME' => $site_name_final, - 'USERNAME'=>'admin', - 'SITE_DESC' => $site_desc_final, - 'TOOLBAR'=>$tb, - 'SCRIPTPATH'=>scriptPath, - 'CONTENTPATH'=>contentPath, - 'CDNPATH' => scriptPath, - 'JS_HEADER' => '', - 'JS_FOOTER' => '', - 'ADMIN_SID_QUES'=>$asq, - 'ADMIN_SID_AMP'=>$asa, - 'ADMIN_SID_AMP_HTML'=>'', - 'ADDITIONAL_HEADERS'=>$this->additional_headers, - 'SIDEBAR_EXTRA'=>'', - 'COPYRIGHT'=>( defined('IN_ENANO_INSTALL') && is_object($lang) ) ? $lang->get('meta_enano_copyright') : ( defined('ENANO_CONFIG_FETCHED') ? getConfig('copyright_notice') : '' ), - 'TOOLBAR_EXTRAS'=>'', - 'REQUEST_URI'=>( isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '' ).$_SERVER['REQUEST_URI'], - 'STYLE_LINK'=>$slink, - 'LOGOUT_LINK'=>'', - 'THEME_LINK'=>'', - 'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme, - 'THEME_ID'=>$this->theme, - 'STYLE_ID'=>$this->style, - 'JS_DYNAMIC_VARS'=>$js_dynamic, - 'SIDEBAR_RIGHT'=>'', - 'REPORT_URI' => '', - 'URL_ABOUT_ENANO' => 'http://enanocms.org/', - 'ENANO_VERSION' => enano_version() - ); - $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings); - - $sidebar = ( is_array(@$sideinfo) ) ? $sideinfo : ''; - if ( $sidebar != '' ) - { - if ( isset($tplvars['sidebar_top']) ) - { - $text = $this->makeParserText($tplvars['sidebar_top']); - $top = $text->run(); - } - else - { - $top = ''; - } - - $p = $this->makeParserText($tplvars['sidebar_section']); - $b = $this->makeParserText($tplvars['sidebar_button']); - $sidebar_text = ''; - - foreach ( $sidebar as $title => $links ) - { - $p->assign_vars(array( - 'TITLE' => $title - )); - // build content - $content = ''; - foreach ( $links as $link_text => $url ) - { - $b->assign_vars(array( - 'HREF' => htmlspecialchars($url), - 'FLAGS' => '', - 'TEXT' => $link_text - )); - $content .= $b->run(); - } - $p->assign_vars(array( - 'CONTENT' => $content - )); - $sidebar_text .= $p->run(); - } - - if ( isset($tplvars['sidebar_bottom']) ) - { - $text = $this->makeParserText($tplvars['sidebar_bottom']); - $bottom = $text->run(); - } - else - { - $bottom = ''; - } - $sidebar = $top . $sidebar_text . $bottom; - } - $this->tpl_strings['SIDEBAR_LEFT'] = $sidebar; - - $this->tpl_bool['sidebar_left'] = ( $this->tpl_strings['SIDEBAR_LEFT'] != '') ? true : false; - $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != '') ? true : false; - $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility - $this->tpl_bool['stupid_mode'] = true; - } - function header($simple = false) - { - $filename = ( $simple ) ? 'simple-header.tpl' : 'header.tpl'; - if ( !$this->no_headers ) - { - echo $this->process_template($filename); - } - } - function footer($simple = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if(!$this->no_headers) { - global $_starttime; - - $filename = ( $simple ) ? 'simple-footer.tpl' : 'footer.tpl'; - $t = $this->process_template($filename); - - $f = microtime_float(); - $f = $f - $_starttime; - $f = round($f, 4); - - if ( is_object($lang) ) - { - $t_loc = $lang->get('page_msg_stats_gentime_short', array('time' => $f)); - $t_loc_long = $lang->get('page_msg_stats_gentime_long', array('time' => $f)); - $q_loc = '' . $lang->get('page_msg_stats_sql', array('nq' => ( is_object($db) ? $db->num_queries : 'N/A' ))) . ''; - $dbg = $t_loc; - $dbg_long = $t_loc_long; - if ( $session->user_level >= USER_LEVEL_ADMIN ) - { - $dbg .= "  |  $q_loc"; - $dbg_long .= "  |  $q_loc"; - } - $t = str_replace('[[EnanoPoweredLink]]', $lang->get('page_enano_powered', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); - $t = str_replace('[[EnanoPoweredLinkLong]]', $lang->get('page_enano_powered_long', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); - } - else - { - $t_loc = "Time: {$f}s"; - $t_loc_long = "Generated in {$f}sec"; - $q_loc = '' . ( is_object($db) ? "{$db->num_queries} SQL" : 'Queries: N/A' ) . ''; - $dbg = $t_loc; - $dbg_long = $t_loc_long; - if ( is_object($session) ) - { - if ( $session->user_level >= USER_LEVEL_ADMIN ) - { - $dbg .= "  |  $q_loc"; - $dbg_long .= "  |  $q_loc"; - } - } - $t = str_replace('[[EnanoPoweredLink]]', 'Powered by Enano', $t); - $t = str_replace('[[EnanoPoweredLinkLong]]', 'Website engine powered by Enano', $t); - } - - $t = str_replace('[[Stats]]', $dbg, $t); - $t = str_replace('[[StatsLong]]', $dbg_long, $t); - $t = str_replace('[[NumQueries]]', ( is_object($db) ? (string)$db->num_queries : '0' ), $t); - $t = str_replace('[[GenTime]]', (string)$f, $t); - $t = str_replace('[[NumQueriesLoc]]', $q_loc, $t); - $t = str_replace('[[GenTimeLoc]]', $t_loc, $t); - - if ( defined('ENANO_PROFILE') ) - { - $t = str_replace('', '
' . profiler_make_html() . '
', $t); - } - - echo $t; - } - else return ''; - } - function getHeader() - { - if(!$this->no_headers) return $this->process_template('header.tpl'); - else return ''; - } - function getFooter() - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!$this->no_headers) { - global $_starttime; - $f = microtime(true); - $f = $f - $_starttime; - $f = round($f, 4); - if(defined('IN_ENANO_INSTALL')) $nq = 'N/A'; - else $nq = $db->num_queries; - if($nq == 0) $nq = 'N/A'; - $dbg = 'Time: '.$f.'s | Queries: '.$nq; - if($nq == 0) $nq = 'N/A'; - $t = $this->process_template('footer.tpl'); - $t = str_replace('[[Stats]]', $dbg, $t); - return $t; - } - else return ''; - } - - function process_template($file) - { - $compiled = $this->compile_template($file); - $result = eval($compiled); - return $result; - } - - function extract_vars($file) { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting'); - $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file); - preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches); - $tplvars = Array(); - for($i=0;$itheme.'/'.$text); - return $this->compile_template_text_post(template_compiler_core($text)); - } - - function compile_template_text($text) - { - return $this->compile_template_text_post(template_compiler_core($text)); - } - - /** - * Post-processor for template code. Basically what this does is it localizes {lang:foo} blocks. - * @param string Mostly-processed TPL code - * @return string - */ - - function compile_template_text_post($text) - { - global $lang; - preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $text, $matches); - foreach ( $matches[1] as $i => $string_id ) - { - if ( is_object(@$lang) ) - { - $string = $lang->get($string_id); - } - else - { - $string = '[language not loaded]'; - } - $string = str_replace('\\', '\\\\', $string); - $string = str_replace('\'', '\\\'', $string); - $text = str_replace_once($matches[0][$i], $string, $text); - } - return $text; - } - - /** - * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;) - * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class. - * @param $filename the filename of the template to be parsed - * @return object - */ - - function makeParser($filename) - { - $filename = ENANO_ROOT.'/themes/'.$this->theme.'/'.$filename; - if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist'); - $code = file_get_contents($filename); - $parser = new templateIndividualSafe($code, $this); - return $parser; - } - - /** - * Same as $template->makeParser(), but takes a string instead of a filename. - * @param $text the text to parse - * @return object - */ - - function makeParserText($code) - { - $parser = new templateIndividualSafe($code, $this); - return $parser; - } - - /** - * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. - * @param $vars array - */ - function assign_vars($vars, $_ignored = false) - { - if(is_array($this->tpl_strings)) - $this->tpl_strings = array_merge($this->tpl_strings, $vars); - else - $this->tpl_strings = $vars; - } - - function get_theme_hook() - { - return ''; - } - + var $fading_button, $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list; + function __construct() + { + $this->tpl_bool = Array(); + $this->tpl_strings = Array(); + $this->sidebar_extra = ''; + $this->sidebar_widgets = ''; + $this->toolbar_menu = ''; + $this->additional_headers = ''; + + $this->fading_button = '
+  +
'; + + // get list of themes + $this->theme_list = array(); + $this->named_theme_list = array(); + $order = 0; + + if ( $dir = @opendir( ENANO_ROOT . '/themes' ) ) + { + while ( $dh = @readdir($dir) ) + { + if ( $dh == '.' || $dh == '..' || !is_dir( ENANO_ROOT . "/themes/$dh" ) ) + continue; + $theme_dir = ENANO_ROOT . "/themes/$dh"; + if ( !file_exists("$theme_dir/theme.cfg") ) + continue; + $data = array( + 'theme_id' => $dh, + 'theme_name' => ucwords($dh), + 'enabled' => 1, + 'theme_order' => ++$order, + 'default_style' => $this->get_default_style($dh) + ); + $this->named_theme_list[$dh] = $data; + $this->theme_list[] =& $this->named_theme_list[$dh]; + } + @closedir($dir); + } + } + function template() { + $this->__construct(); + } + function get_default_style($theme_id) + { + if ( !is_dir( ENANO_ROOT . "/themes/$theme_id/css" ) ) + return false; + $ds = false; + if ( $dh = @opendir( ENANO_ROOT . "/themes/$theme_id/css" ) ) + { + while ( $dir = @readdir($dh) ) + { + if ( !preg_match('/\.css$/', $dir) ) + continue; + if ( $dir == '_printable.css' ) + continue; + $ds = preg_replace('/\.css$/', '', $dir); + break; + } + closedir($dh); + } + else + { + return false; + } + return $ds; + } + function get_css($s = false) + { + if ( $s ) + return $this->process_template('css/'.$s); + else + return $this->process_template('css/'.$this->style.'.css'); + } + function load_theme($name, $css, $auto_init = true) + { + if ( !isset($this->named_theme_list[$name]) ) + $name = $this->theme_list[0]['theme_id']; + + if ( !file_exists(ENANO_ROOT . "/themes/$name/css/$css.css") ) + $css = $this->named_theme_list[$name]['default_style']; + + $this->theme = $name; + $this->style = $css; + + $this->tpl_strings['SCRIPTPATH'] = scriptPath; + if ( $auto_init ) + $this->init_vars(); + } + function add_header($html) + { + $this->additional_headers .= "\n\n\n " . $html; + } + function init_vars() + { + global $sideinfo; + global $this_page; + global $lang; + global $db, $session, $paths, $template, $plugins; // Common objects + $tplvars = $this->extract_vars('elements.tpl'); + $tb = ''; + // Get the "article" button text (depends on namespace) + if(defined('IN_ENANO_INSTALL') && is_object($lang)) $ns = $lang->get('meta_btn_article'); + else if ( isset($GLOBALS['article_btn']) ) $ns = $GLOBALS['article_btn']; + else $ns = 'system error page'; + $t = str_replace('{FLAGS}', 'onclick="return false;" class="current" title="Hey! A button that doesn\'t do anything. Clever..." accesskey="a"', $tplvars['toolbar_button']); + $t = str_replace('{HREF}', '#', $t); + $t = str_replace('{TEXT}', $ns, $t); + $tb .= $t; + + // Page toolbar + + $this->tpl_bool = Array( + 'auth_admin'=>true, + 'user_logged_in'=>true, + 'right_sidebar'=>false, + ); + $this->tpl_bool['in_sidebar_admin'] = false; + + $this->tpl_bool['auth_rename'] = false; + + $asq = $asa = ''; + + $this->tpl_bool['fixed_menus'] = false; + $slink = defined('IN_ENANO_INSTALL') ? scriptPath.'/install.php?mode=css' : makeUrlNS('Special', 'CSS'); + + $title = ( is_object($paths) ) ? $paths->page : 'Critical error'; + + $headers = ''; + + $js_dynamic = ''; + if ( defined('IN_ENANO_INSTALL') ) + { + $js_dynamic .= ''; + } + $js_dynamic .= ''; + + global $site_name, $site_desc; + $site_default_name = ( !empty($site_name) ) ? $site_name : 'Critical error'; + $site_default_desc = ( !empty($site_desc) ) ? $site_desc : 'This site is experiencing a problem and cannot load.'; + + $site_name_final = ( defined('IN_ENANO_INSTALL') && is_object($lang) ) ? $lang->get('meta_site_name') : $site_default_name; + $site_desc_final = ( defined('IN_ENANO_INSTALL') && is_object($lang) ) ? $lang->get('meta_site_desc') : $site_default_desc; + + // The rewritten template engine will process all required vars during the load_template stage instead of (cough) re-processing everything each time around. + $tpl_strings = Array( + 'PAGE_NAME'=>$this_page, + 'PAGE_URLNAME'=>'Null', + 'SITE_NAME' => $site_name_final, + 'USERNAME'=>'admin', + 'SITE_DESC' => $site_desc_final, + 'TOOLBAR'=>$tb, + 'SCRIPTPATH'=>scriptPath, + 'CONTENTPATH'=>contentPath, + 'CDNPATH' => scriptPath, + 'JS_HEADER' => '', + 'JS_FOOTER' => '', + 'ADMIN_SID_QUES'=>$asq, + 'ADMIN_SID_AMP'=>$asa, + 'ADMIN_SID_AMP_HTML'=>'', + 'ADDITIONAL_HEADERS'=>$this->additional_headers, + 'SIDEBAR_EXTRA'=>'', + 'COPYRIGHT'=>( defined('IN_ENANO_INSTALL') && is_object($lang) ) ? $lang->get('meta_enano_copyright') : ( defined('ENANO_CONFIG_FETCHED') ? getConfig('copyright_notice') : '' ), + 'TOOLBAR_EXTRAS'=>'', + 'REQUEST_URI'=>( isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '' ).$_SERVER['REQUEST_URI'], + 'STYLE_LINK'=>$slink, + 'LOGOUT_LINK'=>'', + 'THEME_LINK'=>'', + 'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme, + 'THEME_ID'=>$this->theme, + 'STYLE_ID'=>$this->style, + 'JS_DYNAMIC_VARS'=>$js_dynamic, + 'SIDEBAR_RIGHT'=>'', + 'REPORT_URI' => '', + 'URL_ABOUT_ENANO' => 'http://enanocms.org/', + 'ENANO_VERSION' => enano_version() + ); + $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings); + + $sidebar = ( is_array(@$sideinfo) ) ? $sideinfo : ''; + if ( $sidebar != '' ) + { + if ( isset($tplvars['sidebar_top']) ) + { + $text = $this->makeParserText($tplvars['sidebar_top']); + $top = $text->run(); + } + else + { + $top = ''; + } + + $p = $this->makeParserText($tplvars['sidebar_section']); + $b = $this->makeParserText($tplvars['sidebar_button']); + $sidebar_text = ''; + + foreach ( $sidebar as $title => $links ) + { + $p->assign_vars(array( + 'TITLE' => $title + )); + // build content + $content = ''; + foreach ( $links as $link_text => $url ) + { + $b->assign_vars(array( + 'HREF' => htmlspecialchars($url), + 'FLAGS' => '', + 'TEXT' => $link_text + )); + $content .= $b->run(); + } + $p->assign_vars(array( + 'CONTENT' => $content + )); + $sidebar_text .= $p->run(); + } + + if ( isset($tplvars['sidebar_bottom']) ) + { + $text = $this->makeParserText($tplvars['sidebar_bottom']); + $bottom = $text->run(); + } + else + { + $bottom = ''; + } + $sidebar = $top . $sidebar_text . $bottom; + } + $this->tpl_strings['SIDEBAR_LEFT'] = $sidebar; + + $this->tpl_bool['sidebar_left'] = ( $this->tpl_strings['SIDEBAR_LEFT'] != '') ? true : false; + $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != '') ? true : false; + $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility + $this->tpl_bool['stupid_mode'] = true; + } + function header($simple = false) + { + $filename = ( $simple ) ? 'simple-header.tpl' : 'header.tpl'; + if ( !$this->no_headers ) + { + echo $this->process_template($filename); + } + } + function footer($simple = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if(!$this->no_headers) { + global $_starttime; + + $filename = ( $simple ) ? 'simple-footer.tpl' : 'footer.tpl'; + $t = $this->process_template($filename); + + $f = microtime_float(); + $f = $f - $_starttime; + $f = round($f, 4); + + if ( is_object($lang) ) + { + $t_loc = $lang->get('page_msg_stats_gentime_short', array('time' => $f)); + $t_loc_long = $lang->get('page_msg_stats_gentime_long', array('time' => $f)); + $q_loc = '' . $lang->get('page_msg_stats_sql', array('nq' => ( is_object($db) ? $db->num_queries : 'N/A' ))) . ''; + $dbg = $t_loc; + $dbg_long = $t_loc_long; + if ( $session->user_level >= USER_LEVEL_ADMIN ) + { + $dbg .= "  |  $q_loc"; + $dbg_long .= "  |  $q_loc"; + } + $t = str_replace('[[EnanoPoweredLink]]', $lang->get('page_enano_powered', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); + $t = str_replace('[[EnanoPoweredLinkLong]]', $lang->get('page_enano_powered_long', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); + } + else + { + $t_loc = "Time: {$f}s"; + $t_loc_long = "Generated in {$f}sec"; + $q_loc = '' . ( is_object($db) ? "{$db->num_queries} SQL" : 'Queries: N/A' ) . ''; + $dbg = $t_loc; + $dbg_long = $t_loc_long; + if ( is_object($session) ) + { + if ( $session->user_level >= USER_LEVEL_ADMIN ) + { + $dbg .= "  |  $q_loc"; + $dbg_long .= "  |  $q_loc"; + } + } + $t = str_replace('[[EnanoPoweredLink]]', 'Powered by Enano', $t); + $t = str_replace('[[EnanoPoweredLinkLong]]', 'Website engine powered by Enano', $t); + } + + $t = str_replace('[[Stats]]', $dbg, $t); + $t = str_replace('[[StatsLong]]', $dbg_long, $t); + $t = str_replace('[[NumQueries]]', ( is_object($db) ? (string)$db->num_queries : '0' ), $t); + $t = str_replace('[[GenTime]]', (string)$f, $t); + $t = str_replace('[[NumQueriesLoc]]', $q_loc, $t); + $t = str_replace('[[GenTimeLoc]]', $t_loc, $t); + + if ( defined('ENANO_PROFILE') ) + { + $t = str_replace('', '
' . profiler_make_html() . '
', $t); + } + + echo $t; + } + else return ''; + } + function getHeader() + { + if(!$this->no_headers) return $this->process_template('header.tpl'); + else return ''; + } + function getFooter() + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!$this->no_headers) { + global $_starttime; + $f = microtime(true); + $f = $f - $_starttime; + $f = round($f, 4); + if(defined('IN_ENANO_INSTALL')) $nq = 'N/A'; + else $nq = $db->num_queries; + if($nq == 0) $nq = 'N/A'; + $dbg = 'Time: '.$f.'s | Queries: '.$nq; + if($nq == 0) $nq = 'N/A'; + $t = $this->process_template('footer.tpl'); + $t = str_replace('[[Stats]]', $dbg, $t); + return $t; + } + else return ''; + } + + function process_template($file) + { + $compiled = $this->compile_template($file); + $result = eval($compiled); + return $result; + } + + function extract_vars($file) { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting'); + $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file); + preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches); + $tplvars = Array(); + for($i=0;$itheme.'/'.$text); + return $this->compile_template_text_post(template_compiler_core($text)); + } + + function compile_template_text($text) + { + return $this->compile_template_text_post(template_compiler_core($text)); + } + + /** + * Post-processor for template code. Basically what this does is it localizes {lang:foo} blocks. + * @param string Mostly-processed TPL code + * @return string + */ + + function compile_template_text_post($text) + { + global $lang; + preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $text, $matches); + foreach ( $matches[1] as $i => $string_id ) + { + if ( is_object(@$lang) ) + { + $string = $lang->get($string_id); + } + else + { + $string = '[language not loaded]'; + } + $string = str_replace('\\', '\\\\', $string); + $string = str_replace('\'', '\\\'', $string); + $text = str_replace_once($matches[0][$i], $string, $text); + } + return $text; + } + + /** + * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;) + * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class. + * @param $filename the filename of the template to be parsed + * @return object + */ + + function makeParser($filename) + { + $filename = ENANO_ROOT.'/themes/'.$this->theme.'/'.$filename; + if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist'); + $code = file_get_contents($filename); + $parser = new templateIndividualSafe($code, $this); + return $parser; + } + + /** + * Same as $template->makeParser(), but takes a string instead of a filename. + * @param $text the text to parse + * @return object + */ + + function makeParserText($code) + { + $parser = new templateIndividualSafe($code, $this); + return $parser; + } + + /** + * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. + * @param $vars array + */ + function assign_vars($vars, $_ignored = false) + { + if(is_array($this->tpl_strings)) + $this->tpl_strings = array_merge($this->tpl_strings, $vars); + else + $this->tpl_strings = $vars; + } + + function get_theme_hook() + { + return ''; + } + } // class template_nodb /** @@ -3333,58 +3333,58 @@ class templateIndividualSafe extends template_nodb { - var $tpl_strings, $tpl_bool, $tpl_code; - var $compiled = false; - /** - * Constructor. - */ - function __construct($text, $parent) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $this->tpl_code = $text; - $this->tpl_strings = $parent->tpl_strings; - $this->tpl_bool = $parent->tpl_bool; - } - /** - * PHP 4 constructor. - */ - function templateIndividual($text) - { - $this->__construct($text); - } - /** - * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. - * @param $vars array - */ - function assign_vars($vars, $_ignored = false) - { - if(is_array($this->tpl_strings)) - $this->tpl_strings = array_merge($this->tpl_strings, $vars); - else - $this->tpl_strings = $vars; - } - /** - * Assigns an array of boolean values to the template. These can be used for statements. - * @param $vars array - */ - function assign_bool($vars) - { - $this->tpl_bool = array_merge($this->tpl_bool, $vars); - } - /** - * Compiles and executes the template code. - * @return string - */ - function run() - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!$this->compiled) - { - $this->tpl_code = $this->compile_template_text($this->tpl_code); - $this->compiled = true; - } - return eval($this->tpl_code); - } + var $tpl_strings, $tpl_bool, $tpl_code; + var $compiled = false; + /** + * Constructor. + */ + function __construct($text, $parent) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $this->tpl_code = $text; + $this->tpl_strings = $parent->tpl_strings; + $this->tpl_bool = $parent->tpl_bool; + } + /** + * PHP 4 constructor. + */ + function templateIndividual($text) + { + $this->__construct($text); + } + /** + * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file. + * @param $vars array + */ + function assign_vars($vars, $_ignored = false) + { + if(is_array($this->tpl_strings)) + $this->tpl_strings = array_merge($this->tpl_strings, $vars); + else + $this->tpl_strings = $vars; + } + /** + * Assigns an array of boolean values to the template. These can be used for statements. + * @param $vars array + */ + function assign_bool($vars) + { + $this->tpl_bool = array_merge($this->tpl_bool, $vars); + } + /** + * Compiles and executes the template code. + * @return string + */ + function run() + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!$this->compiled) + { + $this->tpl_code = $this->compile_template_text($this->tpl_code); + $this->compiled = true; + } + return eval($this->tpl_code); + } } ?>