зеркало из https://github.com/mozilla/gecko-dev.git
Bug 418671 - Clean up places views drag and drop code, r=mano
This commit is contained in:
Родитель
af9cc41693
Коммит
5ca634dfa3
|
@ -384,7 +384,7 @@
|
|||
key="showAllHistoryKb"
|
||||
#endif
|
||||
command="Browser:ShowAllHistory"/>
|
||||
<menuseparator id="startHistorySeparator" builder="start"/>
|
||||
<menuseparator id="startHistorySeparator"/>
|
||||
<menuseparator id="endHistorySeparator" builder="end"/>
|
||||
<menu id="historyUndoMenu" label="&historyUndoMenu.label;" disabled="true">
|
||||
<menupopup id="historyUndoPopup" onpopupshowing="HistoryMenu.populateUndoSubmenu();"/>
|
||||
|
@ -396,7 +396,8 @@
|
|||
label="&bookmarksMenu.label;" accesskey="&bookmarksMenu.accesskey;"
|
||||
ondragenter="PlacesMenuDNDController.onBookmarksMenuDragEnter(event);"
|
||||
ondragdrop="nsDragAndDrop.drop(event, BookmarksMenuDropHandler);"
|
||||
ondragover="nsDragAndDrop.dragOver(event, BookmarksMenuDropHandler);">
|
||||
ondragover="nsDragAndDrop.dragOver(event, BookmarksMenuDropHandler);"
|
||||
ondragexit="nsDragAndDrop.dragExit(event, BookmarksMenuDropHandler);">
|
||||
<menupopup id="bookmarksMenuPopup"
|
||||
type="places"
|
||||
place="place:folder=BOOKMARKS_MENU"
|
||||
|
@ -437,7 +438,7 @@
|
|||
context="placesContext"
|
||||
onpopupshowing="BookmarksEventHandler.onPopupShowing(event);"/>
|
||||
</menu>
|
||||
<menuseparator builder="start"/>
|
||||
<menuseparator/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
|
|
|
@ -711,7 +711,6 @@ var BookmarksEventHandler = {
|
|||
if (!target._endOptSeparator) {
|
||||
// create a separator before options
|
||||
target._endOptSeparator = document.createElement("menuseparator");
|
||||
target._endOptSeparator.setAttribute("builder", "end");
|
||||
target._endMarker = target.childNodes.length;
|
||||
target.appendChild(target._endOptSeparator);
|
||||
}
|
||||
|
@ -789,7 +788,8 @@ var BookmarksMenuDropHandler = {
|
|||
* state.
|
||||
*/
|
||||
onDragOver: function BMDH_onDragOver(event, flavor, session) {
|
||||
session.canDrop = this.canDrop(event, session);
|
||||
if (!this.canDrop(event, session))
|
||||
event.dataTransfer.effectAllowed = "none";
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -812,6 +812,8 @@ var BookmarksMenuDropHandler = {
|
|||
* otherwise.
|
||||
*/
|
||||
canDrop: function BMDH_canDrop(event, session) {
|
||||
PlacesControllerDragHelper.currentDataTransfer = event.dataTransfer;
|
||||
|
||||
var ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, -1);
|
||||
return ip && PlacesControllerDragHelper.canDrop(ip);
|
||||
},
|
||||
|
@ -826,9 +828,21 @@ var BookmarksMenuDropHandler = {
|
|||
* The active DragSession
|
||||
*/
|
||||
onDrop: function BMDH_onDrop(event, data, session) {
|
||||
// Put the item at the end of bookmark menu
|
||||
var ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, -1);
|
||||
PlacesControllerDragHelper.currentDataTransfer = event.dataTransfer;
|
||||
|
||||
// Put the item at the end of bookmark menu
|
||||
var ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, -1,
|
||||
Ci.nsITreeView.DROP_ON);
|
||||
PlacesControllerDragHelper.onDrop(ip);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when drop target leaves the menu or after a drop.
|
||||
* @param aEvent
|
||||
* A drop event
|
||||
*/
|
||||
onDragExit: function BMDH_onDragExit(event, session) {
|
||||
PlacesControllerDragHelper.currentDataTransfer = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -903,8 +917,9 @@ var PlacesMenuDNDController = {
|
|||
*` menu-toolbarbutton), false otherwise.
|
||||
*/
|
||||
_isContainer: function PMDC__isContainer(node) {
|
||||
return node.localName == "menu" ||
|
||||
node.localName == "toolbarbutton" && node.getAttribute("type") == "menu";
|
||||
return node.localName == "menu" ||
|
||||
(node.localName == "toolbarbutton" &&
|
||||
node.getAttribute("type") == "menu");
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* Ben Goodger <beng@google.com>
|
||||
* Myk Melez <myk@mozilla.org>
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
* Marco Bonardo <mak77@supereva.it>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -298,7 +298,7 @@ PlacesController.prototype = {
|
|||
return false;
|
||||
|
||||
if (PlacesUtils.nodeIsFolder(nodes[i]) &&
|
||||
!PlacesControllerDragHelper.canMoveContainerNode(nodes[i]))
|
||||
!PlacesControllerDragHelper.canMoveNode(nodes[i]))
|
||||
return false;
|
||||
|
||||
// We don't call nodeIsReadOnly here, because nodeIsReadOnly means that
|
||||
|
@ -351,7 +351,7 @@ PlacesController.prototype = {
|
|||
// if the clipboard contains TYPE_X_MOZ_PLACE_* data, it is definitely
|
||||
// pasteable, with no need to unwrap all the nodes.
|
||||
|
||||
var flavors = PlacesUIUtils.placesFlavors;
|
||||
var flavors = PlacesControllerDragHelper.placesFlavors;
|
||||
var clipboard = PlacesUIUtils.clipboard;
|
||||
var hasPlacesData =
|
||||
clipboard.hasDataMatchingFlavors(flavors, flavors.length,
|
||||
|
@ -1015,62 +1015,50 @@ PlacesController.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Get a TransferDataSet containing the content of the selection that can be
|
||||
* dropped elsewhere.
|
||||
* @param dragAction
|
||||
* The action to happen when dragging, i.e. copy
|
||||
* @returns A TransferDataSet object that can be dragged and dropped
|
||||
* elsewhere.
|
||||
* Fills a DataTransfer object with the content of the selection that can be
|
||||
* dropped elsewhere.
|
||||
* @param aEvent
|
||||
* The dragstart event.
|
||||
*/
|
||||
getTransferData: function PC_getTransferData(dragAction) {
|
||||
var copy = dragAction == Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
setDataTransfer: function PC_setDataTransfer(aEvent) {
|
||||
var dt = aEvent.dataTransfer;
|
||||
var doCopy = dt.effectAllowed == "copyLink" || dt.effectAllowed == "copy";
|
||||
|
||||
var result = this._view.getResult();
|
||||
var oldViewer = result.viewer;
|
||||
try {
|
||||
result.viewer = null;
|
||||
var nodes = this._view.getDragableSelection();
|
||||
if (dragAction == Ci.nsIDragService.DRAGDROP_ACTION_MOVE) {
|
||||
nodes = nodes.filter(function(node) {
|
||||
var parent = node.parent;
|
||||
return parent && !PlacesUtils.nodeIsReadOnly(parent);
|
||||
});
|
||||
}
|
||||
|
||||
var dataSet = new TransferDataSet();
|
||||
for (var i = 0; i < nodes.length; ++i) {
|
||||
var node = nodes[i];
|
||||
|
||||
var data = new TransferData();
|
||||
function addData(type, overrideURI) {
|
||||
data.addDataForFlavour(type, PlacesUIUtils._wrapString(
|
||||
PlacesUtils.wrapNode(node, type, overrideURI, copy)));
|
||||
function addData(type, index, overrideURI) {
|
||||
var wrapNode = PlacesUtils.wrapNode(node, type, overrideURI, doCopy);
|
||||
dt.mozSetDataAt(type, wrapNode, index);
|
||||
}
|
||||
|
||||
function addURIData(overrideURI) {
|
||||
addData(PlacesUtils.TYPE_X_MOZ_URL, overrideURI);
|
||||
addData(PlacesUtils.TYPE_UNICODE, overrideURI);
|
||||
addData(PlacesUtils.TYPE_HTML, overrideURI);
|
||||
function addURIData(index, overrideURI) {
|
||||
addData(PlacesUtils.TYPE_X_MOZ_URL, index, overrideURI);
|
||||
addData(PlacesUtils.TYPE_UNICODE, index, overrideURI);
|
||||
addData(PlacesUtils.TYPE_HTML, index, overrideURI);
|
||||
}
|
||||
|
||||
// This order is _important_! It controls how this and other
|
||||
// applications select data to be inserted based on type.
|
||||
addData(PlacesUtils.TYPE_X_MOZ_PLACE);
|
||||
|
||||
var uri;
|
||||
|
||||
// Allow dropping the feed uri of live-bookmark folders
|
||||
addData(PlacesUtils.TYPE_X_MOZ_PLACE, i);
|
||||
|
||||
// Drop the feed uri for livemark containers
|
||||
if (PlacesUtils.nodeIsLivemarkContainer(node))
|
||||
uri = PlacesUtils.livemarks.getFeedURI(node.itemId).spec;
|
||||
|
||||
addURIData(uri);
|
||||
dataSet.push(data);
|
||||
addURIData(i, PlacesUtils.livemarks.getFeedURI(node.itemId).spec);
|
||||
else if (node.uri)
|
||||
addURIData(i);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (oldViewer)
|
||||
result.viewer = oldViewer;
|
||||
}
|
||||
return dataSet;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1111,7 +1099,7 @@ PlacesController.prototype = {
|
|||
uri) + suffix);
|
||||
|
||||
var placeSuffix = i < (nodes.length - 1) ? "," : "";
|
||||
var resolveShortcuts = !PlacesControllerDragHelper.canMoveContainerNode(node);
|
||||
var resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node);
|
||||
return PlacesUtils.wrapNode(node, type, overrideURI, resolveShortcuts) + placeSuffix;
|
||||
}
|
||||
|
||||
|
@ -1248,6 +1236,18 @@ PlacesController.prototype = {
|
|||
* Drop functions are passed the view that is being dropped on.
|
||||
*/
|
||||
var PlacesControllerDragHelper = {
|
||||
/**
|
||||
* DOM Element currently being dragged over
|
||||
*/
|
||||
currentDropTarget: null,
|
||||
|
||||
/**
|
||||
* Current nsIDOMDataTransfer
|
||||
* We need to cache this because we don't have access to the event in the
|
||||
* treeView's canDrop or drop methods, and session.dataTransfer would not be
|
||||
* filled for drag and drop from external sources (eg. the OS).
|
||||
*/
|
||||
currentDataTransfer: null,
|
||||
|
||||
/**
|
||||
* Determines if the mouse is currently being dragged over a child node of
|
||||
|
@ -1268,11 +1268,6 @@ var PlacesControllerDragHelper = {
|
|||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM Element currently being dragged over
|
||||
*/
|
||||
currentDropTarget: null,
|
||||
|
||||
/**
|
||||
* @returns The current active drag session. Returns null if there is none.
|
||||
*/
|
||||
|
@ -1282,6 +1277,19 @@ var PlacesControllerDragHelper = {
|
|||
return dragService.getCurrentSession();
|
||||
},
|
||||
|
||||
/**
|
||||
* Extract the first accepted flavor from a flavors array.
|
||||
* @param aFlavors
|
||||
* The flavors array.
|
||||
*/
|
||||
getFirstValidFlavor: function PCDH_getFirstValidFlavor(aFlavors) {
|
||||
for (var i = 0; i < aFlavors.length; i++) {
|
||||
if (this.GENERIC_VIEW_DROP_TYPES.indexOf(aFlavors[i]) != -1)
|
||||
return aFlavors[i];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not the data currently being dragged can be dropped
|
||||
* on a places view.
|
||||
|
@ -1289,35 +1297,28 @@ var PlacesControllerDragHelper = {
|
|||
* The insertion point where the items should be dropped
|
||||
*/
|
||||
canDrop: function PCDH_canDrop(ip) {
|
||||
var session = this.getSession();
|
||||
if (!session)
|
||||
return false;
|
||||
|
||||
var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
|
||||
var foundType = false;
|
||||
for (var i = 0; i < types.length && !foundType; ++i) {
|
||||
if (session.isDataFlavorSupported(types[i]))
|
||||
foundType = true;
|
||||
}
|
||||
|
||||
if (!foundType)
|
||||
return false;
|
||||
var dt = this.currentDataTransfer;
|
||||
var dropCount = dt.mozItemCount;
|
||||
|
||||
// Check every dragged item
|
||||
var xferable = this._initTransferable(session);
|
||||
var dropCount = session.numDropItems;
|
||||
for (i = 0; i < dropCount; i++) {
|
||||
// Get the information of the dragged item
|
||||
session.getData(xferable, i);
|
||||
var data = { }, flavor = { };
|
||||
xferable.getAnyTransferData(flavor, data, { });
|
||||
data.value.QueryInterface(Ci.nsISupportsString);
|
||||
var dragged = PlacesUtils.unwrapNodes(data.value.data, flavor.value)[0];
|
||||
for (var i = 0; i < dropCount; i++) {
|
||||
var flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
|
||||
if (!flavor)
|
||||
return false;
|
||||
|
||||
var data = dt.mozGetDataAt(flavor, i);
|
||||
|
||||
try {
|
||||
var dragged = PlacesUtils.unwrapNodes(data, flavor)[0];
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only bookmarks and urls can be dropped into tag containers
|
||||
if (ip.isTag && dragged.type != PlacesUtils.TYPE_X_MOZ_URL &&
|
||||
(dragged.type != PlacesUtils.TYPE_X_MOZ_PLACE ||
|
||||
/^place:/.test(dragged.uri)))
|
||||
if (ip.isTag && ip.orientation == Ci.nsITreeView.DROP_ON &&
|
||||
dragged.type != PlacesUtils.TYPE_X_MOZ_URL &&
|
||||
(dragged.type != PlacesUtils.TYPE_X_MOZ_PLACE ||
|
||||
/^place:/.test(dragged.uri)))
|
||||
return false;
|
||||
|
||||
// The following loop disallows the dropping of a folder on itself or
|
||||
|
@ -1332,39 +1333,36 @@ var PlacesControllerDragHelper = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if a container node can be moved.
|
||||
* Determines if a node can be moved.
|
||||
*
|
||||
* @param aNode
|
||||
* A bookmark folder node.
|
||||
* @param [optional] aInsertionPoint
|
||||
* The insertion point of the drop target.
|
||||
* @returns True if the container can be moved.
|
||||
* A nsINavHistoryResultNode node.
|
||||
* @returns True if the node can be moved, false otherwise.
|
||||
*/
|
||||
canMoveContainerNode:
|
||||
function PCDH_canMoveContainerNode(aNode, aInsertionPoint) {
|
||||
canMoveNode:
|
||||
function PCDH_canMoveNode(aNode) {
|
||||
// can't move query root
|
||||
if (!aNode.parent)
|
||||
return false;
|
||||
|
||||
var targetId = aInsertionPoint ? aInsertionPoint.itemId : -1;
|
||||
var parentId = PlacesUtils.getConcreteItemId(aNode.parent);
|
||||
var concreteId = PlacesUtils.getConcreteItemId(aNode);
|
||||
|
||||
// can't move tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aNode))
|
||||
// can't move children of tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aNode.parent))
|
||||
return false;
|
||||
|
||||
// check is child of a read-only container
|
||||
// can't move children of read-only containers
|
||||
if (PlacesUtils.nodeIsReadOnly(aNode.parent))
|
||||
return false;
|
||||
|
||||
// check for special folders, etc
|
||||
if (!this.canMoveContainer(aNode.itemId, parentId))
|
||||
if (PlacesUtils.nodeIsContainer(aNode) &&
|
||||
!this.canMoveContainer(concreteId, parentId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -1395,89 +1393,95 @@ var PlacesControllerDragHelper = {
|
|||
if (aParentId == null || aParentId == -1)
|
||||
aParentId = PlacesUtils.bookmarks.getFolderIdForItem(aId);
|
||||
|
||||
if(PlacesUtils.bookmarks.getFolderReadonly(aParentId))
|
||||
if (PlacesUtils.bookmarks.getFolderReadonly(aParentId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a Transferable object that can be filled with data of types
|
||||
* supported by a view.
|
||||
* @param session
|
||||
* The active drag session
|
||||
* @returns An object implementing nsITransferable that can receive data
|
||||
* dropped onto a view.
|
||||
*/
|
||||
_initTransferable: function PCDH__initTransferable(session) {
|
||||
var xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
if (session.isDataFlavorSupported(types[i]))
|
||||
xferable.addDataFlavor(types[i]);
|
||||
}
|
||||
return xferable;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the drop of one or more items onto a view.
|
||||
* @param insertionPoint
|
||||
* The insertion point where the items should be dropped
|
||||
*/
|
||||
onDrop: function PCDH_onDrop(insertionPoint) {
|
||||
var session = this.getSession();
|
||||
// XXX dragAction is not valid, so we also set copy below by checking
|
||||
// whether the dropped item is moveable, before creating the transaction
|
||||
var copy = session.dragAction & Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
var dt = this.currentDataTransfer;
|
||||
var doCopy = dt.dropEffect == "copy";
|
||||
|
||||
var transactions = [];
|
||||
var xferable = this._initTransferable(session);
|
||||
var dropCount = session.numDropItems;
|
||||
|
||||
var dropCount = dt.mozItemCount;
|
||||
var movedCount = 0;
|
||||
|
||||
for (var i = 0; i < dropCount; ++i) {
|
||||
session.getData(xferable, i);
|
||||
var flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
|
||||
if (!flavor)
|
||||
return false;
|
||||
|
||||
var data = { }, flavor = { };
|
||||
xferable.getAnyTransferData(flavor, data, { });
|
||||
data.value.QueryInterface(Ci.nsISupportsString);
|
||||
|
||||
// There's only ever one in the D&D case.
|
||||
var unwrapped = PlacesUtils.unwrapNodes(data.value.data,
|
||||
flavor.value)[0];
|
||||
var data = dt.mozGetDataAt(flavor, i);
|
||||
// There's only ever one in the D&D case.
|
||||
var unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
|
||||
|
||||
var index = insertionPoint.index;
|
||||
|
||||
// Adjust insertion index to prevent reversal of dragged items. When you
|
||||
// drag multiple elts upward: need to increment index or each successive
|
||||
// elt will be inserted at the same index, each above the previous.
|
||||
if (index != -1 && index < unwrapped.index) {
|
||||
index = index + movedCount;
|
||||
movedCount++;
|
||||
}
|
||||
var dragginUp = insertionPoint.itemId == unwrapped.parent &&
|
||||
index < PlacesUtils.bookmarks.getItemIndex(unwrapped.id);
|
||||
if (index != -1 && dragginUp)
|
||||
index+= movedCount++;
|
||||
|
||||
// if dragging over a tag container we should tag the item
|
||||
if (insertionPoint.isTag) {
|
||||
if (insertionPoint.isTag &&
|
||||
insertionPoint.orientation == Ci.nsITreeView.DROP_ON) {
|
||||
var uri = PlacesUtils._uri(unwrapped.uri);
|
||||
var tagItemId = insertionPoint.itemId;
|
||||
transactions.push(PlacesUIUtils.ptm.tagURI(uri,[tagItemId]));
|
||||
}
|
||||
else {
|
||||
if (unwrapped.id && !this.canMoveContainer(unwrapped.id, null))
|
||||
copy = true;
|
||||
else if (unwrapped.concreteId &&
|
||||
!this.canMoveContainer(unwrapped.concreteId, null))
|
||||
copy = true;
|
||||
|
||||
transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
|
||||
flavor.value, insertionPoint.itemId,
|
||||
index, copy));
|
||||
flavor, insertionPoint.itemId,
|
||||
index, doCopy));
|
||||
}
|
||||
}
|
||||
|
||||
var txn = PlacesUIUtils.ptm.aggregateTransactions("DropItems", transactions);
|
||||
PlacesUIUtils.ptm.doTransaction(txn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if we can insert into a container.
|
||||
* @param aContainer
|
||||
* The container were we are want to drop
|
||||
*/
|
||||
disallowInsertion: function(aContainer) {
|
||||
NS_ASSERT(aContainer, "empty container");
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
},
|
||||
|
||||
placesFlavors: [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE],
|
||||
|
||||
GENERIC_VIEW_DROP_TYPES: [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE,
|
||||
PlacesUtils.TYPE_X_MOZ_URL,
|
||||
PlacesUtils.TYPE_UNICODE],
|
||||
|
||||
/**
|
||||
* Returns our flavourSet
|
||||
*/
|
||||
get flavourSet() {
|
||||
delete this.flavourSet;
|
||||
var flavourSet = new FlavourSet();
|
||||
var acceptedDropFlavours = this.GENERIC_VIEW_DROP_TYPES;
|
||||
acceptedDropFlavours.forEach(flavourSet.appendFlavour, flavourSet);
|
||||
return this.flavourSet = flavourSet;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
# Ben Goodger <beng@google.com>
|
||||
# Asaf Romano <mano@mozilla.com>
|
||||
# Simon Bünzli <zeniko@gmail.com>
|
||||
# Marco Bonardo <mak77@supereva.it>
|
||||
# Marco Bonardo <mak77@bonardo.net>
|
||||
#
|
||||
# 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
|
||||
|
@ -88,8 +88,11 @@
|
|||
PlacesControllerDragHelper.currentDropTarget = aEvent.target;
|
||||
// check if we have a valid dropPoint
|
||||
var dropPoint = this._getDropPoint(aEvent);
|
||||
if (!dropPoint)
|
||||
if (!dropPoint || !dropPoint.ip ||
|
||||
!PlacesControllerDragHelper.canDrop(dropPoint.ip)) {
|
||||
aEvent.dataTransfer.effectAllowed = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
// add a dragover attribute to this popup
|
||||
this.setAttribute("dragover", "true");
|
||||
|
@ -109,7 +112,7 @@
|
|||
.setTimer(this._overFolder.hoverTime);
|
||||
}
|
||||
// since we are dropping into a folder set the corresponding style
|
||||
dropPoint.folderNode.setAttribute("dragover-into", "true");
|
||||
dropPoint.folderNode.setAttribute("_moz-menuactive", true);
|
||||
}
|
||||
else {
|
||||
// We are not dragging over a folder
|
||||
|
@ -117,6 +120,14 @@
|
|||
this._overFolder.clear();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Check if we should hide the drop indicator for this target
|
||||
if (!aDragSession.canDrop ||
|
||||
!dropPoint || dropPoint.folderNode ||
|
||||
|
@ -125,29 +136,22 @@
|
|||
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 sbo = this._scrollBox.scrollBoxObject;
|
||||
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;
|
||||
newMarginTop = node ? node.boxObject.screenY - sbo.screenY :
|
||||
sbo.height;
|
||||
}
|
||||
else if (scrollDir == 1)
|
||||
newMarginTop = scrollBoxObject.height;
|
||||
newMarginTop = sbo.height;
|
||||
|
||||
// set the new marginTop based on arrowscrollbox
|
||||
newMarginTop += scrollBoxObject.y - this._scrollBox.boxObject.y;
|
||||
newMarginTop += sbo.y - this._scrollBox.boxObject.y;
|
||||
this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
|
||||
this._indicatorBar.hidden = false;
|
||||
]]></body>
|
||||
|
@ -158,9 +162,8 @@
|
|||
<parameter name="aDragSession"/>
|
||||
<body><![CDATA[
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
PlacesControllerDragHelper.currentDataTransfer = 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
|
||||
|
@ -177,7 +180,10 @@
|
|||
// 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")) {
|
||||
// We should also try to close this popup if the drag has started
|
||||
// from here, the timer will check if we are dragging over a child.
|
||||
if (this.hasAttribute("autoopened") ||
|
||||
this.hasAttribute("dragstart")) {
|
||||
this._overFolder.closeMenuTimer = this._overFolder
|
||||
.setTimer(this._overFolder.hoverTime);
|
||||
}
|
||||
|
@ -191,26 +197,32 @@
|
|||
<parameter name="aXferData"/>
|
||||
<parameter name="aDragAction"/>
|
||||
<body><![CDATA[
|
||||
// Force a copy action if parent node is a query or not-removable
|
||||
if (aEvent.ctrlKey ||
|
||||
PlacesUtils.nodeIsQuery(aEvent.target.node.parent) ||
|
||||
!PlacesControllerDragHelper.canMoveContainerNode(aEvent.target.node))
|
||||
aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
var draggedNode = aEvent.target.node;
|
||||
|
||||
// Force a copy action if parent node is a query or we are dragging a
|
||||
// not-removable node
|
||||
if (!PlacesControllerDragHelper.canMoveNode(draggedNode))
|
||||
aEvent.dataTransfer.effectAllowed = "copyLink";
|
||||
|
||||
// activate the view and cache the dragged node
|
||||
this._rootView._draggedNode = aEvent.target.node;
|
||||
this._rootView._draggedNode = draggedNode;
|
||||
this._rootView.focus();
|
||||
|
||||
aXferData.data = this._rootView.controller
|
||||
.getTransferData(aDragAction.action);
|
||||
// Fill the dataTransfer
|
||||
this._rootView._controller.setDataTransfer(aEvent);
|
||||
|
||||
this.setAttribute("dragstart", "true");
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="onDrop">
|
||||
<parameter name="aEvent"/>
|
||||
<parameter name="aDropData"/>
|
||||
<parameter name="aDropData"/>
|
||||
<parameter name="aSession"/>
|
||||
<body><![CDATA[
|
||||
// Cache the dataTransfer
|
||||
PlacesControllerDragHelper.currentDataTransfer = aEvent.dataTransfer;
|
||||
|
||||
var dropPoint = this._getDropPoint(aEvent);
|
||||
if (!dropPoint)
|
||||
return;
|
||||
|
@ -222,10 +234,7 @@
|
|||
<!-- This returns the FavourSet accepted by this popup -->
|
||||
<method name="getSupportedFlavours">
|
||||
<body><![CDATA[
|
||||
var flavourSet = new FlavourSet();
|
||||
var acceptedDropFlavours = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
|
||||
acceptedDropFlavours.forEach(flavourSet.appendFlavour, flavourSet);
|
||||
return flavourSet;
|
||||
return PlacesControllerDragHelper.flavourSet;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -246,7 +255,8 @@
|
|||
betweenMarkers = false;
|
||||
|
||||
// hide the dropmarker if current node is not a places bookmark item
|
||||
return !(target && target.node && betweenMarkers && this.canDrop());
|
||||
return !(target && target.node && betweenMarkers &&
|
||||
this.canDrop(aEvent));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -257,71 +267,87 @@
|
|||
<body><![CDATA[
|
||||
// Can't drop if the menu isn't a folder
|
||||
var resultNode = this._resultNode;
|
||||
if (!PlacesUtils.nodeIsFolder(resultNode))
|
||||
|
||||
if (!PlacesUtils.nodeIsFolder(resultNode) ||
|
||||
PlacesControllerDragHelper.disallowInsertion(resultNode)) {
|
||||
aEvent.dataTransfer.effectAllowed = "none";
|
||||
return null;
|
||||
}
|
||||
|
||||
var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
|
||||
var dropPoint = { ip: null, folderNode: null };
|
||||
|
||||
// set the limits for valid items
|
||||
var start = 0;
|
||||
var popup = this;
|
||||
var end = popup.childNodes.length;
|
||||
if (this._startMarker != -1)
|
||||
start = this._startMarker + 1;
|
||||
if (this._endMarker != -1)
|
||||
end = this._endMarker;
|
||||
// The node we are dragging over
|
||||
var xulNode = aEvent.target;
|
||||
|
||||
// Loop through all the nodes to find the correct dropPoint
|
||||
var popupY = popup.boxObject.y;
|
||||
// we should add the scrollBox button height if visible
|
||||
popupY += this._scrollBox.scrollBoxObject.y - popup.boxObject.y;
|
||||
for (var i = start; i < end; i++) {
|
||||
var xulNode = popup.childNodes[i];
|
||||
var nodeY = xulNode.boxObject.y - popupY;
|
||||
var nodeHeight = xulNode.boxObject.height;
|
||||
if (xulNode.node &&
|
||||
(PlacesUtils.nodeIsFolder(xulNode.node) ||
|
||||
PlacesUtils.nodeIsTagQuery(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;
|
||||
}
|
||||
// Calculate positions taking care of arrowscrollbox
|
||||
var sbo = this._scrollBox.scrollBoxObject;
|
||||
var eventY = aEvent.layerY;
|
||||
var nodeY = xulNode.boxObject.y - sbo.y;
|
||||
var nodeHeight = xulNode.boxObject.height;
|
||||
|
||||
if (!xulNode.node) {
|
||||
// if we are dragging over a non places node drop at the end
|
||||
dropPoint.ip = new InsertionPoint(resultNode.itemId,
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_ON);
|
||||
return dropPoint;
|
||||
}
|
||||
else if ((PlacesUtils.nodeIsFolder(xulNode.node) ||
|
||||
PlacesUtils.nodeIsTagQuery(xulNode.node)) &&
|
||||
!PlacesUtils.nodeIsReadOnly(xulNode.node)) {
|
||||
// This is a folder or a tag container.
|
||||
if (eventY - nodeY < nodeHeight * 0.25) {
|
||||
// If the mouse is in the top 25% of the node,
|
||||
// drop above the folder.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
resultNode.itemId,
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_BEFORE,
|
||||
PlacesUtils.nodeIsTagQuery(xulNode.node),
|
||||
xulNode.node.itemId);
|
||||
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;
|
||||
}
|
||||
else if (eventY - nodeY < nodeHeight * 0.75) {
|
||||
// If the mouse is before the 75 % of the node drop
|
||||
// inside this folder.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
PlacesUtils.getConcreteItemId(xulNode.node),
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_ON,
|
||||
PlacesUtils.nodeIsTagQuery(xulNode.node));
|
||||
dropPoint.folderNode = xulNode;
|
||||
return dropPoint;
|
||||
}
|
||||
}
|
||||
// Should drop below the last node.
|
||||
dropPoint.ip = new InsertionPoint(resultNode.itemId, -1, 1);
|
||||
dropPoint.beforeIndex = -1;
|
||||
else if (eventY - nodeY <= nodeHeight / 2) {
|
||||
// This is a non-folder node or a readonly folder.
|
||||
// If the mouse is above the middle, drop above this item.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
resultNode.itemId,
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_BEFORE,
|
||||
PlacesUtils.nodeIsTagQuery(xulNode.node),
|
||||
xulNode.node.itemId);
|
||||
return dropPoint;
|
||||
}
|
||||
|
||||
// Drop below the item.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
resultNode.itemId,
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_AFTER,
|
||||
PlacesUtils.nodeIsTagQuery(xulNode.node),
|
||||
xulNode.node.itemId);
|
||||
return dropPoint;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="canDrop">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
// Cache the dataTransfer
|
||||
PlacesControllerDragHelper.currentDataTransfer = aEvent.dataTransfer;
|
||||
|
||||
var ip = this._rootView.insertionPoint;
|
||||
return ip && PlacesControllerDragHelper.canDrop(ip);
|
||||
]]></body>
|
||||
|
@ -332,7 +358,10 @@
|
|||
closing of folders when the mouse hovers. -->
|
||||
<field name="_overFolder"><![CDATA[({
|
||||
_self: this,
|
||||
_folder: {node: null, openTimer: null, hoverTime: 350, closeTimer: null},
|
||||
_folder: {node: null,
|
||||
openTimer: null,
|
||||
hoverTime: 350,
|
||||
closeTimer: null},
|
||||
_closeMenuTimer: null,
|
||||
|
||||
get node() {
|
||||
|
@ -406,13 +435,17 @@
|
|||
else if (aTimer == this.closeMenuTimer) {
|
||||
// Timer to close this menu after the drag exit.
|
||||
var popup = this._self;
|
||||
if (!PlacesControllerDragHelper.draggingOverChildNode(popup.parentNode)) {
|
||||
// if we are no more dragging we can leave the menu open to allow
|
||||
// for better D&D bookmark organization
|
||||
if (PlacesControllerDragHelper.getSession() &&
|
||||
!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();
|
||||
}
|
||||
this._closeMenuTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -439,8 +472,8 @@
|
|||
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");
|
||||
// remove menuactive style
|
||||
this._folder.node.removeAttribute("_moz-menuactive");
|
||||
this._folder.node = null;
|
||||
}
|
||||
if (this._folder.openTimer) {
|
||||
|
@ -574,6 +607,9 @@
|
|||
if (document.popupNode == child)
|
||||
document.popupNode = null;
|
||||
child.parentNode.removeChild(child);
|
||||
|
||||
if (this._endMarker != -1)
|
||||
this._endMarker--;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -591,12 +627,16 @@
|
|||
// Add the new element to the menu. If there is static content at
|
||||
// the end of the menu, add the element before that. Otherwise,
|
||||
// just add to the end.
|
||||
if (aParentPopup._endMarker != -1)
|
||||
if (aParentPopup._endMarker != -1) {
|
||||
aParentPopup.insertBefore(element,
|
||||
aParentPopup.childNodes[aParentPopup._endMarker++]);
|
||||
aParentPopup.childNodes[aParentPopup._endMarker]);
|
||||
}
|
||||
else
|
||||
aParentPopup.appendChild(element);
|
||||
}
|
||||
|
||||
if (aParentPopup._endMarker != -1)
|
||||
aParentPopup._endMarker++;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -702,6 +742,7 @@
|
|||
popup.firstChild == popup._emptyMenuItem)) {
|
||||
this._self._showEmptyMenuItem(popup);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -900,15 +941,23 @@
|
|||
<!-- nsIPlacesView -->
|
||||
<property name="insertionPoint">
|
||||
<getter><![CDATA[
|
||||
// there is no insertion point for history queries
|
||||
// so bail out now and save a lot of work when updating commands
|
||||
var resultNode = this._resultNode;
|
||||
if (PlacesUtils.nodeIsQuery(resultNode) &&
|
||||
asQuery(resultNode).queryOptions.queryType ==
|
||||
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
|
||||
return null;
|
||||
|
||||
// By default, the insertion point is at the top level, at the end.
|
||||
var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
|
||||
var container = null;
|
||||
var orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
var isTag = false;
|
||||
|
||||
if (PlacesUtils.nodeIsFolder(this._resultNode)) {
|
||||
container = this._resultNode;
|
||||
isTag = PlacesUtils.nodeIsTagQuery(this._resultNode);
|
||||
if (PlacesUtils.nodeIsFolder(resultNode)) {
|
||||
container = resultNode;
|
||||
isTag = PlacesUtils.nodeIsTagQuery(resultNode);
|
||||
}
|
||||
|
||||
var selectedNode = this.selectedNode;
|
||||
|
@ -928,7 +977,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (this._disallowInsertion(container))
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
|
@ -936,18 +985,6 @@
|
|||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="_disallowInsertion">
|
||||
<parameter name="aContainer"/>
|
||||
<body><![CDATA[
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<method name="selectAll">
|
||||
<body/>
|
||||
|
@ -1017,6 +1054,7 @@
|
|||
// automatically opened when dragged over. Turn off this attribute
|
||||
// when the folder closes because it is no longer applicable.
|
||||
popup.removeAttribute("autoopened");
|
||||
popup.removeAttribute("dragstart");
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# Annie Sullivan <annie.sullivan@gmail.com>
|
||||
# Ben Goodger <beng@google.com>
|
||||
# Myk Melez <myk@mozilla.org>
|
||||
# Marco Bonardo <mak77@bonardo.net>
|
||||
#
|
||||
# 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
|
||||
|
@ -307,6 +308,14 @@
|
|||
popup.setAttribute("type", "places");
|
||||
}
|
||||
}
|
||||
|
||||
// We rebuild the chevron on popupShowing, so if it is open
|
||||
// we must force a rebuild
|
||||
if (this._chevron.open) {
|
||||
var popup = this._chevron.firstChild;
|
||||
for (var i = 0; i < popup.childNodes.length; i++)
|
||||
popup.childNodes[i].hidden = !this.childNodes[i].collapsed;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -406,7 +415,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (this._disallowInsertion(container))
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
|
@ -414,18 +423,6 @@
|
|||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="_disallowInsertion">
|
||||
<parameter name="aContainer"/>
|
||||
<body><![CDATA[
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<method name="selectAll">
|
||||
<body><![CDATA[
|
||||
|
@ -520,6 +517,9 @@
|
|||
popup.firstChild == popup._emptyMenuItem)) {
|
||||
this._self._showEmptyMenuItem(popup);
|
||||
}
|
||||
if (popup._endMarker != -1)
|
||||
popup._endMarker--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -534,11 +534,19 @@
|
|||
|
||||
if (aNewParent == this._self.getResultNode()) {
|
||||
var children = this._self.childNodes;
|
||||
var chevronPopup = this._self._chevron.firstChild;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var button = children[i];
|
||||
if (button.node == aItem) {
|
||||
this._self.removeChild(button);
|
||||
this._self.insertBefore(button, children[aNewIndex]);
|
||||
if (chevronPopup) {
|
||||
// Maintain chevron in sync
|
||||
menuitem = chevronPopup.childNodes[i];
|
||||
chevronPopup.removeChild(menuitem);
|
||||
chevronPopup.insertBefore(menuitem,
|
||||
chevronPopup.childNodes[aNewIndex]);
|
||||
}
|
||||
this._self.updateChevron();
|
||||
return;
|
||||
}
|
||||
|
@ -697,7 +705,10 @@
|
|||
// Menu buttons 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},
|
||||
_overFolder: {node: null,
|
||||
openTimer: null,
|
||||
hoverTime: 350,
|
||||
closeTimer: null},
|
||||
|
||||
// timer for turning of indicator bar, to get rid of flicker
|
||||
_ibTimer: null,
|
||||
|
@ -794,8 +805,10 @@
|
|||
// node (or 25% of the right, in RTL UI), drop before the folder.
|
||||
// If it's in the middle 50%, drop into the folder. If it's past
|
||||
// that, drop after.
|
||||
if ((isRTL && event.clientX > xulNode.boxObject.x + (xulNode.boxObject.width * 0.75)) ||
|
||||
(!isRTL && event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.25))) {
|
||||
if ((isRTL && event.clientX > xulNode.boxObject.x +
|
||||
(xulNode.boxObject.width * 0.75)) ||
|
||||
(!isRTL && event.clientX < xulNode.boxObject.x +
|
||||
(xulNode.boxObject.width * 0.25))) {
|
||||
// Drop to the left of this folder.
|
||||
dropPoint.ip =
|
||||
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
|
||||
|
@ -803,12 +816,15 @@
|
|||
dropPoint.beforeIndex = i;
|
||||
return dropPoint;
|
||||
}
|
||||
else if ((isRTL && event.clientX > xulNode.boxObject.x + (xulNode.boxObject.width * 0.25)) ||
|
||||
(!isRTL && event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.75))) {
|
||||
else if ((isRTL && event.clientX > xulNode.boxObject.x +
|
||||
(xulNode.boxObject.width * 0.25)) ||
|
||||
(!isRTL && event.clientX < xulNode.boxObject.x +
|
||||
(xulNode.boxObject.width * 0.75))) {
|
||||
// Drop inside this folder.
|
||||
dropPoint.ip =
|
||||
new InsertionPoint(PlacesUtils.getConcreteItemId(xulNode.node),
|
||||
-1, 1);
|
||||
-1, 1,
|
||||
PlacesUtils.nodeIsTagQuery(xulNode.node));
|
||||
dropPoint.beforeIndex = i;
|
||||
dropPoint.folderNode = xulNode;
|
||||
return dropPoint;
|
||||
|
@ -836,39 +852,43 @@
|
|||
dropPoint.beforeIndex = -1;
|
||||
return dropPoint;
|
||||
},
|
||||
|
||||
onDragStart: function TBV_DO_onDragStart(event, xferData, dragAction) {
|
||||
|
||||
onDragStart: function TBV_DO_onDragStart(aEvent, aXferData, aDragAction) {
|
||||
var draggedXulNode = aEvent.target;
|
||||
// sub menus have their own d&d handlers
|
||||
if (event.target.parentNode != this._self)
|
||||
if (draggedXulNode.parentNode != this._self)
|
||||
return false;
|
||||
|
||||
if (event.target.localName == "toolbarbutton" &&
|
||||
event.target.getAttribute("type") == "menu") {
|
||||
if (draggedXulNode.localName == "toolbarbutton" &&
|
||||
draggedXulNode.getAttribute("type") == "menu") {
|
||||
#ifdef XP_WIN
|
||||
// Support folder dragging on the personal toolbar when the user
|
||||
// holds the "alt" key while they drag (Ctrl+drag has another
|
||||
// meaning - Copy). This does not appear to work at all on Linux.
|
||||
if (!event.shiftKey && !event.altKey && !event.ctrlKey)
|
||||
// Support folder dragging on the personal toolbar when the user
|
||||
// holds the "alt" or "shift" key while dragging.
|
||||
// Ctrl+drag is Copy
|
||||
if (!aEvent.shiftKey && !aEvent.altKey && !aEvent.ctrlKey)
|
||||
return false;
|
||||
event.target.firstChild.hidePopup();
|
||||
#else
|
||||
return;
|
||||
// Support folder dragging on the personal toolbar when the user
|
||||
// holds the "shift" key while dragging
|
||||
// Ctrl+drag is Copy
|
||||
if (!aEvent.shiftKey && !aEvent.ctrlKey)
|
||||
return false;
|
||||
#endif
|
||||
draggedXulNode.firstChild.hidePopup();
|
||||
}
|
||||
|
||||
if (event.ctrlKey)
|
||||
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
|
||||
// activate the view and cache the dragged node
|
||||
this._self._draggedNode = event.target.node;
|
||||
this._self._draggedNode = draggedXulNode.node;
|
||||
this._self.focus();
|
||||
xferData.data = this._self._controller.getTransferData(dragAction.action);
|
||||
#ifdef XP_WIN
|
||||
|
||||
this._self._controller.setDataTransfer(aEvent);
|
||||
return true;
|
||||
#endif
|
||||
},
|
||||
|
||||
canDrop: function TBV_DO_canDrop(event, session) {
|
||||
canDrop: function TBV_DO_canDrop(aEvent, aDragSession) {
|
||||
// Cache the dataTransfer
|
||||
PlacesControllerDragHelper.currentDataTransfer = aEvent.dataTransfer;
|
||||
|
||||
var ip = this._self.insertionPoint;
|
||||
return ip && PlacesControllerDragHelper.canDrop(ip);
|
||||
},
|
||||
|
@ -939,13 +959,19 @@
|
|||
},
|
||||
|
||||
onDrop: function TBV_DO_onDrop(event, dropData, session) {
|
||||
// Cache the dataTransfer
|
||||
PlacesControllerDragHelper.currentDataTransfer = event.dataTransfer;
|
||||
|
||||
var dropPoint = this._getDropPoint(event);
|
||||
if (dropPoint == null)
|
||||
if (!dropPoint)
|
||||
return;
|
||||
PlacesControllerDragHelper.onDrop(dropPoint.ip);
|
||||
},
|
||||
|
||||
onDragExit: function TBV_DO_onDragExit(event, session) {
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
PlacesControllerDragHelper.currentDataTransfer = null;
|
||||
|
||||
// Set timer to turn off indicator bar (if we turn it off
|
||||
// here, dragenter might be called immediately after, creating
|
||||
// flicker.)
|
||||
|
@ -955,17 +981,12 @@
|
|||
// Close any folder being hovered over
|
||||
if (this._overFolder.node)
|
||||
this._overFolder.closeTimer = this._setTimer(this._overFolder.hoverTime);
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
|
||||
this._self._draggedNode = null;
|
||||
},
|
||||
|
||||
getSupportedFlavours: function TBV_DO_getSupportedFlavours() {
|
||||
var flavorSet = new FlavourSet();
|
||||
var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
|
||||
for (var i = 0; i < types.length; ++i)
|
||||
flavorSet.appendFlavour(types[i]);
|
||||
return flavorSet;
|
||||
return PlacesControllerDragHelper.flavourSet;
|
||||
}
|
||||
})]]></field>
|
||||
|
||||
|
@ -1056,11 +1077,14 @@
|
|||
// just add to the end.
|
||||
if (aParentPopup._endMarker != -1) {
|
||||
aParentPopup.insertBefore(element,
|
||||
aParentPopup.childNodes[aParentPopup._endMarker++]);
|
||||
aParentPopup.childNodes[aParentPopup._endMarker]);
|
||||
}
|
||||
else
|
||||
aParentPopup.appendChild(element);
|
||||
}
|
||||
|
||||
if (aParentPopup._endMarker != -1)
|
||||
aParentPopup._endMarker++;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -1130,6 +1154,17 @@
|
|||
nsDragAndDrop.dragExit(event, this._DNDObserver);
|
||||
]]></handler>
|
||||
<handler event="popupshowing" phase="capturing"><![CDATA[
|
||||
// Don't show the popup if we are dragging a container.
|
||||
if (this._draggingContainer) {
|
||||
this._draggingContainer = false;
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
// Allow drag and drop of folders in Linux.
|
||||
// We must prevent popupshowing event from firing when shift is pressed.
|
||||
event.preventDefault();
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
var popup = event.originalTarget;
|
||||
|
||||
// Avoid handling popupshowing of inner views
|
||||
|
@ -1158,8 +1193,18 @@
|
|||
this._openedMenuButton = null;
|
||||
]]></handler>
|
||||
|
||||
<handler event="mousedown"><![CDATA[
|
||||
// Allow drag and drop of folders in Linux.
|
||||
// We must prevent popupshowing event from firing when shift is pressed.
|
||||
var target = event.originalTarget;
|
||||
if (event.button == 1 && event.shiftKey &&
|
||||
target.localName == "toolbarbutton" && target.type == "menu")
|
||||
this._draggingContainer = true;
|
||||
]]></handler>
|
||||
|
||||
<handler event="mousemove"><![CDATA[
|
||||
if (this._openedMenuButton == null || PlacesControllerDragHelper.getSession())
|
||||
if (this._openedMenuButton == null ||
|
||||
PlacesControllerDragHelper.getSession())
|
||||
return;
|
||||
|
||||
var target = event.originalTarget;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
# Contributor(s):
|
||||
# Ben Goodger <beng@google.com>
|
||||
# Annie Sullivan <annie.sullivan@gmail.com>
|
||||
# Marco Bonardo <mak77@bonardo.net>
|
||||
#
|
||||
# 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
|
||||
|
@ -434,11 +435,10 @@
|
|||
// there is no insertion point for history queries
|
||||
// so bail out now and save a lot of work when updating commands
|
||||
var resultNode = this.getResultNode();
|
||||
if (PlacesUtils.nodeIsQuery(resultNode)) {
|
||||
var options = asQuery(resultNode).queryOptions;
|
||||
if (options.queryType == options.QUERY_TYPE_HISTORY)
|
||||
if (PlacesUtils.nodeIsQuery(resultNode) &&
|
||||
asQuery(resultNode).queryOptions.queryType ==
|
||||
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
|
||||
return this._cachedInsertionPoint = null;
|
||||
}
|
||||
|
||||
var orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
// If there is no selection, insert at the end of the container.
|
||||
|
@ -488,18 +488,6 @@
|
|||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="_disallowInsertion">
|
||||
<parameter name="aContainer"/>
|
||||
<body><![CDATA[
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_getInsertionPoint">
|
||||
<parameter name="index"/>
|
||||
<parameter name="orientation"/>
|
||||
|
@ -519,14 +507,13 @@
|
|||
container = lastSelected;
|
||||
index = -1;
|
||||
}
|
||||
else if (!this._disallowInsertion(lastSelected) &&
|
||||
lastSelected.containerOpen &&
|
||||
else if (lastSelected.containerOpen &&
|
||||
orientation == Ci.nsITreeView.DROP_AFTER &&
|
||||
lastSelected.hasChildren) {
|
||||
// If the last selected item is an open container and the user is
|
||||
// trying to drag into it as a first item, really insert into it.
|
||||
container = lastSelected;
|
||||
orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
index = 0;
|
||||
}
|
||||
else {
|
||||
|
@ -537,7 +524,7 @@
|
|||
|
||||
// avoid the potentially expensive call to getIndexOfNode()
|
||||
// if we know this container doesn't allow insertion
|
||||
if (this._disallowInsertion(container))
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
var queryOptions = asQuery(result.root).queryOptions;
|
||||
|
@ -562,7 +549,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (this._disallowInsertion(container))
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
|
@ -675,14 +662,10 @@
|
|||
|
||||
<!-- nsDragAndDrop -->
|
||||
<method name="onDragStart">
|
||||
<parameter name="event"/>
|
||||
<parameter name="xferData"/>
|
||||
<parameter name="dragAction"/>
|
||||
<parameter name="aEvent"/>
|
||||
<parameter name="aXferData"/>
|
||||
<parameter name="aDragAction"/>
|
||||
<body><![CDATA[
|
||||
// Drag and Drop does not work while a tree view is sorted.
|
||||
if (this.getAttribute("sortActive") == "true")
|
||||
throw Cr.NS_OK;
|
||||
|
||||
var nodes = this.getSelectionNodes();
|
||||
for (var i = 0; i < nodes.length; ++i) {
|
||||
var node = nodes[i];
|
||||
|
@ -690,61 +673,83 @@
|
|||
// Disallow dragging the root node of a tree
|
||||
var parent = node.parent;
|
||||
if (!parent)
|
||||
throw Cr.NS_OK;
|
||||
return;
|
||||
|
||||
// If this node is part of a readonly container (e.g. a livemark) it
|
||||
// cannot be moved, only copied, so we must change the action used
|
||||
// by the drag session.
|
||||
if (PlacesUtils.nodeIsTagQuery(parent) ||
|
||||
!PlacesControllerDragHelper.canMoveContainerNode(node)) {
|
||||
// XXX DOES NOTHING! dragAction doesn't persist
|
||||
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
// If this node is child of a readonly container (e.g. a livemark)
|
||||
// or cannot be moved, we must force a copy.
|
||||
if (!PlacesControllerDragHelper.canMoveNode(node)) {
|
||||
aEvent.dataTransfer.effectAllowed = "copyLink";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// XXXben - the drag wrapper should do this automatically.
|
||||
if (event.ctrlKey)
|
||||
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
|
||||
// Stuff the encoded selection into the transferable data object
|
||||
xferData.data = this._controller.getTransferData(dragAction.action);
|
||||
this._controller.setDataTransfer(aEvent);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsDragAndDrop -->
|
||||
<method name="canDrop">
|
||||
<parameter name="event"/>
|
||||
<parameter name="session"/>
|
||||
<body><![CDATA[
|
||||
<parameter name="aEvent"/>
|
||||
<parameter name="aDragSession"/>
|
||||
<body><![CDATA[
|
||||
// Cache the dataTransfer for the view
|
||||
PlacesControllerDragHelper.currentDataTransfer = aEvent.dataTransfer;
|
||||
|
||||
var row = { }, col = { }, child = { };
|
||||
this.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col,
|
||||
child);
|
||||
return this.view.canDrop(row.value, -1);
|
||||
this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY,
|
||||
row, col, child);
|
||||
var node = row.value != -1 ?
|
||||
this.getResultView().nodeForTreeIndex(row.value) :
|
||||
this.getResultNode();
|
||||
// cache the dropTarget for the view
|
||||
PlacesControllerDragHelper.currentDropTarget = node;
|
||||
|
||||
// We have to calculate the orientation since view.canDrop will use
|
||||
// it and we want to be consistent with the dropfeedback
|
||||
var tbo = this.treeBoxObject;
|
||||
var rowHeight = tbo.rowHeight;
|
||||
var eventY = aEvent.clientY - tbo.treeBody.boxObject.y -
|
||||
rowHeight * (row.value - tbo.getFirstVisibleRow());
|
||||
|
||||
var orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
|
||||
if (row.value == -1) {
|
||||
// If the row is not valid we try to insert inside the resultNode.
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
}
|
||||
else if (PlacesUtils.nodeIsContainer(node) &&
|
||||
eventY > rowHeight * 0.75) {
|
||||
// If we are below the 75% of a container the treeview we try
|
||||
// to drop after the node.
|
||||
orientation = Ci.nsITreeView.DROP_AFTER;
|
||||
}
|
||||
else if (PlacesUtils.nodeIsContainer(node) &&
|
||||
eventY > rowHeight * 0.25) {
|
||||
// If we are below the 25% of a container the treeview we try
|
||||
// to drop inside the node.
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
}
|
||||
|
||||
return this.view.canDrop(row.value, orientation);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsDragAndDrop -->
|
||||
<method name="onDragOver">
|
||||
<parameter name="event"/>
|
||||
<parameter name="flavor"/>
|
||||
<parameter name="session"/>
|
||||
<body><![CDATA[
|
||||
var dragService =
|
||||
Cc["@mozilla.org/widget/dragservice;1"].
|
||||
getService(Ci.nsIDragService);
|
||||
var dragSession = dragService.getCurrentSession();
|
||||
dragSession.canDrop = this.canDrop(event, session);
|
||||
<parameter name="aEvent"/>
|
||||
<parameter name="aFlavour"/>
|
||||
<parameter name="aDragSession"/>
|
||||
<body><![CDATA[
|
||||
if (!this.canDrop(aEvent, aDragSession))
|
||||
aEvent.dataTransfer.effectAllowed = "none";
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsDragAndDrop -->
|
||||
<method name="getSupportedFlavours">
|
||||
<body><![CDATA[
|
||||
var flavorSet = new FlavourSet();
|
||||
var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
|
||||
for (var i = 0; i < types.length; ++i)
|
||||
flavorSet.appendFlavour(types[i]);
|
||||
return flavorSet;
|
||||
return PlacesControllerDragHelper.flavourSet;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -782,7 +787,6 @@
|
|||
}
|
||||
]]></handler>
|
||||
<handler event="draggesture"><![CDATA[
|
||||
// XXXben ew.
|
||||
if (event.target.localName == "treechildren")
|
||||
nsDragAndDrop.startDrag(event, this);
|
||||
]]></handler>
|
||||
|
@ -790,6 +794,13 @@
|
|||
if (event.target.localName == "treechildren")
|
||||
nsDragAndDrop.dragOver(event, this);
|
||||
]]></handler>
|
||||
<handler event="drop"><![CDATA[
|
||||
PlacesControllerDragHelper.currentDataTransfer = event.dataTransfer;
|
||||
]]></handler>
|
||||
<handler event="dragexit"><![CDATA[
|
||||
PlacesControllerDragHelper.currentDataTransfer = null;
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
|
|
|
@ -996,35 +996,14 @@ PlacesTreeView.prototype = {
|
|||
if (!this._result)
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
|
||||
var node = aRow != -1 ? this.nodeForTreeIndex(aRow) : this._result.root;
|
||||
// drop position into a sorted treeview would be wrong
|
||||
if (this.isSorted())
|
||||
return false;
|
||||
|
||||
if (aOrientation == Ci.nsITreeView.DROP_ON) {
|
||||
// The user cannot drop an item into itself or a read-only container
|
||||
var dragService = Cc["@mozilla.org/widget/dragservice;1"].
|
||||
getService(Ci.nsIDragService);
|
||||
var dragSession = dragService.getCurrentSession();
|
||||
var elt = dragSession.sourceNode.parentNode;
|
||||
if (elt.localName == "tree" && elt.view == this &&
|
||||
this.selection.isSelected(aRow))
|
||||
return false;
|
||||
}
|
||||
|
||||
var ip = this._getInsertionPoint(aRow, aOrientation);
|
||||
return ip && PlacesControllerDragHelper.canDrop(ip);
|
||||
},
|
||||
|
||||
// XXXmano: these two are copied over from tree.xml, to fix this we need to
|
||||
// either add a helper to PlacesUtils or keep it here and add insertionPoint
|
||||
// to the view interface.
|
||||
_disallowInsertion: function PTV__disallowInsertion(aContainer) {
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
},
|
||||
|
||||
_getInsertionPoint: function PTV__getInsertionPoint(index, orientation) {
|
||||
var container = this._result.root;
|
||||
var dropNearItemId = -1;
|
||||
|
@ -1038,14 +1017,13 @@ PlacesTreeView.prototype = {
|
|||
container = lastSelected;
|
||||
index = -1;
|
||||
}
|
||||
else if (!this._disallowInsertion(lastSelected) &&
|
||||
lastSelected.containerOpen &&
|
||||
else if (lastSelected.containerOpen &&
|
||||
orientation == Ci.nsITreeView.DROP_AFTER &&
|
||||
lastSelected.hasChildren) {
|
||||
// If the last selected item is an open container and the user is
|
||||
// trying to drag into it as a first item, really insert into it.
|
||||
container = lastSelected;
|
||||
orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
index = 0;
|
||||
}
|
||||
else {
|
||||
|
@ -1056,12 +1034,13 @@ PlacesTreeView.prototype = {
|
|||
|
||||
// avoid the potentially expensive call to getIndexOfNode()
|
||||
// if we know this container doesn't allow insertion
|
||||
if (this._disallowInsertion(container))
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
var queryOptions = asQuery(this._result.root).queryOptions;
|
||||
if (queryOptions.sortingMode != Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
|
||||
// If we are within a sorted view, insert at the end
|
||||
if (queryOptions.sortingMode !=
|
||||
Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
|
||||
// If we are within a sorted view, insert at the ends
|
||||
index = -1;
|
||||
}
|
||||
else if (queryOptions.excludeItems ||
|
||||
|
@ -1080,7 +1059,7 @@ PlacesTreeView.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
if (this._disallowInsertion(container))
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
|
@ -1095,7 +1074,7 @@ PlacesTreeView.prototype = {
|
|||
// since this information is specific to the tree view.
|
||||
var ip = this._getInsertionPoint(aRow, aOrientation);
|
||||
if (!ip)
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
return;
|
||||
PlacesControllerDragHelper.onDrop(ip);
|
||||
},
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Asaf Romano <mano@mozilla.com>
|
||||
* Sungjoon Steve Won <stevewon@gmail.com>
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -377,10 +378,12 @@ var PlacesUIUtils = {
|
|||
return this.ptm.moveItem(data.id, container, index);
|
||||
break;
|
||||
default:
|
||||
if (type == PlacesUtils.TYPE_X_MOZ_URL || type == PlacesUtils.TYPE_UNICODE) {
|
||||
var title = (type == PlacesUtils.TYPE_X_MOZ_URL) ? data.title : data.uri;
|
||||
return this.ptm.createItem(PlacesUtils._uri(data.uri), container, index,
|
||||
title);
|
||||
if (type == PlacesUtils.TYPE_X_MOZ_URL ||
|
||||
type == PlacesUtils.TYPE_UNICODE) {
|
||||
var title = (type == PlacesUtils.TYPE_X_MOZ_URL) ? data.title :
|
||||
data.uri;
|
||||
return this.ptm.createItem(PlacesUtils._uri(data.uri),
|
||||
container, index, title);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -1035,51 +1038,45 @@ var PlacesUIUtils = {
|
|||
},
|
||||
|
||||
cleanPlacesPopup: function PU_cleanPlacesPopup(aPopup) {
|
||||
// Find static menuitems at the start and at the end of the menupopup,
|
||||
// marked by builder="start" and builder="end" attributes, and set
|
||||
// markers to keep track of their indices.
|
||||
// Remove places popup children and update markers to keep track of
|
||||
// their indices.
|
||||
var start = aPopup._startMarker != -1 ? aPopup._startMarker + 1 : 0;
|
||||
var end = aPopup._endMarker != -1 ? aPopup._endMarker :
|
||||
aPopup.childNodes.length;
|
||||
var items = [];
|
||||
aPopup._startMarker = -1;
|
||||
aPopup._endMarker = -1;
|
||||
for (var i = 0; i < aPopup.childNodes.length; ++i) {
|
||||
var placesNodeFound = false;
|
||||
for (var i = start; i < end; ++i) {
|
||||
var item = aPopup.childNodes[i];
|
||||
if (item.getAttribute("builder") == "start") {
|
||||
aPopup._startMarker = i;
|
||||
continue;
|
||||
}
|
||||
if (item.getAttribute("builder") == "end") {
|
||||
// we need to do this for menus that have static content at the end but
|
||||
// are initially empty, eg. the history menu, we need to know where to
|
||||
// start inserting new items.
|
||||
aPopup._endMarker = i;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if ((aPopup._startMarker != -1) && (aPopup._endMarker == -1))
|
||||
if (item.node) {
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
// If static items at the beginning were found, remove all items between
|
||||
// them and the static content at the end.
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
// skip the empty menu item
|
||||
if (aPopup._emptyMenuItem != items[i]) {
|
||||
aPopup.removeChild(items[i]);
|
||||
if (aPopup._endMarker > 0)
|
||||
--aPopup._endMarker;
|
||||
placesNodeFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If no static items were found at the beginning, remove all items before
|
||||
// the static items at the end.
|
||||
if (aPopup._startMarker == -1) {
|
||||
var end = aPopup._endMarker == -1 ?
|
||||
aPopup.childNodes.length - 1 : aPopup._endMarker - 1;
|
||||
for (var i = end; i >= 0; i--) {
|
||||
// skip the empty menu item
|
||||
if (aPopup._emptyMenuItem != aPopup.childNodes[i]) {
|
||||
aPopup.removeChild(aPopup.childNodes[i]);
|
||||
if (aPopup._endMarker > 0)
|
||||
--aPopup._endMarker;
|
||||
else {
|
||||
// This is static content...
|
||||
if (!placesNodeFound)
|
||||
// ...at the start of the popup
|
||||
// Initialized in menu.xml, in the base binding
|
||||
aPopup._startMarker++;
|
||||
else {
|
||||
// ...after places nodes
|
||||
aPopup._endMarker = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
aPopup.removeChild(items[i]);
|
||||
if (aPopup._endMarker != -1)
|
||||
aPopup._endMarker--;
|
||||
}
|
||||
},
|
||||
|
||||
getBestTitle: function PU_getBestTitle(aNode) {
|
||||
|
@ -1232,13 +1229,3 @@ var PlacesUIUtils = {
|
|||
return this.allBookmarksFolderId = this.leftPaneQueries["AllBookmarks"];
|
||||
}
|
||||
};
|
||||
|
||||
PlacesUIUtils.placesFlavors = [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE];
|
||||
|
||||
PlacesUIUtils.GENERIC_VIEW_DROP_TYPES = [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE,
|
||||
PlacesUtils.TYPE_X_MOZ_URL,
|
||||
PlacesUtils.TYPE_UNICODE];
|
||||
|
|
|
@ -1809,12 +1809,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
color: HighlightText !important;
|
||||
}
|
||||
|
||||
/* Bookmark drag and drop styles */
|
||||
.bookmark-item[dragover-into="true"] > .menu-iconic-text {
|
||||
background: Highlight !important;
|
||||
color: HighlightText !important;
|
||||
}
|
||||
|
||||
/* rules for menupopup drop indicators */
|
||||
.menupopup-drop-indicator-bar {
|
||||
position: relative;
|
||||
|
|
|
@ -606,6 +606,10 @@ var PlacesUtils = {
|
|||
var parts = blob.split("\n");
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var uriString = parts[i];
|
||||
// text/uri-list is converted to TYPE_UNICODE but it could contain
|
||||
// comments line prepended by #, we should skip them
|
||||
if (uriString.substr(0, 1) == '\x23')
|
||||
continue;
|
||||
// note: this._uri() will throw if uriString is not a valid URI
|
||||
if (uriString != "" && this._uri(uriString))
|
||||
nodes.push({ uri: uriString,
|
||||
|
|
Загрузка…
Ссылка в новой задаче