Bug 389290 - Bookmarks Menu - dropmarker missing. Patch from Simon Bunzli <zeniko@gmail.com> and Marco Bonardo [mak77] <mak77@supereva.it>, r=me.

This commit is contained in:
mozilla.mano@sent.com 2008-02-20 18:17:52 -08:00
parent eb3e4a8015
commit 22146ff22c
8 changed files with 469 additions and 347 deletions

View File

@ -22,6 +22,7 @@
* Ben Goodger <beng@google.com>
* Myk Melez <myk@mozilla.org>
* Asaf Romano <mano@mozilla.com>
* Marco Bonardo <mak77@supereva.it>
*
* 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
@ -1222,291 +1223,6 @@ PlacesController.prototype = {
}
};
function PlacesMenuDNDObserver(aView, aPopup) {
this._view = aView;
this._popup = aPopup;
this._popup.addEventListener("draggesture", this, false);
this._popup.addEventListener("dragover", this, false);
this._popup.addEventListener("dragdrop", this, false);
this._popup.addEventListener("dragexit", this, false);
}
/**
* XXXmano-please-rewrite-me: This code was ported over from menu.xul in bug 399729.
* Unsurprisngly it's still mostly broken due to bug 337761, thus I didn't bother
* trying to cleaning up this extremely buggy over-folder detection code yet.
*/
PlacesMenuDNDObserver.prototype = {
_view: null,
_popup: null,
// Sub-menus should be opened when the mouse drags over them, and closed
// when the mouse drags off. The overFolder object manages opening and closing
// of folders when the mouse hovers.
_overFolder: {node: null, openTimer: null, hoverTime: 350, closeTimer: null},
// If this menu's parent auto-opened it because it was dragged over, but didn't
// close it because the mouse dragged into it, the menu should close itself
// onDragExit. This timer is set in dragExit to close the menu.
_closeMenuTimer: null,
_setTimer: function TBV_DO_setTimer(time) {
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(this, time, timer.TYPE_ONE_SHOT);
return timer;
},
// Function to process all timer notifications.
notify: function TBV_DO_notify(timer) {
// Timer to open a submenu that's being dragged over.
if (timer == this._overFolder.openTimer) {
this._overFolder.node.lastChild.setAttribute("autoopened", "true");
this._overFolder.node.lastChild.showPopup(this._overFolder.node);
this._overFolder.openTimer = null;
}
// Timer to close a submenu that's been dragged off of.
if (timer == this._overFolder.closeTimer) {
// Only close the submenu if the mouse isn't being dragged over any
// of its child menus.
var draggingOverChild =
PlacesControllerDragHelper.draggingOverChildNode(this._overFolder.node);
if (draggingOverChild)
this._overFolder.node = null;
this._clearOverFolder();
// Close any parent folders which aren't being dragged over.
// (This is necessary because of the above code that keeps a folder
// open while its children are being dragged over.)
if (!draggingOverChild)
this._closeParentMenus();
}
// Timer to close this menu after the drag exit.
if (timer == this._closeMenuTimer) {
if (!PlacesControllerDragHelper.draggingOverChildNode(this._popup)) {
this._popup.hidePopup();
// Close any parent menus that aren't being dragged over;
// otherwise they'll stay open because they couldn't close
// while this menu was being dragged over.
this._closeParentMenus();
}
}
},
// Helper function to close all parent menus of this menu,
// as long as none of the parent's children are currently being
// dragged over.
_closeParentMenus: function TBV_DO_closeParentMenus() {
var parent = this._popup.parentNode;
while (parent) {
if (parent.nodeName == "menupopup" && parent._resultNode) {
if (PlacesControllerDragHelper.draggingOverChildNode(parent.parentNode))
break;
parent.hidePopup();
}
parent = parent.parentNode;
}
},
// The mouse is no longer dragging over the stored menubutton.
// Close the menubutton, clear out drag styles, and clear all
// timers for opening/closing it.
_clearOverFolder: function TBV_DO_clearOverFolder() {
if (this._overFolder.node && this._overFolder.node.lastChild) {
if (!this._overFolder.node.lastChild.hasAttribute("dragover"))
this._overFolder.node.lastChild.hidePopup();
this._overFolder.node = null;
}
if (this._overFolder.openTimer) {
this._overFolder.openTimer.cancel();
this._overFolder.openTimer = null;
}
if (this._overFolder.closeTimer) {
this._overFolder.closeTimer.cancel();
this._overFolder.closeTimer = null;
}
},
// This function returns information about where to drop when
// dragging over this menu--insertion point, child index to drop
// before, and folder to drop into.
_getDropPoint: function TBV_DO_getDropPoint(event) {
// Can't drop if the menu isn't a folder
var resultNode = this._popup._resultNode;
if (!PlacesUtils.nodeIsFolder(resultNode))
return null;
var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
// Loop through all the nodes to see which one this should
// get dropped in/above/below.
var start = 0;
var end = this._popup.childNodes.length;
if (this._popup == this._view && this._view.localName == "menupopup") {
// Ignore static content at the top and bottom of the menu.
start = this._view._startMarker + 1;
if (this._view._endMarker != -1)
end = this._view._endMarker;
}
var popupFirstChildY = this._popup.firstChild.boxObject.y;
for (var i = start; i < end; i++) {
var xulNode = this._popup.childNodes[i];
var nodeY = xulNode.boxObject.y - popupFirstChildY;
var nodeHeight = xulNode.boxObject.height;
if (xulNode.node &&
PlacesUtils.nodeIsFolder(xulNode.node) &&
!PlacesUtils.nodeIsReadOnly(xulNode.node)) {
// This is a folder. If the mouse is in the top 25% of the
// node, drop above the folder. If it's in the middle
// 50%, drop into the folder. If it's past that, drop below.
if (event.layerY < nodeY + (nodeHeight * 0.25)) {
// Drop above this folder.
dropPoint.ip = new InsertionPoint(resultNode.itemId, i - start,
-1);
dropPoint.beforeIndex = i;
return dropPoint;
}
else if (event.layerY < nodeY + (nodeHeight * 0.75)) {
// Drop inside this folder.
dropPoint.ip = new InsertionPoint(xulNode.node.itemId, -1, 1);
dropPoint.beforeIndex = i;
dropPoint.folderNode = xulNode;
return dropPoint;
}
} else {
// This is a non-folder node. If the mouse is above the middle,
// drop above the folder. Otherwise, drop below.
if (event.layerY < nodeY + (nodeHeight / 2)) {
// Drop above this bookmark.
dropPoint.ip = new InsertionPoint(resultNode.itemId, i - start, -1);
dropPoint.beforeIndex = i;
return dropPoint;
}
}
}
// Should drop below the last node.
dropPoint.ip = new InsertionPoint(resultNode.itemId, -1, 1);
dropPoint.beforeIndex = -1;
return dropPoint;
},
// This function clears all of the dragover styles that were set when
// a menuitem was dragged over.
_clearStyles: function TBV_DO_clearStyles() {
this._popup.removeAttribute("dragover");
for (var i = 0; i < this._popup.childNodes.length; i++) {
this._popup.childNodes[i].removeAttribute("dragover-top");
this._popup.childNodes[i].removeAttribute("dragover-bottom");
this._popup.childNodes[i].removeAttribute("dragover-into");
}
},
onDragStart: function TBV_DO_onDragStart(event, xferData, dragAction) {
this._view._selection = event.target.node;
this._view._cachedInsertionPoint = undefined;
if (event.ctrlKey)
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
xferData.data = this._view.controller.getTransferData(dragAction.action);
},
canDrop: function TBV_DO_canDrop(event, session) {
// Can't drop if the menu isn't a folder
var resultNode = this._popup._resultNode;
if (!PlacesUtils.nodeIsFolder(resultNode))
return null;
return PlacesControllerDragHelper.canDrop();
},
onDragOver: function TBV_DO_onDragOver(event, flavor, session) {
PlacesControllerDragHelper.currentDropTarget = event.target;
var dropPoint = this._getDropPoint(event);
if (dropPoint == null)
return;
this._clearStyles();
if (dropPoint.folderNode) {
// Dragging over a folder; set the appropriate styles.
if (this._overFolder.node != dropPoint.folderNode) {
this._clearOverFolder();
this._overFolder.node = dropPoint.folderNode;
this._overFolder.openTimer = this._setTimer(this._overFolder.hoverTime);
}
dropPoint.folderNode.setAttribute("dragover-into", "true");
}
else {
// Dragging over a menuitem, set dragover-top/bottom to show where
// the item will be dropped and clear out any old folder info.
if (dropPoint.beforeIndex == -1) {
if (this._popup == this._view && this._view.localName == "menupopup" &&
this._popup._endMarker != -1) {
this._popup.childNodes[this._popup._endMarker]
.setAttribute("dragover-top", "true");
}
else
this._popup.lastChild.setAttribute("dragover-bottom", "true");
}
else {
this._popup.childNodes[dropPoint.beforeIndex]
.setAttribute("dragover-top", "true");
}
// Clear out old folder information
this._clearOverFolder();
}
this._popup.setAttribute("dragover", "true");
},
onDrop: function TBV_DO_onDrop(event, dropData, session) {
var dropPoint = this._getDropPoint(event);
if (!dropPoint)
return;
PlacesControllerDragHelper.onDrop(dropPoint.ip);
},
onDragExit: function TBV_DO_onDragExit(event, session) {
PlacesControllerDragHelper.currentDropTarget = null;
this._clearStyles();
// Close any folder being hovered over
if (this._overFolder.node)
this._overFolder.closeTimer = this._setTimer(this._overFolder.hoverTime);
// The autoopened attribute is set when this folder was automatically
// opened after the user dragged over it. If this attribute is set,
// auto-close the folder on drag exit.
if (this._popup.hasAttribute("autoopened"))
this._closeMenuTimer = this._setTimer(this._overFolder.hoverTime);
},
getSupportedFlavours: function TBV_DO_getSupportedFlavours() {
var flavorSet = new FlavourSet();
var types = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
for (var i = 0; i < types.length; ++i)
flavorSet.appendFlavour(types[i]);
return flavorSet;
},
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "draggesture":
if (aEvent.target.node) {
nsDragAndDrop.startDrag(aEvent, this);
}
break;
case "dragover":
nsDragAndDrop.dragOver(aEvent, this);
break;
case "dragdrop":
nsDragAndDrop.drop(aEvent, this);
break;
case "dragexit":
nsDragAndDrop.dragExit(aEvent, this);
break;
}
}
}
/**
* Handles drag and drop operations for views. Note that this is view agnostic!
* You should not use PlacesController._view within these methods, since

View File

@ -23,6 +23,8 @@
# Annie Sullivan <annie.sullivan@gmail.com>
# Ben Goodger <beng@google.com>
# Asaf Romano <mano@mozilla.com>
# Simon Bünzli <zeniko@gmail.com>
# Marco Bonardo <mak77@supereva.it>
#
# 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
@ -44,8 +46,422 @@
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="places-menupopup"
<binding id="places-popup-base"
extends="chrome://global/content/bindings/popup.xml#popup">
<content>
<xul:hbox flex="1">
<xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
<xul:image class="menupopup-drop-indicator" mousethrough="always"/>
</xul:vbox>
<xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical">
<children/>
</xul:arrowscrollbox>
</xul:hbox>
</content>
<implementation>
<field name="_indicatorBar">
document.getAnonymousElementByAttribute(this, "class",
"menupopup-drop-indicator-bar");
</field>
<field name="_scrollBox">
document.getAnonymousElementByAttribute(this, "class",
"popup-internal-box");
</field>
<!-- markers for start and end of valid places items -->
<field name="_startMarker">-1</field>
<field name="_endMarker">-1</field>
<!-- This is the view that manage the popup -->
<field name="_rootView">PlacesUtils.getViewForNode(this);</field>
<method name="onDragOver">
<parameter name="aEvent"/>
<parameter name="aFlavour"/>
<parameter name="aDragSession"/>
<body><![CDATA[
PlacesControllerDragHelper.currentDropTarget = aEvent.target;
// check if we have a valid dropPoint
var dropPoint = this._getDropPoint(aEvent);
if (!dropPoint)
return;
// add a dragover attribute to this popup
this.setAttribute("dragover", "true");
if (dropPoint.folderNode) {
// We are dragging over a folder
// _overFolder should take the care of opening it on a timer
if (this._overFolder.node &&
this._overFolder.node != dropPoint.folderNode) {
// we are dragging over a new folder, let's clear old values
this._overFolder.clear();
}
if (!this._overFolder.node) {
this._overFolder.node = dropPoint.folderNode;
// create the timer to open this folder
this._overFolder.openTimer = this._overFolder
.setTimer(this._overFolder.hoverTime);
}
// since we are dropping into a folder set the corresponding style
dropPoint.folderNode.setAttribute("dragover-into", "true");
}
else {
// We are not dragging over a folder
// Clear out old _overFolder information
this._overFolder.clear();
}
// Check if we should hide the drop indicator for this target
if (!aDragSession.canDrop ||
!dropPoint || dropPoint.folderNode ||
this._hideDropIndicator(aEvent, dropPoint)) {
this._indicatorBar.hidden = true;
return;
}
var scrollBoxObject = this._scrollBox.scrollBoxObject;
// Autoscroll the popup strip if we drag over the scroll buttons
var anonid = aEvent.originalTarget.getAttribute("anonid");
var scrollDir = anonid == "scrollbutton-up" ? -1 :
anonid == "scrollbutton-down" ? 1 : 0;
if (scrollDir != 0)
this._scrollBox.scrollByIndex(scrollDir);
// We should display the drop indicator relative to the arrowscrollbox
var newMarginTop = 0;
if (scrollDir == 0) {
var node = this.firstChild;
while (node && aEvent.screenY > node.boxObject.screenY +
node.boxObject.height / 2)
node = node.nextSibling;
newMarginTop = node ? node.boxObject.screenY - scrollBoxObject.screenY :
scrollBoxObject.height;
}
else if (scrollDir == 1)
newMarginTop = scrollBoxObject.height;
// set the new marginTop based on arrowscrollbox
newMarginTop += scrollBoxObject.y - this.boxObject.y;
this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
this._indicatorBar.hidden = false;
]]></body>
</method>
<method name="onDragExit">
<parameter name="aEvent"/>
<parameter name="aDragSession"/>
<body><![CDATA[
PlacesControllerDragHelper.currentDropTarget = null;
this.removeAttribute("dragover");
// remove dragover-into style from previous target
aEvent.target.removeAttribute("dragover-into");
// if we have not moved to a valid new target clear the drop indicator
// this happens when moving out of the popup
var target = aEvent.relatedTarget;
if (!target)
this._indicatorBar.hidden = true;
// Close any folder being hovered over
if (this._overFolder.node) {
this._overFolder.closeTimer = this._overFolder
.setTimer(this._overFolder.hoverTime);
}
// The autoopened attribute is set when this folder was automatically
// opened after the user dragged over it. If this attribute is set,
// auto-close the folder on drag exit.
if (this.hasAttribute("autoopened")) {
this._overFolder.closeMenuTimer = this._overFolder
.setTimer(this._overFolder.hoverTime);
}
]]></body>
</method>
<method name="onDragStart">
<parameter name="aEvent"/>
<parameter name="aXferData"/>
<parameter name="aDragAction"/>
<body><![CDATA[
this._rootView._selection = aEvent.target.node;
this._rootView._cachedInsertionPoint = undefined;
if (aEvent.ctrlKey)
aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
aXferData.data = this._rootView.controller
.getTransferData(aDragAction.action);
]]></body>
</method>
<method name="onDrop">
<parameter name="aEvent"/>
<parameter name="aDropData"/>
<parameter name="aSession"/>
<body><![CDATA[
var dropPoint = this._getDropPoint(aEvent);
if (!dropPoint)
return;
PlacesControllerDragHelper.onDrop(dropPoint.ip);
]]></body>
</method>
<!-- This returns the FavourSet accepted by this popup -->
<method name="getSupportedFlavours">
<body><![CDATA[
var flavourSet = new FlavourSet();
var acceptedDropFlavours = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
acceptedDropFlavours.forEach(flavourSet.appendFlavour, flavourSet);
return flavourSet;
]]></body>
</method>
<!-- Check if we should hide the drop indicator for the target -->
<method name="_hideDropIndicator">
<parameter name="aEvent"/>
<body><![CDATA[
var target = aEvent.target;
// in some view we have _startMarker and _endMarker, we should not
// draw the drop indicator outside of them
var betweenMarkers = true;
if (this._startMarker != -1 &&
target.boxObject.y < this.childNodes[this._startMarker].boxObject.y)
betweenMarkers = false;
if (this._endMarker != -1 &&
target.boxObject.y > this.childNodes[this._endMarker].boxObject.y)
betweenMarkers = false;
// hide the dropmarker if current node is not a places bookmark item
return !(target && betweenMarkers && this.canDrop());
]]></body>
</method>
<!-- This function returns information about where to drop when
dragging over this popup insertion point -->
<method name="_getDropPoint">
<parameter name="aEvent"/>
<body><![CDATA[
// Can't drop if the menu isn't a folder
var resultNode = this._resultNode;
if (!PlacesUtils.nodeIsFolder(resultNode))
return null;
var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
// Loop through all the nodes to see which one this should
// get dropped in/above/below.
var start = 0;
var popup = this;
var end = popup.childNodes.length;
if (popup == this._rootView &&
this._rootView.localName == "menupopup") {
// Ignore static content at the top and bottom of the menu.
start = this._rootView._startMarker + 1;
if (this._rootView._endMarker != -1)
end = this._rootView._endMarker;
}
var popupFirstChildY = popup.firstChild.boxObject.y;
for (var i = start; i < end; i++) {
var xulNode = popup.childNodes[i];
var nodeY = xulNode.boxObject.y - popupFirstChildY;
var nodeHeight = xulNode.boxObject.height;
if (xulNode.node &&
PlacesUtils.nodeIsFolder(xulNode.node) &&
!PlacesUtils.nodeIsReadOnly(xulNode.node)) {
// This is a folder. If the mouse is in the top 25% of the
// node, drop above the folder. If it's in the middle
// 50%, drop into the folder. If it's past that, drop below.
if (aEvent.layerY < nodeY + (nodeHeight * 0.25)) {
// Drop above this folder.
dropPoint.ip = new InsertionPoint(resultNode.itemId,
i - start, -1);
dropPoint.beforeIndex = i;
return dropPoint;
}
else if (aEvent.layerY < nodeY + (nodeHeight * 0.75)) {
// Drop inside this folder.
dropPoint.ip = new InsertionPoint(xulNode.node.itemId, -1, 1);
dropPoint.beforeIndex = i;
dropPoint.folderNode = xulNode;
return dropPoint;
}
}
else {
// This is a non-folder node. If the mouse is above the middle,
// drop above the folder. Otherwise, drop below.
if (aEvent.layerY < nodeY + (nodeHeight / 2)) {
// Drop above this bookmark.
dropPoint.ip = new InsertionPoint(resultNode.itemId,
i - start, -1);
dropPoint.beforeIndex = i;
return dropPoint;
}
}
}
// Should drop below the last node.
dropPoint.ip = new InsertionPoint(resultNode.itemId, -1, 1);
dropPoint.beforeIndex = -1;
return dropPoint;
]]></body>
</method>
<method name="canDrop">
<body><![CDATA[
// Can't drop if the menu isn't a folder
var resultNode = this._rootView.getResultNode();
if (!PlacesUtils.nodeIsFolder(resultNode))
return false;
return PlacesControllerDragHelper.canDrop();
]]></body>
</method>
<!-- Sub-menus should be opened when the mouse drags over them, and closed
when the mouse drags off. The overFolder object manages opening and
closing of folders when the mouse hovers. -->
<field name="_overFolder"><![CDATA[({
_self: this,
_folder: {node: null, openTimer: null, hoverTime: 350, closeTimer: null},
_closeMenuTimer: null,
get node() {
return this._folder.node;
},
set node(val) {
return this._folder.node = val;
},
get openTimer() {
return this._folder.openTimer;
},
set openTimer(val) {
return this._folder.openTimer = val;
},
get hoverTime() {
return this._folder.hoverTime;
},
set hoverTime(val) {
return this._folder.hoverTime = val;
},
get closeTimer() {
return this._folder.closeTimer;
},
set closeTimer(val) {
return this._folder.closeTimer = val;
},
get closeMenuTimer() {
return this._closeMenuTimer;
},
set closeMenuTimer(val) {
return this._closeMenuTimer = val;
},
setTimer: function OF__setTimer(aTime) {
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(this, aTime, timer.TYPE_ONE_SHOT);
return timer;
},
notify: function OF__notify(aTimer) {
// Function to process all timer notifications.
if (aTimer == this._folder.openTimer) {
// Timer to open a submenu that's being dragged over.
this._folder.node.lastChild.setAttribute("autoopened", "true");
this._folder.node.lastChild.showPopup(this._folder.node);
this._folder.openTimer = null;
}
else if (aTimer == this._folder.closeTimer) {
// Timer to close a submenu that's been dragged off of.
// Only close the submenu if the mouse isn't being dragged over any
// of its child menus.
var draggingOverChild = PlacesControllerDragHelper
.draggingOverChildNode(this._folder.node);
if (draggingOverChild)
this._folder.node = null;
this.clear();
// Close any parent folders which aren't being dragged over.
// (This is necessary because of the above code that keeps a folder
// open while its children are being dragged over.)
if (!draggingOverChild)
this.closeParentMenus();
}
else if (aTimer == this.closeMenuTimer) {
// Timer to close this menu after the drag exit.
var popup = this._self;
if (!PlacesControllerDragHelper.draggingOverChildNode(popup.parentNode)) {
popup.hidePopup();
// Close any parent menus that aren't being dragged over;
// otherwise they'll stay open because they couldn't close
// while this menu was being dragged over.
this.closeParentMenus();
}
}
},
// Helper function to close all parent menus of this menu,
// as long as none of the parent's children are currently being
// dragged over.
closeParentMenus: function OF__closeParentMenus() {
var popup = this._self;
var parent = popup.parentNode;
while (parent) {
if (parent.nodeName == "menupopup" && parent._resultNode) {
if (PlacesControllerDragHelper.draggingOverChildNode(parent.parentNode))
break;
parent.hidePopup();
}
parent = parent.parentNode;
}
},
// The mouse is no longer dragging over the stored menubutton.
// Close the menubutton, clear out drag styles, and clear all
// timers for opening/closing it.
clear: function OF__clear() {
if (this._folder.node && this._folder.node.lastChild) {
if (!this._folder.node.lastChild.hasAttribute("dragover"))
this._folder.node.lastChild.hidePopup();
// remove dragover-into style
this._folder.node.removeAttribute("dragover-into");
this._folder.node = null;
}
if (this._folder.openTimer) {
this._folder.openTimer.cancel();
this._folder.openTimer = null;
}
if (this._folder.closeTimer) {
this._folder.closeTimer.cancel();
this._folder.closeTimer = null;
}
}
})]]></field>
</implementation>
<handlers>
<handler event="draggesture" action="if (event.target.node) nsDragAndDrop.startDrag(event, this);"/>
<handler event="dragdrop" action="nsDragAndDrop.drop(event, this);"/>
<handler event="dragover" action="nsDragAndDrop.dragOver(event, this);"/>
<handler event="dragexit" action="nsDragAndDrop.dragExit(event, this);"/>
</handlers>
</binding>
<binding id="places-menupopup"
extends="chrome://browser/content/places/menu.xml#places-popup-base">
<implementation>
<destructor><![CDATA[
this._resultNode = null;
@ -88,8 +504,6 @@
resultNode.containerOpen = true;
if (!popup._built)
this._rebuild(popup);
if (!popup._DNDObserver)
popup._DNDObserver = new PlacesMenuDNDObserver(this, popup);
]]></body>
</method>
@ -572,13 +986,13 @@
</method>
</implementation>
<handlers>
<handler event="popupshowing" phase="capturing">
<handler event="popupshowing" phase="capturing"><![CDATA[
this._ensureInitialized();
if (event.target._resultNode)
this.onPopupShowing(event);
</handler>
]]></handler>
<handler event="popuphidden">
<handler event="popuphidden"><![CDATA[
var popup = event.target;
if (!popup._resultNode)
return;
@ -592,7 +1006,7 @@
// automatically opened when dragged over. Turn off this attribute
// when the folder closes because it is no longer applicable.
popup.removeAttribute("autoopened");
</handler>
]]></handler>
<!-- Set selected node on DOMMenuItemActive/contextmenu events
so that they're set up when command and click events fire. -->

View File

@ -10,3 +10,7 @@ hbox[type="places"] {
menupopup[type="places"] {
-moz-binding: url("chrome://browser/content/places/menu.xml#places-menupopup");
}
menupopup[placespopup="true"] {
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
}

View File

@ -199,6 +199,7 @@
button.setAttribute("livemark", "true");
var popup = document.createElement("menupopup");
popup.setAttribute("placespopup", "true");
button.appendChild(popup);
popup._result = this._result;
popup._resultNode = asContainer(aChild);
@ -1014,9 +1015,6 @@
this._showEmptyMenuItem(aPopup);
}
aPopup._built = true;
if (!aPopup._DNDObserver)
aPopup._DNDObserver = new PlacesMenuDNDObserver(this, aPopup);
]]></body>
</method>

View File

@ -1795,7 +1795,7 @@ var PlacesUtils = {
if (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY)
element.setAttribute("query", "true");
else if (aNode.itemId != -1) {
else if (aNode.itemId != -1) {
if (this.nodeIsLivemarkContainer(aNode))
element.setAttribute("livemark", "true");
else if (this.bookmarks
@ -1804,6 +1804,7 @@ var PlacesUtils = {
}
var popup = document.createElement("menupopup");
popup.setAttribute("placespopup", "true");
popup._resultNode = asContainer(aNode);
#ifndef XP_MACOSX
// no context menu on mac

View File

@ -138,23 +138,26 @@ menuitem.bookmark-item {
}
/* Bookmark drag and drop styles */
.bookmark-item[dragover-left="true"] {
-moz-border-left-colors: #000000;
}
.bookmark-item[dragover-right="true"] {
-moz-border-right-colors: #000000;
}
.bookmark-item[dragover-top="true"] {
-moz-border-top-colors: #000000;
}
.bookmark-item[dragover-bottom="true"] {
-moz-border-bottom-colors: #000000;
}
.bookmark-item[dragover-into="true"] {
background: Highlight !important;
color: HighlightText !important;
}
/* rules for menupopup drop indicators */
.menupopup-drop-indicator-bar {
position: relative;
/* these two margins must together compensate the indicator's height */
margin-top: -1px;
margin-bottom: -1px;
}
.menupopup-drop-indicator {
list-style-image: none;
height: 2px;
-moz-margin-end: -4em;
background-color: Highlight;
}
.toolbar-drop-indicator {
width: 9px;
height: 18px;

View File

@ -239,20 +239,6 @@ toolbarpaletteitem[place="toolbar"] .places-toolbar-items {
height: 16px;
}
/* ----- DRAG AND DROP STYLES ----- */
.bookmark-item[dragover-left="true"] {
-moz-border-left-colors: #000000;
}
.bookmark-item[dragover-right="true"] {
-moz-border-right-colors: #000000;
}
.bookmark-item[dragover-top="true"] {
-moz-border-top-colors: #000000;
}
.bookmark-item[dragover-bottom="true"] {
-moz-border-bottom-colors: #000000;
}
/* ----- PRIMARY TOOLBAR BUTTONS ----- */
.toolbarbutton-1 {
@ -1280,17 +1266,25 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
-moz-image-region: rect(0px, 16px, 16px, 0px) !important;
}
/* Bookmark drag and drop styles */
.bookmark-item[dragover-into="true"] {
background: Highlight !important;
color: HighlightText !important;
}
.bookmark-item[dragover-top="true"] {
-moz-border-top-colors: #000000;
/* rules for menupopup drop indicators */
.menupopup-drop-indicator-bar {
position: relative;
/* these two margins must together compensate the indicator's height */
margin-top: -1px;
margin-bottom: -1px;
}
.bookmark-item[dragover-bottom="true"] {
-moz-border-bottom-colors: #000000;
.menupopup-drop-indicator {
list-style-image: none;
height: 2px;
-moz-margin-end: -4em;
background-color: Highlight;
}
#CustomizeToolbarSheet > #main-box {

View File

@ -146,22 +146,6 @@ menuitem.bookmark-item {
-moz-padding-start: 0px;
}
/* ..... drag and drop styles ..... */
.bookmark-item[dragover-left="true"] {
-moz-border-left-colors: #000000;
}
.bookmark-item[dragover-right="true"] {
-moz-border-right-colors: #000000;
}
.bookmark-item[dragover-top="true"] {
-moz-border-top-colors: #000000;
}
.bookmark-item[dragover-bottom="true"] {
-moz-border-bottom-colors: #000000;
}
/* ::::: bookmark items ::::: */
.bookmark-item {
@ -1696,17 +1680,25 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
-moz-image-region: rect(0px, 16px, 16px, 0px) !important;
}
.bookmark-item[dragover-into="true"] {
/* Bookmark drag and drop styles */
.bookmark-item[dragover-into="true"] > .menu-iconic-text {
background: Highlight !important;
color: HighlightText !important;
}
.bookmark-item[dragover-top="true"] {
-moz-border-top-colors: #000000;
/* rules for menupopup drop indicators */
.menupopup-drop-indicator-bar {
position: relative;
/* these two margins must together compensate the indicator's height */
margin-top: -1px;
margin-bottom: -1px;
}
.bookmark-item[dragover-bottom="true"] {
-moz-border-bottom-colors: #000000;
.menupopup-drop-indicator {
list-style-image: none;
height: 2px;
-moz-margin-end: -4em;
background-color: Highlight;
}
/* ::::: Identity Indicator Styling ::::: */