diff --git a/thirdparty/jstree/.piston.yml b/thirdparty/jstree/.piston.yml
index 9795be7c1..5473a3644 100644
--- a/thirdparty/jstree/.piston.yml
+++ b/thirdparty/jstree/.piston.yml
@@ -1,8 +1,8 @@
---
format: 1
handler:
- piston:remote-revision: 236
- piston:uuid: 7ee4f3fb-cb41-0410-822c-dd8830bd4fbc
+ commit: 53d377b047f45bb4d4042e5928130c66c01a6e8b
+ branch: v.pre1.0
lock: false
-repository_class: Piston::Svn::Repository
-repository_url: http://jstree.googlecode.com/svn/trunk
+repository_class: Piston::Git::Repository
+repository_url: git://github.com/vakata/jstree.git
diff --git a/thirdparty/jstree/README.txt b/thirdparty/jstree/README.txt
new file mode 100644
index 000000000..eb90797b4
--- /dev/null
+++ b/thirdparty/jstree/README.txt
@@ -0,0 +1,10 @@
+jsTree pre1.0
+http://jstree.com/
+
+Copyright (c) 2011 Ivan Bozhanov (vakata.com)
+
+Dual licensed under the MIT and GPL licenses:
+ http://www.opensource.org/licenses/mit-license.php
+ http://www.gnu.org/licenses/gpl.html
+
+This is the latest stable version before switching from GoogleCode to GitHub.
\ No newline at end of file
diff --git a/thirdparty/jstree/_demo/_dump.sql b/thirdparty/jstree/_demo/_dump.sql
new file mode 100644
index 000000000..19dfdd1f3
--- /dev/null
+++ b/thirdparty/jstree/_demo/_dump.sql
@@ -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');
diff --git a/thirdparty/jstree/_demo/_inc/__mysql_errors.log b/thirdparty/jstree/_demo/_inc/__mysql_errors.log
new file mode 100644
index 000000000..e69de29bb
diff --git a/thirdparty/jstree/_demo/_inc/class._database.php b/thirdparty/jstree/_demo/_inc/class._database.php
new file mode 100644
index 000000000..9b6fd56ae
--- /dev/null
+++ b/thirdparty/jstree/_demo/_inc/class._database.php
@@ -0,0 +1,146 @@
+ "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);
+ }
+
+
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/jstree/_demo/_inc/class._database_i.php b/thirdparty/jstree/_demo/_inc/class._database_i.php
new file mode 100644
index 000000000..04f9ee7f9
--- /dev/null
+++ b/thirdparty/jstree/_demo/_inc/class._database_i.php
@@ -0,0 +1,152 @@
+ "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."
:";
+ 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();
+ }
+
+
+}
\ No newline at end of file
diff --git a/thirdparty/jstree/_demo/_inc/class.tree.php b/thirdparty/jstree/_demo/_inc/class.tree.php
new file mode 100644
index 000000000..690b0a3dc
--- /dev/null
+++ b/thirdparty/jstree/_demo/_inc/class.tree.php
@@ -0,0 +1,602 @@
+ 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("
",$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 "
"; + foreach($nodes as $node) { + echo str_repeat(" ",(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"]].")"; + } + 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" + )); + } +} + +?> \ No newline at end of file diff --git a/thirdparty/jstree/_demo/_install.txt b/thirdparty/jstree/_demo/_install.txt new file mode 100644 index 000000000..39aff82c0 --- /dev/null +++ b/thirdparty/jstree/_demo/_install.txt @@ -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 \ No newline at end of file diff --git a/thirdparty/jstree/_demo/config.php b/thirdparty/jstree/_demo/config.php new file mode 100644 index 000000000..354f6a9a9 --- /dev/null +++ b/thirdparty/jstree/_demo/config.php @@ -0,0 +1,14 @@ + "localhost", + "username" => "root", + "password" => "", + "database" => "" +); +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"); +?> \ No newline at end of file diff --git a/thirdparty/jstree/_demo/file.png b/thirdparty/jstree/_demo/file.png new file mode 100644 index 000000000..58959687b Binary files /dev/null and b/thirdparty/jstree/_demo/file.png differ diff --git a/thirdparty/jstree/_demo/folder.png b/thirdparty/jstree/_demo/folder.png new file mode 100644 index 000000000..30eedea1d Binary files /dev/null and b/thirdparty/jstree/_demo/folder.png differ diff --git a/thirdparty/jstree/_demo/index.html b/thirdparty/jstree/_demo/index.html new file mode 100644 index 000000000..342dfc5c0 --- /dev/null +++ b/thirdparty/jstree/_demo/index.html @@ -0,0 +1,461 @@ + + + + +
"; + } + echo str_repeat("-",40); + echo "
Here is how you create an instance, bind an event and then get the instance.
+You can use a few events to do that.
+Here is a PHP & 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.
+ + + + +The checkbox
plugin makes multiselection possible using three-state checkboxes.
If set to true
all selection will be handled by checkboxes. The checkbox plugin will map UI's get_selected function to its own get_checked function and overwrite the UI reselect function. It will also disable the select_node
, deselect_node
and deselect_all
functions. If left as false
nodes can be selected and checked independently.
When set to true
when programatically checking a node in the tree all of its closed parents are opened automatically.
If set to true
checkboxes will be two-state only, meaning that you will be able to select parent and children independently and there will be no undetermined state.
If set to true
real hidden checkboxes will be created for each element, so if the tree is part of a form, checked nodes will be submitted automatically. By default the name of the checkbox is "check_" + the ID of the LI element
and the value is 1
, this can be changed using the real_checkboxes_names
config option.
If real checkboxes are used this function is invoked in the current tree's scope for each new checkbox that is created. It receives a single argument - the node that will contain the checkbox. The function must return an array consisting of two values - the name for the checkbox and the value for the checkbox.
+ +Inserts the checkbox icons on the node. Used internally.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+Repairs the checkbox state inside the node. Used internally.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+Changes the state of a node. Used mostly internally - you'd be better off using the check_node
and uncheck_node
functions. Triggers an event.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+boolean
uncheck
+ If set to true
the node is unchecked, if set to false
the node is checked, otherwise - the state is toggled.
Checks a node.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+Unchecks a node.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+Checks all nodes.
+ +Unchecks all nodes.
+ +Checks if a node is checked. Returns boolean.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+Both functions return jQuery collections.
+mixed
context
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If specified only nodes inside the specified context are returned, otherwise the whole tree is searched.
+boolean
get_all
+ By default these functions return only top level checked/unchecked nodes (if a node is checked its children are note returned), if this parameter is set to true
they will return all checked/unchecked nodes.
Show or hide the checkbox icons.
+ +The contextmenu
plugin enables a contextual menu to be shown, when the user right-clicks a node (or when triggered programatically by the developer).
Whether to select the right clicked node when showing the context menu. If this is set to true
and the node is not selected all currently selected nodes will be deselected.
Whether to show the context menu just below the node, or at the clicked point exactly.
+ +Expects an object or a function, which should return an object. If a function is used it fired in the tree's context and receives one argument - the node that was right clicked. The object format is:
++{ +// Some key +"rename" : { + // The item label + "label" : "Rename", + // The function to execute upon a click + "action" : function (obj) { this.rename(obj); }, + // All below are optional + "_disabled" : true, // clicking the item won't do a thing + "_class" : "class", // class is applied to the item LI node + "separator_before" : false, // Insert a separator before the item + "separator_after" : true, // Insert a separator after the item + // false or string - if does not contain `/` - used as classname + "icon" : false, + "submenu" : { + /* Collection of objects (the same structure) */ + } +} +/* MORE ENTRIES ... */ +} ++
Shows the contextmenu next to a node. Triggered automatically when right-clicking a node.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+number
x
+ The X-coordinate to show the menu at - may be overwritten by show_at_node
. If you omit this the menu is shown aligned with the left of the node.
number
y
+ The Y-coordinate to show the menu at - may be overwritten by show_at_node
. If you omit this the menu is shown just below the node.
The cookies
enables jstree to save the state of the tree across sessions. What this does is save the opened and selected nodes in a cookie, and reopen & reselect them the next time the user loads the tree. Depends on the jQuery.cookie plugin.
The nodes need to have IDs for this plugin to work.
+The name of the cookie to save opened nodes in. If set to false
- opened nodes won't be saved.
The name of the cookie to save selected nodes in. If set to false
- selected nodes won't be saved.
If set to true
jstree will automatically update the cookies every time a change in the state occurs.
The options accepted by the jQuery.cookie plugin.
+ +Check your data plugin documentation (html_data, xml_data, json_data) or take a close look at these examples for information on how to specify multilanguage nodes.
+ +Go ahead and make changes to the tree and then refresh this page.
+Save the current state.
+string
event
+ Used internally with the auto_save
option. Do not set this manually.
First of all, as jsTree is a jQuery component, you need to include jQuery itself. jsTree v.1.0 requires jQuery version 1.4.2
+ ++<script type="text/javascript" src="_lib/jquery.js"></script> +
Then you need to include jsTree:
+ ++<script type="text/javascript" src="jquery.jstree.js"></script> +
Or you could use the minified version:
+ ++<script type="text/javascript" src="jquery.jstree.min.js"></script> +
You may change the path to whatever you like, but it is recommended not to rename jquery.tree.js
or jquery.tree.min.js
as the filenames may be used for path autodetection (for example in the themes
plugin, but if you really need to rename the file most plugins will give you the option to set the path manually).
Additionally some plugins have dependencies - plugins that detect a dependency is missing will throw an error.
+ +You can create a tree in the following manner:
+ ++jQuery("some-selector-to-container-node-here").jstree([ config_object ]); +
In the optional config object you specify all the options that you want to set. Each plugin will describe its configuration and defaults. In the configuration section below you will find the options defined by the core. Each plugin's options (even the core) are set in their own subobject, which is named after the plugin. For example all of the core's options are set in the core
key of the config object:
+jQuery("some-selector-to-container-node-here") + .jstree({ + core : { + /* core options go here */ + } + }); +
Please note that if your options for a given plugin are the same as the defaults you may omit those options or omit the subobject completely (if you do not need to modify the defaults).
+ +There is only one special config option that is not a part of any plugin - this is the plugins
option, which defines a list of active plugins for the instance being created. Although many plugins may be included, only the ones listed in this option will be active. The only autoincluded "plugin" is the jstree core.
+jQuery("some-selector-to-container-node-here") + .jstree({ + core : { /* core options go here */ }, + plugins : [ "themes", "html_data", "some-other-plugin" ] + }); +
To perform an operation programatically on a given instance you can use two methods:
++/* METHOD ONE */ +jQuery("some-selector-to-container-node-here") + .jstree("operation_name" [, argument_1, argument_2, ...]); + +/* METHOD TWO */ +jQuery.jstree._reference(needle) + /* NEEDLE can be a DOM node or selector for the container or a node within the container */ + .operation_name([ argument_1, argument_2, ...]); +
NOTE: Functions prefixed with _
can not be called with method one.
jsTree uses events to notify of any changes happening in the tree. All events fire on the tree container in the jstree
namespace and are named after the function that triggered them. Please note that for some events it is best to bind before creating the instance. For example:
+jQuery("some-container") + .bind("loaded.jstree", function (event, data) { + alert("TREE IS LOADED"); + }) + .jstree({ /* configuration here */ }); +
Please note the second parameter data
. Its structure is as follows:
+{ + "inst" : /* the actual tree instance */, + "args" : /* arguments passed to the function */, + "rslt" : /* any data the function passed to the event */, + "rlbk" : /* an optional rollback object - it is not always present */ +} +
There is also one special event - before.jstree
. This events enables you to prevent an operation from executing. Look at the demo below.
Defines whether titles can contain HTML code.
+ +Defines the duration of open/close animations. 0
means no animation.
Defines which nodes are to be automatically opened (if they are not present they will first be loaded) when the tree finishes loading - a list of IDs is expected.
+ +Defines which nodes are to be automatically loaded (but not opened) when the tree finishes loading - a list of IDs is expected.
+ +When set to true
forces loading of nodes marked as open, which do not have children. Otherwise nodes are only visualized as open without any children and opening/closing such a node won't cause it to load (make a server call).
If set to true opening a node will also open any closed ancestors it has (will open the whole chain down to this node).
+ +If set to true loading nodes with some metadata will trigger some actions on the corresponding plugin. So you can actually set the selected/checked/etc
+ +Defines whether the tree is in right-to-left mode (also make sure you are using a RTL theme - for example the included default-rtl
).
Contains strings needed for the operation of the tree so that you can localize.
+ + ++ +
This is the same demo as above, but this time the operation will be prevented.
+ ++
The important part is e.stopImmediatePropagation(); return false
.
Use extra caution when working with functions prefixed with an underscore - _
!
Those functions are probably for internal usage only.
This object is exposed so that you can apply standart settings to all future instances
+ +This function is used by developers to extend jstree (add "plugins").
+string
plugin_name
+ The plugin name - it should be unique.
+object
plugin_data
+ The plugin itself. It consists of __init
& __destroy
functions, defaults
object (that of course could be an array or a simple value) and a _fn
object, whose keys are all the functions you are extending jstree with. You can overwrite functions (but you can in your function call the overriden old function), and you are responsible for triggering events and setting rollback points. You can omit any of the elements in the plugin_data
param. Keep in mind jstree will automatically clear classes prepended with jstree-
and all events in the jstree
namespace when destroying a tree, so you do not need to worry about those.
Read jstree's code for examples on how to develop plugins.
+This function will roll the tree back to the state specified by the rollback object
+string
rollback_object
+ Normally you will get this object from the event you are handling. You can of course use .get_rollback()
to get the current state of the tree as a rollback object.
+$("some-container").bind("some-event.jstree", function (e, data) { + $.jstree.rollback(data.rlbk); +});
Keep in mind that not all events will give you a rollback object - sometimes data.rlbk
will be false
.
Returns the currently focused tree instance on the page. If not interaction has been made - it is the last one to be created.
+ +Returns the tree instance for the specified needle
.
mixed
needle
+ This can be a DOM node, jQuery node or selector pointing to the tree container, or an element within the tree.
+This function is used internally when creating new tree instances. Calling this function by itself is not enough to create a new instance. To create a tree use the documented method $("selector").jstree([ options ])
.
This object stores all functions included by plugins. It is used internally as a prototype for all instances - do not modify manually.
+ +An object where all plugins store instance specific data. Do not modify manually.
+ +Returns a copy of the instance's settings object - the defaults, extended by your own config object.
+ +Returns the instance's settings object - the defaults, extended by your own config object.
+ +Returns the internal instance index.
+ +Returns the jQuery extended container node of the tree.
+ +Returns the jQuery extended first UL node in the container of the tree.
+ +Replace the settings object with the settings
param. Please note that not all plugins will react to the change. Unless you know exactly what you are doing you'd be better off recreating the tree with the new settings.
This function is used internally when creating a new instance. Triggers an event, which fires after the tree is initialized, but not yet loaded.
+ +Destroys the instance - it will automatically remove all bound events in the jstree
namespace & remove all classes starting with jstree-
. Triggers an event.
Stores the currently open nodes before refreshing. Used internally. Triggers an event.
+ +Reopens all the nodes stored by save_opened
or set in the initially_open
config option on first load. It is called multiple times while reopening nodes - the is_callback
param determines if this is the first call (false
) or not. Used internally. Triggers an event.
Refreshes the tree. Saves all open nodes, and reloads and then reopens all saved nodes. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If set this will reload only the given node - otherwise - the whole tree. Passing -1
also reloads the whole tree.
A dummy function, whose purpose is only to trigger the loaded event. This event is triggered once after the tree's root nodes are loaded, but before any nodes set in initially_open
are opened.
Makes the current instance the focused one on the page. Triggers an event.
+ +If the current instance is focused this removes the focus. Triggers an event.
+ +Returns true
if the current instance is the focused one, otherwise returns false
.
Sets the tree to a locked state - no methods can be called on that instance except for unlock
and is_locked
.
Sets the tree to a unlocked state (the default state).
+Returns true
if the tree is locked, otherwise returns false
.
Return the jQuery extended LI
element of the node, -1
if the container node is passed, or false
otherwise.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+Gets the LI
element representing the node next to the passed node
. Returns false
on failure.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose next sibling we want.
+bool
strict
+ If set to true
only immediate siblings are calculated. Otherwise if the node
is the last child of its parent this function will "jump out" and return the parent's next sibling, etc. Default is false
.
Gets the LI
element representing the node previous to the passed node
. Returns false
on failure.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose previous sibling we want.
+bool
strict
+ If set to true
only immediate siblings are calculated. Otherwise if the node
is the first child of its parent this function will "jump out" and return the parent itself. Default is false
.
Gets the LI
element representing the parent of the passed node
. Returns false
on failure.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose parent we want.
+Gets the LI
elements representing the children of the passed node
. Returns false
on failure (or if the node has no children).
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose children we want. Use -1
to return all root nodes.
Return the path to a node, either as an array of IDs or as an array of node names.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose path we want.
+bool
id_mode
+ If set to true
IDs are returned instead of the names of the parents. Default is false
.
Corrects closed items to leaf items, if no children are found. Used internally, triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element we want corrected.
+Opens a closed node, so that its children are visible. If the animation
config option is greater than 0
the children are revealed using a slide down animation, whose duration is the value of the animation
config option in milliseconds. Triggers an event.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element we want opened.
+function
callback
+ A callback function executed once the node is opened. Used mostly internally, you'd be better of waiting for the event. You can skip this, by not specifying it, or by passing false
.
bool
skip_animation
+ If set to true
the animation set in the animation
config option is skipped. Default is false
.
A dummy function, it triggers an event after the open animation has finished.
+ +Closes an open node, so that its children are not visible. If the animation
config option is greater than 0
the children are hidden using a slide up animation, whose duration is the value of the animation
config option in milliseconds. Triggers an event.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element we want closed.
+bool
skip_animation
+ If set to true
the animation set in the animation
config option is skipped. Default is false
.
A dummy function, it triggers an event after the close animation has finished.
+ +If a node is closed - this function opens it, if it is open - calling this function will close it.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element we want toggled.
+Opens all descendants of the node
node.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element whose descendants you want opened. If this param is omitted or set to -1
all nodes in the tree are opened.
boolean
do_animation
+ If set to true
all nodes are opened with an animation. This can be slow on large trees.
mixed
original_obj
+ Used internally when recursively calling the same function - do not pass this param.
+Closes all descendants of the node
node.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element whose descendants you want closed. If this param is omitted or set to -1
all nodes in the tree are closed.
boolean
do_animation
+ If set to true
all nodes are closed with an animation. This can be slow on large trees.
Those function check if the node
is in a state.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want checked.
+Applies all necessary classes to the node
and its descendants. Used internally. Triggers an event.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want cleaned. If this param is omitted or set to -1
all nodes in the tree are cleaned.
Get the current tree's state in the rollback format. Used mainly internally by plugins.
+ +Rollback the tree. Used ONLY internally! Both arguments are part of the rollback object. If you need to rollback - take a look at jQuery.jstree.rollback(). Triggers event.
+ +A dummy function that is overwritten by data plugins. Triggers event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use -1
for root nodes.
function
success_callback
+ A function to be executed once the node is loaded successfully - used internally. You should wait for the event.
+function
error_callback
+ A function to be executed if the node is not loaded due to an error - used internally. You should wait for the event.
+A dummy function that should return true
if the node's children are loaded or false
otherwise.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want to check.
+Creates the DOM structure necessary for a new node. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element you want to create in (or next to).
+mixed
position
+ The position of the newly created node. This can be a zero based index to position the element at a specific point among the current children. You can also pass in one of those strings: "before"
, "after"
, "inside"
, "first"
, "last"
.
object
js
+ The data for the newly created node. Consists of three keys:
attr
- an object of attributes (same used for jQuery.attr()
. You can omit this key;state
- a string - either "open"
or "closed"
, for a leaf node - omit this key;data
- a string or an object - if a string is passed it is used for the title of the node, if an object is passed there are two keys you can specify: attr
and title
;
function
callback
+ A function to be executed once the node is created - used internally. You should wait for the event.
+bool
is_loaded
+ Specifies if the parent of the node is loaded or not - used ONLY internally.
+Returns the needed string from the config object. If the key does not exist the key itself is returned.
+string
key
+ The name of the string you are looking for.
+Returns the title of a node.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element whose title you need.
+Sets the title of a node. Triggers an event. This is used mostly internally - wait for a .rename_node event to avoid confusion.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element whose title you want to change.
+string
text
+ The new title.
+Sets the title of a node. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element whose title you want to change.
+string
text
+ The new title.
+Removes a node. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element you want to remove.
+This function is used internally to prepare all necessary variables and nodes when moving a node around. It is automatically called as needed - you do not need to call it manually. Triggers an event.
+ +Checks if the prepared move is a valid one.
+ +Moves a node to a new place. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element you want to move.
+mixed
ref
+ This can be a DOM node, jQuery node or selector pointing to the element which will be the reference element in the move. -1
may be used too (to indicate the container node).
mixed
position
+ The new position of the moved node. This can be a zero based index to position the element at a specific point among the reference node's current children. You can also use one of these strings: "before"
, "after"
, "inside"
, "first"
, "last"
.
bool
is_copy
+ Should this be a copy or a move operation.
+bool
is_prepared
+ Used internally when this function is called recursively.
+bool
skip_check
+ If this is set to true
check_move is not called.
Returns the lastly prepared move. The returned object contains:
+.o
- the node being moved
+.r
- the reference node in the move
+.ot
- the origin tree instance
+.rt
- the reference tree instance
+.p
- the position to move to (may be a string - "last"
, "first"
, etc)
+.cp
- the calculated position to move to (always a number)
+.np
- the new parent
+.oc
- the original node (if there was a copy)
+.cy
- boolen indicating if the move was a copy
+.cr
- same as np
, but if a root node is created this is -1
+.op
- the former parent
+.or
- the node that was previously in the position of the moved node
+
The CRRM
plugin handles creating, renaming, removing and moving nodes by the user.
When renaming (or creating) nodes the input for the text will autosize - this number sets the maximum size for the input.
+ +Defines how moves are handled - if set to true
every move will be forced to a copy (leaving the original node in place). If set to "multitree"
only moves between trees will be forced to a copy.
If set to true, when moving a node to a new, closed parent, the parent node will be opened when the move completes.
+ +The default position to move to if no position is specified. This can be a zero based index to position the element at a specific point among the new parent's current children. You can also use one of these strings: "before"
, "after"
, "inside"
, "first"
, "last"
.
The callback function enabling you to prevent some moves - just return false
. The m
parameter is the move object generated by jstree. The object follows the structure described in ._get_move.
move_1 uses the default position - "first"
move_2 specifies a position - "before"
- meaning that the node specified as a first argument will come above the node specified as the second argument
move_3 will never work, because of the specified check_move
function which prevents the first root node from being moved
Renders an input field in a node. Used only internally.
+ +Sets a node in rename mode and when the user has entered changes, an event is triggered.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass null
to use the currently selected item.
Creates a new node. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element you want to create in (or next to). If you use the UI plugin - pass null
to use the currently selected item.
mixed
position
+ The position of the newly created node. This can be a zero based index to position the element at a specific point among the current children. You can also pass in one of those strings: "before"
, "after"
, "inside"
, "first"
, "last"
.
object
js
+ The data for the newly created node. Consists of three keys:
attr
- an object of attributes (same used for jQuery.attr()
. You can omit this key;state
- a string - either "open"
or "closed"
, for a leaf node - omit this key;data
- a string or an object - if a string is passed it is used for the title of the node, if an object is passed there are two keys you can specify: attr
and title
;
function
callback
+ A function to be executed once the node is created. You'd be better off waiting for the event.
+bool
skip_rename
+ Skips the user input step. The node is created with the data you have supplied.
+Removes a node. Triggers an event.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass null
to use the currently selected items.
Both functions are overwritten from the core in order to implement the new functionality.
+ +Cuts a node (prepares it for pasting).
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass null
to use the currently selected item.
Copies a node (prepares it for pasting).
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass null
to use the currently selected item.
Pastes copied or cut nodes inside a node.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass null
to use the currently selected item.
The dnd
plugin enables drag'n'drop support for jstree, also using foreign nodes and drop targets.
All foreign node options and callback functions in the config (drop_target, drop_check, drop_finish, drag_target, drag_check, drag_finish) are to be used ONLY when nodes that are not part of any tree are involved.
If moving nodes from one tree instance to another - just listen for the "move_node.jstree" event on the receiving tree.
DO NOT SET drag_target AND drop_target to match tree nodes!
The special key used to make a drag copy instead of move ("ctrl"
, "shift"
, "alt"
, "meta"
).
The number of milliseconds to wait before checking if a move is valid upon hovering a node (while dragging). 200
is a reasonable value - a higher number means better performance but slow feedback to the user, a lower number means lower performance (possibly) but the user will get feedback faster.
The number of milliseconds to wait before opening a hovered if it has children (while dragging). This means that the user has to stop over the node for half a second in order to trigger the open operation. Keep in mind that a low value in combination with async data could mean a lot of unneeded traffic, so 500
is quite reasonable.
A jquery selector matching all drop targets (you can also use the comma ,
in the string to specify multiple valid targets). If set to false
drop targets are disabled.
Return false
to mark the move as invalid, otherwise return true
. The data
parameter is as follows:
data.o
- the object being dragged
data.r
- the drop target
Gets executed after a valid drop, you get one parameter, which is as follows:
+data.o
- the object being dragged
data.r
- the drop target
A jquery selector matching all foreign nodes that can be dropped on the tree (you can also use the comma ,
in the string to specify multiple valid foreign nodes). If set to false
dragging foreign nodes is disabled.
Return a boolean for each position. The data
parameter is as follows:
data.o
- the foreign object being dragged
data.r
- the hovered node
Gets executed after a dropping a foreign element on a tree item, you get one parameter, which is as follows:
+data.o
- the foreign object being dragged
data.r
- the target node
Drag stuff around!
+All those functions are used internally only. If you want more information - examine the source code.
+ +The hotkeys
plugin enables keyboard navigation and shortcuts. Depends on the jquery.hotkeys plugin.
Expects an object:
each key is the keyboard shortcut (for possible values check the hotkeys plugin)
each value is a function executed in the instance's context, the return value is used as a return value for the event.
Simple example:
+"del" : function () { this.remove(); }
By default "up"
, "ctrl+up"
, "shift+up"
, "down"
, "ctrl+down"
, "shift+down"
, "left"
, "ctrl+left"
, "shift+left"
, "right"
, "ctrl+right"
, "shift+right"
, "space"
, "ctrl+space"
, "shift+space"
, "f2"
, "del"
are bound.
To override any of those - just specify your own function, to disable - just set to false
.
+
Try pressing up
/down
/left
/right
/space
/f2
/del
.
Enable shortcuts on the instance (enabled by default).
+ +Disable shortcuts on the instance.
+ +The html_data
plugin enables jsTree to convert nested unordered lists to interactive trees. jsTree can also get HTML from the server insert it into the DOM and convert that to a tree.
The basic structure you need to follow when supplying data in the HTML format is:
++<li> + <a href="some_value_here">Node title</a> + <!-- UL node only needed for children - omit if there are no children --> + <ul> + <!-- Children LI nodes here --> + </ul> +</li> ++
If you inspect the resulting structure you will find it a bit different - that is because jstree will automatically do some corrections.
++<!-- one of the three classes will be applied depending on node structure --> +<li class="[ jstree-open | jstree-closed | jstree-leaf ]"> + <!-- an INS element is inserted --> + <ins class="jstree-icon"> </ins> + <a href="some_value_here"> + <!-- another INS element is inserted --> + <ins class="jstree-icon"> </ins> + Node title + </a> +</li> ++
Both ins
elements are inserted for visualization purposes. As for the class (jstree-open
, jstree-closed
) - you can specify that yourself to force the node to appear either closed or opened. Making a node with no children appear closed is often used - if you use ajax, opening a closed node with no children will result in jstree making a server call for the children (see the demo below).
Specifies the content to load into the container and convert to a tree.
+The ajax config object is pretty much the same as the jQuery ajax settings object.
+You can set the data
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the node about to be open as a paramater (or -1
for initial load). Whatever you return in the function will be sent to the server as data (so for example you can send the node's ID).
You can set the url
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the node about to be open as a paramater (or -1
for initial load). Whatever you return in the url
function will be used as the ajax URL (so that you can accomodate pretty paths such as /get_children/node_2).
The error
and success
functions (if present) also fire in the context of the tree, and if you return a value in the success
function it will be used to populate the tree - this can be useful if you want to somehow change what the server returned on the client side before it is displayed in the tree.
If this option is set to true
if an AJAX request returns an empty result, the node that was about to be opened will be converted to a leaf node (the open icon will no longer be displayed).
NOTE:
If both data
and ajax
are not set, the current container's HTML is used to build the tree.
If both data
and ajax
are set the initial tree is rendered from the data
string. When opening a closed node (that has no loaded children) an AJAX request is made.
Both dummy functions - _is_loaded
and load_node
are overwritten.
This function is called instead of load_node
.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use -1
for root nodes.
function
success_callback
+ A function to be executed once the node is loaded successfully - used internally. You should wait for the load_node
event.
function
error_callback
+ A function to be executed if the node is not loaded due to an error - used internally. You should wait for the load_node
event.
if you like the project - consider supporting jstree.
+As of version 1.0 jsTree is extremely plugin friendly, so all functionality is now wrapped in plugins, which take care of various aspects of the tree and can be removed without affecting the functionality of other plugins. Below you will find a list of plugins - each with its own documentation page. Probably a good place to start is the core.
+all core functions for manipulating the tree + basic examples of including, configuring and working with the tree, along with demos of the new event system
enables jsTree to convert nested unordered lists to interactive trees, an already existing UL may be used or data could be retrieved from a server
enables jsTree to convert JSON objects to interactive trees, data can be set up in the config or retrieved from a server
enables jsTree to convert XML objects to interactive trees (using XSL), data can be set up in the config or retrieved from a server
controls the looks of jstree - without this plugin you will get a functional tree, but it will look just like an ordinary UL list
handles selecting, deselecting and hovering tree items
handles creating, renaming, removing and moving nodes by the user, also includes cut/copy/paste functions
enables support for keyboard navigation & shortcuts, highly configurable
enables multilanguage support - each node can have multiple titles, but only one is visible
enables jstree to save the state of the tree across sessions, by saving selected and opened nodes in a cookie
enables jstree to automatically sort all nodes
using a specified function
enables drag'n'drop support for jstree, also using foreign nodes and drop targets
makes multiselection possible using three-state checkboxes
enables searching for nodes whose title contains a given string, works on async trees too
enables a multilevel context menu on tree items
each node can have a type, and you can define rules on how that type should behave
adds support for jQuery UI's themes
adds unique checking to jsTree
enhances UIs select & hover functions
The json_data
plugin enables jsTree to convert JSON objects to interactive trees. The data (JSON) can be set up in the config or retrieved from a server (also ondemand). Version 1.0 also introduces the experimental progressive render feature, which is suitable for large heavy trees, when the DOM would be too heavy to manipulate.
The basic structure you need to follow when supplying data in the JSON format is:
++{ + "data" : "node_title", + // omit `attr` if not needed; the `attr` object gets passed to the jQuery `attr` function + "attr" : { "id" : "node_identificator", "some-other-attribute" : "attribute_value" }, + // `state` and `children` are only used for NON-leaf nodes + "state" : "closed", // or "open", defaults to "closed" + "children" : [ /* an array of child nodes objects */ ] +} ++
The attr object will appear as attributes on the resulting li
node.
You may need to pass some attributes to the a
node, or set some metadata, or use language versions (for the languages plugin):
+{ + // `data` can also be an object + "data" : { + "title" : "The node title", + // omit when not needed + "attr" : {}, + // if `icon` contains a slash / it is treated as a file, used for background + // otherwise - it is added as a class to the <ins> node + "icon" : "folder" + }, + + // the `metadata` property will be saved using the jQuery `data` function on the `li` node + "metadata" : "a string, array, object, etc", + + // if you use the language plugin - just set this property + // also make sure that `data` is an array of objects + "language" : "en" // any code you are using +} ++
As seen in the first example below - you can also use a simple string to define a node (Child 1 & Child 2).
+Specifies the content to load into the container and convert to a tree. You can also set this to a function - it will be executed in the tree's scope for every node that needs to be loaded, the function will receive two arguments - the node being loaded & a function to call with the data once your processing is done.
+The ajax config object is pretty much the same as the jQuery ajax settings object.
+You can set the data
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the node about to be open as a paramater (or -1
for initial load). Whatever you return in the data
function will be sent to the server as data (so for example you can send the node's ID).
You can set the url
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the node about to be open as a paramater (or -1
for initial load). Whatever you return in the url
function will be used as the ajax URL (so that you can accomodate pretty paths such as /get_children/node_2).
The error
and success
functions (if present) also fire in the context of the tree, and if you return a value in the success
function it will be used to populate the tree - this can be useful if you want to somehow change what the server returned on the client side before it is displayed in the tree (for example some .NET json implementations require this to work: "success" : function (data) { return data.d; }
.
If this option is set to true
if an AJAX returns an empty result, the node that was about to be opened will be converted to a leaf node (the open icon will no longer be displayed).
If this option is set to true
only the visible (open nodes) parts of the returned JSON are converted to DOM nodes, any hidden parts are saved away and parsed ondemand (when a node becomes visible). This is useful when you have a large nested tree which would result in a heavy DOM.
If this option is set to true
when a node is closed its children are removed from the DOM and saved as metadata on the node itself, on reopen that metadata is used (much like progressive_render
).
NOTE:
If both data
and ajax
are set the initial tree is rendered from the data
string. When opening a closed node (that has no loaded children) an AJAX request is made.
Both dummy functions - _is_loaded
and load_node
are overwritten.
This function is called instead of load_node
.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use -1
for root nodes.
function
success_callback
+ A function to be executed once the node is loaded successfully - used internally. You should wait for the load_node
event.
function
error_callback
+ A function to be executed if the node is not loaded due to an error - used internally. You should wait for the load_node
event.
This function converts JSON nodes to the DOM structure required by jstree. Returns a jQuery object.
+mixed
node
+ This can be a tree node in the JSON format described above, or an array of such JSON nodes, may also be a string.
+mixed
node
+ This is the DOM node, jQuery node or selector pointing to the element for which data is parsed. -1
means root nodes.
bool
is_callback
+ Specifies if the function is called recursively - used ONLY internally.
+This function returns an array of tree nodes converted back to JSON.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want returned. Use -1
or omit to get the whole tree.
array
li_attr
+ The attributes to collect from the LI
node. Defaults to [ "id" , "class" ]
array
a_attr
+ The attributes to collect from the A
node. Defaults to [ ]
boolean
is_callback
+ Used internally.
+The languages
plugin enables multilanguage trees. This means that each node has a specified number of titles - each in a different "language". Only one language set is visible at any given time. This is useful for maintaining the same structure in many languages (hence the name of the plugin)
Expects an array of language codes. Each of the items is used as a CSS class name, so make sure you specify only valid CSS class name strings. The first langauge will be visible onload. For example:
+[ "en", "de", "bg" ]
Check your data plugin documentation (html_data, xml_data, json_data) or take a close look at these examples for information on how to specify multilanguage nodes.
+ +Set the tree's visible language. Triggers an event.
+string
number
lang
+ Either the language code string (as specified in the config) or an index from the config array.
+Returns the name of the currently visible language.
+ +Returns the needed string from the core config object. Overwrites the get_string function from the core. If the key does not exist in that language, but exists in the root of the object - that is returned, if even that does not exist - the key itself is returned.
+string
key
+ The name of the string you are looking for. If you want to use the localize option just set the strings core config option to an object like this one: strings : { "lang-code-here" : { "string-key" : "string-value" ... }, "other-lang" : { ... } }
, otherwise _get_strings won't be affected.
string
lang
+ The language code string (as specified in the config) to get the key in. If not specified the currently visible language is used.
+Returns the title of a node. Overwrites the get_text function from the core.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element whose title you need.
+string
lang
+ The language code string (as specified in the config) to get the title in. If you omit this - the currently visible language is used.
+Sets the title of a node. Overwrites the set_text function from the core. This is used internally - you should use rename_node. Since rename_node
uses set_text
internally you can pass a language string as a third parameter to rename_node.
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element whose title you want to change.
+string
text
+ The new title.
+string
lang
+ The language code string (as specified in the config) to get the title in. If you omit this - the currently visible language is used.
+used only internally to include the CSS necessary for the plugin onload.
+ +Overwrites the create_node function from the core. To create a node with a few titles use an array for the data
property of the js
parameter:
{ "data" : [ { "title" : "EN title", language : "en" }, { "title" : "BG заглавие", language : "bg" } ] }
The search
plugin enables searching for nodes whose title contains a given string, works on async trees too. All found nodes get the jstree-search
class applied to their contained a
nodes - you can use that class to style search results.
The method to use for searching. The other options bundled with jstree are "jstree_contains"
(case insensitive search) and "jstree_title_contains"
(case insensitive based on the title tag of the A node). For multiple word search take a look this: https://github.com/vakata/jstree/issues/10 - you can easily write your own method too.
If set to true
all non-matching nodes are hidden and only the matching nodes (and their parents) are left visible, until the search is cleared. Keep in mind show_only_matches
is heavy on the browser/DOM and is still experimental.
This object can be used to make a request to the server on each search - useful if you are using async trees. That way you can return an array of IDs that need to be loaded before the actual DOM search is performed (so that all the nodes that will match the search are loaded). For example if the user searches for "string", you get that on the server side, check the database and find out that there is a node containing that string. But the node is the child of some other node, etc - so in your response you must return the path to the node (without the node itself) as ids: ["#root_node","#child_node_3"]
. This means that jstree will load those two nodes before doing the client side search, ensuring that your node will be visible.
The ajax config object is pretty much the same as the jQuery ajax settings object.
+You can set the data
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the search string as a paramater. Whatever you return in the function will be sent to the server as data.
You can set the url
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the search string as a paramater. Whatever you return in the function will be used as the URL of the ajax request.
The error
and success
functions (if present) also fire in the context of the tree, and if you return a value in the success
function it will be used as the array of IDs.
Do not open the node - instead - just press the button.
+ + + + +Try pressing the buttons. It will also work with AJAX searching.
+ + + + +Searches for nodes matching the supplied string. Triggers an event.
+string
str
+ The string to search for.
+boolean
skip_async
+ If set to true
- skip the async search (if setup in the config). This is used mostly internally.
Clears the current search. This function is automatically called when doing a new search. Triggers an event.
+ +Used internally if async is setup in the config. This functions loads the nodes returned by the server one by one.
+ +The sort
enables jstree to automatically sort all nodes using a specified function. This means that when the user creates, renames or moves nodes around - they will automatically sort.
Expects a function. The functions receives two arguments - two nodes to be compared. Return -1
or 1
(or any other different from -1). Default is:
function (a, b) { return this.get_text(a) > this.get_text(b) ? 1 : -1; }
Sorts the children of the specified node - this function is called automatically.
+mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element.
+clipboardSwf
is configured.
+ */
+ copyToClipboard : function(highlighter)
+ {
+ var flashDiv, flashSwf,
+ highlighterId = highlighter.id
+ ;
+
+ this.create = function()
+ {
+ var config = sh.config;
+
+ // disable functionality if running locally
+ if (config.clipboardSwf == null)
+ return null;
+
+ function params(list)
+ {
+ var result = '';
+
+ for (var name in list)
+ result += "";
+
+ return result;
+ };
+
+ function attributes(list)
+ {
+ var result = '';
+
+ for (var name in list)
+ result += " " + name + "='" + list[name] + "'";
+
+ return result;
+ };
+
+ var args1 = {
+ width : config.toolbarItemWidth,
+ height : config.toolbarItemHeight,
+ id : highlighterId + '_clipboard',
+ type : 'application/x-shockwave-flash',
+ title : sh.config.strings.copyToClipboard
+ },
+
+ // these arguments are used in IE's collection
+ args2 = {
+ allowScriptAccess : 'always',
+ wmode : 'transparent',
+ flashVars : 'highlighterId=' + highlighterId,
+ menu : 'false'
+ },
+ swf = config.clipboardSwf,
+ html
+ ;
+
+ if (/msie/i.test(navigator.userAgent))
+ {
+ html = ''
+ ;
+ }
+ else
+ {
+ html = ''
+ ;
+ }
+
+ flashDiv = document.createElement('div');
+ flashDiv.innerHTML = html;
+
+ return flashDiv;
+ };
+
+ this.execute = function(sender, event, args)
+ {
+ var command = args.command;
+
+ switch (command)
+ {
+ case 'get':
+ var code = sh.utils.unindent(
+ sh.utils.fixInputString(highlighter.originalCode)
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/&/g, '&')
+ );
+
+ if(window.clipboardData)
+ // will fall through to the confirmation because there isn't a break
+ window.clipboardData.setData('text', code);
+ else
+ return sh.utils.unindent(code);
+
+ case 'ok':
+ sh.utils.alert(sh.config.strings.copyToClipboardConfirmation);
+ break;
+
+ case 'error':
+ sh.utils.alert(args.message);
+ break;
+ }
+ };
+ },
+
+ /** Command to print the colored source code. */
+ printSource : function(highlighter)
+ {
+ this.create = function()
+ {
+ return sh.config.strings.print;
+ };
+
+ this.execute = function(sender, event, args)
+ {
+ var iframe = document.createElement('IFRAME'),
+ doc = null
+ ;
+
+ // make sure there is never more than one hidden iframe created by SH
+ if (sh.vars.printFrame != null)
+ document.body.removeChild(sh.vars.printFrame);
+
+ sh.vars.printFrame = iframe;
+
+ // this hides the iframe
+ iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;';
+
+ document.body.appendChild(iframe);
+ doc = iframe.contentWindow.document;
+
+ copyStyles(doc, window.document);
+ doc.write('
tag with given style applied to it.
+ *
+ * @param {String} str Input string.
+ * @param {String} css Style name to apply to the string.
+ * @return {String} Returns input string with each line surrounded by tag.
+ */
+ decorate: function(str, css)
+ {
+ if (str == null || str.length == 0 || str == '\n')
+ return str;
+
+ str = str.replace(/... to them so that
+ // leading spaces aren't included.
+ if (css != null)
+ str = sh.utils.eachLine(str, function(line)
+ {
+ if (line.length == 0)
+ return '';
+
+ var spaces = '';
+
+ line = line.replace(/^( | )+/, function(s)
+ {
+ spaces = s;
+ return '';
+ });
+
+ if (line.length == 0)
+ return spaces;
+
+ return spaces + '' + line + '
';
+ });
+
+ return str;
+ },
+
+ /**
+ * Pads number with zeros until it's length is the same as given length.
+ *
+ * @param {Number} number Number to pad.
+ * @param {Number} length Max string length with.
+ * @return {String} Returns a string padded with proper amount of '0'.
+ */
+ padNumber : function(number, length)
+ {
+ var result = number.toString();
+
+ while (result.length < length)
+ result = '0' + result;
+
+ return result;
+ },
+
+ /**
+ * Measures width of a single space character.
+ * @return {Number} Returns width of a single space character.
+ */
+ measureSpace : function()
+ {
+ var container = document.createElement('div'),
+ span,
+ result = 0,
+ body = document.body,
+ id = sh.utils.guid('measureSpace'),
+
+ // variable names will be compressed, so it's better than a plain string
+ divOpen = 'regexList
collection.
+ * @return {Array} Returns a list of Match objects.
+ */
+ getMatches: function(code, regexInfo)
+ {
+ function defaultAdd(match, regexInfo)
+ {
+ return [new sh.Match(match[0], match.index, regexInfo.css)];
+ };
+
+ var index = 0,
+ match = null,
+ result = [],
+ func = regexInfo.func ? regexInfo.func : defaultAdd
+ ;
+
+ while((match = regexInfo.regex.exec(code)) != null)
+ result = result.concat(func(match, regexInfo));
+
+ return result;
+ },
+
+ processUrls: function(code)
+ {
+ var lt = '<',
+ gt = '>'
+ ;
+
+ return code.replace(sh.regexLib.url, function(m)
+ {
+ var suffix = '', prefix = '';
+
+ // We include < and > in the URL for the common cases like ' + lineNumber + ' | ' : '')
+ + ''
+ + (spaces != null ? '' + spaces.replace(' ', ' ') + ' ' : '')
+ + line
+ + ' | '
+ + '
.*?)" +
+ "(?" + regexGroup.right.source + ")",
+ "sgi"
+ )
+ };
+ }
+}; // end of Highlighter
+
+return sh;
+}(); // end of anonymous function
+
+
+/**
+ * XRegExp 0.6.1
+ * (c) 2007-2008 Steven Levithan
+ *
+ * MIT License
+ *
+ * provides an augmented, cross-browser implementation of regular expressions
+ * including support for additional modifiers and syntax. several convenience
+ * methods and a recursive-construct parser are also included.
+ */
+
+// prevent running twice, which would break references to native globals
+if (!window.XRegExp) {
+// anonymous function to avoid global variables
+(function () {
+// copy various native globals for reference. can't use the name ``native``
+// because it's a reserved JavaScript keyword.
+var real = {
+ exec: RegExp.prototype.exec,
+ match: String.prototype.match,
+ replace: String.prototype.replace,
+ split: String.prototype.split
+ },
+ /* regex syntax parsing with support for all the necessary cross-
+ browser and context issues (escapings, character classes, etc.) */
+ lib = {
+ part: /(?:[^\\([#\s.]+|\\(?!k<[\w$]+>|[pP]{[^}]+})[\S\s]?|\((?=\?(?!#|<[\w$]+>)))+|(\()(?:\?(?:(#)[^)]*\)|<([$\w]+)>))?|\\(?:k<([\w$]+)>|[pP]{([^}]+)})|(\[\^?)|([\S\s])/g,
+ replaceVar: /(?:[^$]+|\$(?![1-9$&`']|{[$\w]+}))+|\$(?:([1-9]\d*|[$&`'])|{([$\w]+)})/g,
+ extended: /^(?:\s+|#.*)+/,
+ quantifier: /^(?:[?*+]|{\d+(?:,\d*)?})/,
+ classLeft: /&&\[\^?/g,
+ classRight: /]/g
+ },
+ indexOf = function (array, item, from) {
+ for (var i = from || 0; i < array.length; i++)
+ if (array[i] === item) return i;
+ return -1;
+ },
+ brokenExecUndef = /()??/.exec("")[1] !== undefined,
+ plugins = {};
+
+/**
+ * Accepts a pattern and flags, returns a new, extended RegExp object.
+ * differs from a native regex in that additional flags and syntax are
+ * supported and browser inconsistencies are ameliorated.
+ * @ignore
+ */
+XRegExp = function (pattern, flags) {
+ if (pattern instanceof RegExp) {
+ if (flags !== undefined)
+ throw TypeError("can't supply flags when constructing one RegExp from another");
+ return pattern.addFlags(); // new copy
+ }
+
+ var flags = flags || "",
+ singleline = flags.indexOf("s") > -1,
+ extended = flags.indexOf("x") > -1,
+ hasNamedCapture = false,
+ captureNames = [],
+ output = [],
+ part = lib.part,
+ match, cc, len, index, regex;
+
+ part.lastIndex = 0; // in case the last XRegExp compilation threw an error (unbalanced character class)
+
+ while (match = real.exec.call(part, pattern)) {
+ // comment pattern. this check must come before the capturing group check,
+ // because both match[1] and match[2] will be non-empty.
+ if (match[2]) {
+ // keep tokens separated unless the following token is a quantifier
+ if (!lib.quantifier.test(pattern.slice(part.lastIndex)))
+ output.push("(?:)");
+ // capturing group
+ } else if (match[1]) {
+ captureNames.push(match[3] || null);
+ if (match[3])
+ hasNamedCapture = true;
+ output.push("(");
+ // named backreference
+ } else if (match[4]) {
+ index = indexOf(captureNames, match[4]);
+ // keep backreferences separate from subsequent literal numbers
+ // preserve backreferences to named groups that are undefined at this point as literal strings
+ output.push(index > -1 ?
+ "\\" + (index + 1) + (isNaN(pattern.charAt(part.lastIndex)) ? "" : "(?:)") :
+ match[0]
+ );
+ // unicode element (requires plugin)
+ } else if (match[5]) {
+ output.push(plugins.unicode ?
+ plugins.unicode.get(match[5], match[0].charAt(1) === "P") :
+ match[0]
+ );
+ // character class opening delimiter ("[" or "[^")
+ // (non-native unicode elements are not supported within character classes)
+ } else if (match[6]) {
+ if (pattern.charAt(part.lastIndex) === "]") {
+ // for cross-browser compatibility with ECMA-262 v3 behavior,
+ // convert [] to (?!) and [^] to [\S\s].
+ output.push(match[6] === "[" ? "(?!)" : "[\\S\\s]");
+ part.lastIndex++;
+ } else {
+ // parse the character class with support for inner escapes and
+ // ES4's infinitely nesting intersection syntax ([&&[^&&[]]]).
+ cc = XRegExp.matchRecursive("&&" + pattern.slice(match.index), lib.classLeft, lib.classRight, "", {escapeChar: "\\"})[0];
+ output.push(match[6] + cc + "]");
+ part.lastIndex += cc.length + 1;
+ }
+ // dot ("."), pound sign ("#"), or whitespace character
+ } else if (match[7]) {
+ if (singleline && match[7] === ".") {
+ output.push("[\\S\\s]");
+ } else if (extended && lib.extended.test(match[7])) {
+ len = real.exec.call(lib.extended, pattern.slice(part.lastIndex - 1))[0].length;
+ // keep tokens separated unless the following token is a quantifier
+ if (!lib.quantifier.test(pattern.slice(part.lastIndex - 1 + len)))
+ output.push("(?:)");
+ part.lastIndex += len - 1;
+ } else {
+ output.push(match[7]);
+ }
+ } else {
+ output.push(match[0]);
+ }
+ }
+
+ regex = RegExp(output.join(""), real.replace.call(flags, /[sx]+/g, ""));
+ regex._x = {
+ source: pattern,
+ captureNames: hasNamedCapture ? captureNames : null
+ };
+ return regex;
+};
+
+/**
+ * Barebones plugin support for now (intentionally undocumented)
+ * @ignore
+ * @param {Object} name
+ * @param {Object} o
+ */
+XRegExp.addPlugin = function (name, o) {
+ plugins[name] = o;
+};
+
+/**
+ * Adds named capture support, with values returned as ``result.name``.
+ *
+ * Also fixes two cross-browser issues, following the ECMA-262 v3 spec:
+ * - captured values for non-participating capturing groups should be returned
+ * as ``undefined``, rather than the empty string.
+ * - the regex's ``lastIndex`` should not be incremented after zero-length
+ * matches.
+ * @ignore
+ */
+RegExp.prototype.exec = function (str) {
+ var match = real.exec.call(this, str),
+ name, i, r2;
+ if (match) {
+ // fix browsers whose exec methods don't consistently return
+ // undefined for non-participating capturing groups
+ if (brokenExecUndef && match.length > 1) {
+ // r2 doesn't need /g or /y, but they shouldn't hurt
+ r2 = new RegExp("^" + this.source + "$(?!\\s)", this.getNativeFlags());
+ real.replace.call(match[0], r2, function () {
+ for (i = 1; i < arguments.length - 2; i++) {
+ if (arguments[i] === undefined) match[i] = undefined;
+ }
+ });
+ }
+ // attach named capture properties
+ if (this._x && this._x.captureNames) {
+ for (i = 1; i < match.length; i++) {
+ name = this._x.captureNames[i - 1];
+ if (name) match[name] = match[i];
+ }
+ }
+ // fix browsers that increment lastIndex after zero-length matches
+ if (this.global && this.lastIndex > (match.index + match[0].length))
+ this.lastIndex--;
+ }
+ return match;
+};
+})(); // end anonymous function
+} // end if(!window.XRegExp)
+
+/**
+ * intentionally undocumented
+ * @ignore
+ */
+RegExp.prototype.getNativeFlags = function () {
+ return (this.global ? "g" : "") +
+ (this.ignoreCase ? "i" : "") +
+ (this.multiline ? "m" : "") +
+ (this.extended ? "x" : "") +
+ (this.sticky ? "y" : "");
+};
+
+/**
+ * Accepts flags; returns a new XRegExp object generated by recompiling
+ * the regex with the additional flags (may include non-native flags).
+ * The original regex object is not altered.
+ * @ignore
+ */
+RegExp.prototype.addFlags = function (flags) {
+ var regex = new XRegExp(this.source, (flags || "") + this.getNativeFlags());
+ if (this._x) {
+ regex._x = {
+ source: this._x.source,
+ captureNames: this._x.captureNames ? this._x.captureNames.slice(0) : null
+ };
+ }
+ return regex;
+};
+
+/**
+ * Accepts a context object and string; returns the result of calling
+ * ``exec`` with the provided string. the context is ignored but is
+ * accepted for congruity with ``Function.prototype.call``.
+ * @ignore
+ */
+RegExp.prototype.call = function (context, str) {
+ return this.exec(str);
+};
+
+/**
+ * Accepts a context object and arguments array; returns the result of
+ * calling ``exec`` with the first value in the arguments array. the context
+ * is ignored but is accepted for congruity with ``Function.prototype.apply``.
+ * @ignore
+ */
+RegExp.prototype.apply = function (context, args) {
+ return this.exec(args[0]);
+};
+
+/**
+ * Accepts a pattern and flags; returns an XRegExp object. if the pattern
+ * and flag combination has previously been cached, the cached copy is
+ * returned, otherwise the new object is cached.
+ * @ignore
+ */
+XRegExp.cache = function (pattern, flags) {
+ var key = "/" + pattern + "/" + (flags || "");
+ return XRegExp.cache[key] || (XRegExp.cache[key] = new XRegExp(pattern, flags));
+};
+
+/**
+ * Accepts a string; returns the string with regex metacharacters escaped.
+ * the returned string can safely be used within a regex to match a literal
+ * string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $,
+ * |, #, [comma], and whitespace.
+ * @ignore
+ */
+XRegExp.escape = function (str) {
+ return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
+};
+
+/**
+ * Accepts a string to search, left and right delimiters as regex pattern
+ * strings, optional regex flags (may include non-native s, x, and y flags),
+ * and an options object which allows setting an escape character and changing
+ * the return format from an array of matches to a two-dimensional array of
+ * string parts with extended position data. returns an array of matches
+ * (optionally with extended data), allowing nested instances of left and right
+ * delimiters. use the g flag to return all matches, otherwise only the first
+ * is returned. if delimiters are unbalanced within the subject data, an error
+ * is thrown.
+ *
+ * This function admittedly pushes the boundaries of what can be accomplished
+ * sensibly without a "real" parser. however, by doing so it provides flexible
+ * and powerful recursive parsing capabilities with minimal code weight.
+ *
+ * Warning: the ``escapeChar`` option is considered experimental and might be
+ * changed or removed in future versions of XRegExp.
+ *
+ * unsupported features:
+ * - backreferences within delimiter patterns when using ``escapeChar``.
+ * - although providing delimiters as regex objects adds the minor feature of
+ * independent delimiter flags, it introduces other limitations and is only
+ * intended to be done by the ``XRegExp`` constructor (which can't call
+ * itself while building a regex).
+ *
+ * @ignore
+ */
+XRegExp.matchRecursive = function (str, left, right, flags, options) {
+ var options = options || {},
+ escapeChar = options.escapeChar,
+ vN = options.valueNames,
+ flags = flags || "",
+ global = flags.indexOf("g") > -1,
+ ignoreCase = flags.indexOf("i") > -1,
+ multiline = flags.indexOf("m") > -1,
+ sticky = flags.indexOf("y") > -1,
+ /* sticky mode has its own handling in this function, which means you
+ can use flag "y" even in browsers which don't support it natively */
+ flags = flags.replace(/y/g, ""),
+ left = left instanceof RegExp ? (left.global ? left : left.addFlags("g")) : new XRegExp(left, "g" + flags),
+ right = right instanceof RegExp ? (right.global ? right : right.addFlags("g")) : new XRegExp(right, "g" + flags),
+ output = [],
+ openTokens = 0,
+ delimStart = 0,
+ delimEnd = 0,
+ lastOuterEnd = 0,
+ outerStart, innerStart, leftMatch, rightMatch, escaped, esc;
+
+ if (escapeChar) {
+ if (escapeChar.length > 1) throw SyntaxError("can't supply more than one escape character");
+ if (multiline) throw TypeError("can't supply escape character when using the multiline flag");
+ escaped = XRegExp.escape(escapeChar);
+ /* Escape pattern modifiers:
+ /g - not needed here
+ /i - included
+ /m - **unsupported**, throws error
+ /s - handled by XRegExp when delimiters are provided as strings
+ /x - handled by XRegExp when delimiters are provided as strings
+ /y - not needed here; supported by other handling in this function
+ */
+ esc = new RegExp(
+ "^(?:" + escaped + "[\\S\\s]|(?:(?!" + left.source + "|" + right.source + ")[^" + escaped + "])+)+",
+ ignoreCase ? "i" : ""
+ );
+ }
+
+ while (true) {
+ /* advance the starting search position to the end of the last delimiter match.
+ a couple special cases are also covered:
+ - if using an escape character, advance to the next delimiter's starting position,
+ skipping any escaped characters
+ - first time through, reset lastIndex in case delimiters were provided as regexes
+ */
+ left.lastIndex = right.lastIndex = delimEnd +
+ (escapeChar ? (esc.exec(str.slice(delimEnd)) || [""])[0].length : 0);
+
+ leftMatch = left.exec(str);
+ rightMatch = right.exec(str);
+
+ // only keep the result which matched earlier in the string
+ if (leftMatch && rightMatch) {
+ if (leftMatch.index <= rightMatch.index)
+ rightMatch = null;
+ else leftMatch = null;
+ }
+
+ /* paths*:
+ leftMatch | rightMatch | openTokens | result
+ 1 | 0 | 1 | ...
+ 1 | 0 | 0 | ...
+ 0 | 1 | 1 | ...
+ 0 | 1 | 0 | throw
+ 0 | 0 | 1 | throw
+ 0 | 0 | 0 | break
+ * - does not include the sticky mode special case
+ - the loop ends after the first completed match if not in global mode
+ */
+
+ if (leftMatch || rightMatch) {
+ delimStart = (leftMatch || rightMatch).index;
+ delimEnd = (leftMatch ? left : right).lastIndex;
+ } else if (!openTokens) {
+ break;
+ }
+
+ if (sticky && !openTokens && delimStart > lastOuterEnd)
+ break;
+
+ if (leftMatch) {
+ if (!openTokens++) {
+ outerStart = delimStart;
+ innerStart = delimEnd;
+ }
+ } else if (rightMatch && openTokens) {
+ if (!--openTokens) {
+ if (vN) {
+ if (vN[0] && outerStart > lastOuterEnd)
+ output.push([vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart]);
+ if (vN[1]) output.push([vN[1], str.slice(outerStart, innerStart), outerStart, innerStart]);
+ if (vN[2]) output.push([vN[2], str.slice(innerStart, delimStart), innerStart, delimStart]);
+ if (vN[3]) output.push([vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd]);
+ } else {
+ output.push(str.slice(innerStart, delimStart));
+ }
+ lastOuterEnd = delimEnd;
+ if (!global)
+ break;
+ }
+ } else {
+ // reset lastIndex in case delimiters were provided as regexes
+ left.lastIndex = right.lastIndex = 0;
+ throw Error("subject data contains unbalanced delimiters");
+ }
+
+ // if the delimiter matched an empty string, advance delimEnd to avoid an infinite loop
+ if (delimStart === delimEnd)
+ delimEnd++;
+ }
+
+ if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd)
+ output.push([vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length]);
+
+ // reset lastIndex in case delimiters were provided as regexes
+ left.lastIndex = right.lastIndex = 0;
+
+ return output;
+};
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.0.320 (May 03 2009)
+ *
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ *
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter. If not, see .
+ */
+SyntaxHighlighter.brushes.Xml = function()
+{
+ function process(match, regexInfo)
+ {
+ var constructor = SyntaxHighlighter.Match,
+ code = match[0],
+ tag = new XRegExp('(<|<)[\\s\\/\\?]*(?[:\\w-\\.]+)', 'xg').exec(code),
+ result = []
+ ;
+
+ if (match.attributes != null)
+ {
+ var attributes,
+ regex = new XRegExp('(? [\\w:\\-\\.]+)' +
+ '\\s*=\\s*' +
+ '(? ".*?"|\'.*?\'|\\w+)',
+ 'xg');
+
+ while ((attributes = regex.exec(code)) != null)
+ {
+ result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
+ result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
+ }
+ }
+
+ if (tag != null)
+ result.push(
+ new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword')
+ );
+
+ return result;
+ }
+
+ this.regexList = [
+ { regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, //
+ { regex: new XRegExp('(\\<|<)!--\\s*.*?\\s*--(\\>|>)', 'gm'), css: 'comments' }, //
+ { regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process }
+ ];
+};
+
+SyntaxHighlighter.brushes.Xml.prototype = new SyntaxHighlighter.Highlighter();
+SyntaxHighlighter.brushes.Xml.aliases = ['xml', 'xhtml', 'xslt', 'html', 'xhtml'];
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.0.320 (May 03 2009)
+ *
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ *
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter. If not, see .
+ */
+SyntaxHighlighter.brushes.JScript = function()
+{
+ var keywords = 'break case catch continue ' +
+ 'default delete do else false ' +
+ 'for function if in instanceof ' +
+ 'new null return super switch ' +
+ 'this throw true try typeof var while with'
+ ;
+
+ this.regexList = [
+ { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments
+ { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
+ { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings
+ { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings
+ { regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion
+ { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords
+ ];
+
+ this.forHtmlScript(SyntaxHighlighter.regexLib.scriptScriptTags);
+};
+
+SyntaxHighlighter.brushes.JScript.prototype = new SyntaxHighlighter.Highlighter();
+SyntaxHighlighter.brushes.JScript.aliases = ['js', 'jscript', 'javascript'];
+
+
+SyntaxHighlighter.config.clipboardSwf = 'syntax/clipboard.swf';
+$(function () {
+ var divs = $([]);
+ $("#container .source").each(function () {
+ var code = $(this).html().replace(//g,'>'),
+ div = $('' + code + '
'),
+ demo = $(this).prevAll(".demo:eq(0)");
+ $(this).after(div);
+ if(!$(this).hasClass("below")) divs = divs.add(div);
+ });
+ SyntaxHighlighter.all();
+
+ setTimeout((function (divs) {
+ return function () {
+ divs.each(function () {
+ var div = $(this),
+ demo = $(this).prevAll(".demo:eq(0)"),
+ h = false;
+ var h = Math.max(demo[0].offsetHeight, div[0].offsetHeight);
+ if(h) {
+ if(h < 198) h = 198;
+ div.height(h);
+ demo.height(h);
+ }
+ });
+ }
+ })(divs), 500);
+
+ // $(".panel").hide().prev().click(function () { $(this).next().toggle(); }).css("cursor","pointer");
+});
\ No newline at end of file
diff --git a/thirdparty/jstree/_docs/syntax/!style.css b/thirdparty/jstree/_docs/syntax/!style.css
new file mode 100644
index 000000000..ed3cafd9a
--- /dev/null
+++ b/thirdparty/jstree/_docs/syntax/!style.css
@@ -0,0 +1,511 @@
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.1.364 (October 15 2009)
+ *
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ *
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter. If not, see .
+ */
+.syntaxhighlighter,
+.syntaxhighlighter div,
+.syntaxhighlighter code,
+.syntaxhighlighter table,
+.syntaxhighlighter table td,
+.syntaxhighlighter table tr,
+.syntaxhighlighter table tbody
+{
+ margin: 0 !important;
+ padding: 0 !important;
+ border: 0 !important;
+ outline: 0 !important;
+ background: none !important;
+ text-align: left !important;
+ float: none !important;
+ vertical-align: baseline !important;
+ position: static !important;
+ left: auto !important;
+ top: auto !important;
+ right: auto !important;
+ bottom: auto !important;
+ height: auto !important;
+ width: auto !important;
+ font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
+ font-weight: normal !important;
+ font-style: normal !important;
+ min-height: inherit !important; /* For IE8, FF & WebKit */
+ min-height: auto !important; /* For IE7 */
+
+
+/*
+ line-height: 1.1em !important;
+ font-size: 1em !important;
+*/
+
+ font-size:12px !important;
+ line-height:18px !important;
+
+}
+
+.syntaxhighlighter
+{
+ width: 99.9% !important; /* 99% fixes IE8 horizontal scrollbar */
+ margin: 1em 0 1em 0 !important;
+ padding: 1px !important; /* adds a little border on top and bottom */
+ position: relative !important;
+}
+
+.syntaxhighlighter .bold
+{
+ font-weight: bold !important;
+}
+
+.syntaxhighlighter .italic
+{
+ font-style: italic !important;
+}
+
+.syntaxhighlighter .line
+{
+}
+
+.syntaxhighlighter .no-wrap .line .content
+{
+ white-space: pre !important;
+}
+
+.syntaxhighlighter .line table
+{
+ border-collapse: collapse !important;
+}
+
+.syntaxhighlighter .line td
+{
+ vertical-align: top !important;
+}
+
+.syntaxhighlighter .line .number
+{
+ width: 3em !important;
+}
+
+.syntaxhighlighter .line .number code
+{
+ width: 2.7em !important;
+ padding-right: .3em !important;
+ text-align: right !important;
+ display: block !important;
+}
+
+.syntaxhighlighter .line .content
+{
+ padding-left: .5em !important;
+}
+
+.syntaxhighlighter .line .spaces
+{
+}
+
+/* Disable border and margin on the lines when no gutter option is set */
+.syntaxhighlighter.nogutter .line .content
+{
+ border-left: none !important;
+}
+
+.syntaxhighlighter .bar
+{
+ display: none !important;
+}
+
+.syntaxhighlighter .bar.show
+{
+ display: block !important;
+}
+
+.syntaxhighlighter.collapsed .bar
+{
+ display: block !important;
+}
+
+/* Adjust some properties when collapsed */
+
+.syntaxhighlighter.collapsed .lines
+{
+ display: none !important;
+}
+
+.syntaxhighlighter .lines.no-wrap
+{
+ overflow: auto !important;
+ overflow-y: hidden !important;
+}
+
+/* Styles for the toolbar */
+
+.syntaxhighlighter .toolbar
+{
+ position: absolute !important;
+ right: 0px !important;
+ top: 0px !important;
+ font-size: 1px !important;
+ padding: 8px 8px 8px 0 !important; /* in px because images don't scale with ems */
+}
+
+.syntaxhighlighter.collapsed .toolbar
+{
+ font-size: 80% !important;
+ padding: .2em 0 .5em .5em !important;
+ position: static !important;
+}
+
+.syntaxhighlighter .toolbar a.item,
+.syntaxhighlighter .toolbar .item
+{
+ display: block !important;
+ float: left !important;
+ margin-left: 8px !important;
+ background-repeat: no-repeat !important;
+ overflow: hidden !important;
+ text-indent: -5000px !important;
+}
+
+.syntaxhighlighter.collapsed .toolbar .item
+{
+ display: none !important;
+}
+
+.syntaxhighlighter.collapsed .toolbar .item.expandSource
+{
+ background-image: url(magnifier.png) !important;
+ display: inline !important;
+ text-indent: 0 !important;
+ width: auto !important;
+ float: none !important;
+ height: 16px !important;
+ padding-left: 20px !important;
+}
+
+.syntaxhighlighter .toolbar .item.viewSource
+{
+ background-image: url(page_white_code.png) !important;
+}
+
+.syntaxhighlighter .toolbar .item.printSource
+{
+ background-image: url(printer.png) !important;
+}
+
+.syntaxhighlighter .toolbar .item.copyToClipboard
+{
+ text-indent: 0 !important;
+ background: none !important;
+ overflow: visible !important;
+}
+
+.syntaxhighlighter .toolbar .item.about
+{
+ background-image: url(help.png) !important;
+}
+
+/**
+ * Print view.
+ * Colors are based on the default theme without background.
+ */
+
+.syntaxhighlighter.printing,
+.syntaxhighlighter.printing .line.alt1 .content,
+.syntaxhighlighter.printing .line.alt2 .content,
+.syntaxhighlighter.printing .line.highlighted .number,
+.syntaxhighlighter.printing .line.highlighted.alt1 .content,
+.syntaxhighlighter.printing .line.highlighted.alt2 .content,
+{
+ background: none !important;
+}
+
+/* Gutter line numbers */
+.syntaxhighlighter.printing .line .number
+{
+ color: #bbb !important;
+}
+
+/* Add border to the lines */
+.syntaxhighlighter.printing .line .content
+{
+ color: #000 !important;
+}
+
+/* Toolbar when visible */
+.syntaxhighlighter.printing .toolbar
+{
+ display: none !important;
+}
+
+.syntaxhighlighter.printing a
+{
+ text-decoration: none !important;
+}
+
+.syntaxhighlighter.printing .plain,
+.syntaxhighlighter.printing .plain a
+{
+ color: #000 !important;
+}
+
+.syntaxhighlighter.printing .comments,
+.syntaxhighlighter.printing .comments a
+{
+ color: #008200 !important;
+}
+
+.syntaxhighlighter.printing .string,
+.syntaxhighlighter.printing .string a
+{
+ color: blue !important;
+}
+
+.syntaxhighlighter.printing .keyword
+{
+ color: #069 !important;
+ font-weight: bold !important;
+}
+
+.syntaxhighlighter.printing .preprocessor
+{
+ color: gray !important;
+}
+
+.syntaxhighlighter.printing .variable
+{
+ color: #a70 !important;
+}
+
+.syntaxhighlighter.printing .value
+{
+ color: #090 !important;
+}
+
+.syntaxhighlighter.printing .functions
+{
+ color: #ff1493 !important;
+}
+
+.syntaxhighlighter.printing .constants
+{
+ color: #0066CC !important;
+}
+
+.syntaxhighlighter.printing .script
+{
+ font-weight: bold !important;
+}
+
+.syntaxhighlighter.printing .color1,
+.syntaxhighlighter.printing .color1 a
+{
+ color: #808080 !important;
+}
+
+.syntaxhighlighter.printing .color2,
+.syntaxhighlighter.printing .color2 a
+{
+ color: #ff1493 !important;
+}
+
+.syntaxhighlighter.printing .color3,
+.syntaxhighlighter.printing .color3 a
+{
+ color: red !important;
+}
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.1.364 (October 15 2009)
+ *
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ *
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter. If not, see .
+ */
+/************************************
+ * Default Syntax Highlighter theme.
+ *
+ * Interface elements.
+ ************************************/
+
+.syntaxhighlighter
+{
+ background-color: #fff !important;
+}
+
+/* Highlighed line number */
+.syntaxhighlighter .line.highlighted .number
+{
+ color: black !important;
+}
+
+/* Highlighed line */
+.syntaxhighlighter .line.highlighted.alt1,
+.syntaxhighlighter .line.highlighted.alt2
+{
+ background-color: #e0e0e0 !important;
+}
+
+/* Gutter line numbers */
+.syntaxhighlighter .line .number
+{
+ color: #afafaf !important;
+}
+
+/* Add border to the lines */
+.syntaxhighlighter .line .content
+{
+ border-left: 1px solid gray !important;
+ color: #000 !important;
+}
+
+.syntaxhighlighter.printing .line .content
+{
+ border: 0 !important;
+}
+
+/* First line */
+.syntaxhighlighter .line.alt1
+{
+ background-color: #fff !important;
+}
+
+/* Second line */
+.syntaxhighlighter .line.alt2
+{
+ background-color: #F8F8F8 !important;
+}
+
+.syntaxhighlighter .toolbar
+{
+ background-color: #F8F8F8 !important;
+ border: #E7E5DC solid 1px !important;
+}
+
+.syntaxhighlighter .toolbar a
+{
+ color: #a0a0a0 !important;
+}
+
+.syntaxhighlighter .toolbar a:hover
+{
+ color: red !important;
+}
+
+/************************************
+ * Actual syntax highlighter colors.
+ ************************************/
+.syntaxhighlighter .plain,
+.syntaxhighlighter .plain a
+{
+ color: #000 !important;
+}
+
+.syntaxhighlighter .comments,
+.syntaxhighlighter .comments a
+{
+ color: #008200 !important;
+}
+
+.syntaxhighlighter .string,
+.syntaxhighlighter .string a
+{
+ color: blue !important;
+}
+
+.syntaxhighlighter .keyword
+{
+ color: #069 !important;
+ font-weight: bold !important;
+}
+
+.syntaxhighlighter .preprocessor
+{
+ color: gray !important;
+}
+
+.syntaxhighlighter .variable
+{
+ color: #a70 !important;
+}
+
+.syntaxhighlighter .value
+{
+ color: #090 !important;
+}
+
+.syntaxhighlighter .functions
+{
+ color: #ff1493 !important;
+}
+
+.syntaxhighlighter .constants
+{
+ color: #0066CC !important;
+}
+
+.syntaxhighlighter .script
+{
+ background-color: yellow !important;
+}
+
+.syntaxhighlighter .color1,
+.syntaxhighlighter .color1 a
+{
+ color: #808080 !important;
+}
+
+.syntaxhighlighter .color2,
+.syntaxhighlighter .color2 a
+{
+ color: #ff1493 !important;
+}
+
+.syntaxhighlighter .color3,
+.syntaxhighlighter .color3 a
+{
+ color: red !important;
+}
diff --git a/thirdparty/jstree/_docs/syntax/clipboard.swf b/thirdparty/jstree/_docs/syntax/clipboard.swf
new file mode 100644
index 000000000..1b4d90a0f
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/clipboard.swf differ
diff --git a/thirdparty/jstree/_docs/syntax/help.png b/thirdparty/jstree/_docs/syntax/help.png
new file mode 100644
index 000000000..5c870176d
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/help.png differ
diff --git a/thirdparty/jstree/_docs/syntax/magnifier.png b/thirdparty/jstree/_docs/syntax/magnifier.png
new file mode 100644
index 000000000..cf3d97f75
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/magnifier.png differ
diff --git a/thirdparty/jstree/_docs/syntax/page_white_code.png b/thirdparty/jstree/_docs/syntax/page_white_code.png
new file mode 100644
index 000000000..0c76bd129
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/page_white_code.png differ
diff --git a/thirdparty/jstree/_docs/syntax/page_white_copy.png b/thirdparty/jstree/_docs/syntax/page_white_copy.png
new file mode 100644
index 000000000..a9f31a278
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/page_white_copy.png differ
diff --git a/thirdparty/jstree/_docs/syntax/printer.png b/thirdparty/jstree/_docs/syntax/printer.png
new file mode 100644
index 000000000..a350d1871
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/printer.png differ
diff --git a/thirdparty/jstree/_docs/syntax/wrapping.png b/thirdparty/jstree/_docs/syntax/wrapping.png
new file mode 100644
index 000000000..6972c5e59
Binary files /dev/null and b/thirdparty/jstree/_docs/syntax/wrapping.png differ
diff --git a/thirdparty/jstree/_docs/themeroller.html b/thirdparty/jstree/_docs/themeroller.html
new file mode 100644
index 000000000..934dfe853
--- /dev/null
+++ b/thirdparty/jstree/_docs/themeroller.html
@@ -0,0 +1,107 @@
+
+
+
+
+ jsTree v.1.0 - themeroller documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+jsTree v.1.0
+themeroller plugin
+Description
+
+The themeroller
plugin adds support for jQuery UI's themes. Add the plugin as last in your plugins
config option. Also make sure that you have included the jquery theme you'd like to use and you should NOT use the native jstree themes
plugin.
+If using the search plugin - bind to "search.jstree"
to style the found nodes, or apply some styles to the .jstree-search
class (which is added by default) but make sure the selector is stronger than your current theme or use !important
+
+
+Configuration
+
+opened
+
+The class name to use for open nodes (shows the arrow to close).
+
+closed
+
+The class name to use for closed nodes (shows the arrow to open).
+
+item
+
+The class name to use for the actual items.
+
+item_h
+
+The class name to use for the hovered item.
+
+item_a
+
+The class name to use for selected items (UI plugin).
+
+item_open
+
+The class name to use for the opened items. If set to false
the icon is not shown.
+item_clsd
+
+The class name to use for the opened items. If set to false
the icon is not shown.
+item_leaf
+
+The class name to use for the opened items. If set to false
the icon is not shown.
+
+
+
+
+Demos
+
+
+Using the themeroller plugin
+
+
+ -
+ Root node 1
+
+ -
+ Child node 1
+
+ -
+ Child node 2
+
+
+
+ -
+ Root node 2
+
+
+
+
+
+
+
+API
+
+
+._themeroller ( obj )
+Fixes the tree on various events by applying the configured classes - used internally only.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thirdparty/jstree/_docs/themes.html b/thirdparty/jstree/_docs/themes.html
new file mode 100644
index 000000000..a3318f47e
--- /dev/null
+++ b/thirdparty/jstree/_docs/themes.html
@@ -0,0 +1,127 @@
+
+
+
+
+ jsTree v.1.0 - themes documentation
+
+
+
+
+
+
+
+
+
+
+
+
+jsTree v.1.0
+themes plugin
+Description
+
+The themes
plugin controls the looks of jstree - without this plugin you will get a functional tree, but it will look just like an ordinary UL list.
+
+
+Configuration
+
+theme
+
+The name of the theme to use to style the tree.
+
+url
+
+The location of the theme's CSS file, if set to false
jstree will look for the file in < theme folder >/themes/< theme name >/style.css
. You can set the theme folder using $.jstree._themes = "PATH/TO/FOLDER/";
, otherwise it is autodetected as <jquery.tree.js location>/themes/
.
+
+dots
+
+Whether to show the connecting dots or not.
+
+icons
+
+Whether to show the node icons or not.
+
+
+
+Demos
+
+
+Using the themes plugin
+
+
+
+
+
+
+ -
+ Root node 1
+
+ -
+ Child node 1
+
+ -
+ Child node 2
+
+
+
+ -
+ Root node 2
+
+
+
+
+
+
+
+API
+
+
+.set_theme ( name , url )
+Set the tree's theme. Triggers an event.
+
+ -
+
string
name
+ The name of the theme to use to style the tree.
+
+ -
+
string
url
+ The location of the theme's CSS file, if omitted jstree will look for the file in:
< theme folder >/themes/< name >/style.css
.
You can set the theme folder using:
$.jstree._themes = "PATH/TO/FOLDER/";
, otherwise it is autodetected as <jquery.tree.js location>/themes/
.
+
+
+.get_theme ( )
+Returns the name of the currently active theme.
+
+
+.show_dots ( ), .hide_dots ( ), .toggle_dots ( )
+Show, hide or toggle the visibility of the dots connecting the tree's nodes.
+
+
+.show_icons ( ), .hide_icons ( ), .toggle_icons ( )
+Show, hide or toggle the visibility of the icons next to the title of each the tree node.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thirdparty/jstree/_docs/types.html b/thirdparty/jstree/_docs/types.html
new file mode 100644
index 000000000..620bba2f2
--- /dev/null
+++ b/thirdparty/jstree/_docs/types.html
@@ -0,0 +1,178 @@
+
+
+
+
+ jsTree v.1.0 - types documentation
+
+
+
+
+
+
+
+
+
+
+
+
+jsTree v.1.0
+types plugin
+Description
+
+The types
enables node types - each node can have a type, and you can define rules on how that type should behave - maximum children count, maximum depth, valid children types, selectable or not, etc.
+
+
+Configuration
+
+
+max_children
+
+Defines maximum number of root nodes (-1
means unlimited, -2
means disable max_children checking in the tree).
+
+max_depth
+
+Defines maximum depth of the tree (-1
means unlimited, -2
means disable max_depth checking in the tree).
+
+valid_children
+
+Defines valid root node types (could be "all"
, "none"
, or an array of type strings).
+
+use_data
+
+If set to true
jstree will check every node for $.metadata
or $.data
for rules (valid_children, max_depth & the function rules). Keep in mind jstree will look for this data in $("li-node-here").metadata().jstree.rule_name
(or $.data
respectively).
+
+type_attr
+
+Defines the attribute on each li
node, where the type attribute will be stored. For correct usage in IE - do not assign to "type"
- it triggers an IE bug.
+
+types
+
+Defines all the active types in the tree. Each key is the type name, and each value represents the rules for this type. A default
type is defined - all nodes with no explicit type set are treated as if they were of the default
type.
+
+
+types : {
+ // the default type
+ "default" : {
+ "max_children" : -1,
+ "max_depth" : -1,
+ "valid_children": "all"
+
+ // Bound functions - you can bind any other function here (using boolean or function)
+ //"select_node" : true,
+ //"open_node" : true,
+ //"close_node" : true,
+ //"create_node" : true,
+ //"delete_node" : true
+ }
+}
+
+
+For max_children
, max_depth
& valid_children
use the same values as for the tree, but the value you set will only apply for that node type.
+You can set an icon
key - it should be an object consisting of two keys - image
(string - location of the image to be used as an icon) & position
(string - left and top pixels of the image - 10px 40px, only useful when using sprites - omit otherwise).
+You can set more keys in that object - each key should be a function name, and each value - either a boolean (in order to allow or disallow that operation, on that node type) or a function. If you supply a function - your function will be called with two arguments - the name of the called function (the key) and the arguments passed to that function - you can then decide whether to return true
or false
.
+For any type - for now you can control only functions that take the node being manipulated as the first argument.
+
+
+
+Demos
+
+Using the types plugin
+
+
+
+ -
+ Root node 1
+
+ -
+ Child node 1
+
+ -
+ Child node 2
+
+
+
+ -
+ Root node 2
+
+
+
+
+
+
+
+API
+
+
+._get_type ( node )
+Get the type of a node.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element.
+
+
+
+.set_type ( type , node )
+Set the type of a node. Triggers an event.
+
+ -
+
string
type
+ The new type.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element.
+
+
+
+._check ( rule , node , opts )
+Checks a rule on a give node. Used mostly internally.
+
+ -
+
string
rule
+ The rule to check.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to the element.
+
+ -
+
mixed
opts
+ Any additional options regarding the rule. Used internally.
+
+
+
+
+.create_node ( ), .check_move ( )
+Both functions are overwritten to accomodate the new functionality presented by the plugin.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thirdparty/jstree/_docs/ui.html b/thirdparty/jstree/_docs/ui.html
new file mode 100644
index 000000000..4e7bc9a54
--- /dev/null
+++ b/thirdparty/jstree/_docs/ui.html
@@ -0,0 +1,197 @@
+
+
+
+
+ jsTree v.1.0 - UI documentation
+
+
+
+
+
+
+
+
+
+
+
+
+jsTree v.1.0
+ui plugin
+Description
+
+The UI
plugin handles selecting, deselecting and hovering tree items.
+
+
+Configuration
+
+select_limit
+
+Defines how many nodes can be selected at a given time (-1
means unlimited).
+
+select_multiple_modifier
+
+The special key used to make a click add to the selection and not replace it ("ctrl"
, "shift"
, "alt"
, "meta"
).
You can also set this to "on"
making every click add to the selection.
+
+select_range_modifier
+
+The special key used to make a click expand a range from the last selected item ("ctrl"
, "shift"
, "alt"
, "meta"
).
Note that the last clicked elemtn should be a sibling of the currently clicked element so that a range will be created (same as common file explorers).
+
+selected_parent_close
+
+What action to take when a selected node's parent is closed (making the selected node invisible). Possible values are false
- do nothing, "select_parent"
- select the closed node's parent and "deselect"
- deselect the node.
+
+selected_parent_open
+
+When set to true
when programatically selecting a node in the tree all of its closed parents are opened automatically.
+
+select_prev_on_delete
+
+If set to true
when a selected node is deleted, its previous sibling (or parent) is selected.
+
+disable_selecting_children
+
+If set to true
you will not be able to select children of already selected nodes.
+
+initially_select
+
+Defines which nodes are to be automatically selected when the tree finishes loading - a list of IDs is expected.
+
+
+
+Demos
+
+
+Using the UI plugin
+
+
+ -
+ Root node 1
+
+ -
+ Child node 1
+
+ -
+ Child node 2
+
+
+
+ -
+ Root node 2
+
+
+
+
+
+
+
+API
+
+
+._get_node ( node , allow_multiple )
+Overrides the function from the core module.
if node
is undefined
or null
and allow_multiple
is true
all the currently selected nodes are returned
if node
is undefined
or null
and allow_multiple
is NOT true
only the last selected node is returned.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+ -
+
boolean
allow_multiple
+ Whether to return all selected nodes or only the last selected one if node
is null
.
+
+
+
+.save_selected ( )
+Saves away the current selection state of the tree (saves it in a variable, so do not expect a restore after a refresh - for that functionality refer to the cookies plugin. Used mostly internally. Triggers an event.
+
+.reselect ( )
+Restores the state of the tree using the variable saved in the above function. Used mostly internally. Triggers an event.
+
+.refresh ( node )
+Overrides the function form the core module.
Enables saving the selection state before the refresh and restoring it afterwards.
+
+.hover_node ( node )
+Sets the specified node as hovered. Triggers an event.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+
+
+.dehover_node ( )
+Removes the hover state from the currently hovered node (if there is one). Triggers an event.
+
+
+.select_node ( node , check , event )
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+ -
+
bool
check
+ Whether to check the specified rules and do appropriate actions (check select_limit
, deselect other nodes respectively, etc) or to just force selection of the node regardless of select_limit
.
+
+ -
+
event
event
+ Used internally - when a click on a node caused this function to be executed.
+
+
+
+
+.deselect_node ( node ), .toggle_select ( node )
+There functions control the selected state on a node. deselect_node
triggers an event.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+
+
+.deselect_all ( context )
+Deselects all selected nodes. If context is set - only the selected nodes within that context are deselected. Triggers an event.
+
+ -
+
mixed
context
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+
+
+.get_selected ( context )
+Returns all selected nodes. If context is set - only the selected nodes within that context are returned.
+
+ -
+
mixed
context
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+
+
+.is_selected ( node )
+Returns whether the specified node is selected or not.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element within the tree.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thirdparty/jstree/_docs/unique.html b/thirdparty/jstree/_docs/unique.html
new file mode 100644
index 000000000..ae4e5da83
--- /dev/null
+++ b/thirdparty/jstree/_docs/unique.html
@@ -0,0 +1,85 @@
+
+
+
+
+ jsTree v.1.0 - unique documentation
+
+
+
+
+
+
+
+
+
+
+
+
+jsTree v.1.0
+unique plugin
+Description
+
+The unique
plugin prevents from nodes with same titles coexisting (create/move/rename) in the same parent.
+
+
+Configuration
+
+
+error_callback
+
+Whenever the plugin stops an action (because it violates the unique policy) this function will bre triggered in current tree's scope, receiving the name, siblings and function name that caused the conflict.
+
+
+
+Demos
+
+Try moving the child nodes together (drag'n'drop).
+
+Using the unique plugin
+
+
+ -
+ Root node 1
+
+ -
+ Child node 1
+
+
+
+ -
+ Root node 2
+
+ -
+ Child node 1
+
+
+
+
+
+
+
+
+
+API
+
+
+._check_unique ( names, siblings )
+Used internally - checks the names array against the sibling nodes for matches.
+
+
+
+
+
\ No newline at end of file
diff --git a/thirdparty/jstree/_docs/xml_data.html b/thirdparty/jstree/_docs/xml_data.html
new file mode 100644
index 000000000..eecc70835
--- /dev/null
+++ b/thirdparty/jstree/_docs/xml_data.html
@@ -0,0 +1,218 @@
+
+
+
+
+ jsTree v.1.0 - xml_data documentation
+
+
+
+
+
+
+
+
+
+
+
+
+jsTree v.1.0
+xml_data plugin
+Description
+
+The xml_data
plugin enables jsTree to convert XML objects to interactive trees (using XSL). The data (XML) can be set up in the config (as a string) or retrieved from a server (also ondemand).
+Two types of XML structures are supported - flat and nested:
+
+
+<!-- FLAT -->
+<root>
+ <item id="root_1" parent_id="0" state="closed">
+ <content>
+ <name><![CDATA[Node 1]]></name>
+ </content>
+ </item>
+ <item id="node_2" parent_id="root_1">
+ <content>
+ <name><![CDATA[Node 2]]></name>
+ </content>
+ </item>
+</root>
+
+<!-- NESTED -->
+<root>
+ <item id="xml_1">
+ <content><name><![CDATA[Root node 1]]></name></content>
+ <item id="xml_2">
+ <content><name><![CDATA[Child node 1]]></name></content>
+ </item>
+ </item>
+</root>
+
+
+Aside from nesting the only difference is the parent_id
attribute used in xml_flat
.
+parent_id
defines the parent of the node in XML flat, use 0
for root nodes. Also when using async - use 0
for the first level.
+state
defines the state of the node (open
or closed
). You can omit it too - jstree will handle the data automatically - nodes with no children will be leaf nodes, nodes with children will be closed.
+All attributes you set on the item
node will be transfered to the resulting li
node. All attributes you set on the name
node will be transfered to the resulting a
node.
+If you are using the languages plugin you can have multiple name
nodes in a every item
node, just set a language
attribute on each one (<name language="en" ...
).
+Remember to always set the XML header on your XML files.
+
+
+Configuration
+
+data
+
+Specifies the content to load into the container and convert to a tree.
+ajax
+
+The ajax config object is pretty much the same as the jQuery ajax settings object.
+You can set the data
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the node about to be open as a parameter (or -1
for initial load). Whatever you return in the function will be sent to the server as data (so for example you can send the node's ID).
+You can set the url
option to a function, that will be executed in the current tree's scope (this
will be the tree instance) and gets the node about to be open as a paramater (or -1
for initial load). Whatever you return in the url
function will be used as the ajax URL (so that you can accomodate pretty paths such as /get_children/node_2).
+The error
and success
functions (if present) also fire in the context of the tree, and if you return a value in the success
function it will be used to populate the tree - this can be useful if you want to somehow change what the server returned on the client side before it is displayed in the tree. Please note that the success
function receives a string as the first parameter, and also if you decide to return a value - return a string.
+correct_state
+
+If this option is set to true
if an AJAX returns an empty result, the node that was about to be opened will be converted to a leaf node (the open icon will no longer be displayed).
+clean_node
+
+Set to true if node needs to be cleaned - usually you should leave this to false
.
+xsl
+
+The type of structure you wiil be using - set either to "flat"
or "nest"
.
+get_skip_empty
+
+If set to true
empty attributes won't be returned by the get_xml
function.
+
+NOTE:
If both data
and ajax
are set the initial tree is rendered from the data
string. When opening a closed node (that has no loaded children) an AJAX request is made.
+
+
+Demos
+
+
+Using the data config option (flat)
+
+
+
+Using the ajax config option (nested)
+
+
+
+Using both the data & ajax config options (flat)
+
+
+
+
+API
+
+Both dummy functions - _is_loaded
and load_node
are overwritten.
+.load_node_xml ( node , success_callback , error_callback )
+This function is called instead of load_node
.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use -1
for root nodes.
+
+ -
+
function
success_callback
+ A function to be executed once the node is loaded successfully - used internally. You should wait for the load_node
event.
+
+ -
+
function
error_callback
+ A function to be executed if the node is not loaded due to an error - used internally. You should wait for the load_node
event.
+
+
+.parse_xml ( data )
+This function converts XML strings or objects to the DOM structure required by jstree. Returns a jQuery object.
+
+ -
+
mixed
data
+ The XML string/object.
+
+
+.get_xml ( type , node , li_attr , a_attr , is_callback )
+This function returns an array of tree nodes converted back to XML.
+
+ -
+
string
type
+ Either "flat"
or "nest"
. Default is "flat"
.
+
+ -
+
mixed
node
+ This can be a DOM node, jQuery node or selector pointing to an element you want returned. Use -1
or omit to get the whole tree.
+
+ -
+
array
li_attr
+ The attributes to collect from the LI
node. Defaults to [ "id" , "class" ]
+
+ -
+
array
a_attr
+ The attributes to collect from the A
node. Defaults to [ ]
+
+ -
+
string
is_callback
+ Used internally.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thirdparty/jstree/_lib/jquery.cookie.js b/thirdparty/jstree/_lib/jquery.cookie.js
new file mode 100644
index 000000000..6df1faca2
--- /dev/null
+++ b/thirdparty/jstree/_lib/jquery.cookie.js
@@ -0,0 +1,96 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+/**
+ * Create a cookie with the given name and value and other optional parameters.
+ *
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Set the value of a cookie.
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
+ * @desc Create a cookie with all available options.
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Create a session cookie.
+ * @example $.cookie('the_cookie', null);
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
+ * used when the cookie was set.
+ *
+ * @param String name The name of the cookie.
+ * @param String value The value of the cookie.
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
+ * If set to null or omitted, the cookie will be a session cookie and will not be retained
+ * when the the browser exits.
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
+ * require a secure protocol (like HTTPS).
+ * @type undefined
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
+ */
+
+/**
+ * Get the value of a cookie with the given name.
+ *
+ * @example $.cookie('the_cookie');
+ * @desc Get the value of a cookie.
+ *
+ * @param String name The name of the cookie.
+ * @return The value of the cookie.
+ * @type String
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
+ */
+jQuery.cookie = function(name, value, options) {
+ if (typeof value != 'undefined') { // name and value given, set cookie
+ options = options || {};
+ if (value === null) {
+ value = '';
+ options.expires = -1;
+ }
+ var expires = '';
+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
+ var date;
+ if (typeof options.expires == 'number') {
+ date = new Date();
+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
+ } else {
+ date = options.expires;
+ }
+ expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
+ }
+ // CAUTION: Needed to parenthesize options.path and options.domain
+ // in the following expressions, otherwise they evaluate to undefined
+ // in the packed version for some reason...
+ var path = options.path ? '; path=' + (options.path) : '';
+ var domain = options.domain ? '; domain=' + (options.domain) : '';
+ var secure = options.secure ? '; secure' : '';
+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
+ } else { // only name given, get cookie
+ var cookieValue = null;
+ if (document.cookie && document.cookie != '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return cookieValue;
+ }
+};
\ No newline at end of file
diff --git a/thirdparty/jstree/_lib/jquery.hotkeys.js b/thirdparty/jstree/_lib/jquery.hotkeys.js
new file mode 100644
index 000000000..fbd71c71e
--- /dev/null
+++ b/thirdparty/jstree/_lib/jquery.hotkeys.js
@@ -0,0 +1,99 @@
+/*
+ * jQuery Hotkeys Plugin
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Based upon the plugin by Tzury Bar Yochay:
+ * http://github.com/tzuryby/hotkeys
+ *
+ * Original idea by:
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
+*/
+
+(function(jQuery){
+
+ jQuery.hotkeys = {
+ version: "0.8",
+
+ specialKeys: {
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
+ },
+
+ shiftNums: {
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
+ ".": ">", "/": "?", "\\": "|"
+ }
+ };
+
+ function keyHandler( handleObj ) {
+ // Only care when a possible input has been specified
+ if ( typeof handleObj.data !== "string" ) {
+ return;
+ }
+
+ var origHandler = handleObj.handler,
+ keys = handleObj.data.toLowerCase().split(" ");
+
+ handleObj.handler = function( event ) {
+ // Don't fire in text-accepting inputs that we didn't directly bind to
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
+ event.target.type === "text") ) {
+ return;
+ }
+
+ // Keypress represents characters, not special keys
+ var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
+ character = String.fromCharCode( event.which ).toLowerCase(),
+ key, modif = "", possible = {};
+
+ // check combinations (alt|ctrl|shift+anything)
+ if ( event.altKey && special !== "alt" ) {
+ modif += "alt+";
+ }
+
+ if ( event.ctrlKey && special !== "ctrl" ) {
+ modif += "ctrl+";
+ }
+
+ // TODO: Need to make sure this works consistently across platforms
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
+ modif += "meta+";
+ }
+
+ if ( event.shiftKey && special !== "shift" ) {
+ modif += "shift+";
+ }
+
+ if ( special ) {
+ possible[ modif + special ] = true;
+
+ } else {
+ possible[ modif + character ] = true;
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
+
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
+ if ( modif === "shift+" ) {
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
+ }
+ }
+
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
+ if ( possible[ keys[i] ] ) {
+ return origHandler.apply( this, arguments );
+ }
+ }
+ };
+ }
+
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
+ jQuery.event.special[ this ] = { add: keyHandler };
+ });
+
+})( jQuery );
\ No newline at end of file
diff --git a/thirdparty/jstree/_lib/jquery.js b/thirdparty/jstree/_lib/jquery.js
new file mode 100644
index 000000000..eb6a59693
--- /dev/null
+++ b/thirdparty/jstree/_lib/jquery.js
@@ -0,0 +1,18 @@
+/*!
+ * jQuery JavaScript Library v1.6.1
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu May 12 15:04:36 2011 -0400
+ */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="t
",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem
+)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c ",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/",""],legend:[1,""],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,""],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div",""]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1>$2>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||
+b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1>$2>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/