<?php /* Question2Answer (c) Gideon Greenspan http://www.question2answer.org/ File: qa-include/qa-theme-base.php Version: See define()s at top of qa-include/qa-base.php Description: Default theme class, broken into lots of little functions for easy overriding This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. More about this license: http://www.question2answer.org/license.php */ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser header('Location: ../'); exit; } /* How do I make a theme which goes beyond CSS to actually modify the HTML output? Create a file named qa-theme.php in your new theme directory which defines a class qa_html_theme that extends this base class qa_html_theme_base. You can then override any of the methods below, referring back to the default method using double colon (qa_html_theme_base::) notation. Plugins can also do something similar by using a layer. For more information and to see some example code, please consult the online Q2A documentation. */ class qa_html_theme_base { protected $indent = 0; protected $lines = 0; protected $context = array(); // whether to use new block layout in rankings (true) or fall back to tables (false) protected $ranking_block_layout = false; protected $rooturl; protected $template; protected $content; protected $request; public function __construct($template, $content, $rooturl, $request) /* Initialize the object and assign local variables */ { $this->template = $template; $this->content = $content; $this->rooturl = $rooturl; $this->request = $request; } /** * @deprecated PHP4-style constructor deprecated from 1.7; please use proper `__construct` * function instead. */ public function qa_html_theme_base($template, $content, $rooturl, $request) { self::__construct($template, $content, $rooturl, $request); } public function output_array($elements) /* Output each element in $elements on a separate line, with automatic HTML indenting. This should be passed markup which uses the <tag/> form for unpaired tags, to help keep track of indenting, although its actual output converts these to <tag> for W3C validation */ { foreach ($elements as $element) { $delta = substr_count($element, '<') - substr_count($element, '<!') - 2*substr_count($element, '</') - substr_count($element, '/>'); if ($delta < 0) $this->indent += $delta; echo str_repeat("\t", max(0, $this->indent)).str_replace('/>', '>', $element)."\n"; if ($delta > 0) $this->indent += $delta; $this->lines++; } } public function output() // other parameters picked up via func_get_args() /* Output each passed parameter on a separate line - see output_array() comments */ { $args = func_get_args(); $this->output_array($args); } public function output_raw($html) /* Output $html at the current indent level, but don't change indent level based on the markup within. Useful for user-entered HTML which is unlikely to follow the rules we need to track indenting */ { if (strlen($html)) echo str_repeat("\t", max(0, $this->indent)).$html."\n"; } public function output_split($parts, $class, $outertag='span', $innertag='span', $extraclass=null) /* Output the three elements ['prefix'], ['data'] and ['suffix'] of $parts (if they're defined), with appropriate CSS classes based on $class, using $outertag and $innertag in the markup. */ { if (empty($parts) && strtolower($outertag) != 'td') return; $this->output( '<'.$outertag.' class="'.$class.(isset($extraclass) ? (' '.$extraclass) : '').'">', (strlen(@$parts['prefix']) ? ('<'.$innertag.' class="'.$class.'-pad">'.$parts['prefix'].'</'.$innertag.'>') : ''). (strlen(@$parts['data']) ? ('<'.$innertag.' class="'.$class.'-data">'.$parts['data'].'</'.$innertag.'>') : ''). (strlen(@$parts['suffix']) ? ('<'.$innertag.' class="'.$class.'-pad">'.$parts['suffix'].'</'.$innertag.'>') : ''), '</'.$outertag.'>' ); } public function set_context($key, $value) /* Set some context, which be accessed via $this->context for a function to know where it's being used on the page */ { $this->context[$key] = $value; } public function clear_context($key) /* Clear some context (used at the end of the appropriate loop) */ { unset($this->context[$key]); } public function reorder_parts($parts, $beforekey=null, $reorderrelative=true) /* Reorder the parts of the page according to the $parts array which contains part keys in their new order. Call this before main_parts(). See the docs for qa_array_reorder() in qa-util-sort.php for the other parameters. */ { require_once QA_INCLUDE_DIR.'qa-util-sort.php'; qa_array_reorder($this->content, $parts, $beforekey, $reorderrelative); } public function widgets($region, $place) /* Output the widgets (as provided in $this->content['widgets']) for $region and $place */ { if (count(@$this->content['widgets'][$region][$place])) { $this->output('<div class="qa-widgets-'.$region.' qa-widgets-'.$region.'-'.$place.'">'); foreach ($this->content['widgets'][$region][$place] as $module) { $this->output('<div class="qa-widget-'.$region.' qa-widget-'.$region.'-'.$place.'">'); $module->output_widget($region, $place, $this, $this->template, $this->request, $this->content); $this->output('</div>'); } $this->output('</div>', ''); } } public function finish() /* Post-output cleanup. For now, check that the indenting ended right, and if not, output a warning in an HTML comment */ { if ($this->indent) { echo "<!--\nIt's no big deal, but your HTML could not be indented properly. To fix, please:\n". "1. Use this->output() to output all HTML.\n". "2. Balance all paired tags like <td>...</td> or <div>...</div>.\n". "3. Use a slash at the end of unpaired tags like <img/> or <input/>.\n". "Thanks!\n-->\n"; } } // From here on, we have a large number of class methods which output particular pieces of HTML markup // The calling chain is initiated from qa-page.php, or qa-ajax-*.php for refreshing parts of a page, // For most HTML elements, the name of the function is similar to the element's CSS class, for example: // search() outputs <div class="qa-search">, q_list() outputs <div class="qa-q-list">, etc... public function doctype() { $this->output('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'); } public function html() { $attribution = '<!-- Powered by Question2Answer - http://www.question2answer.org/ -->'; $this->output( '<html>', $attribution ); $this->head(); $this->body(); $this->output( $attribution, '</html>' ); } public function head() { $this->output( '<head>', '<meta http-equiv="content-type" content="'.$this->content['content_type'].'"/>' ); $this->head_title(); $this->head_metas(); $this->head_css(); $this->head_links(); $this->head_lines(); $this->head_script(); $this->head_custom(); $this->output('</head>'); } public function head_title() { $pagetitle = strlen($this->request) ? strip_tags(@$this->content['title']) : ''; $headtitle = (strlen($pagetitle) ? ($pagetitle.' - ') : '').$this->content['site_title']; $this->output('<title>'.$headtitle.'</title>'); } public function head_metas() { if (strlen(@$this->content['description'])) $this->output('<meta name="description" content="'.$this->content['description'].'"/>'); if (strlen(@$this->content['keywords'])) // as far as I know, meta keywords have zero effect on search rankings or listings $this->output('<meta name="keywords" content="'.$this->content['keywords'].'"/>'); } public function head_links() { if (isset($this->content['canonical'])) $this->output('<link rel="canonical" href="'.$this->content['canonical'].'"/>'); if (isset($this->content['feed']['url'])) $this->output('<link rel="alternate" type="application/rss+xml" href="'.$this->content['feed']['url'].'" title="'.@$this->content['feed']['label'].'"/>'); // convert page links to rel=prev and rel=next tags if (isset($this->content['page_links']['items'])) { foreach ($this->content['page_links']['items'] as $page_link) { if (in_array($page_link['type'], array('prev', 'next'))) $this->output('<link rel="' . $page_link['type'] . '" href="' . $page_link['url'] . '" />'); } } } public function head_script() { if (isset($this->content['script'])) { foreach ($this->content['script'] as $scriptline) $this->output_raw($scriptline); } } public function head_css() { $this->output('<link rel="stylesheet" type="text/css" href="'.$this->rooturl.$this->css_name().'"/>'); if (isset($this->content['css_src'])) { foreach ($this->content['css_src'] as $css_src) $this->output('<link rel="stylesheet" type="text/css" href="'.$css_src.'"/>'); } if (!empty($this->content['notices'])) { $this->output( '<style><!--', '.qa-body-js-on .qa-notice {display:none;}', '//--></style>' ); } } public function css_name() { return 'qa-styles.css?'.QA_VERSION; } public function head_lines() { if (isset($this->content['head_lines'])) { foreach ($this->content['head_lines'] as $line) $this->output_raw($line); } } public function head_custom() { // abstract method } public function body() { $this->output('<body'); $this->body_tags(); $this->output('>'); $this->body_script(); $this->body_header(); $this->body_content(); $this->body_footer(); $this->body_hidden(); $this->output('</body>'); } public function body_hidden() { $this->output('<div style="position:absolute; left:-9999px; top:-9999px;">'); $this->waiting_template(); $this->output('</div>'); } public function waiting_template() { $this->output('<span id="qa-waiting-template" class="qa-waiting">...</span>'); } public function body_script() { $this->output( '<script type="text/javascript">', "var b=document.getElementsByTagName('body')[0];", "b.className=b.className.replace('qa-body-js-off', 'qa-body-js-on');", '</script>' ); } public function body_header() { if (isset($this->content['body_header'])) $this->output_raw($this->content['body_header']); } public function body_footer() { if (isset($this->content['body_footer'])) $this->output_raw($this->content['body_footer']); } public function body_content() { $this->body_prefix(); $this->notices(); $this->output('<div class="qa-body-wrapper">', ''); $this->widgets('full', 'top'); $this->header(); $this->widgets('full', 'high'); $this->sidepanel(); $this->main(); $this->widgets('full', 'low'); $this->footer(); $this->widgets('full', 'bottom'); $this->output('</div> <!-- END body-wrapper -->'); $this->body_suffix(); } public function body_tags() { $class = 'qa-template-'.qa_html($this->template); if (isset($this->content['categoryids'])) { foreach ($this->content['categoryids'] as $categoryid) $class .= ' qa-category-'.qa_html($categoryid); } $this->output('class="'.$class.' qa-body-js-off"'); } public function body_prefix() { // abstract method } public function body_suffix() { // abstract method } public function notices() { if (!empty($this->content['notices'])) { foreach ($this->content['notices'] as $notice) $this->notice($notice); } } public function notice($notice) { $this->output('<div class="qa-notice" id="'.$notice['id'].'">'); if (isset($notice['form_tags'])) $this->output('<form '.$notice['form_tags'].'>'); $this->output_raw($notice['content']); $this->output('<input '.$notice['close_tags'].' type="submit" value="X" class="qa-notice-close-button"/> '); if (isset($notice['form_tags'])) { $this->form_hidden_elements(@$notice['form_hidden']); $this->output('</form>'); } $this->output('</div>'); } public function header() { $this->output('<div class="qa-header">'); $this->logo(); $this->nav_user_search(); $this->nav_main_sub(); $this->header_clear(); $this->output('</div> <!-- END qa-header -->', ''); } public function nav_user_search() { $this->nav('user'); $this->search(); } public function nav_main_sub() { $this->nav('main'); $this->nav('sub'); } public function logo() { $this->output( '<div class="qa-logo">', $this->content['logo'], '</div>' ); } public function search() { $search = $this->content['search']; $this->output( '<div class="qa-search">', '<form '.$search['form_tags'].'>', @$search['form_extra'] ); $this->search_field($search); $this->search_button($search); $this->output( '</form>', '</div>' ); } public function search_field($search) { $this->output('<input type="text" '.$search['field_tags'].' value="'.@$search['value'].'" class="qa-search-field"/>'); } public function search_button($search) { $this->output('<input type="submit" value="'.$search['button_label'].'" class="qa-search-button"/>'); } public function nav($navtype, $level=null) { $navigation = @$this->content['navigation'][$navtype]; if ($navtype == 'user' || isset($navigation)) { $this->output('<div class="qa-nav-'.$navtype.'">'); if ($navtype == 'user') $this->logged_in(); // reverse order of 'opposite' items since they float right foreach (array_reverse($navigation, true) as $key => $navlink) { if (@$navlink['opposite']) { unset($navigation[$key]); $navigation[$key] = $navlink; } } $this->set_context('nav_type', $navtype); $this->nav_list($navigation, 'nav-'.$navtype, $level); $this->nav_clear($navtype); $this->clear_context('nav_type'); $this->output('</div>'); } } public function nav_list($navigation, $class, $level=null) { $this->output('<ul class="qa-'.$class.'-list'.(isset($level) ? (' qa-'.$class.'-list-'.$level) : '').'">'); $index = 0; foreach ($navigation as $key => $navlink) { $this->set_context('nav_key', $key); $this->set_context('nav_index', $index++); $this->nav_item($key, $navlink, $class, $level); } $this->clear_context('nav_key'); $this->clear_context('nav_index'); $this->output('</ul>'); } public function nav_clear($navtype) { $this->output( '<div class="qa-nav-'.$navtype.'-clear">', '</div>' ); } public function nav_item($key, $navlink, $class, $level=null) { $suffix = strtr($key, array( // map special character in navigation key '$' => '', '/' => '-', )); $this->output('<li class="qa-'.$class.'-item'.(@$navlink['opposite'] ? '-opp' : ''). (@$navlink['state'] ? (' qa-'.$class.'-'.$navlink['state']) : '').' qa-'.$class.'-'.$suffix.'">'); $this->nav_link($navlink, $class); if (count(@$navlink['subnav'])) $this->nav_list($navlink['subnav'], $class, 1+$level); $this->output('</li>'); } public function nav_link($navlink, $class) { if (isset($navlink['url'])) { $this->output( '<a href="'.$navlink['url'].'" class="qa-'.$class.'-link'. (@$navlink['selected'] ? (' qa-'.$class.'-selected') : ''). (@$navlink['favorited'] ? (' qa-'.$class.'-favorited') : ''). '"'.(strlen(@$navlink['popup']) ? (' title="'.$navlink['popup'].'"') : ''). (isset($navlink['target']) ? (' target="'.$navlink['target'].'"') : '').'>'.$navlink['label']. '</a>' ); } else { $this->output( '<span class="qa-'.$class.'-nolink'.(@$navlink['selected'] ? (' qa-'.$class.'-selected') : ''). (@$navlink['favorited'] ? (' qa-'.$class.'-favorited') : '').'"'. (strlen(@$navlink['popup']) ? (' title="'.$navlink['popup'].'"') : ''). '>'.$navlink['label'].'</span>' ); } if (strlen(@$navlink['note'])) $this->output('<span class="qa-'.$class.'-note">'.$navlink['note'].'</span>'); } public function logged_in() { $this->output_split(@$this->content['loggedin'], 'qa-logged-in', 'div'); } public function header_clear() { $this->output( '<div class="qa-header-clear">', '</div>' ); } public function sidepanel() { $this->output('<div class="qa-sidepanel">'); $this->widgets('side', 'top'); $this->sidebar(); $this->widgets('side', 'high'); $this->nav('cat', 1); $this->widgets('side', 'low'); $this->output_raw(@$this->content['sidepanel']); $this->feed(); $this->widgets('side', 'bottom'); $this->output('</div>', ''); } public function sidebar() { $sidebar = @$this->content['sidebar']; if (!empty($sidebar)) { $this->output('<div class="qa-sidebar">'); $this->output_raw($sidebar); $this->output('</div>', ''); } } public function feed() { $feed = @$this->content['feed']; if (!empty($feed)) { $this->output('<div class="qa-feed">'); $this->output('<a href="'.$feed['url'].'" class="qa-feed-link">'.@$feed['label'].'</a>'); $this->output('</div>'); } } public function main() { $content = $this->content; $this->output('<div class="qa-main'.(@$this->content['hidden'] ? ' qa-main-hidden' : '').'">'); $this->widgets('main', 'top'); $this->page_title_error(); $this->widgets('main', 'high'); $this->main_parts($content); $this->widgets('main', 'low'); $this->page_links(); $this->suggest_next(); $this->widgets('main', 'bottom'); $this->output('</div> <!-- END qa-main -->', ''); } public function page_title_error() { $favorite = @$this->content['favorite']; if (isset($favorite)) $this->output('<form '.$favorite['form_tags'].'>'); $this->output('<h1>'); $this->favorite(); $this->title(); $this->output('</h1>'); if (isset($this->content['error'])) $this->error(@$this->content['error']); if (isset($favorite)) { $this->form_hidden_elements(@$favorite['form_hidden']); $this->output('</form>'); } } public function favorite() { $favorite = @$this->content['favorite']; if (isset($favorite)) { $this->output('<span class="qa-favoriting" '.@$favorite['favorite_tags'].'>'); $this->favorite_inner_html($favorite); $this->output('</span>'); } } public function title() { $q_view = @$this->content['q_view']; // link title where appropriate $url = isset($q_view['url']) ? $q_view['url'] : false; if (isset($this->content['title'])) { $this->output( $url ? '<a href="'.$url.'">' : '', $this->content['title'], $url ? '</a>' : '' ); } // add closed note in title if (!empty($q_view['closed'])) $this->output(' ['.$q_view['closed']['state'].']'); } public function favorite_inner_html($favorite) { $this->favorite_button(@$favorite['favorite_add_tags'], 'qa-favorite'); $this->favorite_button(@$favorite['favorite_remove_tags'], 'qa-unfavorite'); } public function favorite_button($tags, $class) { if (isset($tags)) $this->output('<input '.$tags.' type="submit" value="" class="'.$class.'-button"/> '); } public function error($error) { if (strlen($error)) { $this->output( '<div class="qa-error">', $error, '</div>' ); } } public function main_parts($content) { foreach ($content as $key => $part) { $this->set_context('part', $key); $this->main_part($key, $part); } $this->clear_context('part'); } public function main_part($key, $part) { $partdiv = ( strpos($key, 'custom') === 0 || strpos($key, 'form') === 0 || strpos($key, 'q_list') === 0 || strpos($key, 'q_view') === 0 || strpos($key, 'a_form') === 0 || strpos($key, 'a_list') === 0 || strpos($key, 'ranking') === 0 || strpos($key, 'message_list') === 0 || strpos($key, 'nav_list') === 0 ); if ($partdiv) $this->output('<div class="qa-part-'.strtr($key, '_', '-').'">'); // to help target CSS to page parts if (strpos($key, 'custom') === 0) $this->output_raw($part); elseif (strpos($key, 'form') === 0) $this->form($part); elseif (strpos($key, 'q_list') === 0) $this->q_list_and_form($part); elseif (strpos($key, 'q_view') === 0) $this->q_view($part); elseif (strpos($key, 'a_form') === 0) $this->a_form($part); elseif (strpos($key, 'a_list') === 0) $this->a_list($part); elseif (strpos($key, 'ranking') === 0) $this->ranking($part); elseif (strpos($key, 'message_list') === 0) $this->message_list_and_form($part); elseif (strpos($key, 'nav_list') === 0) { $this->part_title($part); $this->nav_list($part['nav'], $part['type'], 1); } if ($partdiv) $this->output('</div>'); } public function footer() { $this->output('<div class="qa-footer">'); $this->nav('footer'); $this->attribution(); $this->footer_clear(); $this->output('</div> <!-- END qa-footer -->', ''); } public function attribution() { // Hi there. I'd really appreciate you displaying this link on your Q2A site. Thank you - Gideon $this->output( '<div class="qa-attribution">', 'Powered by <a href="http://www.question2answer.org/">Question2Answer</a>', '</div>' ); } public function footer_clear() { $this->output( '<div class="qa-footer-clear">', '</div>' ); } public function section($title) { $this->part_title(array('title' => $title)); } public function part_title($part) { if (strlen(@$part['title']) || strlen(@$part['title_tags'])) $this->output('<h2'.rtrim(' '.@$part['title_tags']).'>'.@$part['title'].'</h2>'); } public function form($form) { if (!empty($form)) { $this->part_title($form); if (isset($form['tags'])) $this->output('<form '.$form['tags'].'>'); $this->form_body($form); if (isset($form['tags'])) $this->output('</form>'); } } public function form_columns($form) { if (isset($form['ok']) || !empty($form['fields']) ) $columns = ($form['style'] == 'wide') ? 3 : 1; else $columns = 0; return $columns; } public function form_spacer($form, $columns) { $this->output( '<tr>', '<td colspan="'.$columns.'" class="qa-form-'.$form['style'].'-spacer">', ' ', '</td>', '</tr>' ); } public function form_body($form) { if (@$form['boxed']) $this->output('<div class="qa-form-table-boxed">'); $columns = $this->form_columns($form); if ($columns) $this->output('<table class="qa-form-'.$form['style'].'-table">'); $this->form_ok($form, $columns); $this->form_fields($form, $columns); $this->form_buttons($form, $columns); if ($columns) $this->output('</table>'); $this->form_hidden($form); if (@$form['boxed']) $this->output('</div>'); } public function form_ok($form, $columns) { if (!empty($form['ok'])) { $this->output( '<tr>', '<td colspan="'.$columns.'" class="qa-form-'.$form['style'].'-ok">', $form['ok'], '</td>', '</tr>' ); } } public function form_reorder_fields(&$form, $keys, $beforekey=null, $reorderrelative=true) /* Reorder the fields of $form according to the $keys array which contains the field keys in their new order. Call before any fields are output. See the docs for qa_array_reorder() in qa-util-sort.php for the other parameters. */ { require_once QA_INCLUDE_DIR.'qa-util-sort.php'; if (is_array($form['fields'])) qa_array_reorder($form['fields'], $keys, $beforekey, $reorderrelative); } public function form_fields($form, $columns) { if (!empty($form['fields'])) { foreach ($form['fields'] as $key => $field) { $this->set_context('field_key', $key); if (@$field['type'] == 'blank') $this->form_spacer($form, $columns); else $this->form_field_rows($form, $columns, $field); } $this->clear_context('field_key'); } } public function form_field_rows($form, $columns, $field) { $style = $form['style']; if (isset($field['style'])) { // field has different style to most of form $style = $field['style']; $colspan = $columns; $columns = ($style == 'wide') ? 3 : 1; } else $colspan = null; $prefixed = (@$field['type'] == 'checkbox') && ($columns == 1) && !empty($field['label']); $suffixed = (@$field['type'] == 'select' || @$field['type'] == 'number') && $columns == 1 && !empty($field['label']) && !@$field['loose']; $skipdata = @$field['tight']; $tworows = ($columns == 1) && (!empty($field['label'])) && (!$skipdata) && ( (!($prefixed||$suffixed)) || (!empty($field['error'])) || (!empty($field['note'])) ); if (isset($field['id'])) { if ($columns == 1) $this->output('<tbody id="'.$field['id'].'">', '<tr>'); else $this->output('<tr id="'.$field['id'].'">'); } else $this->output('<tr>'); if ($columns > 1 || !empty($field['label'])) $this->form_label($field, $style, $columns, $prefixed, $suffixed, $colspan); if ($tworows) { $this->output( '</tr>', '<tr>' ); } if (!$skipdata) $this->form_data($field, $style, $columns, !($prefixed||$suffixed), $colspan); $this->output('</tr>'); if ($columns == 1 && isset($field['id'])) $this->output('</tbody>'); } public function form_label($field, $style, $columns, $prefixed, $suffixed, $colspan) { $extratags = ''; if ($columns > 1 && (@$field['type'] == 'select-radio' || @$field['rows'] > 1)) $extratags .= ' style="vertical-align:top;"'; if (isset($colspan)) $extratags .= ' colspan="'.$colspan.'"'; $this->output('<td class="qa-form-'.$style.'-label"'.$extratags.'>'); if ($prefixed) { $this->output('<label>'); $this->form_field($field, $style); } $this->output(@$field['label']); if ($prefixed) $this->output('</label>'); if ($suffixed) { $this->output(' '); $this->form_field($field, $style); } $this->output('</td>'); } public function form_data($field, $style, $columns, $showfield, $colspan) { if ($showfield || (!empty($field['error'])) || (!empty($field['note']))) { $this->output( '<td class="qa-form-'.$style.'-data"'.(isset($colspan) ? (' colspan="'.$colspan.'"') : '').'>' ); if ($showfield) $this->form_field($field, $style); if (!empty($field['error'])) { if (@$field['note_force']) $this->form_note($field, $style, $columns); $this->form_error($field, $style, $columns); } elseif (!empty($field['note'])) $this->form_note($field, $style, $columns); $this->output('</td>'); } } public function form_field($field, $style) { $this->form_prefix($field, $style); $this->output_raw(@$field['html_prefix']); switch (@$field['type']) { case 'checkbox': $this->form_checkbox($field, $style); break; case 'static': $this->form_static($field, $style); break; case 'password': $this->form_password($field, $style); break; case 'number': $this->form_number($field, $style); break; case 'select': $this->form_select($field, $style); break; case 'select-radio': $this->form_select_radio($field, $style); break; case 'image': $this->form_image($field, $style); break; case 'custom': $this->output_raw(@$field['html']); break; default: if (@$field['type'] == 'textarea' || @$field['rows'] > 1) $this->form_text_multi_row($field, $style); else $this->form_text_single_row($field, $style); break; } $this->output_raw(@$field['html_suffix']); $this->form_suffix($field, $style); } public function form_reorder_buttons(&$form, $keys, $beforekey=null, $reorderrelative=true) /* Reorder the buttons of $form according to the $keys array which contains the button keys in their new order. Call before any buttons are output. See the docs for qa_array_reorder() in qa-util-sort.php for the other parameters. */ { require_once QA_INCLUDE_DIR.'qa-util-sort.php'; if (is_array($form['buttons'])) qa_array_reorder($form['buttons'], $keys, $beforekey, $reorderrelative); } public function form_buttons($form, $columns) { if (!empty($form['buttons'])) { $style = @$form['style']; if ($columns) { $this->output( '<tr>', '<td colspan="'.$columns.'" class="qa-form-'.$style.'-buttons">' ); } foreach ($form['buttons'] as $key => $button) { $this->set_context('button_key', $key); if (empty($button)) $this->form_button_spacer($style); else { $this->form_button_data($button, $key, $style); $this->form_button_note($button, $style); } } $this->clear_context('button_key'); if ($columns) { $this->output( '</td>', '</tr>' ); } } } public function form_button_data($button, $key, $style) { $baseclass = 'qa-form-'.$style.'-button qa-form-'.$style.'-button-'.$key; $this->output('<input'.rtrim(' '.@$button['tags']).' value="'.@$button['label'].'" title="'.@$button['popup'].'" type="submit"'. (isset($style) ? (' class="'.$baseclass.'"') : '').'/>'); } public function form_button_note($button, $style) { if (!empty($button['note'])) { $this->output( '<span class="qa-form-'.$style.'-note">', $button['note'], '</span>', '<br/>' ); } } public function form_button_spacer($style) { $this->output('<span class="qa-form-'.$style.'-buttons-spacer"> </span>'); } public function form_hidden($form) { $this->form_hidden_elements(@$form['hidden']); } public function form_hidden_elements($hidden) { if (!empty($hidden)) { foreach ($hidden as $name => $value) $this->output('<input type="hidden" name="'.$name.'" value="'.$value.'"/>'); } } public function form_prefix($field, $style) { if (!empty($field['prefix'])) $this->output('<span class="qa-form-'.$style.'-prefix">'.$field['prefix'].'</span>'); } public function form_suffix($field, $style) { if (!empty($field['suffix'])) $this->output('<span class="qa-form-'.$style.'-suffix">'.$field['suffix'].'</span>'); } public function form_checkbox($field, $style) { $this->output('<input '.@$field['tags'].' type="checkbox" value="1"'.(@$field['value'] ? ' checked' : '').' class="qa-form-'.$style.'-checkbox"/>'); } public function form_static($field, $style) { $this->output('<span class="qa-form-'.$style.'-static">'.@$field['value'].'</span>'); } public function form_password($field, $style) { $this->output('<input '.@$field['tags'].' type="password" value="'.@$field['value'].'" class="qa-form-'.$style.'-text"/>'); } public function form_number($field, $style) { $this->output('<input '.@$field['tags'].' type="text" value="'.@$field['value'].'" class="qa-form-'.$style.'-number"/>'); } public function form_select($field, $style) { $this->output('<select '.@$field['tags'].' class="qa-form-'.$style.'-select">'); foreach ($field['options'] as $tag => $value) $this->output('<option value="'.$tag.'"'.(($value == @$field['value']) ? ' selected' : '').'>'.$value.'</option>'); $this->output('</select>'); } public function form_select_radio($field, $style) { $radios = 0; foreach ($field['options'] as $tag => $value) { if ($radios++) $this->output('<br/>'); $this->output('<input '.@$field['tags'].' type="radio" value="'.$tag.'"'.(($value == @$field['value']) ? ' checked' : '').' class="qa-form-'.$style.'-radio"/> '.$value); } } public function form_image($field, $style) { $this->output('<div class="qa-form-'.$style.'-image">'.@$field['html'].'</div>'); } public function form_text_single_row($field, $style) { $this->output('<input '.@$field['tags'].' type="text" value="'.@$field['value'].'" class="qa-form-'.$style.'-text"/>'); } public function form_text_multi_row($field, $style) { $this->output('<textarea '.@$field['tags'].' rows="'.(int)$field['rows'].'" cols="40" class="qa-form-'.$style.'-text">'.@$field['value'].'</textarea>'); } public function form_error($field, $style, $columns) { $tag = ($columns > 1) ? 'span' : 'div'; $this->output('<'.$tag.' class="qa-form-'.$style.'-error">'.$field['error'].'</'.$tag.'>'); } public function form_note($field, $style, $columns) { $tag = ($columns > 1) ? 'span' : 'div'; $this->output('<'.$tag.' class="qa-form-'.$style.'-note">'.@$field['note'].'</'.$tag.'>'); } public function ranking($ranking) { $this->part_title($ranking); if (!isset($ranking['type'])) $ranking['type'] = 'items'; $class = 'qa-top-'.$ranking['type']; if (!$this->ranking_block_layout) { // old, less semantic table layout $this->ranking_table($ranking, $class); return; } // new block layout foreach ($ranking['items'] as $item) { $this->output('<span class="qa-ranking-item '.$class.'-item">'); $this->ranking_item($item, $class); $this->output('</span>'); } } public function ranking_item($item, $class, $spacer=false) // $spacer is deprecated { if (!$this->ranking_block_layout) { // old table layout $this->ranking_table_item($item, $class, $spacer); return; } if (isset($item['count'])) $this->ranking_count($item, $class); if (isset($item['avatar'])) $this->avatar($item, $class); $this->ranking_label($item, $class); if (isset($item['score'])) $this->ranking_score($item, $class); } public function ranking_cell($content, $class) { $tag = $this->ranking_block_layout ? 'span': 'td'; $this->output('<'.$tag.' class="'.$class.'">' . $content . '</'.$tag.'>'); } public function ranking_count($item, $class) { $this->ranking_cell($item['count'].' ×', $class.'-count'); } public function ranking_label($item, $class) { $this->ranking_cell($item['label'], $class.'-label'); } public function ranking_score($item, $class) { $this->ranking_cell($item['score'], $class.'-score'); } /** * @deprecated Table-based layout of users/tags is deprecated from 1.7 onwards and may be * removed in a future version. Themes can switch to the new layout by setting the member * variable $ranking_block_layout to false. */ public function ranking_table($ranking, $class) { $rows = min($ranking['rows'], count($ranking['items'])); if ($rows > 0) { $this->output('<table class="'.$class.'-table">'); $columns = ceil(count($ranking['items']) / $rows); for ($row = 0; $row < $rows; $row++) { $this->set_context('ranking_row', $row); $this->output('<tr>'); for ($column = 0; $column < $columns; $column++) { $this->set_context('ranking_column', $column); $this->ranking_table_item(@$ranking['items'][$column*$rows+$row], $class, $column>0); } $this->clear_context('ranking_column'); $this->output('</tr>'); } $this->clear_context('ranking_row'); $this->output('</table>'); } } /** * @deprecated See ranking_table above. */ public function ranking_table_item($item, $class, $spacer) { if ($spacer) $this->ranking_spacer($class); if (empty($item)) { $this->ranking_spacer($class); $this->ranking_spacer($class); } else { if (isset($item['count'])) $this->ranking_count($item, $class); if (isset($item['avatar'])) $item['label'] = $item['avatar'].' '.$item['label']; $this->ranking_label($item, $class); if (isset($item['score'])) $this->ranking_score($item, $class); } } /** * @deprecated See ranking_table above. */ public function ranking_spacer($class) { $this->output('<td class="'.$class.'-spacer"> </td>'); } public function message_list_and_form($list) { if (!empty($list)) { $this->part_title($list); $this->error(@$list['error']); if (!empty($list['form'])) { $this->output('<form '.$list['form']['tags'].'>'); unset($list['form']['tags']); // we already output the tags before the messages $this->message_list_form($list); } $this->message_list($list); if (!empty($list['form'])) { $this->output('</form>'); } } } public function message_list_form($list) { if (!empty($list['form'])) { $this->output('<div class="qa-message-list-form">'); $this->form($list['form']); $this->output('</div>'); } } public function message_list($list) { if (isset($list['messages'])) { $this->output('<div class="qa-message-list" '.@$list['tags'].'>'); foreach ($list['messages'] as $message) $this->message_item($message); $this->output('</div> <!-- END qa-message-list -->', ''); } } public function message_item($message) { $this->output('<div class="qa-message-item" '.@$message['tags'].'>'); $this->message_content($message); $this->post_avatar_meta($message, 'qa-message'); $this->message_buttons($message); $this->output('</div> <!-- END qa-message-item -->', ''); } public function message_content($message) { if (!empty($message['content'])) { $this->output('<div class="qa-message-content">'); $this->output_raw($message['content']); $this->output('</div>'); } } public function message_buttons($item) { if (!empty($item['form'])) { $this->output('<div class="qa-message-buttons">'); $this->form($item['form']); $this->output('</div>'); } } public function list_vote_disabled($items) { $disabled = false; if (count($items)) { $disabled = true; foreach ($items as $item) { if (@$item['vote_on_page'] != 'disabled') $disabled = false; } } return $disabled; } public function q_list_and_form($q_list) { if (!empty($q_list)) { $this->part_title($q_list); if (!empty($q_list['form'])) $this->output('<form '.$q_list['form']['tags'].'>'); $this->q_list($q_list); if (!empty($q_list['form'])) { unset($q_list['form']['tags']); // we already output the tags before the qs $this->q_list_form($q_list); $this->output('</form>'); } } } public function q_list_form($q_list) { if (!empty($q_list['form'])) { $this->output('<div class="qa-q-list-form">'); $this->form($q_list['form']); $this->output('</div>'); } } public function q_list($q_list) { if (isset($q_list['qs'])) { $this->output('<div class="qa-q-list'.($this->list_vote_disabled($q_list['qs']) ? ' qa-q-list-vote-disabled' : '').'">', ''); $this->q_list_items($q_list['qs']); $this->output('</div> <!-- END qa-q-list -->', ''); } } public function q_list_items($q_items) { foreach ($q_items as $q_item) $this->q_list_item($q_item); } public function q_list_item($q_item) { $this->output('<div class="qa-q-list-item'.rtrim(' '.@$q_item['classes']).'" '.@$q_item['tags'].'>'); $this->q_item_stats($q_item); $this->q_item_main($q_item); $this->q_item_clear(); $this->output('</div> <!-- END qa-q-list-item -->', ''); } public function q_item_stats($q_item) { $this->output('<div class="qa-q-item-stats">'); $this->voting($q_item); $this->a_count($q_item); $this->output('</div>'); } public function q_item_main($q_item) { $this->output('<div class="qa-q-item-main">'); $this->view_count($q_item); $this->q_item_title($q_item); $this->q_item_content($q_item); $this->post_avatar_meta($q_item, 'qa-q-item'); $this->post_tags($q_item, 'qa-q-item'); $this->q_item_buttons($q_item); $this->output('</div>'); } public function q_item_clear() { $this->output( '<div class="qa-q-item-clear">', '</div>' ); } public function q_item_title($q_item) { $this->output( '<div class="qa-q-item-title">', '<a href="'.$q_item['url'].'">'.$q_item['title'].'</a>', // add closed note in title empty($q_item['closed']) ? '' : ' ['.$q_item['closed']['state'].']', '</div>' ); } public function q_item_content($q_item) { if (!empty($q_item['content'])) { $this->output('<div class="qa-q-item-content">'); $this->output_raw($q_item['content']); $this->output('</div>'); } } public function q_item_buttons($q_item) { if (!empty($q_item['form'])) { $this->output('<div class="qa-q-item-buttons">'); $this->form($q_item['form']); $this->output('</div>'); } } public function voting($post) { if (isset($post['vote_view'])) { $this->output('<div class="qa-voting '.(($post['vote_view'] == 'updown') ? 'qa-voting-updown' : 'qa-voting-net').'" '.@$post['vote_tags'].'>'); $this->voting_inner_html($post); $this->output('</div>'); } } public function voting_inner_html($post) { $this->vote_buttons($post); $this->vote_count($post); $this->vote_clear(); } public function vote_buttons($post) { $this->output('<div class="qa-vote-buttons '.(($post['vote_view'] == 'updown') ? 'qa-vote-buttons-updown' : 'qa-vote-buttons-net').'">'); switch (@$post['vote_state']) { case 'voted_up': $this->post_hover_button($post, 'vote_up_tags', '+', 'qa-vote-one-button qa-voted-up'); break; case 'voted_up_disabled': $this->post_disabled_button($post, 'vote_up_tags', '+', 'qa-vote-one-button qa-vote-up'); break; case 'voted_down': $this->post_hover_button($post, 'vote_down_tags', '–', 'qa-vote-one-button qa-voted-down'); break; case 'voted_down_disabled': $this->post_disabled_button($post, 'vote_down_tags', '–', 'qa-vote-one-button qa-vote-down'); break; case 'up_only': $this->post_hover_button($post, 'vote_up_tags', '+', 'qa-vote-first-button qa-vote-up'); $this->post_disabled_button($post, 'vote_down_tags', '', 'qa-vote-second-button qa-vote-down'); break; case 'enabled': $this->post_hover_button($post, 'vote_up_tags', '+', 'qa-vote-first-button qa-vote-up'); $this->post_hover_button($post, 'vote_down_tags', '–', 'qa-vote-second-button qa-vote-down'); break; default: $this->post_disabled_button($post, 'vote_up_tags', '', 'qa-vote-first-button qa-vote-up'); $this->post_disabled_button($post, 'vote_down_tags', '', 'qa-vote-second-button qa-vote-down'); break; } $this->output('</div>'); } public function vote_count($post) { // You can also use $post['upvotes_raw'], $post['downvotes_raw'], $post['netvotes_raw'] to get // raw integer vote counts, for graphing or showing in other non-textual ways $this->output('<div class="qa-vote-count '.(($post['vote_view'] == 'updown') ? 'qa-vote-count-updown' : 'qa-vote-count-net').'"'.@$post['vote_count_tags'].'>'); if ($post['vote_view'] == 'updown') { $this->output_split($post['upvotes_view'], 'qa-upvote-count'); $this->output_split($post['downvotes_view'], 'qa-downvote-count'); } else $this->output_split($post['netvotes_view'], 'qa-netvote-count'); $this->output('</div>'); } public function vote_clear() { $this->output( '<div class="qa-vote-clear">', '</div>' ); } public function a_count($post) { // You can also use $post['answers_raw'] to get a raw integer count of answers $this->output_split(@$post['answers'], 'qa-a-count', 'span', 'span', @$post['answer_selected'] ? 'qa-a-count-selected' : (@$post['answers_raw'] ? null : 'qa-a-count-zero')); } public function view_count($post) { // You can also use $post['views_raw'] to get a raw integer count of views $this->output_split(@$post['views'], 'qa-view-count'); } public function avatar($item, $class, $prefix=null) { if (isset($item['avatar'])) { if (isset($prefix)) $this->output($prefix); $this->output( '<span class="'.$class.'-avatar">', $item['avatar'], '</span>' ); } } public function a_selection($post) { $this->output('<div class="qa-a-selection">'); if (isset($post['select_tags'])) $this->post_hover_button($post, 'select_tags', '', 'qa-a-select'); elseif (isset($post['unselect_tags'])) $this->post_hover_button($post, 'unselect_tags', '', 'qa-a-unselect'); elseif ($post['selected']) $this->output('<div class="qa-a-selected"> </div>'); if (isset($post['select_text'])) $this->output('<div class="qa-a-selected-text">'.@$post['select_text'].'</div>'); $this->output('</div>'); } public function post_hover_button($post, $element, $value, $class) { if (isset($post[$element])) $this->output('<input '.$post[$element].' type="submit" value="'.$value.'" class="'.$class.'-button"/> '); } public function post_disabled_button($post, $element, $value, $class) { if (isset($post[$element])) $this->output('<input '.$post[$element].' type="submit" value="'.$value.'" class="'.$class.'-disabled" disabled="disabled"/> '); } public function post_avatar_meta($post, $class, $avatarprefix=null, $metaprefix=null, $metaseparator='<br/>') { $this->output('<span class="'.$class.'-avatar-meta">'); $this->avatar($post, $class, $avatarprefix); $this->post_meta($post, $class, $metaprefix, $metaseparator); $this->output('</span>'); } /** * @deprecated Deprecated from 1.7; please use avatar() instead. */ public function post_avatar($post, $class, $prefix=null) { $this->avatar($post, $class, $prefix=null); } public function post_meta($post, $class, $prefix=null, $separator='<br/>') { $this->output('<span class="'.$class.'-meta">'); if (isset($prefix)) $this->output($prefix); $order = explode('^', @$post['meta_order']); foreach ($order as $element) { switch ($element) { case 'what': $this->post_meta_what($post, $class); break; case 'when': $this->post_meta_when($post, $class); break; case 'where': $this->post_meta_where($post, $class); break; case 'who': $this->post_meta_who($post, $class); break; } } $this->post_meta_flags($post, $class); if (!empty($post['what_2'])) { $this->output($separator); foreach ($order as $element) { switch ($element) { case 'what': $this->output('<span class="'.$class.'-what">'.$post['what_2'].'</span>'); break; case 'when': $this->output_split(@$post['when_2'], $class.'-when'); break; case 'who': $this->output_split(@$post['who_2'], $class.'-who'); break; } } } $this->output('</span>'); } public function post_meta_what($post, $class) { if (isset($post['what'])) { $classes = $class.'-what'; if (@$post['what_your']) $classes .= ' '.$class.'-what-your'; if (isset($post['what_url'])) $this->output('<a href="'.$post['what_url'].'" class="'.$classes.'">'.$post['what'].'</a>'); else $this->output('<span class="'.$classes.'">'.$post['what'].'</span>'); } } public function post_meta_when($post, $class) { $this->output_split(@$post['when'], $class.'-when'); } public function post_meta_where($post, $class) { $this->output_split(@$post['where'], $class.'-where'); } public function post_meta_who($post, $class) { if (isset($post['who'])) { $this->output('<span class="'.$class.'-who">'); if (strlen(@$post['who']['prefix'])) $this->output('<span class="'.$class.'-who-pad">'.$post['who']['prefix'].'</span>'); if (isset($post['who']['data'])) $this->output('<span class="'.$class.'-who-data">'.$post['who']['data'].'</span>'); if (isset($post['who']['title'])) $this->output('<span class="'.$class.'-who-title">'.$post['who']['title'].'</span>'); // You can also use $post['level'] to get the author's privilege level (as a string) if (isset($post['who']['points'])) { $post['who']['points']['prefix'] = '('.$post['who']['points']['prefix']; $post['who']['points']['suffix'] .= ')'; $this->output_split($post['who']['points'], $class.'-who-points'); } if (strlen(@$post['who']['suffix'])) $this->output('<span class="'.$class.'-who-pad">'.$post['who']['suffix'].'</span>'); $this->output('</span>'); } } public function post_meta_flags($post, $class) { $this->output_split(@$post['flags'], $class.'-flags'); } public function post_tags($post, $class) { if (!empty($post['q_tags'])) { $this->output('<div class="'.$class.'-tags">'); $this->post_tag_list($post, $class); $this->output('</div>'); } } public function post_tag_list($post, $class) { $this->output('<ul class="'.$class.'-tag-list">'); foreach ($post['q_tags'] as $taghtml) $this->post_tag_item($taghtml, $class); $this->output('</ul>'); } public function post_tag_item($taghtml, $class) { $this->output('<li class="'.$class.'-tag-item">'.$taghtml.'</li>'); } public function page_links() { $page_links = @$this->content['page_links']; if (!empty($page_links)) { $this->output('<div class="qa-page-links">'); $this->page_links_label(@$page_links['label']); $this->page_links_list(@$page_links['items']); $this->page_links_clear(); $this->output('</div>'); } } public function page_links_label($label) { if (!empty($label)) $this->output('<span class="qa-page-links-label">'.$label.'</span>'); } public function page_links_list($page_items) { if (!empty($page_items)) { $this->output('<ul class="qa-page-links-list">'); $index = 0; foreach ($page_items as $page_link) { $this->set_context('page_index', $index++); $this->page_links_item($page_link); if ($page_link['ellipsis']) $this->page_links_item(array('type' => 'ellipsis')); } $this->clear_context('page_index'); $this->output('</ul>'); } } public function page_links_item($page_link) { $this->output('<li class="qa-page-links-item">'); $this->page_link_content($page_link); $this->output('</li>'); } public function page_link_content($page_link) { $label = @$page_link['label']; $url = @$page_link['url']; switch ($page_link['type']) { case 'this': $this->output('<span class="qa-page-selected">'.$label.'</span>'); break; case 'prev': $this->output('<a href="'.$url.'" class="qa-page-prev">« '.$label.'</a>'); break; case 'next': $this->output('<a href="'.$url.'" class="qa-page-next">'.$label.' »</a>'); break; case 'ellipsis': $this->output('<span class="qa-page-ellipsis">...</span>'); break; default: $this->output('<a href="'.$url.'" class="qa-page-link">'.$label.'</a>'); break; } } public function page_links_clear() { $this->output( '<div class="qa-page-links-clear">', '</div>' ); } public function suggest_next() { $suggest = @$this->content['suggest_next']; if (!empty($suggest)) { $this->output('<div class="qa-suggest-next">'); $this->output($suggest); $this->output('</div>'); } } public function q_view($q_view) { if (!empty($q_view)) { $this->output('<div class="qa-q-view'.(@$q_view['hidden'] ? ' qa-q-view-hidden' : '').rtrim(' '.@$q_view['classes']).'"'.rtrim(' '.@$q_view['tags']).'>'); if (isset($q_view['main_form_tags'])) $this->output('<form '.$q_view['main_form_tags'].'>'); // form for voting buttons $this->q_view_stats($q_view); if (isset($q_view['main_form_tags'])) { $this->form_hidden_elements(@$q_view['voting_form_hidden']); $this->output('</form>'); } $this->q_view_main($q_view); $this->q_view_clear(); $this->output('</div> <!-- END qa-q-view -->', ''); } } public function q_view_stats($q_view) { $this->output('<div class="qa-q-view-stats">'); $this->voting($q_view); $this->a_count($q_view); $this->output('</div>'); } public function q_view_main($q_view) { $this->output('<div class="qa-q-view-main">'); if (isset($q_view['main_form_tags'])) $this->output('<form '.$q_view['main_form_tags'].'>'); // form for buttons on question $this->view_count($q_view); $this->q_view_content($q_view); $this->q_view_extra($q_view); $this->q_view_follows($q_view); $this->q_view_closed($q_view); $this->post_tags($q_view, 'qa-q-view'); $this->post_avatar_meta($q_view, 'qa-q-view'); $this->q_view_buttons($q_view); $this->c_list(@$q_view['c_list'], 'qa-q-view'); if (isset($q_view['main_form_tags'])) { $this->form_hidden_elements(@$q_view['buttons_form_hidden']); $this->output('</form>'); } $this->c_form(@$q_view['c_form']); $this->output('</div> <!-- END qa-q-view-main -->'); } public function q_view_content($q_view) { if (!empty($q_view['content'])) { $this->output('<div class="qa-q-view-content">'); $this->output_raw($q_view['content']); $this->output('</div>'); } } public function q_view_follows($q_view) { if (!empty($q_view['follows'])) $this->output( '<div class="qa-q-view-follows">', $q_view['follows']['label'], '<a href="'.$q_view['follows']['url'].'" class="qa-q-view-follows-link">'.$q_view['follows']['title'].'</a>', '</div>' ); } public function q_view_closed($q_view) { if (!empty($q_view['closed'])) { $haslink = isset($q_view['closed']['url']); $this->output( '<div class="qa-q-view-closed">', $q_view['closed']['label'], ($haslink ? ('<a href="'.$q_view['closed']['url'].'"') : '<span').' class="qa-q-view-closed-content">', $q_view['closed']['content'], $haslink ? '</a>' : '</span>', '</div>' ); } } public function q_view_extra($q_view) { if (!empty($q_view['extra'])) { $this->output( '<div class="qa-q-view-extra">', $q_view['extra']['label'], '<span class="qa-q-view-extra-content">', $q_view['extra']['content'], '</span>', '</div>' ); } } public function q_view_buttons($q_view) { if (!empty($q_view['form'])) { $this->output('<div class="qa-q-view-buttons">'); $this->form($q_view['form']); $this->output('</div>'); } } public function q_view_clear() { $this->output( '<div class="qa-q-view-clear">', '</div>' ); } public function a_form($a_form) { $this->output('<div class="qa-a-form"'.(isset($a_form['id']) ? (' id="'.$a_form['id'].'"') : ''). (@$a_form['collapse'] ? ' style="display:none;"' : '').'>'); $this->form($a_form); $this->c_list(@$a_form['c_list'], 'qa-a-item'); $this->output('</div> <!-- END qa-a-form -->', ''); } public function a_list($a_list) { if (!empty($a_list)) { $this->part_title($a_list); $this->output('<div class="qa-a-list'.($this->list_vote_disabled($a_list['as']) ? ' qa-a-list-vote-disabled' : '').'" '.@$a_list['tags'].'>', ''); $this->a_list_items($a_list['as']); $this->output('</div> <!-- END qa-a-list -->', ''); } } public function a_list_items($a_items) { foreach ($a_items as $a_item) $this->a_list_item($a_item); } public function a_list_item($a_item) { $extraclass = @$a_item['classes'].($a_item['hidden'] ? ' qa-a-list-item-hidden' : ($a_item['selected'] ? ' qa-a-list-item-selected' : '')); $this->output('<div class="qa-a-list-item '.$extraclass.'" '.@$a_item['tags'].'>'); if (isset($a_item['main_form_tags'])) $this->output('<form '.$a_item['main_form_tags'].'>'); // form for voting buttons $this->voting($a_item); if (isset($a_item['main_form_tags'])) { $this->form_hidden_elements(@$a_item['voting_form_hidden']); $this->output('</form>'); } $this->a_item_main($a_item); $this->a_item_clear(); $this->output('</div> <!-- END qa-a-list-item -->', ''); } public function a_item_main($a_item) { $this->output('<div class="qa-a-item-main">'); if (isset($a_item['main_form_tags'])) $this->output('<form '.$a_item['main_form_tags'].'>'); // form for buttons on answer if ($a_item['hidden']) $this->output('<div class="qa-a-item-hidden">'); elseif ($a_item['selected']) $this->output('<div class="qa-a-item-selected">'); $this->a_selection($a_item); $this->error(@$a_item['error']); $this->a_item_content($a_item); $this->post_avatar_meta($a_item, 'qa-a-item'); if ($a_item['hidden'] || $a_item['selected']) $this->output('</div>'); $this->a_item_buttons($a_item); $this->c_list(@$a_item['c_list'], 'qa-a-item'); if (isset($a_item['main_form_tags'])) { $this->form_hidden_elements(@$a_item['buttons_form_hidden']); $this->output('</form>'); } $this->c_form(@$a_item['c_form']); $this->output('</div> <!-- END qa-a-item-main -->'); } public function a_item_clear() { $this->output( '<div class="qa-a-item-clear">', '</div>' ); } public function a_item_content($a_item) { $this->output('<div class="qa-a-item-content">'); $this->output_raw($a_item['content']); $this->output('</div>'); } public function a_item_buttons($a_item) { if (!empty($a_item['form'])) { $this->output('<div class="qa-a-item-buttons">'); $this->form($a_item['form']); $this->output('</div>'); } } public function c_form($c_form) { $this->output('<div class="qa-c-form"'.(isset($c_form['id']) ? (' id="'.$c_form['id'].'"') : ''). (@$c_form['collapse'] ? ' style="display:none;"' : '').'>'); $this->form($c_form); $this->output('</div> <!-- END qa-c-form -->', ''); } public function c_list($c_list, $class) { if (!empty($c_list)) { $this->output('', '<div class="'.$class.'-c-list"'.(@$c_list['hidden'] ? ' style="display:none;"' : '').' '.@$c_list['tags'].'>'); $this->c_list_items($c_list['cs']); $this->output('</div> <!-- END qa-c-list -->', ''); } } public function c_list_items($c_items) { foreach ($c_items as $c_item) $this->c_list_item($c_item); } public function c_list_item($c_item) { $extraclass = @$c_item['classes'].(@$c_item['hidden'] ? ' qa-c-item-hidden' : ''); $this->output('<div class="qa-c-list-item '.$extraclass.'" '.@$c_item['tags'].'>'); $this->c_item_main($c_item); $this->c_item_clear(); $this->output('</div> <!-- END qa-c-item -->'); } public function c_item_main($c_item) { $this->error(@$c_item['error']); if (isset($c_item['expand_tags'])) $this->c_item_expand($c_item); elseif (isset($c_item['url'])) $this->c_item_link($c_item); else $this->c_item_content($c_item); $this->output('<div class="qa-c-item-footer">'); $this->post_avatar_meta($c_item, 'qa-c-item'); $this->c_item_buttons($c_item); $this->output('</div>'); } public function c_item_link($c_item) { $this->output( '<a href="'.$c_item['url'].'" class="qa-c-item-link">'.$c_item['title'].'</a>' ); } public function c_item_expand($c_item) { $this->output( '<a href="'.$c_item['url'].'" '.$c_item['expand_tags'].' class="qa-c-item-expand">'.$c_item['title'].'</a>' ); } public function c_item_content($c_item) { $this->output('<div class="qa-c-item-content">'); $this->output_raw($c_item['content']); $this->output('</div>'); } public function c_item_buttons($c_item) { if (!empty($c_item['form'])) { $this->output('<div class="qa-c-item-buttons">'); $this->form($c_item['form']); $this->output('</div>'); } } public function c_item_clear() { $this->output( '<div class="qa-c-item-clear">', '</div>' ); } public function q_title_list($q_list, $attrs=null) /* Generic method to output a basic list of question links. */ { $this->output('<ul class="qa-q-title-list">'); foreach ($q_list as $q) { $this->output( '<li class="qa-q-title-item">', '<a href="' . qa_q_path_html($q['postid'], $q['title']) . '" ' . $attrs . '>' . qa_html($q['title']) . '</a>', '</li>' ); } $this->output('</ul>'); } public function q_ask_similar($q_list, $pretext='') /* Output block of similar questions when asking. */ { if (!count($q_list)) return; $this->output('<div class="qa-ask-similar">'); if (strlen($pretext) > 0) $this->output('<p>'.$pretext.'</p>'); $this->q_title_list($q_list, 'target="_blank"'); $this->output('</div>'); } } /* Omit PHP closing tag to help avoid accidental output */