diff --git a/widget/public/nsIDragSession.idl b/widget/public/nsIDragSession.idl index 8365d922c035..38ed07b78d07 100644 --- a/widget/public/nsIDragSession.idl +++ b/widget/public/nsIDragSession.idl @@ -34,7 +34,7 @@ native nsSize (nsSize); interface nsIDOMDocument; - +interface nsIDOMNode; [scriptable, uuid(CBA22C53-FCCE-11d2-96D4-0060B0FB9956)] interface nsIDragSession : nsISupports @@ -68,6 +68,12 @@ interface nsIDragSession : nsISupports */ readonly attribute nsIDOMDocument sourceDocument; + /** + * The dom node that was originally dragged to start the session, which will be null if the + * drag originated outside the application. + */ + readonly attribute nsIDOMNode sourceNode; + /** * Get data from a Drag&Drop. Can be called while the drag is in process * or after the drop has completed. diff --git a/widget/src/xpwidgets/nsBaseDragService.cpp b/widget/src/xpwidgets/nsBaseDragService.cpp index 97d19a7f040e..4822d1e3aa88 100644 --- a/widget/src/xpwidgets/nsBaseDragService.cpp +++ b/widget/src/xpwidgets/nsBaseDragService.cpp @@ -135,6 +135,21 @@ nsBaseDragService :: GetSourceDocument ( nsIDOMDocument** aSourceDocument ) return NS_OK; } +// +// GetSourceNode +// +// Returns the DOM node where the drag was initiated. This will be +// nsnull if the drag began outside of our application. +// +NS_IMETHODIMP +nsBaseDragService :: GetSourceNode ( nsIDOMNode** aSourceNode ) +{ + *aSourceNode = mSourceNode.get(); + NS_IF_ADDREF ( *aSourceNode ); + + return NS_OK; +} + //------------------------------------------------------------------------- @@ -157,7 +172,8 @@ NS_IMETHODIMP nsBaseDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISup if ( aDOMNode ) { // stash the document of the dom node aDOMNode->GetOwnerDocument ( getter_AddRefs(mSourceDocument) ); - + mSourceNode = aDOMNode; + // When the mouse goes down, the selection code starts a mouse capture. However, // this gets in the way of determining drag feedback for things like trees because // the event coordinates are in the wrong coord system. Turn off capture by diff --git a/widget/src/xpwidgets/nsBaseDragService.h b/widget/src/xpwidgets/nsBaseDragService.h index 4ae819ece348..2086e6bbfb7f 100644 --- a/widget/src/xpwidgets/nsBaseDragService.h +++ b/widget/src/xpwidgets/nsBaseDragService.h @@ -64,9 +64,9 @@ protected: nsSize mTargetSize; PRUint32 mDragAction; nsCOMPtr mCurrentlyTracking; + nsCOMPtr mSourceNode; nsCOMPtr mSourceDocument; // the document at the drag source. will be null // if it came from outside the app. - }; #endif // nsBaseDragService_h__ diff --git a/xpfe/browser/resources/content/navigatorDD.js b/xpfe/browser/resources/content/navigatorDD.js index ca6493ac72db..d40d7ba9f401 100644 --- a/xpfe/browser/resources/content/navigatorDD.js +++ b/xpfe/browser/resources/content/navigatorDD.js @@ -98,24 +98,27 @@ var personalToolbarObserver = { onDrop: function (aEvent, aXferData, aDragSession) { - var dropElement = aEvent.target.id; var xferData = aXferData.data.split("\n"); var elementRes = RDFUtils.getResource(xferData[0]); - var dropElementRes = RDFUtils.getResource(dropElement); var personalToolbarRes = RDFUtils.getResource("NC:PersonalToolbarFolder"); - var childDB = document.getElementById("innermostBox").database; + var inner = document.getElementById("innermostBox"); + var childDB = inner.database; const kCtrContractID = "@mozilla.org/rdf/container;1"; const kCtrIID = Components.interfaces.nsIRDFContainer; - var rdfContainer = Components.classes[kCtrContractID].getService(kCtrIID); + var rdfContainer = Components.classes[kCtrContractID].createInstance(kCtrIID); - var parentContainer = this.findParentContainer(aDragSession.sourceElement); + // if dragged url is already bookmarked, remove it from current location first + var parentContainer = this.findParentContainer(aDragSession.sourceNode); if (parentContainer) { rdfContainer.Init(childDB, parentContainer); - rdfContainer.RemoveElement(elementRes, true); + rdfContainer.RemoveElement(elementRes, false); } + // determine charset of link + var linkCharset = aDragSession.sourceDocument ? aDragSession.sourceDocument.characterSet : null; + // determine title of link var linkTitle; if (xferData.length >= 2) linkTitle = xferData[1] @@ -124,41 +127,50 @@ var personalToolbarObserver = { // look up this URL's title in global history var potentialTitle = null; var historyDS = gRDFService.GetDataSource("rdf:history"); - var historyTitleProperty = RDFUtils.getResource(NC_RDF("Name")); - var titleFromHistory = historyDS.GetTarget(elementRes, historyTitleProperty, true); + var titlePropRes = RDFUtils.getResource(NC_RDF("Name")); + var titleFromHistory = historyDS.GetTarget(elementRes, titlePropRes, true); if (titleFromHistory) titleFromHistory = titleFromHistory.QueryInterface(Components.interfaces.nsIRDFLiteral); if (titleFromHistory) potentialTitle = titleFromHistory.Value; linkTitle = potentialTitle; - - if (linkTitle) - childDB.Assert(elementRes, historyTitleProperty, - gRDFService.GetLiteral(linkTitle), true); } - rdfContainer.Init (childDB, personalToolbarRes); - var dropIndex = rdfContainer.IndexOf(dropElementRes); - // determine the drop position - var dropPosition = this.determineDropPosition(aEvent); + + var dropElement = aEvent.target.id; + var dropElementRes, dropIndex, dropPosition; + if (dropElement == "innermostBox") + { + dropElementRes = personalToolbarRes; + dropPosition = this.DROP_ON; + } + else + { + dropElementRes = RDFUtils.getResource(dropElement); + rdfContainer.Init(childDB, personalToolbarRes); + dropIndex = rdfContainer.IndexOf(dropElementRes); + if (dropPosition == undefined) + dropPosition = this.determineDropPosition(aEvent); + } + switch (dropPosition) { case this.DROP_BEFORE: if (dropIndex<1) dropIndex = 1; - rdfContainer.Init(childDB, personalToolbarRes); - rdfContainer.InsertElementAt(elementRes, dropIndex, true); + this.insertBookmarkAt(xferData[0], linkTitle, linkCharset, personalToolbarRes, dropIndex); break; case this.DROP_ON: - if (dropIndex<1) dropIndex = 1; - // do something here to drop into subfolders - rdfContainer.Init(childDB, dropElementRes); - rdfContainer.AppendElement(elementRes); + this.insertBookmarkAt(xferData[0], linkTitle, linkCharset, dropElementRes, -1); break; case this.DROP_AFTER: default: + // compensate for badly calculated dropIndex + rdfContainer.Init(childDB, personalToolbarRes); + if (dropIndex < rdfContainer.GetCount()) ++dropIndex; + if (dropIndex<0) dropIndex = 0; - rdfContainer.Init (childDB, personalToolbarRes); - rdfContainer.InsertElementAt(elementRes, dropIndex+1, true); + this.insertBookmarkAt(xferData[0], linkTitle, linkCharset, personalToolbarRes, dropIndex); break; } + return true; }, @@ -277,6 +289,14 @@ var personalToolbarObserver = { return RDFUtils.getResource(treeitem.id); } return null; + }, + + insertBookmarkAt: function(aURL, aTitle, aCharset, aFolderRes, aIndex) + { + const kBMSContractID = "@mozilla.org/browser/bookmarks-service;1"; + const kBMSIID = Components.interfaces.nsIBookmarksService; + const kBMS = Components.classes[kBMSContractID].getService(kBMSIID); + kBMS.insertBookmarkInFolder(aURL, aTitle, aCharset, aFolderRes, aIndex); } }; diff --git a/xpfe/components/bookmarks/public/nsIBookmarksService.idl b/xpfe/components/bookmarks/public/nsIBookmarksService.idl index c2fa4a932e73..818bf06cc130 100644 --- a/xpfe/components/bookmarks/public/nsIBookmarksService.idl +++ b/xpfe/components/bookmarks/public/nsIBookmarksService.idl @@ -45,6 +45,9 @@ interface nsIBookmarksService : nsISupports void AddBookmarkToFolder(in string aURI, in nsIRDFResource aFolder, in wstring aTitle, in wstring docCharSet); + void insertBookmarkInFolder(in string aURI, in wstring aTitle, in wstring docCharSet, + in nsIRDFResource aFolder, in long aIndex); + void UpdateBookmarkLastVisitedDate(in string aURL, in wstring docCharset); string FindShortcut(in wstring aName); diff --git a/xpfe/components/bookmarks/src/nsBookmarksService.cpp b/xpfe/components/bookmarks/src/nsBookmarksService.cpp index eaa694850619..e40d66913d15 100644 --- a/xpfe/components/bookmarks/src/nsBookmarksService.cpp +++ b/xpfe/components/bookmarks/src/nsBookmarksService.cpp @@ -396,7 +396,8 @@ public: const char* aShortcutURL, nsIRDFResource* aNodeType, nsIRDFResource** bookmarkNode, - const PRUnichar* aCharset); + const PRUnichar* aCharset, + PRInt32 aIndex); nsresult SetIEFavoritesRoot(const char *IEFavoritesRootURL) { @@ -1366,7 +1367,8 @@ BookmarkParser::AddBookmark(nsCOMPtr aContainer, const char* aShortcutURL, nsIRDFResource* aNodeType, nsIRDFResource** bookmarkNode, - const PRUnichar* aCharset) + const PRUnichar* aCharset, + PRInt32 aIndex) { nsresult rv; nsAutoString fullURL; @@ -1464,7 +1466,10 @@ BookmarkParser::AddBookmark(nsCOMPtr aContainer, } // The last thing we do is add the bookmark to the container. This ensures the minimal amount of reflow. - rv = aContainer->AppendElement(bookmark); + if (aIndex < 0) + rv = aContainer->AppendElement(bookmark); + else + rv = aContainer->InsertElementAt(bookmark, aIndex, PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add bookmark to container"); return(rv); } @@ -2481,6 +2486,17 @@ nsBookmarksService::AddBookmarkToFolder(const char *aURI, nsIRDFResource *aFolder, const PRUnichar* aTitle, const PRUnichar *aCharset) +{ + return InsertBookmarkInFolder(aURI, aTitle, aCharset, aFolder, -1); +} + + +NS_IMETHODIMP +nsBookmarksService::InsertBookmarkInFolder(const char *aURI, + const PRUnichar* aTitle, + const PRUnichar *aCharset, + nsIRDFResource *aFolder, + PRInt32 aIndex) { // XXX Constructing a parser object to do this is bad. // We need to factor AddBookmark() into its own little @@ -2510,7 +2526,7 @@ nsBookmarksService::AddBookmarkToFolder(const char *aURI, LL_L2I(now32, now64); rv = parser.AddBookmark(container, aURI, aTitle, now32, - 0L, 0L, nsnull, kNC_Bookmark, nsnull, aCharset); + 0L, 0L, nsnull, kNC_Bookmark, nsnull, aCharset, aIndex); if (NS_FAILED(rv)) return rv; @@ -4345,7 +4361,7 @@ nsBookmarksService::WriteBookmarksContainer(nsIRDFDataSource *ds, nsOutputFileSt } } } - + strm << indentation; strm << " "; if (isContainer == PR_TRUE)