📄 xtree2.js
字号:
/*----------------------------------------------------------------------------\
| xTree 2.0 PRE RELEASE |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| This is a pre release and may not be redistributed. |
| Watch http://webfx.eae.net for the final version |
|-----------------------------------------------------------------------------|
| Created by Erik Arvidsson & Emil A Eklund |
| (http://webfx.eae.net/contact.html#erik) |
| (http://webfx.eae.net/contact.html#emil) |
| For WebFX (http://webfx.eae.net/) |
|-----------------------------------------------------------------------------|
| A tree menu system for IE 5.5+, Mozilla 1.4+, Opera 7, KHTML |
|-----------------------------------------------------------------------------|
| Copyright (c) 2003, 2004, 2005, 2006 Erik Arvidsson & Emil A Eklund |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License. You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| License for the specific language governing permissions and limitations |
| under the License. |
|-----------------------------------------------------------------------------|
| Dependencies: xtree2.css - Used to define the look and feel |
|-----------------------------------------------------------------------------|
| 2004-02-21 | Pre release distributed to a few selected tester |
| 2005-06-06 | Added single tab index to improve keyboard navigation |
| 2006-05-28 | Changed license to Apache Software License 2.0. |
|-----------------------------------------------------------------------------|
| Created 2003-??-?? | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/
//
// WebFXTreePersisitance
function WebFXTreePersistence() {}
var _p = WebFXTreePersistence.prototype;
_p.getExpanded = function getExpanded(oNode) { return false; };
_p.setExpanded = function setExpanded(oNode, bOpen) {};
// Cookie handling
function WebFXCookie() {}
_p = WebFXCookie.prototype;
_p.setCookie = function setCookie(sName, sValue, nDays) {
var expires = "";
if (typeof nDays == "number") {
var d = new Date();
d.setTime(d.getTime() + nDays * 24 * 60 * 60 * 1000);
expires = "; expires=" + d.toGMTString();
}
document.cookie = sName + "=" + escape(sValue) + expires + "; path=/";
};
_p.getCookie = function getCookie(sName) {
var re = new RegExp("(\;|^)[^;]*(" + sName + ")\=([^;]*)(;|$)");
var res = re.exec(document.cookie);
return res != null ? unescape(res[3]) : null;
};
_p.removeCookie = function removeCookie(name) {
this.setCookie(name, "", -1);
};
//
// persistence using cookies
//
// This is uses one cookie with the ids of the expanded nodes separated using '+'
//
function WebFXTreeCookiePersistence() {
this._openedMap = {};
this._cookies = new WebFXCookie;
var s = this._cookies.getCookie(this.cookieName);
if (s) {
var a = s.split("+");
for (var i = a.length - 1; i >= 0; i--)
this._openedMap[a[i]] = true;
}
}
_p = WebFXTreeCookiePersistence.prototype = new WebFXTreePersistence;
_p.cookieName = "webfx-tree-cookie-persistence"
_p.getExpanded = function getExpanded(oNode) {
return oNode.id in this._openedMap;
};
_p.setExpanded = function setExpanded(oNode, bOpen) {
var old = this.getExpanded(oNode);
if (old != bOpen) {
if (bOpen) {
this._openedMap[oNode.id] = true;
} else {
delete this._openedMap[oNode.id];
}
var res = [];
var i = 0;
for (var id in this._openedMap)
res[i++] = id;
this._cookies.setCookie(this.cookieName, res.join("+"));
}
};
// this object provides a few useful methods when working with arrays
var arrayHelper = {
indexOf: function (a, o) {
for (var i = 0; i < a.length; i++) {
if (a[i] == o) {
return i;
}
}
return -1;
},
insertBefore: function (a, o, o2) {
var i = this.indexOf(a, o2);
if (i == -1) {
a.push(o);
} else {
a.splice(i, 0, o);
}
},
remove: function (a, o) {
var i = this.indexOf(a, o);
if (i != -1) {
a.splice(i, 1);
}
}
};
///////////////////////////////////////////////////////////////////////////////
// WebFX Tree Config object //
///////////////////////////////////////////////////////////////////////////////
var webFXTreeConfig = {
rootIcon : "images/folder.png",
openRootIcon : "images/openfolder.png",
folderIcon : "images/folder.png",
openFolderIcon : "images/openfolder.png",
fileIcon : "images/file.png",
iIcon : "images/I.png",
lIcon : "images/L.png",
lMinusIcon : "images/Lminus.png",
lPlusIcon : "images/Lplus.png",
tIcon : "images/T.png",
tMinusIcon : "images/Tminus.png",
tPlusIcon : "images/Tplus.png",
plusIcon : "images/plus.png",
minusIcon : "images/minus.png",
blankIcon : "images/blank.png",
defaultText : "Tree Item",
defaultAction : null,
defaultBehavior : "classic",
usePersistence : true
};
///////////////////////////////////////////////////////////////////////////////
// WebFX Tree Handler object //
///////////////////////////////////////////////////////////////////////////////
var webFXTreeHandler = {
ie: /msie/i.test(navigator.userAgent),
opera: /opera/i.test(navigator.userAgent),
idCounter: 0,
idPrefix: "wfxt-",
getUniqueId: function () {
return this.idPrefix + this.idCounter++;
},
all: {},
getNodeById: function (sId) {
return all[sId];
},
addNode: function (oNode) {
this.all[oNode.id] = oNode;
},
removeNode: function (oNode) {
delete this.all[oNode.id];
},
handleEvent: function (e) {
var el = e.target || e.srcElement;
while (el != null && !this.all[el.id]) {
el = el.parentNode;
}
if (el == null) {
return false;
}
var node = this.all[el.id];
if (typeof node["_on" + e.type] == "function") {
return node["_on" + e.type](e);
}
return false;
},
dispose: function () {
if (this.disposed) return;
for (var id in this.all) {
this.all[id].dispose();
}
this.disposed = true;
},
htmlToText: function (s) {
return String(s).replace(/\s+|<([^>])+>|&|<|>|"| /gi, this._htmlToText);
},
_htmlToText: function (s) {
switch (s) {
case "&":
return "&";
case "<":
return "<";
case ">":
return ">";
case """:
return "\"";
case " ":
return String.fromCharCode(160);
default:
if (/\s+/.test(s)) {
return " ";
}
if (/^<BR/gi.test(s)) {
return "\n";
}
return "";
}
},
textToHtml: function (s) {
return String(s).replace(/&|<|>|\n|\"\u00A0/g, this._textToHtml);
},
_textToHtml: function (s) {
switch (s) {
case "&":
return "&";
case "<":
return "<";
case ">":
return ">";
case "\n":
return "<BR>";
case "\"":
return """; // so we can use this in attributes
default:
return " ";
}
},
persistenceManager: new WebFXTreeCookiePersistence()
};
///////////////////////////////////////////////////////////////////////////////
// WebFXTreeAbstractNode
///////////////////////////////////////////////////////////////////////////////
function WebFXTreeAbstractNode(sText, oAction) {
this.childNodes = [];
if (sText) this.text = sText;
if (oAction) this.action = oAction;
this.id = webFXTreeHandler.getUniqueId();
if (webFXTreeConfig.usePersistence) {
this.open = webFXTreeHandler.persistenceManager.getExpanded(this);
}
webFXTreeHandler.addNode(this);
}
_p = WebFXTreeAbstractNode.prototype;
_p._selected = false;
_p.indentWidth = 19;
_p.open = false;
_p.text = webFXTreeConfig.defaultText;
_p.action = null;
_p.target = null;
_p.toolTip = null;
_p._focused = false;
/* begin tree model */
_p.add = function add(oChild, oBefore) {
var oldLast;
var emptyBefore = this.childNodes.length == 0;
var p = oChild.parentNode;
if (oBefore == null) { // append
if (p != null)
p.remove(oChild);
oldLast = this.getLastChild();
this.childNodes.push(oChild);
} else { // insertBefore
if (oBefore.parentNode != this) {
throw new Error("Can only add nodes before siblings");
}
if (p != null) {
p.remove(oChild);
}
arrayHelper.insertBefore(this.childNodes, oChild, oBefore);
}
if (oBefore) {
if (oBefore == this.firstChild) {
this.firstChild = oChild;
}
oChild.previousSibling = oBefore.previousSibling;
oBefore.previousSibling = oChild;
oChild.nextSibling = oBefore;
} else {
if (!this.firstChild) {
this.firstChild = oChild;
}
if (this.lastChild) {
this.lastChild.nextSibling = oChild;
}
oChild.previousSibling = this.lastChild;
this.lastChild = oChild;
}
oChild.parentNode = this;
var t = this.getTree();
if (t) {
oChild.tree = t;
}
var d = this.getDepth();
if (d != null) {
oChild.depth = d + 1;
}
if (this.getCreated() && !t.getSuspendRedraw()) {
var el = this.getChildrenElement();
var newEl = oChild.create();
var refEl = oBefore ? oBefore.getElement() : null;
el.insertBefore(newEl, refEl);
if (oldLast) {
oldLast.updateExpandIcon();
}
if (emptyBefore) {
this.setExpanded(this.getExpanded());
// if we are using classic expand will not update icon
if (t && t.getBehavior() != "classic")
this.updateIcon();
}
}
return oChild;
};
_p.remove = function remove(oChild) {
// backwards compatible. If no argument remove the node
if (arguments.length == 0) {
if (this.parentNode) {
return this.parentNode.remove(this);
}
return null;
}
// if we remove selected or tree with the selected we should select this
var t = this.getTree();
var si = t ? t.getSelected() : null;
if (si == oChild || oChild.contains(si)) {
if (si.getFocused()) {
this.select();
window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10);
} else {
this.select();
}
}
if (oChild.parentNode != this) {
throw new Error("Can only remove children");
}
arrayHelper.remove(this.childNodes, oChild);
if (this.lastChild == oChild) {
this.lastChild = oChild.previousSibling;
}
if (this.firstChild == oChild) {
this.firstChild = oChild.nextSibling;
}
if (oChild.previousSibling) {
oChild.previousSibling.nextSibling = oChild.nextSibling;
}
if (oChild.nextSibling) {
oChild.nextSibling.previousSibling = oChild.previousSibling;
}
var wasLast = oChild.isLastSibling();
oChild.parentNode = null;
oChild.tree = null;
oChild.depth = null;
if (t && this.getCreated() && !t.getSuspendRedraw()) {
var el = this.getChildrenElement();
var childEl = oChild.getElement();
el.removeChild(childEl);
if (wasLast) {
var newLast = this.getLastChild();
if (newLast) {
newLast.updateExpandIcon();
}
}
if (!this.hasChildren()) {
el.style.display = "none";
this.updateExpandIcon();
this.updateIcon();
}
}
return oChild;
};
WebFXTreeAbstractNode._onTimeoutFocus = function (sId) {
var jsNode = webFXTreeHandler.all[sId];
jsNode.focus();
};
_p.getId = function getId() {
return this.id;
};
_p.getTree = function getTree() {
throw new Error("getTree called on Abstract Node");
};
_p.getDepth = function getDepth() {
throw new Error("getDepth called on Abstract Node");
};
_p.getCreated = function getCreated() {
var t = this.getTree();
return t && t.rendered;
};
_p.getParent = function getParent() {
return this.parentNode;
};
_p.contains = function contains(oDescendant) {
if (oDescendant == null) return false;
if (oDescendant == this) return true;
var p = oDescendant.parentNode;
return this.contains(p);
};
_p.getChildren = _p.getChildNodes = function getChildNodes() {
return this.childNodes;
};
_p.getFirstChild = function getFirstChild() {
return this.childNodes[0];
};
_p.getLastChild = function getLastChild() {
return this.childNodes[this.childNodes.length - 1];
};
_p.getPreviousSibling = function getPreviousSibling() {
return this.previousSibling;
//var p = this.parentNode;
//if (p == null) return null;
//var cs = p.childNodes;
//return cs[arrayHelper.indexOf(cs, this) - 1]
};
_p.getNextSibling = function getNextSibling() {
return this.nextSibling;
//var p = this.parentNode;
//if (p == null) return null;
//var cs = p.childNodes;
//return cs[arrayHelper.indexOf(cs, this) + 1]
};
_p.hasChildren = function hasChildren() {
return this.childNodes.length > 0;
};
_p.isLastSibling = function isLastSibling() {
return this.nextSibling == null;
//return this.parentNode && this == this.parentNode.getLastChild();
};
_p.findChildByText = function findChildByText(s, n) {
if (!n) {
n = 0;
}
var isRe = s instanceof RegExp;
for (var i = 0; i < this.childNodes.length; i++) {
if (isRe && s.test(this.childNodes[i].getText()) ||
this.childNodes[i].getText() == s) {
if (n == 0) {
return this.childNodes[i];
}
n--;
}
}
return null;
};
_p.findNodeByText = function findNodeByText(s, n) {
if (!n) {
n = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -