зеркало из https://github.com/mozilla/pjs.git
New bookmarks window stuff, not yet part of build.
This commit is contained in:
Родитель
95defc7d0e
Коммит
530f85f222
|
@ -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 >>">
|
||||||
|
<!ENTITY button.createin.accesskey "c">
|
||||||
|
<!ENTITY button.createin2.label "Create In <<">
|
||||||
|
<!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.">
|
Загрузка…
Ссылка в новой задаче