home *** CD-ROM | disk | FTP | other *** search
/ ftp.swcp.com / ftp.swcp.com.zip / ftp.swcp.com / mac / mozilla-macos9-1.3.1.sea.bin / Mozilla1.3.1 / Chrome / comm.jar / content / navigator / navigatorDD.js < prev    next >
Text File  |  2003-06-08  |  26KB  |  710 lines

  1. /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Netscape Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/NPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is mozilla.org code.
  16.  *
  17.  * The Initial Developer of the Original Code is 
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 1998
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *  - Kevin Puetz (puetzk@iastate.edu)
  24.  *  - Ben Goodger <ben@netscape.com> 
  25.  *  - Blake Ross <blaker@netscape.com>
  26.  *  - Pierre Chanial <pierrechanial@netscape.net>
  27.  *
  28.  * Alternatively, the contents of this file may be used under the terms of
  29.  * either the GNU General Public License Version 2 or later (the "GPL"), or 
  30.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  31.  * in which case the provisions of the GPL or the LGPL are applicable instead
  32.  * of those above. If you wish to allow use of your version of this file only
  33.  * under the terms of either the GPL or the LGPL, and not to allow others to
  34.  * use your version of this file under the terms of the NPL, indicate your
  35.  * decision by deleting the provisions above and replace them with the notice
  36.  * and other provisions required by the GPL or the LGPL. If you do not delete
  37.  * the provisions above, a recipient may use your version of this file under
  38.  * the terms of any one of the NPL, the GPL or the LGPL.
  39.  *
  40.  * ***** END LICENSE BLOCK ***** */
  41.  
  42. function _RDF(aType)
  43.   {
  44.     return "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + aType;
  45.   }
  46. function NC_RDF(aType)
  47.   {
  48.     return "http://home.netscape.com/NC-rdf#" + aType;
  49.   }
  50.  
  51. var RDFUtils = {
  52.   getResource: function(aString)
  53.     {
  54.       return this.rdf.GetResource(aString, true);
  55.     },
  56.  
  57.   getTarget: function(aDS, aSourceID, aPropertyID)
  58.     {
  59.       var source = this.getResource(aSourceID);
  60.       var property = this.getResource(aPropertyID);
  61.       return aDS.GetTarget(source, property, true);
  62.     },
  63.  
  64.   getValueFromResource: function(aResource)
  65.     {
  66.       aResource = aResource.QueryInterface(Components.interfaces.nsIRDFResource);
  67.       return aResource ? aResource.Value : null;
  68.     },
  69.   _rdf: null,
  70.   get rdf() {
  71.     if (!this._rdf) {
  72.       this._rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  73.                             .getService(Components.interfaces.nsIRDFService);
  74.     }
  75.     return this._rdf;
  76.   }
  77. }
  78.  
  79. var proxyIconDNDObserver = {
  80.   onDragStart: function (aEvent, aXferData, aDragAction)
  81.     {
  82.       var urlBar = document.getElementById("urlbar");
  83.  
  84.       // XXX - do we want to allow the user to set a blank page to their homepage?
  85.       //       if so then we want to modify this a little to set about:blank as
  86.       //       the homepage in the event of an empty urlbar.
  87.       if (!urlBar.value) return;
  88.  
  89.       var urlString = urlBar.value + "\n" + window._content.document.title;
  90.       var htmlString = "<a href=\"" + urlBar.value + "\">" + urlBar.value + "</a>";
  91.  
  92.       aXferData.data = new TransferData();
  93.       aXferData.data.addDataForFlavour("text/x-moz-url", urlString);
  94.       aXferData.data.addDataForFlavour("text/unicode", urlBar.value);
  95.       aXferData.data.addDataForFlavour("text/html", htmlString);
  96.     }
  97. }
  98.  
  99. var homeButtonObserver = {
  100.   onDragStart: function (aEvent, aXferData, aDragAction)
  101.     {
  102.       var homepage = nsPreferences.getLocalizedUnicharPref("browser.startup.homepage", "about:blank");
  103.  
  104.       if (homepage)
  105.         {
  106.           // XXX find a readable title string for homepage, perhaps do a history lookup.
  107.           var htmlString = "<a href=\"" + homepage + "\">" + homepage + "</a>";
  108.           aXferData.data = new TransferData();
  109.           aXferData.data.addDataForFlavour("text/x-moz-url", homepage + "\n" + homepage);
  110.           aXferData.data.addDataForFlavour("text/html", htmlString);
  111.           aXferData.data.addDataForFlavour("text/unicode", homepage);
  112.         }
  113.     },
  114.  
  115.   onDrop: function (aEvent, aXferData, aDragSession)
  116.     {
  117.       var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  118.       setTimeout(openHomeDialog, 0, url);
  119.     },
  120.  
  121.   onDragOver: function (aEvent, aFlavour, aDragSession)
  122.     {
  123.       var statusTextFld = document.getElementById("statusbar-display");
  124.       statusTextFld.label = gNavigatorBundle.getString("droponhomebutton");
  125.       aDragSession.dragAction = Components.interfaces.nsIDragService.DRAGDROP_ACTION_LINK;
  126.     },
  127.  
  128.   onDragExit: function (aEvent, aDragSession)
  129.     {
  130.       var statusTextFld = document.getElementById("statusbar-display");
  131.       statusTextFld.label = "";
  132.     },
  133.  
  134.   getSupportedFlavours: function ()
  135.     {
  136.       var flavourSet = new FlavourSet();
  137.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  138.       flavourSet.appendFlavour("text/x-moz-url");
  139.       flavourSet.appendFlavour("text/unicode");
  140.       return flavourSet;
  141.     }
  142. }
  143.  
  144. function openHomeDialog(aURL)
  145. {
  146.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  147.   var promptTitle = gNavigatorBundle.getString("droponhometitle");
  148.   var promptMsg   = gNavigatorBundle.getString("droponhomemsg");
  149.   var okButton    = gNavigatorBundle.getString("droponhomeokbutton");
  150.   var pressedVal = promptService.confirmEx(window, promptTitle, promptMsg,
  151.                           (promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0) +
  152.                           (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
  153.                           okButton, null, null, null, {value:0});
  154.  
  155.   if (pressedVal == 0) {
  156.     nsPreferences.setUnicharPref("browser.startup.homepage", aURL);
  157.   }
  158. }
  159.  
  160. var goButtonObserver = {
  161.   onDragOver: function(aEvent, aFlavour, aDragSession)
  162.     {
  163.       aEvent.target.setAttribute("dragover", "true");
  164.       return true;
  165.     },
  166.   onDragExit: function (aEvent, aDragSession)
  167.     {
  168.       aEvent.target.removeAttribute("dragover");
  169.     },
  170.   onDrop: function (aEvent, aXferData, aDragSession)
  171.     {
  172.       var xferData = aXferData.data.split("\n");
  173.       var uri = xferData[0] ? xferData[0] : xferData[1];
  174.       if (uri)
  175.         loadURI(uri);
  176.     },
  177.   getSupportedFlavours: function ()
  178.     {
  179.       var flavourSet = new FlavourSet();
  180.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  181.       flavourSet.appendFlavour("text/x-moz-url");
  182.       flavourSet.appendFlavour("text/unicode");
  183.       return flavourSet;
  184.     }
  185. }
  186.  
  187. var searchButtonObserver = {
  188.   onDragOver: function(aEvent, aFlavour, aDragSession)
  189.     {
  190.       aEvent.target.setAttribute("dragover", "true");
  191.       return true;
  192.     },
  193.   onDragExit: function (aEvent, aDragSession)
  194.     {
  195.       aEvent.target.removeAttribute("dragover");
  196.     },
  197.   onDrop: function (aEvent, aXferData, aDragSession)
  198.     {
  199.       var xferData = aXferData.data.split("\n");
  200.       var uri = xferData[1] ? xferData[1] : xferData[0];
  201.       if (uri)
  202.         OpenSearch('internet',false, uri);
  203.     },
  204.   getSupportedFlavours: function ()
  205.     {
  206.       var flavourSet = new FlavourSet();
  207.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  208.       flavourSet.appendFlavour("text/x-moz-url");
  209.       flavourSet.appendFlavour("text/unicode");
  210.       return flavourSet;
  211.     }
  212. }
  213.  
  214. var personalToolbarDNDObserver = {
  215.  
  216.   ////////////////////
  217.   // Public methods //
  218.   ////////////////////
  219.  
  220.   onDragStart: function (aEvent, aXferData, aDragAction)
  221.     {
  222.  
  223.       // Prevent dragging from an invalid region
  224.       if (!this.canDrop(aEvent))
  225.         return;
  226.  
  227.       // Prevent dragging out of menupopups on non Win32 platforms. 
  228.       // a) on Mac drag from menus is generally regarded as being satanic
  229.       // b) on Linux, this causes an X-server crash, see bug 79003, 96504 and 139471
  230.       // c) on Windows, there is no hang or crash associated with this, so we'll leave 
  231.       // the functionality there. 
  232.       if (navigator.platform != "Win32" && aEvent.target.localName != "toolbarbutton")
  233.         return;
  234.  
  235.       // prevent dragging folders in the personal toolbar and menus.
  236.       // PCH: under linux, since containers open on mouse down, we hit bug 96504. 
  237.       // In addition, a drag start is fired when leaving an open toolbarbutton(type=menu) 
  238.       // menupopup (see bug 143031)
  239.       if (this.isContainer(aEvent.target) && aEvent.target.getAttribute("group") != "true") {
  240.         if (this.isPlatformNotSupported) 
  241.           return;
  242.         if (!aEvent.shiftKey && !aEvent.altKey)
  243.           return;
  244.         // menus open on mouse down
  245.         aEvent.target.firstChild.hidePopup();
  246.       }
  247.  
  248.       // Prevent dragging non-bookmark menuitem or menus
  249.       var uri = aEvent.target.id;
  250.       if (!this.isBookmark(uri))
  251.         return;
  252.  
  253.       //PCH: cleanup needed here, url is already calculated in isBookmark()
  254.       var db = document.getElementById("NC:PersonalToolbarFolder").database;
  255.       var url = RDFUtils.getTarget(db, uri, NC_RDF("URL"));
  256.       if (url)
  257.         url = url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
  258.       else
  259.         url = "";
  260.       var name = RDFUtils.getTarget(db, uri, NC_RDF("Name"));
  261.       if (name)
  262.         name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
  263.       else
  264.         name = "";
  265.       var urlString = url + "\n" + name;
  266.       var htmlString = "<A HREF='" + url + "'>" + name + "</A>";
  267.       aXferData.data = new TransferData();
  268.       aXferData.data.addDataForFlavour("moz/rdfitem", uri);
  269.       aXferData.data.addDataForFlavour("text/x-moz-url", urlString);
  270.       aXferData.data.addDataForFlavour("text/html", htmlString);
  271.       aXferData.data.addDataForFlavour("text/unicode", url);
  272.  
  273.       return;
  274.     },
  275.  
  276.   onDragOver: function(aEvent, aFlavour, aDragSession) 
  277.   {
  278.     if (aDragSession.canDrop)
  279.       this.onDragSetFeedBack(aEvent);
  280.     if (this.determineDropPosition(aEvent) != this.mCurrentDropPosition) {
  281.       // emulating onDragExit and onDragEnter events since the drop region
  282.       // has changed on the target.
  283.       this.onDragExit(aEvent, aDragSession);
  284.       this.onDragEnter(aEvent, aDragSession);
  285.     }
  286.     if (this.isPlatformNotSupported)
  287.       return;
  288.     if (this.isTimerSupported)
  289.       return;
  290.     this.onDragOverCheckTimers();
  291.     return;
  292.   },
  293.  
  294.   onDragEnter: function (aEvent, aDragSession)
  295.   {
  296.     var target = aEvent.target;
  297.     if (target.localName == "menupopup" || target.localName == "hbox")
  298.       target = target.parentNode;
  299.     if (aDragSession.canDrop) {
  300.       this.onDragSetFeedBack(aEvent);
  301.       this.onDragEnterSetTimer(target, aDragSession);
  302.     }
  303.     this.mCurrentDragOverTarget = target;
  304.     this.mCurrentDropPosition = this.determineDropPosition(aEvent);
  305.     return;
  306.   },
  307.  
  308.   onDragExit: function (aEvent, aDragSession)
  309.   {
  310.     var target = aEvent.target;
  311.     if (target.localName == "menupopup" || target.localName == "hbox")
  312.       target = target.parentNode;
  313.     this.onDragRemoveFeedBack(target);
  314.     this.onDragExitSetTimer(target, aDragSession);
  315.     this.mCurrentDragOverTarget = null;
  316.     this.mCurrentDropPosition = null;
  317.     return;
  318.   },
  319.  
  320.   onDrop: function (aEvent, aXferData, aDragSession)
  321.   {
  322.  
  323.     this.onDragRemoveFeedBack(aEvent.target);
  324.     var dropPosition = this.determineDropPosition(aEvent);
  325.  
  326.     // PCH: BAD!!! We should use the flavor
  327.     // this code should be merged with the one in bookmarks.xml
  328.     var xferData = aXferData.data.split("\n");
  329.     if (xferData[0] == "")
  330.       return;
  331.     var elementRes = RDFUtils.getResource(xferData[0]);
  332.  
  333.     var childDB = document.getElementById("NC:PersonalToolbarFolder").database;
  334.     var rdfContainer = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  335.  
  336.     // if dragged url is already bookmarked, remove it from current location first
  337.     var parentContainer = this.findParentContainer(aDragSession.sourceNode);
  338.     if (parentContainer) {
  339.       rdfContainer.Init(childDB, parentContainer);
  340.       rdfContainer.RemoveElement(elementRes, false);
  341.     }
  342.  
  343.     // Don't try to determine the charset of the link (bug 174197)
  344.     var linkCharset = null;
  345.     // determine title of link
  346.     var linkTitle;
  347.     // look it up in bookmarks
  348.     var bookmarksDS = RDFUtils.rdf.GetDataSource("rdf:bookmarks");
  349.     var nameRes = RDFUtils.getResource(NC_RDF("Name"));
  350.     var nameFromBookmarks = bookmarksDS.GetTarget(elementRes, nameRes, true);
  351.     if (nameFromBookmarks)
  352.       nameFromBookmarks = nameFromBookmarks.QueryInterface(Components.interfaces.nsIRDFLiteral);
  353.     if (nameFromBookmarks)
  354.       linkTitle = nameFromBookmarks.Value;
  355.     else if (xferData.length >= 2)
  356.       linkTitle = xferData[1]
  357.     else {
  358.       // look up this URL's title in global history
  359.       var historyDS = RDFUtils.rdf.GetDataSource("rdf:history");
  360.       var titlePropRes = RDFUtils.getResource(NC_RDF("Name"));
  361.       var titleFromHistory = historyDS.GetTarget(elementRes, titlePropRes, true);
  362.       if (titleFromHistory)
  363.         titleFromHistory = titleFromHistory.QueryInterface(Components.interfaces.nsIRDFLiteral);
  364.       if (titleFromHistory)
  365.         linkTitle = titleFromHistory.Value;
  366.       else
  367.         linkTitle = xferData[0];
  368.     }
  369.  
  370.     var dropIndex;
  371.     if (aEvent.target.id == "bookmarks-button") 
  372.       // dropPosition is always DROP_ON
  373.       parentContainer = RDFUtils.getResource("NC:BookmarksRoot");
  374.     else if (dropPosition == this.DROP_ON) 
  375.       parentContainer = RDFUtils.getResource(aEvent.target.id);
  376.     else {
  377.       parentContainer = this.findParentContainer(aEvent.target);
  378.       rdfContainer.Init(childDB, parentContainer);
  379.       var dropElementRes = RDFUtils.getResource(aEvent.target.id);
  380.       dropIndex = rdfContainer.IndexOf(dropElementRes);
  381.     }
  382.     switch (dropPosition) {
  383.       case this.DROP_BEFORE:
  384.         if (dropIndex<1) dropIndex = 1;
  385.         break;
  386.       case this.DROP_ON:
  387.         dropIndex = -1;
  388.         break;
  389.       case this.DROP_AFTER:
  390.         if (dropIndex <= rdfContainer.GetCount()) ++dropIndex;         
  391.         if (dropIndex<1) dropIndex = -1;
  392.         break;
  393.     }
  394.  
  395.     this.insertBookmarkAt(xferData[0], linkTitle, linkCharset, parentContainer, dropIndex);       
  396.     return;
  397.   },
  398.  
  399.   canDrop: function (aEvent, aDragSession)
  400.   {
  401.     var target = aEvent.target;
  402.     return target.id && target.localName != "menupopup" && target.localName != "toolbar" &&
  403.            target.localName != "menuseparator" && target.localName != "toolbarseparator" &
  404.            target.id != "NC:SystemBookmarksStaticRoot" &&
  405.            target.id.substring(0,5) != "find:";
  406.   },
  407.  
  408.   getSupportedFlavours: function () 
  409.   {
  410.     var flavourSet = new FlavourSet();
  411.     flavourSet.appendFlavour("moz/rdfitem");
  412.     flavourSet.appendFlavour("text/unicode");
  413.     flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  414.     flavourSet.appendFlavour("text/x-moz-url");
  415.     return flavourSet;
  416.   }, 
  417.   
  418.  
  419.   ////////////////////////////////////
  420.   // Private methods and properties //
  421.   ////////////////////////////////////
  422.  
  423.   DROP_BEFORE:-1,
  424.   DROP_ON    : 0,
  425.   DROP_AFTER : 1,
  426.   springLoadedMenuDelay: 350, // milliseconds
  427.   isPlatformNotSupported: navigator.platform.indexOf("Mac") != -1, // see bug 136524
  428.   isTimerSupported: navigator.platform.indexOf("Win") == -1,
  429.  
  430.   mCurrentDragOverTarget: null,
  431.   mCurrentDropPosition: null,
  432.   loadTimer  : null,
  433.   closeTimer : null,
  434.   loadTarget : null,
  435.   closeTarget: null,
  436.  
  437.  
  438.   onDragCloseMenu: function (aNode)
  439.   {
  440.     var children = aNode.childNodes;
  441.     for (var i = 0; i < children.length; i++) {
  442.       if (children[i].id == "NC:PersonalToolbarFolder" && children[i].localName == "hbox") {
  443.         this.onDragCloseMenu(children[i]);
  444.       }
  445.       else if (this.isContainer(children[i]) && children[i].getAttribute("open") == "true") {
  446.         this.onDragCloseMenu(children[i].firstChild);
  447.         if (children[i] != this.mCurrentDragOverTarget || this.mCurrentDropPosition != this.DROP_ON)
  448.           children[i].firstChild.hidePopup();
  449.       }
  450.     } 
  451.   },
  452.  
  453.   onDragCloseTarget: function ()
  454.   {
  455.     // if the mouse is not over a menu, then close everything.
  456.     if (!this.mCurrentDragOverTarget) {
  457.       this.onDragCloseMenu(document.getElementById("PersonalToolbar"));
  458.       return
  459.     }
  460.     // The bookmark button is not a sibling of the folders in the PT
  461.     if (this.mCurrentDragOverTarget.parentNode.id == "NC:PersonalToolbarFolder" && this.mCurrentDragOverTarget.parentNode.localName == "hbox")
  462.       this.onDragCloseMenu(document.getElementById("PersonalToolbar"));
  463.     else
  464.       this.onDragCloseMenu(this.mCurrentDragOverTarget.parentNode);
  465.   },
  466.  
  467.   onDragLoadTarget: function (aTarget) 
  468.   {
  469.     if (!this.mCurrentDragOverTarget)
  470.       return;
  471.     // Load the current menu
  472.     if (this.mCurrentDropPosition == this.DROP_ON && 
  473.         this.isContainer(aTarget)                 && 
  474.         aTarget.getAttribute("group") != "true")
  475.       aTarget.firstChild.showPopup(aTarget, -1, -1, "menupopup");
  476.   },
  477.  
  478.   onDragOverCheckTimers: function ()
  479.   {
  480.     var now = new Date().getTime();
  481.     if (this.closeTimer && now-this.springLoadedMenuDelay>this.closeTimer) {
  482.       this.onDragCloseTarget();
  483.       this.closeTimer = null;
  484.     }
  485.     if (this.loadTimer && (now-this.springLoadedMenuDelay>this.loadTimer)) {
  486.       this.onDragLoadTarget(this.loadTarget);
  487.       this.loadTimer = null;
  488.     }
  489.   },
  490.  
  491.   onDragEnterSetTimer: function (aTarget, aDragSession)
  492.   {
  493.     if (this.isPlatformNotSupported)
  494.       return;
  495.     if (this.isTimerSupported) {
  496.       var targetToBeLoaded = aTarget;
  497.       clearTimeout(this.loadTimer);
  498.       if (aTarget == aDragSession.sourceNode)
  499.         return;
  500.       //XXX Hack: see bug 139645
  501.       var thisHack = this;
  502.       this.loadTimer=setTimeout(function () {thisHack.onDragLoadTarget(targetToBeLoaded)}, this.springLoadedMenuDelay);
  503.     } else {
  504.       var now = new Date().getTime();
  505.       this.loadTimer  = now;
  506.       this.loadTarget = aTarget;
  507.     }
  508.   },
  509.  
  510.   onDragExitSetTimer: function (aTarget, aDragSession)
  511.   {
  512.     if (this.isPlatformNotSupported)
  513.       return;
  514.     var thisHack = this;
  515.     if (this.isTimerSupported) {
  516.       clearTimeout(this.closeTimer)
  517.       this.closeTimer=setTimeout(function () {thisHack.onDragCloseTarget()}, this.springLoadedMenuDelay);
  518.     } else {
  519.       var now = new Date().getTime();
  520.       this.closeTimer  = now;
  521.       this.closeTarget = aTarget;
  522.       this.loadTimer = null;
  523.  
  524.       // If user isn't rearranging within the menu, close it
  525.       // To do so, we exploit a Mac bug: timeout set during
  526.       // drag and drop on Windows and Mac are fired only after that the drop is released.
  527.       // timeouts will pile up, we may have a better approach but for the moment, this one
  528.       // correctly close the menus after a drop/cancel outside the personal toolbar.
  529.       // The if statement in the function has been introduced to deal with rare but reproducible
  530.       // missing Exit events.
  531.       if (aDragSession.sourceNode.localName != "menuitem" && aDragSession.sourceNode.localName != "menu")
  532.         setTimeout(function () { if (thisHack.mCurrentDragOverTarget) {thisHack.onDragRemoveFeedBack(thisHack.mCurrentDragOverTarget); thisHack.mCurrentDragOverTarget=null} thisHack.loadTimer=null; thisHack.onDragCloseTarget() }, 0);
  533.     }
  534.   },
  535.  
  536.   onDragSetFeedBack: function (aEvent)
  537.   {
  538.     var target = aEvent.target
  539.     var dropPosition = this.determineDropPosition(aEvent)
  540.     switch (target.localName) {
  541.       case "toolbarseparator":
  542.       case "toolbarbutton":
  543.         switch (dropPosition) {
  544.           case this.DROP_BEFORE: 
  545.             target.setAttribute("dragover-left", "true");
  546.             break;
  547.           case this.DROP_AFTER:
  548.             target.setAttribute("dragover-right", "true");
  549.             break;
  550.           case this.DROP_ON:
  551.             target.setAttribute("dragover-top"   , "true");
  552.             target.setAttribute("dragover-bottom", "true");
  553.             target.setAttribute("dragover-left"  , "true");
  554.             target.setAttribute("dragover-right" , "true");
  555.             break;
  556.         }
  557.         break;
  558.       case "menuseparator": 
  559.       case "menu":
  560.       case "menuitem":
  561.         switch (dropPosition) {
  562.           case this.DROP_BEFORE: 
  563.             target.setAttribute("dragover-top", "true");
  564.             break;
  565.           case this.DROP_AFTER:
  566.             target.setAttribute("dragover-bottom", "true");
  567.             break;
  568.           case this.DROP_ON:
  569.             break;
  570.         }
  571.         break;
  572.       case "hbox"     : 
  573.         target.lastChild.setAttribute("dragover-right", "true");
  574.         break;
  575.       case "menupopup": 
  576.       case "toolbar"  : break;
  577.       default: dump("No feedback for: "+target.localName+"\n");
  578.     }
  579.   },
  580.  
  581.   onDragRemoveFeedBack: function (aTarget)
  582.   {
  583.     if (aTarget.localName == "toolbar") {
  584.       aTarget.lastChild.lastChild.removeAttribute("dragover-right");
  585.     } else if (aTarget.localName == "hbox") {
  586.       aTarget.lastChild.removeAttribute("dragover-right");
  587.     } else {
  588.       aTarget.removeAttribute("dragover-left");
  589.       aTarget.removeAttribute("dragover-right");
  590.       aTarget.removeAttribute("dragover-top");
  591.       aTarget.removeAttribute("dragover-bottom");
  592.     }
  593.   },
  594.  
  595.   onDropSetFeedBack: function (aTarget)
  596.   {
  597.     //XXX Not yet...
  598.   },
  599.  
  600.   isContainer: function (aTarget)
  601.   {
  602.     return (aTarget.localName == "menu" || aTarget.localName == "toolbarbutton") &&
  603.            (aTarget.getAttribute("container") == "true" || aTarget.getAttribute("group") == "true");
  604.   },
  605.  
  606.  
  607.   ///////////////////////////////////////////////////////
  608.   // Methods that need to be moved into BookmarksUtils //
  609.   ///////////////////////////////////////////////////////
  610.  
  611.   //XXX skin authors could break us, we'll cross that bridge when they turn us 90degrees
  612.   determineDropPosition: function (aEvent)
  613.   {
  614.     if (aEvent.target.id == "bookmarks-button")
  615.       return this.DROP_ON;
  616.  
  617.     var overButtonBoxObject = aEvent.target.boxObject.QueryInterface(Components.interfaces.nsIBoxObject);
  618.     var overParentBoxObject = aEvent.target.parentNode.boxObject.QueryInterface(Components.interfaces.nsIBoxObject);
  619.  
  620.     var size, border;
  621.     var coordValue, clientCoordValue;
  622.     switch (aEvent.target.localName) {
  623.       case "toolbarseparator":
  624.       case "toolbarbutton":
  625.         size = overButtonBoxObject.width;
  626.         coordValue = overButtonBoxObject.x;
  627.         clientCoordValue = aEvent.clientX;
  628.         break;
  629.       case "menuseparator": 
  630.       case "menu":
  631.       case "menuitem":
  632.         size = overButtonBoxObject.height;
  633.         coordValue = overButtonBoxObject.y-overParentBoxObject.y;
  634.         clientCoordValue = aEvent.clientY;
  635.         break;
  636.       default: return this.DROP_ON;
  637.     }
  638.     
  639.     if (this.isContainer(aEvent.target))
  640.       if (aEvent.target.localName == "toolbarbutton") {
  641.         // the DROP_BEFORE area excludes the label
  642.         var iconNode = document.getAnonymousElementByAttribute(aEvent.target, "class", "toolbarbutton-icon");
  643.         border = parseInt(document.defaultView.getComputedStyle(aEvent.target,"").getPropertyValue("padding-left")) +
  644.                  parseInt(document.defaultView.getComputedStyle(iconNode     ,"").getPropertyValue("width"));
  645.         border = Math.min(size/5,Math.max(border,4));
  646.       } else
  647.         border = size/5;
  648.     else
  649.       border = size/2;
  650.       
  651.     // in the first region?
  652.     if (clientCoordValue-coordValue < border)
  653.       return this.DROP_BEFORE;
  654.     // in the last region?
  655.     if (clientCoordValue-coordValue >= size-border)
  656.       return this.DROP_AFTER;
  657.     // must be in the middle somewhere
  658.     return this.DROP_ON;
  659.   },
  660.  
  661.   isBookmark: function (aURI)
  662.   {
  663.     if (!aURI)
  664.       return false;
  665.     var db = document.getElementById("NC:PersonalToolbarFolder").database;
  666.     var typeValue = RDFUtils.getTarget(db, aURI, _RDF("type"));
  667.     typeValue = RDFUtils.getValueFromResource(typeValue);
  668.     return (typeValue == NC_RDF("BookmarkSeparator") ||
  669.             typeValue == NC_RDF("Bookmark") ||
  670.             typeValue == NC_RDF("Folder"))
  671.   },
  672.  
  673.   // returns the parent resource of the dragged element. This is determined
  674.   // by inspecting the source element of the drag and walking up the DOM tree
  675.   // to find the appropriate containing node.
  676.   findParentContainer: function (aElement)
  677.   {
  678.     if (!aElement) return null;
  679.     switch (aElement.localName) {
  680.       case "toolbarbutton":
  681.         var box = aElement.parentNode;
  682.         return RDFUtils.getResource(box.getAttribute("ref"));
  683.       case "menu":
  684.       case "menuitem":
  685.         var parentNode = aElement.parentNode.parentNode;
  686.      
  687.         if (parentNode.getAttribute("type") != NC_RDF("Folder") &&
  688.             parentNode.getAttributeNS("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "type") != "http://home.netscape.com/NC-rdf#Folder")
  689.           return RDFUtils.getResource("NC:BookmarksRoot");
  690.         return RDFUtils.getResource(parentNode.id);
  691.       case "treecell":
  692.         var treeitem = aElement.parentNode.parentNode.parentNode.parentNode;
  693.         var res = treeitem.getAttribute("ref");
  694.         if (!res)
  695.           res = treeitem.id;            
  696.         return RDFUtils.getResource(res);
  697.     }
  698.     return null;
  699.   },
  700.  
  701.   insertBookmarkAt: function (aURL, aTitle, aCharset, aFolderRes, aIndex)
  702.   {
  703.     const kBMSContractID = "@mozilla.org/browser/bookmarks-service;1";
  704.     const kBMSIID = Components.interfaces.nsIBookmarksService;
  705.     const kBMS = Components.classes[kBMSContractID].getService(kBMSIID);
  706.     kBMS.createBookmarkInContainer(aTitle, aURL, aCharset, aFolderRes, aIndex);
  707.   }
  708.  
  709. }
  710.