home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.swcp.com
/
ftp.swcp.com.zip
/
ftp.swcp.com
/
mac
/
mozilla-macos9-1.3.1.sea.bin
/
Mozilla1.3.1
/
Chrome
/
comm.jar
/
content
/
communicator
/
bookmarks
/
bookmarks.xml
< prev
next >
Wrap
Extensible Markup Language
|
2003-06-08
|
98KB
|
2,180 lines
<?xml version="1.0"?>
<!-- -*- Mode: HTML; indent-tabs-mode: nil; -*- -->
<!--
The contents of this file are subject to the Netscape Public
License Version 1.1 (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.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is mozilla.org code.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s):
Ben Goodger <ben@netscape.com> (Original Author)
Blake Ross <blakeross@telocity.com>
-->
<!DOCTYPE window [
<!ENTITY % bookmarksDTD SYSTEM "chrome://communicator/locale/bookmarks/bookmarks.dtd" >
%bookmarksDTD;
]>
<bindings id="bookmarksBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="bookmarksBase">
<implementation>
<!-- RDF Namespace URIs -->
<field name="RDF_NS">"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</field>
<field name="NC_NS">"http://home.netscape.com/NC-rdf#"</field>
<field name="NC_NS_CMD">this.NC_NS + "command?cmd=";</field>
<property name="rdfContainer">
<getter><![CDATA[
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFCIID = Components.interfaces.nsIRDFContainer;
return Components.classes[kRDFCContractID].getService(kRDFCIID);
]]></getter>
</property>
<field name="_rdf">null</field>
<property name="rdf">
<getter><![CDATA[
if (!this._rdf) {
const kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFIID = Components.interfaces.nsIRDFService;
this._rdf = Components.classes[kRDFContractID].getService(kRDFIID);
}
return this._rdf;
]]></getter>
</property>
<field name="_bundle">null</field>
<field name="_bookmarksDS">null</field>
<property name="bookmarksDS">
<getter><![CDATA[
if (!this._bookmarksDS)
this._bookmarksDS = this.rdf.GetDataSource("rdf:bookmarks");
return this._bookmarksDS;
]]></getter>
</property>
<method name="flushBMDatasource">
<body><![CDATA[
var remoteDS = this.bookmarksDS.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
remoteDS.Flush();
]]></body>
</method>
</implementation>
</binding>
<binding id="bookmarks-tree"
extends="chrome://communicator/content/bookmarks/bookmarks.xml#bookmarksBase">
<implementation>
<constructor><![CDATA[
var bookmarksSvc = Components.classes["@mozilla.org/browser/bookmarks-service;1"].getService(Components.interfaces.nsIBookmarksService);
// This function only reads in the bookmarks from disk if they have not already been read.
bookmarksSvc.ReadBookmarks();
// We implement nsIController
this.tree.controllers.appendController(this.controller);
var olb = document.getAnonymousElementByAttribute(this, "anonid", "bookmarks-tree");
olb = olb.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
olb.addObserver(this.builderObserver);
// need to create string bundle manually instead of using <xul:stringbundle/>
// see bug 63370 for details
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
.getService(Components.interfaces.nsILocaleService);
var stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
var bundleURL = "chrome://communicator/locale/bookmarks/bookmark.properties";
this._bundle = stringBundleService.createBundle(bundleURL, localeService.GetApplicationLocale());
// Load column settings from persisted attribute
var colinfostr = this.getAttribute("colinfo");
var colinfo = colinfostr.split(" ");
for (var i = 0; i < colinfo.length; ++i) {
if (colinfo[i] == "") continue;
var querymarker = colinfo[i].indexOf("?");
var anonid = colinfo[i].substring(4, querymarker);
var col = document.getAnonymousElementByAttribute(this, "id", anonid);
if (!anonid || !col) break;
var attrstring = colinfo[i].substr(querymarker + 1);
var attrpairs = attrstring.split("&");
for (var j = 0; j < attrpairs.length; ++j) {
var pair = attrpairs[j].split("=");
col.setAttribute(pair[0], pair[1]);
}
}
// Load sort data from preferences
this.refreshSort();
// Observe for changes in sort from other concurrent UI
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var prefs = prefSvc.getBranch(null);
const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranchInternal;
var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
bookmarksPrefsInternal.addObserver(this.sortChangedObserver.domain,
this.sortChangedObserver, false);
]]></constructor>
<destructor><![CDATA[
this.treeBuilder.removeObserver(this.builderObserver);
this.tree.controllers.removeController(this.controller);
// Save column settings and sort info to persisted attribute
var persistString = "";
var sortResource = this.NC_NS + "Name";
var sortDirection = "none";
var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
var child = treecols.firstChild;
while (child) {
if (child.localName != "splitter") {
var formatString = " col:%1%?width=%2%&hidden=%3%&ordinal=%6%";
formatString = formatString.replace(/%1%/, child.getAttribute("id"));
formatString = formatString.replace(/%2%/, child.getAttribute("width"));
formatString = formatString.replace(/%3%/, child.getAttribute("hidden"));
// While we're walking the columns, if we discover the column that represents the
// field sorted by, save the resource associated with that column so that we
// can save that in prefs (see below)
if (child.getAttribute("sortActive") == "true") {
sortResource = child.getAttribute("sort");
sortDirection = child.getAttribute("sortDirection");
}
formatString = formatString.replace(/%6%/, child.getAttribute("ordinal"));
persistString += formatString;
}
child = child.nextSibling;
}
this.setAttribute("colinfo", persistString);
document.persist(this.id, "colinfo");
// Unhook the sort change observer for this tree
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var prefs = prefSvc.getBranch(null);
const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranchInternal;
var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
bookmarksPrefsInternal.removeObserver(this.sortChangedObserver.domain,
this.sortChangedObserver);
]]></destructor>
<field name="sortChangedObserver">
<![CDATA[
({
outer: this,
domain: "browser.bookmarks.sort",
observe: function BMOL_sortChangedObserver(aSubject, aTopic, aPrefName)
{
if (aTopic != "nsPref:changed") return;
if (aPrefName.substr(0, this.domain.length) != this.domain) return;
this.outer.refreshSort();
}
})
]]>
</field>
<field name="sorted">false</field>
<method name="refreshSort">
<body>
<![CDATA[
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
// This ensures that we don't sort twice in the tree that is clicked on
// as a result of 1) the click and 2) the pref listener.
if (!this.sorted) {
try {
var sortResource = bookmarksSortPrefs.getCharPref("resource");
var sortDirection = bookmarksSortPrefs.getCharPref("direction");
// Walk the columns, when we find a column with a sort resource that matches the supplied
// data, stop and make sure it's sort active.
var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
var child = treecols.firstChild;
while (child) {
if (child.localName != "splitter") {
if (child.getAttribute("sort") == sortResource) {
child.setAttribute("sortActive", "true");
child.setAttribute("sortDirection", sortDirection);
this.treeBuilder.sort(child, false);
break;
}
}
child = child.nextSibling;
}
}
catch (e) {
}
}
this.sorted = false;
]]>
</body>
</method>
<property name="columns">
<getter>
<![CDATA[
var cols = [];
var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
var child = treecols.firstChild;
while (child) {
if (child.localName != "splitter") {
var obj = {
label: child.getAttribute("label"),
accesskey: child.getAttribute("accesskey"),
resource: child.getAttribute("sort"),
sortActive: child.getAttribute("sortActive") == "true",
hidden: child.getAttribute("hidden")
}
cols.push(obj);
}
child = child.nextSibling;
}
return cols;
]]>
</getter>
</property>
<method name="toggleColumnVisibility">
<parameter name="aColumnResource"/>
<body>
<![CDATA[
var elt = document.getAnonymousElementByAttribute(this, "sort", aColumnResource);
if (elt)
elt.setAttribute("hidden", elt.getAttribute("hidden") != "true");
]]>
</body>
</method>
<property name="treeBoxObject">
<getter><![CDATA[
return this.tree.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);
]]></getter>
</property>
<property name="treeBuilder">
<getter><![CDATA[
return this.tree.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
]]></getter>
</property>
<property name="tree">
<getter><![CDATA[
return document.getAnonymousElementByAttribute(this, "anonid", "bookmarks-tree");
]]></getter>
</property>
<property name="currentIndex">
<getter><![CDATA[
return this.treeBoxObject.selection.currentIndex;
]]></getter>
</property>
<property name="currentRes">
<getter><![CDATA[
return this.treeBuilder.getResourceAtIndex(this.currentIndex);
]]></getter>
</property>
<property name="parentRes">
<getter><![CDATA[
const currIndex = this.currentIndex;
if (currIndex == -1)
return this.rdf.GetResource("NC:BookmarksRoot");
var parentIndex = this.treeBoxObject.view.getParentIndex(currIndex);
if (parentIndex != -1)
return this.treeBuilder.getResourceAtIndex(parentIndex)
return this.rdf.GetResource("NC:BookmarksRoot"); // assume its parent is the root
]]></getter>
</property>
<property name="firstSelectedIndex">
<getter><![CDATA[
var first = { };
this.treeBoxObject.selection.getRangeAt(0, first, { });
return first.value;
]]></getter>
</property>
<property name="lastSelectedIndex">
<getter><![CDATA[
var bo = this.treeBoxObject;
var last = { };
var rangeCount = bo.selection.getRangeCount();
bo.selection.getRangeAt(rangeCount - 1, { }, last);
return last.value;
]]></getter>
</property>
<property name="_browserURL">
<getter><![CDATA[
try {
var prefs = Components.classes["@mozilla.org/preferences;1"];
if (prefs) {
prefs = prefs.getService();
if (prefs)
prefs = prefs.QueryInterface(Components.interfaces.nsIPref);
}
if (prefs) {
var url = prefs.CopyCharPref("browser.chromeURL");
if (url)
return url;
}
} catch(e) {
}
return "chrome://navigator/content/navigator.xul";
]]></getter>
</property>
<field name="_type">null</field>
<property name="type">
<getter><![CDATA[
if (!this._type) {
var type = this.getAttribute("type");
if (!type)
type = "multi-column";
this._type = type;
}
return this._type;
]]></getter>
</property>
<!-- Returns the row index of the best row at which to perform an operation
relative to the current selection, e.g. creating a new bookmark
adjacent to the current selection. -->
<method name="getNextRowIndex">
<body><![CDATA[
var bo = this.treeBoxObject;
var rangeCount = bo.selection.getRangeCount();
var currLevel, lastIndex = 0;
if (!rangeCount)
currLevel = 0;
else
currLevel = bo.view.getLevel(this.firstSelectedIndex);
// Walk the selection. If the level for the current item is less than
// our running minimum, assume it is higher in the hierarchy than any
// previous. In this case, or in the case with a selected item of same
// hierarchy, set the lastIndex.
// XXXben - erk this comment sort of sucks. A diagram might help.
for (var i = 0; i < rangeCount; ++i) {
var rangeMin = { };
var rangeMax = { };
bo.selection.getRangeAt(i, rangeMin, rangeMax);
for (var j = rangeMax.value; j >= rangeMin.value; --j) {
var level = bo.view.getLevel(j);
if (level <= currLevel) {
currLevel = level;
lastIndex = j;
}
}
}
return lastIndex;
]]></body>
</method>
<method name="getTypeAtIndex">
<parameter name="aIndex" />
<body><![CDATA[
try {
return BookmarksUtils.resolveType(this.treeBuilder.getResourceAtIndex(aIndex));
}
catch(ex) {
return null;
}
]]></body>
</method>
<!-- observer -->
<field name="newFolderRDFObserver" readonly="true"><![CDATA[
({
_newFolderURI: null,
onAssert: function (aDS, aSource, aProperty, aValue)
{
try {
var value = aValue.QueryInterface(Components.interfaces.nsIRDFResource);
if (aDS.URI == "rdf:bookmarks" && aProperty.Value == this.RDF_NS + "type" &&
value.Value == this.NC_NS + "Folder")
this._newFolderURI = aSource.Value;
}
catch (e) {
// Failures are OK, the value could be a literal instead of a resource.
}
},
onUnassert: function (aDS, aSource, aProperty, aTarget) { },
onChange: function (aDS, aSource, aProperty, aOldTarget, aNewTarget) { },
onMove: function (aDS, aOldSource, aNewSource, aProperty, aTarget) { },
beginUpdateBatch: function (aDS) { },
endUpdateBatch: function (aDS) { }
})
]]></field>
<!-- observer -->
<field name="DNDObserver" readonly="true"><![CDATA[
({
mOuter: this,
onDragStart: function (aEvent, aXferData, aDragAction)
{
if (this.mOuter.tree.getAttribute("sortActive") == "true")
throw Components.results.NS_OK;
aXferData.data = new TransferDataSet();
var rangeCount = this.mOuter.treeBoxObject.selection.getRangeCount();
for (var i = rangeCount - 1; i >= 0; --i) {
var rangeMin = { };
var rangeMax = { };
this.mOuter.treeBoxObject.selection.getRangeAt(i, rangeMin, rangeMax);
for (var j = rangeMax.value; j >= rangeMin.value; --j) {
var currRes = this.mOuter.treeBuilder.getResourceAtIndex(j);
var parentIndex = this.mOuter.treeBoxObject.view.getParentIndex(j);
var parentRes;
if (parentIndex == -1)
parentRes = this.mOuter.rdf.GetResource("NC:BookmarksRoot");
else
parentRes = this.mOuter.treeBuilder.getResourceAtIndex(parentIndex);
var type = this.mOuter.db.GetTarget(currRes, this.mOuter.rdf.GetResource(this.mOuter.RDF_NS + "type"), true);
type = type.QueryInterface(Components.interfaces.nsIRDFResource).Value;
if (!type || (type != (this.mOuter.NC_NS + "BookmarkSeparator") &&
type != (this.mOuter.NC_NS + "Bookmark") &&
type != (this.mOuter.NC_NS + "Folder")))
throw Components.results.NS_OK;
var name = this.mOuter.db.GetTarget(currRes, this.mOuter.rdf.GetResource(this.mOuter.NC_NS + "Name"), true);
var data = new TransferData();
if (name) {
name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
data.addDataForFlavour("text/x-moz-url", currRes.Value + "\n" + name);
}
else {
data.addDataForFlavour("text/x-moz-url", currRes.Value);
}
data.addDataForFlavour("moz/rdfitem", currRes.Value + "\n" + parentRes.Value);
data.addDataForFlavour("text/unicode", currRes.Value);
aXferData.data.push(data);
}
if (aEvent.ctrlKey) {
const kDSIID = Components.interfaces.nsIDragService;
aDragAction.action = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
}
}
}
})
]]></field>
<!-- nsIController -->
<field name="controller" readonly="true"><![CDATA[
({
mOuter: this,
supportsCommand: function BMOLController_supportsCommand(aCommand)
{
switch (aCommand) {
case "cmd_bm_undo":
case "cmd_bm_redo":
return false;
case "cmd_bm_cut":
case "cmd_bm_copy":
case "cmd_bm_paste":
case "cmd_bm_delete":
case "cmd_bm_selectAll":
case "cmd_bm_open":
case "cmd_bm_openinnewwindow":
case "cmd_bm_openfolder":
case "cmd_bm_newbookmark":
case "cmd_bm_newfolder":
case "cmd_bm_newseparator":
case "cmd_bm_find":
case "cmd_bm_properties":
case "cmd_bm_rename":
case "cmd_bm_setnewbookmarkfolder":
case "cmd_bm_setpersonaltoolbarfolder":
case "cmd_bm_setnewsearchfolder":
case "cmd_bm_import":
case "cmd_bm_export":
case "cmd_bm_fileBookmark":
return true;
default:
return false;
}
},
isCommandEnabled: function BMOLController_isCommandEnabled(aCommand)
{
var bo = this.mOuter.treeBoxObject;
var type; // The bookmark's RDF:type arc
switch (aCommand) {
case "cmd_bm_undo":
case "cmd_bm_redo":
return false;
case "cmd_bm_openfolder":
// 'Expand' is only available if one item is selected and that item is a
// container item.
return bo.view.rowCount && bo.selection.count == 1 && bo.view.isContainer(this.mOuter.firstSelectedIndex);
case "cmd_bm_open":
return this.mOuter.getTypeAtIndex(this.mOuter.firstSelectedIndex) == this.mOuter.NC_NS + "Bookmark";
case "cmd_bm_openinnewwindow":
return true;
case "cmd_bm_rename":
case "cmd_bm_properties":
if (bo.selection.count != 1)
return false;
type = this.mOuter.getTypeAtIndex(this.mOuter.firstSelectedIndex);
return type == this.mOuter.NC_NS + "Bookmark" || type == this.mOuter.NC_NS + "Folder";
case "cmd_bm_cut":
type = this.mOuter.getTypeAtIndex(this.mOuter.firstSelectedIndex);
if (type != this.mOuter.NC_NS + "Bookmark" && type != this.mOuter.NC_NS + "BookmarkSeparator" && type != this.mOuter.NC_NS + "Folder")
return false;
return bo.selection.count > 0;
case "cmd_bm_find":
return true;
case "cmd_bm_newbookmark":
case "cmd_bm_newfolder":
case "cmd_bm_newseparator":
// This is not really correct because it gives the false impression
// that it is possible to create an item as a child of some immutable folders
// like IE Favorites, but it will do for now.
return true;
case "cmd_bm_delete":
// Determining whether or not the selection is mutable is handled by
// the deletion routine.
type = this.mOuter.getTypeAtIndex(this.mOuter.firstSelectedIndex);
if (type != this.mOuter.NC_NS + "Bookmark" && type != this.mOuter.NC_NS + "BookmarkSeparator" &&
type != this.mOuter.NC_NS + "Folder" && type != this.mOuter.NC_NS + "IEFavoriteFolder")
return false;
return bo.selection.count >= 1;
case "cmd_bm_selectAll":
// "Select All" is disabled when all visible rows are selected.
// XXXben this could be cleverer.
return bo.view.rowCount != bo.selection.count;
case "cmd_bm_copy":
return bo.selection.count >= 1;
case "cmd_bm_paste":
return this.mOuter.canPaste();
case "cmd_bm_setnewbookmarkfolder":
case "cmd_bm_setpersonaltoolbarfolder":
case "cmd_bm_setnewsearchfolder":
if (bo.selection.count != 1)
return false;
// XXXbar if a folder has more than one of these special attributes,
// this won't work
var folderURI;
if (aCommand == "cmd_bm_setnewbookmarkfolder")
folderURI = "NC:NewBookmarkFolder";
else if (aCommand == "cmd_bm_setpersonaltoolbarfolder")
folderURI = "NC:PersonalToolbarFolder";
else
folderURI = "NC:NewSearchFolder";
return (this.mOuter.getTypeAtIndex(this.mOuter.firstSelectedIndex) == this.mOuter.NC_NS + "Folder")
&& (this.mOuter.treeBuilder.getResourceAtIndex(this.mOuter.firstSelectedIndex).Value != folderURI);
case "cmd_bm_import":
case "cmd_bm_export":
return true;
case "cmd_bm_fileBookmark":
if (bo.selection.count < 1)
return false;
type = this.mOuter.getTypeAtIndex(this.mOuter.firstSelectedIndex);
return type == this.mOuter.NC_NS + "Folder" || type == this.mOuter.NC_NS + "Bookmark";
default:
return false;
}
},
doCommand: function BMOLController_doCommand(aCommand)
{
switch (aCommand) {
case "cmd_bm_cut":
this.mOuter.copySelection();
this.mOuter.deleteSelection();
break;
case "cmd_bm_copy":
this.mOuter.copySelection();
break;
case "cmd_bm_paste":
this.mOuter.paste();
break;
case "cmd_bm_delete":
this.mOuter.deleteSelection();
break;
case "cmd_bm_selectAll":
this.mOuter.selectAll();
break;
case "cmd_bm_open":
this.mOuter.openItem(null, false, false);
break;
case "cmd_bm_openfolder":
this.mOuter.treeBoxObject.view.toggleOpenState(this.mOuter.currentIndex);
break;
case "cmd_bm_openinnewwindow":
var type = this.mOuter.getTypeAtIndex(this.mOuter.currentIndex);
if (type == this.mOuter.NC_NS + "Folder")
this.mOuter.openFolderInNewWindow();
else
this.mOuter.openItem(null, true, false);
break;
case "cmd_bm_newbookmark":
this.mOuter.addBookmark();
break;
case "cmd_bm_newfolder":
this.mOuter.createNewFolder();
break;
case "cmd_bm_newseparator":
this.mOuter.createNewSeparator();
break;
case "cmd_bm_find":
this.mOuter.openFindDialog();
break;
case "cmd_bm_properties":
case "cmd_bm_rename":
this.mOuter.openPropertiesForItem();
break;
case "cmd_bm_setnewbookmarkfolder":
this.mOuter.setAsNewBookmarkFolder();
break;
case "cmd_bm_setpersonaltoolbarfolder":
this.mOuter.setAsPersonalToolbarFolder();
break;
case "cmd_bm_setnewsearchfolder":
this.mOuter.setAsNewSearchFolder();
break;
case "cmd_bm_import":
this.mOuter.importBookmarks();
break;
case "cmd_bm_export":
this.mOuter.exportBookmarks();
break;
case "cmd_bm_fileBookmark":
this.mOuter.fileBookmark();
break;
default:
}
}
})
]]></field>
<method name="onCommandUpdate">
<body><![CDATA[
var commands = ["cmd_bm_properties", "cmd_bm_rename", "cmd_bm_copy",
"cmd_bm_paste", "cmd_bm_cut", "cmd_bm_delete",
"cmd_bm_setpersonaltoolbarfolder",
"cmd_bm_setnewbookmarkfolder",
"cmd_bm_setnewsearchfolder", "cmd_bm_fileBookmark",
"cmd_bm_openfolder"];
for (var i = 0; i < commands.length; ++i) {
var enabled = this.controller.isCommandEnabled(commands[i]);
var commandNode = document.getElementById(commands[i]);
if (commandNode) {
if (enabled)
commandNode.removeAttribute("disabled");
else
commandNode.setAttribute("disabled", "true");
}
}
]]></body>
</method>
<method name="selectionChanged">
<parameter name="aEvent" />
<body><![CDATA[
]]></body>
</method>
<!-- nsIXULTreeBuilderObserver -->
<field name="builderObserver"><![CDATA[
({
mOuter: this,
canDropOn: function(index)
{
return true;
},
canDropBeforeAfter: function(index, before)
{
return true;
},
onDrop: function(row, orientation)
{
var dragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService);
var dragSession = dragService.getCurrentSession();
if (!dragSession)
return;
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFIID = Components.interfaces.nsIRDFContainer;
var RDFC = Components.classes[kRDFCContractID].getService(kRDFIID);
var rTarget = this.mOuter.treeBuilder.getResourceAtIndex(row);
var parentIndex = this.mOuter.treeBoxObject.view.getParentIndex(row);
var rContainer;
if (parentIndex == -1)
rContainer = this.mOuter.rdf.GetResource("NC:BookmarksRoot");
else
rContainer = this.mOuter.treeBuilder.getResourceAtIndex(parentIndex);
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
var rBookmark = this.mOuter.rdf.GetResource(this.mOuter.NC_NS + "Bookmark");
trans.addDataFlavor("moz/rdfitem");
trans.addDataFlavor("text/x-moz-url");
trans.addDataFlavor("text/unicode");
var list = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
var sourceUri;
var sourceResource;
var dirty = false;
var additiveFlag = false;
for (var i = 0; i < dragSession.numDropItems; ++i) {
dragSession.getData(trans, i);
var dataObj = {};
var bestFlavor = {};
var len = {};
trans.getAnyTransferData(bestFlavor, dataObj, len);
if (dataObj)
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
if (!dataObj)
continue;
sourceUri = dataObj.data.substring(0, len.value);
if (!sourceUri)
continue;
var sourceID = [], parentID = [], nameRequired = [], name = [];
nameRequired[i] = false;
name[i] = null;
switch (bestFlavor.value) {
case "moz/rdfitem":
var ix = sourceUri.indexOf("\n");
sourceID[i] = ix >= 0 ? (parentID[i] = sourceUri.substr(ix+1), sourceUri.substr(0, ix)) : sourceUri;
break;
case "text/x-moz-url":
ix = sourceUri.indexOf("\n");
sourceID[i] = ix >= 0 ? (name[i] = sourceUri.substr(ix+1), sourceUri.substr(0, ix)) : sourceUri;
break;
case "text/unicode":
sourceID[i] = sourceUri;
nameRequired[i] = true;
break;
default:
continue;
}
var rSource = this.mOuter.rdf.GetResource(sourceID[i]);
var rParent = parentID[i] ? this.mOuter.rdf.GetResource(parentID[i]) : null;
const kBMDS = this.mOuter.bookmarksDS;
var bmType = BookmarksUtils.resolveType(rSource);
var rType = this.mOuter.rdf.GetResource(this.mOuter.RDF_NS + "type");
if (!bmType)
kBMDS.Assert(rSource, rType, rBookmark, true);
// prevent dropping folder within itself or one of its subfolders
if (bmType == this.mOuter.NC_NS + "Folder") {
var currRow = row;
do {
var currURI = this.mOuter.treeBuilder.getResourceAtIndex(currRow).Value;
currRow = this.mOuter.treeBoxObject.view.getParentIndex(currRow);
}
while (currRow != -1 && currURI != "NC:BookmarksRoot" && currURI != rSource.Value);
if (currURI == rSource.Value)
return;
}
var dropIndex;
if (orientation == Components.interfaces.nsITreeView.inDropAfter &&
this.mOuter.treeBoxObject.view.isContainer(row) &&
this.mOuter.treeBoxObject.view.isContainerOpen(row) &&
!this.mOuter.treeBoxObject.view.isContainerEmpty(row)) {
rContainer = rTarget;
dropIndex = 1;
}
else {
RDFC.Init(kBMDS, rContainer);
dropIndex = RDFC.IndexOf(rTarget);
if (dropIndex == -1)
break;
if (orientation == Components.interfaces.nsITreeView.inDropAfter) {
++dropIndex;
}
}
const kDSIID = Components.interfaces.nsIDragService;
const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
if (rParent) {
if (!(dragSession.dragAction & kCopyAction)) {
RDFC.Init(kBMDS, rParent);
RDFC.RemoveElement(rSource, false);
}
}
if (bmType == this.mOuter.NC_NS + "Folder") {
// If we're going to copy a folder type, we need to clone the folder
// rather than just asserting the new node as a child of the drop folder.
if (dragSession.dragAction & kCopyAction)
rSource = BookmarksUtils.cloneFolder(rSource, rContainer, rTarget);
}
if (orientation != Components.interfaces.nsITreeView.inDropOn) {
RDFC.Init(kBMDS, rContainer);
RDFC.InsertElementAt(rSource, dropIndex, true);
}
else {
RDFC.Init(kBMDS, rTarget);
RDFC.AppendElement(rSource);
}
dirty = true;
//if (rParent) {
// gBookmarksShell.selectFolderItem(rContainer.Value, sourceID[i], additiveFlag);
// if (!additiveFlag) additiveFlag = true;
//}
// If a name is supplied, we want to assert this information into the
// graph. E.g. user drags an internet shortcut to the app, we want to
// preserve not only the URL but the name of the shortcut. The other case
// where we need to assert a name is when the node does not already exist
// in the graph, in this case we'll just use the URL as the name.
if (name[i] || nameRequired[i]) {
var currentName = kBMDS.GetTarget(this.mOuter.rdf.GetResource(sourceID[i]), this.mOuter.rdf.GetResource(this.mOuter.NC_NS + "Name"), true);
if (!currentName) {
var rDefaultName = this.mOuter.rdf.GetLiteral(name[i] || sourceID[i]);
if (rDefaultName) {
var rName = this.mOuter.rdf.GetResource(this.mOuter.NC_NS + "Name");
kBMDS.Assert(rSource, rName, rDefaultName, true);
}
}
}
if (dirty)
this.mOuter.flushBMDatasource();
}
},
onToggleOpenState: function BMOLBuilderObserver_onToggleOpenState(aItemIndex)
{
},
onCycleHeader: function BMOLBuilderObserver_onCycleHeader(aColumnID, aHeaderElement)
{
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
// Sorted! http://www.sorted.org.nz/
this.mOuter.sorted = true;
bookmarksSortPrefs.setCharPref("resource", aHeaderElement.getAttribute("sort"));
bookmarksSortPrefs.setCharPref("direction", aHeaderElement.getAttribute("sortDirection"));
},
onCycleCell: function BMOLBuilderObserver_onCycleCell(aItemIndex, aColumnID)
{
},
onSelectionChanged: function BMOLBuilderObserver_onSelectionChanged()
{
this.mOuter.onCommandUpdate();
const kStatusBar = document.getAnonymousElementByAttribute(this.mOuter, "anonid", "statusbar-text");
if (!kStatusBar)
return;
const currentIndex = this.mOuter.currentIndex;
var displayValue = "";
if (this.mOuter.treeBoxObject.selection.count == 1) {
if (this.mOuter.treeBoxObject.view.isContainer(currentIndex)) {
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFCIID = Components.interfaces.nsIRDFContainer;
const kRDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
const krSrc = this.mOuter.treeBuilder.getResourceAtIndex(currentIndex);
try {
kRDFC.Init(this.mOuter.db, krSrc);
var count = kRDFC.GetCount();
displayValue = this.mOuter._bundle.GetStringFromName("status_foldercount");
displayValue = displayValue.replace(/%num_items%/, count);
}
catch (e) {
}
}
else {
try {
displayValue = this.mOuter.db.GetTarget(this.mOuter.treeBuilder.getResourceAtIndex(currentIndex), this.mOuter.rdf.GetResource(this.mOuter.NC_NS + "URL"), true);
displayValue = displayValue.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
}
catch (e) {
displayValue = "";
}
}
if (displayValue.substring(0, 3) == "NC:")
displayValue = "";
}
kStatusBar.label = displayValue;
},
isEditable: function BMOLBuilderObserver_isEditable(aItemIndex, aColumnID)
{
},
onSetCellText: function BMOLBuilderObserver_onSetCellText(aItemIndex, aColumnID, aValue)
{
},
onPerformAction: function BMOLBuilderObserver_onPerformAction(aAction)
{
},
onPerformActionOnRow: function BMOLBuilderObserver_onPerformActionOnRow(aAction, aItemIndex)
{
},
onPerformActionOnCell: function BMOLBuilderObserver_onPerformActionOnCell(aAction, aItemIndex, aColumnID)
{
}
})
]]></field>
<!-- RDF utility functions required by base binding -->
<property name="db">
<getter><![CDATA[
return this.tree.database;
]]></getter>
</property>
<method name="doBookmarksCommand">
<parameter name="aSourceURI"/>
<parameter name="aCommand"/>
<parameter name="aArgumentsArray"/>
<body><![CDATA[
var rCommand = this.rdf.GetResource(aCommand);
var kSuppArrayContractID = "@mozilla.org/supports-array;1";
var kSuppArrayIID = Components.interfaces.nsISupportsArray;
var sourcesArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
if (aSourceURI) {
var rSource = this.rdf.GetResource(aSourceURI);
sourcesArray.AppendElement (rSource);
}
var argsArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
for (var i = 0; i < aArgumentsArray.length; ++i) {
var rArc = this.rdf.GetResource(aArgumentsArray[i].property);
argsArray.AppendElement(rArc);
var rValue = null;
if ("resource" in aArgumentsArray[i])
rValue = this.rdf.GetResource(aArgumentsArray[i].resource);
else
rValue = this.rdf.GetLiteral(aArgumentsArray[i].literal);
argsArray.AppendElement(rValue);
}
// Exec the command in the Composite (not Bookmarks) datasource
// so that command aggregation works
this.db.DoCommand(sourcesArray, rCommand, argsArray);
]]></body>
</method>
<method name="selectAll">
<body><![CDATA[
this.treeBoxObject.selection.selectAll();
]]></body>
</method>
<method name="paste">
<body><![CDATA[
const kXferableContractID = "@mozilla.org/widget/transferable;1";
const kXferableIID = Components.interfaces.nsITransferable;
var xferable = Components.classes[kXferableContractID].createInstance(kXferableIID);
xferable.addDataFlavor("moz/bookmarkclipboarditem");
xferable.addDataFlavor("text/x-moz-url");
xferable.addDataFlavor("text/unicode");
const kClipboardContractID = "@mozilla.org/widget/clipboard;1";
const kClipboardIID = Components.interfaces.nsIClipboard;
var clipboard = Components.classes[kClipboardContractID].getService(kClipboardIID);
clipboard.getData(xferable, kClipboardIID.kGlobalClipboard);
var flavour = { };
var data = { };
var length = { };
xferable.getAnyTransferData(flavour, data, length);
var nodes = []; var names = [];
data = data.value.QueryInterface(Components.interfaces.nsISupportsString).data;
switch (flavour.value) {
case "moz/bookmarkclipboarditem":
nodes = data.split("\n");
break;
case "text/x-moz-url":
var ix = data.indexOf("\n");
nodes.push(data.substring(0, ix != -1 ? ix : data.length));
names.push(data.substring(ix));
break;
default:
return;
}
const kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFIID = Components.interfaces.nsIRDFService;
const ksRDF = Components.classes[kRDFContractID].getService(kRDFIID);
var parentRes;
const currentIndex = this.currentIndex;
if (!this.treeBoxObject.view.isContainer(currentIndex))
parentRes = this.parentRes;
else
parentRes = this.treeBuilder.getResourceAtIndex(currentIndex);
const currentRes = this.currentRes;
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFCIID = Components.interfaces.nsIRDFContainer;
const ksRDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
var additiveFlag = false;
for (var i = 0; i < nodes.length; ++i) {
if (!nodes[i]) continue;
var aNode = nodes[i];
var rType = null;
var tabIndex = aNode.indexOf("\t");
if (tabIndex > 0)
{
rType = ksRDF.GetResource(aNode.substring(tabIndex + 1));
aNode = aNode.substring(0, tabIndex);
}
var rCurrent = ksRDF.GetResource(aNode);
if (!rType && names[i])
{
const krName = ksRDF.GetResource(names[i]);
const krNameProperty = ksRDF.GetResource("http://home.netscape.com/NC-rdf#Name");
const krBookmark = ksRDF.GetResource("http://home.netscape.com/NC-rdf#Bookmark");
kBMDS.Assert(rCurrent, krNameProperty, krName, true);
// note: never need to assert type (it is derived)
}
// If the node is a folder, then we need to create a new anonymous
// resource and copy all the arcs over.
if (rType && rType.Value == "http://home.netscape.com/NC-rdf#Folder") {
// but wait, copying a folder into its child or itself may cause recursive
// folder, so need a check before the cloning.
var checkIndex = this.currentIndex;
var checkRes;
while (checkIndex != -1) {
checkRes = this.treeBuilder.getResourceAtIndex(checkIndex);
if (checkRes.EqualsNode(rCurrent))
break;
checkIndex = this.treeBoxObject.view.getParentIndex(checkIndex);
}
if (checkIndex == -1)
rCurrent = BookmarksUtils.cloneFolder(rCurrent, parentRes, currentRes);
else
continue;
}
// If this item already exists in this container, don't paste, as
// this will result in the creation of multiple copies in the datasource
// but will not result in an update of the UI. (In Short: we don't
// handle multiple bookmarks well)
ksRDFC.Init(this.bookmarksDS, parentRes);
ix = ksRDFC.IndexOf(rCurrent);
if (ix != -1)
continue;
ix = ksRDFC.IndexOf(currentRes);
if (ix != -1)
ksRDFC.InsertElementAt(rCurrent, ix+1, true);
else
ksRDFC.AppendElement(rCurrent);
this.flushBMDatasource();
}
]]></body>
</method>
<method name="copySelection">
<body><![CDATA[
const kSuppArrayContractID = "@mozilla.org/supports-array;1";
const kSuppArrayIID = Components.interfaces.nsISupportsArray;
var itemArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
const kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFIID = Components.interfaces.nsIRDFService;
const ksRDF = Components.classes[kRDFContractID].getService(kRDFIID);
const kSuppWStringContractID = "@mozilla.org/supports-string;1";
const kSuppWStringIID = Components.interfaces.nsISupportsString;
var bmstring = Components.classes[kSuppWStringContractID].createInstance(kSuppWStringIID);
var unicodestring = Components.classes[kSuppWStringContractID].createInstance(kSuppWStringIID);
var htmlstring = Components.classes[kSuppWStringContractID].createInstance(kSuppWStringIID);
var sBookmarkItem = ""; var sTextUnicode = ""; var sTextHTML = "";
var rangeCount = this.treeBoxObject.selection.getRangeCount();
for (var i = rangeCount - 1; i >= 0; --i) {
var rangeMin = {};
var rangeMax = {};
this.treeBoxObject.selection.getRangeAt(i, rangeMin, rangeMax);
for (var j = rangeMax.value; j >= rangeMin.value; --j) {
var res = this.treeBuilder.getResourceAtIndex(j);
var urlRes = ksRDF.GetResource("http://home.netscape.com/NC-rdf#URL");
var nameRes = ksRDF.GetResource("http://home.netscape.com/NC-rdf#Name");
var typeRes = ksRDF.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
var url = this.db.GetTarget(res, urlRes, true);
if (url)
url = url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
var name = this.db.GetTarget(res, nameRes, true);
name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
var bmkType = this.db.GetTarget(res, typeRes, true);
if (bmkType)
bmkType = bmkType.Value;
// XXXben is "\n" the best delimiter here? I think not.
sBookmarkItem += res.Value;
if (bmkType)
{
sBookmarkItem += "\t" + bmkType;
}
sBookmarkItem += "\n";
sTextUnicode += url + "\n";
sTextHTML += "<A HREF=\"" + url + "\">" + name + "</A>";
}
}
const kXferableContractID = "@mozilla.org/widget/transferable;1";
const kXferableIID = Components.interfaces.nsITransferable;
var xferable = Components.classes[kXferableContractID].createInstance(kXferableIID);
xferable.addDataFlavor("moz/bookmarkclipboarditem");
bmstring.data = sBookmarkItem;
xferable.setTransferData("moz/bookmarkclipboarditem", bmstring, sBookmarkItem.length*2)
xferable.addDataFlavor("text/html");
htmlstring.data = sTextHTML;
xferable.setTransferData("text/html", htmlstring, sTextHTML.length*2)
xferable.addDataFlavor("text/unicode");
unicodestring.data = sTextUnicode;
xferable.setTransferData("text/unicode", unicodestring, sTextUnicode.length*2)
const kClipboardContractID = "@mozilla.org/widget/clipboard;1";
const kClipboardIID = Components.interfaces.nsIClipboard;
var clipboard = Components.classes[kClipboardContractID].getService(kClipboardIID);
clipboard.setData(xferable, null, kClipboardIID.kGlobalClipboard);
]]></body>
</method>
<method name="deleteSelection">
<body><![CDATA[
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFIID = Components.interfaces.nsIRDFService;
const kRDFCIID = Components.interfaces.nsIRDFContainer;
const ksRDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
const ksRDF = Components.classes[kRDFContractID].getService(kRDFIID);
var nextIndex = 0; // Used to determine which item to select after the deletion
// is performed.
// Whether or not the selection contains items which cannot be deleted.
// var selectionContainsImmutableItems = false;
var boxObject = this.treeBoxObject;
var treeBuilder = this.treeBuilder;
var rangeCount = this.treeBoxObject.selection.getRangeCount();
var rangeMax = { };
var rangeMin = { };
// First, walk the selection and see if there's anything we /can't/
// delete. If so, present a warning dialog listing the items that
// we can't remove.
const kIMDSContractID = "@mozilla.org/rdf/datasource;1?name=in-memory-datasource";
const kIMDSIID = Components.interfaces.nsIRDFDataSource;
var imDS = Components.classes[kIMDSContractID].getService(kIMDSIID);
const kRDFCUContractID = "@mozilla.org/rdf/container-utils;1";
const kRDFCUIID = Components.interfaces.nsIRDFContainerUtils;
const kRDFCU = Components.classes[kRDFCUContractID].getService(kRDFCUIID);
/*
var immutableList = this.rdf.GetResource("NC:ImmutableBookmarkList");
var container = kRDFCU.MakeSeq(imDS, immutableList);
for (var i = rangeCount - 1; i >= 0; --i) {
boxObject.selection.getRangeAt(i, rangeMin, rangeMax);
for (var j = rangeMax.value; j >= rangeMin.value; --j) {
var resource = treeBuilder.getResourceAtIndex(j);
var type = this.getTypeAtIndex(j);
if (resource.Value == "NC:BookmarksRoot" || type == this.NC_NS + "IEFavoriteFolder")
continue;
if (type != this.NC_NS + "Bookmark" && type != this.NC_NS + "BookmarkSeparator" && type != this.NC_NS + "Folder") {
// This delete operation contains items which cannot be deleted
// for one reason or another. Make a list of the items which
// we can't delete, and show a dialog.
container.AppendElement(resource);
selectionContainsImmutableItems = true;
// Now we need to ensure that this item's parent chain is not
// part of the current selection so that we don't delete that. We
// preserve selection on any deletable items in the folder chain
// however, and these are removed.
for (var parentIndex = boxObject.view.getParentIndex(j);
parentIndex != -1;
parentIndex = boxObject.view.getParentIndex(parentIndex)) {
// Note that we don't combine this with the check in the
// |while| above, as this would mean that if you had a folder
// hierarchy consisting of:
//
// Folder -> [ selected ]
// Folder -> [ not selected ]
// Immutable item [ selected ]
//
// This code would not work and the containing folder would be
// deleted.
if (boxObject.selection.isSelected(parentIndex))
boxObject.selection.toggleSelect(parentIndex);
}
}
}
}
// Present a dialog showing any items that we can't delete.
// if (selectionContainsImmutableItems) {
// openDialog("chrome://communicator/content/bookmarks/deleteBookmark.xul", "", "modal=yes,resizable=no", imDS);
// Now clear the list of immutable items.
ksRDFC.Init(imDS, immutableList);
var count = ksRDFC.GetCount();
for (var i = 0; i < count; ++i)
ksRDFC.RemoveElementAt(i, false);
}
*/
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksPrefs = prefSvc.getBranch("browser.bookmarks.");
for (i = rangeCount - 1; i >= 0; --i) {
rangeMax = { };
rangeMin = { };
boxObject.selection.getRangeAt(i, rangeMin, rangeMax);
for (var j = rangeMax.value; j >= rangeMin.value; --j) {
var resource = treeBuilder.getResourceAtIndex(j);
if (resource.Value == "NC:BookmarksRoot")
continue;
// If we're removing the static root, make sure we set the pref that
// tells the bookmark service that it's been added so that after
// we remove it, the bookmark service doesn't try to add it back
// on subsequent launches.
if (resource.Value == "NC:SystemBookmarksStaticRoot")
bookmarksPrefs.setBoolPref("added_static_root", true);
var currType = this.getTypeAtIndex(j);
if (currType == this.NC_NS + "IEFavoriteFolder")
bookmarksPrefs.setBoolPref("import_system_favorites", false);
else if (currType != this.NC_NS + "Bookmark" &&
currType != this.NC_NS + "BookmarkSeparator" &&
currType != this.NC_NS + "Folder")
continue;
var parentIndex = boxObject.view.getParentIndex(j);
var parent;
if (parentIndex != -1)
parent = treeBuilder.getResourceAtIndex(parentIndex);
else {
// assume its parent is the root
parent = ksRDF.GetResource("NC:BookmarksRoot");
}
/*
Use RDF datasource command APIs instead of trying to
directly manipulate the bookmarks datasource graph via:
ksRDFC.Init(this.bookmarksDS, parent);
ksRDFC.RemoveElement(resource, true);
*/
try {
var args = [{ property: this.NC_NS + "parent",
resource: parent.Value }];
this.doBookmarksCommand(resource.Value, this.NC_NS_CMD + "deletebookmark", args);
}
catch (e) {
}
nextIndex = j;
}
}
// Select the next row
boxObject.selection.select(nextIndex);
]]></body>
</method>
<method name="openFindDialog">
<body><![CDATA[
openDialog("chrome://communicator/content/bookmarks/findBookmark.xul",
"FindBookmarksWindow",
"dialog=no,centerscreen,resizable=no,chrome,dependent");
]]></body>
</method>
<method name="canSendLink">
<body><![CDATA[
var selectedIndex = this.treeBoxObject.selection.currentIndex;
return (this.treeBoxObject.selection.count == 1 &&
!this.treeBoxObject.view.isContainer(selectedIndex) &&
this.getTypeAtIndex(selectedIndex) != this.NC_NS + "BookmarkSeparator");
]]></body>
</method>
<method name="sendLink">
<body><![CDATA[
const currentRes = this.currentRes;
var urlLiteral = this.db.GetTarget(currentRes, this.rdf.GetResource(this.NC_NS + "URL"), true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
var nameLiteral = this.db.GetTarget(currentRes, this.rdf.GetResource(this.NC_NS + "Name"), true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
sendLink(urlLiteral, nameLiteral);
]]></body>
</method>
<method name="getAllCmds">
<parameter name="aNodeID"/>
<body><![CDATA[
var type = BookmarksUtils.resolveType(aNodeID);
if (!type) {
if (aNodeID == "NC:PersonalToolbarFolder" || aNodeID == "NC:BookmarksRoot")
type = "http://home.netscape.com/NC-rdf#Folder";
else
return null;
}
var commands = [];
// menu order:
//
// bm_open
// bm_openfolder
// bm_openinnewwindow
// /* bm_openinnewtab not yet supported */
// ---------------------
// /* bm_find removed */
// bm_newfolder
// ---------------------
// bm_cut
// bm_copy
// bm_paste
// bm_fileBookmark
// ---------------------
// bm_delete
// bm_rename
// ---------------------
// bm_properties
switch (type) {
case "http://home.netscape.com/NC-rdf#BookmarkSeparator":
commands = ["bm_newfolder", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_separator",
"bm_delete"];
break;
case "http://home.netscape.com/NC-rdf#Bookmark":
commands = ["bm_open", "bm_openinnewwindow", /* "bm_openinnewtab", */ "bm_separator",
"bm_newfolder", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_fileBookmark", "bm_separator",
"bm_delete", "bm_rename", "bm_separator",
"bm_properties"];
break;
case "http://home.netscape.com/NC-rdf#Folder":
commands = ["bm_openfolder", "bm_openinnewwindow", "bm_separator",
"bm_newfolder", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_fileBookmark", "bm_separator",
"bm_delete", "bm_rename", "bm_separator",
"bm_properties"];
break;
case "http://home.netscape.com/NC-rdf#IEFavoriteFolder":
commands = ["bm_openfolder", "bm_separator",
"bm_delete"];
break;
case "http://home.netscape.com/NC-rdf#IEFavorite":
commands = ["bm_open", "bm_openinnewwindow", /* "bm_openinnewtab", */ "bm_separator",
"bm_copy"];
break;
case "http://home.netscape.com/NC-rdf#FileSystemObject":
commands = ["bm_open", "bm_openinnewwindow", /* "bm_openinnewtab", */ "bm_separator",
"bm_copy"];
break;
default:
var source = this.rdf.GetResource(aNodeID);
return this.db.GetAllCmds(source);
}
return new CommandArrayEnumerator(commands);
]]></body>
</method>
<method name="flattenEnumerator">
<parameter name="aEnumerator"/>
<body><![CDATA[
if ("_index" in aEnumerator)
return aEnumerator._inner;
var temp = [];
while (aEnumerator.hasMoreElements())
temp.push(aEnumerator.getNext());
return temp;
]]></body>
</method>
<method name="findCommonNodes">
<parameter name="aNewArray"/>
<parameter name="aOldArray"/>
<body><![CDATA[
var common = [];
for (var i = 0; i < aNewArray.length; ++i) {
for (var j = 0; j < aOldArray.length; ++j) {
if (common.length > 0 && common[common.length-1] == aNewArray[i])
continue;
if (aNewArray[i] == aOldArray[j])
common.push(aNewArray[i]);
}
}
return common;
]]></body>
</method>
<method name="createMenuItem">
<parameter name="aDisplayName"/>
<parameter name="aCommandName"/>
<parameter name="aSelectedIndex"/>
<body><![CDATA[
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var xulElement = document.createElementNS(kXULNS, "menuitem");
xulElement.setAttribute("cmd", aCommandName);
xulElement.setAttribute("command", "cmd_" + aCommandName.substring(this.NC_NS_CMD.length));
switch (aCommandName) {
case this.NC_NS_CMD + "bm_open":
xulElement.setAttribute("label", aDisplayName);
xulElement.setAttribute("default", "true");
break;
case this.NC_NS_CMD + "bm_openfolder":
aDisplayName = this.treeBoxObject.view.isContainerOpen(aSelectedIndex) ? this._bundle.GetStringFromName("cmd_bm_openfolder2") : aDisplayName;
xulElement.setAttribute("label", aDisplayName);
xulElement.setAttribute("default", "true");
break;
case this.NC_NS_CMD + "bm_renamebookmark":
if (!document.popupNode.hasAttribute("type")) {
xulElement.setAttribute("label", this._bundle.GetStringFromName("cmd_bm_renamebookmark2"));
xulElement.setAttribute("cmd", (this.NC_NS_CMD + "bm_editurl"));
}
else
xulElement.setAttribute("label", aDisplayName);
break;
default:
xulElement.setAttribute("label", aDisplayName);
break;
}
return xulElement;
]]></body>
</method>
<method name="getCommandName">
<parameter name="aCommand"/>
<body><![CDATA[
var cmdName = aCommand.substring(this.NC_NS_CMD.length);
try {
// Note: this will succeed only if there's a string in the bookmarks
// string bundle for this command name. Otherwise, <xul:stringbundle/>
// will throw, we'll catch & stifle the error, and look up the command
// name in the datasource.
return BookmarksUtils.getLocaleString("cmd_" + cmdName);
}
catch (e) {
// XXX - WORK TO DO HERE! (rjc will cry if we don't fix this)
// need to ask the ds for the commands for this node, however we don't
// have the right params. This is kind of a problem.
dump("*** BAD! EVIL! WICKED! NO! ACK! ARGH! ORGH!\n");
const rName = this.rdf.GetResource(this.NC_NS + "Name");
const rSource = this.rdf.GetResource(aCommand);
return this.db.GetTarget(rSource, rName, true).Value;
}
]]></body>
</method>
<method name="createContextMenu">
<parameter name="aEvent"/>
<body><![CDATA[
var popup = aEvent.target;
// clear out the old context menu contents (if any)
while (popup.hasChildNodes())
popup.removeChild(popup.firstChild);
var popupNode = document.popupNode;
var commonCommands = [];
var rangeCount = this.treeBoxObject.selection.getRangeCount();
for (var i = rangeCount - 1; i >= 0; --i) {
var minRange = {};
var maxRange = {};
this.treeBoxObject.selection.getRangeAt(i, minRange, maxRange);
for (var j = maxRange.value; j >= minRange.value; --j) {
var nodeURI = this.treeBuilder.getResourceAtIndex(j).Value;
var commands = this.getAllCmds(nodeURI);
if (!commands) {
aEvent.preventDefault();
return;
}
commands = this.flattenEnumerator(commands);
if (!commonCommands.length) commonCommands = commands;
commonCommands = this.findCommonNodes(commands, commonCommands);
}
}
if (!commonCommands.length) {
aEvent.preventDefault();
return;
}
// Now that we should have generated a list of commands that is valid
// for the entire selection, build a context menu.
for (i = 0; i < commonCommands.length; ++i) {
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var currCommand = commonCommands[i].QueryInterface(Components.interfaces.nsIRDFResource).Value;
var element = null;
if (currCommand != this.NC_NS_CMD + "bm_separator") {
var commandName = this.getCommandName(currCommand);
var selectedIndex = this.treeBoxObject.selection.currentIndex;
element = this.createMenuItem(commandName, currCommand, selectedIndex);
}
else if (i != 0 && i < commonCommands.length-1) {
// Never append a separator as the first or last element in a context
// menu.
element = document.createElementNS(kXULNS, "menuseparator");
}
if (element)
popup.appendChild(element);
}
]]></body>
</method>
<method name="openPropertiesForItem">
<body><![CDATA[
// XXX if not bookmarks separator
var itemURI = this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex).Value;
openDialog("chrome://communicator/content/bookmarks/bm-props.xul",
"", "centerscreen,chrome,dialog=no,resizable=no,dependent",
itemURI);
]]></body>
</method>
<method name="setAsPersonalToolbarFolder">
<body><![CDATA[
var selectedURI = this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex).Value;
var args = [];
this.doBookmarksCommand(selectedURI, this.NC_NS_CMD + "setpersonaltoolbarfolder", args);
]]></body>
</method>
<method name="setAsNewSearchFolder">
<body><![CDATA[
var selectedURI = this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex).Value;
var args = [];
this.doBookmarksCommand(selectedURI, this.NC_NS_CMD + "setnewsearchfolder", args);
]]></body>
</method>
<method name="setAsNewBookmarkFolder">
<body><![CDATA[
var selectedURI = this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex).Value;
var args = [];
this.doBookmarksCommand(selectedURI, this.NC_NS_CMD + "setnewbookmarkfolder", args);
]]></body>
</method>
<method name="addBookmark">
<body><![CDATA[
const currentIndex = this.currentIndex;
var parentIndex;
if (this.treeBoxObject.view.rowCount) {
if (this.treeBoxObject.view.isContainerOpen(currentIndex))
parentIndex = currentIndex;
else
parentIndex = this.treeBoxObject.view.getParentIndex(currentIndex);
}
else
parentIndex = -1;
var parentURI;
if (parentIndex == -1)
parentURI = this.rdf.GetResource("NC:BookmarksRoot").Value;
else
parentURI = this.treeBuilder.getResourceAtIndex(parentIndex).Value;
var rv = { newBookmark: null };
openDialog("chrome://communicator/content/bookmarks/addBookmark.xul", "",
"centerscreen,chrome,modal=yes,dialog=yes,resizable=no", null, null, parentURI, null, "newBookmark", rv);
if (rv.newBookmark) {
var ind = this.treeBuilder.getIndexOfResource(rv.newBookmark);
this.treeBoxObject.selection.select(ind);
}
]]></body>
</method>
<method name="fileBookmark">
<body><![CDATA[
// XXX folder arg
var rv = { selectedFolder: null };
openDialog("chrome://communicator/content/bookmarks/addBookmark.xul", "",
"centerscreen,chrome,modal=yes,dialog=yes,resizable=yes", null, null, null, null, "selectFolder", rv);
if (rv.selectedFolder) {
var rangeCount = this.treeBoxObject.selection.getRangeCount();
for (var k = rangeCount - 1; k >= 0; --k) {
var rangeMin = {};
var rangeMax = {};
this.treeBoxObject.selection.getRangeAt(k, rangeMin, rangeMax);
for (var i = rangeMax.value; i >= rangeMin.value; --i) {
var selected = this.treeBuilder.getResourceAtIndex(i);
if (selected.Value == rv.selectedFolder)
return; // Selection contains the target folder. Just fail silently.
var additiveFlag = false;
var parentIndex = this.treeBoxObject.view.getParentIndex(i);
var parentURI;
if (parentIndex == -1)
parentURI = this.rdf.GetResource("NC:BookmarksRoot").Value;
else
parentURI = this.treeBuilder.getResourceAtIndex(parentIndex).Value;
this.moveBookmark(selected.Value, parentURI, rv.selectedFolder);
// gBookmarksShell.selectFolderItem(rv.selectedFolder, selected.Value, additiveFlag);
if (!additiveFlag) additiveFlag = true;
}
}
this.flushBMDatasource();
}
]]></body>
</method>
<method name="moveBookmark">
<parameter name="aBookmarkURI"/>
<parameter name="aFromFolderURI"/>
<parameter name="aToFolderURI"/>
<body><![CDATA[
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFCIID = Components.interfaces.nsIRDFContainer;
const kRDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
const krSrc = this.rdf.GetResource(aBookmarkURI);
const krOldParent = this.rdf.GetResource(aFromFolderURI);
const krNewParent = this.rdf.GetResource(aToFolderURI);
kRDFC.Init(this.bookmarksDS, krNewParent);
kRDFC.AppendElement(krSrc);
kRDFC.Init(this.bookmarksDS, krOldParent);
kRDFC.RemoveElement(krSrc, true);
]]></body>
</method>
<method name="importBookmarks">
<body><![CDATA[
try {
const kFilePickerContractID = "@mozilla.org/filepicker;1";
const kFilePickerIID = Components.interfaces.nsIFilePicker;
const kFilePicker = Components.classes[kFilePickerContractID].createInstance(kFilePickerIID);
const kTitle = this._bundle.GetStringFromName("SelectImport");
kFilePicker.init(window, kTitle, kFilePickerIID["modeOpen"]);
kFilePicker.appendFilters(kFilePickerIID.filterHTML | kFilePickerIID.filterAll);
var fileName;
if (kFilePicker.show() != kFilePickerIID.returnCancel) {
fileName = kFilePicker.fileURL.spec;
if (!fileName) return;
}
else return;
}
catch (e) {
return;
}
var seln = null;
try {
seln = this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex).Value;
}
catch(ex) {
seln = this.rdf.GetResource("NC:BookmarksRoot").Value;
}
var args = [{ property: this.NC_NS + "URL", literal: fileName}];
this.doBookmarksCommand(seln, this.NC_NS_CMD + "import", args);
]]></body>
</method>
<method name="exportBookmarks">
<body><![CDATA[
try {
const kFilePickerContractID = "@mozilla.org/filepicker;1";
const kFilePickerIID = Components.interfaces.nsIFilePicker;
const kFilePicker = Components.classes[kFilePickerContractID].createInstance(kFilePickerIID);
const kTitle = this._bundle.GetStringFromName("EnterExport");
const kRDFExportIndex = 2;
kFilePicker.init(window, kTitle, kFilePickerIID["modeSave"]);
kFilePicker.appendFilters(kFilePickerIID.filterHTML | kFilePickerIID.filterAll);
kFilePicker.appendFilter("RDF", "*.rdf"); // index 2: kRDFExportIndex
kFilePicker.defaultString = "bookmarks.html";
var fileName;
if (kFilePicker.show() != kFilePickerIID.returnCancel) {
fileName = kFilePicker.fileURL.spec;
if (!fileName) return;
}
else return;
}
catch (e) {
return;
}
var seln = null;
try {
seln = this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex).Value;
}
catch(ex) {
seln = this.rdf.GetResource("NC:BookmarksRoot").Value;
}
var args = [{ property: this.NC_NS + "URL", literal: fileName},
{ property: this.RDF_NS + "type",
literal: (kFilePicker.filterIndex == kRDFExportIndex) ? "RDF" : "HTML"}];
this.doBookmarksCommand(seln, this.NC_NS_CMD + "export", args);
]]></body>
</method>
<method name="openFolderInNewWindow">
<body><![CDATA[
var selectedIndex = this.treeBoxObject.selection.currentIndex;
var selectedURI = this.treeBuilder.getResourceAtIndex(selectedIndex).Value;
openDialog("chrome://communicator/content/bookmarks/bookmarks.xul",
"", "chrome,all,dialog=no", selectedURI);
]]>
</body>
</method>
<method name="createNewSeparator">
<body><![CDATA[
var currIndex = this.treeBoxObject.selection.currentIndex;
if (currIndex == -1)
currIndex = this.treeBoxObject.view.rowCount - 1;
var parentIndex = this.treeBoxObject.view.getParentIndex(currIndex);
var parentValue;
if (parentIndex == -1)
parentValue = this.rdf.GetResource("NC:BookmarksRoot").Value;
else
parentValue = this.treeBuilder.getResourceAtIndex(parentIndex).Value;
args = [{ property: this.NC_NS + "parent",
resource: parentValue }];
this.doBookmarksCommand(this.treeBuilder.getResourceAtIndex(currIndex).Value,
this.NC_NS_CMD + "newseparator", args);
]]></body>
</method>
<method name="createNewFolder">
<body><![CDATA[
const kPromptSvcContractID = "@mozilla.org/embedcomp/prompt-service;1";
const kPromptSvcIID = Components.interfaces.nsIPromptService;
const kPromptSvc = Components.classes[kPromptSvcContractID].getService(kPromptSvcIID);
var defaultValue = this._bundle.GetStringFromName("ile_newfolder");
var dialogTitle = this._bundle.GetStringFromName("newfolder_dialog_title");
var dialogMsg = this._bundle.GetStringFromName("newfolder_dialog_msg");
var stringValue = { value: defaultValue };
var relativeIndex = this.currentIndex;
const currentIndex = this.currentIndex;
var parentRes;
var isParent = false;
if (kPromptSvc.prompt(window, dialogTitle, dialogMsg, stringValue, null, { value: 0 })) {
if (currentIndex != -1 && currentIndex < this.treeBoxObject.view.rowCount) {
// If it's an open container, the relative index should be that of the last child.
if (this.treeBoxObject.view.isContainerOpen(currentIndex)) {
isParent = true;
var index = currentIndex + 1;
while (index < this.treeBoxObject.view.rowCount
&& this.treeBoxObject.view.getParentIndex(index) == currentIndex)
++index;
relativeIndex = index - 1;
}
if (isParent) {
parentRes = this.treeBuilder.getResourceAtIndex(currentIndex);
} else {
parentRes = this.parentRes;
}
}
else {
parentRes = this.rdf.GetResource("NC:BookmarksRoot");
relativeIndex = -1;
}
var args = [{ property: this.NC_NS + "parent",
resource: parentRes.Value },
{ property: this.NC_NS + "Name",
literal: stringValue.value }];
this.bookmarksDS.AddObserver(this.newFolderRDFObserver);
var relativeRes;
if (relativeIndex != -1)
relativeRes = this.treeBuilder.getResourceAtIndex(relativeIndex).Value;
else
relativeRes = this.rdf.GetResource("NC:BookmarksRoot").Value;
this.doBookmarksCommand(relativeRes, this.NC_NS_CMD + "newfolder", args);
this.bookmarksDS.RemoveObserver(this.newFolderRDFObserver);
}
]]></body>
</method>
<method name="validOpenClickConditions">
<parameter name="aEvent"/>
<body><![CDATA[
if (aEvent.button != 0 || aEvent.originalTarget.localName != "treechildren")
return false;
var row = {};
var col = {};
var obj = {};
this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
if (row.value == -1 || obj.value == "twisty")
return false;
return true;
]]></body>
</method>
// requires utilityOverlay.js if opening in new window for opentopwin()
<method name="openItem">
<parameter name="aEvent"/>
<parameter name="aInNewWindow"/>
<parameter name="aOpenGroups"/>
<body><![CDATA[
var groupRes = this.rdf.GetResource(this.NC_NS + "FolderGroup");
var groupTarget = this.db.GetTarget(this.treeBuilder.getResourceAtIndex(this.treeBoxObject.selection.currentIndex),
groupRes, true);
if (groupTarget && (!aOpenGroups || aEvent.detail > 1))
return;
if (!groupTarget && this.treeBoxObject.view.isContainer(this.treeBoxObject.selection.currentIndex)) {
if (this.clickCount == 1) {
var row = { };
var col = { };
var elt = { };
this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row, col, elt);
if (row.value >= 0)
this.treeBoxObject.view.toggleOpenState(row.value);
}
return;
}
var urlRes, urlValue, w;
if (aEvent && aEvent.altKey)
this.openPropertiesForItem();
else if (aInNewWindow) {
var seln = this.treeBoxObject.selection;
var rangeCount = seln.getRangeCount();
for (var i = rangeCount - 1; i >= 0; --i) {
var rangeMin = { };
var rangeMax = { };
seln.getRangeAt(i, rangeMin, rangeMax);
for (var k = rangeMax.value; k >= rangeMin.value; --k) {
groupTarget = this.db.GetTarget(this.treeBuilder.getResourceAtIndex(k),
groupRes, true);
if (!groupTarget) {
urlRes = this.rdf.GetResource(this.NC_NS + "URL");
urlValue = this.db.GetTarget(this.treeBuilder.getResourceAtIndex(k), urlRes, true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
// Ignore "NC:" and empty urls
if (!urlValue || urlValue.substring(0,3) == "NC:") return;
}
else
urlValue = "about:blank";
w = openDialog(this._browserURL, "_blank", "chrome,all,dialog=no", urlValue);
if (groupTarget)
w.OpenBookmarkGroupFromResource(this.treeBuilder.getResourceAtIndex(k),
this.db, this.rdf);
}
}
}
else {
groupTarget = this.db.GetTarget(this.currentRes, groupRes, true);
if (!groupTarget) {
urlRes = this.rdf.GetResource(this.NC_NS + "URL");
urlValue = this.db.GetTarget(this.currentRes, urlRes, true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
// Ignore "NC:" and empty urls
if (!urlValue || urlValue.substring(0,3) == "NC:") return;
}
else
urlValue = "about:blank";
if (groupTarget) {
w = getTopWin();
w.focus();
w.OpenBookmarkGroupFromResource(this.currentRes, this.db, this.rdf);
}
else {
openTopWin(urlValue);
}
}
if (aEvent)
aEvent.preventBubble();
]]></body>
</method>
<method name="canPaste">
<body><![CDATA[
// XXXben
return true;
]]></body>
</method>
<method name="searchBookmarks">
<parameter name="aInput"/>
<body><![CDATA[
if (!aInput)
this.tree.setAttribute("ref", "NC:BookmarksRoot");
else {
const ref = "find:datasource=rdf:bookmarks&match=http://home.netscape.com/NC-rdf#Name&method=contains&text=";
this.tree.setAttribute("ref", ref + escape(aInput));
}
]]></body>
</method>
</implementation>
</binding>
<!-- Full Bookmarks Tree, multi-columned -->
<!-- Localize column labels! -->
<binding id="bookmarks-tree-full" extends="chrome://communicator/content/bookmarks/bookmarks.xml#bookmarks-tree">
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"
contextmenu="_child">
<!-- XXXben need focus event handler for cmd update -->
<menupopup id="bmContext"
onpopupshowing="this.parentNode.createContextMenu(event);"/>
<vbox flex="1">
<tree anonid="bookmarks-tree" flex="1" class="plain" enableColumnDrag="true"
datasources="rdf:bookmarks rdf:internetsearch rdf:files rdf:localsearch" ref="NC:BookmarksRoot" flags="dont-build-content"
onkeypress="if (event.keyCode == 13) this.parentNode.parentNode.openItem(event, false, false);"
ondblclick="if (this.parentNode.parentNode.validOpenClickConditions(event)) this.parentNode.parentNode.openItem(event, false, false);"
ondraggesture="if (event.originalTarget.localName == 'treechildren') nsDragAndDrop.startDrag(event, this.parentNode.parentNode.DNDObserver);"
onselect="this.treeBoxObject.view.selectionChanged();">
<template xmlns:nc="http://home.netscape.com/NC-rdf#">
<rule rdf:type="http://home.netscape.com/NC-rdf#BookmarkSeparator">
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type separator"/>
</treeitem>
</treechildren>
</rule>
<rule nc:FolderGroup="true">
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
<treecell properties="group" label="rdf:http://home.netscape.com/NC-rdf#Name" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#URL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#ShortcutURL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#Description" />
<treecell label="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate"/>
<treecell label="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#LastModifiedDate" />
</treerow>
</treeitem>
</treechildren>
</rule>
<rule>
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
<treecell label="rdf:http://home.netscape.com/NC-rdf#Name" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#URL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#ShortcutURL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#Description" />
<treecell label="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate"/>
<treecell label="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#LastModifiedDate" />
</treerow>
</treeitem>
</treechildren>
</rule>
</template>
<treecols anonid="treecols">
<treecol id="Name" label="&treecol.name.label;" flex="1" primary="true"
class="sortDirectionIndicator"
persist="width hidden sortActive sortDirection ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortDirection="none"/>
<splitter class="tree-splitter" />
<treecol id="URL" label="&treecol.url.label;"
flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#URL"
persist="width hidden sortActive sortDirection ordinal" />
<splitter class="tree-splitter" />
<treecol id="ShortcutURL" label="&treecol.shortcut.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#ShortcutURL"/>
<splitter class="tree-splitter"/>
<treecol id="Description" label="&treecol.description.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#Description"/>
<splitter class="tree-splitter"/>
<treecol id="AddDate" label="&treecol.addedon.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate"
persist="width hidden sortActive sortDirection ordinal" />
<splitter class="tree-splitter" />
<treecol id="LastModDate" label="&treecol.lastmod.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#LastModifiedDate"
persist="width hidden sortActive sortDirection ordinal" />
<splitter class="tree-splitter" />
<treecol id="LastVisitDate" label="&treecol.lastvisit.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#LastVisitDate"
persist="width hidden sortActive sortDirection ordinal" />
</treecols>
</tree>
<statusbar class="chromeclass-status" xbl:inherits="hidden=hidestatusbar" hidden="false">
<statusbarpanel anonid="statusbar-text" flex="1"/>
</statusbar>
</vbox>
</xbl:content>
<implementation>
<field name="clickCount">2</field>
</implementation>
</binding>
<!-- Single column tree -->
<binding id="bookmarks-tree-name" extends="chrome://communicator/content/bookmarks/bookmarks.xml#bookmarks-tree">
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl" contextmenu="_child">
<menupopup id="bmContext"
onpopupshowing="this.parentNode.createContextMenu(event);"/>
<tree anonid="bookmarks-tree" flex="1" hidecolumnpicker="true" class="plain"
datasources="rdf:bookmarks rdf:internetsearch rdf:files rdf:localsearch" ref="NC:BookmarksRoot" flags="dont-build-content"
onkeypress="if (event.keyCode == 13) this.parentNode.openItem(event, false, true);"
ondraggesture="if (event.originalTarget.localName == 'treechildren') nsDragAndDrop.startDrag(event, this.parentNode.DNDObserver);"
onclick="if (this.parentNode.validOpenClickConditions(event)) this.parentNode.openItem(event, false, true);"
onselect="this.parentNode.treeBoxObject.view.selectionChanged();">
<template xmlns:nc="http://home.netscape.com/NC-rdf#">
<rule rdf:type="http://home.netscape.com/NC-rdf#BookmarkSeparator">
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type separator" />
</treeitem>
</treechildren>
</rule>
<rule nc:FolderGroup="true">
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
<treecell properties="group hidetwisty" label="rdf:http://home.netscape.com/NC-rdf#Name" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#URL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#ShortcutURL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#Description" />
<treecell label="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate"/>
<treecell label="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#LastModifiedDate" />
</treerow>
</treeitem>
</treechildren>
</rule>
<rule>
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
<treecell label="rdf:http://home.netscape.com/NC-rdf#Name" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#URL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#ShortcutURL" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#Description" />
<treecell label="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate"/>
<treecell label="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" />
<treecell label="rdf:http://home.netscape.com/NC-rdf#LastModifiedDate" />
</treerow>
</treeitem>
</treechildren>
</rule>
</template>
<treecols anonid="treecols">
<treecol id="Name" label="&treecol.name.label;" flex="1" primary="true"
class="sortDirectionIndicator"
persist="width hidden sortActive sortDirection ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortDirection="none"/>
<splitter class="tree-splitter" />
<treecol id="URL" label="&treecol.url.label;"
flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#URL"
hidden="true"/>
<splitter class="tree-splitter" />
<treecol id="ShortcutURL" label="&treecol.shortcut.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#ShortcutURL"/>
<splitter class="tree-splitter" />
<treecol id="Description" label="&treecol.description.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#Description"/>
<splitter class="tree-splitter" />
<treecol id="AddDate" label="&treecol.addedon.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" />
<splitter class="tree-splitter" />
<treecol id="LastModDate" label="&treecol.lastmod.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#LastModifiedDate" />
<splitter class="tree-splitter" />
<treecol id="LastVisitDate" label="&treecol.lastvisit.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#LastVisitDate" />
</treecols>
</tree>
</xbl:content>
<implementation>
<field name="clickCount">1</field>
</implementation>
</binding>
<!-- Tree with folders only -->
<binding id="bookmarks-tree-folders" extends="chrome://communicator/content/bookmarks/bookmarks.xml#bookmarks-tree">
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl">
<tree anonid="bookmarks-tree" flex="1" hidecolumnpicker="true"
datasources="rdf:bookmarks rdf:internetsearch rdf:files rdf:localsearch" ref="NC:BookmarksRoot" flags="dont-build-content"
onselect="this.parentNode.treeBoxObject.view.selectionChanged();">
<template>
<rule iscontainer="true">
<treechildren>
<treeitem uri="rdf:*">
<treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
<treecell label="rdf:http://home.netscape.com/NC-rdf#Name" />
</treerow>
</treeitem>
</treechildren>
</rule>
</template>
<treecols anonid="treecols">
<treecol id="Name" label="&treecol.name.label;" flex="1" primary="true"
class="sortDirectionIndicator" persist="width hidden sortActive sortDirection"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortDirection="none"/>
</treecols>
</tree>
</xbl:content>
<implementation>
<field name="clickCount">1</field>
</implementation>
</binding>
</bindings>
<!--
API:
- root ref
- datasources
- columns
- click count
- sort
- selection
- default action oncommand
- context menu
- insert, remove bookmarks
-
//-->
<!--
ILE:
- impl ILE on tree.xml
//-->
<!--
Command handling:
- impl |nsIController|
- actual controller implemented by client which intercepts commands and provides
special handling for things like open in new browser etc.
- client can alternatively use the built in controller for default functionality.
- decisions:
Implementation pattern:
client:
(A) bookmarksUIElement.prototype.doCommand = function () { .. }
OR
(B) var ctrlr = { doCommand: function () { bookmarksUIElement.doCommand(); }
Tend to prefer (B) as it supports delegation
//-->