프리샵 추가

This commit is contained in:
gnuboard
2013-01-25 11:48:46 +09:00
parent 52da376f32
commit 26088ece3b
583 changed files with 44699 additions and 0 deletions

View File

@ -0,0 +1,20 @@
CREATE TABLE IF NOT EXISTS `tree` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` bigint(20) unsigned NOT NULL,
`position` bigint(20) unsigned NOT NULL,
`left` bigint(20) unsigned NOT NULL,
`right` bigint(20) unsigned NOT NULL,
`level` bigint(20) unsigned NOT NULL,
`title` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=13 ;
INSERT INTO `tree` (`id`, `parent_id`, `position`, `left`, `right`, `level`, `title`, `type`) VALUES
(1, 0, 2, 1, 14, 0, 'ROOT', ''),
(2, 1, 0, 2, 11, 1, 'C:', 'drive'),
(3, 2, 0, 3, 6, 2, '_demo', 'folder'),
(4, 3, 0, 4, 5, 3, 'index.html', 'default'),
(5, 2, 1, 7, 10, 2, '_docs', 'folder'),
(6, 1, 1, 12, 13, 1, 'D:', 'drive'),
(12, 5, 0, 8, 9, 3, 'zmei.html', 'default');

View File

@ -0,0 +1,146 @@
<?php
class _database {
private $link = false;
private $result = false;
private $row = false;
public $settings = array(
"servername"=> "localhost",
"serverport"=> "3306",
"username" => false,
"password" => false,
"database" => false,
"persist" => false,
"dieonerror"=> false,
"showerror" => false,
"error_file"=> true
);
function __construct() {
global $db_config;
$this->settings = array_merge($this->settings, $db_config);
if($this->settings["error_file"] === true) $this->settings["error_file"] = dirname(__FILE__)."/__mysql_errors.log";
}
function connect() {
if (!$this->link) {
$this->link = ($this->settings["persist"]) ?
mysql_pconnect(
$this->settings["servername"].":".$this->settings["serverport"],
$this->settings["username"],
$this->settings["password"]
) :
mysql_connect(
$this->settings["servername"].":".$this->settings["serverport"],
$this->settings["username"],
$this->settings["password"]
) or $this->error();
}
if (!mysql_select_db($this->settings["database"], $this->link)) $this->error();
if($this->link) mysql_query("SET NAMES 'utf8'");
return ($this->link) ? true : false;
}
function query($sql) {
if (!$this->link && !$this->connect()) $this->error();
if (!($this->result = mysql_query($sql, $this->link))) $this->error($sql);
return ($this->result) ? true : false;
}
function nextr() {
if(!$this->result) {
$this->error("No query pending");
return false;
}
unset($this->row);
$this->row = mysql_fetch_array($this->result, MYSQL_BOTH);
return ($this->row) ? true : false ;
}
function get_row($mode = "both") {
if(!$this->row) return false;
$return = array();
switch($mode) {
case "assoc":
foreach($this->row as $k => $v) {
if(!is_int($k)) $return[$k] = $v;
}
break;
case "num":
foreach($this->row as $k => $v) {
if(is_int($k)) $return[$k] = $v;
}
break;
default:
$return = $this->row;
break;
}
return array_map("stripslashes",$return);
}
function get_all($mode = "both", $key = false) {
if(!$this->result) {
$this->error("No query pending");
return false;
}
$return = array();
while($this->nextr()) {
if($key !== false) $return[$this->f($key)] = $this->get_row($mode);
else $return[] = $this->get_row($mode);
}
return $return;
}
function f($index) {
return stripslashes($this->row[$index]);
}
function go_to($row) {
if(!$this->result) {
$this->error("No query pending");
return false;
}
if(!mysql_data_seek($this->result, $row)) $this->error();
}
function nf() {
if ($numb = mysql_num_rows($this->result) === false) $this->error();
return mysql_num_rows($this->result);
}
function af() {
return mysql_affected_rows();
}
function error($string="") {
$error = mysql_error();
if($this->settings["show_error"]) echo $error;
if($this->settings["error_file"] !== false) {
$handle = @fopen($this->settings["error_file"], "a+");
if($handle) {
@fwrite($handle, "[".date("Y-m-d H:i:s")."] ".$string." <".$error.">\n");
@fclose($handle);
}
}
if($this->settings["dieonerror"]) {
if(isset($this->result)) mysql_free_result($this->result);
mysql_close($this->link);
die();
}
}
function insert_id() {
if(!$this->link) return false;
return mysql_insert_id();
}
function escape($string){
if(!$this->link) return addslashes($string);
return mysql_real_escape_string($string);
}
function destroy(){
if (isset($this->result)) mysql_free_result($this->result);
if (isset($this->link)) mysql_close($this->link);
}
}
?>

View File

@ -0,0 +1,152 @@
<?php
class _database {
private $data = false;
private $result = false;
private $row = false;
public $settings = array(
"servername"=> "localhost",
"serverport"=> "3306",
"username" => false,
"password" => false,
"database" => false,
"persist" => false,
"dieonerror"=> false,
"showerror" => false,
"error_file"=> true
);
function __construct() {
global $db_config;
$this->settings = array_merge($this->settings, $db_config);
if($this->settings["error_file"] === true) $this->settings["error_file"] = dirname(__FILE__)."/__mysql_errors.log";
}
function connect() {
$this->data = new mysqli(
$this->settings["servername"],
$this->settings["username"],
$this->settings["password"],
$this->settings["database"],
$this->settings["serverport"]
);
if(mysqli_connect_errno()) {
$this->error("Connection error: ".mysqli_connect_error() );
return false;
}
if(!$this->data->set_charset("utf8")) {
$this->error("Error loading character set utf8");
return false;
}
return true;
}
function query($sql) {
if(!$this->data && !$this->connect()) {
$this->error("Could node connect for query: ".$sql);
return false;
}
//echo $sql."<br />:";
if(!($this->result = $this->data->query($sql))) $this->error($sql);
return ($this->result) ? true : false;
}
function nextr(){
if(!$this->result) {
$this->error("No query pending");
return false;
}
unset($this->row);
$this->row = $this->result->fetch_array(MYSQL_BOTH);
return ($this->row) ? true : false ;
}
function get_row($mode = "both") {
if(!$this->row) return false;
$return = array();
switch($mode) {
case "assoc":
foreach($this->row as $k => $v) {
if(!is_int($k)) $return[$k] = $v;
}
break;
case "num":
foreach($this->row as $k => $v) {
if(is_int($k)) $return[$k] = $v;
}
break;
default:
$return = $this->row;
break;
}
return array_map("stripslashes",$return);
}
function get_all($mode = "both", $key = false) {
if(!$this->result) {
$this->error("No query pending");
return false;
}
$return = array();
while($this->nextr()) {
if($key !== false) $return[$this->f($key)] = $this->get_row($mode);
else $return[] = $this->get_row($mode);
}
return $return;
}
function f($index) {
return stripslashes($this->row[$index]);
}
function go_to($row) {
if(!$this->result) {
$this->error("No query pending");
return false;
}
if(!$this->data->data_seek($row)) $this->error();
}
function nf() {
if (!$this->result) {
$this->error("nf: no result set");
return false;
}
return $this->result->num_rows;
}
function af() {
return $this->data->affected_rows;
}
function error($string = "") {
$error = $this->data->error;
if($this->settings["show_error"]) echo $error;
if($this->settings["error_file"] !== false) {
$handle = @fopen($this->settings["error_file"], "a+");
if($handle) {
@fwrite($handle, "[".date("Y-m-d H:i:s")."] ".$string." <".$error.">\n");
@fclose($handle);
}
}
if($this->settings["dieonerror"]) {
if(isset($this->result)) $this->result->free();
@$this->data->close();
die();
}
}
function insert_id() {
return $this->data->insert_id;
}
function escape($string) {
if(!$this->data) return addslashes($string);
return $this->data->escape_string($string);
}
function destroy() {
if(isset($this->result)) $this->result->free();
if($this->data) $this->data->close();
}
}

View File

@ -0,0 +1,602 @@
<?php
class _tree_struct {
// Structure table and fields
protected $table = "";
protected $fields = array(
"id" => false,
"parent_id" => false,
"position" => false,
"left" => false,
"right" => false,
"level" => false
);
// Constructor
function __construct($table = "tree", $fields = array()) {
$this->table = $table;
if(!count($fields)) {
foreach($this->fields as $k => &$v) { $v = $k; }
}
else {
foreach($fields as $key => $field) {
switch($key) {
case "id":
case "parent_id":
case "position":
case "left":
case "right":
case "level":
$this->fields[$key] = $field;
break;
}
}
}
// Database
$this->db = new _database;
}
function _get_node($id) {
$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["id"]."` = ".(int) $id);
$this->db->nextr();
return $this->db->nf() === 0 ? false : $this->db->get_row("assoc");
}
function _get_children($id, $recursive = false) {
$children = array();
if($recursive) {
$node = $this->_get_node($id);
$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["left"]."` >= ".(int) $node[$this->fields["left"]]." AND `".$this->fields["right"]."` <= ".(int) $node[$this->fields["right"]]." ORDER BY `".$this->fields["left"]."` ASC");
}
else {
$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["parent_id"]."` = ".(int) $id." ORDER BY `".$this->fields["position"]."` ASC");
}
while($this->db->nextr()) $children[$this->db->f($this->fields["id"])] = $this->db->get_row("assoc");
return $children;
}
function _get_path($id) {
$node = $this->_get_node($id);
$path = array();
if(!$node === false) return false;
$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["left"]."` <= ".(int) $node[$this->fields["left"]]." AND `".$this->fields["right"]."` >= ".(int) $node[$this->fields["right"]]);
while($this->db->nextr()) $path[$this->db->f($this->fields["id"])] = $this->db->get_row("assoc");
return $path;
}
function _create($parent, $position) {
return $this->_move(0, $parent, $position);
}
function _remove($id) {
if((int)$id === 1) { return false; }
$data = $this->_get_node($id);
$lft = (int)$data[$this->fields["left"]];
$rgt = (int)$data[$this->fields["right"]];
$dif = $rgt - $lft + 1;
// deleting node and its children
$this->db->query("" .
"DELETE FROM `".$this->table."` " .
"WHERE `".$this->fields["left"]."` >= ".$lft." AND `".$this->fields["right"]."` <= ".$rgt
);
// shift left indexes of nodes right of the node
$this->db->query("".
"UPDATE `".$this->table."` " .
"SET `".$this->fields["left"]."` = `".$this->fields["left"]."` - ".$dif." " .
"WHERE `".$this->fields["left"]."` > ".$rgt
);
// shift right indexes of nodes right of the node and the node's parents
$this->db->query("" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["right"]."` = `".$this->fields["right"]."` - ".$dif." " .
"WHERE `".$this->fields["right"]."` > ".$lft
);
$pid = (int)$data[$this->fields["parent_id"]];
$pos = (int)$data[$this->fields["position"]];
// Update position of siblings below the deleted node
$this->db->query("" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["position"]."` = `".$this->fields["position"]."` - 1 " .
"WHERE `".$this->fields["parent_id"]."` = ".$pid." AND `".$this->fields["position"]."` > ".$pos
);
return true;
}
function _move($id, $ref_id, $position = 0, $is_copy = false) {
if((int)$ref_id === 0 || (int)$id === 1) { return false; }
$sql = array(); // Queries executed at the end
$node = $this->_get_node($id); // Node data
$nchildren = $this->_get_children($id); // Node children
$ref_node = $this->_get_node($ref_id); // Ref node data
$rchildren = $this->_get_children($ref_id);// Ref node children
$ndif = 2;
$node_ids = array(-1);
if($node !== false) {
$node_ids = array_keys($this->_get_children($id, true));
// TODO: should be !$is_copy && , but if copied to self - screws some right indexes
if(in_array($ref_id, $node_ids)) return false;
$ndif = $node[$this->fields["right"]] - $node[$this->fields["left"]] + 1;
}
if($position >= count($rchildren)) {
$position = count($rchildren);
}
// Not creating or copying - old parent is cleaned
if($node !== false && $is_copy == false) {
$sql[] = "" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["position"]."` = `".$this->fields["position"]."` - 1 " .
"WHERE " .
"`".$this->fields["parent_id"]."` = ".$node[$this->fields["parent_id"]]." AND " .
"`".$this->fields["position"]."` > ".$node[$this->fields["position"]];
$sql[] = "" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["left"]."` = `".$this->fields["left"]."` - ".$ndif." " .
"WHERE `".$this->fields["left"]."` > ".$node[$this->fields["right"]];
$sql[] = "" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["right"]."` = `".$this->fields["right"]."` - ".$ndif." " .
"WHERE " .
"`".$this->fields["right"]."` > ".$node[$this->fields["left"]]." AND " .
"`".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ";
}
// Preparing new parent
$sql[] = "" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["position"]."` = `".$this->fields["position"]."` + 1 " .
"WHERE " .
"`".$this->fields["parent_id"]."` = ".$ref_id." AND " .
"`".$this->fields["position"]."` >= ".$position." " .
( $is_copy ? "" : " AND `".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ");
$ref_ind = $ref_id === 0 ? (int)$rchildren[count($rchildren) - 1][$this->fields["right"]] + 1 : (int)$ref_node[$this->fields["right"]];
$ref_ind = max($ref_ind, 1);
$self = ($node !== false && !$is_copy && (int)$node[$this->fields["parent_id"]] == $ref_id && $position > $node[$this->fields["position"]]) ? 1 : 0;
foreach($rchildren as $k => $v) {
if($v[$this->fields["position"]] - $self == $position) {
$ref_ind = (int)$v[$this->fields["left"]];
break;
}
}
if($node !== false && !$is_copy && $node[$this->fields["left"]] < $ref_ind) {
$ref_ind -= $ndif;
}
$sql[] = "" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["left"]."` = `".$this->fields["left"]."` + ".$ndif." " .
"WHERE " .
"`".$this->fields["left"]."` >= ".$ref_ind." " .
( $is_copy ? "" : " AND `".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ");
$sql[] = "" .
"UPDATE `".$this->table."` " .
"SET `".$this->fields["right"]."` = `".$this->fields["right"]."` + ".$ndif." " .
"WHERE " .
"`".$this->fields["right"]."` >= ".$ref_ind." " .
( $is_copy ? "" : " AND `".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ");
$ldif = $ref_id == 0 ? 0 : $ref_node[$this->fields["level"]] + 1;
$idif = $ref_ind;
if($node !== false) {
$ldif = $node[$this->fields["level"]] - ($ref_node[$this->fields["level"]] + 1);
$idif = $node[$this->fields["left"]] - $ref_ind;
if($is_copy) {
$sql[] = "" .
"INSERT INTO `".$this->table."` (" .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."`, " .
"`".$this->fields["left"]."`, " .
"`".$this->fields["right"]."`, " .
"`".$this->fields["level"]."`" .
") " .
"SELECT " .
"".$ref_id.", " .
"`".$this->fields["position"]."`, " .
"`".$this->fields["left"]."` - (".($idif + ($node[$this->fields["left"]] >= $ref_ind ? $ndif : 0))."), " .
"`".$this->fields["right"]."` - (".($idif + ($node[$this->fields["left"]] >= $ref_ind ? $ndif : 0))."), " .
"`".$this->fields["level"]."` - (".$ldif.") " .
"FROM `".$this->table."` " .
"WHERE " .
"`".$this->fields["id"]."` IN (".implode(",", $node_ids).") " .
"ORDER BY `".$this->fields["level"]."` ASC";
}
else {
$sql[] = "" .
"UPDATE `".$this->table."` SET " .
"`".$this->fields["parent_id"]."` = ".$ref_id.", " .
"`".$this->fields["position"]."` = ".$position." " .
"WHERE " .
"`".$this->fields["id"]."` = ".$id;
$sql[] = "" .
"UPDATE `".$this->table."` SET " .
"`".$this->fields["left"]."` = `".$this->fields["left"]."` - (".$idif."), " .
"`".$this->fields["right"]."` = `".$this->fields["right"]."` - (".$idif."), " .
"`".$this->fields["level"]."` = `".$this->fields["level"]."` - (".$ldif.") " .
"WHERE " .
"`".$this->fields["id"]."` IN (".implode(",", $node_ids).") ";
}
}
else {
$sql[] = "" .
"INSERT INTO `".$this->table."` (" .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."`, " .
"`".$this->fields["left"]."`, " .
"`".$this->fields["right"]."`, " .
"`".$this->fields["level"]."` " .
") " .
"VALUES (" .
$ref_id.", " .
$position.", " .
$idif.", " .
($idif + 1).", " .
$ldif.
")";
}
foreach($sql as $q) { $this->db->query($q); }
$ind = $this->db->insert_id();
if($is_copy) $this->_fix_copy($ind, $position);
return $node === false || $is_copy ? $ind : true;
}
function _fix_copy($id, $position) {
$node = $this->_get_node($id);
$children = $this->_get_children($id, true);
$map = array();
for($i = $node[$this->fields["left"]] + 1; $i < $node[$this->fields["right"]]; $i++) {
$map[$i] = $id;
}
foreach($children as $cid => $child) {
if((int)$cid == (int)$id) {
$this->db->query("UPDATE `".$this->table."` SET `".$this->fields["position"]."` = ".$position." WHERE `".$this->fields["id"]."` = ".$cid);
continue;
}
$this->db->query("UPDATE `".$this->table."` SET `".$this->fields["parent_id"]."` = ".$map[(int)$child[$this->fields["left"]]]." WHERE `".$this->fields["id"]."` = ".$cid);
for($i = $child[$this->fields["left"]] + 1; $i < $child[$this->fields["right"]]; $i++) {
$map[$i] = $cid;
}
}
}
function _reconstruct() {
$this->db->query("" .
"CREATE TEMPORARY TABLE `temp_tree` (" .
"`".$this->fields["id"]."` INTEGER NOT NULL, " .
"`".$this->fields["parent_id"]."` INTEGER NOT NULL, " .
"`". $this->fields["position"]."` INTEGER NOT NULL" .
") type=HEAP"
);
$this->db->query("" .
"INSERT INTO `temp_tree` " .
"SELECT " .
"`".$this->fields["id"]."`, " .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."` " .
"FROM `".$this->table."`"
);
$this->db->query("" .
"CREATE TEMPORARY TABLE `temp_stack` (" .
"`".$this->fields["id"]."` INTEGER NOT NULL, " .
"`".$this->fields["left"]."` INTEGER, " .
"`".$this->fields["right"]."` INTEGER, " .
"`".$this->fields["level"]."` INTEGER, " .
"`stack_top` INTEGER NOT NULL, " .
"`".$this->fields["parent_id"]."` INTEGER, " .
"`".$this->fields["position"]."` INTEGER " .
") type=HEAP"
);
$counter = 2;
$this->db->query("SELECT COUNT(*) FROM temp_tree");
$this->db->nextr();
$maxcounter = (int) $this->db->f(0) * 2;
$currenttop = 1;
$this->db->query("" .
"INSERT INTO `temp_stack` " .
"SELECT " .
"`".$this->fields["id"]."`, " .
"1, " .
"NULL, " .
"0, " .
"1, " .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."` " .
"FROM `temp_tree` " .
"WHERE `".$this->fields["parent_id"]."` = 0"
);
$this->db->query("DELETE FROM `temp_tree` WHERE `".$this->fields["parent_id"]."` = 0");
while ($counter <= $maxcounter) {
$this->db->query("" .
"SELECT " .
"`temp_tree`.`".$this->fields["id"]."` AS tempmin, " .
"`temp_tree`.`".$this->fields["parent_id"]."` AS pid, " .
"`temp_tree`.`".$this->fields["position"]."` AS lid " .
"FROM `temp_stack`, `temp_tree` " .
"WHERE " .
"`temp_stack`.`".$this->fields["id"]."` = `temp_tree`.`".$this->fields["parent_id"]."` AND " .
"`temp_stack`.`stack_top` = ".$currenttop." " .
"ORDER BY `temp_tree`.`".$this->fields["position"]."` ASC LIMIT 1"
);
if ($this->db->nextr()) {
$tmp = $this->db->f("tempmin");
$q = "INSERT INTO temp_stack (stack_top, `".$this->fields["id"]."`, `".$this->fields["left"]."`, `".$this->fields["right"]."`, `".$this->fields["level"]."`, `".$this->fields["parent_id"]."`, `".$this->fields["position"]."`) VALUES(".($currenttop + 1).", ".$tmp.", ".$counter.", NULL, ".$currenttop.", ".$this->db->f("pid").", ".$this->db->f("lid").")";
$this->db->query($q);
$this->db->query("DELETE FROM `temp_tree` WHERE `".$this->fields["id"]."` = ".$tmp);
$counter++;
$currenttop++;
}
else {
$this->db->query("" .
"UPDATE temp_stack SET " .
"`".$this->fields["right"]."` = ".$counter.", " .
"`stack_top` = -`stack_top` " .
"WHERE `stack_top` = ".$currenttop
);
$counter++;
$currenttop--;
}
}
$temp_fields = $this->fields;
unset($temp_fields["parent_id"]);
unset($temp_fields["position"]);
unset($temp_fields["left"]);
unset($temp_fields["right"]);
unset($temp_fields["level"]);
if(count($temp_fields) > 1) {
$this->db->query("" .
"CREATE TEMPORARY TABLE `temp_tree2` " .
"SELECT `".implode("`, `", $temp_fields)."` FROM `".$this->table."` "
);
}
$this->db->query("TRUNCATE TABLE `".$this->table."`");
$this->db->query("" .
"INSERT INTO ".$this->table." (" .
"`".$this->fields["id"]."`, " .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."`, " .
"`".$this->fields["left"]."`, " .
"`".$this->fields["right"]."`, " .
"`".$this->fields["level"]."` " .
") " .
"SELECT " .
"`".$this->fields["id"]."`, " .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."`, " .
"`".$this->fields["left"]."`, " .
"`".$this->fields["right"]."`, " .
"`".$this->fields["level"]."` " .
"FROM temp_stack " .
"ORDER BY `".$this->fields["id"]."`"
);
if(count($temp_fields) > 1) {
$sql = "" .
"UPDATE `".$this->table."` v, `temp_tree2` SET v.`".$this->fields["id"]."` = v.`".$this->fields["id"]."` ";
foreach($temp_fields as $k => $v) {
if($k == "id") continue;
$sql .= ", v.`".$v."` = `temp_tree2`.`".$v."` ";
}
$sql .= " WHERE v.`".$this->fields["id"]."` = `temp_tree2`.`".$this->fields["id"]."` ";
$this->db->query($sql);
}
}
function _analyze() {
$report = array();
$this->db->query("" .
"SELECT " .
"`".$this->fields["left"]."` FROM `".$this->table."` s " .
"WHERE " .
"`".$this->fields["parent_id"]."` = 0 "
);
$this->db->nextr();
if($this->db->nf() == 0) {
$report[] = "[FAIL]\tNo root node.";
}
else {
$report[] = ($this->db->nf() > 1) ? "[FAIL]\tMore than one root node." : "[OK]\tJust one root node.";
}
$report[] = ($this->db->f(0) != 1) ? "[FAIL]\tRoot node's left index is not 1." : "[OK]\tRoot node's left index is 1.";
$this->db->query("" .
"SELECT " .
"COUNT(*) FROM `".$this->table."` s " .
"WHERE " .
"`".$this->fields["parent_id"]."` != 0 AND " .
"(SELECT COUNT(*) FROM `".$this->table."` WHERE `".$this->fields["id"]."` = s.`".$this->fields["parent_id"]."`) = 0 ");
$this->db->nextr();
$report[] = ($this->db->f(0) > 0) ? "[FAIL]\tMissing parents." : "[OK]\tNo missing parents.";
$this->db->query("SELECT MAX(`".$this->fields["right"]."`) FROM `".$this->table."`");
$this->db->nextr();
$n = $this->db->f(0);
$this->db->query("SELECT COUNT(*) FROM `".$this->table."`");
$this->db->nextr();
$c = $this->db->f(0);
$report[] = ($n/2 != $c) ? "[FAIL]\tRight index does not match node count." : "[OK]\tRight index matches count.";
$this->db->query("" .
"SELECT COUNT(`".$this->fields["id"]."`) FROM `".$this->table."` s " .
"WHERE " .
"(SELECT COUNT(*) FROM `".$this->table."` WHERE " .
"`".$this->fields["right"]."` < s.`".$this->fields["right"]."` AND " .
"`".$this->fields["left"]."` > s.`".$this->fields["left"]."` AND " .
"`".$this->fields["level"]."` = s.`".$this->fields["level"]."` + 1" .
") != " .
"(SELECT COUNT(*) FROM `".$this->table."` WHERE " .
"`".$this->fields["parent_id"]."` = s.`".$this->fields["id"]."`" .
") "
);
$this->db->nextr();
$report[] = ($this->db->f(0) > 0) ? "[FAIL]\tAdjacency and nested set do not match." : "[OK]\tNS and AJ match";
return implode("<br />",$report);
}
function _dump($output = false) {
$nodes = array();
$this->db->query("SELECT * FROM ".$this->table." ORDER BY `".$this->fields["left"]."`");
while($this->db->nextr()) $nodes[] = $this->db->get_row("assoc");
if($output) {
echo "<pre>";
foreach($nodes as $node) {
echo str_repeat("&#160;",(int)$node[$this->fields["level"]] * 2);
echo $node[$this->fields["id"]]." (".$node[$this->fields["left"]].",".$node[$this->fields["right"]].",".$node[$this->fields["level"]].",".$node[$this->fields["parent_id"]].",".$node[$this->fields["position"]].")<br />";
}
echo str_repeat("-",40);
echo "</pre>";
}
return $nodes;
}
function _drop() {
$this->db->query("TRUNCATE TABLE `".$this->table."`");
$this->db->query("" .
"INSERT INTO `".$this->table."` (" .
"`".$this->fields["id"]."`, " .
"`".$this->fields["parent_id"]."`, " .
"`".$this->fields["position"]."`, " .
"`".$this->fields["left"]."`, " .
"`".$this->fields["right"]."`, " .
"`".$this->fields["level"]."` " .
") " .
"VALUES (" .
"1, " .
"0, " .
"0, " .
"1, " .
"2, " .
"0 ".
")");
}
}
class json_tree extends _tree_struct {
function __construct($table = "tree", $fields = array(), $add_fields = array("title" => "title", "type" => "type")) {
parent::__construct($table, $fields);
$this->fields = array_merge($this->fields, $add_fields);
$this->add_fields = $add_fields;
}
function create_node($data) {
$id = parent::_create((int)$data[$this->fields["id"]], (int)$data[$this->fields["position"]]);
if($id) {
$data["id"] = $id;
$this->set_data($data);
return "{ \"status\" : 1, \"id\" : ".(int)$id." }";
}
return "{ \"status\" : 0 }";
}
function set_data($data) {
if(count($this->add_fields) == 0) { return "{ \"status\" : 1 }"; }
$s = "UPDATE `".$this->table."` SET `".$this->fields["id"]."` = `".$this->fields["id"]."` ";
foreach($this->add_fields as $k => $v) {
if(isset($data[$k])) $s .= ", `".$this->fields[$v]."` = \"".$this->db->escape($data[$k])."\" ";
else $s .= ", `".$this->fields[$v]."` = `".$this->fields[$v]."` ";
}
$s .= "WHERE `".$this->fields["id"]."` = ".(int)$data["id"];
$this->db->query($s);
return "{ \"status\" : 1 }";
}
function rename_node($data) { return $this->set_data($data); }
function move_node($data) {
$id = parent::_move((int)$data["id"], (int)$data["ref"], (int)$data["position"], (int)$data["copy"]);
if(!$id) return "{ \"status\" : 0 }";
if((int)$data["copy"] && count($this->add_fields)) {
$ids = array_keys($this->_get_children($id, true));
$data = $this->_get_children((int)$data["id"], true);
$i = 0;
foreach($data as $dk => $dv) {
$s = "UPDATE `".$this->table."` SET `".$this->fields["id"]."` = `".$this->fields["id"]."` ";
foreach($this->add_fields as $k => $v) {
if(isset($dv[$k])) $s .= ", `".$this->fields[$v]."` = \"".$this->db->escape($dv[$k])."\" ";
else $s .= ", `".$this->fields[$v]."` = `".$this->fields[$v]."` ";
}
$s .= "WHERE `".$this->fields["id"]."` = ".$ids[$i];
$this->db->query($s);
$i++;
}
}
return "{ \"status\" : 1, \"id\" : ".$id." }";
}
function remove_node($data) {
$id = parent::_remove((int)$data["id"]);
return "{ \"status\" : 1 }";
}
function get_children($data) {
$tmp = $this->_get_children((int)$data["id"]);
if((int)$data["id"] === 1 && count($tmp) === 0) {
$this->_create_default();
$tmp = $this->_get_children((int)$data["id"]);
}
$result = array();
if((int)$data["id"] === 0) return json_encode($result);
foreach($tmp as $k => $v) {
$result[] = array(
"attr" => array("id" => "node_".$k, "rel" => $v[$this->fields["type"]]),
"data" => $v[$this->fields["title"]],
"state" => ((int)$v[$this->fields["right"]] - (int)$v[$this->fields["left"]] > 1) ? "closed" : ""
);
}
return json_encode($result);
}
function search($data) {
$this->db->query("SELECT `".$this->fields["left"]."`, `".$this->fields["right"]."` FROM `".$this->table."` WHERE `".$this->fields["title"]."` LIKE '%".$this->db->escape($data["search_str"])."%'");
if($this->db->nf() === 0) return "[]";
$q = "SELECT DISTINCT `".$this->fields["id"]."` FROM `".$this->table."` WHERE 0 ";
while($this->db->nextr()) {
$q .= " OR (`".$this->fields["left"]."` < ".(int)$this->db->f(0)." AND `".$this->fields["right"]."` > ".(int)$this->db->f(1).") ";
}
$result = array();
$this->db->query($q);
while($this->db->nextr()) { $result[] = "#node_".$this->db->f(0); }
return json_encode($result);
}
function _create_default() {
$this->_drop();
$this->create_node(array(
"id" => 1,
"position" => 0,
"title" => "C:",
"type" => "drive"
));
$this->create_node(array(
"id" => 1,
"position" => 1,
"title" => "D:",
"type" => "drive"
));
$this->create_node(array(
"id" => 2,
"position" => 0,
"title" => "_demo",
"type" => "folder"
));
$this->create_node(array(
"id" => 2,
"position" => 1,
"title" => "_docs",
"type" => "folder"
));
$this->create_node(array(
"id" => 4,
"position" => 0,
"title" => "index.html",
"type" => "default"
));
$this->create_node(array(
"id" => 5,
"position" => 1,
"title" => "doc.html",
"type" => "default"
));
}
}
?>

View File

@ -0,0 +1,6 @@
1) Create a database and a user with all privileges for this database.
2) Edit the config.php file and update the configuration for the database at the top of the file
3) Import the _dump.sql in your newly created database
4) You are ready to go
*) PLEASE NOTE THAT THE PHP TREE CLASS HAS NOT BEEN THOROUGHLY TESTED

View File

@ -0,0 +1,14 @@
<?php
// Database config & class
$db_config = array(
"servername"=> "localhost",
"username" => "fs4s",
"password" => "",
"database" => "fs4s"
);
if(extension_loaded("mysqli")) require_once("_inc/class._database_i.php");
else require_once("_inc/class._database.php");
// Tree class
require_once("_inc/class.tree.php");
?>

BIN
shop/jstree/_demo/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

View File

@ -0,0 +1,461 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jsTree v.1.0 - Demo</title>
<script type="text/javascript" src="../_lib/jquery.js"></script>
<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
<script type="text/javascript" src="../jquery.jstree.js"></script>
<link type="text/css" rel="stylesheet" href="../_docs/syntax/!style.css"/>
<link type="text/css" rel="stylesheet" href="../_docs/!style.css"/>
<script type="text/javascript" src="../_docs/syntax/!script.js"></script>
</head>
<body id="demo_body">
<div id="container">
<h1 id="dhead">jsTree v.1.0</h1>
<h1>DEMO</h1>
<h2>Creating a tree, binding events, using the instance</h2>
<div id="description">
<p>Here is how you create an instance, bind an event and then get the instance.</p>
<div id="demo1" class="demo" style="height:100px;">
<ul>
<li id="phtml_1">
<a href="#">Root node 1</a>
<ul>
<li id="phtml_2">
<a href="#">Child node 1</a>
</li>
<li id="phtml_3">
<a href="#">Child node 2</a>
</li>
</ul>
</li>
<li id="phtml_4">
<a href="#">Root node 2</a>
</li>
</ul>
</div>
<script type="text/javascript" class="source below">
$(function () {
// TO CREATE AN INSTANCE
// select the tree container using jQuery
$("#demo1")
// call `.jstree` with the options object
.jstree({
// the `plugins` array allows you to configure the active plugins on this instance
"plugins" : ["themes","html_data","ui","crrm","hotkeys"],
// each plugin you have included can have its own config object
"core" : { "initially_open" : [ "phtml_1" ] }
// it makes sense to configure a plugin only if overriding the defaults
})
// EVENTS
// each instance triggers its own events - to process those listen on the container
// all events are in the `.jstree` namespace
// so listen for `function_name`.`jstree` - you can function names from the docs
.bind("loaded.jstree", function (event, data) {
// you get two params - event & data - check the core docs for a detailed description
});
// INSTANCES
// 1) you can call most functions just by selecting the container and calling `.jstree("func",`
setTimeout(function () { $("#demo1").jstree("set_focus"); }, 500);
// with the methods below you can call even private functions (prefixed with `_`)
// 2) you can get the focused instance using `$.jstree._focused()`.
setTimeout(function () { $.jstree._focused().select_node("#phtml_1"); }, 1000);
// 3) you can use $.jstree._reference - just pass the container, a node inside it, or a selector
setTimeout(function () { $.jstree._reference("#phtml_1").close_node("#phtml_1"); }, 1500);
// 4) when you are working with an event you can use a shortcut
$("#demo1").bind("open_node.jstree", function (e, data) {
// data.inst is the instance which triggered this event
data.inst.select_node("#phtml_2", true);
});
setTimeout(function () { $.jstree._reference("#phtml_1").open_node("#phtml_1"); }, 2500);
});
</script>
</div>
<h2>Doing something when the tree is loaded</h2>
<div id="description">
<p>You can use a few events to do that.</p>
<div id="demo2" class="demo" style="height:100px;">
<ul>
<li id="rhtml_1" class="jstree-open">
<a href="#">Root node 1</a>
<ul>
<li id="rhtml_2">
<a href="#">Child node 1</a>
</li>
<li id="rhtml_3">
<a href="#">Child node 2</a>
</li>
</ul>
</li>
<li id="rhtml_4">
<a href="#">Root node 2</a>
</li>
</ul>
</div>
<script type="text/javascript" class="source below">
// Note method 2) and 3) use `one`, this is because if `refresh` is called those events are triggered
$(function () {
$("#demo2")
.jstree({ "plugins" : ["themes","html_data","ui"] })
// 1) the loaded event fires as soon as data is parsed and inserted
.bind("loaded.jstree", function (event, data) { })
// 2) but if you are using the cookie plugin or the core `initially_open` option:
.one("reopen.jstree", function (event, data) { })
// 3) but if you are using the cookie plugin or the UI `initially_select` option:
.one("reselect.jstree", function (event, data) { });
});
</script>
</div>
<h2>Doing something when a node is clicked</h2>
<div id="description">
<div id="demo3" class="demo" style="height:100px;">
<ul>
<li id="shtml_1" class="jstree-open">
<a href="#">Root node 1</a>
<ul>
<li id="shtml_2">
<a href="#">Child node 1</a>
</li>
<li id="shtml_3">
<a href="#">Child node 2</a>
</li>
</ul>
</li>
<li id="shtml_4">
<a href="#">Root node 2</a>
</li>
</ul>
</div>
<script type="text/javascript" class="source below">
$(function () {
$("#demo3")
.jstree({ "plugins" : ["themes","html_data","ui"] })
// 1) if using the UI plugin bind to select_node
.bind("select_node.jstree", function (event, data) {
// `data.rslt.obj` is the jquery extended node that was clicked
alert(data.rslt.obj.attr("id"));
})
// 2) if not using the UI plugin - the Anchor tags work as expected
// so if the anchor has a HREF attirbute - the page will be changed
// you can actually prevent the default, etc (normal jquery usage)
.delegate("a", "click", function (event, data) { event.preventDefault(); })
});
</script>
</div>
<h2>Using CSS to make nodes wrap</h2>
<div id="description">
<div id="demo4" class="demo" style="height:120px;">
<ul>
<li class="jstree-open">
<a href="#">Root node 1</a>
<ul>
<li>
<a href="#">Child node 1 with a long text which would normally just cause a scrollbar, but with this line of CSS it will actually wrap, this is not really throughly tested but it works</a>
</li>
<li>
<a href="#">Child node 2</a>
</li>
</ul>
</li>
<li>
<a href="#">Root node 2</a>
</li>
</ul>
</div>
<style type="text/css" class="source below">
#demo4 a { white-space:normal !important; height: auto; padding:1px 2px; }
#demo4 li > ins { vertical-align:top; }
#demo4 .jstree-hovered, #demo4 .jstree-clicked { border:0; }
</style>
<script type="text/javascript">
$(function () {
$("#demo4")
.jstree({ "plugins" : ["themes","html_data","ui"] });
});
</script>
</div>
<h2>Using CSS to make the nodes bigger</h2>
<div id="description">
<div id="demo5" class="demo" style="height:120px;">
<ul>
<li class="jstree-open">
<a href="#">Root node 1</a>
<ul>
<li>
<a href="#">Child node 1 with a long text which would normally just cause a scrollbar, but with this line of CSS it will actually wrap, this is not really throughly tested but it works</a>
</li>
<li>
<a href="#">Child node 2</a>
</li>
</ul>
</li>
<li>
<a href="#">Root node 2</a>
</li>
</ul>
</div>
<style type="text/css" class="source below">
#demo5 li { min-height:22px; line-height:22px; }
#demo5 a { line-height:20px; height:20px; font-size:10px; }
#demo5 a ins { height:20px; width:20px; background-position:-56px -17px; }
</style>
<script type="text/javascript">
$(function () {
$("#demo5")
.jstree({ "plugins" : ["themes","html_data","ui"] });
});
</script>
</div>
<h2>PHP &amp; mySQL demo + event order</h2>
<div id="description">
<p>Here is a PHP &amp; mySQL enabled demo. You can use the classes/DB structure included, but those are not thoroughly tested and not officially a part of jstree. In the log window you can also see all function calls as they happen on the instance.</p>
<div id="mmenu" style="height:30px; overflow:auto;">
<input type="button" id="add_folder" value="add folder" style="display:block; float:left;"/>
<input type="button" id="add_default" value="add file" style="display:block; float:left;"/>
<input type="button" id="rename" value="rename" style="display:block; float:left;"/>
<input type="button" id="remove" value="remove" style="display:block; float:left;"/>
<input type="button" id="cut" value="cut" style="display:block; float:left;"/>
<input type="button" id="copy" value="copy" style="display:block; float:left;"/>
<input type="button" id="paste" value="paste" style="display:block; float:left;"/>
<input type="button" id="clear_search" value="clear" style="display:block; float:right;"/>
<input type="button" id="search" value="search" style="display:block; float:right;"/>
<input type="text" id="text" value="" style="display:block; float:right;" />
</div>
<!-- the tree container (notice NOT an UL node) -->
<div id="demo" class="demo" style="height:200px;"></div>
<div style="height:30px; text-align:center;">
<input type="button" style='width:170px; height:24px; margin:5px auto;' value="reconstruct" onclick="$.get('./server.php?reconstruct', function () { $('#demo').jstree('refresh',-1); });" />
<input type="button" style='width:170px; height:24px; margin:5px auto;' id="analyze" value="analyze" onclick="$('#alog').load('./server.php?analyze');" />
<input type="button" style='width:170px; height:24px; margin:5px auto;' value="refresh" onclick="$('#demo').jstree('refresh',-1);" />
</div>
<div id='alog' style="border:1px solid gray; padding:5px; height:100px; margin-top:15px; overflow:auto; font-family:Monospace;"></div>
<!-- JavaScript neccessary for the tree -->
<script type="text/javascript" class="source below">
$(function () {
$("#demo")
.bind("before.jstree", function (e, data) {
$("#alog").append(data.func + "<br />");
})
.jstree({
// List of active plugins
"plugins" : [
"themes","json_data","ui","crrm","cookies","dnd","search","types","hotkeys","contextmenu"
],
// I usually configure the plugin that handles the data first
// This example uses JSON as it is most common
"json_data" : {
// This tree is ajax enabled - as this is most common, and maybe a bit more complex
// All the options are almost the same as jQuery's AJAX (read the docs)
"ajax" : {
// the URL to fetch the data
"url" : "./server.php",
// the `data` function is executed in the instance's scope
// the parameter is the node being loaded
// (may be -1, 0, or undefined when loading the root nodes)
"data" : function (n) {
// the result is fed to the AJAX request `data` option
return {
"operation" : "get_children",
"id" : n.attr ? n.attr("id").replace("node_","") : 1
};
}
}
},
// Configuring the search plugin
"search" : {
// As this has been a common question - async search
// Same as above - the `ajax` config option is actually jQuery's AJAX object
"ajax" : {
"url" : "./server.php",
// You get the search string as a parameter
"data" : function (str) {
return {
"operation" : "search",
"search_str" : str
};
}
}
},
// Using types - most of the time this is an overkill
// read the docs carefully to decide whether you need types
"types" : {
// I set both options to -2, as I do not need depth and children count checking
// Those two checks may slow jstree a lot, so use only when needed
"max_depth" : -2,
"max_children" : -2,
// I want only `drive` nodes to be root nodes
// This will prevent moving or creating any other type as a root node
"valid_children" : [ "drive" ],
"types" : {
// The default type
"default" : {
// I want this type to have no children (so only leaf nodes)
// In my case - those are files
"valid_children" : "none",
// If we specify an icon for the default type it WILL OVERRIDE the theme icons
"icon" : {
"image" : "./file.png"
}
},
// The `folder` type
"folder" : {
// can have files and other folders inside of it, but NOT `drive` nodes
"valid_children" : [ "default", "folder" ],
"icon" : {
"image" : "./folder.png"
}
},
// The `drive` nodes
"drive" : {
// can have files and folders inside, but NOT other `drive` nodes
"valid_children" : [ "default", "folder" ],
"icon" : {
"image" : "./root.png"
},
// those prevent the functions with the same name to be used on `drive` nodes
// internally the `before` event is used
"start_drag" : false,
"move_node" : false,
"delete_node" : false,
"remove" : false
}
}
},
// UI & core - the nodes to initially select and open will be overwritten by the cookie plugin
// the UI plugin - it handles selecting/deselecting/hovering nodes
"ui" : {
// this makes the node with ID node_4 selected onload
"initially_select" : [ "node_4" ]
},
// the core plugin - not many options here
"core" : {
// just open those two nodes up
// as this is an AJAX enabled tree, both will be downloaded from the server
"initially_open" : [ "node_2" , "node_3" ]
}
})
.bind("create.jstree", function (e, data) {
$.post(
"./server.php",
{
"operation" : "create_node",
"id" : data.rslt.parent.attr("id").replace("node_",""),
"position" : data.rslt.position,
"title" : data.rslt.name,
"type" : data.rslt.obj.attr("rel")
},
function (r) {
if(r.status) {
$(data.rslt.obj).attr("id", "node_" + r.id);
}
else {
$.jstree.rollback(data.rlbk);
}
}
);
})
.bind("remove.jstree", function (e, data) {
data.rslt.obj.each(function () {
$.ajax({
async : false,
type: 'POST',
url: "./server.php",
data : {
"operation" : "remove_node",
"id" : this.id.replace("node_","")
},
success : function (r) {
if(!r.status) {
data.inst.refresh();
}
}
});
});
})
.bind("rename.jstree", function (e, data) {
$.post(
"./server.php",
{
"operation" : "rename_node",
"id" : data.rslt.obj.attr("id").replace("node_",""),
"title" : data.rslt.new_name
},
function (r) {
if(!r.status) {
$.jstree.rollback(data.rlbk);
}
}
);
})
.bind("move_node.jstree", function (e, data) {
data.rslt.o.each(function (i) {
$.ajax({
async : false,
type: 'POST',
url: "./server.php",
data : {
"operation" : "move_node",
"id" : $(this).attr("id").replace("node_",""),
"ref" : data.rslt.cr === -1 ? 1 : data.rslt.np.attr("id").replace("node_",""),
"position" : data.rslt.cp + i,
"title" : data.rslt.name,
"copy" : data.rslt.cy ? 1 : 0
},
success : function (r) {
if(!r.status) {
$.jstree.rollback(data.rlbk);
}
else {
$(data.rslt.oc).attr("id", "node_" + r.id);
if(data.rslt.cy && $(data.rslt.oc).children("UL").length) {
data.inst.refresh(data.inst._get_parent(data.rslt.oc));
}
}
$("#analyze").click();
}
});
});
});
});
</script>
<script type="text/javascript" class="source below">
// Code for the menu buttons
$(function () {
$("#mmenu input").click(function () {
switch(this.id) {
case "add_default":
case "add_folder":
$("#demo").jstree("create", null, "last", { "attr" : { "rel" : this.id.toString().replace("add_", "") } });
break;
case "search":
$("#demo").jstree("search", document.getElementById("text").value);
break;
case "text": break;
default:
$("#demo").jstree(this.id);
break;
}
});
});
</script>
</div>
</div>
</body>
</html>

BIN
shop/jstree/_demo/root.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,69 @@
<?php
require_once("config.php");
$jstree = new json_tree();
//$jstree->_create_default();
//die();
if(isset($_GET["reconstruct"])) {
$jstree->_reconstruct();
die();
}
if(isset($_GET["analyze"])) {
echo $jstree->_analyze();
die();
}
if($_REQUEST["operation"] && strpos($_REQUEST["operation"], "_") !== 0 && method_exists($jstree, $_REQUEST["operation"])) {
header("HTTP/1.0 200 OK");
header('Content-type: application/json; charset=utf-8');
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Pragma: no-cache");
echo $jstree->{$_REQUEST["operation"]}($_REQUEST);
die();
}
header("HTTP/1.0 404 Not Found");
?>
<?php
/*
$jstree->_drop();
$jstree->create_node(array("id"=>0,"position"=>0));
$jstree->create_node(array("id"=>1,"position"=>0));
$jstree->create_node(array("id"=>1,"position"=>0));
$jstree->create_node(array("id"=>3,"position"=>0,"name"=>"Pesho"));
$jstree->move(3,2,0,true);
$jstree->_dump(true);
$jstree->_reconstruct();
echo $jstree->_analyze();
die();
$tree = new _tree_struct;
$tree->drop();
$tree->create(0, 0);
$tree->create(0, 0);
$tree->create(1, 0);
$tree->create(0, 3);
$tree->create(2, 3);
$tree->create(2, 0);
$tree->dump(true);
$tree->move(6,4,0);
$tree->move(1,0,0);
$tree->move(3,2,99,true);
$tree->move(7,1,0,true);
$tree->move(1,7,0);
$tree->move(1,0,1,true);
$tree->move(2, 0, 0, true);
$tree->move(13, 12, 2, true);
$tree->dump(true);
$tree->move(15, 16, 2, true);
$tree->dump(true);
$tree->move(4, 0, 0);
$tree->dump(true);
$tree->move(4, 0, 2);
$tree->dump(true);
echo $tree->analyze();
$tree->drop();
*/
?>