plugins/SpecialLog.php
changeset 1227 bdac73ed481e
parent 1081 745200a9cc2a
--- a/plugins/SpecialLog.php	Sun Mar 28 21:49:26 2010 -0400
+++ b/plugins/SpecialLog.php	Sun Mar 28 23:10:46 2010 -0400
@@ -1,12 +1,12 @@
 <?php
 /**!info**
 {
-  "Plugin Name"  : "plugin_speciallog_title",
-  "Plugin URI"   : "http://enanocms.org/",
-  "Description"  : "plugin_speciallog_desc",
-  "Author"       : "Dan Fuhry",
-  "Version"      : "1.1.6",
-  "Author URI"   : "http://enanocms.org/"
+	"Plugin Name"  : "plugin_speciallog_title",
+	"Plugin URI"   : "http://enanocms.org/",
+	"Description"  : "plugin_speciallog_desc",
+	"Author"       : "Dan Fuhry",
+	"Version"      : "1.1.6",
+	"Author URI"   : "http://enanocms.org/"
 }
 **!*/
 
@@ -23,409 +23,409 @@
 
 function SpecialLog_paths_init()
 {
-  register_special_page('Log', 'specialpage_log');
+	register_special_page('Log', 'specialpage_log');
 }
 
 function page_Special_Log()
 {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $lang;
-  global $output;
-  
-  // FIXME: This doesn't currently prohibit viewing of aggregate logs that might include a page for which
-  // we don't have permission to view history. It does, however, block access if a list of pages is given
-  // and one of those doesn't allow history_view.
-  
-  // FIXME: This is a real hack. We're trying to get permissions on a random non-existent article, which
-  // effectively forces calculation to occur based on site-wide permissions.
-  $pid = '';
-  for ( $i = 0; $i < 32; $i++ )
-  {
-    $pid .= chr(mt_rand(32, 126));
-  }
-  $perms = $session->fetch_page_acl($pid, 'Article');
-  $perms_changed = false;
-  
-  require_once(ENANO_ROOT . '/includes/log.php');
-  $log = new LogDisplay();
-  $page = 1;
-  $pagesize = 50;
-  $fmt = 'full';
-  
-  if ( $params = $paths->getAllParams() )
-  {
-    if ( $params === 'AddFilter' && !empty($_POST['type']) && !empty($_POST['value']) )
-    {
-      $type = $_POST['type'];
-      if ( $type == 'within' )
-        $value = strval(intval($_POST['value']['within'])) . $_POST['value']['withinunits'];
-      else
-        $value = $_POST['value'][$type];
-      
-      if ( !ctype_digit($value) )
-        $value = str_replace('/', '.2f', sanitize_page_id($value));
-      
-      if ( $value !== '0' && (empty($value) || ( $type == 'within' && intval($value) == 0 )) )
-      {
-        $adderror = $lang->get('log_err_addfilter_field_empty');
-      }
-      else
-      {
-        $append = ( !empty($_POST['existing_filters']) ) ? "{$_POST['existing_filters']}/" : '';
-        $url = makeUrlNS('Special', "Log/{$append}{$type}={$value}");
-        
-        redirect($url, '', '', 0);
-      }
-    }
-    $params = explode('/', $params);
-    foreach ( $params as $i => $param )
-    {
-      $param = str_replace('.2f', '/', dirtify_page_id($param));
-      if ( preg_match('/^([a-z]+)!?=(.+?)$/', $param, $match) )
-      {
-        $name =& $match[1];
-        $value =& $match[2];
-        switch($name)
-        {
-          case 'resultpage':
-            $page = intval($value);
-            break;
-          case 'size':
-            $pagesize = intval($value);
-            break;
-          case 'fmt':
-            switch($value)
-            {
-              case 'barenaked':
-              case 'ajax':
-                $fmt = 'naked';
-                $output = new Output_Naked();
-                break;
-            }
-            break;
-          case 'page':
-            // tolerate slashes
-            $j = $i;
-            while ( true )
-            {
-              if ( isset($params[++$j]) )
-              {
-                if ( preg_match('/^([a-z]+)!?=(.+?)$/', $params[$j]) )
-                  break;
-                
-                $value .= '/' . $params[$j];
-              }
-              else
-              {
-                break;
-              }
-            }
-            if ( get_class($perms) == 'sessionManager' )
-            {
-              unset($perms);
-              list($pid, $ns) = RenderMan::strToPageID($value);
-              $perms = $session->fetch_page_acl($pid, $ns);
-              if ( !$perms->get_permissions('history_view') )
-              {
-                die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('log_err_access_denied') . '</p>');
-              }
-            }
-            // no break here on purpose
-          default:
-            try
-            {
-              $log->add_criterion($name, $value);
-            }
-            catch ( Exception $e )
-            {
-            }
-            break;
-        }
-      }
-    }
-  }
-  if ( !$perms->get_permissions('history_view') )
-  {
-    die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('log_err_access_denied') . '</p>');
-  }
-  
-  $page--;
-  $rowcount = $log->get_row_count();
-  $paramsbit = rtrim(preg_replace('|/?resultpage=([0-9]+)/?|', '/', $paths->getAllParams()), '/');
-  $paramsbit = ( !empty($paramsbit) ) ? "/$paramsbit" : '';
-  $result_url = makeUrlNS('Special', 'Log' . $paramsbit . '/resultpage=%s', false, true);
-  $paginator = generate_paginator($page, ceil($rowcount / $pagesize), $result_url);
-  
-  $dataset = $log->get_data($page * $pagesize, $pagesize);
-  
-  $output->header();
-  
-  // breadcrumbs
-  if ( $fmt != 'naked' )
-  {
-    echo '<div class="breadcrumbs" style="font-weight: normal;" id="log-breadcrumbs">';
-    echo speciallog_generate_breadcrumbs($log->get_criteria());
-    echo '</div>';
-  
-  // form
-  ?>
-  
-  <!-- Begin filter add form -->
-  
-  <form action="<?php echo makeUrlNS('Special', 'Log/AddFilter', false, true); ?>" method="post" enctype="multipart/form-data">
-    <?php
-    // serialize parameters
-    $params_pre = rtrim(preg_replace('#/?resultpage=[0-9]+/?#', '/', $paths->getAllParams()), '/');
-    echo '<input type="hidden" name="existing_filters" value="' . htmlspecialchars($params_pre) . '" />';
-    ?>
-    <script type="text/javascript">//<![CDATA[
-      addOnloadHook(function()
-        {
-          load_component('jquery');
-          $('#log_addfilter_select').change(function()
-            {
-              var value = $(this).val();
-              $('.log_addfilter').hide();
-              $('#log_addform_' + value).show();
-            });
-          $('#log_addform_' + $('#log_addfilter_select').val()).show();
-        });
-    // ]]>
-    </script>
-    <?php
-    if ( isset($adderror) )
-    {
-      echo '<div class="error-box">' . $adderror . '</div>';
-    }
-    ?>
-    <div class="tblholder">
-    <table border="0" cellspacing="1" cellpadding="4">
-      <tr>
-        <th colspan="2">
-          <?php echo $lang->get('log_heading_addfilter'); ?>
-        </th>
-      </tr>
-      <tr>
-      <td class="row1" style="width: 50%; text-align: right;">
-          <select name="type" id="log_addfilter_select">
-            <option value="user"><?php echo $lang->get('log_form_filtertype_user'); ?></option>
-            <option value="page"><?php echo $lang->get('log_form_filtertype_page'); ?></option>
-            <option value="within"><?php echo $lang->get('log_form_filtertype_within'); ?></option>
-            <option value="action"><?php echo $lang->get('log_form_filtertype_action'); ?></option>
-            <option value="minor"><?php echo $lang->get('log_form_filtertype_minor'); ?></option>
-          </select>
-        </td>
-        <td class="row1" style="width: 50%; text-align: left;">
-          <div class="log_addfilter" id="log_addform_user">
-            <input type="text" class="autofill username" name="value[user]" size="40" />
-          </div>
-          <div class="log_addfilter" id="log_addform_page">
-            <input type="text" class="autofill page" name="value[page]" size="40" />
-          </div>
-          <div class="log_addfilter" id="log_addform_within">
-            <input type="text" name="value[within]" size="7" />
-            <select name="value[withinunits]">
-              <option value="d"><?php echo $lang->get('etc_unit_days'); ?></option>
-              <option value="w"><?php echo $lang->get('etc_unit_weeks'); ?></option>
-              <option value="m"><?php echo $lang->get('etc_unit_months'); ?></option>
-              <option value="y"><?php echo $lang->get('etc_unit_years'); ?></option>
-            </select>
-          </div>
-          <div class="log_addfilter" id="log_addform_action">
-            <select name="value[action]">
-              <option value="rename"><?php echo $lang->get('log_formaction_rename'); ?></option>
-              <option value="create"><?php echo $lang->get('log_formaction_create'); ?></option>
-              <option value="delete"><?php echo $lang->get('log_formaction_delete'); ?></option>
-              <option value="protect"><?php echo $lang->get('log_action_protect'); ?></option>
-              <option value="edit"><?php echo $lang->get('log_action_edit'); ?></option>
-              <option value="edit"><?php echo $lang->get('log_formaction_reupload'); ?></option>
-              <option value="edit"><?php echo $lang->get('log_formaction_votereset'); ?></option>
-            </select>
-          </div>
-          <div class="log_addfilter" id="log_addform_minor">
-            <label>
-              <input type="radio" name="value[minor]" value="1" checked="checked" />
-              <?php echo $lang->get('log_form_filtertype_minor_yes'); ?>
-            </label>
-            <label>
-              <input type="radio" name="value[minor]" value="0" />
-              <?php echo $lang->get('log_form_filtertype_minor_no'); ?>
-            </label>
-          </div>
-        </td>
-      </tr>
-      <tr>
-        <th colspan="2" class="subhead">
-          <input type="submit" value="<?php echo $lang->get('log_btn_add_filter'); ?>" />
-        </th>
-      </tr>
-    </table>
-    </div>
-  
-  </form>
-  
-  <!-- End filter add form -->
-  
-  <?php
-  
-  }
-  
-  // start of actual log output area
-  if ( $fmt != 'naked' )
-  {
-    echo '<div id="log-body">';
-  }
-  
-  if ( $rowcount > 0 )
-  {
-    // we have some results, show pagination + result list
-    echo '<h3 style="float: left;">' . $lang->get('log_heading_logdisplay') . '</h3>';
-    
-    echo $paginator;
-    // padding
-    echo '<div style="height: 10px; clear: both;"></div>';
-    foreach ( $dataset as $row )
-    {
-      echo LogDisplay::render_row($row) . '<br />';
-    }
-    echo $paginator;
-  }
-  else
-  {
-    // no results
-    echo '<h2 class="emptymessage">' . $lang->get('log_msg_no_results') . '</h2>';
-  }
-  
-  if ( $fmt != 'naked' )
-    echo '</div> <!-- div#log-body -->';
-  
-  $output->footer();
+	global $db, $session, $paths, $template, $plugins; // Common objects
+	global $lang;
+	global $output;
+	
+	// FIXME: This doesn't currently prohibit viewing of aggregate logs that might include a page for which
+	// we don't have permission to view history. It does, however, block access if a list of pages is given
+	// and one of those doesn't allow history_view.
+	
+	// FIXME: This is a real hack. We're trying to get permissions on a random non-existent article, which
+	// effectively forces calculation to occur based on site-wide permissions.
+	$pid = '';
+	for ( $i = 0; $i < 32; $i++ )
+	{
+		$pid .= chr(mt_rand(32, 126));
+	}
+	$perms = $session->fetch_page_acl($pid, 'Article');
+	$perms_changed = false;
+	
+	require_once(ENANO_ROOT . '/includes/log.php');
+	$log = new LogDisplay();
+	$page = 1;
+	$pagesize = 50;
+	$fmt = 'full';
+	
+	if ( $params = $paths->getAllParams() )
+	{
+		if ( $params === 'AddFilter' && !empty($_POST['type']) && !empty($_POST['value']) )
+		{
+			$type = $_POST['type'];
+			if ( $type == 'within' )
+				$value = strval(intval($_POST['value']['within'])) . $_POST['value']['withinunits'];
+			else
+				$value = $_POST['value'][$type];
+			
+			if ( !ctype_digit($value) )
+				$value = str_replace('/', '.2f', sanitize_page_id($value));
+			
+			if ( $value !== '0' && (empty($value) || ( $type == 'within' && intval($value) == 0 )) )
+			{
+				$adderror = $lang->get('log_err_addfilter_field_empty');
+			}
+			else
+			{
+				$append = ( !empty($_POST['existing_filters']) ) ? "{$_POST['existing_filters']}/" : '';
+				$url = makeUrlNS('Special', "Log/{$append}{$type}={$value}");
+				
+				redirect($url, '', '', 0);
+			}
+		}
+		$params = explode('/', $params);
+		foreach ( $params as $i => $param )
+		{
+			$param = str_replace('.2f', '/', dirtify_page_id($param));
+			if ( preg_match('/^([a-z]+)!?=(.+?)$/', $param, $match) )
+			{
+				$name =& $match[1];
+				$value =& $match[2];
+				switch($name)
+				{
+					case 'resultpage':
+						$page = intval($value);
+						break;
+					case 'size':
+						$pagesize = intval($value);
+						break;
+					case 'fmt':
+						switch($value)
+						{
+							case 'barenaked':
+							case 'ajax':
+								$fmt = 'naked';
+								$output = new Output_Naked();
+								break;
+						}
+						break;
+					case 'page':
+						// tolerate slashes
+						$j = $i;
+						while ( true )
+						{
+							if ( isset($params[++$j]) )
+							{
+								if ( preg_match('/^([a-z]+)!?=(.+?)$/', $params[$j]) )
+									break;
+								
+								$value .= '/' . $params[$j];
+							}
+							else
+							{
+								break;
+							}
+						}
+						if ( get_class($perms) == 'sessionManager' )
+						{
+							unset($perms);
+							list($pid, $ns) = RenderMan::strToPageID($value);
+							$perms = $session->fetch_page_acl($pid, $ns);
+							if ( !$perms->get_permissions('history_view') )
+							{
+								die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('log_err_access_denied') . '</p>');
+							}
+						}
+						// no break here on purpose
+					default:
+						try
+						{
+							$log->add_criterion($name, $value);
+						}
+						catch ( Exception $e )
+						{
+						}
+						break;
+				}
+			}
+		}
+	}
+	if ( !$perms->get_permissions('history_view') )
+	{
+		die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('log_err_access_denied') . '</p>');
+	}
+	
+	$page--;
+	$rowcount = $log->get_row_count();
+	$paramsbit = rtrim(preg_replace('|/?resultpage=([0-9]+)/?|', '/', $paths->getAllParams()), '/');
+	$paramsbit = ( !empty($paramsbit) ) ? "/$paramsbit" : '';
+	$result_url = makeUrlNS('Special', 'Log' . $paramsbit . '/resultpage=%s', false, true);
+	$paginator = generate_paginator($page, ceil($rowcount / $pagesize), $result_url);
+	
+	$dataset = $log->get_data($page * $pagesize, $pagesize);
+	
+	$output->header();
+	
+	// breadcrumbs
+	if ( $fmt != 'naked' )
+	{
+		echo '<div class="breadcrumbs" style="font-weight: normal;" id="log-breadcrumbs">';
+		echo speciallog_generate_breadcrumbs($log->get_criteria());
+		echo '</div>';
+	
+	// form
+	?>
+	
+	<!-- Begin filter add form -->
+	
+	<form action="<?php echo makeUrlNS('Special', 'Log/AddFilter', false, true); ?>" method="post" enctype="multipart/form-data">
+		<?php
+		// serialize parameters
+		$params_pre = rtrim(preg_replace('#/?resultpage=[0-9]+/?#', '/', $paths->getAllParams()), '/');
+		echo '<input type="hidden" name="existing_filters" value="' . htmlspecialchars($params_pre) . '" />';
+		?>
+		<script type="text/javascript">//<![CDATA[
+			addOnloadHook(function()
+				{
+					load_component('jquery');
+					$('#log_addfilter_select').change(function()
+						{
+							var value = $(this).val();
+							$('.log_addfilter').hide();
+							$('#log_addform_' + value).show();
+						});
+					$('#log_addform_' + $('#log_addfilter_select').val()).show();
+				});
+		// ]]>
+		</script>
+		<?php
+		if ( isset($adderror) )
+		{
+			echo '<div class="error-box">' . $adderror . '</div>';
+		}
+		?>
+		<div class="tblholder">
+		<table border="0" cellspacing="1" cellpadding="4">
+			<tr>
+				<th colspan="2">
+					<?php echo $lang->get('log_heading_addfilter'); ?>
+				</th>
+			</tr>
+			<tr>
+			<td class="row1" style="width: 50%; text-align: right;">
+					<select name="type" id="log_addfilter_select">
+						<option value="user"><?php echo $lang->get('log_form_filtertype_user'); ?></option>
+						<option value="page"><?php echo $lang->get('log_form_filtertype_page'); ?></option>
+						<option value="within"><?php echo $lang->get('log_form_filtertype_within'); ?></option>
+						<option value="action"><?php echo $lang->get('log_form_filtertype_action'); ?></option>
+						<option value="minor"><?php echo $lang->get('log_form_filtertype_minor'); ?></option>
+					</select>
+				</td>
+				<td class="row1" style="width: 50%; text-align: left;">
+					<div class="log_addfilter" id="log_addform_user">
+						<input type="text" class="autofill username" name="value[user]" size="40" />
+					</div>
+					<div class="log_addfilter" id="log_addform_page">
+						<input type="text" class="autofill page" name="value[page]" size="40" />
+					</div>
+					<div class="log_addfilter" id="log_addform_within">
+						<input type="text" name="value[within]" size="7" />
+						<select name="value[withinunits]">
+							<option value="d"><?php echo $lang->get('etc_unit_days'); ?></option>
+							<option value="w"><?php echo $lang->get('etc_unit_weeks'); ?></option>
+							<option value="m"><?php echo $lang->get('etc_unit_months'); ?></option>
+							<option value="y"><?php echo $lang->get('etc_unit_years'); ?></option>
+						</select>
+					</div>
+					<div class="log_addfilter" id="log_addform_action">
+						<select name="value[action]">
+							<option value="rename"><?php echo $lang->get('log_formaction_rename'); ?></option>
+							<option value="create"><?php echo $lang->get('log_formaction_create'); ?></option>
+							<option value="delete"><?php echo $lang->get('log_formaction_delete'); ?></option>
+							<option value="protect"><?php echo $lang->get('log_action_protect'); ?></option>
+							<option value="edit"><?php echo $lang->get('log_action_edit'); ?></option>
+							<option value="edit"><?php echo $lang->get('log_formaction_reupload'); ?></option>
+							<option value="edit"><?php echo $lang->get('log_formaction_votereset'); ?></option>
+						</select>
+					</div>
+					<div class="log_addfilter" id="log_addform_minor">
+						<label>
+							<input type="radio" name="value[minor]" value="1" checked="checked" />
+							<?php echo $lang->get('log_form_filtertype_minor_yes'); ?>
+						</label>
+						<label>
+							<input type="radio" name="value[minor]" value="0" />
+							<?php echo $lang->get('log_form_filtertype_minor_no'); ?>
+						</label>
+					</div>
+				</td>
+			</tr>
+			<tr>
+				<th colspan="2" class="subhead">
+					<input type="submit" value="<?php echo $lang->get('log_btn_add_filter'); ?>" />
+				</th>
+			</tr>
+		</table>
+		</div>
+	
+	</form>
+	
+	<!-- End filter add form -->
+	
+	<?php
+	
+	}
+	
+	// start of actual log output area
+	if ( $fmt != 'naked' )
+	{
+		echo '<div id="log-body">';
+	}
+	
+	if ( $rowcount > 0 )
+	{
+		// we have some results, show pagination + result list
+		echo '<h3 style="float: left;">' . $lang->get('log_heading_logdisplay') . '</h3>';
+		
+		echo $paginator;
+		// padding
+		echo '<div style="height: 10px; clear: both;"></div>';
+		foreach ( $dataset as $row )
+		{
+			echo LogDisplay::render_row($row) . '<br />';
+		}
+		echo $paginator;
+	}
+	else
+	{
+		// no results
+		echo '<h2 class="emptymessage">' . $lang->get('log_msg_no_results') . '</h2>';
+	}
+	
+	if ( $fmt != 'naked' )
+		echo '</div> <!-- div#log-body -->';
+	
+	$output->footer();
 }
 
 function speciallog_generate_breadcrumbs($criteria)
 {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $lang;
-  
-  if ( count($criteria) == 0 )
-  {
-    return $lang->get('log_msg_no_filters');
-  }
-  
-  $html = array();
-  foreach ( $criteria as $criterion )
-  {
-    list($type, $value) = $criterion;
-    switch($type)
-    {
-      case 'user':
-        $rank_info = $session->get_user_rank($value);
-        $user_link = '<a href="' . makeUrlNS('User', $value, false, true) . '" style="' . $rank_info['rank_style'] . '" title="' . htmlspecialchars($lang->get($rank_info['rank_title'])) . '">';
-        $user_link .= htmlspecialchars(str_replace('_', ' ', $value)) . '</a>';
-        
-        $crumb = $lang->get('log_breadcrumb_author', array('user' => $user_link));
-        break;
-      case 'page':
-        list($pid, $ns) = RenderMan::strToPageID($value);
-        $ns = namespace_factory($pid, $ns);
-        $exist = $ns->exists() ? '' : ' class="wikilink-nonexistent"';
-        $crumb = $lang->get('log_breadcrumb_page', array('page' => '<a' . $exist . ' href="' . makeUrl($value, false, true) . '">' . htmlspecialchars($ns->title) . '</a>'));
-        break;
-      case 'action':
-        $action = ( $lang->get("log_formaction_{$value}") === "log_formaction_{$value}" ) ? $lang->get("log_action_{$value}") : $lang->get("log_formaction_{$value}");
-        $crumb = $lang->get('log_breadcrumb_action', array('action' => htmlspecialchars($action)));
-        break;
-      case 'minor':
-        $crumb = $value == '1' ? $lang->get('log_form_filtertype_minor_yes') : $lang->get('log_form_filtertype_minor_no');
-        break;
-      case 'within':
-        $value = intval($value);
-        if ( $value % 31536000 == 0 )
-        {
-          $n = $value / 31536000;
-          $value = "$n " . $lang->get( $n > 1 ? 'etc_unit_years' : 'etc_unit_year' );
-        }
-        else if ( $value % 2592000 == 0 )
-        {
-          $n = $value / 2592000;
-          $value = "$n " . $lang->get( $n > 1 ? 'etc_unit_months' : 'etc_unit_month' );
-        }
-        else if ( $value % 604800 == 0 )
-        {
-          $n = $value / 604800;
-          $value = "$n " . $lang->get( $n > 1 ? 'etc_unit_weeks' : 'etc_unit_week' );
-        }
-        else if ( $value % 86400 == 0 )
-        {
-          $n = $value / 86400;
-          $value = "$n " . $lang->get( $n > 1 ? 'etc_unit_days' : 'etc_unit_day' );
-        }
-        else
-        {
-          $value = "$value " . $lang->get( $value > 1 ? 'etc_unit_seconds' : 'etc_unit_second' );
-        }
-        $crumb = $lang->get('log_breadcrumb_within', array('time' => $value));
-        break;
-    }
-    $html[] = $crumb . ' ' . speciallog_crumb_remove_link($criterion);
-  }
-  return implode(' &raquo; ', $html);
+	global $db, $session, $paths, $template, $plugins; // Common objects
+	global $lang;
+	
+	if ( count($criteria) == 0 )
+	{
+		return $lang->get('log_msg_no_filters');
+	}
+	
+	$html = array();
+	foreach ( $criteria as $criterion )
+	{
+		list($type, $value) = $criterion;
+		switch($type)
+		{
+			case 'user':
+				$rank_info = $session->get_user_rank($value);
+				$user_link = '<a href="' . makeUrlNS('User', $value, false, true) . '" style="' . $rank_info['rank_style'] . '" title="' . htmlspecialchars($lang->get($rank_info['rank_title'])) . '">';
+				$user_link .= htmlspecialchars(str_replace('_', ' ', $value)) . '</a>';
+				
+				$crumb = $lang->get('log_breadcrumb_author', array('user' => $user_link));
+				break;
+			case 'page':
+				list($pid, $ns) = RenderMan::strToPageID($value);
+				$ns = namespace_factory($pid, $ns);
+				$exist = $ns->exists() ? '' : ' class="wikilink-nonexistent"';
+				$crumb = $lang->get('log_breadcrumb_page', array('page' => '<a' . $exist . ' href="' . makeUrl($value, false, true) . '">' . htmlspecialchars($ns->title) . '</a>'));
+				break;
+			case 'action':
+				$action = ( $lang->get("log_formaction_{$value}") === "log_formaction_{$value}" ) ? $lang->get("log_action_{$value}") : $lang->get("log_formaction_{$value}");
+				$crumb = $lang->get('log_breadcrumb_action', array('action' => htmlspecialchars($action)));
+				break;
+			case 'minor':
+				$crumb = $value == '1' ? $lang->get('log_form_filtertype_minor_yes') : $lang->get('log_form_filtertype_minor_no');
+				break;
+			case 'within':
+				$value = intval($value);
+				if ( $value % 31536000 == 0 )
+				{
+					$n = $value / 31536000;
+					$value = "$n " . $lang->get( $n > 1 ? 'etc_unit_years' : 'etc_unit_year' );
+				}
+				else if ( $value % 2592000 == 0 )
+				{
+					$n = $value / 2592000;
+					$value = "$n " . $lang->get( $n > 1 ? 'etc_unit_months' : 'etc_unit_month' );
+				}
+				else if ( $value % 604800 == 0 )
+				{
+					$n = $value / 604800;
+					$value = "$n " . $lang->get( $n > 1 ? 'etc_unit_weeks' : 'etc_unit_week' );
+				}
+				else if ( $value % 86400 == 0 )
+				{
+					$n = $value / 86400;
+					$value = "$n " . $lang->get( $n > 1 ? 'etc_unit_days' : 'etc_unit_day' );
+				}
+				else
+				{
+					$value = "$value " . $lang->get( $value > 1 ? 'etc_unit_seconds' : 'etc_unit_second' );
+				}
+				$crumb = $lang->get('log_breadcrumb_within', array('time' => $value));
+				break;
+		}
+		$html[] = $crumb . ' ' . speciallog_crumb_remove_link($criterion);
+	}
+	return implode(' &raquo; ', $html);
 }
 
 function speciallog_crumb_remove_link($criterion)
 {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $lang;
-  
-  list($type, $value) = $criterion;
-  
-  $params = explode('/', dirtify_page_id($paths->getAllParams()));
-  foreach ( $params as $i => $param )
-  {
-    if ( $param === "$type=$value" )
-    {
-      unset($params[$i]);
-      break;
-    }
-    else if ( $type === 'within' )
-    {
-      list($ptype, $pvalue) = explode('=', $param);
-      if ( $ptype !== 'within' )
-        continue;
-      
-      $lastchar = substr($pvalue, -1);
-      $amt = intval($pvalue);
-      switch($lastchar)
-      {
-        case 'd':
-          $amt = $amt * 86400;
-          break;
-        case 'w':
-          $amt = $amt * 604800;
-          break;
-        case 'm':
-          $amt = $amt * 2592000;
-          break;
-        case 'y':
-          $amt = $amt * 31536000;
-          break;
-      }
-      if ( $amt === $value )
-      {
-        unset($params[$i]);
-        break;
-      }
-    }
-  }
-  if ( count($params) > 0 )
-  {
-    $params = implode('/', $params);
-    $url = makeUrlNS('Special', "Log/$params", false, true);
-  }
-  else
-  {
-    $url = makeUrlNS('Special', "Log", false, true);
-  }
-  
-  return '<sup><a href="' . $url . '">(x)</a></sup>';
+	global $db, $session, $paths, $template, $plugins; // Common objects
+	global $lang;
+	
+	list($type, $value) = $criterion;
+	
+	$params = explode('/', dirtify_page_id($paths->getAllParams()));
+	foreach ( $params as $i => $param )
+	{
+		if ( $param === "$type=$value" )
+		{
+			unset($params[$i]);
+			break;
+		}
+		else if ( $type === 'within' )
+		{
+			list($ptype, $pvalue) = explode('=', $param);
+			if ( $ptype !== 'within' )
+				continue;
+			
+			$lastchar = substr($pvalue, -1);
+			$amt = intval($pvalue);
+			switch($lastchar)
+			{
+				case 'd':
+					$amt = $amt * 86400;
+					break;
+				case 'w':
+					$amt = $amt * 604800;
+					break;
+				case 'm':
+					$amt = $amt * 2592000;
+					break;
+				case 'y':
+					$amt = $amt * 31536000;
+					break;
+			}
+			if ( $amt === $value )
+			{
+				unset($params[$i]);
+				break;
+			}
+		}
+	}
+	if ( count($params) > 0 )
+	{
+		$params = implode('/', $params);
+		$url = makeUrlNS('Special', "Log/$params", false, true);
+	}
+	else
+	{
+		$url = makeUrlNS('Special', "Log", false, true);
+	}
+	
+	return '<sup><a href="' . $url . '">(x)</a></sup>';
 }