summaryrefslogtreecommitdiff
path: root/browser/base/content/browser-menudragging.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/browser-menudragging.js')
-rw-r--r--browser/base/content/browser-menudragging.js351
1 files changed, 351 insertions, 0 deletions
diff --git a/browser/base/content/browser-menudragging.js b/browser/base/content/browser-menudragging.js
new file mode 100644
index 000000000..29142a662
--- /dev/null
+++ b/browser/base/content/browser-menudragging.js
@@ -0,0 +1,351 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Based on original code by alice0775 https://github.com/alice0775
+
+
+"use strict";
+var browserMenuDragging = {
+ //-- config --
+ STAY_OPEN_ONDRAGEXIT: false,
+ DEBUG: false,
+ //-- config --
+
+ menupopup: ['bookmarksMenuPopup',
+ 'PlacesToolbar',
+ 'BMB_bookmarksPopup',
+ 'appmenu_bookmarksPopup',
+ 'BookmarksMenuToolButtonPopup',
+ 'UnsortedBookmarksFolderToolButtonPopup',
+ 'bookmarksMenuPopup-context'],
+ timer:[],
+ count:[],
+
+
+ init: function() {
+ window.removeEventListener('load', this, false);
+ window.addEventListener('unload', this, false);
+ this.addPrefListener(this.PrefListener);
+
+ window.addEventListener('aftercustomization', this, false);
+
+ this.initPref();
+ this.delayedStartup();
+ },
+
+ uninit: function() {
+ window.removeEventListener('unload', this, false);
+ this.removePrefListener(this.PrefListener);
+
+ window.removeEventListener('aftercustomization', this, false);
+
+ for (var i = 0; i < this.menupopup.length; i++){
+ var menupopup = document.getElementById(this.menupopup[i]);
+ if (menupopup){
+ menupopup.removeEventListener('popupshowing', this, false);
+ menupopup.removeEventListener('popuphiding', this, false);
+ }
+ }
+
+ },
+
+ initPref: function() {
+ this.STAY_OPEN_ONDRAGEXIT =
+ Services.prefs.getBoolPref('browser.menu.dragging.stayOpen', false);
+ this.DEBUG =
+ Services.prefs.getBoolPref('browser.menu.dragging.debug', false);
+ },
+
+ //delayed startup
+ delayedStartup: function() {
+ //wait until construction of bookmarksBarContent is completed.
+ for (var i = 0; i < this.menupopup.length; i++) {
+ this.count[i] = 0;
+ this.timer[i] = setInterval(function(self, i) {
+ if(++self.count[i] > 50 || document.getElementById(self.menupopup[i])) {
+ clearInterval(self.timer[i]);
+ var menupopup = document.getElementById(self.menupopup[i]);
+ if (menupopup) {
+ menupopup.addEventListener('popupshowing', self, false);
+ menupopup.addEventListener('popuphiding', self, false);
+ }
+ }
+ }, 250, this, i);
+ }
+ },
+
+ handleEvent: function(event) {
+ switch (event.type) {
+ case 'popupshowing':
+ this.popupshowing(event);
+ break;
+ case 'popuphiding':
+ this.popuphiding(event);
+ break;
+ case 'aftercustomization':
+ setTimeout(function(self){self.delayedStartup(self);}, 0, this);
+ break;
+ case 'load':
+ this.init();
+ break;
+ case 'unload':
+ this.uninit();
+ break;
+ }
+ },
+
+ popuphiding: function(event) {
+ var menupopup = event.originalTarget;
+ menupopup.parentNode.parentNode.openNode = null;
+
+ if (menupopup.parentNode.localName == 'toolbarbutton') {
+ // Fix for Bug 225434 - dragging bookmark from personal toolbar and releasing
+ // (on same bookmark or elsewhere) or clicking on bookmark menu then cancelling
+ // leaves button depressed/sunken when hovered
+ menupopup.parentNode.parentNode._openedMenuButton = null;
+
+ if (!PlacesControllerDragHelper.getSession()) {
+ // Clear the dragover attribute if present, if we are dragging into a
+ // folder in the hierachy of current opened popup we don't clear
+ // this attribute on clearOverFolder. See Notify for closeTimer.
+ if (menupopup.parentNode.hasAttribute('dragover')) {
+ menupopup.parentNode.removeAttribute('dragover');
+ }
+ }
+ }
+ },
+
+ popupshowing: function(event) {
+ var menupopup = event.originalTarget;
+ browserMenuDragging.debug("popupshowing ===============\n" + menupopup.parentNode.getAttribute('label'));
+
+ var parentPopup = menupopup.parentNode.parentNode;
+
+ if (!!parentPopup.openNode) {
+ try {
+ parentPopup.openNode.hidePopup();
+ } catch(e) {}
+ }
+ parentPopup.openNode = menupopup;
+
+ menupopup.onDragStart = function (event) {
+ // Bug 555474 - While bookmark is dragged, the tooltip should not appear
+ browserMenuDragging.hideTooltip();
+ }
+
+ menupopup.onDragOver = function (event) {
+ // Bug 555474 - While bookmark is dragged, the tooltip should not appear
+ browserMenuDragging.hideTooltip();
+
+ var target = event.originalTarget;
+ while (target) {
+ if (/menupopup/.test(target.localName)) {
+ break;
+ }
+ target = target.parentNode;
+ }
+
+ if (this != target) {
+ return;
+ }
+
+ event.stopPropagation();
+ browserMenuDragging.debug("onDragOver " + "\n" + this.parentNode.getAttribute('label'));
+
+ PlacesControllerDragHelper.currentDropTarget = event.target;
+ let dt = event.dataTransfer;
+
+ let dropPoint = this._getDropPoint(event);
+
+ if (!dropPoint || !dropPoint.ip ||
+ !PlacesControllerDragHelper.canDrop(dropPoint.ip, dt)) {
+ this._indicatorBar.hidden = true;
+ event.stopPropagation();
+ return;
+ }
+
+ // Mark this popup as being dragged over.
+ this.setAttribute('dragover', 'true');
+
+ if (dropPoint.folderElt) {
+ // We are dragging over a folder.
+ // _overFolder should take the care of opening it on a timer.
+ if (this._overFolder.elt &&
+ this._overFolder.elt != dropPoint.folderElt) {
+ }
+ if (!this._overFolder.elt) {
+ this._overFolder.elt = dropPoint.folderElt;
+ // Create the timer to open this folder.
+ this._overFolder.openTimer = this._overFolder
+ .setTimer(this._overFolder.hoverTime);
+ }
+ }
+ else {
+ // We are not dragging over a folder.
+ }
+
+ // Autoscroll the popup strip if we drag over the scroll buttons.
+ let anonid = event.originalTarget.getAttribute('anonid');
+ let scrollDir = anonid == 'scrollbutton-up' ? -1 :
+ anonid == 'scrollbutton-down' ? 1 : 0;
+ if (scrollDir != 0) {
+ this._scrollBox.scrollByIndex(scrollDir, false);
+ }
+
+ // Check if we should hide the drop indicator for this target.
+ if (dropPoint.folderElt || this._hideDropIndicator(event)) {
+ this._indicatorBar.hidden = true;
+ event.preventDefault();
+ event.stopPropagation();
+ return;
+ }
+
+ // We should display the drop indicator relative to the arrowscrollbox.
+ let sbo = this._scrollBox.scrollBoxObject;
+ let newMarginTop = 0;
+ if (scrollDir == 0) {
+ let elt = this.firstChild;
+ while (elt && event.screenY > elt.boxObject.screenY +
+ elt.boxObject.height / 2) {
+ elt = elt.nextSibling;
+ }
+ newMarginTop = elt ? elt.boxObject.screenY - sbo.screenY : sbo.height;
+ } else if (scrollDir == 1) {
+ newMarginTop = sbo.height;
+ }
+
+ // Set the new marginTop based on arrowscrollbox.
+ newMarginTop += sbo.y - this._scrollBox.boxObject.y;
+ this._indicatorBar.firstChild.style.marginTop = newMarginTop + 'px';
+ this._indicatorBar.hidden = false;
+
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ menupopup.onDragExit = function (event) {
+ var target = event.originalTarget;
+ while (target) {
+ if (/menupopup/.test(target.localName)) {
+ break;
+ }
+ target = target.parentNode;
+ }
+
+ if (this != target) {
+ return;
+ }
+
+ event.stopPropagation();
+ browserMenuDragging.debug("onDragExit " + browserMenuDragging.STAY_OPEN_ONDRAGEXIT);
+
+ PlacesControllerDragHelper.currentDropTarget = null;
+ this.removeAttribute('dragover');
+
+ // If we have not moved to a valid new target clear the drop indicator
+ // this happens when moving out of the popup.
+ target = event.relatedTarget;
+ if (!target) {
+ this._indicatorBar.hidden = true;
+ }
+
+ // Close any folder being hovered over
+ if (this._overFolder.elt) {
+ this._overFolder.closeTimer = this._overFolder.setTimer(this._overFolder.hoverTime);
+ }
+
+ // The auto-opened 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.
+ // 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') ||
+ !browserMenuDragging.STAY_OPEN_ONDRAGEXIT &&
+ this.hasAttribute('dragstart')) {
+ this._overFolder.closeMenuTimer = this._overFolder
+ .setTimer(this._overFolder.hoverTime);
+ }
+
+ event.stopPropagation();
+ }
+
+ menupopup.addEventListener('dragstart', menupopup.onDragStart, true);
+ menupopup.addEventListener('dragover', menupopup.onDragOver, true);
+ menupopup.addEventListener('dragleave', menupopup.onDragExit, true);
+ },
+
+ hideTooltip: function() {
+ ['bhTooltip', 'btTooltip2'].forEach(function(id) {
+ var tooltip = document.getElementById(id);
+ if (tooltip) {
+ tooltip.hidePopup();
+ }
+ });
+ },
+
+ get getVer() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ var info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
+ var ver = parseInt(info.version.substr(0,3) * 10,10) / 10;
+ return ver;
+ },
+
+ debug: function(aMsg) {
+ if (!browserMenuDragging.DEBUG) {
+ return;
+ }
+ Components.classes["@mozilla.org/consoleservice;1"]
+ .getService(Components.interfaces.nsIConsoleService)
+ .logStringMessage(aMsg);
+ },
+
+ setPref: function(aPrefString, aPrefType, aValue) {
+ var xpPref = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefService);
+ try{
+ switch (aPrefType){
+ case 'complex':
+ return xpPref.setComplexValue(aPrefString, Components.interfaces.nsILocalFile, aValue); break;
+ case 'str':
+ return xpPref.setCharPref(aPrefString, aValue); break;
+ case 'int':
+ aValue = parseInt(aValue);
+ return xpPref.setIntPref(aPrefString, aValue); break;
+ case 'bool':
+ default:
+ return xpPref.setBoolPref(aPrefString, aValue); break;
+ }
+ } catch(e) {}
+ return null;
+ },
+
+ addPrefListener: function(aObserver) {
+ try {
+ var pbi = Components.classes["@mozilla.org/preferences;1"].
+ getService(Components.interfaces.nsIPrefBranch2);
+ pbi.addObserver(aObserver.domain, aObserver, false);
+ } catch(e) {}
+ },
+
+ removePrefListener: function(aObserver) {
+ try {
+ var pbi = Components.classes["@mozilla.org/preferences;1"].
+ getService(Components.interfaces.nsIPrefBranch2);
+ pbi.removeObserver(aObserver.domain, aObserver);
+ } catch(e) {}
+ },
+
+ PrefListener:{
+ domain : 'browser.menu.dragging.stayOpen',
+
+ observe : function(aSubject, aTopic, aPrefstring) {
+ if (aTopic == 'nsPref:changed') {
+ browserMenuDragging.initPref();
+ }
+ }
+ }
+}
+
+window.addEventListener('load', browserMenuDragging, false); \ No newline at end of file