1235 lines
34 KiB
HTML
1235 lines
34 KiB
HTML
<html>
|
|
<head>
|
|
|
|
<script language="Javascript">
|
|
|
|
tree = null;
|
|
ready = false;
|
|
|
|
|
|
/***************************************************************************************
|
|
* Javascript global variables *
|
|
**************************************************************************************/
|
|
|
|
var NODE_EXPAND_BUTTON_FAKE = "<%Links::Browser::JFunction::node_expand_button_fake()%>";
|
|
var NODE_EXPAND_BUTTON_PLUS = "<%Links::Browser::JFunction::node_expand_button_plus()%>";
|
|
var NODE_EXPAND_BUTTON_LESS = "<%Links::Browser::JFunction::node_expand_button_less()%>";
|
|
var NODE_UNSELECTED_BUTTON = "<%Links::Browser::JFunction::node_unselected_button()%>";
|
|
var MAX_LOAD_FULL = <%max_load_full%>;
|
|
var TOTAL_CATEGORIES = <%total_categories%>;
|
|
|
|
LEFT_FRAME_ID = 0;
|
|
RIGHT_FRAME_ID = 1;
|
|
CODE_FRAME_ID = 2;
|
|
CAN_UPDATE = 0;
|
|
|
|
/***************************************************************************************
|
|
* Javascript UnloadedNode class *
|
|
**************************************************************************************/
|
|
|
|
|
|
/**
|
|
* An unloaded node is a node which could potentially
|
|
* be expanded but which information is not yet stored
|
|
* in the memory. When clicked, it has to perform a
|
|
* network access to upload the document state and re
|
|
* draw the tree.
|
|
*/
|
|
function UnloadedNode (id, fatherId, name, nbLinks)
|
|
{
|
|
this.setId (id);
|
|
this.setFatherId (fatherId);
|
|
this.setName (name);
|
|
this.setNumberOfLinks (nbLinks);
|
|
this.selected = false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the number of links for an Unloaded Node.
|
|
*/
|
|
function UnloadedNode_setNumberOfLinks (nbLinks)
|
|
{
|
|
this.numberOfLinks = nbLinks;
|
|
}
|
|
UnloadedNode.prototype.setNumberOfLinks = UnloadedNode_setNumberOfLinks;
|
|
|
|
|
|
/**
|
|
* Gets the number of links for an Unloaded Node.
|
|
*/
|
|
function UnloadedNode_getNumberOfLinks()
|
|
{
|
|
return this.numberOfLinks;
|
|
}
|
|
UnloadedNode.prototype.getNumberOfLinks = UnloadedNode_getNumberOfLinks;
|
|
|
|
|
|
/**
|
|
* This method should always return
|
|
* false because an UnloadedNode is
|
|
* never loaded !
|
|
*/
|
|
function UnloadedNode_isLoaded()
|
|
{
|
|
return false;
|
|
}
|
|
UnloadedNode.prototype.isLoaded = UnloadedNode_isLoaded;
|
|
|
|
|
|
/**
|
|
* This method tells if a node is
|
|
* the same as another according
|
|
* to it's ID number
|
|
*/
|
|
function UnloadedNode_equals (aNode)
|
|
{
|
|
return this.id == aNode.id;
|
|
}
|
|
UnloadedNode.prototype.equals = UnloadedNode_equals;
|
|
|
|
|
|
/**
|
|
* This method sets the ID of a
|
|
* node to the specified ID. Should
|
|
* normally be used only by the
|
|
* constructor
|
|
*/
|
|
function UnloadedNode_setId (id)
|
|
{
|
|
this.id = id;
|
|
}
|
|
UnloadedNode.prototype.setId = UnloadedNode_setId;
|
|
|
|
|
|
/**
|
|
* Returns the current node's ID.
|
|
*/
|
|
function UnloadedNode_getId()
|
|
{
|
|
return this.id;
|
|
}
|
|
UnloadedNode.prototype.getId = UnloadedNode_getId;
|
|
|
|
|
|
/**
|
|
* This method sets the fatherId of a
|
|
* node to the specified fatherId. Should
|
|
* normally be used only by the constructor.
|
|
*/
|
|
function UnloadedNode_setFatherId (fatherId)
|
|
{
|
|
this.fatherId = fatherId;
|
|
}
|
|
UnloadedNode.prototype.setFatherId = UnloadedNode_setFatherId;
|
|
|
|
|
|
/**
|
|
* returns the current node's fatherId.
|
|
*/
|
|
function UnloadedNode_getFatherId()
|
|
{
|
|
return this.fatherId;
|
|
}
|
|
UnloadedNode.prototype.getFatherId = UnloadedNode_getFatherId;
|
|
|
|
|
|
/**
|
|
* This method sets the name of the
|
|
* current node.
|
|
*/
|
|
function UnloadedNode_setName (name)
|
|
{
|
|
this.name = name;
|
|
}
|
|
UnloadedNode.prototype.setName = UnloadedNode_setName;
|
|
|
|
|
|
/**
|
|
* This method returns the name of the
|
|
* current node.
|
|
*/
|
|
function UnloadedNode_getName()
|
|
{
|
|
return this.name;
|
|
}
|
|
UnloadedNode.prototype.getName = UnloadedNode_getName;
|
|
|
|
|
|
/**
|
|
* Sets whether the node is expanded or not.
|
|
*/
|
|
function UnloadedNode_setExpanded (expanded)
|
|
{
|
|
alert ("Cannot set the expanded property on Unloaded nodes !");
|
|
}
|
|
UnloadedNode.prototype.setExpanded = UnloadedNode_setExpanded;
|
|
|
|
|
|
/**
|
|
* returns true if the node is expanded,
|
|
* false otherwise. An unloaded node can never
|
|
* be expanded because otherwise it would
|
|
* necessarily be loaded !
|
|
*/
|
|
function UnloadedNode_isExpanded()
|
|
{
|
|
return false;
|
|
}
|
|
UnloadedNode.prototype.isExpanded = UnloadedNode_isExpanded;
|
|
|
|
|
|
/**
|
|
* Sets whether the node is selected or not.
|
|
*/
|
|
function UnloadedNode_setSelected (selected)
|
|
{
|
|
this.selected = selected;
|
|
}
|
|
UnloadedNode.prototype.setSelected = UnloadedNode_setSelected;
|
|
|
|
|
|
/**
|
|
* returns true if the node is currently
|
|
* selected, false otherwise.
|
|
*/
|
|
function UnloadedNode_isSelected()
|
|
{
|
|
return this.selected;
|
|
}
|
|
UnloadedNode.prototype.isSelected = UnloadedNode_isSelected;
|
|
|
|
|
|
/**
|
|
* adds a child to this node. Does not
|
|
* currently lookup in the sub-tree to
|
|
* check if the node has been inserted.
|
|
*
|
|
* this function should never be called
|
|
* on an unloaded node !
|
|
*/
|
|
function UnloadedNode_addChild (aChild)
|
|
{
|
|
alert ("Software error : addChild should never be called on an Unloaded node!");
|
|
}
|
|
UnloadedNode.prototype.addChild = UnloadedNode_addChild;
|
|
|
|
|
|
/**
|
|
* removes a child from a node. Does
|
|
* not currently lookup in the sub-tree to
|
|
* check if the node to remove is there
|
|
* but only in the children array.
|
|
*
|
|
* this function should never be called
|
|
* on an unloaded node !
|
|
*/
|
|
function UnloadedNode_delChild (aChild)
|
|
{
|
|
alert ("Software error : addChild should never be called on an Unloaded node!");
|
|
}
|
|
UnloadedNode.prototype.delChild = UnloadedNode_delChild;
|
|
|
|
|
|
/**
|
|
* Returns the array of current node's children.
|
|
*
|
|
* this function should never be called
|
|
* on an unloaded node !
|
|
*/
|
|
function UnloadedNode_getChildArray()
|
|
{
|
|
alert ("Software error : getChildArray should never be called on an Unloaded node!");
|
|
}
|
|
UnloadedNode.prototype.getChildArray = UnloadedNode_getChildArray;
|
|
|
|
|
|
/**
|
|
* Returns true if the node is a leaf,
|
|
* false otherwise. An unloaded node
|
|
* shall never be a leaf !
|
|
*/
|
|
function UnloadedNode_isLeaf()
|
|
{
|
|
return false;
|
|
}
|
|
UnloadedNode.prototype.isLeaf = UnloadedNode_isLeaf;
|
|
|
|
|
|
/**
|
|
* Lookup for a node the id of which is
|
|
* id in the current subtree. If the node
|
|
* is found, returns it, otherwise returns
|
|
* null.
|
|
*
|
|
* An unloaded node knows itself only,
|
|
* therefore we do not search the
|
|
* subtree.
|
|
*/
|
|
function UnloadedNode_lookup (id)
|
|
{
|
|
if (this.id == id) return this;
|
|
else return null;
|
|
}
|
|
UnloadedNode.prototype.lookup = UnloadedNode_lookup;
|
|
|
|
|
|
/**
|
|
* Returns an HTML representation of this node.
|
|
*/
|
|
function UnloadedNode_toHtml()
|
|
{
|
|
return '<a name="' + this.getId() + '"></a>' +
|
|
this.expandButtonHtml() +
|
|
this.folderHtml() +
|
|
" " +
|
|
this.name +
|
|
" (" +
|
|
this.getNumberOfLinks() +
|
|
")</p>\n";
|
|
}
|
|
UnloadedNode.prototype.toHtml = UnloadedNode_toHtml;
|
|
|
|
|
|
/**
|
|
* Returns HTML code that represents the
|
|
* button which is being clicked to expand
|
|
* or unexpand a node.
|
|
*/
|
|
function UnloadedNode_expandButtonHtml()
|
|
{
|
|
var node_id = this.getId();
|
|
if (this.isLeaf())
|
|
{
|
|
alert ("Software error: An Unloaded Node can never be a Leaf !");
|
|
}
|
|
else
|
|
{
|
|
if (this.isExpanded())
|
|
{
|
|
alert ("Software error: An Unloaded Node can never be expanded !");
|
|
}
|
|
else
|
|
{
|
|
return '<a href="#" onClick="return parent.clickEvent(' +
|
|
"'" + 'UnloadedNode' + "', " +
|
|
"'" + 'expand' + "', " +
|
|
node_id +
|
|
')"><img src="' +
|
|
NODE_EXPAND_BUTTON_PLUS +
|
|
'" border=0></a>';
|
|
}
|
|
}
|
|
}
|
|
UnloadedNode.prototype.expandButtonHtml = UnloadedNode_expandButtonHtml;
|
|
|
|
|
|
/**
|
|
* Returns HTML code that represents the
|
|
* folder which is being clicked to be selected.
|
|
*/
|
|
function UnloadedNode_folderHtml()
|
|
{
|
|
var node_id = this.getId();
|
|
return '<a name="' + node_id + '" href="#" onClick="return parent.clickEvent(' +
|
|
"'" + 'UnloadedNode' + "', " +
|
|
"'" + 'select' + "', " +
|
|
node_id +
|
|
')"><img src="' +
|
|
NODE_UNSELECTED_BUTTON +
|
|
'" border=0></a>';
|
|
}
|
|
UnloadedNode.prototype.folderHtml = UnloadedNode_folderHtml;
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
* Javascript LoadedNode class *
|
|
**************************************************************************************/
|
|
|
|
|
|
/**
|
|
* A loaded node is a node which has been
|
|
* already loaded in memory, i.e. a node which
|
|
* knows its children (even if it has no children)
|
|
*/
|
|
function LoadedNode (id, fatherId, name, nbLinks)
|
|
{
|
|
this.setId (id);
|
|
this.setFatherId (fatherId);
|
|
this.setName (name);
|
|
if (nbLinks == null) this.setNumberOfLinks ("");
|
|
else this.setNumberOfLinks (nbLinks);
|
|
this.expanded = false;
|
|
this.child = new Array();
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the number of links for an Unloaded Node.
|
|
*/
|
|
function LoadedNode_setNumberOfLinks (nbLinks)
|
|
{
|
|
this.numberOfLinks = nbLinks;
|
|
}
|
|
LoadedNode.prototype.setNumberOfLinks = LoadedNode_setNumberOfLinks;
|
|
|
|
|
|
/**
|
|
* Gets the number of links for an Unloaded Node.
|
|
*/
|
|
function LoadedNode_getNumberOfLinks()
|
|
{
|
|
return this.numberOfLinks;
|
|
}
|
|
LoadedNode.prototype.getNumberOfLinks = LoadedNode_getNumberOfLinks;
|
|
|
|
|
|
/**
|
|
* This method should always return
|
|
* true because a LoadedNode is always
|
|
* loaded !
|
|
*/
|
|
function LoadedNode_isLoaded()
|
|
{
|
|
return true;
|
|
}
|
|
LoadedNode.prototype.isLoaded = LoadedNode_isLoaded;
|
|
|
|
|
|
/**
|
|
* This method tells if a node is
|
|
* the same as another according
|
|
* to it's ID number.
|
|
*/
|
|
function LoadedNode_equals (aNode)
|
|
{
|
|
return this.id == aNode.id;
|
|
}
|
|
LoadedNode.prototype.equals = LoadedNode_equals;
|
|
|
|
|
|
/**
|
|
* This method sets the ID of a
|
|
* node to the specified ID. Should
|
|
* normally be used only by the
|
|
* constructor.
|
|
*/
|
|
function LoadedNode_setId (id)
|
|
{
|
|
this.id = id;
|
|
}
|
|
LoadedNode.prototype.setId = LoadedNode_setId;
|
|
|
|
|
|
/**
|
|
* returns the current node's ID.
|
|
*/
|
|
function LoadedNode_getId()
|
|
{
|
|
return this.id;
|
|
}
|
|
LoadedNode.prototype.getId = LoadedNode_getId;
|
|
|
|
|
|
/**
|
|
* This method sets the fatherId of a
|
|
* node to the specified fatherId. Should
|
|
* normally be used only by the constructor.
|
|
*/
|
|
function LoadedNode_setFatherId (fatherId)
|
|
{
|
|
this.fatherId = fatherId;
|
|
}
|
|
LoadedNode.prototype.setFatherId = LoadedNode_setFatherId;
|
|
|
|
|
|
/**
|
|
* returns the current node's fatherId.
|
|
*/
|
|
function LoadedNode_getFatherId()
|
|
{
|
|
return this.fatherId;
|
|
}
|
|
LoadedNode.prototype.getFatherId = LoadedNode_getFatherId;
|
|
|
|
|
|
/**
|
|
* this method sets the name of the
|
|
* current node.
|
|
*/
|
|
function LoadedNode_setName (name)
|
|
{
|
|
this.name = name;
|
|
}
|
|
LoadedNode.prototype.setName = LoadedNode_setName;
|
|
|
|
|
|
/**
|
|
* this method returns the name of the
|
|
* current node.
|
|
*/
|
|
function LoadedNode_getName()
|
|
{
|
|
return this.name;
|
|
}
|
|
LoadedNode.prototype.getName = LoadedNode_getName;
|
|
|
|
|
|
/**
|
|
* Sets whether the node is expanded or not.
|
|
*/
|
|
function LoadedNode_setExpanded (expanded)
|
|
{
|
|
this.expanded = expanded;
|
|
}
|
|
LoadedNode.prototype.setExpanded = LoadedNode_setExpanded;
|
|
|
|
|
|
/**
|
|
* returns true if the node is expanded,
|
|
* false otherwise.
|
|
*/
|
|
function LoadedNode_isExpanded()
|
|
{
|
|
return this.expanded;
|
|
}
|
|
LoadedNode.prototype.isExpanded = LoadedNode_isExpanded;
|
|
|
|
|
|
/**
|
|
* Sets whether the node is selected or not.
|
|
*/
|
|
function LoadedNode_setSelected (selected)
|
|
{
|
|
this.selected = selected;
|
|
}
|
|
LoadedNode.prototype.setSelected = LoadedNode_setSelected;
|
|
|
|
|
|
/**
|
|
* returns true if the node is currently
|
|
* selected, false otherwise.
|
|
*/
|
|
function LoadedNode_isSelected()
|
|
{
|
|
return this.selected;
|
|
}
|
|
LoadedNode.prototype.isSelected = LoadedNode_isSelected;
|
|
|
|
|
|
/**
|
|
* adds a child to this node. Does not
|
|
* currently lookup in the sub-tree to
|
|
* check if the node has been inserted.
|
|
*/
|
|
function LoadedNode_addChild (aChild)
|
|
{
|
|
for (var i=0; i<this.child.length; i++)
|
|
{
|
|
if (this.child[i].equals (aChild)) return;
|
|
}
|
|
for (var i=this.child.length; i>0; i--)
|
|
{
|
|
if (this.child[i-1].getName().toUpperCase() < aChild.getName().toUpperCase())
|
|
{
|
|
this.child[i] = aChild;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
this.child[i] = this.child[i-1];
|
|
}
|
|
}
|
|
this.child[0] = aChild;
|
|
}
|
|
LoadedNode.prototype.addChild = LoadedNode_addChild;
|
|
|
|
|
|
/**
|
|
* removes a child from a node. Does
|
|
* not currently lookup in the sub-tree to
|
|
* check if the node to remove is there
|
|
* but only in the children array.
|
|
*/
|
|
function LoadedNode_delChild (aChild)
|
|
{
|
|
var newChildArray = new Array();
|
|
for (var i=0; i<this.child.length; i++)
|
|
{
|
|
if (this.child[i].equals (aChild))
|
|
{
|
|
;
|
|
}
|
|
else
|
|
{
|
|
newChildArray[newChildArray.length] = this.child[i];
|
|
}
|
|
}
|
|
this.child = newChildArray;
|
|
}
|
|
LoadedNode.prototype.delChild = LoadedNode_delChild;
|
|
|
|
|
|
/**
|
|
* Returns the array of current node's children.
|
|
*/
|
|
function LoadedNode_getChildArray()
|
|
{
|
|
return this.child;
|
|
}
|
|
LoadedNode.prototype.getChildArray = LoadedNode_getChildArray;
|
|
|
|
|
|
/**
|
|
* Returns true if the node is a leaf,
|
|
* false otherwise.
|
|
*/
|
|
function LoadedNode_isLeaf()
|
|
{
|
|
return this.child.length == 0;
|
|
}
|
|
LoadedNode.prototype.isLeaf = LoadedNode_isLeaf;
|
|
|
|
|
|
/**
|
|
* Lookup for a node the id of which is
|
|
* id in the current subtree. If the node
|
|
* is found, returns it, otherwise returns
|
|
* null.
|
|
*/
|
|
function LoadedNode_lookup (id)
|
|
{
|
|
if (this.id == id) return this;
|
|
else
|
|
{
|
|
for (var i=0; i<this.child.length; i++)
|
|
{
|
|
var lookup = this.child[i].lookup(id);
|
|
if (lookup != null) return lookup;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
LoadedNode.prototype.lookup = LoadedNode_lookup;
|
|
|
|
|
|
/**
|
|
* Returns an HTML representation of this node.
|
|
*/
|
|
function LoadedNode_toHtml()
|
|
{
|
|
if (this.getId() == 0) {
|
|
return this.expandButtonHtml() +
|
|
this.folderHtml() +
|
|
" " +
|
|
this.name +
|
|
"</p>\n";
|
|
}
|
|
else {
|
|
return '<a name="' + this.getId() + '"></a>' +
|
|
this.expandButtonHtml() +
|
|
this.folderHtml() +
|
|
" " +
|
|
this.name +
|
|
" (" +
|
|
this.getNumberOfLinks() +
|
|
")</p>\n";
|
|
}
|
|
}
|
|
LoadedNode.prototype.toHtml = LoadedNode_toHtml;
|
|
|
|
|
|
/**
|
|
* Returns HTML code that represents the
|
|
* button which is being clicked to expand
|
|
* or unexpand a node.
|
|
*/
|
|
function LoadedNode_expandButtonHtml()
|
|
{
|
|
var node_id = this.getId();
|
|
if (this.isLeaf())
|
|
{
|
|
return '<img src="' + NODE_EXPAND_BUTTON_FAKE + '" border=0></img>';
|
|
}
|
|
else
|
|
{
|
|
if (this.isExpanded())
|
|
{
|
|
return '<a href="#" onClick="return parent.clickEvent(' +
|
|
"'" + 'LoadedNode' + "', " +
|
|
"'" + 'unexpand' + "', " +
|
|
node_id +
|
|
')"><img src="' +
|
|
NODE_EXPAND_BUTTON_LESS +
|
|
'" border=0></a>';
|
|
}
|
|
else
|
|
{
|
|
return '<a href="#" onClick="return parent.clickEvent(' +
|
|
"'" + 'LoadedNode' + "', " +
|
|
"'" + 'expand' + "', " +
|
|
node_id +
|
|
')"><img src="' +
|
|
NODE_EXPAND_BUTTON_PLUS +
|
|
'" border=0></a>';
|
|
}
|
|
}
|
|
}
|
|
LoadedNode.prototype.expandButtonHtml = LoadedNode_expandButtonHtml;
|
|
|
|
|
|
/**
|
|
* Returns HTML code that represents the
|
|
* folder which is being clicked to be selected.
|
|
*/
|
|
function LoadedNode_folderHtml()
|
|
{
|
|
var node_id = this.getId();
|
|
if (<%is_rooted%> && (node_id == 0)) {
|
|
return '<img src="' +
|
|
NODE_UNSELECTED_BUTTON +
|
|
'" border=0>';
|
|
}
|
|
else {
|
|
return '<a name="' + node_id + '" href="#" onClick="return parent.clickEvent(' +
|
|
"'" + 'LoadedNode' + "', " +
|
|
"'" + 'select' + "', " +
|
|
node_id +
|
|
')"><img src="' +
|
|
NODE_UNSELECTED_BUTTON +
|
|
'" border=0></a>';
|
|
}
|
|
}
|
|
|
|
LoadedNode.prototype.folderHtml = LoadedNode_folderHtml;
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
* Javascript Tree class *
|
|
**************************************************************************************/
|
|
|
|
|
|
/**
|
|
* Builds a new Tree object
|
|
*/
|
|
function Tree()
|
|
{
|
|
this.nodes = new Array();
|
|
this.nodes[<%id%>] = new LoadedNode (<%id%>, <%fatherid%>, "<%name%>", <%nb_links%>);
|
|
this.selectedNodeId = null;
|
|
this.foo = this;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method unselects all the nodes. Added to
|
|
* see if it can fix the netscape 4 / linux selection
|
|
* "Feature".
|
|
*/
|
|
function Tree_unselect()
|
|
{
|
|
for (var i=0; i < this.nodes.length; i++)
|
|
{
|
|
var node = this.nodes[i];
|
|
if (node != null)
|
|
{
|
|
node.setSelected (false);
|
|
}
|
|
}
|
|
}
|
|
Tree.prototype.unselect = Tree_unselect;
|
|
|
|
|
|
/**
|
|
* Searches the tree for a node the
|
|
* id of which would be aNodeId, null
|
|
* if this node does not exist in the
|
|
* tree.
|
|
*/
|
|
function Tree_lookup (aNodeId)
|
|
{
|
|
return this.nodes[aNodeId];
|
|
}
|
|
Tree.prototype.lookup = Tree_lookup;
|
|
|
|
|
|
/**
|
|
* This function takes as input a node id
|
|
* and a boolean and sets the node machine
|
|
* the given node id 'expanded' property.
|
|
*/
|
|
function Tree_setExpandedNodeId (aNodeId, expanded)
|
|
{
|
|
var node = this.lookup (aNodeId);
|
|
if (node != null) node.setExpanded (expanded);
|
|
}
|
|
Tree.prototype.setExpandedNodeId = Tree_setExpandedNodeId;
|
|
|
|
|
|
/**
|
|
* This function returns the currently
|
|
* selected node, if it exists.
|
|
*/
|
|
function Tree_getSelectedNodeId()
|
|
{
|
|
return this.selectedNodeId;
|
|
}
|
|
Tree.prototype.getSelectedNodeId = Tree_getSelectedNodeId;
|
|
|
|
|
|
/**
|
|
* This function changes the currently
|
|
* selected node.
|
|
*/
|
|
function Tree_setSelectedNodeId (aNodeId)
|
|
{
|
|
var selectedNode = this.lookup (this.getSelectedNodeId());
|
|
var nodeToSelect = this.lookup (aNodeId);
|
|
if (nodeToSelect == null) return;
|
|
else
|
|
{
|
|
if (selectedNode == null)
|
|
{
|
|
/* if the selected node is null,
|
|
then we do nothing with it. */
|
|
}
|
|
else
|
|
{
|
|
/* else, we deselect it. */
|
|
selectedNode.setSelected (false);
|
|
}
|
|
/* then we select the new node */
|
|
nodeToSelect.setSelected (true);
|
|
}
|
|
}
|
|
Tree.prototype.setSelectedNodeId = Tree_setSelectedNodeId;
|
|
|
|
|
|
/**
|
|
* Adds a node to the tree.
|
|
*/
|
|
function Tree_addNode (aNode)
|
|
{
|
|
var fathernode = this.lookup (aNode.getFatherId());
|
|
if (fathernode == null)
|
|
{
|
|
alert ("Software error: Cannot add node " +
|
|
aNode.getName() +
|
|
" because node with id " +
|
|
aNode.getFatherId() +
|
|
" does not exist.");
|
|
return;
|
|
}
|
|
|
|
this.delNode (aNode);
|
|
if (fathernode.isLoaded())
|
|
{
|
|
fathernode.addChild (aNode);
|
|
this.nodes[aNode.getId()] = aNode;
|
|
}
|
|
else
|
|
{
|
|
fathernode = new LoadedNode (fathernode.getId(),
|
|
fathernode.getFatherId(),
|
|
fathernode.getName(),
|
|
fathernode.getNumberOfLinks());
|
|
this.addNode (fathernode);
|
|
this.addNode (aNode);
|
|
}
|
|
}
|
|
Tree.prototype.addNode = Tree_addNode;
|
|
|
|
|
|
/**
|
|
* deletes a node from the tree.
|
|
*/
|
|
function Tree_delNode (aNode)
|
|
{
|
|
var node = this.lookup (aNode.getId());
|
|
var fathernode = this.lookup (aNode.getFatherId());
|
|
|
|
if (node == null || fathernode == null) return;
|
|
else
|
|
{
|
|
(this.lookup (node.getFatherId())).delChild (node);
|
|
this.nodes[node.getId()] = null;
|
|
}
|
|
}
|
|
Tree.prototype.delNode = Tree_delNode;
|
|
|
|
|
|
/**
|
|
* Returns an HTML representation of the Tree.
|
|
*/
|
|
function Tree_toHtml()
|
|
{
|
|
return '<html><head>\n' +
|
|
'<body bgcolor="#FFFFFF">' +
|
|
'<p><font face="Tahoma,Arial,Helvetica" size="2"><%if not is_admin%><b>Editor:</b><br><%Name%> (<%owner_links%>)<br><br><%endif%><b>Category Browser:</b><br>' +
|
|
this.toHtml_nodeLevel (<%id%>, 0) +
|
|
'</font></p></body></html>';
|
|
}
|
|
Tree.prototype.toHtml = Tree_toHtml;
|
|
|
|
|
|
function Tree_toHtml_nodeLevel (nodeid, level)
|
|
{
|
|
var node = this.lookup (nodeid);
|
|
result = '<p style="margin-top:5;margin-bottom:5"><nobr>';
|
|
if (node == null) ;
|
|
else
|
|
{
|
|
var width = 10 * level;
|
|
var leftspace = '<img src="' + NODE_EXPAND_BUTTON_FAKE + '" width="' + width + '" height=1 border=0>';
|
|
result += leftspace + node.toHtml() + "\n";
|
|
if (node.isExpanded())
|
|
{
|
|
level++;
|
|
var childArray = node.getChildArray();
|
|
for (var i=0; i<childArray.length; i++)
|
|
{
|
|
result += this.toHtml_nodeLevel (childArray[i].getId(), level);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
Tree.prototype.toHtml_nodeLevel = Tree_toHtml_nodeLevel;
|
|
|
|
|
|
|
|
/**************************************************************************************
|
|
* Javascript main control subroutines *
|
|
**************************************************************************************/
|
|
|
|
|
|
function refresh_tree_empty()
|
|
{
|
|
frames[CODE_FRAME_ID].location.replace ("<%Links::Browser::JFunction::tree_reload_empty()%>&anticache=" + anticache());
|
|
return false;
|
|
}
|
|
|
|
|
|
function refresh_tree_full()
|
|
{
|
|
frames[CODE_FRAME_ID].location.replace ("<%Links::Browser::JFunction::tree_reload_full()%>&anticache=" + anticache());
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* This function is triggered when the user adds a node
|
|
* in order to update the tree if necessary.
|
|
*/
|
|
function user_add_node (id)
|
|
{
|
|
var node_to_refresh = tree.lookup (id);
|
|
if (node_to_refresh.isLoaded())
|
|
{
|
|
frames[CODE_FRAME_ID].location.replace ("<%Links::Browser::JFunction::user_add_node()%>&category_id=" +
|
|
"&anticache=" + anticache());
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* if the node is not loaded, then we need not do anything
|
|
* because it will be updated whenever the user expands it.
|
|
*/
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* This function redraws the javascript tree.
|
|
*/
|
|
function draw_tree()
|
|
{
|
|
if (tree != null)
|
|
{
|
|
frames[LEFT_FRAME_ID].document.open();
|
|
frames[LEFT_FRAME_ID].document.writeln (tree.toHtml());
|
|
frames[LEFT_FRAME_ID].document.close();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* This method loads the information which is related to node
|
|
* with id id into the tree structure.
|
|
*/
|
|
function tree_loadnode (id)
|
|
{
|
|
frames[CODE_FRAME_ID].location.replace ("<%Links::Browser::JFunction::tree_loadnode()%>&category_id=" + id +
|
|
"&anticache=" + anticache());
|
|
}
|
|
|
|
/**
|
|
* A cool comment goes here
|
|
*/
|
|
function list_links (id)
|
|
{
|
|
/* frames[RIGHT_FRAME_ID].location */
|
|
}
|
|
|
|
/**
|
|
* Triggered when the user selects a node.
|
|
*/
|
|
function select_node (id)
|
|
{
|
|
tree.setSelectedNodeId (id);
|
|
frames[RIGHT_FRAME_ID].location.replace ("<%Links::Browser::JFunction::tree_selectnode()%>&category_id=" + id +
|
|
"&anticache=" + anticache());
|
|
draw_tree();
|
|
set_location (id);
|
|
}
|
|
|
|
/**
|
|
* This function is triggered whenever an user wants to move
|
|
* node with id from to node with id to.
|
|
*/
|
|
function move_node (from, to)
|
|
{
|
|
frames[LEFT_FRAME_ID].document.body.innerHTML = '<H2><BLINK>Querying database...</BLINK></H2>';
|
|
frames[RIGHT_FRAME_ID].location.replace ("<%Links::Browser::JFunction::tree_movenode()%>&category_from=" + from +
|
|
"&category_to=" + to + "&anticache=" + anticache());
|
|
}
|
|
|
|
|
|
/**
|
|
* this function is moves a link from a category to
|
|
* another category which is clicked by the user.
|
|
*/
|
|
function link_move (linkid, oldcategoryid, newcategoryid)
|
|
{
|
|
frames[RIGHT_FRAME_ID].location.replace ("<%Links::Browser::JFunction::movelink()%>&old_category_id=" + oldcategoryid +
|
|
"&new_category_id=" + newcategoryid +
|
|
"&link_id=" + linkid + "&anticache=" + anticache());
|
|
}
|
|
|
|
|
|
/**
|
|
* this function is copies a link from a category to
|
|
* another category which is clicked by the user.
|
|
*/
|
|
function link_copy (linkid, oldcategoryid, newcategoryid)
|
|
{
|
|
frames[RIGHT_FRAME_ID].location.replace ("<%Links::Browser::JFunction::copylink()%>&old_category_id=" + oldcategoryid +
|
|
"&new_category_id=" + newcategoryid +
|
|
"&link_id=" + linkid + "&anticache=" + anticache());
|
|
}
|
|
|
|
|
|
/**
|
|
* clickEvent function. This is the main function, it
|
|
* is supposed to trigger the right functions according
|
|
* to the user actions and the state of the program.
|
|
*/
|
|
function clickEvent (classname, action, id)
|
|
{
|
|
if (ready == null || !ready) return false;
|
|
if (classname == "LoadedNode")
|
|
{
|
|
var node = tree.lookup (id);
|
|
if (action == "expand")
|
|
{
|
|
node.setExpanded (true);
|
|
draw_tree();
|
|
set_location (id);
|
|
}
|
|
else if (action == "unexpand")
|
|
{
|
|
node.setExpanded (false);
|
|
draw_tree();
|
|
set_location (id);
|
|
}
|
|
else if (action == "select")
|
|
{
|
|
/*
|
|
* Can't click on root node if base is set.
|
|
*/
|
|
if (<%is_rooted%> && (id == 0)) {
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* We test if the right frame is a move frame. If so, when
|
|
* user clicks on a node then we must trigger a move action,
|
|
* otherwise it is a normal select action.
|
|
*/
|
|
if (frames[RIGHT_FRAME_ID].move_from && typeof(frames[RIGHT_FRAME_ID].move_from) != "function")
|
|
{
|
|
CAN_UPDATE = 1;
|
|
move_node (frames[RIGHT_FRAME_ID].move_from, id);
|
|
}
|
|
else if (frames[RIGHT_FRAME_ID].link_move && typeof(frames[RIGHT_FRAME_ID].link_move) != "function")
|
|
{
|
|
CAN_UPDATE = 1;
|
|
link_move (frames[RIGHT_FRAME_ID].link_move, frames[RIGHT_FRAME_ID].old_category_id, id)
|
|
}
|
|
else if (frames[RIGHT_FRAME_ID].link_copy && typeof(frames[RIGHT_FRAME_ID].link_copy) != "function")
|
|
{
|
|
CAN_UPDATE = 1;
|
|
link_copy (frames[RIGHT_FRAME_ID].link_copy, frames[RIGHT_FRAME_ID].old_category_id, id)
|
|
}
|
|
else if (frames[RIGHT_FRAME_ID].related_to && typeof(frames[RIGHT_FRAME_ID].related_to) != "function")
|
|
{
|
|
frames[RIGHT_FRAME_ID].document.related_form.related_to.value = id;
|
|
frames[RIGHT_FRAME_ID].document.related_form.category_id.value = frames[RIGHT_FRAME_ID].related_to;
|
|
frames[RIGHT_FRAME_ID].document.related_form.submit();
|
|
}
|
|
else
|
|
{
|
|
select_node (id);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alert ("Software error: '" + action + "' is not a valid action");
|
|
}
|
|
}
|
|
else if (classname == "UnloadedNode")
|
|
{
|
|
if (action == "expand")
|
|
{
|
|
frames[LEFT_FRAME_ID].document.body.innerHTML = '<H2><BLINK>Querying database...</BLINK></H2>';
|
|
tree_loadnode (id);
|
|
return false;
|
|
}
|
|
else if (action == "unexpand")
|
|
{
|
|
alert ("Software error: unexpand should never happen on an UnloadedNode !");
|
|
}
|
|
else if (action == "select")
|
|
{
|
|
/*
|
|
* We test if the right frame is a move frame. If so, when
|
|
* user clicks on a node then we must trigger a move action,
|
|
* otherwise it is a normal select action.
|
|
*/
|
|
if (frames[RIGHT_FRAME_ID].move_from && typeof(frames[RIGHT_FRAME_ID].move_from) != "function")
|
|
{
|
|
CAN_UPDATE = 1;
|
|
move_node (frames[RIGHT_FRAME_ID].move_from, id);
|
|
}
|
|
else if (frames[RIGHT_FRAME_ID].link_move && typeof(frames[RIGHT_FRAME_ID].link_move) != "function")
|
|
{
|
|
CAN_UPDATE = 1;
|
|
link_move (frames[RIGHT_FRAME_ID].link_move, frames[RIGHT_FRAME_ID].old_category_id, id)
|
|
}
|
|
else if (frames[RIGHT_FRAME_ID].link_copy && typeof(frames[RIGHT_FRAME_ID].link_copy) != "function")
|
|
{
|
|
CAN_UPDATE = 1;
|
|
link_copy (frames[RIGHT_FRAME_ID].link_copy, frames[RIGHT_FRAME_ID].old_category_id, id)
|
|
}
|
|
else if (frames[RIGHT_FRAME_ID].related_to && typeof(frames[RIGHT_FRAME_ID].related_to) != "function")
|
|
{
|
|
frames[RIGHT_FRAME_ID].document.related_form.related_to.value = id;
|
|
frames[RIGHT_FRAME_ID].document.related_form.category_id.value = frames[RIGHT_FRAME_ID].related_to;
|
|
frames[RIGHT_FRAME_ID].document.related_form.submit();
|
|
}
|
|
else
|
|
{
|
|
select_node (id);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alert ("Software error: '" + action + "' is not a valid action");
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* This function returns a 10 bytes long random string
|
|
* in order to cheat the navigator's cache.
|
|
*/
|
|
function anticache()
|
|
{
|
|
var elements = [ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ];
|
|
var result = "";
|
|
for (var i=0; i<10; i++) result += elements[Math.round((elements.length - 1) * Math.random())];
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* This function is triggered when the whole frameset is loaded.
|
|
*/
|
|
function frameset_onLoad()
|
|
{
|
|
tree = new Tree();
|
|
frames[LEFT_FRAME_ID].location = "about:blank";
|
|
frames[RIGHT_FRAME_ID].location = "about:blank";
|
|
frames[CODE_FRAME_ID].location = "about:blank";
|
|
setTimeout('frames[LEFT_FRAME_ID].location = "<%Links::Browser::JFunction::tree_panel_url%>&anticache=" + anticache();', 100);
|
|
setTimeout('frames[RIGHT_FRAME_ID].location = "<%Links::Browser::JFunction::info_panel_url%>&anticache=" + anticache();', 100);
|
|
setTimeout('frames[CODE_FRAME_ID].location = "<%Links::Browser::JFunction::code_panel_url%>&anticache=" + anticache();', 100);
|
|
ready = true;
|
|
}
|
|
|
|
/**
|
|
* Set the location, this prevents the tree from redrawing and positioning
|
|
* up at the top again. Only works in IE 5.5, but Netscape behave nicely.
|
|
*/
|
|
function set_location (node_id) {
|
|
if (document.all) {
|
|
if (isIE()) {
|
|
frames[LEFT_FRAME_ID].location.hash = node_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
function isIE() {
|
|
var ver = window.navigator.appVersion;
|
|
|
|
var pos = ver.search('MSIE ');
|
|
var ie = false;
|
|
|
|
if ( pos == -1 ) {
|
|
return ie;
|
|
}
|
|
|
|
if ( ver.substr(pos + 5, 1) > 5 ) {
|
|
ie = true;
|
|
}
|
|
else if ( ver.substr(pos + 5, 1) == 5 ) {
|
|
var v = ver.substr(pos + 7, 1);
|
|
if ( !isNaN(v) && v >= 5 ) {
|
|
ie = true;
|
|
}
|
|
}
|
|
return ie;
|
|
}
|
|
|
|
/***************************************************************************************
|
|
* Javascript and HTML startup *
|
|
**************************************************************************************/
|
|
|
|
|
|
</script>
|
|
|
|
<title>Gossamer Links</title>
|
|
|
|
</head>
|
|
|
|
<script language="Javascript">
|
|
document.writeln (
|
|
'<FRAMESET COLS="25%,74%,1" FRAMEBORDER="0" onLoad="frameset_onLoad()">' +
|
|
'<FRAME NAME="left" scrolling="auto" src="about:blank"></FRAME>' +
|
|
'<FRAME NAME="right" scrolling="auto" src="about:blank"></FRAME>' +
|
|
'<FRAME NAME="code" scrolling="no" src="about:blank"></FRAME>' +
|
|
'</FRAMESET>' );
|
|
</script>
|
|
<NOSCRIPT>
|
|
<BODY BGCOLOR="#FFFFFF"><CENTER><H1>
|
|
You will need to have JavaScript enabled in order to use the Category Browser.
|
|
</H1></CENTER></BODY>
|
|
</NOSCRIPT>
|
|
</HTML>
|
|
|
|
|