Деревья в базах данных => Примеры скриптов => Вывод деревьев => С дозагрузкой
Генерация динамического дерева
popoff
tree_print_dynamic.html
<?php
// tree_print_dynamic - скрипт вывода дерева с динамической дозагрузкой
// (c) 2005 Yuri Popoff, http://popoff.donetsk.ua/
// Специально для PHP Club Cookbook & FAQ
//
// Динамическая загрузка данных реализована с помощью
// Subsys_JsHttpRequest: JavaScript DHTML loader.
// (C) 2005 Dmitry Koterov, http://forum.dklab.ru/users/DmitryKoterov/
if(!empty($_GET['is-inline']))
{
include('JsHttpRequest.php');
$JsHttpRequest =&new Subsys_JsHttpRequest_Php("windows-1251");
}
/////////////////////////////////////
/// Подготовка данных
/// Целиком и полностью зависит от того, каким способом хранения деревьев
/// Вы пользуетесь.
/// Здесь привиден лишь пример, в которм дерево задается прямо в скрипте
/// !!!!!!!!
/// Для работы основной части скрипта - вывода дерева не имеет никакого значения,
/// каким именно способом Вы подготовили данные. Для подготовки данных обычно
/// не требуется загружать все дерево, а нужно загрузить только некоторую
// его часть - ту, которая, собственно, будет показываться.
/// !!!!!!!!
/////////////////////////////////////
// Пример дерева.
//1 root
//2 1
//3 1.1
//4 1.1.1
//5 1.1.2
//6 1.1.3
//7 1.1.3.1
//8 1.2
//9 1.3
//10 1.3.1
//11 1.3.2
//12 1.4
//13 1.4.1
//14 2
//15 3
//16 3.1
$a_tree=array(
array('k_item' =>1,'s_name' =>'root','a_tree' => array(
array('k_item' =>2,'s_name' =>'1','a_tree' => array(
array('k_item' =>3,'s_name' =>'1.1','a_tree' => array(
array('k_item' =>4,'s_name' =>'1.1.1','a_tree' => array()),
array('k_item' =>5,'s_name' =>'1.1.2','a_tree' => array()),
array('k_item' =>6,'s_name' =>'1.1.3','a_tree' => array(
array('k_item' =>7,'s_name' =>'1.1.3.1','a_tree' => array())
)),
)),
array('k_item' =>8,'s_name' =>'1.2','a_tree' => array()),
array('k_item' =>9,'s_name' =>'1.3','a_tree' => array(
array('k_item' =>10,'s_name' =>'1.3.1','a_tree' => array()),
array('k_item' =>11,'s_name' =>'1.3.2','a_tree' => array())
)),
array('k_item' =>12,'s_name' =>'1.4','a_tree' => array(
array('k_item' =>13,'s_name' =>'1.4.1','a_tree' => array())
)),
)),
array('k_item' =>14,'s_name' =>'2','a_tree' => array()),
array('k_item' =>15,'s_name' =>'3','a_tree' => array(
array('k_item' =>16,'s_name' =>'3.1','a_tree' => array())
))
))
);
// возвращает самый верхний уровень (под)дерева $a_tree,
// подготавливает этот уровень к отображению
function tree_level(&$a_tree,$is_top)
{
$a_level=array();
for($i=0;$i<count($a_tree);$i++)
{
if(empty($a_tree[$i]['a_tree']))
{
$s_state='leaf';
$url_open='';
}
else
{
$s_state='close';
$url_open='?k_item='.urlencode($a_tree[$i]['k_item']).'&is-inline=1';
}
$a_level[]=array(
'a_tree' => array(),
'k_item' => $a_tree[$i]['k_item'],
's_name' => $a_tree[$i]['s_name'],
'state' => $s_state,
'url' => '?k_item='.urlencode($a_tree[$i]['k_item']),
'url-open' => $url_open,
'is-top' => $is_top
);
}
return $a_level;
}
//Ищет вершину $k_item и загружает всех ее непосредственных детей в $a_level
// Возвращает истину, если вершина $k_item найдена и ложь, если не найдена
// Если в $want_path передана истина, то $a_level будет содержать в себе не
// только уровень, но и весь путь к этому уровню
function tree_find(&$a_tree,$k_item,$want_path,$is_top=true)
{
if(empty($k_item)||!is_numeric($k_item)) return false;
$k=-1;
for($i=0;$i<count($a_tree);$i++)
{
if($a_tree[$i]['k_item']==$k_item)
{
$a_level=tree_level($a_tree[$i]['a_tree'],false);
$k=$i;
break;
}
$a_level=tree_find($a_tree[$i]['a_tree'],$k_item,$want_path,false);
if($a_level)
{
$k=$i;
break;
}
}
if($k<0) return false;
if(!$want_path) return $a_level;
return array(
array(
'a_tree' => $a_level,
'k_item' => $a_tree[$k]['k_item'],
's_name' => $a_tree[$k]['s_name'],
'state' => 'open',
'url' => '?k_item='.urlencode($a_tree[$k]['k_item']),
'url-open' => '',
'is-top' => $is_top,
'is-bold' => $a_tree[$k]['k_item']==$k_item
));
}
if(!isset($_GET['k_item'])) $_GET['k_item']=$a_tree[0]['k_item'];
$a_level=tree_find($a_tree,$_GET['k_item'],empty($_GET['is-inline']));
if($a_level===false)
{
if(empty($_GET['is-inline']))
header("Location: ?");
else
echo 'Item not found: '.htmlspecialchars($_GET['k_item']);
exit;
}
/////////////////////////////////////
/// Функция, которая по готовому массиву дерева определяет позицию
/// каждого элемента в дереве (первый, последний, нужна ли линия и т.п.)
/// В исходном массиве должен быть установлен элемент массива "is-top",
/// в случае, если соответсвующий элемент дерева является элементом верхнего
/// уровня
/// В результате устанавливаются следующие элементы массива:
/// position - позиция элемента в дереве:
/// single - этот элемент является одновременно и первым и последним
/// first - это самый первый элемент уровня
/// inside - есть элементы до и после этого элемента
/// last - это самый последний элемент уровня
/// want-line - требуется ли линия слева от этого элемента
/// state - состояние элемента дерева.
/// эта функция не устанавливает состояние для элементов, а только
/// проверяет, что бы состояние было одним из допустимых состояний.
/// если установленное в исходном дереве состояние не является допустимым,
/// то оно меняется на состояние по умолчанию:
/// - leaf - у этого элемента дерева нет детей
/// - open - открытый элемент дерева
/// - close - закрытый элемент дерева
/////////////////////////////////////
function tree_position(&$a_tree)
{
for($i=0;$i<count($a_tree);$i++)
{
if(!isset($a_tree[$i])) continue;
if($i)
{
if($i<count($a_tree)-1)
{
$a_tree[$i]['position']='inside';
$a_tree[$i]['want-line']=true;
}
else
$a_tree[$i]['position']='last';
}
else
{
if(count($a_tree)==1)
{
if(!empty($a_tree[$i]['is-top']))
$a_tree[$i]['position']='single';
else
$a_tree[$i]['position']='last';
}
else
{
if(!empty($a_tree[$i]['is-top']))
$a_tree[$i]['position']='first';
else
$a_tree[$i]['position']='inside';
$a_tree[$i]['want-line']=true;
}
}
if(empty($a_tree[$i]['state']))
$a_tree[$i]['state']='';
switch($a_tree[$i]['state'])
{
case 'leaf':
case 'open':
case 'close':
break;
default:
$a_tree[$i]['state']='leaf';
}
if(!empty($a_tree[$i]['a_tree']))
tree_position($a_tree[$i]['a_tree']);
}
}
tree_position($a_level);
/////////////////////////////////////
/// Другие вспомагательные функции
/////////////////////////////////////
function tree_template_load(&$a_level)
{
include('tree_print_dynamic.php');
}
function tree_template_load_html(&$a_level)
{
include('tree_print_dynamic_html.php');
}
/////////////////////////////////////
/// Собственно вывод дерева
/////////////////////////////////////
if(!empty($_GET['is-inline']))
{ //Загружается часть дерева
tree_template_load($a_level);
}
else
{ //Загружается html-страница
tree_template_load_html($a_level);
}
?>
tree_print_dynamic_html.php
<!--
tree_print_dynamic - скрипт вывода дерева с динамической дозагрузкой
(c) 2005 Yuri Popoff, http://popoff.donetsk.ua/
Специально для PHP Club Cookbook & FAQ
---------
В этом файле определяется вид html-страницы, на которой расположено дерево.
-->
<html>
<head>
<script language="JavaScript" src="JsHttpRequest.js"></script>
<script>
function tree_collapse(id)
{
var o_img = document.getElementById(id+'-img');
var o_tr = document.getElementById(id+'-tr');
if(!o_img||!o_tr) return;
o_tr.style.display= 'none';
o_img.src=o_img.src.replace(/-open-/g, "-close-");
}
function tree_expand(id,url)
{
var o_img = document.getElementById(id+'-img');
var o_tr = document.getElementById(id+'-tr');
var o_td = document.getElementById(id+'-td');
if(!o_img||!o_tr||!o_td) return;
if(o_tr.style.display == 'none')
{
o_tr.style.display= '';
o_img.src=o_img.src.replace(/-close-/g, "-open-");
o_td.innerHTML=
'<b style="color:#888888;font-size:8pt;">Loading...</b>';
var req = new Subsys_JsHttpRequest_Js();
req.onreadystatechange = function() {
if (req.readyState == 4) {
o_td.innerHTML=req.responseText;
}
};
req.caching = true;
req.open('GET', url, true);
req.send({});
}
else
{
o_tr.style.display= 'none';
o_img.src=o_img.src.replace(/-open-/g, "-close-");
}
}
</script>
</head>
<body>
<?php tree_template_load($a_level); ?>
</body>
</html>
tree_print_dynamic.php
<!--
tree_print_dynamic - скрипт вывода дерева с динамической дозагрузкой
(c) 2005 Yuri Popoff, http://popoff.donetsk.ua/
Специально для PHP Club Cookbook & FAQ
---------
В этом файле определятся вид одного уровня дерева
-->
<?php if(!count($a_level)) { ?>
No items inside
<?php } else { ?>
<table cellpadding="0" cellspacing="0" width="100%" border="0">
<?php for($i=0;$i<count($a_level);$i++) { ?>
<tr>
<?php if(!empty($a_level[$i]['url-open'])) { ?>
<td
width="16"
valign="top"
onclick="tree_expand('tree-<?= $a_level[$i]['k_item'] ?>',
'<?= $a_level[$i]['url-open'] ?>');"
style="cursor:hand;"><a href="<?= $a_level[$i]['url'] ?>"
onClick="return false;"
><img
id="tree-<?= $a_level[$i]['k_item'] ?>-img"
src="tree-close-<?= $a_level[$i]['position'] ?>.gif"
border="0"
/></a></td
>
<?php } else { ?>
<td width="16" valign="top"><img
id="tree-<?= $a_level[$i]['k_item'] ?>-img"
src="tree-leaf-<?= $a_level[$i]['position'] ?>.gif"
border="0" /></td>
<?php } ?>
<td style="font-size:8pt;">
<?php if(!empty($a_level[$i]['is-bold'])) { ?>
<b style="font-size:8pt;">
<?= $a_level[$i]['s_name'] ?>
</b>
<?php } else { ?>
<a href="<?= $a_level[$i]['url'] ?>" style="font-size:8pt;"><?= $a_level[$i]['s_name'] ?></a>
<?php } ?>
</td>
</tr>
<?php if(!empty($a_level[$i]['want-line'])) { ?>
<tr id="tree-<?= $a_level[$i]['k_item'] ?>-tr" <?php if(empty($a_level[$i]['a_tree'])) { ?>style="display:none;"<?php } ?>>
<td background="tree-line.gif"> </td>
<td id="tree-<?= $a_level[$i]['k_item'] ?>-td">
<?php if(!empty($a_level[$i]['a_tree'])) { ?>
<?php tree_template_load($a_level[$i]['a_tree']); ?>
<?php } else { ?>
<?php } ?>
</td>
</tr>
<?php } else { ?>
<tr id="tree-<?= $a_level[$i]['k_item'] ?>-tr" <?php if(empty($a_level[$i]['a_tree'])) { ?>style="display:none;"<?php } ?>>
<td> </td>
<td id="tree-<?= $a_level[$i]['k_item'] ?>-td">
<?php if(!empty($a_level[$i]['a_tree'])) { ?>
<?php tree_template_load($a_level[$i]['a_tree']); ?>
<?php } else { ?>
<?php } ?>
</td>
</tr>
<?php } ?>
<?php } ?>
</table>
<?php } ?>
Попробовать этот пример:
http://popoff.donetsk.ua/try/tree_dynamic/tree_print_dynamic.html
Закачать все файлы примера в zip-архиве (14 340 байт):
http://download.popoff.donetsk.ua/tree_print_dynamic.zip