toolkit/content/customizeToolbar.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 var gToolboxDocument = null;
     6 var gToolbox = null;
     7 var gCurrentDragOverItem = null;
     8 var gToolboxChanged = false;
     9 var gToolboxSheet = false;
    10 var gPaletteBox = null;
    12 Components.utils.import("resource://gre/modules/Services.jsm");
    14 function onLoad()
    15 {
    16   if ("arguments" in window && window.arguments[0]) {
    17     InitWithToolbox(window.arguments[0]);
    18     repositionDialog(window);
    19   }
    20   else if (window.frameElement &&
    21            "toolbox" in window.frameElement) {
    22     gToolboxSheet = true;
    23     InitWithToolbox(window.frameElement.toolbox);
    24     repositionDialog(window.frameElement.panel);
    25   }
    26 }
    28 function InitWithToolbox(aToolbox)
    29 {
    30   gToolbox = aToolbox;
    31   dispatchCustomizationEvent("beforecustomization");
    32   gToolboxDocument = gToolbox.ownerDocument;
    33   gToolbox.customizing = true;
    34   forEachCustomizableToolbar(function (toolbar) {
    35     toolbar.setAttribute("customizing", "true");
    36   });
    37   gPaletteBox = document.getElementById("palette-box");
    39   var elts = getRootElements();
    40   for (let i=0; i < elts.length; i++) {
    41     elts[i].addEventListener("dragstart", onToolbarDragStart, true);
    42     elts[i].addEventListener("dragover", onToolbarDragOver, true);
    43     elts[i].addEventListener("dragexit", onToolbarDragExit, true);
    44     elts[i].addEventListener("drop", onToolbarDrop, true);
    45   }
    47   initDialog();
    48 }
    50 function onClose()
    51 {
    52   if (!gToolboxSheet)
    53     window.close();
    54   else
    55     finishToolbarCustomization();
    56 }
    58 function onUnload()
    59 {
    60   if (!gToolboxSheet)
    61     finishToolbarCustomization();
    62 }
    64 function finishToolbarCustomization()
    65 {
    66   removeToolboxListeners();
    67   unwrapToolbarItems();
    68   persistCurrentSets();
    69   gToolbox.customizing = false;
    70   forEachCustomizableToolbar(function (toolbar) {
    71     toolbar.removeAttribute("customizing");
    72   });
    74   notifyParentComplete();
    75 }
    77 function initDialog()
    78 {
    79   if (!gToolbox.toolbarset) {
    80     document.getElementById("newtoolbar").hidden = true;
    81   }
    83   var mode = gToolbox.getAttribute("mode");
    84   document.getElementById("modelist").value = mode;
    85   var smallIconsCheckbox = document.getElementById("smallicons");
    86   smallIconsCheckbox.checked = gToolbox.getAttribute("iconsize") == "small";
    87   if (mode == "text")
    88     smallIconsCheckbox.disabled = true;
    90   // Build up the palette of other items.
    91   buildPalette();
    93   // Wrap all the items on the toolbar in toolbarpaletteitems.
    94   wrapToolbarItems();
    95 }
    97 function repositionDialog(aWindow)
    98 {
    99   // Position the dialog touching the bottom of the toolbox and centered with
   100   // it.
   101   if (!aWindow)
   102     return;
   104   var width;
   105   if (aWindow != window)
   106     width = aWindow.getBoundingClientRect().width;
   107   else if (document.documentElement.hasAttribute("width"))
   108     width = document.documentElement.getAttribute("width");
   109   else
   110     width = parseInt(document.documentElement.style.width);
   111   var screenX = gToolbox.boxObject.screenX
   112                 + ((gToolbox.boxObject.width - width) / 2);
   113   var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height;
   115   aWindow.moveTo(screenX, screenY);
   116 }
   118 function removeToolboxListeners()
   119 {
   120   var elts = getRootElements();
   121   for (let i=0; i < elts.length; i++) {
   122     elts[i].removeEventListener("dragstart", onToolbarDragStart, true);
   123     elts[i].removeEventListener("dragover", onToolbarDragOver, true);
   124     elts[i].removeEventListener("dragexit", onToolbarDragExit, true);
   125     elts[i].removeEventListener("drop", onToolbarDrop, true);
   126   }
   127 }
   129 /**
   130  * Invoke a callback on the toolbox to notify it that the dialog is done
   131  * and going away.
   132  */
   133 function notifyParentComplete()
   134 {
   135   if ("customizeDone" in gToolbox)
   136     gToolbox.customizeDone(gToolboxChanged);
   137   dispatchCustomizationEvent("aftercustomization");
   138 }
   140 function toolboxChanged(aType)
   141 {
   142   gToolboxChanged = true;
   143   if ("customizeChange" in gToolbox)
   144     gToolbox.customizeChange(aType);
   145   dispatchCustomizationEvent("customizationchange");
   146 }
   148 function dispatchCustomizationEvent(aEventName) {
   149   var evt = document.createEvent("Events");
   150   evt.initEvent(aEventName, true, true);
   151   gToolbox.dispatchEvent(evt);
   152 }
   154 /**
   155  * Persist the current set of buttons in all customizable toolbars to
   156  * localstore.
   157  */
   158 function persistCurrentSets()
   159 {
   160   if (!gToolboxChanged || gToolboxDocument.defaultView.closed)
   161     return;
   163   var customCount = 0;
   164   forEachCustomizableToolbar(function (toolbar) {
   165     // Calculate currentset and store it in the attribute.
   166     var currentSet = toolbar.currentSet;
   167     toolbar.setAttribute("currentset", currentSet);
   169     var customIndex = toolbar.hasAttribute("customindex");
   170     if (customIndex) {
   171       if (!toolbar.hasChildNodes()) {
   172         // Remove custom toolbars whose contents have been removed.
   173         gToolbox.removeChild(toolbar);
   174       } else if (gToolbox.toolbarset) {
   175         // Persist custom toolbar info on the <toolbarset/>
   176         gToolbox.toolbarset.setAttribute("toolbar"+(++customCount),
   177                                          toolbar.toolbarName + ":" + currentSet);
   178         gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
   179       }
   180     }
   182     if (!customIndex) {
   183       // Persist the currentset attribute directly on hardcoded toolbars.
   184       gToolboxDocument.persist(toolbar.id, "currentset");
   185     }
   186   });
   188   // Remove toolbarX attributes for removed toolbars.
   189   while (gToolbox.toolbarset && gToolbox.toolbarset.hasAttribute("toolbar"+(++customCount))) {
   190     gToolbox.toolbarset.removeAttribute("toolbar"+customCount);
   191     gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
   192   }
   193 }
   195 /**
   196  * Wraps all items in all customizable toolbars in a toolbox.
   197  */
   198 function wrapToolbarItems()
   199 {
   200   forEachCustomizableToolbar(function (toolbar) {
   201     Array.forEach(toolbar.childNodes, function (item) {
   202 #ifdef XP_MACOSX
   203       if (item.firstChild && item.firstChild.localName == "menubar")
   204         return;
   205 #endif
   206       if (isToolbarItem(item)) {
   207         let wrapper = wrapToolbarItem(item);
   208         cleanupItemForToolbar(item, wrapper);
   209       }
   210     });
   211   });
   212 }
   214 function getRootElements()
   215 {
   216   return [gToolbox].concat(gToolbox.externalToolbars);
   217 }
   219 /**
   220  * Unwraps all items in all customizable toolbars in a toolbox.
   221  */
   222 function unwrapToolbarItems()
   223 {
   224   let elts = getRootElements();
   225   for (let i=0; i < elts.length; i++) {
   226     let paletteItems = elts[i].getElementsByTagName("toolbarpaletteitem");
   227     let paletteItem;
   228     while ((paletteItem = paletteItems.item(0)) != null) {
   229       let toolbarItem = paletteItem.firstChild;
   230       restoreItemForToolbar(toolbarItem, paletteItem);
   231       paletteItem.parentNode.replaceChild(toolbarItem, paletteItem);
   232     }
   233   }
   234 }
   236 /**
   237  * Creates a wrapper that can be used to contain a toolbaritem and prevent
   238  * it from receiving UI events.
   239  */
   240 function createWrapper(aId, aDocument)
   241 {
   242   var wrapper = aDocument.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
   243                                          "toolbarpaletteitem");
   245   wrapper.id = "wrapper-"+aId;
   246   return wrapper;
   247 }
   249 /**
   250  * Wraps an item that has been cloned from a template and adds
   251  * it to the end of the palette.
   252  */
   253 function wrapPaletteItem(aPaletteItem)
   254 {
   255   var wrapper = createWrapper(aPaletteItem.id, document);
   257   wrapper.appendChild(aPaletteItem);
   259   // XXX We need to call this AFTER the palette item has been appended
   260   // to the wrapper or else we crash dropping certain buttons on the
   261   // palette due to removal of the command and disabled attributes - JRH
   262   cleanUpItemForPalette(aPaletteItem, wrapper);
   264   gPaletteBox.appendChild(wrapper);
   265 }
   267 /**
   268  * Wraps an item that is currently on a toolbar and replaces the item
   269  * with the wrapper. This is not used when dropping items from the palette,
   270  * only when first starting the dialog and wrapping everything on the toolbars.
   271  */
   272 function wrapToolbarItem(aToolbarItem)
   273 {
   274   var wrapper = createWrapper(aToolbarItem.id, gToolboxDocument);
   276   wrapper.flex = aToolbarItem.flex;
   278   aToolbarItem.parentNode.replaceChild(wrapper, aToolbarItem);
   280   wrapper.appendChild(aToolbarItem);
   282   return wrapper;
   283 }
   285 /**
   286  * Get the list of ids for the current set of items on each toolbar.
   287  */
   288 function getCurrentItemIds()
   289 {
   290   var currentItems = {};
   291   forEachCustomizableToolbar(function (toolbar) {
   292     var child = toolbar.firstChild;
   293     while (child) {
   294       if (isToolbarItem(child))
   295         currentItems[child.id] = 1;
   296       child = child.nextSibling;
   297     }
   298   });
   299   return currentItems;
   300 }
   302 /**
   303  * Builds the palette of draggable items that are not yet in a toolbar.
   304  */
   305 function buildPalette()
   306 {
   307   // Empty the palette first.
   308   while (gPaletteBox.lastChild)
   309     gPaletteBox.removeChild(gPaletteBox.lastChild);
   311   // Add the toolbar separator item.
   312   var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
   313                                               "toolbarseparator");
   314   templateNode.id = "separator";
   315   wrapPaletteItem(templateNode);
   317   // Add the toolbar spring item.
   318   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
   319                                               "toolbarspring");
   320   templateNode.id = "spring";
   321   templateNode.flex = 1;
   322   wrapPaletteItem(templateNode);
   324   // Add the toolbar spacer item.
   325   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
   326                                               "toolbarspacer");
   327   templateNode.id = "spacer";
   328   templateNode.flex = 1;
   329   wrapPaletteItem(templateNode);
   331   var currentItems = getCurrentItemIds();
   332   templateNode = gToolbox.palette.firstChild;
   333   while (templateNode) {
   334     // Check if the item is already in a toolbar before adding it to the palette.
   335     if (!(templateNode.id in currentItems)) {
   336       var paletteItem = document.importNode(templateNode, true);
   337       wrapPaletteItem(paletteItem);
   338     }
   340     templateNode = templateNode.nextSibling;
   341   }
   342 }
   344 /**
   345  * Makes sure that an item that has been cloned from a template
   346  * is stripped of any attributes that may adversely affect its
   347  * appearance in the palette.
   348  */
   349 function cleanUpItemForPalette(aItem, aWrapper)
   350 {
   351   aWrapper.setAttribute("place", "palette");
   352   setWrapperType(aItem, aWrapper);
   354   if (aItem.hasAttribute("title"))
   355     aWrapper.setAttribute("title", aItem.getAttribute("title"));
   356   else if (aItem.hasAttribute("label"))
   357     aWrapper.setAttribute("title", aItem.getAttribute("label"));
   358   else if (isSpecialItem(aItem)) {
   359     var stringBundle = document.getElementById("stringBundle");
   360     // Remove the common "toolbar" prefix to generate the string name.
   361     var title = stringBundle.getString(aItem.localName.slice(7) + "Title");
   362     aWrapper.setAttribute("title", title);
   363   }
   364   aWrapper.setAttribute("tooltiptext", aWrapper.getAttribute("title"));
   366   // Remove attributes that screw up our appearance.
   367   aItem.removeAttribute("command");
   368   aItem.removeAttribute("observes");
   369   aItem.removeAttribute("type");
   370   aItem.removeAttribute("width");
   372   Array.forEach(aWrapper.querySelectorAll("[disabled]"), function(aNode) {
   373     aNode.removeAttribute("disabled");
   374   });
   375 }
   377 /**
   378  * Makes sure that an item that has been cloned from a template
   379  * is stripped of all properties that may adversely affect its
   380  * appearance in the toolbar.  Store critical properties on the
   381  * wrapper so they can be put back on the item when we're done.
   382  */
   383 function cleanupItemForToolbar(aItem, aWrapper)
   384 {
   385   setWrapperType(aItem, aWrapper);
   386   aWrapper.setAttribute("place", "toolbar");
   388   if (aItem.hasAttribute("command")) {
   389     aWrapper.setAttribute("itemcommand", aItem.getAttribute("command"));
   390     aItem.removeAttribute("command");
   391   }
   393   if (aItem.checked) {
   394     aWrapper.setAttribute("itemchecked", "true");
   395     aItem.checked = false;
   396   }
   398   if (aItem.disabled) {
   399     aWrapper.setAttribute("itemdisabled", "true");
   400     aItem.disabled = false;
   401   }
   402 }
   404 /**
   405  * Restore all the properties that we stripped off above.
   406  */
   407 function restoreItemForToolbar(aItem, aWrapper)
   408 {
   409   if (aWrapper.hasAttribute("itemdisabled"))
   410     aItem.disabled = true;
   412   if (aWrapper.hasAttribute("itemchecked"))
   413     aItem.checked = true;
   415   if (aWrapper.hasAttribute("itemcommand")) {
   416     let commandID = aWrapper.getAttribute("itemcommand");
   417     aItem.setAttribute("command", commandID);
   419     //XXX Bug 309953 - toolbarbuttons aren't in sync with their commands after customizing
   420     let command = gToolboxDocument.getElementById(commandID);
   421     if (command && command.hasAttribute("disabled"))
   422       aItem.setAttribute("disabled", command.getAttribute("disabled"));
   423   }
   424 }
   426 function setWrapperType(aItem, aWrapper)
   427 {
   428   if (aItem.localName == "toolbarseparator") {
   429     aWrapper.setAttribute("type", "separator");
   430   } else if (aItem.localName == "toolbarspring") {
   431     aWrapper.setAttribute("type", "spring");
   432   } else if (aItem.localName == "toolbarspacer") {
   433     aWrapper.setAttribute("type", "spacer");
   434   } else if (aItem.localName == "toolbaritem" && aItem.firstChild) {
   435     aWrapper.setAttribute("type", aItem.firstChild.localName);
   436   }
   437 }
   439 function setDragActive(aItem, aValue)
   440 {
   441   var node = aItem;
   442   var direction = window.getComputedStyle(aItem, null).direction;
   443   var value = direction == "ltr"? "left" : "right";
   444   if (aItem.localName == "toolbar") {
   445     node = aItem.lastChild;
   446     value = direction == "ltr"? "right" : "left";
   447   }
   449   if (!node)
   450     return;
   452   if (aValue) {
   453     if (!node.hasAttribute("dragover"))
   454       node.setAttribute("dragover", value);
   455   } else {
   456     node.removeAttribute("dragover");
   457   }
   458 }
   460 function addNewToolbar()
   461 {
   462   var promptService = Services.prompt;
   463   var stringBundle = document.getElementById("stringBundle");
   464   var message = stringBundle.getString("enterToolbarName");
   465   var title = stringBundle.getString("enterToolbarTitle");
   467   var name = {};
   469   // Quitting from the toolbar dialog while the new toolbar prompt is up
   470   // can cause things to become unresponsive on the Mac. Until dialog modality
   471   // is fixed (395465), disable the "Done" button explicitly.
   472   var doneButton = document.getElementById("donebutton");
   473   doneButton.disabled = true;
   475   while (true) {
   477     if (!promptService.prompt(window, title, message, name, null, {})) {
   478       doneButton.disabled = false;
   479       return;
   480     }
   482     if (!name.value) {
   483       message = stringBundle.getFormattedString("enterToolbarBlank", [name.value]);
   484       continue;
   485     }
   487     var dupeFound = false;
   489      // Check for an existing toolbar with the same display name
   490     for (let i = 0; i < gToolbox.childNodes.length; ++i) {
   491       var toolbar = gToolbox.childNodes[i];
   492       var toolbarName = toolbar.getAttribute("toolbarname");
   494       if (toolbarName == name.value &&
   495           toolbar.getAttribute("type") != "menubar" &&
   496           toolbar.nodeName == 'toolbar') {
   497         dupeFound = true;
   498         break;
   499       }
   500     }
   502     if (!dupeFound)
   503       break;
   505     message = stringBundle.getFormattedString("enterToolbarDup", [name.value]);
   506   }
   508   gToolbox.appendCustomToolbar(name.value, "");
   510   toolboxChanged();
   512   doneButton.disabled = false;
   513 }
   515 /**
   516  * Restore the default set of buttons to fixed toolbars,
   517  * remove all custom toolbars, and rebuild the palette.
   518  */
   519 function restoreDefaultSet()
   520 {
   521   // Unwrap the items on the toolbar.
   522   unwrapToolbarItems();
   524   // Remove all of the customized toolbars.
   525   var child = gToolbox.lastChild;
   526   while (child) {
   527     if (child.hasAttribute("customindex")) {
   528       var thisChild = child;
   529       child = child.previousSibling;
   530       thisChild.currentSet = "__empty";
   531       gToolbox.removeChild(thisChild);
   532     } else {
   533       child = child.previousSibling;
   534     }
   535   }
   537   // Restore the defaultset for fixed toolbars.
   538   forEachCustomizableToolbar(function (toolbar) {
   539     var defaultSet = toolbar.getAttribute("defaultset");
   540     if (defaultSet)
   541       toolbar.currentSet = defaultSet;
   542   });
   544   // Restore the default icon size and mode.
   545   document.getElementById("smallicons").checked = (updateIconSize() == "small");
   546   document.getElementById("modelist").value = updateToolbarMode();
   548   // Now rebuild the palette.
   549   buildPalette();
   551   // Now re-wrap the items on the toolbar.
   552   wrapToolbarItems();
   554   toolboxChanged("reset");
   555 }
   557 function updateIconSize(aSize) {
   558   return updateToolboxProperty("iconsize", aSize, "large");
   559 }
   561 function updateToolbarMode(aModeValue) {
   562   var mode = updateToolboxProperty("mode", aModeValue, "icons");
   564   var iconSizeCheckbox = document.getElementById("smallicons");
   565   iconSizeCheckbox.disabled = mode == "text";
   567   return mode;
   568 }
   570 function updateToolboxProperty(aProp, aValue, aToolkitDefault) {
   571   var toolboxDefault = gToolbox.getAttribute("default" + aProp) ||
   572                        aToolkitDefault;
   574   gToolbox.setAttribute(aProp, aValue || toolboxDefault);
   575   gToolboxDocument.persist(gToolbox.id, aProp);
   577   forEachCustomizableToolbar(function (toolbar) {
   578     var toolbarDefault = toolbar.getAttribute("default" + aProp) ||
   579                          toolboxDefault;
   580     if (toolbar.getAttribute("lock" + aProp) == "true" &&
   581         toolbar.getAttribute(aProp) == toolbarDefault)
   582       return;
   584     toolbar.setAttribute(aProp, aValue || toolbarDefault);
   585     gToolboxDocument.persist(toolbar.id, aProp);
   586   });
   588   toolboxChanged(aProp);
   590   return aValue || toolboxDefault;
   591 }
   593 function forEachCustomizableToolbar(callback) {
   594   Array.filter(gToolbox.childNodes, isCustomizableToolbar).forEach(callback);
   595   Array.filter(gToolbox.externalToolbars, isCustomizableToolbar).forEach(callback);
   596 }
   598 function isCustomizableToolbar(aElt)
   599 {
   600   return aElt.localName == "toolbar" &&
   601          aElt.getAttribute("customizable") == "true";
   602 }
   604 function isSpecialItem(aElt)
   605 {
   606   return aElt.localName == "toolbarseparator" ||
   607          aElt.localName == "toolbarspring" ||
   608          aElt.localName == "toolbarspacer";
   609 }
   611 function isToolbarItem(aElt)
   612 {
   613   return aElt.localName == "toolbarbutton" ||
   614          aElt.localName == "toolbaritem" ||
   615          aElt.localName == "toolbarseparator" ||
   616          aElt.localName == "toolbarspring" ||
   617          aElt.localName == "toolbarspacer";
   618 }
   620 ///////////////////////////////////////////////////////////////////////////
   621 //// Drag and Drop observers
   623 function onToolbarDragExit(aEvent)
   624 {
   625   if (isUnwantedDragEvent(aEvent)) {
   626     return;
   627   }
   629   if (gCurrentDragOverItem)
   630     setDragActive(gCurrentDragOverItem, false);
   631 }
   633 function onToolbarDragStart(aEvent)
   634 {
   635   var item = aEvent.target;
   636   while (item && item.localName != "toolbarpaletteitem") {
   637     if (item.localName == "toolbar")
   638       return;
   639     item = item.parentNode;
   640   }
   642   item.setAttribute("dragactive", "true");
   644   var dt = aEvent.dataTransfer;
   645   var documentId = gToolboxDocument.documentElement.id;
   646   dt.setData("text/toolbarwrapper-id/" + documentId, item.firstChild.id);
   647   dt.effectAllowed = "move";
   648 }
   650 function onToolbarDragOver(aEvent)
   651 {
   652   if (isUnwantedDragEvent(aEvent)) {
   653     return;
   654   }
   656   var documentId = gToolboxDocument.documentElement.id;
   657   if (!aEvent.dataTransfer.types.contains("text/toolbarwrapper-id/" + documentId.toLowerCase()))
   658     return;
   660   var toolbar = aEvent.target;
   661   var dropTarget = aEvent.target;
   662   while (toolbar && toolbar.localName != "toolbar") {
   663     dropTarget = toolbar;
   664     toolbar = toolbar.parentNode;
   665   }
   667   // Make sure we are dragging over a customizable toolbar.
   668   if (!toolbar || !isCustomizableToolbar(toolbar)) {
   669     gCurrentDragOverItem = null;
   670     return;
   671   }
   673   var previousDragItem = gCurrentDragOverItem;
   675   if (dropTarget.localName == "toolbar") {
   676     gCurrentDragOverItem = dropTarget;
   677   } else {
   678     gCurrentDragOverItem = null;
   680     var direction = window.getComputedStyle(dropTarget.parentNode, null).direction;
   681     var dropTargetCenter = dropTarget.boxObject.x + (dropTarget.boxObject.width / 2);
   682     var dragAfter;
   683     if (direction == "ltr")
   684       dragAfter = aEvent.clientX > dropTargetCenter;
   685     else
   686       dragAfter = aEvent.clientX < dropTargetCenter;
   688     if (dragAfter) {
   689       gCurrentDragOverItem = dropTarget.nextSibling;
   690       if (!gCurrentDragOverItem)
   691         gCurrentDragOverItem = toolbar;
   692     } else
   693       gCurrentDragOverItem = dropTarget;
   694   }
   696   if (previousDragItem && gCurrentDragOverItem != previousDragItem) {
   697     setDragActive(previousDragItem, false);
   698   }
   700   setDragActive(gCurrentDragOverItem, true);
   702   aEvent.preventDefault();
   703   aEvent.stopPropagation();
   704 }
   706 function onToolbarDrop(aEvent)
   707 {
   708   if (isUnwantedDragEvent(aEvent)) {
   709     return;
   710   }
   712   if (!gCurrentDragOverItem)
   713     return;
   715   setDragActive(gCurrentDragOverItem, false);
   717   var documentId = gToolboxDocument.documentElement.id;
   718   var draggedItemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
   719   if (gCurrentDragOverItem.id == draggedItemId)
   720     return;
   722   var toolbar = aEvent.target;
   723   while (toolbar.localName != "toolbar")
   724     toolbar = toolbar.parentNode;
   726   var draggedPaletteWrapper = document.getElementById("wrapper-"+draggedItemId);
   727   if (!draggedPaletteWrapper) {
   728     // The wrapper has been dragged from the toolbar.
   729     // Get the wrapper from the toolbar document and make sure that
   730     // it isn't being dropped on itself.
   731     var wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId);
   732     if (wrapper == gCurrentDragOverItem)
   733        return;
   735     // Don't allow non-removable kids (e.g., the menubar) to move.
   736     if (wrapper.firstChild.getAttribute("removable") != "true")
   737       return;
   739     // Remove the item from its place in the toolbar.
   740     wrapper.parentNode.removeChild(wrapper);
   742     // Determine which toolbar we are dropping on.
   743     var dropToolbar = null;
   744     if (gCurrentDragOverItem.localName == "toolbar")
   745       dropToolbar = gCurrentDragOverItem;
   746     else
   747       dropToolbar = gCurrentDragOverItem.parentNode;
   749     // Insert the item into the toolbar.
   750     if (gCurrentDragOverItem != dropToolbar)
   751       dropToolbar.insertBefore(wrapper, gCurrentDragOverItem);
   752     else
   753       dropToolbar.appendChild(wrapper);
   754   } else {
   755     // The item has been dragged from the palette
   757     // Create a new wrapper for the item. We don't know the id yet.
   758     var wrapper = createWrapper("", gToolboxDocument);
   760     // Ask the toolbar to clone the item's template, place it inside the wrapper, and insert it in the toolbar.
   761     var newItem = toolbar.insertItem(draggedItemId, gCurrentDragOverItem == toolbar ? null : gCurrentDragOverItem, wrapper);
   763     // Prepare the item and wrapper to look good on the toolbar.
   764     cleanupItemForToolbar(newItem, wrapper);
   765     wrapper.id = "wrapper-"+newItem.id;
   766     wrapper.flex = newItem.flex;
   768     // Remove the wrapper from the palette.
   769     if (draggedItemId != "separator" &&
   770         draggedItemId != "spring" &&
   771         draggedItemId != "spacer")
   772       gPaletteBox.removeChild(draggedPaletteWrapper);
   773   }
   775   gCurrentDragOverItem = null;
   777   toolboxChanged();
   778 };
   780 function onPaletteDragOver(aEvent)
   781 {
   782   if (isUnwantedDragEvent(aEvent)) {
   783     return;
   784   }
   785   var documentId = gToolboxDocument.documentElement.id;
   786   if (aEvent.dataTransfer.types.contains("text/toolbarwrapper-id/" + documentId.toLowerCase()))
   787     aEvent.preventDefault();
   788 }
   790 function onPaletteDrop(aEvent)
   791 {
   792   if (isUnwantedDragEvent(aEvent)) {
   793     return;
   794   }
   795   var documentId = gToolboxDocument.documentElement.id;
   796   var itemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
   798   var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId);
   799   if (wrapper) {
   800     // Don't allow non-removable kids (e.g., the menubar) to move.
   801     if (wrapper.firstChild.getAttribute("removable") != "true")
   802       return;
   804     var wrapperType = wrapper.getAttribute("type");
   805     if (wrapperType != "separator" &&
   806         wrapperType != "spacer" &&
   807         wrapperType != "spring") {
   808       restoreItemForToolbar(wrapper.firstChild, wrapper);
   809       wrapPaletteItem(document.importNode(wrapper.firstChild, true));
   810       gToolbox.palette.appendChild(wrapper.firstChild);
   811     }
   813     // The item was dragged out of the toolbar.
   814     wrapper.parentNode.removeChild(wrapper);
   815   }
   817   toolboxChanged();
   818 }
   821 function isUnwantedDragEvent(aEvent) {
   822   try {
   823     if (Services.prefs.getBoolPref("toolkit.customization.unsafe_drag_events")) {
   824       return false;
   825     }
   826   } catch (ex) {}
   828   /* Discard drag events that originated from a separate window to
   829      prevent content->chrome privilege escalations. */
   830   let mozSourceNode = aEvent.dataTransfer.mozSourceNode;
   831   // mozSourceNode is null in the dragStart event handler or if
   832   // the drag event originated in an external application.
   833   if (!mozSourceNode) {
   834     return true;
   835   }
   836   let sourceWindow = mozSourceNode.ownerDocument.defaultView;
   837   return sourceWindow != window && sourceWindow != gToolboxDocument.defaultView;
   838 }

mercurial