Creating an Explorer-like Navigation
I´ve written a helper to administrate documents in an explorer-like tree.
It doesn´t matter how many folders you have or how deep is the tree.
It doesn´t matter how many folders you have or how deep is the tree.
For a project in my curriculum I wrote a tree, where you can adminster documents.
Sorry, I´m not good in writing so I only post my code without any more words:
Download code
P.S.: It would be great if anyone would expand the example with some ajax (releoad in a period like 10sek but remain the preferences which folder is open/closed) and javascript(open/close folder). Please post the code. Thanks
_____________________________________________________________________________________________________
Update on: 18. Januar 21:35
Now I´ve rewritten my code and expanded it to work with some Javascript to toggle the Folder (open/close) and additionally remain the settings after a refresh of the page.
Heres the full code:
document.php
Download code
documents_controller.php
Download code
types_controller.php: not needed
index.ctp (/app/views/documents/)
Download code
helper: explorer_tree.php
Download code
explorer_tree.css (app/webroot/css/)
Download code
explorer_tree.js (/app/webroot/js/)
Download code
As you can see in the view, you additionally need jquery.
Sorry, I´m not good in writing so I only post my code without any more words:
Download code
<?php
/*
* 2 Tabellen müssen existieren:
*
* create table types (
* id int(4) auto_increment,
* typ varchar(128) not null,
* parent int(4) null,
* primary key(id)
* );
*
* create table documents (
* id int(8) auto_increment,
* type_id int(4) not null,
* name varchar(128) not null,
* primary key(id)
* );
*
*
* 2 Models:
*
* class Type extends AppModel {
* var $hasMany = array('Document');
* }
*
* class Document extends AppModel {
* var $belongsTo = array('Type');
* }
*
*
* 1 Controller:
*
* class DocumentsController extends AppController {
* var $helpers = array('explorerTree', 'javascript');
*
* function index() {
* $this->set('types', $this->Document->Type->find('all'));
* }
* }
*
*
* 1 View:
*
* Muss mind. das Javascript laden ($javascript->link('explorer_tree', false);)
* und natürlich die Methoden des Helpers aufrufen
* ($newArray = $explorerTree->init($types);echo $explorerTree->createTree($newArray);
*/
class explorerTreeHelper extends AppHelper {
/*
* Initialisiert das Array
*/
function init($types) {
return $this->__createArray($types);
}
function __createArray($types) {
$newArray;
foreach ($types as $type) {
// Dokumenten-Array leeren
foreach ($type['Document'] as $document) {
array_splice($document, 0, 2);
}
// Werte auslesen und speichern
$id = $type['Type']['id'];
$name = $type['Type']['typ'];
$parent = $type['Type']['parent'];
$docs = $type['Document'];
// Types-Array leeren
array_splice($type, 0);
// Array neu formatieren
$newArray[] = $this->__reArrangeArray($id, $name, $parent, $docs);
}
foreach ($newArray as $array) {
if ($array['parent'] != null) {
$newArray = $this->__connect($newArray);
}
}
return $newArray;
}
// function __reArrangeArray
// $id (int) ID des Types
// $name (String) Name des Types
// $parent (int) Vorfahre des Types
// $docs (Array) Dokumenten des Typess
function __reArrangeArray($id, $name, $parent, $docs) {
$tmpArray['id'] = $id;
$tmpArray['name'] = $name;
$tmpArray['parent'] = $parent;
$tmpArray['docs'] = $docs;
$tmpArray['descendants'] = array();
return $tmpArray;
}
// function __connect
// $newArray Neuformatiertes Array
function __connect($newArray) {
// Index zum Element mit der höchsten ParentId ermitteln
$indexArr = $this->__getMaxParentIndex($newArray);
$indexArr = explode(':' , $indexArr);
$index = $indexArr[0];
$maxId = $indexArr[1];
$hookHere;
foreach($newArray as $key => $value) {
if ($value['id'] == $maxId) {
$hookHere = $key;
break;
}
}
$newArray[$hookHere]['descendants'][] = $newArray[$index];
array_splice($newArray, $index, 1);
return $newArray;
}
// function __getMaxParentId
// $newArray (Array) neu formatiertes Array
function __getMaxParentIndex($newArray) {
$maxParent = 0;
$index;
for ($i = 0; $i < count($newArray); $i++) {
if ($newArray[$i]['parent'] >= $maxParent) {
$maxParent = $newArray[$i]['parent'];
$index = $i;
}
}
//$index (int) Index zum Element mit der höchsten ParentId
//$maxParent (int) Enthält den höchsten ParentIndex
return $index . ':' . $maxParent;
}
/*
* Ende der Initialisierung des Arrays
*/
/*
* Erstellung des Baumes
*/
var $helpers = array('html');
var $tree;
function createTree($newArray) {
$this->tree = $this->html->tag('div', null, array('id' => 'tree'));
$this->__getFolder($newArray);
$this->tree .= $this->html->tag('/div');
return $this->tree;
}
// function __getFolder
// $position Enthät die aktuelle Position im Array
function __getFolder($position) {
$this->tree .= $this->html->tag('ul', null, array('id' => 'folder'));
foreach ($position as $element) {
$this->tree .= $this->html->tag('li', null, array('onclick' => 'javascript:toggle();'));
$this->tree .= $this->html->image('opened.gif');
$this->tree .= $element['name'];
$this->tree .= $this->html->tag('/li');
$this->__getDocuments($element['docs']);
if ($element['descendants']) {
$this->__getFolder($element['descendants']);
}
}
$this->tree .= $this->html->tag('/ul');
}
// function __getDocuments
// $position Enthält die aktuelle Position im Array
function __getDocuments($position) {
$this->tree .= $this->html->tag('ul', null, array('id' => 'document'));
foreach ($position as $doc) {
$this->tree .= $this->html->tag('li');
$this->tree .= $this->html->image('doc.gif');
$this->tree .= $this->html->link($doc['name'], '');
$this->tree .= $this->html->tag('/li');
}
$this->tree .= $this->html->tag('/ul');
}
/*
* Ende Erstellung des Baumes
*/
}
?>
P.S.: It would be great if anyone would expand the example with some ajax (releoad in a period like 10sek but remain the preferences which folder is open/closed) and javascript(open/close folder). Please post the code. Thanks
_____________________________________________________________________________________________________
Update on: 18. Januar 21:35
Now I´ve rewritten my code and expanded it to work with some Javascript to toggle the Folder (open/close) and additionally remain the settings after a refresh of the page.
Heres the full code:
document.php
Download code
<?php
class Document extends AppModel {
var $belongsTo = array('Type');
}
?>
type.php
<?php
class Type extends AppModel {
var $hasMany = array('Document');
}
?>
documents_controller.php
Download code
<?php
class DocumentsController extends AppController {
var $helpers = array('explorerTree', 'javascript');
function index() {
$this->set('documents', $this->Document->find('all'));
$this->set('types', $this->Document->Type->find('all'));
}
}
?>
types_controller.php: not needed
index.ctp (/app/views/documents/)
Download code
<?php
echo $javascript->link('jquery/jquery-1.2.6', false);
echo $javascript->link('explorer_tree', false);
echo $html->css('explorer_tree');
$newArray = $explorerTree->init($types);
echo $explorerTree->createTree($newArray);
?>
helper: explorer_tree.php
Download code
<?php
/*
* 2 Tabellen müssen existieren:
*
* create table types (
* id int(4) auto_increment,
* typ varchar(128) not null,
* parent int(4) null,
* primary key(id)
* );
*
* create table documents (
* id int(8) auto_increment,
* type_id int(4) not null,
* name varchar(128) not null,
* primary key(id)
* );
*
*
* 2 Models:
*
* class Type extends AppModel {
* var $hasMany = array('Document');
* }
*
* class Document extends AppModel {
* var $belongsTo = array('Type');
* }
*
*
* 1 Controller:
*
* class DocumentsController extends AppController {
* var $helpers = array('explorerTree', 'javascript');
*
* function index() {
* $this->set('types', $this->Document->Type->find('all'));
* }
* }
*
*
* 1 View:
*
* Muss mind. das Javascript laden ($javascript->link('explorer_tree', false);)
* und natürlich die Methoden des Helpers aufrufen
* ($newArray = $explorerTree->init($types);echo $explorerTree->createTree($newArray);
*/
class explorerTreeHelper extends AppHelper {
/*
* Initialisiert das Array
*/
function init($types) {
return $this->__createArray($types);
}
function __createArray($types) {
$newArray;
foreach ($types as $type) {
// Dokumenten-Array leeren
foreach ($type['Document'] as $document) {
array_splice($document, 0, 2);
}
// Werte auslesen und speichern
$id = $type['Type']['id'];
$name = $type['Type']['typ'];
$parent = $type['Type']['parent'];
$docs = $type['Document'];
// Types-Array leeren
array_splice($type, 0);
// Array neu formatieren
$newArray[] = $this->__reArrangeArray($id, $name, $parent, $docs);
}
foreach ($newArray as $array) {
if ($array['parent'] != null) {
$newArray = $this->__connect($newArray);
}
}
return $newArray;
}
// function __reArrangeArray
// $id (int) ID des Types
// $name (String) Name des Types
// $parent (int) Vorfahre des Types
// $docs (Array) Dokumenten des Typess
function __reArrangeArray($id, $name, $parent, $docs) {
$tmpArray['id'] = $id;
$tmpArray['name'] = $name;
$tmpArray['parent'] = $parent;
$tmpArray['docs'] = $docs;
$tmpArray['descendants'] = array();
return $tmpArray;
}
// function __connect
// $newArray Neuformatiertes Array
function __connect($newArray) {
// Index zum Element mit der höchsten ParentId ermitteln
$indexArr = $this->__getMaxParentIndex($newArray);
$indexArr = explode(':' , $indexArr);
$index = $indexArr[0];
$maxId = $indexArr[1];
$hookHere;
foreach($newArray as $key => $value) {
if ($value['id'] == $maxId) {
$hookHere = $key;
break;
}
}
$newArray[$hookHere]['descendants'][] = $newArray[$index];
array_splice($newArray, $index, 1);
return $newArray;
}
// function __getMaxParentId
// $newArray (Array) neu formatiertes Array
function __getMaxParentIndex($newArray) {
$maxParent = 0;
$index;
for ($i = 0; $i < count($newArray); $i++) {
if ($newArray[$i]['parent'] >= $maxParent) {
$maxParent = $newArray[$i]['parent'];
$index = $i;
}
}
//$index (int) Index zum Element mit der höchsten ParentId
//$maxParent (int) Enthält den höchsten ParentIndex
return $index . ':' . $maxParent;
}
/*
* Ende der Initialisierung des Arrays
*/
/*
* Erstellung des Baumes
*/
var $helpers = array('html');
var $tree;
function createTree($newArray) {
$this->tree = $this->html->tag('div', null, array('id' => 'tree'));
$this->__getFolder($newArray, null, null);
$this->tree .= $this->html->tag('/div');
return $this->tree;
}
// function __getFolder
// $position (Array) Enthät die aktuelle Position im Array
// $parent (int) Id des Elternelements
// $id (int) Eigene Id
function __getFolder($position, $parent, $id) {
if ($id == null) {
$this->tree .= $this->html->tag('ul', null, array('id' => $id));
}
foreach ($position as $element) {
$this->tree .= $this->html->tag('li', null, array(
'onclick' => 'javascript:toggle(' . $element['id'] . ');',
'class' => 'folder'
));
$this->tree .= $this->html->image('opened.gif', array(
'alt' => $element['name'],
'id' => 'img' . $element['id']
));
$this->tree .= $element['name'];
$this->tree .= $this->html->tag('/li');
$this->__getDocuments($element['docs'], $element['id']);
if ($element['descendants']) {
$parent .= $element['id'] . ';';
$this->__getFolder($element['descendants'], $parent, $element['id']);
$this->tree .= $this->html->tag('/ul');
} else {
$this->tree .= $this->html->tag('/ul');
}
}
if ($id == null) {
$this->tree .= $this->html->tag('/ul');
}
}
// function __getDocuments
// $position (Array) Enthält die aktuelle Position im Array
function __getDocuments($position, $id) {
$this->tree .= $this->html->tag('ul', null, array('id' => $id));
foreach ($position as $doc) {
$this->tree .= $this->html->tag('li');
$this->tree .= $this->html->image('doc.gif');
$this->tree .= $this->html->link($doc['name'], '');
$this->tree .= $this->html->tag('/li');
}
//$this->tree .= $this->html->tag('/ul');
}
/*
* Ende Erstellung des Baumes
*/
}
?>
explorer_tree.css (app/webroot/css/)
Download code
ul, li {
list-style-type: none;
}
li.folder {
cursor: pointer;
}
a {
cursor: default;
}
explorer_tree.js (/app/webroot/js/)
Download code
$(document).ready(function() {
$("ul").css({display: "block"});
loadSettings();
});
function toggle(id) {
ul = $("ul#" + id);
img = $("img#img" + id);
if (ul.css("display") == "block") {
ul.css({display: "none"});
img.attr("src", "/cake/img/closed.gif");
} else {
ul.css({display: "block"});
img.attr("src", "/cake/img/opened.gif");
}
event.cancelBubble = true;
/* Speichern der Einstellungen */
save = window.name;
save += ul.attr("id") + "=" + ul.css("display") + ":";
window.name = save;
}
function loadSettings() {
var settings = window.name.split(":");
var setting;
var id;
var css;
var ul;
var img;
if (window.name != "") {
for (i = 0; i < settings.length - 1; i++) {
setting = settings.split("=");
id = setting[0];
css = setting[1];
ul = $("ul#" + id);
img = $("img#img" + id);
ul.css({display: css});
if (ul.css("display") == "block") {
img.attr("src", "/cake/img/opened.gif");
} else {
img.attr("src", "/cake/img/closed.gif");
}
}
}
}
As you can see in the view, you additionally need jquery.
Comments
Comment
1 Code download
The types table actually refers to folders/directories (not file types).
Question
2 display none of default
davide
Comment
3 Nice Post.
Hence the $this->redirect in the code, Lez Sohbet and the return statement Bayan Chat (that you left out in your Bayan Sohbet copy-paste, Almanya Chat but it's in the original ;-) Arkadaş Sohbet This will make sure the view will Porno Sohbet not be rendered, Diyarbakır Sohbet and you will be redirected. Lez That's why you don't need to "prepare" Mirc indir the view by setting variables for it.