New bookmarks window stuff, not yet part of build.

This commit is contained in:
ben%netscape.com 2001-01-22 10:36:40 +00:00
Родитель 95defc7d0e
Коммит 530f85f222
10 изменённых файлов: 1855 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,140 @@
/* -*- Mode: C; c-basic-offset: 2 -*-
*
* 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>
* Josh Soref <timeless@mac.com>
*/
/**
* Style rules for bookmarks tree items. Ideally this would be usage agnostic, but
* there's window/panel specific cruft in here too.
**/
.treecell-bookmark
{
list-style-image : inherit;
}
.treeitem-bookmark
{
list-style-image : url("chrome://communicator/skin/bookmarks/location.gif");
}
.treeitem-bookmark[container="true"][open="true"][loading="true"]
{
list-style-image : url("chrome://global/skin/loading.gif") ! important ;
}
.treeitem-bookmark[status="new"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/bookmark-item-updated.gif") ! important ;
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#Folder"],
.treeitem-bookmark[container="true"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/bookmark-folder-closed.gif");
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#Folder"][open="true"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/bookmark-folder-open.gif");
}
.treeitem-bookmark[container="true"][open="true"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/bookmark-folder-open.gif");
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#Folder"][id="NC:PersonalToolbarFolder"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/personal-folder-closed.gif") !important;
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#Folder"][id="NC:PersonalToolbarFolder"][open="true"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/personal-folder-open.gif") !important;
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#BookmarkSeparator"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/location.gif");
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#Bookmark"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/location.gif");
}
/**
* XXX - need to create some different icons for file system objects
**/
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#FileSystemObject"][container="true"][open="true"]
{
list-style-image : url("chrome://communicator/skin/directory/file-folder-open.gif");
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#FileSystemObject"][container="true"]
{
list-style-image : url("chrome://communicator/skin/directory/file-folder-closed.gif");
}
.treeitem-bookmark[type="http://home.netscape.com/NC-rdf#FileSystemObject"]
{
list-style-image : url("chrome://communicator/skin/directory/file-icon.gif");
}
/**
* Bookmarks tree
**/
.bookmarks-panel-tree, .bookmarks-panel-tree > .tree-container-treerows
{
border : none;
}
#bookmarksTree
{
border-top : none;
border-bottom : none;
}
/**
* XXX - disable print plus. This needs to go into ns/!!!
*/
#navprintplus
{
display : none !important;
}
#status-bar
{
height : 1em;
}
#notification-icon
{
list-style-image : url("chrome://communicator/skin/bookmarks/notification.gif");
}
#schedule-icon
{
list-style-image : url("chrome://communicator/skin/bookmarks/schedule.gif");
}

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,155 @@
/* -*- Mode: C; c-basic-offset: 2 -*-
*
* 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>
* Josh Soref <timeless@mac.com>
*/
/**
* Style rules for bookmark items in Navigator.
**/
#home-button
{
list-style-image : url("chrome://communicator/skin/bookmarks/home.gif");
}
#home-button:hover
{
list-style-image : url("chrome://communicator/skin/bookmarks/home-hover.gif");
}
#home-button:hover:active
{
list-style-image : url("chrome://communicator/skin/bookmarks/home-active.gif");
}
/**
* Personal toolbar items
**/
.bookmarkitem
{
list-style-image : url("chrome://communicator/skin/bookmarks/location.gif");
cursor : pointer;
}
.bookmarkfolder
{
list-style-image : url("chrome://communicator/skin/bookmarks/bookmark-folder-closed.gif");
}
.bookmarkfolder > .menubutton-toolbar-single-internal-box > .menubutton-toolbar-single-dropmarker
{
display : none;
}
.bookmarkfolder[open="true"]
{
list-style-image : url("chrome://communicator/skin/bookmarks/bookmark-folder-open.gif");
}
/* Bookmark item/folder buttons on the personal toolbar */
/* need to override default border on button-toolbar buttons/menubuttons */
.button-toolbar.bookmarkitem
{
-moz-binding : url("chrome://global/skin/classicBindings.xml#toolbarbutton-left");
border : none;
vertical-align : middle;
}
.button-toolbar.bookmarkitem,
.button-toolbar.bookmarkfolder
{
max-width : 10em;
}
.button-toolbar.bookmarkfolder > box > text
{
max-width: 8em !important;
}
.toolbarbutton-top-icon
{
max-width : 2em;
}
.toolbarbutton-left-text
{
max-width : 8em;
}
.button-toolbar.bookmarkfolder, .button-toolbar.bookmarkfolder:hover
{
border : none;
}
.button-toolbar.bookmarkitem > .toolbarbutton-left-icon
{
margin-right : 4px;
}
.bookmarkfolder.button-toolbar:hover
{
color : #0000FF;
cursor : pointer;
border : none;
}
.bookmarkfolder.button-toolbar:hover:active
{
color : #FF0000;
border : none;
}
.bookmarkitem.button-toolbar:hover
{
color : #0000FF;
text-decoration : underline;
cursor : pointer;
border : none;
}
.bookmarkitem.button-toolbar:hover:active
{
color : #FF0000;
text-decoration : underline;
border : none;
}
/* drag and drop feedback */
.bookmarkitem.button-toolbar[dragover-left="true"]
{
margin-left : 0px;
border-left : 2px solid threeddarkshadow;
}
.bookmarkitem.button-toolbar[dragover-right="true"]
{
margin-right : 0px;
border-right : 2px solid threeddarkshadow;
}
.menubutton-toolbar-single-text[dragover-top="true"]
{
background-color : threeddarkshadow;
color : threedhighlight;
}

Просмотреть файл

@ -0,0 +1,137 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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)
*/
var gFld_Name = null;
var gFld_URL = null;
var gFolderTree = null;
const kRDFSContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFSIID = Components.interfaces.nsIRDFService;
const kRDF = Components.classes[kRDFSContractID].getService(kRDFSIID);
var gSelectItemObserver = null;
var gCreateInFolder = "NC:NewBookmarkFolder";
function Startup()
{
doSetOKCancel(onOK);
gFld_Name = document.getElementById("name");
gFld_URL = document.getElementById("url");
gFolderTree = document.getElementById("folders");
if ("arguments" in window) {
gFld_Name.value = window.arguments[0] || "";
gFld_URL.value = window.arguments[1] || "";
if (window.arguments[2]) {
gCreateInFolder = window.arguments[2];
//document.getElementById("createin").setAttribute("hidden", "true");
//document.getElementById("folderbox").setAttribute("hidden", "true");
}
}
onLocationInput();
gFld_Name.focus();
}
function toggleCreateIn()
{
var folderbox = document.getElementById("folderbox");
var createInButton = document.getElementById("createin");
var dontaskagain = document.getElementById("dontaskagain");
var oldID, newID;
if (folderbox.getAttribute("hidden") == "true") {
createInButton.value = createInButton.getAttribute("value2");
folderbox.removeAttribute("hidden");
dontaskagain.removeAttribute("hidden");
oldID = "buttonsparent";
newID = "openParent";
}
else {
createInButton.value = createInButton.getAttribute("value1");
folderbox.setAttribute("hidden", "true");
dontaskagain.setAttribute("hidden", "true");
oldID = "openParent";
newID = "buttonsparent";
}
var oldParent = document.getElementById(oldID);
var newParent = document.getElementById(newID);
var buttons = oldParent.firstChild.cloneNode(true);
oldParent.removeChild(oldParent.firstChild);
newParent.appendChild(buttons);
sizeToContent();
}
function onLocationInput ()
{
var ok = document.getElementById("ok");
if (!gFld_URL.value)
ok.setAttribute("disabled", "true");
else
ok.removeAttribute("disabled");
}
function onOK()
{
const kBMDS = kRDF.GetDataSource("rdf:bookmarks");
const kBMSContractID = "@mozilla.org/browser/bookmarks-service;1";
const kBMSIID = Components.interfaces.nsIBookmarksService;
const kBMS = Components.classes[kBMSContractID].getService(kBMSIID);
var rFolder = kRDF.GetResource(gCreateInFolder, true);
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFIID = Components.interfaces.nsIRDFContainer;
const kRDFC = Components.classes[kRDFCContractID].getService(kRDFIID);
try {
kRDFC.Init(kBMDS, rFolder);
}
catch (e) {
// No "NC:NewBookmarkFolder" exists, just append to the root.
rFolder = kRDF.GetResource("NC:BookmarksRoot", true);
}
if (!gFld_URL.value) return;
kBMS.AddBookmarkToFolder(gFld_URL.value, rFolder, gFld_Name.value, null);
close();
}
function onTreeSelect ()
{
if (gFolderTree.selectedItems.length < 1)
gCreateInFolder = "NC:NewBookmarkFolder";
var selectedItem = gFolderTree.selectedItems[0];
gCreateInFolder = selectedItem.id;
}
var gBookmarksShell = null;
function createNewFolder ()
{
// ick.
gBookmarksShell = new BookmarksTree("folders");
var item = null;
var folderKids = document.getElementById("folderKids");
if (gFolderTree.selectedItems.length < 1)
item = folderKids.firstChild;
item = gFolderTree.selectedItems.length < 1 ? folderKids.firstChild : gFolderTree.selectedItems[0];
gBookmarksShell.commands.createBookmarkItem("folder", item);
}

Просмотреть файл

@ -0,0 +1,152 @@
<?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)
-->
<?xml-stylesheet href="chrome://communicator/skin/"?>
<?xml-stylesheet href="chrome://communicator/skin/bookmarks/bookmarks-tree.css"?>
<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd" >
%brandDTD;
<!ENTITY % addBookmarkDTD SYSTEM "chrome://communicator/locale/bookmarks/addBookmark.dtd">
%addBookmarkDTD;
]>
<window id="newBookmarkWindow" style="width: 36em;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&newBookmark.title;" orient="vertical" class="dialog"
onload="Startup();">
<script type="text/javascript" src="chrome://communicator/content/bookmarks/bookmarksOverlay.js"></script>
<script type="text/javascript" src="chrome://communicator/content/bookmarks/bookmarksTree.js"></script>
<script type="text/javascript" src="chrome://communicator/content/bookmarks/addBookmark.js"></script>
<stringbundle id="bookmarksbundle"
src="chrome://communicator/locale/bookmarks/bookmark.properties"/>
<keyset id="keyset"/>
<popupset id="aTooltipSet"/>
<separator class="thin"/>
<grid id="bookmarknamegrid">
<columns>
<column/>
<column flex="5"/>
<column flex="1"/>
</columns>
<rows>
<row autostretch="never">
<text class="label" value="&name.label;" accesskey="&name.accesskey;" for="name"/>
<textfield id="name"/>
</row>
<row>
<separator class="thin"/>
<separator class="thin"/>
</row>
<row autostretch="never">
<text class="label" value="&url.label;" accesskey="&url.accesskey;" for="url"/>
<textfield id="url" oninput="onLocationInput();"/>
</row>
</rows>
</grid>
<separator/>
<box id="createinbuttonbox">
<button id="createin" class="disclosure-triangle" value="&button.createin.label;"
accesskey="&button.createin.accesskey;"
value1="&button.createin.label;"
value2="&button.createin2.label;"
oncommand="toggleCreateIn();"/>
<spring flex="1"/>
<box id="buttonsparent">
<box id="okCancelButtonsRight"/>
</box>
</box>
<box id="folderbox" orient="vertical" hidden="true">
<separator/>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row autostretch="never" valign="top">
<text class="label" value="&createin.label;"/>
<box autostretch="never" valign="top">
<tree id="folders" flex="1" style="height: 12em; width: 0px"
class="inset" ref="NC:BookmarksRoot" datasources="rdf:bookmarks"
template="file-bookmarks-template">
<treecols>
<treecol flex="1"/>
</treecols>
<template id="file-bookmarks-template">
<rule iscontainer="true">
<treechildren>
<treeitem uri="rdf:*" persist="open" class="treeitem-bookmark"
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
<treerow>
<treecell value="rdf:http://home.netscape.com/NC-rdf#Name"
class="treecell-indent-editable" editable="true"
src="rdf:http://home.netscape.com/NC-rdf#Icon"
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
loading="rdf:http://home.netscape.com/NC-rdf#loading"/>
</treerow>
</treeitem>
</treechildren>
</rule>
</template>
<treechildren id="folderKids" flex="1"/>
</tree>
<button value="&button.newfolder.label;" accesskey="&button.newfolder.accesskey;"
oncommand="createNewFolder();"/>
</box>
</row>
</rows>
</grid>
<separator/>
</box>
<box valign="bottom">
<box autostretch="never">
<checkbox id="dontaskagain" hidden="true"
tooltip="aTooltip" tooltiptext="&dontshowmessage.tooltip;"
value="&alwayscreateinfolder.label;"
accesskey="&alwayscreateinfolder.accesskey;"/>
</box>
<spring flex="1"/>
<box id="openParent" orient="vertical"/>
</box>
</window>

Просмотреть файл

@ -0,0 +1,596 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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)
*/
var NC_NS = "http://home.netscape.com/NC-rdf#";
var RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
const NC_NS_CMD = NC_NS + "command?cmd=";
function NODE_ID (aElement)
{
return aElement.getAttribute("ref") || aElement.id;
}
function LITERAL (aDB, aElement, aPropertyID)
{
var RDF = BookmarksUIElement.prototype.RDF;
var rSource = RDF.GetResource(NODE_ID(aElement));
var rProperty = RDF.GetResource(aPropertyID);
var node = aDB.GetTarget(rSource, rProperty, true);
return node ? node.QueryInterface(Components.interfaces.nsIRDFLiteral).Value : "";
}
function BookmarksUIElement () { }
BookmarksUIElement.prototype = {
_rdf: null,
get RDF ()
{
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;
},
propertySet: function (sourceID, propertyID, newValue)
{
if (!newValue) return;
const kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFIID = Components.interfaces.nsIRDFService;
const kRDF = Components.classes[kRDFContractID].getService(kRDFIID);
// need to shuffle this into an API.
const kBMDS = kRDF.GetDataSource("rdf:bookmarks");
const krProperty = kRDF.GetResource(propertyID);
const krItem = kRDF.GetResource(sourceID);
var rCurrValue = kBMDS.GetTarget(krItem, krProperty, true);
const krNewValue = kRDF.GetLiteral(newValue);
if (!rCurrValue)
kBMDS.Assert(krItem, krProperty, krNewValue, true);
else {
rCurrValue = rCurrValue.QueryInterface(Components.interfaces.nsIRDFLiteral);
if (rCurrValue.Value != newValue)
kBMDS.Change(krItem, krProperty, rCurrValue, krNewValue);
}
},
/////////////////////////////////////////////////////////////////////////////
// Fill a context menu popup with menuitems that are appropriate for the current
// selection.
createContextMenu: function (aEvent)
{
var popup = aEvent.target;
// clear out the old context menu contents (if any)
while (popup.hasChildNodes())
popup.removeChild(popup.firstChild);
var popupNode = document.popupNode;
if (!("findRDFNode" in this))
throw "Clients must implement findRDFNode!";
var itemNode = this.findRDFNode(popupNode, true);
if (!itemNode) return;
if (!("getContextSelection" in this))
throw "Clients must implement getContextSelection!";
var selection = this.getContextSelection (itemNode);
var commonCommands = [];
for (var i = 0; i < selection.length; ++i) {
var nodeURI = NODE_ID(selection[i]);
var commands = this.getAllCmds(nodeURI);
commands = this.flattenEnumerator(commands);
if (!commonCommands.length) commonCommands = commands;
commonCommands = this.findCommonNodes(commands, commonCommands);
}
// 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 != NC_NS_CMD + "separator") {
var commandName = this.getCommandName(currCommand);
element = this.createMenuItem(commandName, currCommand, itemNode);
}
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);
}
},
/////////////////////////////////////////////////////////////////////////////
// Given two unique arrays, return an array that contains only the elements
// common to both.
findCommonNodes: function (aNewArray, aOldArray)
{
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;
},
flattenEnumerator: function (aEnumerator)
{
if ("_index" in aEnumerator)
return aEnumerator._inner;
var temp = [];
while (aEnumerator.hasMoreElements())
temp.push(aEnumerator.getNext());
return temp;
},
/////////////////////////////////////////////////////////////////////////////
// For a given URI (a unique identifier of a resource in the graph) return
// an enumeration of applicable commands for that URI.
getAllCmds: function (aNodeID)
{
var type = this.resolveType(aNodeID);
var commands = [];
switch (type) {
case "http://home.netscape.com/NC-rdf#BookmarkSeparator":
commands = ["find", "separator", "cut", "copy", "paste",
"delete"];
break;
case "http://home.netscape.com/NC-rdf#Bookmark":
commands = ["open", "find", "separator", "cut", "copy", "paste",
"delete", "separator", "rename", "separator",
"properties"];
break;
case "http://home.netscape.com/NC-rdf#Folder":
commands = ["openfolder", "openfolderinnewwindow", "find", "separator",
"cut", "copy", "paste", "delete", "separator", "rename",
"separator", "newfolder", "separator", "properties"];
break;
default:
var source = this.RDF.GetResource(aNodeID);
return this.db.GetAllCmds(source);
}
return new CommandArrayEnumerator(commands);
},
/////////////////////////////////////////////////////////////////////////////
// Retrieve the human-readable name for a particular command. Used when
// manufacturing a UI to invoke commands.
getCommandName: function (aCommand)
{
var cmdName = aCommand.substring(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 this.getLocaleString ("cmd_" + cmdName);
}
catch (e) {
}
const rName = this.RDF.GetResource(NC_NS + "Name");
const rSource = this.RDF.GetResource(aNodeID);
return this.db.GetTarget(rSource, rName, true).Value;
},
/////////////////////////////////////////////////////////////////////////////
// Perform a command based on a UI event. XXX - work to do here.
preExecCommand: function (aEvent)
{
var commandID = aEvent.target.getAttribute("command");
if (!commandID) return;
goDoCommand("cmd_" + commandID.substring(NC_NS_CMD.length));
},
execCommand: function (commandID)
{
var selection = this.getSelection ();
if (selection.length == 1 && commandID != "cut" && commandID != "copy" &&
commandID != "paste" && commandID != "delete") {
// Commands that can only be performed on a single selection
var selectedItem = selection[0];
switch (commandID) {
case "open":
this.openRDFNode(selectedItem);
break;
case "openfolder":
this.commands.openFolder(selectedItem);
break;
case "openfolderinnewwindow":
this.openFolderInNewWindow(selectedItem);
break;
case "rename":
// XXX - this is SO going to break if we ever do column re-ordering.
this.commands.editCell(selectedItem, 0);
break;
case "editurl":
this.commands.editCell(selectedItem, 1);
break;
case "setnewbookmarkfolder":
case "setpersonaltoolbarfolder":
case "setnewsearchfolder":
rCommand = this.RDF.GetResource(NC_NS_CMD + commandID);
rSource = this.RDF.GetResource(NODE_ID(selectedItem));
kSuppArrayContractID = "@mozilla.org/supports-array;1";
kSuppArrayIID = Components.interfaces.nsISupportsArray;
var sourcesArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
sourcesArray.AppendElement (krSource);
var argsArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
this.db.DoCommand(sourcesArray, krCommand, argsArray);
break;
case "properties":
this.showPropertiesForNode(selectedItem);
break;
case "find":
this.findInBookmarks();
break;
}
}
else {
// Commands that can be performed on a selection of 1 or more items.
switch (commandID) {
case "cut":
this.copySelection (selection);
this.deleteSelection (selection);
break;
case "copy":
this.copySelection (selection);
break;
case "paste":
this.paste (selection);
break;
case "delete":
this.deleteSelection (selection);
break;
case "find":
this.findInBookmarks();
break;
case "newfolder":
var nfseln = this.getBestItem ();
this.commands.createBookmarkItem("folder", nfseln);
break;
case "newbookmark":
var folder = this.getSelectedFolder();
openDialog("chrome://communicator/content/bookmarks/addBookmark.xul", "",
"centerscreen,chrome,dialog=no,resizable=no", null, null, folder);
break;
case "newseparator":
break;
}
}
},
///////////////////////////////////////////////////////////////////////////
// Execute a command with the given source and arguments
doBookmarksCommand: function (aSourceURI, aCommand, aArgumentsArray)
{
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 Bookmarks datasource.
const kBMDS = this.RDF.GetDataSource("rdf:bookmarks");
kBMDS.DoCommand(sourcesArray, rCommand, argsArray);
},
openFolderInNewWindow: function (aSelectedItem)
{
openDialog("chrome://communicator/content/bookmarks/bookmarks.xul",
"", "chrome,all,dialog=no", NODE_ID(aSelectedItem));
},
copySelection: function (aSelection)
{
const kSuppArrayContractID = "@mozilla.org/supports-array;1";
const kSuppArrayIID = Components.interfaces.nsISupportsArray;
var itemArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
const kSuppWStringContractID = "@mozilla.org/supports-wstring;1";
const kSuppWStringIID = Components.interfaces.nsISupportsWString;
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 = "";
for (var i = 0; i < aSelection.length; ++i) {
var url = LITERAL(this.db, aSelection[i], NC_NS + "URL");
var name = LITERAL(this.db, aSelection[i], NC_NS + "Name");
sBookmarkItem += NODE_ID(aSelection[i]) + "\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 = sTextHTML;
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);
},
paste: function (aSelection)
{
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.nsISupportsWString).data;
switch (flavour.value) {
case "moz/bookmarkclipboarditem":
nodes = data.split("\n");
break;
case "text/x-moz-url":
var ix = data.value.indexOf("\n");
nodes.push(data.substring(0, ix != -1 ? ix : data.length));
names.push(data.substring(ix));
break;
default:
return;
}
const lastSelected = aSelection[aSelection.length-1];
const kParentNode = this.resolvePasteFolder(aSelection);
const krParent = this.RDF.GetResource(NODE_ID(kParentNode));
const krSource = this.RDF.GetResource(NODE_ID(lastSelected));
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFCIID = Components.interfaces.nsIRDFContainer;
const ksRDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
const kBMDS = this.RDF.GetDataSource("rdf:bookmarks");
ksRDFC.Init(kBMDS, krParent);
for (var i = 0; i < nodes.length; ++i) {
if (!nodes[i]) continue;
const krCurrent = this.RDF.GetResource(nodes[i]);
if (names.length) {
// If we are given names, this implies that the nodes do not already
// exist in the graph, and we need to create some additional information
// for them.
const krName = this.RDF.GetResource(names[i]);
const krNameProperty = this.RDF.GetResource(NC_NS + "Name");
const krTypeProperty = this.RDF.GetResource(RDF_NS + "type");
const krBookmark = this.RDF.GetResource(NC_NS + "Bookmark");
this.db.Assert(krCurrent, krNameProperty, krName, true);
this.db.Assert(krCurrent, krTypeProperty, krBookmark, true);
}
ix = ksRDFC.IndexOf(krSource);
if (ix != -1)
ksRDFC.InsertElementAt(krCurrent, ix+1, true);
else
ksRDFC.AppendElement(krCurrent);
if ("addItemToSelection" in this)
this.addItemToSelection(krCurrent.Value);
}
},
canPaste: function ()
{
const kClipboardContractID = "@mozilla.org/widget/clipboard;1";
const kClipboardIID = Components.interfaces.nsIClipboard;
var clipboard = Components.classes[kClipboardContractID].getService(kClipboardIID);
const kSuppArrayContractID = "@mozilla.org/supports-array;1";
const kSuppArrayIID = Components.interfaces.nsISupportsArray;
var flavourArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
const kSuppStringContractID = "@mozilla.org/supports-string;1";
const kSuppStringIID = Components.interfaces.nsISupportsString;
var flavours = ["moz/bookmarkclipboarditem", "text/x-moz-url"];
for (var i = 0; i < flavours.length; ++i) {
const kSuppString = Components.classes[kSuppStringContractID].createInstance(kSuppStringIID);
kSuppString.data = flavours[i];
flavourArray.AppendElement(kSuppString);
}
var hasFlavors = clipboard.hasDataMatchingFlavors(flavourArray, kClipboardIID.kGlobalClipboard);
return hasFlavors;
},
deleteSelection: function (aSelection)
{
const kRDFCContractID = "@mozilla.org/rdf/container;1";
const kRDFCIID = Components.interfaces.nsIRDFContainer;
const ksRDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
// We must create a copy here because we're going to be modifying the
// selectedItems list.
var tempSelection = aSelection;
var nextElement;
for (var i = 0; i < tempSelection.length; ++i) {
const currParent = this.findRDFNode(tempSelection[i], false);
const kSelectionURI = NODE_ID(tempSelection[i]);
// Disallow the removal of certain 'special' nodes
if (kSelectionURI == "NC:BookmarksRoot" || kSelectionURI == "NC:IEFavoritesRoot")
continue;
const krParent = this.RDF.GetResource(NODE_ID(currParent));
const krNode = this.RDF.GetResource(kSelectionURI);
const kBMDS = this.RDF.GetDataSource("rdf:bookmarks");
ksRDFC.Init(kBMDS, krParent);
nextElement = this.getNextElement(tempSelection[i]);
ksRDFC.RemoveElement(krNode, true);
}
this.selectElement(nextElement);
},
moveBookmark: function (aBookmarkURI, aFromFolderURI, aToFolderURI)
{
const kBMDS = this.RDF.GetDataSource("rdf:bookmarks");
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(kBMDS, krNewParent);
kRDFC.AppendElement(krSrc);
kRDFC.Init(kBMDS, krOldParent);
kRDFC.RemoveElement(krSrc, true);
},
openRDFNode: function (aRDFNode)
{
var urlValue = LITERAL(this.db, aRDFNode, NC_NS + "URL");
// Ignore "NC:" and empty urls.
if (urlValue.substring(0,3) == "NC:" || !urlValue) return;
openDialog (getBrowserURL(), "_blank", "chrome,all,dialog=no", urlValue);
},
open: function (aEvent)
{
if (!this.isValidOpenEvent(aEvent))
return;
var rdfNode = this.findRDFNode(aEvent.target, true);
if (rdfNode.getAttribute("container") == "true")
return;
var urlValue = LITERAL(this.db, rdfNode, NC_NS + "URL");
// Ignore "NC:" and empty urls.
if (urlValue.substring(0,3) == "NC:" || !urlValue) return;
if (aEvent.altKey)
this.showPropertiesForNode (rdfNode);
else
openDialog (getBrowserURL(), "_blank", "chrome,all,dialog=no", urlValue);
aEvent.preventBubble();
},
showPropertiesForNode: function (aBookmarkItem)
{
openDialog("chrome://communicator/content/bookmarks/bm-props.xul",
"", "centerscreen,chrome,dialog=no,resizable=no",
NODE_ID(aBookmarkItem));
},
findInBookmarks: function ()
{
openDialog("chrome://communicator/content/bookmarks/bm-find.xul",
"FindBookmarksWindow",
"centerscreen,chrome,resizable");
},
getLocaleString: function (aStringKey)
{
var bundle = document.getElementById("bookmarksbundle");
return bundle.getString (aStringKey);
},
flushDataSource: function ()
{
const kBMDS = this.RDF.GetDataSource("rdf:bookmarks");
var remoteDS = kBMDS.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
remoteDS.Flush();
},
/////////////////////////////////////////////////////////////////////////////
// Determine the rdf:type property for the given resource.
resolveType: function (aID)
{
const bmTree = document.getElementById("bookmarksTree");
const krType = this.RDF.GetResource(RDF_NS + "type");
const krElement = this.RDF.GetResource(aID);
const type = bmTree.database.GetTarget(krElement, krType, true);
return type.QueryInterface(Components.interfaces.nsIRDFResource).Value;
}
};
function CommandArrayEnumerator (aCommandArray)
{
this._inner = [];
const kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
const kRDFIID = Components.interfaces.nsIRDFService;
const RDF = Components.classes[kRDFContractID].getService(kRDFIID);
for (var i = 0; i < aCommandArray.length; ++i)
this._inner.push(RDF.GetResource(NC_NS_CMD + aCommandArray[i]));
this._index = 0;
}
CommandArrayEnumerator.prototype = {
getNext: function ()
{
return this._inner[this._index];
},
hasMoreElements: function ()
{
return this._index < this._inner.length;
}
};

Просмотреть файл

@ -0,0 +1,44 @@
<?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)
-->
<!DOCTYPE window SYSTEM "chrome://communicator/locale/bookmarks/bookmarksOverlay.dtd">
<overlay id="bookmarksOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<stringbundleset id="stringbundleset">
<stringbundle id="bookmarksbundle"
src="chrome://communicator/locale/bookmarks/bookmark.properties"/>
</stringbundleset>
<popupset id="popupset">
<popup id="bmContext"
oncreate="if (gBookmarksShell) gBookmarksShell.createContextMenu(event);"/>
</popupset>
</overlay>

Просмотреть файл

@ -0,0 +1,593 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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)
*/
var gBookmarksShell = null;
///////////////////////////////////////////////////////////////////////////////
// Tracks the selected item, the cell last clicked on, and the number of clicks
// given to it. Used to activate inline edit mode.
var gSelectionTracker = { currentItem: null, currentCell: null, clickCount: 0 };
///////////////////////////////////////////////////////////////////////////////
// Class which defines methods for a bookmarks UI implementation based around
// a treeview. Subclasses BookmarksBase in bookmarksOverlay.js. Some methods
// are required by the base class, others are for event handling. Window specific
// glue code should go into the BookmarksWindow class in bookmarks.js
function BookmarksTree (aID)
{
this.id = aID;
}
BookmarksTree.prototype = {
__proto__: BookmarksUIElement.prototype,
get tree ()
{
return document.getElementById(this.id);
},
/////////////////////////////////////////////////////////////////////////////
// This method constructs a menuitem for a context menu for the given command.
// This is implemented by the client so that it can intercept menuitem naming
// as appropriate.
createMenuItem: function (aDisplayName, aCommandName, aItemNode)
{
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var xulElement = document.createElementNS(kXULNS, "menuitem");
xulElement.setAttribute("command", aCommandName);
xulElement.setAttribute("observes", "cmd_" + aCommandName.substring(NC_NS_CMD.length));
switch (aCommandName) {
case NC_NS_CMD + "open":
xulElement.setAttribute("value", aDisplayName);
xulElement.setAttribute("default", "true");
break;
case NC_NS_CMD + "openfolder":
aDisplayName = aItemNode.getAttribute("open") == "true" ? this.getLocaleString("cmd_openfolder2") : aDisplayName;
xulElement.setAttribute("value", aDisplayName);
xulElement.setAttribute("default", "true");
break;
case NC_NS_CMD + "renamebookmark":
if (!document.popupNode.hasAttribute("type")) {
xulElement.setAttribute("value", this.getLocaleString("cmd_renamebookmark2"));
xulElement.setAttribute("command", (NC_NS_CMD + "editurl"));
}
else
xulElement.setAttribute("value", aDisplayName);
break;
default:
xulElement.setAttribute("value", aDisplayName);
break;
}
return xulElement;
},
/////////////////////////////////////////////////////////////////////////////
// For the given selection, determines the element that should form the
// container to paste items into.
resolvePasteFolder: function (aSelection)
{
const lastSelected = aSelection[aSelection.length-1];
if (lastSelected.getAttribute("container") == "true" &&
lastSelected.getAttribute("open") == "true" &&
aSelection.length == 1)
return lastSelected;
return this.findRDFNode(lastSelected, false);
},
// Command implementation
commands: {
openFolder: function (aSelectedItem)
{
if (aSelectedItem.getAttribute("open") == "true")
aSelectedItem.removeAttribute("open");
else
aSelectedItem.setAttribute("open", "true");
},
// Things Needed to Satisfy Mac Weenies:
// 1) need to implement timed single click edit. This could be Hard.
// 2) need to implement some other method of key access apart from F2.
// mpt claims that 'Cmd+U' is the excel equivalent.
editCell: function (aSelectedItem, aCell)
{
var editCell = aSelectedItem.firstChild.childNodes[aCell];
if (editCell.getAttribute("editable") != "true")
return;
var editColGroup = document.getElementById("theColumns");
var count = 0;
var property = "";
for (var i = 0; i < editColGroup.childNodes.length; ++i) {
var currCol = editColGroup.childNodes[i];
if (count == aCell) {
property = currCol.getAttribute("resource");
break;
}
++count;
// Deal with interleaved column resizer splitters
if (currCol.nextSibling.localName == "splitter") ++i;
}
if (property) {
editCell.setMode("edit");
editCell.addObserver(this.postModifyCallback, "accept",
[gBookmarksShell, NODE_ID(aSelectedItem), property]);
}
},
///////////////////////////////////////////////////////////////////////////
// Called after an inline-edit cell has left inline-edit mode, and data
// needs to be modified in the datasource.
postModifyCallback: function (aParams)
{
var aShell = aParams[0];
aShell.propertySet(aParams[1], aParams[2], aParams[3]);
gBookmarksShell.tree.focus();
gSelectionTracker.clickCount = 0;
},
///////////////////////////////////////////////////////////////////////////
// New Folder Creation
// Strategy: create a dummy row with edit fields to harvest information
// from the user, then destroy these rows and create an item
// in its place.
///////////////////////////////////////////////////////////////////////////
// Edit folder name & update the datasource if name is valid
onEditFolderName: function (aParams, aTopic)
{
var name = aParams[3];
var shell = gBookmarksShell.commands; // suck
var dummyItem = aParams[2];
var relativeNode = aParams[1];
var parentNode = gBookmarksShell.findRDFNode(relativeNode, false);
if (!shell.validateNameAndTopic(name, aTopic, relativeNode, dummyItem))
return;
// If we're attempting to create a folder as a subfolder of an open folder,
// we need to set the parentFolder to be relativeNode, which will be the
// parent of the new folder, rather than the parent of the relativeNode,
// which will result in the folder being created in an incorrect position
// (adjacent to the relativeNode).
var selKids = ContentUtils.childByLocalName(relativeNode, "treechildren");
if (selKids && selKids.hasChildNodes() && selKids.lastChild == dummyItem)
parentNode = relativeNode;
var args = [{ property: NC_NS + "parent",
resource: NODE_ID(parentNode) },
{ property: NC_NS + "Name",
literal: name }];
const kBMDS = gBookmarksShell.RDF.GetDataSource("rdf:bookmarks");
kBMDS.AddObserver(newFolderRDFObserver);
gBookmarksShell.doBookmarksCommand(NODE_ID(relativeNode), NC_NS_CMD + "newfolder", args);
kBMDS.RemoveObserver(newFolderRDFObserver);
var newFolderItem = document.getElementById(newFolderRDFObserver._newFolderURI);
gBookmarksShell.tree.focus();
gBookmarksShell.tree.selectItem(newFolderItem);
},
///////////////////////////////////////////////////////////////////////////
// Performs simple validation on what the user has entered:
// 1) prevents entering an empty string
// 2) in the case of a canceled operation, remove the dummy item and
// restore selection.
validateNameAndTopic: function (aName, aTopic, aOldSelectedItem, aDummyItem)
{
// Don't allow user to enter an empty string "";
if (!aName) return false;
// If the user hit escape, go no further.
if (aTopic == "reject") {
if (aOldSelectedItem)
gBookmarksShell.tree.selectItem(aOldSelectedItem);
aDummyItem.parentNode.removeChild(aDummyItem);
return false;
}
return true;
},
///////////////////////////////////////////////////////////////////////////
// Creates a dummy item that can be placed in edit mode to retrieve data
// to create new bookmarks/folders.
createBookmarkItem: function (aMode, aSelectedItem)
{
aSelectedItem.removeAttribute("selected");
var dummyItem = aSelectedItem.cloneNode(true);
dummyItem.removeAttribute("id");
dummyItem.removeAttribute("selected");
if (aMode == "folder")
dummyItem.setAttribute("container", "true");
for (var i = 0; i < dummyItem.firstChild.childNodes.length; ++i)
dummyItem.firstChild.childNodes[i].removeAttribute("value");
var editCell = dummyItem.firstChild.firstChild;
editCell.setAttribute("value",
gBookmarksShell.getLocaleString(aMode == "folder" ? "ile_newfolder" :
"ile_newbookmark"));
editCell.setAttribute("type", NC_NS + (aMode == "folder" ? "Folder" : "Bookmark"));
var relativeNode = aSelectedItem;
if (dummyItem.getAttribute("container") == "true") {
for (i = 0; i < dummyItem.childNodes.length; ++i) {
if (dummyItem.childNodes[i].localName == "treechildren")
dummyItem.removeChild(dummyItem.childNodes[i]);
}
if (dummyItem.getAttribute("open") == "true") {
var treechildren = ContentUtils.childByLocalName(aSelectedItem, "treechildren");
if (!treechildren) {
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
treechildren = document.createElementNS(kXULNS, "treechildren");
aSelectedItem.appendChild(treechildren);
}
// Insert new item after last item.
treechildren.appendChild(dummyItem);
}
else {
if (aSelectedItem.nextSibling)
aSelectedItem.parentNode.insertBefore(dummyItem, aSelectedItem.nextSibling);
else
aSelectedItem.parentNode.appendChild(dummyItem);
}
}
else {
if (aSelectedItem.nextSibling)
aSelectedItem.parentNode.insertBefore(dummyItem, aSelectedItem.nextSibling);
else
aSelectedItem.parentNode.appendChild(dummyItem);
}
editCell.setMode("edit");
var fn = aMode == "folder" ? this.onEditFolderName : this.onEditBookmarkName;
editCell.addObserver(fn, "accept", [editCell, relativeNode, dummyItem]);
editCell.addObserver(fn, "reject", [editCell, relativeNode, dummyItem]);
}
},
/////////////////////////////////////////////////////////////////////////////
// Evaluates an event to determine whether or not it affords opening a tree
// item. Typically, this is when the left mouse button is used, and provided
// the click-rate matches that specified by our owning tree class. For example,
// some trees open an item when double clicked (bookmarks/history windows) and
// others on a single click (sidebar panels).
isValidOpenEvent: function (aEvent)
{
return !(aEvent.type == "click" &&
(aEvent.button != 1 || aEvent.detail != this.openClickCount))
},
/////////////////////////////////////////////////////////////////////////////
// For the given selection, selects the best adjacent element. This method is
// useful when an action such as a cut or a deletion is performed on a
// selection, and focus/selection needs to be restored after the operation
// is performed.
getNextElement: function (aElement)
{
if (aElement.nextSibling)
return aElement.nextSibling;
else if (aElement.previousSibling)
return aElement.previousSibling;
else
return aElement.parentNode.parentNode;
},
selectElement: function (aElement)
{
this.tree.selectItem(aElement);
},
//////////////////////////////////////////////////////////////////////////////
// Add the treeitem element specified by aURI to the tree's current selection.
addItemToSelection: function (aURI)
{
var item = document.getElementById(aURI) // XXX flawed for multiple ids
this.tree.addItemToSelection(item);
},
/////////////////////////////////////////////////////////////////////////////
// Return a set of DOM nodes that represent the selection in the tree widget.
// This method is takes a node parameter which is the popupNode for the
// document. If the popupNode is not contained by the selection, the
// popupNode is selected and the new selection returned.
getSelection: function ()
{
return this.tree.selectedItems;
},
getBestItem: function ()
{
var seln = this.getSelection ();
if (seln.length < 1) {
var kids = ContentUtils.childByLocalName(this.tree, "treechildren");
if (kids) return kids.lastChild;
}
else
return seln[0];
return null;
},
/////////////////////////////////////////////////////////////////////////////
// Return a set of DOM nodes that represent the selection in the tree widget.
// This method is takes a node parameter which is the popupNode for the
// document. If the popupNode is not contained by the selection, the
// popupNode is selected and the new selection returned.
getContextSelection: function (aItemNode)
{
// How a context-click works:
// if the popup node is contained by the selection, the context menu is
// built for that selection. However, if the popup node is invoked on a
// non-selected node, unless modifiers are pressed**, the previous
// selection is discarded and that node selected.
var selectedItems = this.tree.selectedItems;
for (var i = 0; i < selectedItems.length; ++i) {
if (selectedItems[i] == aItemNode)
return selectedItems;
}
this.tree.selectItem(aItemNode);
return this.tree.selectedItems;
},
getSelectedFolder: function ()
{
var selectedItem = this.getBestItem();
if (!selectedItem) return "NC:BookmarksRoot";
while (selectedItem) {
if (selectedItem.getAttribute("container") == "true")
return NODE_ID(selectedItem);
selectedItem = selectedItem.parentNode.parentNode;
}
return "NC:BookmarksRoot";
},
/////////////////////////////////////////////////////////////////////////////
// For a given start DOM element, find the enclosing DOM element that contains
// the template builder RDF resource decorations (id, ref, etc).
findRDFNode: function (aStartNode, aIncludeStartNodeFlag)
{
var temp = aIncludeStartNodeFlag ? aStartNode : aStartNode.parentNode;
while (temp && temp.localName != "treeitem")
temp = temp.parentNode;
return temp || this.tree;
},
/////////////////////////////////////////////////////////////////////////////
// Tree click events. This handles when to go into inline-edit mode for
// editable cells.
treeClicked: function (aEvent)
{
if (this.tree.selectedItems.length > 1 || aEvent.detail > 1 || aEvent.button != 1)
return;
if (gSelectionTracker.currentItem == this.tree.currentItem &&
gSelectionTracker.currentCell == aEvent.target)
++gSelectionTracker.clickCount;
else
gSelectionTracker.clickCount = 0;
gSelectionTracker.currentItem = this.tree.currentItem;
gSelectionTracker.currentCell = aEvent.target;
var row = gSelectionTracker.currentItem.firstChild;
for (var i = 0; i < row.childNodes.length; ++i) {
if (row.childNodes[i] == gSelectionTracker.currentCell) {
// Don't allow inline-edit of cells other than name for folders.
if (gSelectionTracker.currentItem.getAttribute("type") != NC_NS + "Bookmark" &&
i > 1)
return;
if (gSelectionTracker.clickCount == 1)
gBookmarksShell.commands.editCell(this.tree.currentItem, i);
break;
}
}
},
/////////////////////////////////////////////////////////////////////////////
// Tree key events. This handles when to go into inline-edit mode for editable
// cells, when to load a URL, etc.
treeKeyPress: function (aEvent)
{
if (this.tree.selectedItems.length > 1) return;
if (aEvent.keyCode == 113 && aEvent.shiftKey) {
if (this.resolveType(NODE_ID(this.tree.currentItem)) == NC_NS + "Bookmark")
gBookmarksShell.commands.editCell (this.tree.currentItem, 1);
}
else if (aEvent.keyCode == 113)
goDoCommand("cmd_rename");
else if (aEvent.keyCode == 13 &&
this.tree.currentItem.firstChild.getAttribute("inline-edit") != "true")
goDoCommand("cmd_open");
},
selectFolderItem: function (aFolderURI, aItemURI, aAdditiveFlag)
{
var folder = document.getElementById(aFolderURI);
var kids = ContentUtils.childByLocalName(aSelectedItem, "treechildren");
if (!kids) return;
var item = kids.firstChild;
while (item) {
if (item.id == aItemURI) break;
item = item.nextSibling;
}
if (!item) return;
this.tree[aAdditiveFlag ? "addItemToSelection" : "selectItem"](item);
},
/////////////////////////////////////////////////////////////////////////////
// Command handling & Updating.
controller: {
supportsCommand: function (aCommand)
{
switch(aCommand) {
case "cmd_undo":
case "cmd_redo":
return false;
case "cmd_cut":
case "cmd_copy":
case "cmd_paste":
case "cmd_delete":
case "cmd_selectAll":
return true;
case "cmd_open":
case "cmd_openfolder":
case "cmd_newbookmark":
case "cmd_newfolder":
case "cmd_newseparator":
case "cmd_find":
case "cmd_properties":
case "cmd_rename":
case "cmd_delete":
case "cmd_setnewbookmarkfolder":
case "cmd_setpersonaltoolbarfolder":
case "cmd_setnewsearchfolder":
return true;
default:
return false;
}
},
isCommandEnabled: function (aCommand)
{
var numSelectedItems = gBookmarksShell.tree.selectedItems.length;
switch(aCommand) {
case "cmd_undo":
case "cmd_redo":
return false;
case "cmd_paste":
return gBookmarksShell.canPaste();
case "cmd_cut":
case "cmd_copy":
case "cmd_delete":
return numSelectedItems >= 1;
case "cmd_selectAll":
return true;
case "cmd_open":
var seln = gBookmarksShell.tree.selectedItems;
return numSelectedItems == 1 && seln[0].getAttribute("type") == NC_NS + "Bookmark";
case "cmd_openfolder":
seln = gBookmarksShell.tree.selectedItems;
return numSelectedItems == 1 && seln[0].getAttribute("type") == NC_NS + "Folder";
case "cmd_find":
case "cmd_newbookmark":
case "cmd_newfolder":
case "cmd_newseparator":
return true;
case "cmd_properties":
case "cmd_rename":
return numSelectedItems == 1;
case "cmd_setnewbookmarkfolder":
seln = gBookmarksShell.tree.selectedItems;
return numSelectedItems == 1 && !(NODE_ID(seln[0]) == "NC:NewBookmarkFolder");
case "cmd_setpersonaltoolbarfolder":
seln = gBookmarksShell.tree.selectedItems;
return numSelectedItems == 1 && !(NODE_ID(seln[0]) == "NC:PersonalToolbarFolder");
case "cmd_setnewsearchfolder":
seln = gBookmarksShell.tree.selectedItems;
return numSelectedItems == 1 && !(NODE_ID(seln[0]) == "NC:NewSearchFolder");
default:
return false;
}
},
doCommand: function (aCommand)
{
switch(aCommand) {
case "cmd_undo":
case "cmd_redo":
break;
case "cmd_paste":
case "cmd_copy":
case "cmd_cut":
case "cmd_delete":
case "cmd_newbookmark":
case "cmd_newfolder":
case "cmd_newseparator":
case "cmd_properties":
case "cmd_rename":
case "cmd_open":
case "cmd_openfolder":
case "cmd_setnewbookmarkfolder":
case "cmd_setpersonaltoolbarfolder":
case "cmd_setnewsearchfolder":
case "cmd_find":
gBookmarksShell.execCommand(aCommand.substring("cmd_".length));
break;
}
},
onEvent: function (aEvent)
{
switch (aEvent) {
case "tree-select":
this.onCommandUpdate();
break;
}
},
onCommandUpdate: function ()
{
var commands = ["cmd_properties", "cmd_rename", "cmd_copy",
"cmd_paste", "cmd_cut", "cmd_delete",
"cmd_setpersonaltoolbarfolder", "cmd_setnewbookmarkfolder",
"cmd_setnewsearchfolder"];
for (var i = 0; i < commands.length; ++i)
goUpdateCommand(commands[i]);
}
}
};
var newFolderRDFObserver = {
_newFolderURI: null,
onAssert: function (aDS, aSource, aProperty, aValue)
{
try {
var value = aValue.QueryInterface(Components.interfaces.nsIRDFResource);
if (aDS.URI == "rdf:bookmarks" && aProperty.Value == RDF_NS + "type" &&
value.Value == 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) { }
};
var ContentUtils = {
childByLocalName: function (aSelectedItem, aLocalName)
{
var temp = aSelectedItem.firstChild;
while (temp) {
if (temp.localName == aLocalName)
return temp;
temp = temp.nextSibling;
}
return null;
}
};

Просмотреть файл

@ -0,0 +1,38 @@
<!--
- The contents of this file are subject to the Mozilla 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/MPL/
-
- 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 Communicator.
-
- The Initial Developer of the Original Code is Netscape
- Communications Corp. Portions created by Netscape Communications
- Corp. are Copyright (C) 1999 Netscape Communications Corp. All
- Rights Reserved.
-
- Contributor(s):
- Ben Goodger <ben@netscape.com> (Original Author)
-->
<!ENTITY newBookmark.title "Add Bookmark">
<!ENTITY newbookmark.label "&brandShortName; will add a bookmark to this page.">
<!ENTITY name.label "Name:">
<!ENTITY name.accesskey "n">
<!ENTITY url.label "Location:">
<!ENTITY url.accesskey "l">
<!ENTITY button.createin.label "Create In &gt;&gt;">
<!ENTITY button.createin.accesskey "c">
<!ENTITY button.createin2.label "Create In &lt;&lt;">
<!ENTITY createin.label "Create in:">
<!ENTITY createin.accesskey "i">
<!ENTITY button.newfolder.label "New Folder...">
<!ENTITY button.newfolder.accesskey "w">
<!ENTITY alwayscreateinfolder.label "Don't show this dialog again">
<!ENTITY alwayscreateinfolder.accesskey "a">
<!ENTITY dontshowmessage.tooltip "When this option is selected, new Bookmarks will be added using the title provided by the page.">