You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

422 lines
10 KiB

<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 分类输出
*
* @category typecho
* @package Widget
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id$
*/
/**
* 分类输出组件
*
* @category typecho
* @package Widget
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
*/
class Widget_Metas_Category_List extends Widget_Abstract_Metas
{
/**
* 树状分类结构
*
* @var array
* @access private
*/
private $_treeViewCategories = array();
/**
* _categoryOptions
*
* @var mixed
* @access private
*/
private $_categoryOptions = NULL;
/**
* 顶层分类
*
* @var array
* @access private
*/
private $_top = array();
/**
* 所有分类哈希表
*
* @var array
* @access private
*/
private $_map = array();
/**
* 顺序流
*
* @var array
* @access private
*/
private $_orders = array();
/**
* 所有子节点列表
*
* @var array
* @access private
*/
private $_children = array();
/**
* 所有父节点列表
*
* @var array
* @access private
*/
private $_parents = array();
/**
* 构造函数,初始化组件
*
* @access public
* @param mixed $request request对象
* @param mixed $response response对象
* @param mixed $params 参数列表
*/
public function __construct($request, $response, $params = NULL)
{
parent::__construct($request, $response, $params);
$this->parameter->setDefault('ignore=0&current=');
$select = $this->select()->where('type = ?', 'category');
if ($this->parameter->ignore) {
$select->where('mid <> ?', $this->parameter->ignore);
}
$categories = $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC));
foreach ($categories as $category) {
$category['levels'] = 0;
$this->_map[$category['mid']] = $category;
}
// 读取数据
foreach ($this->_map as $mid => $category) {
$parent = $category['parent'];
if (0 != $parent && isset($this->_map[$parent])) {
$this->_treeViewCategories[$parent][] = $mid;
} else {
$this->_top[] = $mid;
}
}
// 预处理深度
$this->levelWalkCallback($this->_top);
$this->_map = array_map(array($this, 'filter'), $this->_map);
}
/**
* 列出分类回调
*
* @access private
*/
private function treeViewCategoriesCallback()
{
$categoryOptions = $this->_categoryOptions;
if (function_exists('treeViewCategories')) {
return treeViewCategories($this, $categoryOptions);
}
$classes = array();
if ($categoryOptions->itemClass) {
$classes[] = $categoryOptions->itemClass;
}
$classes[] = 'category-level-' . $this->levels;
echo '<' . $categoryOptions->itemTag . ' class="'
. implode(' ', $classes);
if ($this->levels > 0) {
echo ' category-child';
$this->levelsAlt(' category-level-odd', ' category-level-even');
} else {
echo ' category-parent';
}
if ($this->mid == $this->parameter->current) {
echo ' category-active';
} else if (isset($this->_children[$this->mid]) && in_array($this->parameter->current, $this->_children[$this->mid])) {
echo ' category-parent-active';
}
echo '"><a href="' . $this->permalink . '">' . $this->name . '</a>';
if ($categoryOptions->showCount) {
printf($categoryOptions->countTemplate, intval($this->count));
}
if ($categoryOptions->showFeed) {
printf($categoryOptions->feedTemplate, $this->feedUrl);
}
if ($this->children) {
$this->treeViewCategories();
}
echo '</' . $categoryOptions->itemTag . '>';
}
/**
* 预处理分类迭代
*
* @param array $categories
* @param array $parents
* @access private
*/
private function levelWalkCallback(array $categories, $parents = array())
{
foreach ($parents as $parent) {
if (!isset($this->_children[$parent])) {
$this->_children[$parent] = array();
}
$this->_children[$parent] = array_merge($this->_children[$parent], $categories);
}
foreach ($categories as $mid) {
$this->_orders[] = $mid;
$parent = $this->_map[$mid]['parent'];
if (0 != $parent && isset($this->_map[$parent])) {
$levels = $this->_map[$parent]['levels'] + 1;
$this->_map[$mid]['levels'] = $levels;
}
$this->_parents[$mid] = $parents;
if (!empty($this->_treeViewCategories[$mid])) {
$new = $parents;
$new[] = $mid;
$this->levelWalkCallback($this->_treeViewCategories[$mid], $new);
}
}
}
/**
* 子评论
*
* @access protected
* @return array
*/
protected function ___children()
{
return isset($this->_treeViewCategories[$this->mid]) ?
$this->getCategories($this->_treeViewCategories[$this->mid]) : array();
}
/**
* 执行函数
*
* @access public
* @return void
*/
public function execute()
{
$this->stack = $this->getCategories($this->_orders);
}
/**
* treeViewCategories
*
* @access public
* @return void
*/
public function treeViewCategories()
{
$children = $this->children;
if ($children) {
//缓存变量便于还原
$tmp = $this->row;
$this->sequence ++;
//在子评论之前输出
echo '<' . $this->_categoryOptions->wrapTag . (empty($this->_categoryOptions->wrapClass)
? '' : ' class="' . $this->_categoryOptions->wrapClass . '"') . '>';
foreach ($children as $child) {
$this->row = $child;
$this->treeViewCategoriesCallback();
$this->row = $tmp;
}
//在子评论之后输出
echo '</' . $this->_categoryOptions->wrapTag . '>';
$this->sequence --;
}
}
/**
* treeViewCategories
*
* @param $categoryOptions 输出选项
* @access public
* @return void
*/
public function listCategories($categoryOptions = NULL)
{
//初始化一些变量
$this->_categoryOptions = Typecho_Config::factory($categoryOptions);
$this->_categoryOptions->setDefault(array(
'wrapTag' => 'ul',
'wrapClass' => '',
'itemTag' => 'li',
'itemClass' => '',
'showCount' => false,
'showFeed' => false,
'countTemplate' => '(%d)',
'feedTemplate' => '<a href="%s">RSS</a>'
));
// 插件插件接口
$this->pluginHandle()->trigger($plugged)->listCategories($this->_categoryOptions, $this);
if (!$plugged) {
$this->stack = $this->getCategories($this->_top);
if ($this->have()) {
echo '<' . $this->_categoryOptions->wrapTag . (empty($this->_categoryOptions->wrapClass)
? '' : ' class="' . $this->_categoryOptions->wrapClass . '"') . '>';
while ($this->next()) {
$this->treeViewCategoriesCallback();
}
echo '</' . $this->_categoryOptions->wrapTag . '>';
}
$this->stack = $this->_map;
}
}
/**
* 根据深度余数输出
*
* @access public
* @return void
*/
public function levelsAlt()
{
$args = func_get_args();
$num = func_num_args();
$split = $this->levels % $num;
echo $args[(0 == $split ? $num : $split) -1];
}
/**
* 将每行的值压入堆栈
*
* @access public
* @param array $value 每行的值
* @return array
*/
public function filter(array $value)
{
$value['directory'] = $this->getAllParentsSlug($value['mid']);
$value['directory'][] = $value['slug'];
$tmpCategoryTree = $value['directory'];
$value['directory'] = implode('/', array_map('urlencode', $value['directory']));
$value = parent::filter($value);
$value['directory'] = $tmpCategoryTree;
return $value;
}
/**
* 获取某个分类下的所有子节点
*
* @param mixed $mid
* @access public
* @return array
*/
public function getAllChildren($mid)
{
return isset($this->_children[$mid]) ? $this->_children[$mid] : array();
}
/**
* 获取某个分类所有父级节点
*
* @param mixed $mid
* @access public
* @return array
*/
public function getAllParents($mid)
{
$parents = array();
if (isset($this->_parents[$mid])) {
foreach ($this->_parents[$mid] as $parent) {
$parents[] = $this->_map[$parent];
}
}
return $parents;
}
/**
* 获取某个分类所有父级节点缩略名
*
* @param mixed $mid
* @access public
* @return array
*/
public function getAllParentsSlug($mid)
{
$parents = array();
if (isset($this->_parents[$mid])) {
foreach ($this->_parents[$mid] as $parent) {
$parents[] = $this->_map[$parent]['slug'];
}
}
return $parents;
}
/**
* 获取单个分类
*
* @param integer $mid
* @access public
* @return mixed
*/
public function getCategory($mid)
{
return isset($this->_map[$mid]) ? $this->_map[$mid] : NULL;
}
/**
* 获取多个分类
*
* @param mixed $mids
* @access public
* @return array
*/
public function getCategories($mids)
{
$result = array();
if (!empty($mids)) {
foreach ($mids as $mid) {
$result[] = $this->_map[$mid];
}
}
return $result;
}
}