mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-16 12:30:13 +01:00
2301 lines
80 KiB
JavaScript
2301 lines
80 KiB
JavaScript
|
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
|
# ***** BEGIN LICENSE BLOCK *****
|
||
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||
|
#
|
||
|
# 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.org code.
|
||
|
#
|
||
|
# The Initial Developer of the Original Code is
|
||
|
# Netscape Communications Corporation.
|
||
|
# Portions created by the Initial Developer are Copyright (C) 1998
|
||
|
# the Initial Developer. All Rights Reserved.
|
||
|
#
|
||
|
# Contributor(s):
|
||
|
# Ben Goodger <ben@netscape.com> (Original Author)
|
||
|
# Joey Minta <jminta@gmail.com>
|
||
|
#
|
||
|
# Alternatively, the contents of this file may be used under the terms of
|
||
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||
|
# of those above. If you wish to allow use of your version of this file only
|
||
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||
|
# use your version of this file under the terms of the MPL, indicate your
|
||
|
# decision by deleting the provisions above and replace them with the notice
|
||
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||
|
# the provisions above, a recipient may use your version of this file under
|
||
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
||
|
#
|
||
|
# ***** END LICENSE BLOCK *****
|
||
|
|
||
|
#ifdef XP_MACOSX
|
||
|
const ADD_BM_DIALOG_FEATURES = "centerscreen,chrome,dialog,resizable,modal";
|
||
|
#else
|
||
|
const ADD_BM_DIALOG_FEATURES = "centerscreen,chrome,dialog,resizable,dependent";
|
||
|
#endif
|
||
|
|
||
|
const kBATCH_LIMIT = 4;
|
||
|
|
||
|
var gNC_NS, gWEB_NS, gRDF_NS, gXUL_NS, gNC_NS_CMD;
|
||
|
|
||
|
// definition of the services frequently used for bookmarks
|
||
|
var kRDFContractID;
|
||
|
var kRDFSVCIID;
|
||
|
var kRDFRSCIID;
|
||
|
var kRDFLITIID;
|
||
|
var RDF;
|
||
|
|
||
|
var kRDFCContractID;
|
||
|
var kRDFCIID;
|
||
|
var RDFC;
|
||
|
|
||
|
var kRDFCUContractID;
|
||
|
var kRDFCUIID;
|
||
|
var RDFCU;
|
||
|
|
||
|
var BMDS;
|
||
|
var kBMSVCIID;
|
||
|
var BMSVC;
|
||
|
|
||
|
var kPREFContractID;
|
||
|
var kPREFIID;
|
||
|
var PREF;
|
||
|
|
||
|
var kSOUNDContractID;
|
||
|
var kSOUNDIID;
|
||
|
var SOUND;
|
||
|
|
||
|
var kWINDOWContractID;
|
||
|
var kWINDOWIID;
|
||
|
var WINDOWSVC;
|
||
|
|
||
|
var kDSContractID;
|
||
|
var kDSIID;
|
||
|
var DS;
|
||
|
|
||
|
var kIOContractID;
|
||
|
var kIOIID;
|
||
|
var IOSVC;
|
||
|
|
||
|
var kMICSUMContractID;
|
||
|
var kMICSUMIID;
|
||
|
var MICSUMSVC;
|
||
|
|
||
|
var gBmProperties;
|
||
|
var gBkmkTxnSvc;
|
||
|
|
||
|
// should be moved in a separate file
|
||
|
function initServices()
|
||
|
{
|
||
|
gNC_NS = "http://home.netscape.com/NC-rdf#";
|
||
|
gWEB_NS = "http://home.netscape.com/WEB-rdf#";
|
||
|
gRDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
|
||
|
gXUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||
|
gNC_NS_CMD = gNC_NS + "command?cmd=";
|
||
|
|
||
|
kRDFContractID = "@mozilla.org/rdf/rdf-service;1";
|
||
|
kRDFSVCIID = Components.interfaces.nsIRDFService;
|
||
|
kRDFRSCIID = Components.interfaces.nsIRDFResource;
|
||
|
kRDFLITIID = Components.interfaces.nsIRDFLiteral;
|
||
|
RDF = Components.classes[kRDFContractID].getService(kRDFSVCIID);
|
||
|
|
||
|
kRDFCContractID = "@mozilla.org/rdf/container;1";
|
||
|
kRDFCIID = Components.interfaces.nsIRDFContainer;
|
||
|
RDFC = Components.classes[kRDFCContractID].createInstance(kRDFCIID);
|
||
|
|
||
|
kRDFCUContractID = "@mozilla.org/rdf/container-utils;1";
|
||
|
kRDFCUIID = Components.interfaces.nsIRDFContainerUtils;
|
||
|
RDFCU = Components.classes[kRDFCUContractID].getService(kRDFCUIID);
|
||
|
|
||
|
kPREFContractID = "@mozilla.org/preferences-service;1";
|
||
|
kPREFIID = Components.interfaces.nsIPrefService;
|
||
|
PREF = Components.classes[kPREFContractID].getService(kPREFIID)
|
||
|
.getBranch(null);
|
||
|
|
||
|
kSOUNDContractID = "@mozilla.org/sound;1";
|
||
|
kSOUNDIID = Components.interfaces.nsISound;
|
||
|
SOUND = Components.classes[kSOUNDContractID].createInstance(kSOUNDIID);
|
||
|
|
||
|
kWINDOWContractID = "@mozilla.org/appshell/window-mediator;1";
|
||
|
kWINDOWIID = Components.interfaces.nsIWindowMediator;
|
||
|
WINDOWSVC = Components.classes[kWINDOWContractID].getService(kWINDOWIID);
|
||
|
|
||
|
kDSContractID = "@mozilla.org/widget/dragservice;1";
|
||
|
kDSIID = Components.interfaces.nsIDragService;
|
||
|
DS = Components.classes[kDSContractID].getService(kDSIID);
|
||
|
|
||
|
kIOContractID = "@mozilla.org/network/io-service;1";
|
||
|
kIOIID = Components.interfaces.nsIIOService;
|
||
|
IOSVC = Components.classes[kIOContractID].getService(kIOIID);
|
||
|
|
||
|
kMICSUMContractID = "@mozilla.org/microsummary/service;1";
|
||
|
kMICSUMIID = Components.interfaces.nsIMicrosummaryService;
|
||
|
MICSUMSVC = Components.classes[kMICSUMContractID].getService(kMICSUMIID);
|
||
|
|
||
|
gBmProperties = [RDF.GetResource(gNC_NS+"Name"),
|
||
|
RDF.GetResource(gNC_NS+"URL"),
|
||
|
RDF.GetResource(gNC_NS+"ShortcutURL"),
|
||
|
RDF.GetResource(gNC_NS+"Description"),
|
||
|
RDF.GetResource(gNC_NS+"WebPanel"),
|
||
|
RDF.GetResource(gNC_NS+"FeedURL"),
|
||
|
RDF.GetResource(gNC_NS+"MicsumGenURI"),
|
||
|
RDF.GetResource(gNC_NS+"MicsumExpiration"),
|
||
|
RDF.GetResource(gNC_NS+"GeneratedTitle")];
|
||
|
gBkmkTxnSvc = Components.classes["@mozilla.org/bookmarks/transactionmanager;1"]
|
||
|
.getService(Components.interfaces.nsIBookmarkTransactionManager);
|
||
|
}
|
||
|
|
||
|
function initBMService()
|
||
|
{
|
||
|
kBMSVCIID = Components.interfaces.nsIBookmarksService;
|
||
|
BMDS = RDF.GetDataSource("rdf:bookmarks");
|
||
|
BMSVC = BMDS.QueryInterface(kBMSVCIID);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* XXX - 24 Jul 04
|
||
|
* If you add a command that needs to run from the main browser window,
|
||
|
* it needs to be added to browser/base/content/browser-sets.inc as well!
|
||
|
*
|
||
|
* XXX - 04/16/01
|
||
|
* ACK! massive command name collision problems are causing big issues
|
||
|
* in getting this stuff to work in the Navigator window. For sanity's
|
||
|
* sake, we need to rename all the commands to be of the form cmd_bm_*
|
||
|
* otherwise there'll continue to be problems. For now, we're just
|
||
|
* renaming those that affect the personal toolbar (edit operations,
|
||
|
* which were clashing with the textfield controller)
|
||
|
*
|
||
|
* There are also several places that need to be updated if you need
|
||
|
* to change a command name.
|
||
|
* 1) the controller...
|
||
|
* - in bookmarksTree.xml if the command is tree-specifc
|
||
|
* - in bookmarksMenu.js if the command is DOM-specific
|
||
|
* - in bookmarks.js otherwise
|
||
|
* 2) the command nodes in the overlay or xul file
|
||
|
* 3) the command human-readable name key in bookmarks.properties
|
||
|
* 4) the function 'getCommands' in bookmarks.js
|
||
|
*/
|
||
|
|
||
|
var BookmarksCommand = {
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// 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, aAccessKey, aCommandName, aSelection)
|
||
|
{
|
||
|
var xulElement = document.createElementNS(gXUL_NS, "menuitem");
|
||
|
xulElement.setAttribute("cmd", aCommandName);
|
||
|
var cmd = "cmd_" + aCommandName.substring(gNC_NS_CMD.length);
|
||
|
xulElement.setAttribute("command", cmd);
|
||
|
xulElement.setAttribute("label", aDisplayName);
|
||
|
xulElement.setAttribute("accesskey", aAccessKey);
|
||
|
return xulElement;
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Fill a context menu popup with menuitems that are appropriate for the current
|
||
|
// selection.
|
||
|
createContextMenu: function (aEvent, aSelection, aDS)
|
||
|
{
|
||
|
if (aSelection == undefined) {
|
||
|
aEvent.preventDefault();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var popup = aEvent.target;
|
||
|
// clear out the old context menu contents (if any)
|
||
|
while (popup.hasChildNodes())
|
||
|
popup.removeChild(popup.firstChild);
|
||
|
|
||
|
var commonCommands = [];
|
||
|
for (var i = 0; i < aSelection.length; ++i) {
|
||
|
var commands = this.getCommands(aSelection.item[i], aSelection.parent[i], aDS);
|
||
|
if (!commands) {
|
||
|
aEvent.preventDefault();
|
||
|
return;
|
||
|
}
|
||
|
commands = this.flattenEnumerator(commands);
|
||
|
if (!commonCommands.length) commonCommands = commands;
|
||
|
commonCommands = this.findCommonNodes(commands, commonCommands);
|
||
|
}
|
||
|
|
||
|
if (!commonCommands.length) {
|
||
|
aEvent.preventDefault();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Now that we should have generated a list of commands that is valid
|
||
|
// for the entire selection, build a context menu.
|
||
|
for (i = 0; i < commonCommands.length; ++i) {
|
||
|
var currCommand = commonCommands[i].QueryInterface(kRDFRSCIID).Value;
|
||
|
var element = null;
|
||
|
if (currCommand != gNC_NS_CMD + "bm_separator") {
|
||
|
var commandName = this.getCommandName(currCommand);
|
||
|
var accessKey = this.getAccessKey(currCommand);
|
||
|
element = this.createMenuItem(commandName, accessKey, currCommand, aSelection);
|
||
|
}
|
||
|
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(gXUL_NS, "menuseparator");
|
||
|
}
|
||
|
if (element)
|
||
|
popup.appendChild(element);
|
||
|
}
|
||
|
|
||
|
if (popup.firstChild.getAttribute("command") == "cmd_bm_open")
|
||
|
popup.firstChild.setAttribute("default", "true");
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// 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.
|
||
|
getCommands: function (aNodeID, aParent, aDS)
|
||
|
{
|
||
|
var type = BookmarksUtils.resolveType(aNodeID, aDS);
|
||
|
if (!type)
|
||
|
return null;
|
||
|
|
||
|
var ptype = null;
|
||
|
aParent = (aParent != null) ? aParent : BMSVC.getParent(aNodeID);
|
||
|
if (aParent) {
|
||
|
ptype = BookmarksUtils.resolveType(aParent, aDS);
|
||
|
if (ptype == "Livemark") {
|
||
|
type = "LivemarkBookmark";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var commands = [];
|
||
|
// menu order:
|
||
|
//
|
||
|
// bm_open, bm_openfolder
|
||
|
// bm_openinnewwindow
|
||
|
// bm_openinnewtab
|
||
|
// ---------------------
|
||
|
// bm_newfolder
|
||
|
// ---------------------
|
||
|
// cut
|
||
|
// copy
|
||
|
// paste
|
||
|
// ---------------------
|
||
|
// delete
|
||
|
// ---------------------
|
||
|
// bm_refreshlivemark
|
||
|
// bm_refreshmicrosummary
|
||
|
// bm_sortbyname
|
||
|
// ---------------------
|
||
|
// bm_properties
|
||
|
switch (type) {
|
||
|
case "BookmarkSeparator":
|
||
|
commands = ["bm_newbookmark", "bm_newfolder", "bm_newseparator", "bm_separator",
|
||
|
"cut", "copy", "paste", "bm_separator",
|
||
|
"delete", "bm_separator",
|
||
|
"bm_sortbyname", "bm_separator",
|
||
|
"bm_properties"];
|
||
|
break;
|
||
|
case "Bookmark":
|
||
|
commands = ["bm_open", "bm_openinnewwindow", "bm_openinnewtab", "bm_separator",
|
||
|
"bm_newbookmark", "bm_newfolder", "bm_newseparator", "bm_separator",
|
||
|
"cut", "copy", "paste", "bm_separator",
|
||
|
"delete", "bm_separator",
|
||
|
"bm_sortbyname", "bm_separator",
|
||
|
"bm_properties"];
|
||
|
// If this bookmark has a microsummary, add a command for refreshing it
|
||
|
// right before the "sort by name" (bm_sortbyname) command.
|
||
|
if (MICSUMSVC.hasMicrosummary(aNodeID))
|
||
|
commands.splice(14, 0, "bm_refreshmicrosummary");
|
||
|
break;
|
||
|
case "Folder":
|
||
|
case "PersonalToolbarFolder":
|
||
|
commands = ["bm_openfolder", "bm_separator", "bm_newbookmark",
|
||
|
"bm_newfolder", "bm_newseparator", "bm_separator",
|
||
|
"cut", "copy", "paste", "bm_separator",
|
||
|
"delete", "bm_separator",
|
||
|
"bm_sortbyname", "bm_separator",
|
||
|
"bm_properties"];
|
||
|
break;
|
||
|
case "IEFavoriteFolder":
|
||
|
commands = ["bm_separator", "delete"];
|
||
|
break;
|
||
|
case "IEFavorite":
|
||
|
commands = ["bm_open", "bm_openinnewwindow", "bm_openinnewtab", "bm_separator",
|
||
|
"copy"];
|
||
|
break;
|
||
|
case "FileSystemObject":
|
||
|
commands = ["bm_open", "bm_openinnewwindow", "bm_openinnewtab", "bm_separator",
|
||
|
"copy"];
|
||
|
break;
|
||
|
case "Livemark":
|
||
|
commands = ["bm_openfolder", "bm_separator",
|
||
|
"cut", "copy", "bm_separator",
|
||
|
"delete", "bm_separator",
|
||
|
"bm_refreshlivemark", "bm_sortbyname", "bm_separator",
|
||
|
"bm_properties"];
|
||
|
break;
|
||
|
case "LivemarkBookmark":
|
||
|
commands = ["bm_open", "bm_openinnewwindow", "bm_openinnewtab", "bm_separator",
|
||
|
"copy"];
|
||
|
break;
|
||
|
case "ImmutableBookmark":
|
||
|
commands = ["bm_open", "bm_openinnewwindow", "bm_openinnewtab"];
|
||
|
break;
|
||
|
default:
|
||
|
commands = [];
|
||
|
}
|
||
|
|
||
|
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(gNC_NS_CMD.length);
|
||
|
return BookmarksUtils.getLocaleString ("cmd_" + cmdName);
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Retrieve the access key for a particular command. Used when
|
||
|
// manufacturing a UI to invoke commands.
|
||
|
getAccessKey: function (aCommand)
|
||
|
{
|
||
|
var cmdName = aCommand.substring(gNC_NS_CMD.length);
|
||
|
return BookmarksUtils.getLocaleString ("cmd_" + cmdName + "_accesskey");
|
||
|
},
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Execute a command with the given source and arguments
|
||
|
doBookmarksCommand: function (aSource, aCommand, aArgumentsArray)
|
||
|
{
|
||
|
var rCommand = RDF.GetResource(aCommand);
|
||
|
|
||
|
var kSuppArrayContractID = "@mozilla.org/supports-array;1";
|
||
|
var kSuppArrayIID = Components.interfaces.nsISupportsArray;
|
||
|
var sourcesArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
|
||
|
if (aSource) {
|
||
|
sourcesArray.AppendElement(aSource);
|
||
|
}
|
||
|
|
||
|
var argsArray = Components.classes[kSuppArrayContractID].createInstance(kSuppArrayIID);
|
||
|
var length = aArgumentsArray?aArgumentsArray.length:0;
|
||
|
for (var i = 0; i < length; ++i) {
|
||
|
var rArc = RDF.GetResource(aArgumentsArray[i].property);
|
||
|
argsArray.AppendElement(rArc);
|
||
|
var rValue = null;
|
||
|
if ("resource" in aArgumentsArray[i]) {
|
||
|
rValue = RDF.GetResource(aArgumentsArray[i].resource);
|
||
|
}
|
||
|
else
|
||
|
rValue = RDF.GetLiteral(aArgumentsArray[i].literal);
|
||
|
argsArray.AppendElement(rValue);
|
||
|
}
|
||
|
|
||
|
// Exec the command in the Bookmarks datasource.
|
||
|
BMDS.DoCommand(sourcesArray, rCommand, argsArray);
|
||
|
},
|
||
|
|
||
|
undoBookmarkTransaction: function ()
|
||
|
{
|
||
|
gBkmkTxnSvc.undo();
|
||
|
BookmarksUtils.refreshSearch();
|
||
|
BookmarksUtils.flushDataSource();
|
||
|
},
|
||
|
|
||
|
redoBookmarkTransaction: function ()
|
||
|
{
|
||
|
gBkmkTxnSvc.redo();
|
||
|
BookmarksUtils.refreshSearch();
|
||
|
BookmarksUtils.flushDataSource();
|
||
|
},
|
||
|
|
||
|
manageFolder: function (aSelection)
|
||
|
{
|
||
|
openDialog("chrome://browser/content/bookmarks/bookmarksManager.xul",
|
||
|
"", "chrome,all,dialog=no", aSelection.item[0].Value);
|
||
|
},
|
||
|
|
||
|
cutBookmark: function (aSelection)
|
||
|
{
|
||
|
this.copyBookmark(aSelection);
|
||
|
BookmarksUtils.removeAndCheckSelection("cut", aSelection);
|
||
|
},
|
||
|
|
||
|
copyBookmark: 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-string;1";
|
||
|
const kSuppWStringIID = Components.interfaces.nsISupportsString;
|
||
|
var bmstring = Components.classes[kSuppWStringContractID].createInstance(kSuppWStringIID);
|
||
|
var unicodestring = Components.classes[kSuppWStringContractID].createInstance(kSuppWStringIID);
|
||
|
var htmlstring = Components.classes[kSuppWStringContractID].createInstance(kSuppWStringIID);
|
||
|
|
||
|
var sBookmarkItem = ""; var sTextUnicode = ""; var sTextHTML = ""; var tmpBmItem = [];
|
||
|
for (var i = 0; i < aSelection.length; ++i) {
|
||
|
sBookmarkItem += aSelection.item[i].Value + "\n";
|
||
|
|
||
|
// save the selection property into text string that we will use later in paste function
|
||
|
// and in INSERT tranasactions
|
||
|
// (if the selection is folder or livemark save all childs property)
|
||
|
var aType = BookmarksUtils.resolveType(aSelection.item[i]);
|
||
|
if (aType == "Livemark") {
|
||
|
sBookmarkItem += "\n\n\n\n\n\n\n\n\n"; // don't change livemark properties
|
||
|
} else {
|
||
|
for (var j = 0; j < gBmProperties.length; ++j) {
|
||
|
var itemValue = BMDS.GetTarget(aSelection.item[i], gBmProperties[j], true);
|
||
|
if (itemValue)
|
||
|
sBookmarkItem += itemValue.QueryInterface(kRDFLITIID).Value + "\n";
|
||
|
else
|
||
|
sBookmarkItem += "\n";
|
||
|
}
|
||
|
}
|
||
|
var childCount = 1;
|
||
|
if (aType == "Folder" || aType == "Livemark") {
|
||
|
var propArray = [];
|
||
|
BookmarksUtils.getAllChildren(aSelection.item[i], propArray);
|
||
|
for (var k = 0; k < propArray.length; ++k) {
|
||
|
for (var j = 0; j < gBmProperties.length + 1; ++j) {
|
||
|
if (propArray[k][j])
|
||
|
sBookmarkItem += propArray[k][j].Value + "\n";
|
||
|
else
|
||
|
sBookmarkItem += "\n";
|
||
|
}
|
||
|
}
|
||
|
childCount += propArray.length;
|
||
|
}
|
||
|
tmpBmItem.push(childCount + "\n" + sBookmarkItem);
|
||
|
sBookmarkItem = "";
|
||
|
|
||
|
var url;
|
||
|
if (aType == "Livemark")
|
||
|
url = BookmarksUtils.getProperty(aSelection.item[i], gNC_NS+"FeedURL");
|
||
|
else
|
||
|
url = BookmarksUtils.getProperty(aSelection.item[i], gNC_NS+"URL");
|
||
|
|
||
|
var name = BookmarksUtils.getProperty(aSelection.item[i], gNC_NS+"Name");
|
||
|
|
||
|
sTextUnicode += url + "\n";
|
||
|
sTextHTML += "<A HREF=\"" + url + "\">" + name + "</A>";
|
||
|
}
|
||
|
sTextUnicode = sTextUnicode.replace(/\n$/,"");
|
||
|
|
||
|
// generate unique separator and combine the array to one string
|
||
|
var bmSeparator = "]-[", extrarSeparator = "@";
|
||
|
for (var i = 0; i < tmpBmItem.length; ++i) {
|
||
|
while (tmpBmItem[i].indexOf(bmSeparator)>-1)
|
||
|
bmSeparator += extrarSeparator;
|
||
|
}
|
||
|
for (var i = 0; i < tmpBmItem.length; ++i) {
|
||
|
sBookmarkItem += tmpBmItem[i] + bmSeparator;
|
||
|
}
|
||
|
// insert the separator to sBookmarkItem so we can extract it in pasteBookmark
|
||
|
sBookmarkItem = bmSeparator + "\n" + sBookmarkItem;
|
||
|
|
||
|
const kXferableContractID = "@mozilla.org/widget/transferable;1";
|
||
|
const kXferableIID = Components.interfaces.nsITransferable;
|
||
|
var xferable = Components.classes[kXferableContractID].createInstance(kXferableIID);
|
||
|
|
||
|
xferable.addDataFlavor("moz/bookmarkclipboarditem");
|
||
|
bmstring.data = sBookmarkItem;
|
||
|
xferable.setTransferData("moz/bookmarkclipboarditem", bmstring, sBookmarkItem.length*2);
|
||
|
|
||
|
xferable.addDataFlavor("text/html");
|
||
|
htmlstring.data = sTextHTML;
|
||
|
xferable.setTransferData("text/html", htmlstring, sTextHTML.length*2);
|
||
|
|
||
|
xferable.addDataFlavor("text/unicode");
|
||
|
unicodestring.data = sTextUnicode;
|
||
|
xferable.setTransferData("text/unicode", unicodestring, sTextUnicode.length*2);
|
||
|
|
||
|
const kClipboardContractID = "@mozilla.org/widget/clipboard;1";
|
||
|
const kClipboardIID = Components.interfaces.nsIClipboard;
|
||
|
var clipboard = Components.classes[kClipboardContractID].getService(kClipboardIID);
|
||
|
clipboard.setData(xferable, null, kClipboardIID.kGlobalClipboard);
|
||
|
},
|
||
|
|
||
|
pasteBookmark: function (aTarget)
|
||
|
{
|
||
|
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 items, name, url, childs, removedProps = [];
|
||
|
data = data.value.QueryInterface(Components.interfaces.nsISupportsString).data;
|
||
|
switch (flavour.value) {
|
||
|
case "moz/bookmarkclipboarditem":
|
||
|
var tmpItem = data.split("\n");
|
||
|
var sep = tmpItem.shift();
|
||
|
data = tmpItem.join("\n");
|
||
|
items = data.split(sep);
|
||
|
// since data are ended by separator, remove the last empty node
|
||
|
items.pop();
|
||
|
// convert propery from text string to array
|
||
|
var p = gBmProperties.length+1;
|
||
|
for (var i = 0; i < items.length; ++i) {
|
||
|
childs = items[i].split("\n");
|
||
|
childs.pop();
|
||
|
var childCount = childs.shift();
|
||
|
items[i] = RDF.GetResource(childs[0]);
|
||
|
var propArray = [];
|
||
|
for (var k = 0; k < childCount; ++k) {
|
||
|
for (var j = 1; j < p; ++j) {
|
||
|
var prop = childs[p*k+j];
|
||
|
if (prop)
|
||
|
propArray.push(RDF.GetLiteral(prop));
|
||
|
else
|
||
|
propArray.push(null);
|
||
|
}
|
||
|
}
|
||
|
removedProps.push(propArray);
|
||
|
}
|
||
|
break;
|
||
|
case "text/x-moz-url":
|
||
|
// there should be only one item in this case
|
||
|
var ix = data.indexOf("\n");
|
||
|
items = data.substring(0, ix != -1 ? ix : data.length);
|
||
|
name = data.substring(ix);
|
||
|
// XXX: we should infer the best charset
|
||
|
var createdBookmarkResource = BookmarksUtils.createBookmark(null, items, null, name, null);
|
||
|
items = [createdBookmarkResource];
|
||
|
break;
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var selection = {item: items, parent:Array(items.length), length: items.length, prop: removedProps};
|
||
|
BookmarksUtils.checkSelection(selection);
|
||
|
BookmarksUtils.insertAndCheckSelection("paste", selection, aTarget, -1);
|
||
|
},
|
||
|
|
||
|
deleteBookmark: function (aSelection)
|
||
|
{
|
||
|
// call checkSelection here to update the immutable and other
|
||
|
// flags on the selection; when new resources get created,
|
||
|
// they're temporarily not valid because they're not in a
|
||
|
// bookmark container. So, they can't be removed until that's
|
||
|
// fixed.
|
||
|
BookmarksUtils.checkSelection(aSelection);
|
||
|
BookmarksUtils.removeAndCheckSelection("delete", aSelection);
|
||
|
},
|
||
|
|
||
|
moveBookmark: function (aSelection)
|
||
|
{
|
||
|
var rv = { selectedFolder: null };
|
||
|
openDialog("chrome://browser/content/bookmarks/addBookmark.xul", "",
|
||
|
"centerscreen,chrome,modal=yes,dialog=yes,resizable=yes", null,
|
||
|
null, null, null, "selectFolder", rv);
|
||
|
if (!rv.target)
|
||
|
return;
|
||
|
BookmarksUtils.moveAndCheckSelection("move", aSelection, rv.target);
|
||
|
},
|
||
|
|
||
|
openBookmark: function (aSelection, aTargetBrowser, aDS)
|
||
|
{
|
||
|
if (!aTargetBrowser)
|
||
|
return;
|
||
|
|
||
|
// in this case, we can just use |aSelection.length| as "Open in Tabs"
|
||
|
// is only available when you are only selecting multiple bookmarks
|
||
|
// if you selected a folder of bookmarks, we check the number of tabs in
|
||
|
// openGroupBookmark()
|
||
|
if (aTargetBrowser == "tab" && !this._confirmOpenTabs(aSelection.length))
|
||
|
return;
|
||
|
|
||
|
for (var i=0; i<aSelection.length; ++i) {
|
||
|
var type = aSelection.type[i];
|
||
|
if (aTargetBrowser == "save") {
|
||
|
this.saveBookmark(aSelection.item[i].Value, aDS);
|
||
|
}
|
||
|
else if (type == "Bookmark" || type == "ImmutableBookmark") {
|
||
|
var webPanel = BMDS.GetTarget(aSelection.item[i],
|
||
|
RDF.GetResource(gNC_NS + "WebPanel"),
|
||
|
true);
|
||
|
if (webPanel && aTargetBrowser == "current")
|
||
|
this.openWebPanel(aSelection.item[i].Value, aDS);
|
||
|
else
|
||
|
this.openOneBookmark(aSelection.item[i].Value, aTargetBrowser, aDS);
|
||
|
}
|
||
|
else if (type == "Folder" || type == "PersonalToolbarFolder" || type == "Livemark")
|
||
|
this.openGroupBookmark(aSelection.item[i].Value, aTargetBrowser);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
openBookmarkProperties: function (aSelection)
|
||
|
{
|
||
|
// Bookmark Properties dialog is only ever opened with one selection
|
||
|
// (command is disabled otherwise)
|
||
|
var bookmark = aSelection.item[0].Value;
|
||
|
var value = {};
|
||
|
openDialog("chrome://browser/content/bookmarks/bookmarksProperties.xul", "", "centerscreen,chrome,modal,resizable=no", bookmark, value);
|
||
|
return value.ok;
|
||
|
},
|
||
|
|
||
|
// requires utilityOverlay.js if opening in new window for getTopWin()
|
||
|
openWebPanel: function(aResource, aDS)
|
||
|
{
|
||
|
var url = BookmarksUtils.getProperty(aResource, gNC_NS+"URL", aDS);
|
||
|
// Ignore "NC:" and empty urls.
|
||
|
if (url == "")
|
||
|
return;
|
||
|
var w = getTopWin();
|
||
|
if (!w) {
|
||
|
openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", url);
|
||
|
return;
|
||
|
}
|
||
|
w.openWebPanel(BookmarksUtils.getProperty(aResource, gNC_NS+"Name"), url);
|
||
|
},
|
||
|
|
||
|
// requires contentAreaUtils.js because it calls saveURL
|
||
|
saveBookmark: function(aResource, aDS)
|
||
|
{
|
||
|
var url = BookmarksUtils.getProperty(aResource, gNC_NS+"URL", aDS);
|
||
|
// Ignore "NC:" and empty urls.
|
||
|
if (url == "")
|
||
|
return;
|
||
|
var fileName = BookmarksUtils.getProperty(aResource, gNC_NS+"Name", aDS);
|
||
|
|
||
|
saveURL(url, fileName, null, true);
|
||
|
},
|
||
|
|
||
|
// requires utilityOverlay.js because it calls openUILinkIn
|
||
|
openOneBookmark: function (aURI, aTargetBrowser, aDS)
|
||
|
{
|
||
|
var url = BookmarksUtils.getProperty(aURI, gNC_NS+"URL", aDS);
|
||
|
// Ignore "NC:" and empty urls.
|
||
|
if (url == "")
|
||
|
return;
|
||
|
|
||
|
openUILinkIn(url, aTargetBrowser);
|
||
|
},
|
||
|
|
||
|
_confirmOpenTabs: function(numTabsToOpen)
|
||
|
{
|
||
|
var reallyOpen = true;
|
||
|
|
||
|
const kWarnOnOpenPref = "browser.tabs.warnOnOpen";
|
||
|
if (PREF.getBoolPref(kWarnOnOpenPref))
|
||
|
{
|
||
|
if (numTabsToOpen >= PREF.getIntPref("browser.tabs.maxOpenBeforeWarn"))
|
||
|
{
|
||
|
var promptService =
|
||
|
Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
|
||
|
getService(Components.interfaces.nsIPromptService);
|
||
|
|
||
|
// default to true: if it were false, we wouldn't get this far
|
||
|
var warnOnOpen = { value: true };
|
||
|
|
||
|
var messageKey = "tabs.openWarningMultipleBranded";
|
||
|
var openKey = "tabs.openButtonMultiple";
|
||
|
|
||
|
var buttonPressed = promptService.confirmEx(window,
|
||
|
BookmarksUtils.getLocaleString("tabs.openWarningTitle"),
|
||
|
BookmarksUtils.getLocaleString(messageKey,
|
||
|
[numTabsToOpen, BookmarksUtils._brandShortName]),
|
||
|
(promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0)
|
||
|
+ (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
|
||
|
BookmarksUtils.getLocaleString(openKey),
|
||
|
null, null,
|
||
|
BookmarksUtils.getLocaleString("tabs.openWarningPromptMeBranded",
|
||
|
[BookmarksUtils._brandShortName]),
|
||
|
warnOnOpen);
|
||
|
|
||
|
reallyOpen = (buttonPressed == 0);
|
||
|
// don't set the pref unless they press OK and it's false
|
||
|
if (reallyOpen && !warnOnOpen.value)
|
||
|
PREF.setBoolPref(kWarnOnOpenPref, false);
|
||
|
}
|
||
|
}
|
||
|
return reallyOpen;
|
||
|
},
|
||
|
|
||
|
openGroupBookmark: function (aURI, aTargetBrowser)
|
||
|
{
|
||
|
var w = getTopWin();
|
||
|
if (!w)
|
||
|
// no browser window is open, we have to open the group into a new window
|
||
|
aTargetBrowser = "window";
|
||
|
|
||
|
var resource = RDF.GetResource(aURI);
|
||
|
var urlArc = RDF.GetResource(gNC_NS+"URL");
|
||
|
RDFC.Init(BMDS, resource);
|
||
|
var containerChildren = RDFC.GetElements();
|
||
|
var numTabsToOpen = 0;
|
||
|
|
||
|
// we can't just use |RDFC.GetCount()| as that might include
|
||
|
// folders, separators, deleted bookmarks, etc.
|
||
|
while (containerChildren.hasMoreElements()) {
|
||
|
var res = containerChildren.getNext().QueryInterface(kRDFRSCIID);
|
||
|
var type = BookmarksUtils.resolveType(res);
|
||
|
// these are the types in getCommands() that support the
|
||
|
// "bm_openinnewwindow" and "bm_openinnewtab" commands
|
||
|
if (type == "Bookmark" || type == "LivemarkBookmark" ||
|
||
|
type == "ImmutableBookmark" || type == "IEFavorite" ||
|
||
|
type == "FileSystemObject")
|
||
|
numTabsToOpen++;
|
||
|
}
|
||
|
|
||
|
if (!this._confirmOpenTabs(numTabsToOpen))
|
||
|
return;
|
||
|
|
||
|
// counting the number of tabs to open modified the
|
||
|
// containerChildren enumerator, so we need to reset it.
|
||
|
containerChildren = RDFC.GetElements();
|
||
|
if (aTargetBrowser == "current" || aTargetBrowser == "tab") {
|
||
|
var browser = w.document.getElementById("content");
|
||
|
var tabPanels = browser.browsers;
|
||
|
var tabCount = tabPanels.length;
|
||
|
var doReplace = PREF.getBoolPref("browser.tabs.loadFolderAndReplace");
|
||
|
var loadInBackground = PREF.getBoolPref("browser.tabs.loadBookmarksInBackground");
|
||
|
var index0;
|
||
|
if (doReplace)
|
||
|
index0 = 0;
|
||
|
else {
|
||
|
for (index0=tabCount-1; index0>=0; --index0)
|
||
|
{
|
||
|
var tab = tabPanels[index0];
|
||
|
if (tab.webNavigation.currentURI.spec != "about:blank" ||
|
||
|
tab.webProgress.isLoadingDocument)
|
||
|
break;
|
||
|
}
|
||
|
++index0;
|
||
|
}
|
||
|
|
||
|
var index = index0;
|
||
|
while (containerChildren.hasMoreElements()) {
|
||
|
var res = containerChildren.getNext().QueryInterface(kRDFRSCIID);
|
||
|
var target = BMDS.GetTarget(res, urlArc, true);
|
||
|
if (target) {
|
||
|
var uri = target.QueryInterface(kRDFLITIID).Value;
|
||
|
if (index < tabCount)
|
||
|
tabPanels[index].loadURI(uri);
|
||
|
else {
|
||
|
// This is not a modal sub-action of a given tab/document within a window
|
||
|
// since opening a bookmarks group replaces all existing tabs in the window,
|
||
|
// closing extras. If this ever changes to be augmentative, this code will
|
||
|
// have to change to probably just use <tabbrowser>.loadTabs() which figures
|
||
|
// out whether or not owner should be set.
|
||
|
browser.addTab(uri);
|
||
|
}
|
||
|
++index;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If the bookmark group was completely invalid, just bail.
|
||
|
if (index == index0)
|
||
|
return;
|
||
|
|
||
|
// focus the first tab if prefs say to
|
||
|
if (!loadInBackground || doReplace) {
|
||
|
// Select the first tab in the group.
|
||
|
// Set newly selected tab after quick timeout, otherwise hideous focus problems
|
||
|
// can occur because new presshell is not ready to handle events
|
||
|
function selectNewForegroundTab(browser, tab) {
|
||
|
browser.selectedTab = tab;
|
||
|
}
|
||
|
var tabs = browser.mTabContainer.childNodes;
|
||
|
setTimeout(selectNewForegroundTab, 0, browser, tabs[index0]);
|
||
|
}
|
||
|
|
||
|
// Close any remaining open tabs that are left over.
|
||
|
// (Always skipped when we append tabs)
|
||
|
for (var i = tabCount-1; i >= index; --i)
|
||
|
browser.removeTab(tabs[i]);
|
||
|
|
||
|
// and focus the content
|
||
|
w.content.focus();
|
||
|
|
||
|
} else if (aTargetBrowser == "window") {
|
||
|
var URIs = [];
|
||
|
|
||
|
while (containerChildren.hasMoreElements()) {
|
||
|
var res = containerChildren.getNext().QueryInterface(kRDFRSCIID);
|
||
|
var target = BMDS.GetTarget(res, urlArc, true);
|
||
|
if (target)
|
||
|
URIs.push(target.QueryInterface(kRDFLITIID).Value);
|
||
|
}
|
||
|
|
||
|
openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", URIs.join("|"));
|
||
|
}
|
||
|
},
|
||
|
|
||
|
createNewBookmark: function (aTarget)
|
||
|
{
|
||
|
var name = BookmarksUtils.getLocaleString("ile_newbookmark");
|
||
|
var resource = BMSVC.createBookmark(name, "", "", "", "", null);
|
||
|
this.createNewResource(resource, aTarget, "newbookmark");
|
||
|
},
|
||
|
|
||
|
createNewLivemark: function (aTarget)
|
||
|
{
|
||
|
var name = BookmarksUtils.getLocaleString("ile_newlivemark");
|
||
|
var resource = BMSVC.createLivemark(name, "", "", null);
|
||
|
this.createNewResource(resource, aTarget, "newlivemark");
|
||
|
},
|
||
|
|
||
|
createNewFolder: function (aTarget)
|
||
|
{
|
||
|
var name = BookmarksUtils.getLocaleString("ile_newfolder");
|
||
|
var resource = BMSVC.createFolder(name);
|
||
|
this.createNewResource(resource, aTarget, "newfolder");
|
||
|
// temporary hack...
|
||
|
return resource;
|
||
|
},
|
||
|
|
||
|
createNewSeparator: function (aTarget)
|
||
|
{
|
||
|
var resource = BMSVC.createSeparator();
|
||
|
this.createNewResource(resource, aTarget, "newseparator");
|
||
|
},
|
||
|
|
||
|
createNewResource: function(aResource, aTarget, aTxnType)
|
||
|
{
|
||
|
var selection = BookmarksUtils.getSelectionFromResource(aResource, aTarget.parent);
|
||
|
var ok = BookmarksUtils.insertAndCheckSelection(aTxnType, selection, aTarget, -1);
|
||
|
if (ok && aTxnType != "newseparator") {
|
||
|
ok = this.openBookmarkProperties(selection);
|
||
|
if (!ok)
|
||
|
BookmarksCommand.deleteBookmark(selection);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
importBookmarks: function ()
|
||
|
{
|
||
|
// XXX: ifdef it to be non-modal (non-"sheet") on mac (see bug 259039)
|
||
|
var features = "modal,centerscreen,chrome,resizable=no";
|
||
|
window.fromFile = false;
|
||
|
window.openDialog("chrome://browser/content/migration/migration.xul", "migration", features, "bookmarks");
|
||
|
if(window.fromFile)
|
||
|
{
|
||
|
this.importBookmarksFromFile();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
importBookmarksFromFile: function ()
|
||
|
{
|
||
|
///transaction...
|
||
|
try {
|
||
|
const kFilePickerContractID = "@mozilla.org/filepicker;1";
|
||
|
const kFilePickerIID = Components.interfaces.nsIFilePicker;
|
||
|
const kFilePicker = Components.classes[kFilePickerContractID].createInstance(kFilePickerIID);
|
||
|
|
||
|
const kTitle = BookmarksUtils.getLocaleString("SelectImport");
|
||
|
kFilePicker.init(window, kTitle, kFilePickerIID["modeOpen"]);
|
||
|
kFilePicker.appendFilters(kFilePickerIID.filterHTML | kFilePickerIID.filterAll);
|
||
|
var fileName;
|
||
|
if (kFilePicker.show() != kFilePickerIID.returnCancel) {
|
||
|
fileName = kFilePicker.file.path;
|
||
|
if (!fileName) return;
|
||
|
}
|
||
|
else return;
|
||
|
}
|
||
|
catch (e) {
|
||
|
return;
|
||
|
}
|
||
|
rTarget = RDF.GetResource("NC:BookmarksRoot");
|
||
|
RDFC.Init(BMDS, rTarget);
|
||
|
var countBefore = parseInt(BookmarksUtils.getProperty(rTarget, gRDF_NS+"nextVal"));
|
||
|
var args = [{ property: gNC_NS+"URL", literal: fileName}];
|
||
|
this.doBookmarksCommand(rTarget, gNC_NS_CMD+"import", args);
|
||
|
var countAfter = parseInt(BookmarksUtils.getProperty(rTarget, gRDF_NS+"nextVal"));
|
||
|
|
||
|
if (countAfter - countBefore > 1)
|
||
|
gBkmkTxnSvc.startBatch();
|
||
|
for (var index = countBefore; index < countAfter; index++) {
|
||
|
var nChildArc = RDFCU.IndexToOrdinalResource(index);
|
||
|
var rChild = BMDS.GetTarget(rTarget, nChildArc, true);
|
||
|
gBkmkTxnSvc.createAndCommitTxn(gBkmkTxnSvc.IMPORT, "IMPORT", rChild, index,
|
||
|
rTarget, 0, null);
|
||
|
}
|
||
|
if (countAfter - countBefore > 1)
|
||
|
gBkmkTxnSvc.endBatch();
|
||
|
|
||
|
BookmarksUtils.flushDataSource();
|
||
|
},
|
||
|
|
||
|
exportBookmarks: function ()
|
||
|
{
|
||
|
try {
|
||
|
const kFilePickerContractID = "@mozilla.org/filepicker;1";
|
||
|
const kFilePickerIID = Components.interfaces.nsIFilePicker;
|
||
|
const kFilePicker = Components.classes[kFilePickerContractID].createInstance(kFilePickerIID);
|
||
|
|
||
|
const kTitle = BookmarksUtils.getLocaleString("EnterExport");
|
||
|
kFilePicker.init(window, kTitle, kFilePickerIID["modeSave"]);
|
||
|
kFilePicker.appendFilters(kFilePickerIID.filterHTML | kFilePickerIID.filterAll);
|
||
|
kFilePicker.defaultString = "bookmarks.html";
|
||
|
var fileName;
|
||
|
if (kFilePicker.show() != kFilePickerIID.returnCancel) {
|
||
|
fileName = kFilePicker.file.path;
|
||
|
if (!fileName) return;
|
||
|
}
|
||
|
else return;
|
||
|
|
||
|
var file = Components.classes["@mozilla.org/file/local;1"]
|
||
|
.createInstance(Components.interfaces.nsILocalFile);
|
||
|
if (!file)
|
||
|
return;
|
||
|
file.initWithPath(fileName);
|
||
|
if (!file.exists()) {
|
||
|
file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
|
||
|
}
|
||
|
}
|
||
|
catch (e) {
|
||
|
return;
|
||
|
}
|
||
|
var selection = RDF.GetResource("NC:BookmarksRoot");
|
||
|
var args = [{ property: gNC_NS+"URL", literal: fileName}];
|
||
|
this.doBookmarksCommand(selection, gNC_NS_CMD+"export", args);
|
||
|
},
|
||
|
|
||
|
refreshLivemark: function (aSelection)
|
||
|
{
|
||
|
var exp = RDF.GetResource(gNC_NS+"LivemarkExpiration");
|
||
|
for (var i = 0; i < aSelection.length; i++) {
|
||
|
rsrc = RDF.GetResource(aSelection.item[i].Value);
|
||
|
oldtgt = BMDS.GetTarget(rsrc, exp, true);
|
||
|
if (oldtgt) {
|
||
|
BMDS.Unassert(rsrc, exp, oldtgt);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
refreshMicrosummary: function (aSelection)
|
||
|
{
|
||
|
for (var i = 0; i < aSelection.length; i++) {
|
||
|
rsrc = RDF.GetResource(aSelection.item[i].Value);
|
||
|
MICSUMSVC.refreshMicrosummary(rsrc);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
sortByName: function (aSelection)
|
||
|
{
|
||
|
// do the real sorting in a timeout, to make sure that
|
||
|
// if we sort from a menu that the menu gets torn down
|
||
|
// before we sort. the template builder really doesn't
|
||
|
// like it if we move things around; the menu code also
|
||
|
// doesn't like it if we move the menuparent while a
|
||
|
// popup is open.
|
||
|
setTimeout(function () { BookmarksCommand.realSortByName(aSelection); }, 0);
|
||
|
},
|
||
|
|
||
|
realSortByName: function (aSelection)
|
||
|
{
|
||
|
var theFolder;
|
||
|
|
||
|
if (aSelection.length != 1)
|
||
|
return;
|
||
|
|
||
|
var selType = BookmarksUtils.resolveType(aSelection.item[0]);
|
||
|
if (selType == "Folder" || selType == "Bookmark" ||
|
||
|
selType == "PersonalToolbarFolder" || selType == "Livemark")
|
||
|
{
|
||
|
theFolder = aSelection.parent[0];
|
||
|
} else {
|
||
|
// we're not going to try to sort ImmutableBookmark siblings or
|
||
|
// any other such thing, since it'll probably just get us into
|
||
|
// trouble
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var toSort = [];
|
||
|
RDFC.Init(BMDS, theFolder);
|
||
|
var folderContents = RDFC.GetElements();
|
||
|
while (folderContents.hasMoreElements()) {
|
||
|
var rsrc = folderContents.getNext().QueryInterface(kRDFRSCIID);
|
||
|
var rtype = BookmarksUtils.resolveType(rsrc);
|
||
|
if (rtype == "BookmarkSeparator")
|
||
|
continue;
|
||
|
toSort.push(rsrc);
|
||
|
}
|
||
|
|
||
|
const kName = RDF.GetResource(gNC_NS+"Name");
|
||
|
|
||
|
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
|
||
|
.getService(Components.interfaces.nsILocaleService);
|
||
|
var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
|
||
|
.getService(Components.interfaces.nsICollationFactory);
|
||
|
var collation = collationFactory.CreateCollation(localeService.getApplicationLocale());
|
||
|
|
||
|
toSort.sort (function (a, b) {
|
||
|
var atype = BookmarksUtils.resolveType(a);
|
||
|
var btype = BookmarksUtils.resolveType(b);
|
||
|
|
||
|
var aisfolder = (atype == "Folder") || (atype == "PersonalToolbarFolder");
|
||
|
var bisfolder = (btype == "Folder") || (btype == "PersonalToolbarFolder");
|
||
|
|
||
|
// folders above bookmarks
|
||
|
if (aisfolder && !bisfolder)
|
||
|
return -1;
|
||
|
if (bisfolder && !aisfolder)
|
||
|
return 1;
|
||
|
|
||
|
// then sort by name
|
||
|
var aname = BMDS.GetTarget(a, kName, true).QueryInterface(kRDFLITIID).Value;
|
||
|
var bname = BMDS.GetTarget(b, kName, true).QueryInterface(kRDFLITIID).Value;
|
||
|
|
||
|
return collation.compareString(0, aname, bname);
|
||
|
});
|
||
|
|
||
|
// we now have the resources here sorted by name
|
||
|
BMDS.beginUpdateBatch();
|
||
|
|
||
|
RDFC.Init(BMDS, theFolder);
|
||
|
|
||
|
// remove existing elements
|
||
|
var folderContents = RDFC.GetElements();
|
||
|
while (folderContents.hasMoreElements()) {
|
||
|
RDFC.RemoveElement (folderContents.getNext(), false);
|
||
|
}
|
||
|
|
||
|
// and add our elements back
|
||
|
for (var i = 0; i < toSort.length; i++) {
|
||
|
RDFC.InsertElementAt (toSort[i], i+1, true);
|
||
|
}
|
||
|
|
||
|
BMDS.endUpdateBatch();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Command handling & Updating.
|
||
|
var BookmarksController = {
|
||
|
|
||
|
supportsCommand: function (aCommand)
|
||
|
{
|
||
|
var isCommandSupported;
|
||
|
switch(aCommand) {
|
||
|
case "cmd_undo":
|
||
|
case "cmd_redo":
|
||
|
case "cmd_bm_undo":
|
||
|
case "cmd_bm_redo":
|
||
|
case "cmd_cut":
|
||
|
case "cmd_copy":
|
||
|
case "cmd_paste":
|
||
|
case "cmd_delete":
|
||
|
case "cmd_selectAll":
|
||
|
case "cmd_bm_open":
|
||
|
case "cmd_bm_openinnewwindow":
|
||
|
case "cmd_bm_openinnewtab":
|
||
|
case "cmd_bm_openfolder":
|
||
|
case "cmd_bm_managefolder":
|
||
|
case "cmd_bm_newbookmark":
|
||
|
case "cmd_bm_newlivemark":
|
||
|
case "cmd_bm_newfolder":
|
||
|
case "cmd_bm_newseparator":
|
||
|
case "cmd_bm_properties":
|
||
|
case "cmd_bm_rename":
|
||
|
case "cmd_bm_setnewbookmarkfolder":
|
||
|
case "cmd_bm_setpersonaltoolbarfolder":
|
||
|
case "cmd_bm_setnewsearchfolder":
|
||
|
case "cmd_bm_import":
|
||
|
case "cmd_bm_export":
|
||
|
case "cmd_bm_movebookmark":
|
||
|
case "cmd_bm_refreshlivemark":
|
||
|
case "cmd_bm_refreshmicrosummary":
|
||
|
case "cmd_bm_sortbyname":
|
||
|
isCommandSupported = true;
|
||
|
break;
|
||
|
default:
|
||
|
isCommandSupported = false;
|
||
|
}
|
||
|
//if (!isCommandSupported)
|
||
|
// dump("Bookmark command '"+aCommand+"' is not supported!\n");
|
||
|
return isCommandSupported;
|
||
|
},
|
||
|
|
||
|
isCommandEnabled: function (aCommand, aSelection, aTarget)
|
||
|
{
|
||
|
var item0, type0, junk, parent0, ptype0;
|
||
|
var length = 0;
|
||
|
if (aSelection && aSelection.length != 0) {
|
||
|
length = aSelection.length;
|
||
|
item0 = aSelection.item[0].Value;
|
||
|
type0 = aSelection.type[0];
|
||
|
parent0 = (aSelection.parent[0] != null) ? aSelection.parent[0] : BMSVC.getParent(aSelection.item[0]);
|
||
|
ptype0 = BookmarksUtils.resolveType(parent0);
|
||
|
}
|
||
|
var i;
|
||
|
|
||
|
switch(aCommand) {
|
||
|
case "cmd_undo":
|
||
|
case "cmd_bm_undo":
|
||
|
return gBkmkTxnSvc.canUndo();
|
||
|
case "cmd_redo":
|
||
|
case "cmd_bm_redo":
|
||
|
return gBkmkTxnSvc.canRedo();
|
||
|
case "cmd_paste":
|
||
|
if (ptype0 == "Livemark" || (aTarget && !BookmarksUtils.isValidTargetContainer(aTarget.parent)))
|
||
|
return false;
|
||
|
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-cstring;1";
|
||
|
const kSuppStringIID = Components.interfaces.nsISupportsCString;
|
||
|
|
||
|
var flavours = ["moz/bookmarkclipboarditem", "text/x-moz-url"];
|
||
|
for (i = 0; i < flavours.length; ++i) {
|
||
|
const kSuppString = Components.classes[kSuppStringContractID].createInstance(kSuppStringIID);
|
||
|
kSuppString.data = flavours[i];
|
||
|
flavourArray.AppendElement(kSuppString);
|
||
|
}
|
||
|
var hasFlavours = clipboard.hasDataMatchingFlavors(flavourArray, kClipboardIID.kGlobalClipboard);
|
||
|
return hasFlavours;
|
||
|
case "cmd_copy":
|
||
|
return length > 0;
|
||
|
case "cmd_cut":
|
||
|
case "cmd_delete":
|
||
|
return length > 0 && !aSelection.containsImmutable && ptype0 != "Livemark" && !aSelection.containsPTF;
|
||
|
case "cmd_selectAll":
|
||
|
return true;
|
||
|
case "cmd_bm_open":
|
||
|
case "cmd_bm_managefolder":
|
||
|
return length == 1;
|
||
|
case "cmd_bm_openinnewwindow":
|
||
|
case "cmd_bm_openinnewtab":
|
||
|
return true;
|
||
|
case "cmd_bm_openfolder":
|
||
|
for (i=0; i<length; ++i) {
|
||
|
if (aSelection.type[i] == "ImmutableBookmark" ||
|
||
|
aSelection.type[i] == "ImmutableFolder" ||
|
||
|
aSelection.type[i] == "Bookmark" ||
|
||
|
aSelection.type[i] == "BookmarkSeparator")
|
||
|
return false;
|
||
|
RDFC.Init(BMDS, aSelection.item[i]);
|
||
|
var children = RDFC.GetElements();
|
||
|
while (children.hasMoreElements()) {
|
||
|
var childType = BookmarksUtils.resolveType(children.getNext());
|
||
|
if (childType == "Bookmark" || childType == "LivemarkBookmark")
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
case "cmd_bm_import":
|
||
|
case "cmd_bm_export":
|
||
|
return true;
|
||
|
case "cmd_bm_newbookmark":
|
||
|
case "cmd_bm_newlivemark":
|
||
|
case "cmd_bm_newfolder":
|
||
|
case "cmd_bm_newseparator":
|
||
|
return (ptype0 != "Livemark" && ((type0 == "PersonalToolbarFolder") ||
|
||
|
(aTarget && BookmarksUtils.isValidTargetContainer(aTarget.parent))));
|
||
|
case "cmd_bm_properties":
|
||
|
case "cmd_bm_rename":
|
||
|
if (length != 1 ||
|
||
|
aSelection.item[0].Value == "NC:BookmarksRoot" ||
|
||
|
ptype0 == "Livemark")
|
||
|
return false;
|
||
|
return true;
|
||
|
case "cmd_bm_setpersonaltoolbarfolder":
|
||
|
if (length != 1 || type0 == "Livemark")
|
||
|
return false;
|
||
|
return item0 != BMSVC.getBookmarksToolbarFolder().Value &&
|
||
|
item0 != "NC:BookmarksRoot" && type0 == "Folder";
|
||
|
case "cmd_bm_movebookmark":
|
||
|
return length > 0 && !aSelection.containsImmutable && ptype0 != "Livemark";
|
||
|
case "cmd_bm_refreshlivemark":
|
||
|
for (i=0; i<length; ++i) {
|
||
|
if (aSelection.type[i] != "Livemark")
|
||
|
return false;
|
||
|
}
|
||
|
return length > 0;
|
||
|
case "cmd_bm_refreshmicrosummary":
|
||
|
for (i=0; i<length; ++i) {
|
||
|
if (!MICSUMSVC.hasMicrosummary(aSelection.item[i]))
|
||
|
return false;
|
||
|
}
|
||
|
return length > 0;
|
||
|
case "cmd_bm_sortbyname":
|
||
|
if (length == 1 && (aSelection.type[0] == "Folder" ||
|
||
|
aSelection.type[0] == "Bookmark" ||
|
||
|
aSelection.type[0] == "PersonalToolbarFolder" ||
|
||
|
aSelection.type[0] == "Livemark"))
|
||
|
return true;
|
||
|
return false;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
doCommand: function (aCommand, aSelection, aTarget, aDS)
|
||
|
{
|
||
|
var resource0, type0, realTarget;
|
||
|
if (aSelection && aSelection.length == 1) {
|
||
|
resource0 = aSelection.item[0];
|
||
|
type0 = aSelection.type[0];
|
||
|
}
|
||
|
|
||
|
if (type0 == "PersonalToolbarFolder" && aTarget == null)
|
||
|
realTarget = { parent: resource0, index: -1 };
|
||
|
else
|
||
|
realTarget = aTarget;
|
||
|
|
||
|
switch (aCommand) {
|
||
|
case "cmd_undo":
|
||
|
case "cmd_bm_undo":
|
||
|
BookmarksCommand.undoBookmarkTransaction();
|
||
|
break;
|
||
|
case "cmd_redo":
|
||
|
case "cmd_bm_redo":
|
||
|
BookmarksCommand.redoBookmarkTransaction();
|
||
|
break;
|
||
|
case "cmd_bm_open":
|
||
|
BookmarksCommand.openBookmark(aSelection, "current", aDS);
|
||
|
break;
|
||
|
case "cmd_bm_openinnewwindow":
|
||
|
BookmarksCommand.openBookmark(aSelection, "window", aDS);
|
||
|
break;
|
||
|
case "cmd_bm_openinnewtab":
|
||
|
BookmarksCommand.openBookmark(aSelection, "tab", aDS);
|
||
|
break;
|
||
|
case "cmd_bm_openfolder":
|
||
|
BookmarksCommand.openBookmark(aSelection, "current", aDS);
|
||
|
break;
|
||
|
case "cmd_bm_managefolder":
|
||
|
BookmarksCommand.manageFolder(aSelection);
|
||
|
break;
|
||
|
case "cmd_bm_setnewbookmarkfolder":
|
||
|
case "cmd_bm_setpersonaltoolbarfolder":
|
||
|
case "cmd_bm_setnewsearchfolder":
|
||
|
BookmarksCommand.doBookmarksCommand(aSelection.item[0], gNC_NS_CMD+aCommand.substring("cmd_bm_".length), []);
|
||
|
break;
|
||
|
case "cmd_bm_rename":
|
||
|
case "cmd_bm_properties":
|
||
|
junk = BookmarksCommand.openBookmarkProperties(aSelection);
|
||
|
break;
|
||
|
case "cmd_cut":
|
||
|
BookmarksCommand.cutBookmark(aSelection);
|
||
|
break;
|
||
|
case "cmd_copy":
|
||
|
BookmarksCommand.copyBookmark(aSelection);
|
||
|
break;
|
||
|
case "cmd_paste":
|
||
|
BookmarksCommand.pasteBookmark(realTarget);
|
||
|
break;
|
||
|
case "cmd_delete":
|
||
|
BookmarksCommand.deleteBookmark(aSelection);
|
||
|
break;
|
||
|
case "cmd_bm_movebookmark":
|
||
|
BookmarksCommand.moveBookmark(aSelection);
|
||
|
break;
|
||
|
case "cmd_bm_newbookmark":
|
||
|
BookmarksCommand.createNewBookmark(realTarget);
|
||
|
break;
|
||
|
case "cmd_bm_newlivemark":
|
||
|
BookmarksCommand.createNewLivemark(realTarget);
|
||
|
break;
|
||
|
case "cmd_bm_newfolder":
|
||
|
BookmarksCommand.createNewFolder(realTarget);
|
||
|
break;
|
||
|
case "cmd_bm_newseparator":
|
||
|
BookmarksCommand.createNewSeparator(realTarget);
|
||
|
break;
|
||
|
case "cmd_bm_import":
|
||
|
BookmarksCommand.importBookmarks();
|
||
|
break;
|
||
|
case "cmd_bm_export":
|
||
|
BookmarksCommand.exportBookmarks();
|
||
|
break;
|
||
|
case "cmd_bm_refreshlivemark":
|
||
|
BookmarksCommand.refreshLivemark(aSelection);
|
||
|
break;
|
||
|
case "cmd_bm_refreshmicrosummary":
|
||
|
BookmarksCommand.refreshMicrosummary(aSelection);
|
||
|
break;
|
||
|
case "cmd_bm_sortbyname":
|
||
|
BookmarksCommand.sortByName(aSelection);
|
||
|
break;
|
||
|
default:
|
||
|
dump("Bookmark command "+aCommand+" not handled!\n");
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
onCommandUpdate: function (aSelection, aTarget)
|
||
|
{
|
||
|
var commands = ["cmd_bm_newbookmark", "cmd_bm_newlivemark", "cmd_bm_newfolder", "cmd_bm_newseparator",
|
||
|
"cmd_undo", "cmd_redo", "cmd_bm_properties", "cmd_bm_rename",
|
||
|
"cmd_copy", "cmd_paste", "cmd_cut", "cmd_delete",
|
||
|
"cmd_bm_setpersonaltoolbarfolder", "cmd_bm_movebookmark",
|
||
|
"cmd_bm_openfolder", "cmd_bm_managefolder", "cmd_bm_refreshlivemark",
|
||
|
"cmd_bm_refreshmicrosummary", "cmd_bm_sortbyname"];
|
||
|
for (var i = 0; i < commands.length; ++i) {
|
||
|
var enabled = this.isCommandEnabled(commands[i], aSelection, aTarget);
|
||
|
var commandNode = document.getElementById(commands[i]);
|
||
|
if (commandNode) {
|
||
|
if (enabled)
|
||
|
commandNode.removeAttribute("disabled");
|
||
|
else
|
||
|
commandNode.setAttribute("disabled", "true");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function CommandArrayEnumerator (aCommandArray)
|
||
|
{
|
||
|
this._inner = [];
|
||
|
for (var i = 0; i < aCommandArray.length; ++i)
|
||
|
this._inner.push(RDF.GetResource(gNC_NS_CMD + aCommandArray[i]));
|
||
|
|
||
|
this._index = 0;
|
||
|
}
|
||
|
|
||
|
CommandArrayEnumerator.prototype = {
|
||
|
getNext: function ()
|
||
|
{
|
||
|
return this._inner[this._index];
|
||
|
},
|
||
|
|
||
|
hasMoreElements: function ()
|
||
|
{
|
||
|
return this._index < this._inner.length;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var BookmarksUtils = {
|
||
|
|
||
|
DROP_BEFORE: Components.interfaces.nsITreeView.DROP_BEFORE,
|
||
|
DROP_ON : Components.interfaces.nsITreeView.DROP_ON,
|
||
|
DROP_AFTER : Components.interfaces.nsITreeView.DROP_AFTER,
|
||
|
|
||
|
_bundle : null,
|
||
|
_brandShortName: null,
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
// returns a property from chrome://browser/locale/bookmarks/bookmarks.properties
|
||
|
getLocaleString: function (aStringKey, aReplaceString)
|
||
|
{
|
||
|
if (!this._bundle) {
|
||
|
// for those who would xblify Bookmarks.js, there is a need to create string bundle
|
||
|
// manually instead of using <xul:stringbundle/> see bug 63370 for details
|
||
|
var LOCALESVC = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
|
||
|
.getService(Components.interfaces.nsILocaleService);
|
||
|
var BUNDLESVC = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||
|
.getService(Components.interfaces.nsIStringBundleService);
|
||
|
var bookmarksBundle = "chrome://browser/locale/bookmarks/bookmarks.properties";
|
||
|
this._bundle = BUNDLESVC.createBundle(bookmarksBundle, LOCALESVC.getApplicationLocale());
|
||
|
var brandBundle = "chrome://branding/locale/brand.properties";
|
||
|
this._brandShortName = BUNDLESVC.createBundle(brandBundle, LOCALESVC.getApplicationLocale())
|
||
|
.GetStringFromName("brandShortName");
|
||
|
}
|
||
|
|
||
|
var bundle;
|
||
|
try {
|
||
|
if (!aReplaceString)
|
||
|
bundle = this._bundle.GetStringFromName(aStringKey);
|
||
|
else if (typeof(aReplaceString) == "string")
|
||
|
bundle = this._bundle.formatStringFromName(aStringKey, [aReplaceString], 1);
|
||
|
else
|
||
|
bundle = this._bundle.formatStringFromName(aStringKey, aReplaceString, aReplaceString.length);
|
||
|
} catch (e) {
|
||
|
dump("Bookmark bundle "+aStringKey+" not found!\n");
|
||
|
bundle = "";
|
||
|
}
|
||
|
|
||
|
bundle = bundle.replace(/%brandShortName%/, this._brandShortName);
|
||
|
return bundle;
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// returns the literal targeted by the URI aArcURI for a resource or uri
|
||
|
getProperty: function (aInput, aArcURI, aDS)
|
||
|
{
|
||
|
var node;
|
||
|
var arc = RDF.GetResource(aArcURI);
|
||
|
if (typeof(aInput) == "string")
|
||
|
aInput = RDF.GetResource(aInput);
|
||
|
if (!aDS)
|
||
|
node = BMDS.GetTarget(aInput, arc, true);
|
||
|
else
|
||
|
node = aDS .GetTarget(aInput, arc, true);
|
||
|
try {
|
||
|
return node.QueryInterface(kRDFRSCIID).Value;
|
||
|
}
|
||
|
catch (e) {
|
||
|
return node? node.QueryInterface(kRDFLITIID).Value : "";
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Determine the rdf:type property for the given resource.
|
||
|
resolveType: function (aResource, aDS)
|
||
|
{
|
||
|
var type = this.getProperty(aResource, gRDF_NS+"type", aDS);
|
||
|
if (type != "")
|
||
|
type = type.split("#")[1];
|
||
|
if (type == "Folder") {
|
||
|
if (aResource == BMSVC.getBookmarksToolbarFolder())
|
||
|
type = "PersonalToolbarFolder";
|
||
|
}
|
||
|
// Treat microsummary bookmarks like regular bookmarks, since they behave
|
||
|
// like regular bookmarks in almost every regard.
|
||
|
if (type == "MicsumBookmark")
|
||
|
type = "Bookmark";
|
||
|
|
||
|
if (type == "") {
|
||
|
// we're not sure what type it is. figure out if it's a container.
|
||
|
var child = this.getProperty(aResource, gNC_NS+"child", aDS);
|
||
|
if (child || RDFCU.IsContainer(aDS?aDS:BMDS, RDF.GetResource(aResource)))
|
||
|
return "ImmutableFolder";
|
||
|
|
||
|
// not a container; make sure it has at least a URL
|
||
|
if (this.getProperty(aResource, gNC_NS+"URL") != null)
|
||
|
return "ImmutableBookmark";
|
||
|
}
|
||
|
|
||
|
return type;
|
||
|
},
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Caches frequently used informations about the selection
|
||
|
checkSelection: function (aSelection)
|
||
|
{
|
||
|
if (aSelection.length == 0)
|
||
|
return;
|
||
|
|
||
|
aSelection.type = new Array(aSelection.length);
|
||
|
aSelection.isContainer = new Array(aSelection.length);
|
||
|
aSelection.containsPTF = false;
|
||
|
aSelection.containsImmutable = false;
|
||
|
var index, item, parent, type, ptype, protocol, isContainer, isImmutable;
|
||
|
for (var i=0; i<aSelection.length; ++i) {
|
||
|
item = aSelection.item[i];
|
||
|
parent = aSelection.parent[i];
|
||
|
type = BookmarksUtils.resolveType(item);
|
||
|
protocol = item.Value.split(":")[0];
|
||
|
isContainer = RDFCU.IsContainer(BMDS, item) ||
|
||
|
protocol == "find" || protocol == "file";
|
||
|
isImmutable = false;
|
||
|
if (item.Value == "NC:BookmarksRoot") {
|
||
|
isImmutable = true;
|
||
|
}
|
||
|
else if (type != "Bookmark" && type != "BookmarkSeparator" &&
|
||
|
type != "Folder" && type != "PersonalToolbarFolder" &&
|
||
|
type != "Livemark")
|
||
|
isImmutable = true;
|
||
|
else if (parent) {
|
||
|
var ptype = BookmarksUtils.resolveType(parent);
|
||
|
if (ptype == "Livemark")
|
||
|
isImmutable = true;
|
||
|
var parentProtocol = parent.Value.split(":")[0];
|
||
|
if (parentProtocol == "find" || parentProtocol == "file")
|
||
|
aSelection.parent[i] = null;
|
||
|
}
|
||
|
if (isImmutable)
|
||
|
aSelection.containsImmutable = true;
|
||
|
|
||
|
aSelection.type [i] = type;
|
||
|
aSelection.isContainer[i] = isContainer;
|
||
|
}
|
||
|
if (this.isContainerChildOrSelf(BMSVC.getBookmarksToolbarFolder(), aSelection))
|
||
|
aSelection.containsPTF = true;
|
||
|
},
|
||
|
|
||
|
isSelectionValidForInsertion: function (aSelection, aTarget)
|
||
|
{
|
||
|
return BookmarksUtils.isValidTargetContainer(aTarget.parent, aSelection)
|
||
|
},
|
||
|
|
||
|
isSelectionValidForDeletion: function (aSelection)
|
||
|
{
|
||
|
return !aSelection.containsImmutable && !aSelection.containsPTF;
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Returns true is aContainer is a member or a child of the selection
|
||
|
isContainerChildOrSelf: function (aContainer, aSelection)
|
||
|
{
|
||
|
var folder = aContainer;
|
||
|
do {
|
||
|
for (var i=0; i<aSelection.length; ++i) {
|
||
|
if (aSelection.isContainer[i] && aSelection.item[i].Value == folder.Value)
|
||
|
return true;
|
||
|
}
|
||
|
folder = BMSVC.getParent(folder);
|
||
|
if (!folder)
|
||
|
return false; // sanity check
|
||
|
} while (folder.Value != "NC:BookmarksRoot")
|
||
|
return false;
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Returns true if aSelection can be inserted in aFolder
|
||
|
isValidTargetContainer: function (aFolder, aSelection)
|
||
|
{
|
||
|
if (!aFolder)
|
||
|
return false;
|
||
|
if (aFolder.Value == "NC:BookmarksTopRoot")
|
||
|
return false;
|
||
|
if (aFolder.Value == "NC:BookmarksRoot")
|
||
|
return true;
|
||
|
|
||
|
// don't insert items in an invalid container
|
||
|
// 'file:' and 'find:' items have a 'Bookmark' type
|
||
|
var type = BookmarksUtils.resolveType(aFolder);
|
||
|
if (type != "Folder" && type != "PersonalToolbarFolder")
|
||
|
return false;
|
||
|
|
||
|
// bail if we just check the container
|
||
|
if (!aSelection)
|
||
|
return true;
|
||
|
|
||
|
// check that the selected folder is not the selected item nor its child
|
||
|
if (this.isContainerChildOrSelf(aFolder, aSelection))
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
removeAndCheckSelection: function (aAction, aSelection)
|
||
|
{
|
||
|
var isValid = BookmarksUtils.isSelectionValidForDeletion(aSelection);
|
||
|
if (!isValid) {
|
||
|
SOUND.beep();
|
||
|
return false;
|
||
|
}
|
||
|
this.removeSelection(aAction, aSelection);
|
||
|
BookmarksUtils.flushDataSource();
|
||
|
BookmarksUtils.refreshSearch();
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
removeSelection: function (aAction, aSelection)
|
||
|
{
|
||
|
if (aSelection.length > 1)
|
||
|
gBkmkTxnSvc.startBatch();
|
||
|
if (aSelection.length > kBATCH_LIMIT && aAction != "move")
|
||
|
BMDS.beginUpdateBatch();
|
||
|
|
||
|
for (var i = 0; i < aSelection.length; ++i) {
|
||
|
// try to put back aSelection.parent[i] if it's null, so we can delete after searching
|
||
|
if (aSelection.parent[i] == null)
|
||
|
aSelection.parent[i] = BMDS.getParent(aSelection.item[i]);
|
||
|
|
||
|
if (aSelection.parent[i]) {
|
||
|
RDFC.Init(BMDS, aSelection.parent[i]);
|
||
|
|
||
|
// save the selection property into array that is used later in
|
||
|
// when performing the REMOVE transaction
|
||
|
// (if the selection is folder save all childs property)
|
||
|
var propArray;
|
||
|
if (aAction != "move") {
|
||
|
propArray = new Array(gBmProperties.length);
|
||
|
var aType = BookmarksUtils.resolveType(aSelection.item[i]);
|
||
|
if (aType != "Livemark") {// don't change livemark properties
|
||
|
for (var j = 0; j < gBmProperties.length; ++j) {
|
||
|
var oldValue = BMDS.GetTarget(aSelection.item[i], gBmProperties[j], true);
|
||
|
if (oldValue)
|
||
|
propArray[j] = oldValue.QueryInterface(kRDFLITIID);
|
||
|
}
|
||
|
}
|
||
|
if (aType == "Folder" || aType == "Livemark")
|
||
|
BookmarksUtils.getAllChildren(aSelection.item[i], propArray);
|
||
|
}
|
||
|
|
||
|
var proplength = propArray ? propArray.length : 0;
|
||
|
gBkmkTxnSvc.createAndCommitTxn(gBkmkTxnSvc.REMOVE, aAction,
|
||
|
aSelection.item[i],
|
||
|
RDFC.IndexOf(aSelection.item[i]),
|
||
|
aSelection.parent[i],
|
||
|
proplength, propArray);
|
||
|
}
|
||
|
}
|
||
|
if (aSelection.length > 1)
|
||
|
gBkmkTxnSvc.endBatch();
|
||
|
if (aSelection.length > kBATCH_LIMIT && aAction != "move")
|
||
|
BMDS.beginUpdateBatch();
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
// this recursive function return array of all childrens properties for given folder
|
||
|
getAllChildren: function (folder, propArray)
|
||
|
{
|
||
|
var container = Components.classes[kRDFCContractID].createInstance(kRDFCIID);
|
||
|
container.Init(BMDS, folder);
|
||
|
var children = container.GetElements();
|
||
|
while (children.hasMoreElements()){
|
||
|
var child = children.getNext() ;
|
||
|
if (child instanceof Components.interfaces.nsIRDFResource){
|
||
|
var aType = BookmarksUtils.resolveType(child);
|
||
|
var childResource = child.QueryInterface(kRDFRSCIID);
|
||
|
var props = new Array(gBmProperties.length);
|
||
|
// don't change livemark properties
|
||
|
if (aType != "Livemark") {
|
||
|
for (var j = 0; j < gBmProperties.length; ++j) {
|
||
|
var oldValue = BMDS.GetTarget(childResource, gBmProperties[j], true);
|
||
|
if (oldValue)
|
||
|
props[(j)] = oldValue.QueryInterface(kRDFLITIID);
|
||
|
}
|
||
|
}
|
||
|
propArray.push(props);
|
||
|
if (aType == "Folder" || aType == "Livemark")
|
||
|
BookmarksUtils.getAllChildren(child, propArray);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// if we are in search mode i.e. "find:" is in ref attribute we refresh the Search
|
||
|
refreshSearch: function ()
|
||
|
{
|
||
|
var bmTree, bmView = document.getElementById("bookmarks-view");
|
||
|
if (bmView) bmTree = bmView.tree;
|
||
|
else return;
|
||
|
var aRef = bmTree.getAttribute("ref");
|
||
|
var aProtocol = aRef.split(":")[0];
|
||
|
if (aProtocol == "find"){
|
||
|
bmTree.setAttribute("ref", "");
|
||
|
bmTree.setAttribute("ref", aRef);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
insertAndCheckSelection: function (aAction, aSelection, aTarget, aTargetIndex)
|
||
|
{
|
||
|
var isValid = BookmarksUtils.isSelectionValidForInsertion(aSelection, aTarget);
|
||
|
if (!isValid) {
|
||
|
SOUND.beep();
|
||
|
return false;
|
||
|
}
|
||
|
this.insertSelection(aAction, aSelection, aTarget, aTargetIndex);
|
||
|
BookmarksUtils.flushDataSource();
|
||
|
BookmarksUtils.refreshSearch();
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
insertSelection: function (aAction, aSelection, aTarget, aTargetIndex)
|
||
|
{
|
||
|
var item, removedProps;
|
||
|
var index = aTarget.index;
|
||
|
var brokenIndex = aTarget.index;
|
||
|
|
||
|
if (aSelection.length > 1)
|
||
|
gBkmkTxnSvc.startBatch();
|
||
|
if (aSelection.length > kBATCH_LIMIT && aAction != "move")
|
||
|
BMDS.beginUpdateBatch();
|
||
|
|
||
|
for (var i=0; i<aSelection.length; ++i) {
|
||
|
var rSource = aSelection.item[i];
|
||
|
if (BMSVC.isBookmarkedResource(rSource))
|
||
|
rSource = BMSVC.cloneResource(rSource);
|
||
|
item = rSource;
|
||
|
// we only have aSelection.prop if insertSelection call by paste action we don't use it for move
|
||
|
removedProps = aSelection.prop ? aSelection.prop[i] : null;
|
||
|
// Broken Insert Code attempts to always insert items in the
|
||
|
// right place (i.e. after the selected item). However, because
|
||
|
// of RDF Container suckyness, this code gets very confused, due
|
||
|
// to rdf container indexes not matching up to number of items,
|
||
|
// and because we can't trust GetCount to return a real count.
|
||
|
// The -1 is there to handle inserting into the persontal toolbar
|
||
|
// folder via right-click on the PTF.
|
||
|
if (aTarget.index == -1) {
|
||
|
index = -1;
|
||
|
} else {
|
||
|
#ifdef BROKEN_INSERT_CODE
|
||
|
if (aTargetIndex == -1)
|
||
|
index = (++brokenIndex);
|
||
|
else
|
||
|
index = (brokenIndex++);
|
||
|
#else
|
||
|
index = brokenIndex++;
|
||
|
#endif
|
||
|
}
|
||
|
var proplength = removedProps ? removedProps.length : 0;
|
||
|
gBkmkTxnSvc.createAndCommitTxn(gBkmkTxnSvc.INSERT, aAction, item, index,
|
||
|
aTarget.parent, proplength, removedProps);
|
||
|
}
|
||
|
if (aSelection.length > 1)
|
||
|
gBkmkTxnSvc.endBatch();
|
||
|
if (aSelection.length > kBATCH_LIMIT && aAction != "move")
|
||
|
BMDS.endUpdateBatch();
|
||
|
},
|
||
|
|
||
|
moveAndCheckSelection: function (aAction, aSelection, aTarget)
|
||
|
{
|
||
|
var isValid = BookmarksUtils.isSelectionValidForDeletion(aSelection) &&
|
||
|
BookmarksUtils.isSelectionValidForInsertion(aSelection, aTarget);
|
||
|
if (!isValid) {
|
||
|
SOUND.beep();
|
||
|
return false;
|
||
|
}
|
||
|
this.moveSelection(aAction, aSelection, aTarget);
|
||
|
BookmarksUtils.flushDataSource();
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
moveSelection: function (aAction, aSelection, aTarget)
|
||
|
{
|
||
|
if (aSelection.length > kBATCH_LIMIT)
|
||
|
BMDS.beginUpdateBatch();
|
||
|
|
||
|
gBkmkTxnSvc.startBatch();
|
||
|
BookmarksUtils.removeSelection("move", aSelection);
|
||
|
BookmarksUtils.insertSelection("move", aSelection, aTarget);
|
||
|
gBkmkTxnSvc.endBatch();
|
||
|
if (aSelection.length > kBATCH_LIMIT)
|
||
|
BMDS.endUpdateBatch();
|
||
|
},
|
||
|
|
||
|
// returns true if this selection should be copied instead of moved,
|
||
|
// if a move was originally requested
|
||
|
shouldCopySelection: function (aAction, aSelection)
|
||
|
{
|
||
|
for (var i = 0; i < aSelection.length; i++) {
|
||
|
var parentType = BookmarksUtils.resolveType(aSelection.parent[i]);
|
||
|
if (aSelection.type[i] == "ImmutableBookmark" ||
|
||
|
aSelection.type[i] == "ImmutableFolder" ||
|
||
|
aSelection.parent[i] == null ||
|
||
|
(aSelection.type[i] == "Bookmark" && parentType == "Livemark"))
|
||
|
{
|
||
|
return true; // if any of these are found
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
},
|
||
|
|
||
|
getXferDataFromSelection: function (aSelection)
|
||
|
{
|
||
|
if (aSelection.length == 0)
|
||
|
return null;
|
||
|
var dataSet = new TransferDataSet();
|
||
|
var data, item, itemUrl, itemName, parent, name;
|
||
|
for (var i=0; i<aSelection.length; ++i) {
|
||
|
data = new TransferData();
|
||
|
item = aSelection.item[i].Value;
|
||
|
itemUrl = this.getProperty(item, gNC_NS+"URL");
|
||
|
itemName = this.getProperty(item, gNC_NS+"Name");
|
||
|
parent = aSelection.parent[i].Value;
|
||
|
data.addDataForFlavour("moz/rdfitem", item+"\n"+(parent?parent:""));
|
||
|
data.addDataForFlavour("text/x-moz-url", itemUrl+"\n"+itemName);
|
||
|
data.addDataForFlavour("text/html", "<A HREF='"+itemUrl+"'>"+itemName+"</A>");
|
||
|
data.addDataForFlavour("text/unicode", itemUrl);
|
||
|
dataSet.push(data);
|
||
|
}
|
||
|
return dataSet;
|
||
|
},
|
||
|
|
||
|
getSelectionFromXferData: function (aDragSession)
|
||
|
{
|
||
|
var selection = {};
|
||
|
selection.item = [];
|
||
|
selection.parent = [];
|
||
|
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
|
||
|
.createInstance(Components.interfaces.nsITransferable);
|
||
|
trans.addDataFlavor("moz/rdfitem");
|
||
|
trans.addDataFlavor("text/x-moz-url");
|
||
|
trans.addDataFlavor("text/unicode");
|
||
|
var uri, extra, rSource, rParent, parent;
|
||
|
for (var i = 0; i < aDragSession.numDropItems; ++i) {
|
||
|
var bestFlavour = {}, dataObj = {}, len = {};
|
||
|
aDragSession.getData(trans, i);
|
||
|
trans.getAnyTransferData(bestFlavour, dataObj, len);
|
||
|
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
|
||
|
if (!dataObj)
|
||
|
continue;
|
||
|
dataObj = dataObj.data.substring(0, len.value).split("\n");
|
||
|
uri = dataObj[0];
|
||
|
if (dataObj.length > 1 && dataObj[1] != "")
|
||
|
extra = dataObj[1];
|
||
|
else
|
||
|
extra = null;
|
||
|
switch (bestFlavour.value) {
|
||
|
case "moz/rdfitem":
|
||
|
rSource = RDF.GetResource(uri);
|
||
|
parent = extra;
|
||
|
break;
|
||
|
case "text/x-moz-url":
|
||
|
case "text/unicode":
|
||
|
rSource = BookmarksUtils.createBookmark(null, uri, null, extra, null);
|
||
|
parent = null;
|
||
|
break;
|
||
|
}
|
||
|
selection.item.push(rSource);
|
||
|
if (parent)
|
||
|
rParent = RDF.GetResource(parent);
|
||
|
else
|
||
|
rParent = null;
|
||
|
selection.parent.push(rParent);
|
||
|
}
|
||
|
selection.length = selection.item.length;
|
||
|
BookmarksUtils.checkSelection(selection);
|
||
|
return selection;
|
||
|
},
|
||
|
|
||
|
getTargetFromFolder: function(aResource)
|
||
|
{
|
||
|
var index = parseInt(this.getProperty(aResource, gRDF_NS+"nextVal"));
|
||
|
if (isNaN(index))
|
||
|
return {parent: null, index: -1};
|
||
|
else
|
||
|
return {parent: aResource, index: index};
|
||
|
},
|
||
|
|
||
|
getSelectionFromResource: function (aItem, aParent)
|
||
|
{
|
||
|
var selection = {};
|
||
|
selection.length = 1;
|
||
|
selection.item = [aItem ];
|
||
|
selection.parent = [aParent];
|
||
|
this.checkSelection(selection);
|
||
|
return selection;
|
||
|
},
|
||
|
|
||
|
createBookmark: function (aName, aURL, aCharSet, aDefaultName)
|
||
|
{
|
||
|
if (!aName) {
|
||
|
// look up in the history ds to retrieve the name
|
||
|
var rSource = RDF.GetResource(aURL);
|
||
|
var HISTDS = RDF.GetDataSource("rdf:history");
|
||
|
var nameArc = RDF.GetResource(gNC_NS+"Name");
|
||
|
var rName = HISTDS.GetTarget(rSource, nameArc, true);
|
||
|
aName = rName ? rName.QueryInterface(kRDFLITIID).Value : aDefaultName;
|
||
|
if (!aName)
|
||
|
aName = aURL;
|
||
|
}
|
||
|
if (!aCharSet) {
|
||
|
var fw = document.commandDispatcher.focusedWindow;
|
||
|
if (fw)
|
||
|
aCharSet = fw.document.characterSet;
|
||
|
}
|
||
|
return BMSVC.createBookmark(aName, aURL, null, null, aCharSet, null);
|
||
|
},
|
||
|
|
||
|
createLivemark: function (aName, aURL, aFeedURL, aDefaultName)
|
||
|
{
|
||
|
if (!aName) {
|
||
|
// look up in the history ds to retrieve the name
|
||
|
var rSource = RDF.GetResource(aURL);
|
||
|
var HISTDS = RDF.GetDataSource("rdf:history");
|
||
|
var nameArc = RDF.GetResource(gNC_NS+"Name");
|
||
|
var rName = HISTDS.GetTarget(rSource, nameArc, true);
|
||
|
aName = rName ? rName.QueryInterface(kRDFLITIID).Value : aDefaultName;
|
||
|
if (!aName)
|
||
|
aName = aURL;
|
||
|
}
|
||
|
return BMSVC.createLivemark(aName, aURL, aFeedURL, null);
|
||
|
},
|
||
|
|
||
|
flushDataSource: function ()
|
||
|
{
|
||
|
var remoteDS = BMDS.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
|
||
|
setTimeout(function () {remoteDS.Flush()}, 100);
|
||
|
},
|
||
|
|
||
|
addBookmark: function (aURL, aTitle, aCharset, aIsWebPanel, aDescription)
|
||
|
{
|
||
|
var dArgs = {
|
||
|
name: aTitle,
|
||
|
url: aURL,
|
||
|
charset: aCharset,
|
||
|
bWebPanel: aIsWebPanel,
|
||
|
description: aDescription
|
||
|
}
|
||
|
openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
|
||
|
ADD_BM_DIALOG_FEATURES, dArgs);
|
||
|
},
|
||
|
|
||
|
addLivemark: function (aURL, aFeedURL, aTitle, aDescription)
|
||
|
{
|
||
|
var dArgs = {
|
||
|
name: aTitle,
|
||
|
url: aURL,
|
||
|
bWebPanel: false,
|
||
|
feedURL: aFeedURL,
|
||
|
description: aDescription
|
||
|
};
|
||
|
try {
|
||
|
var toolbarFolderURI = BMDS.getBookmarksToolbarFolder().Value;
|
||
|
dArgs.folderURI = toolbarFolderURI;
|
||
|
}
|
||
|
catch (e) {
|
||
|
}
|
||
|
openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
|
||
|
ADD_BM_DIALOG_FEATURES, dArgs);
|
||
|
},
|
||
|
|
||
|
getDescriptionFromDocument: function (aDocument) {
|
||
|
var metaElements = aDocument.getElementsByTagName('META');
|
||
|
for (var m = 0; m < metaElements.length; m++) {
|
||
|
if (metaElements[m].name.toLowerCase() == 'description' || metaElements[m].httpEquiv.toLowerCase() == 'description')
|
||
|
return metaElements[m].content;
|
||
|
}
|
||
|
return '';
|
||
|
},
|
||
|
|
||
|
loadFavIcon: function (aURL, aFavIconURL) {
|
||
|
if (!RDF || !BMSVC)
|
||
|
return;
|
||
|
|
||
|
var urlLiteral = RDF.GetLiteral(aURL);
|
||
|
// don't do anything if this URI isn't bookmarked
|
||
|
var bmResources = BMSVC.GetSources(RDF.GetResource(gNC_NS+"URL"), urlLiteral, true);
|
||
|
var toUpdate = 0;
|
||
|
|
||
|
while (bmResources.hasMoreElements()) {
|
||
|
var bmResource = bmResources.getNext();
|
||
|
|
||
|
// don't flag this as needing update if it already has a data: icon url set
|
||
|
var oldIcon = BMDS.GetTarget(bmResource, RDF.GetResource(gNC_NS+"Icon"), true);
|
||
|
if (oldIcon && (oldIcon.QueryInterface(kRDFLITIID).Value.substring(0,5) == "data:"))
|
||
|
continue;
|
||
|
|
||
|
toUpdate++;
|
||
|
}
|
||
|
|
||
|
if (toUpdate == 0)
|
||
|
return;
|
||
|
|
||
|
var chan = IOSVC.newChannel(aFavIconURL, null, null);
|
||
|
var listener = new bookmarksFavIconLoadListener (aURL, aFavIconURL, chan);
|
||
|
chan.notificationCallbacks = listener;
|
||
|
chan.asyncOpen(listener, null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var BookmarkEditMenuTxnListener =
|
||
|
{
|
||
|
didDo: function (aTxmgr, aTxn)
|
||
|
{
|
||
|
this.updateMenuItem(aTxmgr, aTxn);
|
||
|
},
|
||
|
|
||
|
didUndo: function (aTxmgr, aTxn)
|
||
|
{
|
||
|
this.updateMenuItem(aTxmgr, aTxn);
|
||
|
},
|
||
|
|
||
|
didRedo: function (aTxmgr, aTxn)
|
||
|
{
|
||
|
this.updateMenuItem(aTxmgr, aTxn);
|
||
|
},
|
||
|
|
||
|
didMerge : function (aTxmgr, aTxn) {},
|
||
|
didBeginBatch : function (aTxmgr, aTxn) {},
|
||
|
didEndBatch : function (aTxmgr, aTxn) {
|
||
|
this.updateMenuItem(aTxmgr, aTxn);
|
||
|
},
|
||
|
willDo : function (aTxmgr, aTxn) {},
|
||
|
willUndo : function (aTxmgr, aTxn) {},
|
||
|
willRedo : function (aTxmgr, aTxn) {},
|
||
|
willMerge : function (aTxmgr, aTxn) {},
|
||
|
willBeginBatch : function (aTxmgr, aTxn) {},
|
||
|
willEndBatch : function (aTxmgr, aTxn) {},
|
||
|
|
||
|
updateMenuItem: function bkmkMenuListenerUpdate(aTxmgr, aTxn) {
|
||
|
var node, transactionNumber, transactionList, transactionLabel, action, item;
|
||
|
node = document.getElementById("cmd_undo");
|
||
|
transactionNumber = aTxmgr.numberOfUndoItems;
|
||
|
dump("N UNDO: "+transactionNumber+"\n");
|
||
|
if (transactionNumber == 0) {
|
||
|
transactionLabel = BookmarksUtils.getLocaleString("cmd_bm_undo");
|
||
|
} else {
|
||
|
transactionList = aTxmgr.getUndoList();
|
||
|
if (!transactionList.itemIsBatch(transactionNumber-1)) {
|
||
|
item = transactionList.getItem(transactionNumber-1);
|
||
|
action = item.wrappedJSObject.action;
|
||
|
} else {
|
||
|
var childList = transactionList.getChildListForItem(transactionNumber-1);
|
||
|
item = childList.getItem(0);
|
||
|
action = item.wrappedJSObject.action;
|
||
|
}
|
||
|
transactionLabel = BookmarksUtils.getLocaleString("cmd_bm_"+action+"_undo");
|
||
|
}
|
||
|
node.setAttribute("label", transactionLabel);
|
||
|
|
||
|
node = document.getElementById("cmd_redo");
|
||
|
transactionNumber = aTxmgr.numberOfRedoItems;
|
||
|
dump("N REDO: "+transactionNumber+"\n");
|
||
|
if (transactionNumber == 0) {
|
||
|
transactionLabel = BookmarksUtils.getLocaleString("cmd_bm_redo");
|
||
|
} else {
|
||
|
transactionList = aTxmgr.getRedoList();
|
||
|
if (!transactionList.itemIsBatch(transactionNumber-1)) {
|
||
|
item = transactionList.getItem(transactionNumber-1);
|
||
|
action = item.wrappedJSObject.action;
|
||
|
} else {
|
||
|
var childList = transactionList.getChildListForItem(transactionNumber-1);
|
||
|
item = childList.getItem(0);
|
||
|
action = item.wrappedJSObject.action;
|
||
|
}
|
||
|
transactionLabel = BookmarksUtils.getLocaleString("cmd_bm_"+action+"_redo");
|
||
|
}
|
||
|
node.setAttribute("label", transactionLabel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// favicon loaders
|
||
|
|
||
|
function bookmarksFavIconLoadListener(uri, faviconurl, channel) {
|
||
|
this.mURI = uri;
|
||
|
this.mFavIconURL = faviconurl;
|
||
|
this.mCountRead = 0;
|
||
|
this.mChannel = channel;
|
||
|
}
|
||
|
|
||
|
bookmarksFavIconLoadListener.prototype = {
|
||
|
mURI : null,
|
||
|
mFavIconURL : null,
|
||
|
mCountRead : null,
|
||
|
mChannel : null,
|
||
|
mBytes : Array(),
|
||
|
mStream : null,
|
||
|
|
||
|
QueryInterface: function (iid) {
|
||
|
if (!iid.equals(Components.interfaces.nsISupports) &&
|
||
|
!iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
|
||
|
!iid.equals(Components.interfaces.nsIRequestObserver) &&
|
||
|
!iid.equals(Components.interfaces.nsIChannelEventSink) &&
|
||
|
!iid.equals(Components.interfaces.nsIProgressEventSink) && // see below
|
||
|
!iid.equals(Components.interfaces.nsIStreamListener)) {
|
||
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
// nsIInterfaceRequestor
|
||
|
getInterface: function (iid) {
|
||
|
try {
|
||
|
return this.QueryInterface(iid);
|
||
|
} catch (e) {
|
||
|
throw Components.results.NS_NOINTERFACE;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// nsIRequestObserver
|
||
|
onStartRequest : function (aRequest, aContext) {
|
||
|
this.mStream = Components.classes['@mozilla.org/binaryinputstream;1'].createInstance(Components.interfaces.nsIBinaryInputStream);
|
||
|
},
|
||
|
|
||
|
onStopRequest : function (aRequest, aContext, aStatusCode) {
|
||
|
var httpChannel = this.mChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||
|
if ((httpChannel && httpChannel.requestSucceeded) &&
|
||
|
Components.isSuccessCode(aStatusCode) &&
|
||
|
this.mCountRead > 0)
|
||
|
{
|
||
|
var dataurl;
|
||
|
// XXX - arbitrary size beyond which we won't store a favicon. This is /extremely/
|
||
|
// generous, and is probably too high.
|
||
|
if (this.mCountRead > 16384) {
|
||
|
dataurl = "data:"; // hack meaning "pretend this doesn't exist"
|
||
|
} else {
|
||
|
// get us a mime type for this
|
||
|
var mimeType = null;
|
||
|
|
||
|
const nsICategoryManager = Components.interfaces.nsICategoryManager;
|
||
|
const nsIContentSniffer = Components.interfaces.nsIContentSniffer;
|
||
|
|
||
|
var catMgr = Components.classes["@mozilla.org/categorymanager;1"].getService(nsICategoryManager);
|
||
|
var sniffers = catMgr.enumerateCategory("content-sniffing-services");
|
||
|
while (mimeType == null && sniffers.hasMoreElements()) {
|
||
|
var snifferCID = sniffers.getNext().QueryInterface(Components.interfaces.nsISupportsCString).toString();
|
||
|
var sniffer = Components.classes[snifferCID].getService(nsIContentSniffer);
|
||
|
|
||
|
try {
|
||
|
mimeType = sniffer.getMIMETypeFromContent (this.mBytes, this.mCountRead);
|
||
|
} catch (e) {
|
||
|
mimeType = null;
|
||
|
// ignore
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (mimeType == null) {
|
||
|
BMSVC.updateBookmarkIcon(this.mURI, null, null, 0);
|
||
|
} else {
|
||
|
BMSVC.updateBookmarkIcon(this.mURI, mimeType, this.mBytes, this.mCountRead);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.mChannel = null;
|
||
|
},
|
||
|
|
||
|
// nsIStreamObserver
|
||
|
onDataAvailable : function (aRequest, aContext, aInputStream, aOffset, aCount) {
|
||
|
// we could get a different aInputStream, so we don't save this;
|
||
|
// it's unlikely we'll get more than one onDataAvailable for a
|
||
|
// favicon anyway
|
||
|
this.mStream.setInputStream(aInputStream);
|
||
|
|
||
|
var chunk = this.mStream.readByteArray(aCount);
|
||
|
this.mBytes = this.mBytes.concat(chunk);
|
||
|
this.mCountRead += aCount;
|
||
|
},
|
||
|
|
||
|
// nsIChannelEventSink
|
||
|
onChannelRedirect : function (aOldChannel, aNewChannel, aFlags) {
|
||
|
this.mChannel = aNewChannel;
|
||
|
},
|
||
|
|
||
|
// nsIProgressEventSink: the only reason we support
|
||
|
// nsIProgressEventSink is to shut up a whole slew of xpconnect
|
||
|
// warnings in debug builds. (see bug #253127)
|
||
|
onProgress : function (aRequest, aContext, aProgress, aProgressMax) { },
|
||
|
onStatus : function (aRequest, aContext, aStatus, aStatusArg) { }
|
||
|
}
|
||
|
|
||
|
#ifdef 0
|
||
|
|
||
|
var _dumpTIME;
|
||
|
function dumpTIME(aString)
|
||
|
{
|
||
|
var now=Date.now();
|
||
|
dump(aString);
|
||
|
if (_dumpTIME)
|
||
|
dump(now-_dumpTIME+'ms\n');
|
||
|
else
|
||
|
_dumpTIME = now;
|
||
|
}
|
||
|
|
||
|
function dumpOBJ (aObj)
|
||
|
{
|
||
|
if (!aObj)
|
||
|
dump("*** null object\n");
|
||
|
for (var i in aObj) {
|
||
|
dump("*** aObj[" + i + "] = ");
|
||
|
try {
|
||
|
dump(aObj[i] + "\n");
|
||
|
} catch (e) {
|
||
|
dump("*** not available\n")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function dumpDOM (aElement, aIndent)
|
||
|
{
|
||
|
if (!aElement)
|
||
|
return;
|
||
|
if (typeof(aElement) == "string")
|
||
|
aElement = document.getElementById(aElement);
|
||
|
|
||
|
if (!aIndent)
|
||
|
aIndent = 0;
|
||
|
for (var i=0; i<aIndent*2; ++i)
|
||
|
dump("-");
|
||
|
dump("-> ");
|
||
|
dump(aElement.localName+ " ("+aElement.id+') "'+aElement.getAttribute("class")+'"\n');
|
||
|
var element = aElement.firstChild;
|
||
|
while (element) {
|
||
|
dumpDOM(element,++aIndent);
|
||
|
--aIndent;
|
||
|
element = element.nextSibling;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function dumpRDF (aDS, aRDFNode)
|
||
|
{
|
||
|
dumpRDFOut(aDS, aRDFNode);
|
||
|
dump("\n");
|
||
|
dumpRDFIn (aDS, aRDFNode);
|
||
|
}
|
||
|
|
||
|
function dumpRDFOut (aDS, aRDFNode)
|
||
|
{
|
||
|
dump("Arcs Out for "+aRDFNode.Value+"\n");
|
||
|
var arcsout=aDS.ArcLabelsOut(aRDFNode);
|
||
|
while (arcsout.hasMoreElements()) {
|
||
|
var arc = arcsout.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
|
||
|
var targets = aDS.GetTargets(aRDFNode, arc, true);
|
||
|
while (targets.hasMoreElements()) {
|
||
|
var target = targets.getNext();
|
||
|
try {
|
||
|
target = target.QueryInterface(Components.interfaces.nsIRDFResource).Value;
|
||
|
} catch (e) {
|
||
|
try {
|
||
|
target = target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||
|
} catch (e) {}
|
||
|
}
|
||
|
dump("=>"+arc.Value+"=>"+target+"\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function dumpRDFIn (aDS, aRDFNode)
|
||
|
{
|
||
|
dump("Arcs In for "+aRDFNode.Value+"\n");
|
||
|
var arcs=aDS.ArcLabelsIn(aRDFNode);
|
||
|
while (arcs.hasMoreElements()) {
|
||
|
var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
|
||
|
var sources = aDS.GetSources(arc, aRDFNode, true);
|
||
|
while (sources.hasMoreElements()) {
|
||
|
var source = sources.getNext();
|
||
|
try {
|
||
|
source = source.QueryInterface(Components.interfaces.nsIRDFResource).Value;
|
||
|
} catch (e) {
|
||
|
try {
|
||
|
source = source.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||
|
} catch (e) {}
|
||
|
}
|
||
|
dump("<="+arc.Value+"<="+source+"\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function dumpTXN(aTxn)
|
||
|
{
|
||
|
aTxn = aTxn.wrappedJSObject;
|
||
|
dump(aTxn.type+", "+aTxn.action+"\n");
|
||
|
if (aTxn.type == "insert" || aTxn.type == "remove") {
|
||
|
for (var i=0; i<aTxn.item.length; ++i) {
|
||
|
dump(i+": "+aTxn.item[i].Value+" in "+BookmarksUtils.getProperty(aTxn.parent[i], gNC_NS+"Name")+", i:"+aTxn.index[i]+"\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|