зеркало из https://github.com/mozilla/pjs.git
bug 142215 - Personal Toolbar folders should work like main menu (open on mouseover), p=paradigmk@technodrome.com r=Neil
This commit is contained in:
Родитель
1b733ca296
Коммит
594c667912
|
@ -261,6 +261,9 @@
|
|||
|
||||
<toolbar id="PersonalToolbar" class="chromeclass-directories" persist="collapsed"
|
||||
grippytooltiptext="&personalToolbar.tooltip;" tbalign="stretch" prefixhidden="true"
|
||||
onmouseover="BookmarksToolbar.autoOpenMenu(event.target);"
|
||||
onpopupshowing="BookmarksToolbar.onMenuOpen(event.target);"
|
||||
onpopuphidden="BookmarksToolbar.onMenuClose(event.target);"
|
||||
ondraggesture="nsDragAndDrop.startDrag(event, BookmarksMenuDNDObserver)"
|
||||
ondragdrop="nsDragAndDrop.drop(event, BookmarksMenuDNDObserver); event.stopPropagation()"
|
||||
ondragenter="nsDragAndDrop.dragEnter(event, BookmarksMenuDNDObserver); event.stopPropagation()"
|
||||
|
|
|
@ -1,859 +0,0 @@
|
|||
/* -*- Mode: Java; 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
|
||||
* Pierre Chanial <chanial@noos.fr>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
var BookmarksMenu = {
|
||||
_selection:null,
|
||||
_target:null,
|
||||
_orientation:null,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Fill a context menu popup with menuitems appropriate for the current
|
||||
// selection.
|
||||
createContextMenu: function (aEvent)
|
||||
{
|
||||
var target = document.popupNode;
|
||||
if (!this.isBTBookmark(target.id) && target.id != "bookmarks-ptf")
|
||||
return false;
|
||||
target.focus() // buttons in the pt have -moz-user-focus: ignore -->
|
||||
this._selection = this.getBTSelection(target);
|
||||
this._orientation = this.getBTOrientation(aEvent, target);
|
||||
this._target = this.getBTTarget(target, this._orientation);
|
||||
BookmarksCommand.createContextMenu(aEvent, this._selection);
|
||||
this.onCommandUpdate();
|
||||
aEvent.target.addEventListener("mousemove", BookmarksMenuController.onMouseMove, false);
|
||||
return true;
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Clean up after closing the context menu popup
|
||||
destroyContextMenu: function (aEvent)
|
||||
{
|
||||
if (content)
|
||||
content.focus();
|
||||
BookmarksMenuDNDObserver.onDragRemoveFeedBack(document.popupNode); // needed on cancel
|
||||
aEvent.target.removeEventListener("mousemove", BookmarksMenuController.onMouseMove, false);
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// returns the formatted selection from aNode
|
||||
getBTSelection: function (aNode)
|
||||
{
|
||||
var item;
|
||||
switch (aNode.id) {
|
||||
case "bookmarks-ptf":
|
||||
item = "NC:PersonalToolbarFolder";
|
||||
break;
|
||||
case "BookmarksMenu":
|
||||
item = "NC:BookmarksRoot";
|
||||
break;
|
||||
default:
|
||||
item = aNode.id;
|
||||
}
|
||||
if (!this.isBTBookmark(item))
|
||||
return {length:0};
|
||||
var parent = this.getBTContainer(aNode);
|
||||
var isExpanded = aNode.hasAttribute("open") && aNode.open;
|
||||
var selection = {};
|
||||
selection.item = [RDF.GetResource(item)];
|
||||
selection.parent = [RDF.GetResource(parent)];
|
||||
selection.isExpanded = [isExpanded];
|
||||
selection.length = selection.item.length;
|
||||
BookmarksUtils.checkSelection(selection);
|
||||
return selection;
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// returns the insertion target from aNode
|
||||
getBTTarget: function (aNode, aOrientation)
|
||||
{
|
||||
var item, parent, index;
|
||||
|
||||
switch (aNode.id) {
|
||||
case "BookmarksMenu":
|
||||
case "bookmarks-button":
|
||||
parent = "NC:BookmarksRoot";
|
||||
break;
|
||||
case "bookmarks-ptf":
|
||||
item = BookmarksToolbar.getLastVisibleBookmark();
|
||||
// Continue to next case.
|
||||
case "bookmarks-chevron":
|
||||
parent = "NC:PersonalToolbarFolder";
|
||||
break;
|
||||
default:
|
||||
if (aOrientation == BookmarksUtils.DROP_ON)
|
||||
parent = aNode.id
|
||||
else {
|
||||
parent = this.getBTContainer(aNode);
|
||||
item = aNode;
|
||||
}
|
||||
}
|
||||
|
||||
parent = RDF.GetResource(parent);
|
||||
if (aOrientation == BookmarksUtils.DROP_ON)
|
||||
return BookmarksUtils.getTargetFromFolder(parent);
|
||||
|
||||
item = RDF.GetResource(item.id);
|
||||
RDFC.Init(BMDS, parent);
|
||||
index = RDFC.IndexOf(item);
|
||||
if (aOrientation == BookmarksUtils.DROP_AFTER)
|
||||
++index;
|
||||
|
||||
return { parent: parent, index: index };
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// returns the parent resource of a node in the personal toolbar.
|
||||
// this is determined by inspecting the source element and walking up the
|
||||
// DOM tree to find the appropriate containing node.
|
||||
getBTContainer: function (aNode)
|
||||
{
|
||||
var parent;
|
||||
var item = aNode.id;
|
||||
if (!this.isBTBookmark(item))
|
||||
return "NC:BookmarksRoot"
|
||||
parent = aNode.parentNode.parentNode;
|
||||
parent = parent.id;
|
||||
switch (parent) {
|
||||
case "BookmarksMenu":
|
||||
case "bookmarks-button":
|
||||
return "NC:BookmarksRoot";
|
||||
case "PersonalToolbar":
|
||||
case "bookmarks-chevron":
|
||||
return "NC:PersonalToolbarFolder";
|
||||
default:
|
||||
return parent;
|
||||
}
|
||||
},
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// returns true if the node is a bookmark, a folder or a bookmark separator
|
||||
isBTBookmark: function (aURI)
|
||||
{
|
||||
if (!aURI)
|
||||
return false;
|
||||
var type = BookmarksUtils.resolveType(aURI);
|
||||
return (type == "BookmarkSeparator" ||
|
||||
type == "Bookmark" ||
|
||||
type == "Folder" ||
|
||||
type == "FolderGroup" ||
|
||||
type == "PersonalToolbarFolder")
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// returns true if the node is a container. -->
|
||||
isBTContainer: function (aTarget)
|
||||
{
|
||||
return aTarget.localName == "menu" || (aTarget.localName == "toolbarbutton" &&
|
||||
(aTarget.getAttribute("container") == "true" || aTarget.getAttribute("group") == "true"));
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// returns BookmarksUtils.DROP_BEFORE, DROP_ON or DROP_AFTER accordingly
|
||||
// to the event coordinates. Skin authors could break us, we'll cross that
|
||||
// bridge when they turn us 90degrees. -->
|
||||
getBTOrientation: function (aEvent, aTarget)
|
||||
{
|
||||
var target
|
||||
if (!aTarget)
|
||||
target = aEvent.target;
|
||||
else
|
||||
target = aTarget;
|
||||
if (target.localName == "menu" &&
|
||||
target.parentNode.localName != "menupopup")
|
||||
return BookmarksUtils.DROP_ON;
|
||||
if (target.id == "bookmarks-ptf") {
|
||||
return target.hasChildNodes() ?
|
||||
BookmarksUtils.DROP_AFTER : BookmarksUtils.DROP_ON;
|
||||
}
|
||||
if (target.id == "bookmarks-chevron")
|
||||
return BookmarksUtils.DROP_ON;
|
||||
|
||||
var overButtonBoxObject = target.boxObject.QueryInterface(Components.interfaces.nsIBoxObject);
|
||||
var overParentBoxObject = target.parentNode.boxObject.QueryInterface(Components.interfaces.nsIBoxObject);
|
||||
|
||||
var size, border;
|
||||
var coordValue, clientCoordValue;
|
||||
switch (target.localName) {
|
||||
case "toolbarseparator":
|
||||
case "toolbarbutton":
|
||||
size = overButtonBoxObject.width;
|
||||
coordValue = overButtonBoxObject.x;
|
||||
clientCoordValue = aEvent.clientX;
|
||||
break;
|
||||
case "menuseparator":
|
||||
case "menu":
|
||||
case "menuitem":
|
||||
size = overButtonBoxObject.height;
|
||||
coordValue = overButtonBoxObject.screenY;
|
||||
clientCoordValue = aEvent.screenY;
|
||||
break;
|
||||
default: return BookmarksUtils.DROP_ON;
|
||||
}
|
||||
if (this.isBTContainer(target))
|
||||
if (target.localName == "toolbarbutton") {
|
||||
// the DROP_BEFORE area excludes the label
|
||||
var iconNode = document.getAnonymousElementByAttribute(target, "class", "toolbarbutton-icon");
|
||||
border = parseInt(document.defaultView.getComputedStyle(target,"").getPropertyValue("padding-left")) +
|
||||
parseInt(document.defaultView.getComputedStyle(iconNode ,"").getPropertyValue("width"));
|
||||
border = Math.min(size/5,Math.max(border,4));
|
||||
} else
|
||||
border = size/5;
|
||||
else
|
||||
border = size/2;
|
||||
|
||||
// in the first region?
|
||||
if (clientCoordValue-coordValue < border)
|
||||
return BookmarksUtils.DROP_BEFORE;
|
||||
// in the last region?
|
||||
if (clientCoordValue-coordValue >= size-border)
|
||||
return BookmarksUtils.DROP_AFTER;
|
||||
// must be in the middle somewhere
|
||||
return BookmarksUtils.DROP_ON;
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// expand the folder targeted by the context menu.
|
||||
expandBTFolder: function ()
|
||||
{
|
||||
var target = document.popupNode.lastChild;
|
||||
if (document.popupNode.open)
|
||||
target.hidePopup();
|
||||
else
|
||||
target.showPopup(document.popupNode);
|
||||
},
|
||||
|
||||
onCommandUpdate: function ()
|
||||
{
|
||||
var selection = this._selection;
|
||||
var target = this._target;
|
||||
BookmarksController.onCommandUpdate(selection, target);
|
||||
if (document.popupNode.id == "bookmarks-ptf") {
|
||||
// disabling 'cut' and 'copy' on the empty area of the personal toolbar
|
||||
var commandNode = document.getElementById("cmd_bm_cut");
|
||||
commandNode.setAttribute("disabled", "true");
|
||||
commandNode = document.getElementById("cmd_bm_copy");
|
||||
commandNode.setAttribute("disabled", "true");
|
||||
}
|
||||
},
|
||||
|
||||
loadBookmark: function (aEvent, aDS)
|
||||
{
|
||||
if (this.isBTBookmark(aEvent.target.id))
|
||||
BookmarksUtils.loadBookmarkBrowser(aEvent, aDS);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// loads a bookmark with the middle mouse button
|
||||
loadBookmarkMiddleClick: function (aEvent, aDS)
|
||||
{
|
||||
if (aEvent.type != "click" || aEvent.button != 1)
|
||||
return;
|
||||
// unlike for command events, we have to close the menus manually
|
||||
for (var node = aEvent.target; node != aEvent.currentTarget;
|
||||
node = node.parentNode) {
|
||||
if (node.nodeType == node.ELEMENT_NODE && node.tagName == "menupopup")
|
||||
node.hidePopup();
|
||||
}
|
||||
this.loadBookmark(aEvent, aDS);
|
||||
}
|
||||
}
|
||||
|
||||
var BookmarksMenuController = {
|
||||
|
||||
supportsCommand: BookmarksController.supportsCommand,
|
||||
|
||||
isCommandEnabled: function (aCommand)
|
||||
{
|
||||
// warning: this is not the function called in BookmarksController.onCommandUpdate
|
||||
var selection = BookmarksMenu._selection;
|
||||
var target = BookmarksMenu._target;
|
||||
if (selection)
|
||||
return BookmarksController.isCommandEnabled(aCommand, selection, target);
|
||||
return false;
|
||||
},
|
||||
|
||||
doCommand: function (aCommand)
|
||||
{
|
||||
BookmarksMenuDNDObserver.onDragRemoveFeedBack(document.popupNode);
|
||||
var selection = BookmarksMenu._selection;
|
||||
var target = BookmarksMenu._target;
|
||||
switch (aCommand) {
|
||||
case "cmd_bm_expandfolder":
|
||||
setTimeout(BookmarksMenu.expandBTFolder, 0);
|
||||
break;
|
||||
default:
|
||||
BookmarksController.doCommand(aCommand, selection, target);
|
||||
}
|
||||
},
|
||||
|
||||
onMouseMove: function (aEvent)
|
||||
{
|
||||
var command = aEvent.target.getAttribute("command");
|
||||
var isDisabled = aEvent.target.getAttribute("disabled")
|
||||
if (isDisabled != "true" && (command == "cmd_bm_newfolder" || command == "cmd_bm_paste")) {
|
||||
BookmarksMenuDNDObserver.onDragSetFeedBack(document.popupNode, BookmarksMenu._orientation);
|
||||
} else {
|
||||
BookmarksMenuDNDObserver.onDragRemoveFeedBack(document.popupNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var BookmarksMenuDNDObserver = {
|
||||
|
||||
////////////////////
|
||||
// Public methods //
|
||||
////////////////////
|
||||
|
||||
onDragStart: function (aEvent, aXferData, aDragAction)
|
||||
{
|
||||
var target = aEvent.target;
|
||||
|
||||
// Prevent dragging from an invalid region
|
||||
if (!this.canDrop(aEvent))
|
||||
return;
|
||||
|
||||
// Prevent dragging out of menupopups on non Win32 platforms.
|
||||
// a) on Mac drag from menus is generally regarded as being satanic
|
||||
// b) on Linux, this causes an X-server crash, (bug 151336)
|
||||
// c) on Windows, there is no hang or crash associated with this, so we'll leave
|
||||
// the functionality there.
|
||||
if (navigator.platform != "Win32" && target.localName != "toolbarbutton")
|
||||
return;
|
||||
|
||||
// bail if dragging from the empty area of the bookmarks toolbar
|
||||
if (target.id == "bookmarks-ptf")
|
||||
return
|
||||
|
||||
// a drag start is fired when leaving an open toolbarbutton(type=menu)
|
||||
// (see bug 143031)
|
||||
if (this.isContainer(target) &&
|
||||
target.getAttribute("group") != "true") {
|
||||
if (this.isPlatformNotSupported)
|
||||
return;
|
||||
if (!aEvent.shiftKey && !aEvent.altKey && !aEvent.ctrlKey)
|
||||
return;
|
||||
// menus open on mouse down
|
||||
target.firstChild.hidePopup();
|
||||
}
|
||||
var selection = BookmarksMenu.getBTSelection(target);
|
||||
aXferData.data = BookmarksUtils.getXferDataFromSelection(selection);
|
||||
},
|
||||
|
||||
onDragOver: function(aEvent, aFlavour, aDragSession)
|
||||
{
|
||||
var orientation = BookmarksMenu.getBTOrientation(aEvent)
|
||||
if (aDragSession.canDrop)
|
||||
this.onDragSetFeedBack(aEvent.target, orientation);
|
||||
if (orientation != this.mCurrentDropPosition) {
|
||||
// emulating onDragExit and onDragEnter events since the drop region
|
||||
// has changed on the target.
|
||||
this.onDragExit(aEvent, aDragSession);
|
||||
this.onDragEnter(aEvent, aDragSession);
|
||||
}
|
||||
if (this.isPlatformNotSupported)
|
||||
return;
|
||||
if (this.isTimerSupported || !aDragSession.sourceNode)
|
||||
return;
|
||||
this.onDragOverCheckTimers();
|
||||
},
|
||||
|
||||
onDragEnter: function (aEvent, aDragSession)
|
||||
{
|
||||
var target = aEvent.target;
|
||||
var orientation = BookmarksMenu.getBTOrientation(aEvent);
|
||||
if (target.localName == "menupopup" || target.id == "bookmarks-ptf")
|
||||
target = target.parentNode;
|
||||
if (aDragSession.canDrop) {
|
||||
this.onDragSetFeedBack(target, orientation);
|
||||
this.onDragEnterSetTimer(target, aDragSession);
|
||||
}
|
||||
this.mCurrentDragOverTarget = target;
|
||||
this.mCurrentDropPosition = orientation;
|
||||
},
|
||||
|
||||
onDragExit: function (aEvent, aDragSession)
|
||||
{
|
||||
var target = aEvent.target;
|
||||
if (target.localName == "menupopup" || target.id == "bookmarks-ptf")
|
||||
target = target.parentNode;
|
||||
this.onDragRemoveFeedBack(target);
|
||||
this.onDragExitSetTimer(target, aDragSession);
|
||||
this.mCurrentDragOverTarget = null;
|
||||
this.mCurrentDropPosition = null;
|
||||
},
|
||||
|
||||
onDrop: function (aEvent, aXferData, aDragSession)
|
||||
{
|
||||
var target = aEvent.target;
|
||||
this.onDragRemoveFeedBack(target);
|
||||
|
||||
var selection = BookmarksUtils.getSelectionFromXferData(aDragSession);
|
||||
|
||||
var orientation = BookmarksMenu.getBTOrientation(aEvent);
|
||||
|
||||
// For RTL PersonalBar bookmarks buttons, orientation should be inverted (only in drop case)
|
||||
// because "before" (to the left) on the screen translates to "after" in the collection of items.
|
||||
if (target.localName == "toolbarbutton")
|
||||
if (window.getComputedStyle(document.getElementById("PersonalToolbar"),'').direction == 'rtl')
|
||||
if (orientation == BookmarksUtils.DROP_AFTER)
|
||||
orientation = BookmarksUtils.DROP_BEFORE;
|
||||
else if (orientation == BookmarksUtils.DROP_BEFORE)
|
||||
orientation = BookmarksUtils.DROP_AFTER;
|
||||
|
||||
var selTarget = BookmarksMenu.getBTTarget(target, orientation);
|
||||
|
||||
const kDSIID = Components.interfaces.nsIDragService;
|
||||
const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
|
||||
|
||||
// hide the 'open in tab' menuseparator because bookmarks
|
||||
// can be inserted after it if they are dropped after the last bookmark
|
||||
// a more comprehensive fix would be in the menupopup template builder
|
||||
var menuTarget = (target.localName == "toolbarbutton" ||
|
||||
target.localName == "menu") &&
|
||||
orientation == BookmarksUtils.DROP_ON?
|
||||
target.lastChild:target.parentNode;
|
||||
if (menuTarget.hasChildNodes() &&
|
||||
menuTarget.lastChild.id == "openintabs-menuitem") {
|
||||
menuTarget.removeChild(menuTarget.lastChild.previousSibling);
|
||||
}
|
||||
|
||||
if (aDragSession.dragAction & kCopyAction)
|
||||
BookmarksUtils.insertSelection("drag", selection, selTarget);
|
||||
else
|
||||
BookmarksUtils.moveSelection("drag", selection, selTarget);
|
||||
|
||||
var chevron = document.getElementById("bookmarks-chevron");
|
||||
if (chevron.getAttribute("open") == "true") {
|
||||
BookmarksToolbar.resizeFunc(null);
|
||||
BookmarksToolbar.updateOverflowMenu(document.getElementById("bookmarks-chevron-popup"));
|
||||
}
|
||||
|
||||
// show again the menuseparator
|
||||
if (menuTarget.hasChildNodes() &&
|
||||
menuTarget.lastChild.id == "openintabs-menuitem") {
|
||||
var element = document.createElementNS(XUL_NS, "menuseparator");
|
||||
menuTarget.insertBefore(element, menuTarget.lastChild);
|
||||
}
|
||||
},
|
||||
|
||||
canDrop: function (aEvent, aDragSession)
|
||||
{
|
||||
var target = aEvent.target;
|
||||
|
||||
// onDragStart calls this without a drag session
|
||||
// There will be no sourceNode for drags from external apps
|
||||
if (aDragSession && aDragSession.sourceNode) {
|
||||
var orientation = BookmarksMenu.getBTOrientation(aEvent, target);
|
||||
if (target == aDragSession.sourceNode ||
|
||||
(target == aDragSession.sourceNode.previousSibling &&
|
||||
orientation == BookmarksUtils.DROP_AFTER) ||
|
||||
(target == aDragSession.sourceNode.nextSibling &&
|
||||
orientation == BookmarksUtils.DROP_BEFORE))
|
||||
return false;
|
||||
}
|
||||
|
||||
return BookmarksMenu.isBTBookmark(target.id) &&
|
||||
target.id != "NC:SystemBookmarksStaticRoot" &&
|
||||
target.id.substring(0,5) != "find:" ||
|
||||
target.id == "BookmarksMenu" ||
|
||||
target.id == "bookmarks-button" ||
|
||||
target.id == "bookmarks-chevron" ||
|
||||
target.id == "bookmarks-ptf";
|
||||
},
|
||||
|
||||
canHandleMultipleItems: true,
|
||||
|
||||
getSupportedFlavours: function ()
|
||||
{
|
||||
var flavourSet = new FlavourSet();
|
||||
flavourSet.appendFlavour("moz/rdfitem");
|
||||
flavourSet.appendFlavour("text/x-moz-url");
|
||||
flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
|
||||
flavourSet.appendFlavour("text/unicode");
|
||||
return flavourSet;
|
||||
},
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// Private methods and properties //
|
||||
////////////////////////////////////
|
||||
|
||||
springLoadedMenuDelay: 350, // milliseconds
|
||||
isPlatformNotSupported: navigator.platform.indexOf("Mac") != -1, // see bug 136524
|
||||
// Needs to be dynamically overridden (to |true|) in the case of an external drag: see bug 232795.
|
||||
isTimerSupported: navigator.platform.indexOf("Win") == -1,
|
||||
|
||||
mCurrentDragOverTarget: null,
|
||||
mCurrentDropPosition: null,
|
||||
loadTimer : null,
|
||||
closeTimer : null,
|
||||
loadTarget : null,
|
||||
closeTarget: null,
|
||||
|
||||
_observers : null,
|
||||
get mObservers ()
|
||||
{
|
||||
if (!this._observers) {
|
||||
this._observers = [
|
||||
document.getElementById("bookmarks-ptf"),
|
||||
document.getElementById("BookmarksMenu").parentNode,
|
||||
document.getElementById("bookmarks-chevron").parentNode,
|
||||
document.getElementById("PersonalToolbar")
|
||||
]
|
||||
}
|
||||
return this._observers;
|
||||
},
|
||||
|
||||
getObserverForNode: function (aNode)
|
||||
{
|
||||
if (!aNode)
|
||||
return null;
|
||||
var node = aNode;
|
||||
var observer;
|
||||
do {
|
||||
for (var i=0; i < this.mObservers.length; i++) {
|
||||
observer = this.mObservers[i];
|
||||
if (observer == node)
|
||||
return observer;
|
||||
}
|
||||
node = node.parentNode;
|
||||
} while (node != document)
|
||||
return null;
|
||||
},
|
||||
|
||||
onDragCloseMenu: function (aNode)
|
||||
{
|
||||
var children = aNode.childNodes;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (this.isContainer(children[i]) &&
|
||||
children[i].getAttribute("open") == "true") {
|
||||
this.onDragCloseMenu(children[i].lastChild);
|
||||
if (children[i] != this.mCurrentDragOverTarget || this.mCurrentDropPosition != BookmarksUtils.DROP_ON)
|
||||
children[i].lastChild.hidePopup();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onDragCloseTarget: function ()
|
||||
{
|
||||
var currentObserver = this.getObserverForNode(this.mCurrentDragOverTarget);
|
||||
// close all the menus not hovered by the mouse
|
||||
for (var i=0; i < this.mObservers.length; i++) {
|
||||
if (currentObserver != this.mObservers[i])
|
||||
this.onDragCloseMenu(this.mObservers[i]);
|
||||
else
|
||||
this.onDragCloseMenu(this.mCurrentDragOverTarget.parentNode);
|
||||
}
|
||||
},
|
||||
|
||||
onDragLoadTarget: function (aTarget)
|
||||
{
|
||||
if (!this.mCurrentDragOverTarget)
|
||||
return;
|
||||
// Load the current menu
|
||||
if (this.mCurrentDropPosition == BookmarksUtils.DROP_ON &&
|
||||
this.isContainer(aTarget) &&
|
||||
aTarget.getAttribute("group") != "true")
|
||||
aTarget.lastChild.showPopup(aTarget);
|
||||
},
|
||||
|
||||
onDragOverCheckTimers: function ()
|
||||
{
|
||||
var now = new Date().getTime();
|
||||
if (this.closeTimer && now-this.springLoadedMenuDelay>this.closeTimer) {
|
||||
this.onDragCloseTarget();
|
||||
this.closeTimer = null;
|
||||
}
|
||||
if (this.loadTimer && (now-this.springLoadedMenuDelay>this.loadTimer)) {
|
||||
this.onDragLoadTarget(this.loadTarget);
|
||||
this.loadTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
onDragEnterSetTimer: function (aTarget, aDragSession)
|
||||
{
|
||||
if (this.isPlatformNotSupported)
|
||||
return;
|
||||
if (this.isTimerSupported || !aDragSession.sourceNode) {
|
||||
var targetToBeLoaded = aTarget;
|
||||
clearTimeout(this.loadTimer);
|
||||
if (aTarget == aDragSession.sourceNode)
|
||||
return;
|
||||
var This = this;
|
||||
this.loadTimer=setTimeout(function () {This.onDragLoadTarget(targetToBeLoaded)}, This.springLoadedMenuDelay);
|
||||
} else {
|
||||
var now = new Date().getTime();
|
||||
this.loadTimer = now;
|
||||
this.loadTarget = aTarget;
|
||||
}
|
||||
},
|
||||
|
||||
onDragExitSetTimer: function (aTarget, aDragSession)
|
||||
{
|
||||
if (this.isPlatformNotSupported)
|
||||
return;
|
||||
var This = this;
|
||||
if (this.isTimerSupported || !aDragSession.sourceNode) {
|
||||
clearTimeout(this.closeTimer)
|
||||
this.closeTimer=setTimeout(function () {This.onDragCloseTarget()}, This.springLoadedMenuDelay);
|
||||
} else {
|
||||
var now = new Date().getTime();
|
||||
this.closeTimer = now;
|
||||
this.closeTarget = aTarget;
|
||||
this.loadTimer = null;
|
||||
|
||||
// If the user isn't rearranging within the menu, close it
|
||||
// To do so, we exploit a Mac bug: timeout set during
|
||||
// drag and drop on Windows and Mac are fired only after that the drop is released.
|
||||
// timeouts will pile up, we may have a better approach but for the moment, this one
|
||||
// correctly close the menus after a drop/cancel outside the personal toolbar.
|
||||
// The if statement in the function has been introduced to deal with rare but reproducible
|
||||
// missing Exit events.
|
||||
if (aDragSession.sourceNode.localName != "menuitem" && aDragSession.sourceNode.localName != "menu")
|
||||
setTimeout(function () { if (This.mCurrentDragOverTarget) {This.onDragRemoveFeedBack(This.mCurrentDragOverTarget); This.mCurrentDragOverTarget=null} This.loadTimer=null; This.onDragCloseTarget() }, 0);
|
||||
}
|
||||
},
|
||||
|
||||
onDragSetFeedBack: function (aTarget, aOrientation)
|
||||
{
|
||||
switch (aTarget.localName) {
|
||||
case "toolbarseparator":
|
||||
case "toolbarbutton":
|
||||
switch (aOrientation) {
|
||||
case BookmarksUtils.DROP_BEFORE:
|
||||
aTarget.setAttribute("dragover-left", "true");
|
||||
break;
|
||||
case BookmarksUtils.DROP_AFTER:
|
||||
aTarget.setAttribute("dragover-right", "true");
|
||||
break;
|
||||
case BookmarksUtils.DROP_ON:
|
||||
aTarget.setAttribute("dragover-top" , "true");
|
||||
aTarget.setAttribute("dragover-bottom", "true");
|
||||
aTarget.setAttribute("dragover-left" , "true");
|
||||
aTarget.setAttribute("dragover-right" , "true");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "menuseparator":
|
||||
case "menu":
|
||||
case "menuitem":
|
||||
switch (aOrientation) {
|
||||
case BookmarksUtils.DROP_BEFORE:
|
||||
aTarget.setAttribute("dragover-top", "true");
|
||||
break;
|
||||
case BookmarksUtils.DROP_AFTER:
|
||||
aTarget.setAttribute("dragover-bottom", "true");
|
||||
break;
|
||||
case BookmarksUtils.DROP_ON:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "toolbar":
|
||||
var newTarget = BookmarksToolbar.getLastVisibleBookmark();
|
||||
if (newTarget)
|
||||
newTarget.setAttribute("dragover-right", "true");
|
||||
break;
|
||||
case "hbox":
|
||||
case "menupopup": break;
|
||||
default: dump("No feedback for: "+aTarget.localName+"\n");
|
||||
}
|
||||
},
|
||||
|
||||
onDragRemoveFeedBack: function (aTarget)
|
||||
{
|
||||
var newTarget;
|
||||
var bt;
|
||||
if (aTarget.id == "PersonalToolbar" || aTarget.id == "bookmarks-ptf") {
|
||||
newTarget = BookmarksToolbar.getLastVisibleBookmark();
|
||||
if (newTarget)
|
||||
newTarget.removeAttribute("dragover-right");
|
||||
} else {
|
||||
aTarget.removeAttribute("dragover-left");
|
||||
aTarget.removeAttribute("dragover-right");
|
||||
aTarget.removeAttribute("dragover-top");
|
||||
aTarget.removeAttribute("dragover-bottom");
|
||||
}
|
||||
},
|
||||
|
||||
onDropSetFeedBack: function (aTarget)
|
||||
{
|
||||
//XXX Not yet...
|
||||
},
|
||||
|
||||
isContainer: function (aTarget)
|
||||
{
|
||||
return aTarget.localName == "menu" ||
|
||||
aTarget.localName == "toolbarbutton" &&
|
||||
aTarget.getAttribute("type") == "menu";
|
||||
}
|
||||
}
|
||||
|
||||
var BookmarksToolbar =
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// returns the node of the last visible bookmark on the toolbar -->
|
||||
getLastVisibleBookmark: function ()
|
||||
{
|
||||
var buttons = document.getElementById("bookmarks-ptf");
|
||||
var button = buttons.firstChild;
|
||||
if (!button)
|
||||
return null; // empty bookmarks toolbar
|
||||
do {
|
||||
if (button.collapsed)
|
||||
return button.previousSibling;
|
||||
button = button.nextSibling;
|
||||
} while (button)
|
||||
return buttons.lastChild;
|
||||
},
|
||||
|
||||
updateOverflowMenu: function (aMenuPopup)
|
||||
{
|
||||
var hbox = document.getElementById("bookmarks-ptf");
|
||||
for (var i = 0; i < hbox.childNodes.length; i++) {
|
||||
var button = hbox.childNodes[i];
|
||||
var menu = aMenuPopup.childNodes[i];
|
||||
if (menu.hidden == button.collapsed)
|
||||
menu.hidden = !menu.hidden;
|
||||
}
|
||||
},
|
||||
|
||||
resizeFunc: function(event)
|
||||
{
|
||||
if (!event) // timer callback case
|
||||
BookmarksToolbarRDFObserver._overflowTimerInEffect = false;
|
||||
else if (event.target != window)
|
||||
return; // only interested in chrome resizes
|
||||
|
||||
var buttons = document.getElementById("bookmarks-ptf");
|
||||
if (!buttons)
|
||||
return;
|
||||
|
||||
var chevron = document.getElementById("bookmarks-chevron");
|
||||
if (!buttons.firstChild) {
|
||||
// No bookmarks means no chevron
|
||||
chevron.collapsed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
chevron.collapsed = false;
|
||||
var chevronWidth = chevron.boxObject.width;
|
||||
chevron.collapsed = true;
|
||||
|
||||
var remainingWidth = buttons.boxObject.width;
|
||||
var overflowed = false;
|
||||
|
||||
for (var i=0; i<buttons.childNodes.length; i++) {
|
||||
var button = buttons.childNodes[i];
|
||||
button.collapsed = overflowed;
|
||||
|
||||
if (i == buttons.childNodes.length - 1)
|
||||
chevronWidth = 0;
|
||||
remainingWidth -= button.boxObject.width;
|
||||
if (remainingWidth < chevronWidth) {
|
||||
overflowed = true;
|
||||
// This button doesn't fit. Show it in the menu. Hide it in the toolbar.
|
||||
if (!button.collapsed)
|
||||
button.collapsed = true;
|
||||
if (chevron.collapsed) {
|
||||
chevron.collapsed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Fill in tooltips for personal toolbar (and Bookmarks menu).
|
||||
fillInBTTooltip: function (tipElement)
|
||||
{
|
||||
// Don't show a tooltip for non bookmark related elements.
|
||||
if (!/bookmark/.test(tipElement.className))
|
||||
return false;
|
||||
|
||||
var title = tipElement.label;
|
||||
var url = tipElement.statusText;
|
||||
|
||||
// Don't show a tooltip without any data.
|
||||
if (!title && !url)
|
||||
return false;
|
||||
|
||||
var tooltipElement = document.getElementById("btTitleText");
|
||||
tooltipElement.hidden = !title || (title == url);
|
||||
if (!tooltipElement.hidden)
|
||||
tooltipElement.setAttribute("value", title);
|
||||
|
||||
tooltipElement = document.getElementById("btUrlText");
|
||||
tooltipElement.hidden = !url;
|
||||
if (!tooltipElement.hidden)
|
||||
tooltipElement.setAttribute("value", url);
|
||||
|
||||
// Show the tooltip.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Implement nsIRDFObserver so we can update our overflow state when items get
|
||||
// added/removed from the toolbar
|
||||
var BookmarksToolbarRDFObserver =
|
||||
{
|
||||
onAssert: function (aDataSource, aSource, aProperty, aTarget)
|
||||
{
|
||||
this.setOverflowTimeout(aSource, aProperty);
|
||||
},
|
||||
onUnassert: function (aDataSource, aSource, aProperty, aTarget)
|
||||
{
|
||||
this.setOverflowTimeout(aSource, aProperty);
|
||||
},
|
||||
onChange: function (aDataSource, aSource, aProperty, aOldTarget, aNewTarget) {},
|
||||
onMove: function (aDataSource, aOldSource, aNewSource, aProperty, aTarget) {},
|
||||
onBeginUpdateBatch: function (aDataSource) {},
|
||||
onEndUpdateBatch: function (aDataSource)
|
||||
{
|
||||
if (this._overflowTimerInEffect)
|
||||
return;
|
||||
this._overflowTimerInEffect = true;
|
||||
setTimeout(BookmarksToolbar.resizeFunc, 0, null);
|
||||
},
|
||||
_overflowTimerInEffect: false,
|
||||
setOverflowTimeout: function (aSource, aProperty)
|
||||
{
|
||||
if (this._overflowTimerInEffect)
|
||||
return;
|
||||
if (aSource.Value != "NC:PersonalToolbarFolder" || aProperty.Value == NC_NS+"LastModifiedDate")
|
||||
return;
|
||||
this._overflowTimerInEffect = true;
|
||||
setTimeout(BookmarksToolbar.resizeFunc, 0, null);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче