includes/namespaces/default.php
changeset 800 9cdfe82c56cd
child 801 eb8b23f11744
equal deleted inserted replaced
799:4629ad98ee88 800:9cdfe82c56cd
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
       
     5  * Version 1.1.5 (Caoineag alpha 5)
       
     6  * Copyright (C) 2006-2008 Dan Fuhry
       
     7  *
       
     8  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
     9  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    12  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    13  */
       
    14 
       
    15 /**
       
    16  * The default handler for namespaces. Basically fetches the page text from the database. Other namespaces should extend this class.
       
    17  * @package Enano
       
    18  * @subpackage PageHandler
       
    19  * @author Dan Fuhry <dan@enanocms.org>
       
    20  * @license GNU General Public License <http://www.gnu.org/licenses/gpl-2.0.html>
       
    21  */
       
    22 
       
    23 class Namespace_Default
       
    24 {
       
    25   /**
       
    26    * Page ID
       
    27    * @var string
       
    28    */
       
    29   
       
    30   public $page_id;
       
    31   
       
    32   /**
       
    33    * Namespace
       
    34    * @var string
       
    35    */
       
    36   
       
    37   public $namespace;
       
    38   
       
    39   /**
       
    40    * Local copy of the page text
       
    41    */
       
    42   
       
    43   public $text_cache;
       
    44   
       
    45   /**
       
    46    * Revision ID to send. If 0, the latest revision.
       
    47    * @var int
       
    48    */
       
    49   
       
    50   public $revision_id = 0;
       
    51   
       
    52   /**
       
    53    * Tracks whether the page exists
       
    54    * @var bool
       
    55    */
       
    56   
       
    57   public $exists = false;
       
    58   
       
    59   /**
       
    60    * Page title
       
    61    * @var string
       
    62    */
       
    63   
       
    64   public $title = '';
       
    65   
       
    66   /**
       
    67    * Constructor.
       
    68    */
       
    69   
       
    70   public function __construct($page_id, $namespace, $revision_id = 0)
       
    71   {
       
    72     global $db, $session, $paths, $template, $plugins; // Common objects
       
    73     
       
    74     $this->page_id = sanitize_page_id($page_id);
       
    75     $this->namespace = $namespace;
       
    76     $this->revision_id = intval($revision_id);
       
    77     
       
    78     // only do this if calling from the (very heavily feature filled) abstract
       
    79     // this will still be called if you're using your own handler but not replacing the constructor
       
    80     if ( __CLASS__ == 'Namespace_Default' )
       
    81     {
       
    82       $this->exists = false;
       
    83       // NOTE! These should already be WELL sanitized before we reach this stage.
       
    84       $q = $db->sql_query('SELECT name FROM ' . table_prefix . "pages WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';");
       
    85       if ( !$q )
       
    86         $db->_die();
       
    87       
       
    88       if ( $db->numrows() < 1 )
       
    89       {
       
    90         // we still have a chance... some older databases don't do dots in the page title right
       
    91         if ( strstr(dirtify_page_id($this->page_id), '.') )
       
    92         {
       
    93           $page_id = str_replace('.', '.2e', $page_id);
       
    94           
       
    95           $q = $db->sql_query('SELECT name FROM ' . table_prefix . "pages WHERE urlname = '$page_id' AND namespace = '$this->namespace';");
       
    96           if ( !$q )
       
    97             $db->_die();
       
    98           
       
    99           if ( $db->numrows() < 1 )
       
   100           {
       
   101             $this->title = $paths->nslist[$namespace] . dirtify_page_id($page_id);
       
   102           }
       
   103           else
       
   104           {
       
   105             list($this->title) = $db->fetchrow_num();
       
   106             $this->exists = true;
       
   107             $this->page_id = $page_id;
       
   108           }
       
   109         }
       
   110         else
       
   111         {
       
   112           $this->title = $paths->nslist[$namespace] . dirtify_page_id($page_id);
       
   113         }
       
   114       }
       
   115       else
       
   116       {
       
   117         list($this->title) = $db->fetchrow_num();
       
   118         $this->exists = true;
       
   119       }
       
   120       $db->free_result();
       
   121     }
       
   122   }
       
   123   
       
   124   /**
       
   125    * Pulls the page's actual text from the database.
       
   126    */
       
   127   
       
   128   function fetch_text()
       
   129   {
       
   130     global $db, $session, $paths, $template, $plugins; // Common objects
       
   131     
       
   132     if ( !empty($this->text_cache) )
       
   133     {
       
   134       return $this->text_cache;
       
   135     }
       
   136     
       
   137     if ( $this->revision_id > 0 && is_int($this->revision_id) )
       
   138     {
       
   139     
       
   140       $q = $db->sql_query('SELECT page_text, char_tag, time_id FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' AND log_id=' . $this->revision_id . ';');
       
   141       if ( !$q )
       
   142       {
       
   143         $this->send_error('Error during SQL query.', true);
       
   144       }
       
   145       if ( $db->numrows() < 1 )
       
   146       {
       
   147         // Compatibility fix for old pages with dots in the page ID
       
   148         if ( strstr($this->page_id, '.2e') )
       
   149         {
       
   150           $db->free_result();
       
   151           $page_id = str_replace('.2e', '.', $this->page_id);
       
   152           $q = $db->sql_query('SELECT page_text, char_tag, time_id FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $this->namespace . '\' AND log_id=' . $this->revision_id . ';');
       
   153           if ( !$q )
       
   154           {
       
   155             $this->send_error('Error during SQL query.', true);
       
   156           }
       
   157           if ( $db->numrows() < 1 )
       
   158           {
       
   159             $this->page_exists = false;
       
   160             return 'err_no_text_rows';
       
   161           }
       
   162         }
       
   163         else
       
   164         {
       
   165           $this->page_exists = false;
       
   166           return 'err_no_text_rows';
       
   167         }
       
   168       }
       
   169       else
       
   170       {
       
   171         $row = $db->fetchrow();
       
   172       }
       
   173       
       
   174       $db->free_result();
       
   175       
       
   176     }
       
   177     else
       
   178     {
       
   179       $q = $db->sql_query('SELECT t.page_text, t.char_tag, l.time_id FROM '.table_prefix."page_text AS t\n"
       
   180                         . "  LEFT JOIN " . table_prefix . "logs AS l\n"
       
   181                         . "    ON ( l.page_id = t.page_id AND l.namespace = t.namespace )\n"
       
   182                         . "  WHERE t.page_id='$this->page_id' AND t.namespace='$this->namespace'\n"
       
   183                         . "  ORDER BY l.time_id DESC LIMIT 1;");
       
   184       if ( !$q )
       
   185       {
       
   186         $this->send_error('Error during SQL query.', true);
       
   187       }
       
   188       if ( $db->numrows() < 1 )
       
   189       {
       
   190         // Compatibility fix for old pages with dots in the page ID
       
   191         if ( strstr($this->page_id, '.2e') )
       
   192         {
       
   193           $db->free_result();
       
   194           $page_id = str_replace('.2e', '.', $this->page_id);
       
   195           $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $this->namespace . '\';');
       
   196           if ( !$q )
       
   197           {
       
   198             $this->send_error('Error during SQL query.', true);
       
   199           }
       
   200           if ( $db->numrows() < 1 )
       
   201           {
       
   202             $this->page_exists = false;
       
   203             return 'err_no_text_rows';
       
   204           }
       
   205         }
       
   206         else
       
   207         {
       
   208           $this->page_exists = false;
       
   209           return 'err_no_text_rows';
       
   210         }
       
   211       }
       
   212       
       
   213       $row = $db->fetchrow();
       
   214       $db->free_result();
       
   215       
       
   216     }
       
   217     
       
   218     if ( !empty($row['char_tag']) )
       
   219     {
       
   220       // This page text entry uses the old text-escaping format
       
   221       $from = array(
       
   222           "{APOS:{$row['char_tag']}}",
       
   223           "{QUOT:{$row['char_tag']}}",
       
   224           "{SLASH:{$row['char_tag']}}"
       
   225         );
       
   226       $to = array("'", '"',  '\\');
       
   227       $row['page_text'] = str_replace($from, $to, $row['page_text']);
       
   228     }
       
   229     
       
   230     $this->text_cache = $row['page_text'];
       
   231     
       
   232     if ( isset($row['time_id']) )
       
   233     {
       
   234       $this->revision_time = intval($row['time_id']);
       
   235     }
       
   236     
       
   237     return $row['page_text'];
       
   238   }
       
   239   
       
   240   /**
       
   241    * Send the page.
       
   242    */
       
   243   
       
   244   public function send()
       
   245   {
       
   246     global $db, $session, $paths, $template, $plugins; // Common objects
       
   247     global $output;
       
   248     
       
   249     $output->add_before_footer($this->display_categories());
       
   250     
       
   251     if ( $this->exists )
       
   252       $this->send_from_db();
       
   253     else
       
   254     {
       
   255       // This is the DEPRECATED way to extend namespaces. It's left in only for compatibility with older plugins.
       
   256       ob_start();
       
   257       $code = $plugins->setHook('page_not_found');
       
   258       foreach ( $code as $cmd )
       
   259       {
       
   260         eval($cmd);
       
   261       }
       
   262       $c = ob_get_contents();
       
   263       if ( !empty($c) )
       
   264       {
       
   265         ob_end_clean();
       
   266         echo $c;
       
   267       }
       
   268       else
       
   269       {
       
   270         $output->header();
       
   271         $this->error_404();
       
   272         $output->footer();
       
   273       }
       
   274     }
       
   275   }
       
   276    
       
   277   /**
       
   278    * The "real" send-the-page function. The reason for this is so other namespaces can re-use the code
       
   279    * to fetch the page from the DB while being able to install their own wrappers.
       
   280    */
       
   281   
       
   282   public function send_from_db($incl_inner_headers = true, $send_headers = true)
       
   283   {
       
   284     global $db, $session, $paths, $template, $plugins; // Common objects
       
   285     global $lang;
       
   286     global $output;
       
   287     
       
   288     $text = $this->fetch_text();
       
   289     
       
   290     $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text);
       
   291     $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text);
       
   292     
       
   293     $redir_enabled = false;
       
   294     if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) )
       
   295     {
       
   296       $redir_enabled = true;
       
   297       
       
   298       $oldtarget = RenderMan::strToPageID($match[1]);
       
   299       $oldtarget[0] = sanitize_page_id($oldtarget[0]);
       
   300       
       
   301       $url = makeUrlNS($oldtarget[1], $oldtarget[0], false, true);
       
   302       $page_id_key = $paths->nslist[ $oldtarget[1] ] . $oldtarget[0];
       
   303       $page_data = $paths->pages[$page_id_key];
       
   304       $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) );
       
   305       if ( !isset($page_data['name']) )
       
   306       {
       
   307         $cls = 'class="wikilink-nonexistent"';
       
   308       }
       
   309       else
       
   310       {
       
   311         $cls = '';
       
   312       }
       
   313       $a = '<a ' . $cls . ' href="' . $url . '">' . $title . '</a>';
       
   314       $redir_html = '<br /><div class="mdg-infobox">
       
   315               <table border="0" width="100%" cellspacing="0" cellpadding="0">
       
   316                 <tr>
       
   317                   <td valign="top">
       
   318                     <img alt="Cute wet-floor icon" src="'.scriptPath.'/images/redirector.png" />
       
   319                   </td>
       
   320                   <td valign="top" style="padding-left: 10px;">
       
   321                     ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . '
       
   322                   </td>
       
   323                 </tr>
       
   324               </table>
       
   325             </div>
       
   326             <br />
       
   327             <hr style="margin-left: 1em; width: 200px;" />';
       
   328       $text = str_replace($match[0], '', $text);
       
   329       $text = trim($text);
       
   330     }
       
   331     
       
   332     if ( $send_headers )
       
   333     {
       
   334       $output->set_title($this->title);
       
   335       $output->header();
       
   336     }
       
   337     $this->do_breadcrumbs();
       
   338     
       
   339     if ( $incl_inner_headers )
       
   340     {
       
   341       display_page_headers();
       
   342     }
       
   343     
       
   344     if ( $this->revision_id )
       
   345     {
       
   346       echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;">
       
   347               <b>' . $lang->get('page_msg_archived_title') . '</b><br />
       
   348               ' . $lang->get('page_msg_archived_body', array(
       
   349                   'archive_date' => enano_date('F d, Y', $this->revision_time),
       
   350                   'archive_time' => enano_date('h:i a', $this->revision_time),
       
   351                   'current_link' => makeUrlNS($this->namespace, $this->page_id),
       
   352                   'restore_link' => makeUrlNS($this->namespace, $this->page_id, 'do=edit&amp;revid='.$this->revision_id),
       
   353                   'restore_onclick' => 'ajaxEditor(\''.$this->revision_id.'\'); return false;',
       
   354                 )) . '
       
   355             </div>';
       
   356     }
       
   357     
       
   358     if ( $redir_enabled )
       
   359     {
       
   360       echo $redir_html;
       
   361     }
       
   362     
       
   363     $code = $plugins->setHook('pageprocess_render_head');
       
   364     foreach ( $code as $cmd )
       
   365     {
       
   366       eval($cmd);
       
   367     }
       
   368     
       
   369     if ( $incl_inner_headers )
       
   370     {
       
   371       $text = '?>' . RenderMan::render($text);
       
   372     }
       
   373     else
       
   374     {
       
   375       $text = '?>' . $text;
       
   376       $text = preg_replace('/<nowiki>(.*?)<\/nowiki>/s', '\\1', $text);
       
   377     }
       
   378     
       
   379     eval ( $text );
       
   380     
       
   381     $code = $plugins->setHook('pageprocess_render_tail');
       
   382     foreach ( $code as $cmd )
       
   383     {
       
   384       eval($cmd);
       
   385     }
       
   386     
       
   387     if ( $incl_inner_headers )
       
   388     {
       
   389       display_page_footers();
       
   390     }
       
   391     
       
   392     if ( $send_headers )
       
   393       $output->footer();
       
   394   }
       
   395   
       
   396   /**
       
   397    * Echoes out breadcrumb data, if appropriate.
       
   398    * @access private
       
   399    */
       
   400   
       
   401   function do_breadcrumbs()
       
   402   {
       
   403     global $db, $session, $paths, $template, $plugins; // Common objects
       
   404     global $lang;
       
   405     
       
   406     if ( strpos($this->text_cache, '__NOBREADCRUMBS__') !== false )
       
   407       return false;
       
   408     
       
   409     $mode = getConfig('breadcrumb_mode');
       
   410     
       
   411     if ( $mode == 'never' )
       
   412       // Breadcrumbs are disabled
       
   413       return true;
       
   414       
       
   415     // Minimum depth for breadcrumb display
       
   416     $threshold = ( $mode == 'always' ) ? 0 : 1;
       
   417     
       
   418     $breadcrumb_data = explode('/', $this->page_id);
       
   419     if ( count($breadcrumb_data) > $threshold )
       
   420     {
       
   421       // If we're not on a subpage of the main page, add "Home" to the list
       
   422       $show_home = false;
       
   423       if ( $mode == 'always' )
       
   424       {
       
   425         $show_home = true;
       
   426       }
       
   427       echo '<!-- Start breadcrumbs -->
       
   428             <div class="breadcrumbs">
       
   429               ';
       
   430       if ( $show_home )
       
   431       {
       
   432         // Display the "home" link first.
       
   433         $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id;
       
   434         if ( $pathskey !== get_main_page() )
       
   435           echo '<a href="' . makeUrl(get_main_page(), false, true) . '">';
       
   436         echo $lang->get('onpage_btn_breadcrumbs_home');
       
   437         if ( $pathskey !== get_main_page() )
       
   438           echo '</a>';
       
   439       }
       
   440       foreach ( $breadcrumb_data as $i => $crumb )
       
   441       {
       
   442         $cumulative = implode('/', array_slice($breadcrumb_data, 0, ( $i + 1 )));
       
   443         if ( $show_home && $cumulative === get_main_page() )
       
   444           continue;
       
   445         if ( $show_home || $i > 0 )
       
   446           echo ' &raquo; ';
       
   447         $title = ( isPage($cumulative) ) ? get_page_title($cumulative) : get_page_title($crumb);
       
   448         if ( $i + 1 == count($breadcrumb_data) )
       
   449         {
       
   450           echo htmlspecialchars($title);
       
   451         }
       
   452         else
       
   453         {
       
   454           $exists = ( isPage($cumulative) ) ? '' : ' class="wikilink-nonexistent"';
       
   455           echo '<a href="' . makeUrl($cumulative, false, true) . '"' . $exists . '>' . htmlspecialchars($title) . '</a>';
       
   456         }
       
   457       }
       
   458       echo '</div>
       
   459             <!-- End breadcrumbs -->
       
   460             ';
       
   461     }
       
   462   }
       
   463   
       
   464   public function error_404($userpage = false)
       
   465   {
       
   466     global $db, $session, $paths, $template, $plugins; // Common objects
       
   467     global $lang, $output;
       
   468     
       
   469     @header('HTTP/1.1 404 Not Found');
       
   470     
       
   471     $msg = ( $pp = $paths->sysmsg('Page_not_found') ) ? $pp : '{STANDARD404}';
       
   472     
       
   473     $standard_404 = '';
       
   474     
       
   475     if ( $userpage )
       
   476     {
       
   477       $standard_404 .= '<h3>' . $lang->get('page_msg_404_title_userpage') . '</h3>
       
   478              <p>' . $lang->get('page_msg_404_body_userpage');
       
   479     }
       
   480     else
       
   481     {
       
   482       $standard_404 .= '<h3>' . $lang->get('page_msg_404_title') . '</h3>
       
   483              <p>' . $lang->get('page_msg_404_body');
       
   484     }
       
   485     if ( $session->get_permissions('create_page') )
       
   486     {
       
   487       $standard_404 .= ' ' . $lang->get('page_msg_404_create', array(
       
   488           'create_flags' => 'href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;"',
       
   489           'mainpage_link' => makeUrl(get_main_page(), false, true)
       
   490         ));
       
   491     }
       
   492     else
       
   493     {
       
   494       $standard_404 .= ' ' . $lang->get('page_msg_404_gohome', array(
       
   495           'mainpage_link' => makeUrl(get_main_page(), false, true)
       
   496         ));
       
   497     }
       
   498     $standard_404 .= '</p>';
       
   499     if ( $session->get_permissions('history_rollback') )
       
   500     {
       
   501       $e = $db->sql_query('SELECT * FROM ' . table_prefix . 'logs WHERE action=\'delete\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' ORDER BY time_id DESC;');
       
   502       if ( !$e )
       
   503       {
       
   504         $db->_die('The deletion log could not be selected.');
       
   505       }
       
   506       if ( $db->numrows() > 0 )
       
   507       {
       
   508         $r = $db->fetchrow();
       
   509         $standard_404 .= '<p>' . $lang->get('page_msg_404_was_deleted', array(
       
   510                   'delete_time' => enano_date('d M Y h:i a', $r['time_id']),
       
   511                   'delete_reason' => htmlspecialchars($r['edit_summary']),
       
   512                   'rollback_flags' => 'href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['log_id']).'" onclick="ajaxRollback(\''.$r['log_id'].'\'); return false;"'
       
   513                 ))
       
   514               . '</p>';
       
   515         if ( $session->user_level >= USER_LEVEL_ADMIN )
       
   516         {
       
   517           $standard_404 .= '<p>' . $lang->get('page_msg_404_admin_opts', array(
       
   518                     'detag_link' => makeUrl($paths->page, 'do=detag', true)
       
   519                   ))
       
   520                 . '</p>';
       
   521         }
       
   522       }
       
   523       $db->free_result();
       
   524     }
       
   525     $standard_404 .= '<p>
       
   526             ' . $lang->get('page_msg_404_http_response') . '
       
   527           </p>';
       
   528           
       
   529     $parser = $template->makeParserText($msg);
       
   530     $parser->assign_vars(array(
       
   531         'STANDARD404' => $standard_404
       
   532       ));
       
   533     
       
   534     $msg = RenderMan::render($parser->run());
       
   535     eval( '?>' . $msg );
       
   536   }
       
   537   
       
   538   /**
       
   539    * Display the categories a page is in. If the current page is a category, its contents will also be printed.
       
   540    */
       
   541   
       
   542   function display_categories()
       
   543   {
       
   544     global $db, $session, $paths, $template, $plugins; // Common objects
       
   545     global $lang;
       
   546     
       
   547     $html = '';
       
   548     
       
   549     if ( $this->namespace == 'Category' )
       
   550     {
       
   551       // Show member pages and subcategories
       
   552       $q = $db->sql_query('SELECT p.urlname, p.namespace, p.name, p.namespace=\'Category\' AS is_category FROM '.table_prefix.'categories AS c
       
   553                              LEFT JOIN '.table_prefix.'pages AS p
       
   554                                ON ( p.urlname = c.page_id AND p.namespace = c.namespace )
       
   555                              WHERE c.category_id=\'' . $db->escape($this->page_id) . '\'
       
   556                              ORDER BY is_category DESC, p.name ASC;');
       
   557       if ( !$q )
       
   558       {
       
   559         $db->_die();
       
   560       }
       
   561       $html .= '<h3>' . $lang->get('onpage_cat_heading_subcategories') . '</h3>';
       
   562       $html .= '<div class="tblholder">';
       
   563       $html .= '<table border="0" cellspacing="1" cellpadding="4">';
       
   564       $html .= '<tr>';
       
   565       $ticker = 0;
       
   566       $counter = 0;
       
   567       $switched = false;
       
   568       $class  = 'row1';
       
   569       while ( $row = $db->fetchrow() )
       
   570       {
       
   571         if ( $row['is_category'] == 0 && !$switched )
       
   572         {
       
   573           if ( $counter > 0 )
       
   574           {
       
   575             // Fill-in
       
   576             while ( $ticker < 3 )
       
   577             {
       
   578               $ticker++;
       
   579               $html .= '<td class="' . $class . '" style="width: 33.3%;"></td>';
       
   580             }
       
   581           }
       
   582           else
       
   583           {
       
   584             $html .= '<td class="' . $class . '">' . $lang->get('onpage_cat_msg_no_subcategories') . '</td>';
       
   585           }
       
   586           $html .= '</tr></table></div>' . "\n\n";
       
   587           $html .= '<h3>' . $lang->get('onpage_cat_heading_pages') . '</h3>';
       
   588           $html .= '<div class="tblholder">';
       
   589           $html .= '<table border="0" cellspacing="1" cellpadding="4">';
       
   590           $html .= '<tr>';
       
   591           $counter = 0;
       
   592           $ticker = -1;
       
   593           $switched = true;
       
   594         }
       
   595         $counter++;
       
   596         $ticker++;
       
   597         if ( $ticker == 3 )
       
   598         {
       
   599           $html .= '</tr><tr>';
       
   600           $ticker = 0;
       
   601           $class = ( $class == 'row3' ) ? 'row1' : 'row3';
       
   602         }
       
   603         $html .= "<td class=\"{$class}\" style=\"width: 33.3%;\">"; // " to workaround stupid jEdit bug
       
   604         
       
   605         $link = makeUrlNS($row['namespace'], sanitize_page_id($row['urlname']));
       
   606         $html .= '<a href="' . $link . '"';
       
   607         $key = $paths->nslist[$row['namespace']] . sanitize_page_id($row['urlname']);
       
   608         if ( !isPage( $key ) )
       
   609         {
       
   610           $html .= ' class="wikilink-nonexistent"';
       
   611         }
       
   612         $html .= '>';
       
   613         $title = get_page_title_ns($row['urlname'], $row['namespace']);
       
   614         $html .= htmlspecialchars($title);
       
   615         $html .= '</a>';
       
   616         
       
   617         $html .= "</td>";
       
   618       }
       
   619       if ( !$switched )
       
   620       {
       
   621         if ( $counter > 0 )
       
   622         {
       
   623           // Fill-in
       
   624           while ( $ticker < 2 )
       
   625           {
       
   626             $ticker++;
       
   627             $html .= '<td class="' . $class . '" style="width: 33.3%;"></td>';
       
   628           }
       
   629         }
       
   630         else
       
   631         {
       
   632           $html .= '<td class="' . $class . '">' . $lang->get('onpage_cat_msg_no_subcategories') . '</td>';
       
   633         }
       
   634         $html .= '</tr></table></div>' . "\n\n";
       
   635         $html .= '<h3>' . $lang->get('onpage_cat_heading_pages') . '</h3>';
       
   636         $html .= '<div class="tblholder">';
       
   637         $html .= '<table border="0" cellspacing="1" cellpadding="4">';
       
   638         $html .= '<tr>';
       
   639         $counter = 0;
       
   640         $ticker = 0;
       
   641         $switched = true;
       
   642       }
       
   643       if ( $counter > 0 )
       
   644       {
       
   645         // Fill-in
       
   646         while ( $ticker < 2 )
       
   647         {
       
   648           $ticker++;
       
   649           $html .= '<td class="' . $class . '" style="width: 33.3%;"></td>';
       
   650         }
       
   651       }
       
   652       else
       
   653       {
       
   654         $html .= '<td class="' . $class . '">' . $lang->get('onpage_cat_msg_no_pages') . '</td>';
       
   655       }
       
   656       $html .= '</tr></table></div>' . "\n\n";
       
   657     }
       
   658     
       
   659     if ( $this->namespace != 'Special' && $this->namespace != 'Admin' )
       
   660     {
       
   661       $html .= '<div class="mdg-comment" style="margin: 10px 0 0 0;" id="category_box_wrapper">';
       
   662       $html .= '<div style="float: right;">';
       
   663       $html .= '(<a href="#" onclick="ajaxCatToTag(); return false;">' . $lang->get('tags_catbox_link') . '</a>)';
       
   664       $html .= '</div>';
       
   665       $html .= '<div id="mdgCatBox">' . $lang->get('catedit_catbox_lbl_categories') . ' ';
       
   666       
       
   667       $where = '( c.page_id=\'' . $db->escape($this->page_id) . '\' AND c.namespace=\'' . $db->escape($this->namespace) . '\' )';
       
   668       $prefix = table_prefix;
       
   669       $sql = <<<EOF
       
   670 SELECT c.category_id FROM {$prefix}categories AS c
       
   671   LEFT JOIN {$prefix}pages AS p
       
   672     ON ( ( p.urlname = c.page_id AND p.namespace = c.namespace ) OR ( p.urlname IS NULL AND p.namespace IS NULL ) )
       
   673   WHERE $where
       
   674   ORDER BY p.name ASC, c.page_id ASC;
       
   675 EOF;
       
   676       $q = $db->sql_query($sql);
       
   677       if ( !$q )
       
   678         $db->_die();
       
   679       
       
   680       if ( $row = $db->fetchrow() )
       
   681       {
       
   682         $list = array();
       
   683         do
       
   684         {
       
   685           $cid = sanitize_page_id($row['category_id']);
       
   686           $title = get_page_title_ns($cid, 'Category');
       
   687           $link = makeUrlNS('Category', $cid);
       
   688           $list[] = '<a href="' . $link . '">' . htmlspecialchars($title) . '</a>';
       
   689         }
       
   690         while ( $row = $db->fetchrow() );
       
   691         $html .= implode(', ', $list);
       
   692       }
       
   693       else
       
   694       {
       
   695         $html .= $lang->get('catedit_catbox_lbl_uncategorized');
       
   696       }
       
   697       
       
   698       $can_edit = ( $session->get_permissions('edit_cat') && ( !$paths->page_protected || $session->get_permissions('even_when_protected') ) );
       
   699       if ( $can_edit )
       
   700       {
       
   701         $edit_link = '<a href="' . makeUrl($paths->page, 'do=catedit', true) . '" onclick="ajaxCatEdit(); return false;">' . $lang->get('catedit_catbox_link_edit') . '</a>';
       
   702         $html .= ' [ ' . $edit_link . ' ]';
       
   703       }
       
   704       
       
   705       $html .= '</div></div>';
       
   706     }
       
   707     return $html;
       
   708   }
       
   709   /**
       
   710    * Just tell us if the current page exists or not.
       
   711    * @return bool
       
   712    */
       
   713    
       
   714   function exists()
       
   715   {
       
   716     return $this->exists;
       
   717   }
       
   718 }
       
   719 
       
   720 /**
       
   721  * The namespaces that use the default handler.
       
   722  */
       
   723 
       
   724 class Namespace_Article extends Namespace_Default
       
   725 {
       
   726 }
       
   727 
       
   728 class Namespace_Project extends Namespace_Default
       
   729 {
       
   730 }
       
   731 
       
   732 class Namespace_Help extends Namespace_Default
       
   733 {
       
   734 }
       
   735