home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 March / PCWorld_2007-03_cd.bin / komunikace / nvu / nvu-1.0-cs-CZ.win32.installer.exe / chrome / toolkit.jar / content / global / customizeToolbar.js < prev    next >
Text File  |  2004-12-21  |  28KB  |  949 lines

  1.  
  2. const kRowMax = 4;
  3. const kWindowWidth = 600;
  4. const kWindowHeight = 400;
  5. const kAnimateIncrement = 50;
  6. const kAnimateSteps = kWindowHeight / kAnimateIncrement - 1;
  7.  
  8. var gToolboxDocument = null;
  9. var gToolbox = null;
  10. var gCurrentDragOverItem = null;
  11. var gToolboxChanged = false;
  12.  
  13. function onLoad()
  14. {
  15.   gToolbox = window.arguments[0];
  16.   gToolboxDocument = gToolbox.ownerDocument;
  17.   
  18.   gToolbox.addEventListener("draggesture", onToolbarDragGesture, false);
  19.   gToolbox.addEventListener("dragover", onToolbarDragOver, false);
  20.   gToolbox.addEventListener("dragexit", onToolbarDragExit, false);
  21.   gToolbox.addEventListener("dragdrop", onToolbarDragDrop, false);
  22.  
  23.   document.documentElement.setAttribute("hidechrome", "true");
  24.  
  25.   repositionDialog();
  26.   window.outerWidth = kWindowWidth;
  27.   window.outerHeight = 50;
  28.   slideOpen(0);
  29. }
  30.  
  31. function onUnload(aEvent)
  32. {
  33.   removeToolboxListeners();
  34.   unwrapToolbarItems();
  35.   persistCurrentSets();
  36.   
  37.   notifyParentComplete();
  38. }
  39.  
  40. function onAccept(aEvent)
  41. {
  42.   document.getElementById("main-box").collapsed = true;
  43.   slideClosed(0);
  44. }
  45.  
  46. function initDialog()
  47. {
  48.   document.getElementById("main-box").collapsed = false;
  49.   
  50.   var mode = gToolbox.getAttribute("mode");
  51.   document.getElementById("modelist").value = mode;
  52.   var iconSize = gToolbox.getAttribute("iconsize");
  53.   var smallIconsCheckbox = document.getElementById("smallicons");
  54.  
  55.   if (gToolbox.getAttribute("canchangemode") == "false")
  56.   {
  57.     document.getElementById("modelist").hidden = true;
  58.     document.getElementById("modelabel").hidden = true;
  59.   }
  60.  
  61.   if (!gToolbox.toolbarset)
  62.   {
  63.     document.getElementById("newtoolbars").hidden = true;
  64.   }
  65.  
  66.   if (smallIconsCheckbox)
  67.   {
  68.     if ( mode == "text")
  69.       smallIconsCheckbox.disabled = true;
  70.     else
  71.       smallIconsCheckbox.checked = iconSize == "small"; 
  72.   }
  73.  
  74.   // Build up the palette of other items.
  75.   buildPalette();
  76.  
  77.   // Wrap all the items on the toolbar in toolbarpaletteitems.
  78.   wrapToolbarItems();
  79. }
  80.  
  81. function slideOpen(aStep)
  82. {
  83.   if (aStep < kAnimateSteps) {
  84.     window.outerHeight += kAnimateIncrement;
  85.     setTimeout(slideOpen, 20, ++aStep);
  86.   } else {
  87.     initDialog();
  88.   }
  89. }
  90.  
  91. function slideClosed(aStep)
  92. {
  93.   if (aStep < kAnimateSteps) {
  94.     window.outerHeight -= kAnimateIncrement;
  95.     setTimeout(slideClosed, 10, ++aStep);
  96.   } else {
  97.     window.close();
  98.   }
  99. }
  100.  
  101. function repositionDialog()
  102. {
  103.   // Position the dialog touching the bottom of the toolbox and centered with it
  104.   var screenX = gToolbox.boxObject.screenX + ((gToolbox.boxObject.width - kWindowWidth) / 2);
  105.   var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height;
  106.   window.moveTo(screenX, screenY);
  107. }
  108.  
  109. function removeToolboxListeners()
  110. {
  111.   gToolbox.removeEventListener("draggesture", onToolbarDragGesture, false);
  112.   gToolbox.removeEventListener("dragover", onToolbarDragOver, false);
  113.   gToolbox.removeEventListener("dragexit", onToolbarDragExit, false);
  114.   gToolbox.removeEventListener("dragdrop", onToolbarDragDrop, false);
  115. }
  116.  
  117. /**
  118.  * Invoke a callback on the toolbox to notify it that the dialog is done
  119.  * and going away.
  120.  */
  121. function notifyParentComplete()
  122. {
  123.   if ("customizeDone" in gToolbox)
  124.     gToolbox.customizeDone(gToolboxChanged);
  125. }
  126.  
  127. function getToolbarAt(i)
  128. {
  129.   return gToolbox.childNodes[i];
  130. }
  131.  
  132. /**
  133.  * Persist the current set of buttons in all customizable toolbars to
  134.  * localstore.
  135.  */
  136. function persistCurrentSets()
  137. {
  138.   if (!gToolboxChanged)
  139.     return;
  140.  
  141.   var customCount = 0;
  142.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  143.     // Look for customizable toolbars that need to be persisted.
  144.     var toolbar = getToolbarAt(i);
  145.     if (isCustomizableToolbar(toolbar)) {
  146.       // Calculate currentset and store it in the attribute.
  147.       var currentSet = toolbar.currentSet;
  148.       toolbar.setAttribute("currentset", currentSet);
  149.       
  150.       var customIndex = toolbar.hasAttribute("customindex");
  151.       if (customIndex) {
  152.         if (!toolbar.firstChild) {
  153.           // Remove custom toolbars whose contents have been removed.
  154.           gToolbox.removeChild(toolbar);
  155.           --i;
  156.         } else {
  157.           // Persist custom toolbar info on the <toolbarset/>
  158.           gToolbox.toolbarset.setAttribute("toolbar"+(++customCount),
  159.                                            toolbar.toolbarName + ":" + currentSet);
  160.           gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
  161.         }
  162.       }
  163.  
  164.       if (!customIndex) {
  165.         // Persist the currentset attribute directly on hardcoded toolbars.
  166.         gToolboxDocument.persist(toolbar.id, "currentset");
  167.       }
  168.     }
  169.   }
  170.   
  171.   // Remove toolbarX attributes for removed toolbars.
  172.   while (gToolbox.toolbarset.hasAttribute("toolbar"+(++customCount))) {
  173.     gToolbox.toolbarset.removeAttribute("toolbar"+customCount);
  174.     gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
  175.   }
  176. }
  177.  
  178. /**
  179.  * Wraps all items in all customizable toolbars in a toolbox.
  180.  */
  181. function wrapToolbarItems()
  182. {
  183.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  184.     var toolbar = getToolbarAt(i);
  185.     if (isCustomizableToolbar(toolbar)) {
  186.       for (var k = 0; k < toolbar.childNodes.length; ++k) {
  187.         var item = toolbar.childNodes[k];
  188.         if (isToolbarItem(item)) {
  189.           var nextSibling = item.nextSibling;
  190.           
  191.           var wrapper = wrapToolbarItem(item);     
  192.           if (nextSibling)
  193.             toolbar.insertBefore(wrapper, nextSibling);
  194.           else
  195.             toolbar.appendChild(wrapper);
  196.         }
  197.       }
  198.     }
  199.   }
  200. }
  201.  
  202. /**
  203.  * Unwraps all items in all customizable toolbars in a toolbox.
  204.  */
  205.  function unwrapToolbarItems()
  206. {
  207.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  208.     var toolbar = getToolbarAt(i);
  209.     if (isCustomizableToolbar(toolbar)) {
  210.       for (var k = 0; k < toolbar.childNodes.length; ++k) {
  211.         var paletteItem = toolbar.childNodes[k];
  212.         var toolbarItem = paletteItem.firstChild;
  213.  
  214.         if (isToolbarItem(toolbarItem)) {
  215.           var nextSibling = paletteItem.nextSibling;
  216.  
  217.           if (paletteItem.hasAttribute("itemcommand"))
  218.             toolbarItem.setAttribute("command", paletteItem.getAttribute("itemcommand"));
  219.           if (paletteItem.hasAttribute("itemobserves"))
  220.             toolbarItem.setAttribute("observes", paletteItem.getAttribute("itemobserves"));
  221.  
  222.           paletteItem.removeChild(toolbarItem); 
  223.           paletteItem.parentNode.removeChild(paletteItem);
  224.  
  225.           if (nextSibling)
  226.             toolbar.insertBefore(toolbarItem, nextSibling);
  227.           else
  228.             toolbar.appendChild(toolbarItem);
  229.         }
  230.       }
  231.     }
  232.   }
  233. }
  234.  
  235.  
  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)
  241. {
  242.   var wrapper = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  243.                                          "toolbarpaletteitem");
  244.  
  245.   wrapper.id = "wrapper-"+aId;  
  246.   return wrapper;
  247. }
  248.  
  249. /**
  250.  * Wraps an item that has been cloned from a template and adds
  251.  * it to the end of a row in the palette.
  252.  */
  253. function wrapPaletteItem(aPaletteItem, aCurrentRow, aSpacer)
  254. {
  255.   if (!aPaletteItem.getAttribute("label"))
  256.   {
  257.     aPaletteItem.setAttribute("label",
  258.       aPaletteItem.getAttribute("tooltiptext"));
  259.     aPaletteItem.setAttribute("class", "toolbarbutton-1");
  260.   }
  261.  
  262.   var wrapper = createWrapper(aPaletteItem.id);
  263.  
  264.   wrapper.setAttribute("flex", 1);
  265.   wrapper.setAttribute("align", "center");
  266.   wrapper.setAttribute("pack", "center");
  267.   wrapper.setAttribute("minheight", "0");
  268.   wrapper.setAttribute("minwidth", "0");
  269.  
  270.   wrapper.appendChild(aPaletteItem);
  271.   
  272.   // XXX We need to call this AFTER the palette item has been appended
  273.   // to the wrapper or else we crash dropping certain buttons on the 
  274.   // palette due to removal of the command and disabled attributes - JRH
  275.   cleanUpItemForPalette(aPaletteItem, wrapper);
  276.  
  277.   if (aSpacer)
  278.     aCurrentRow.insertBefore(wrapper, aSpacer);
  279.   else
  280.     aCurrentRow.appendChild(wrapper);
  281.  
  282. }
  283.  
  284. /**
  285.  * Wraps an item that is currently on a toolbar and replaces the item
  286.  * with the wrapper. This is not used when dropping items from the palette,
  287.  * only when first starting the dialog and wrapping everything on the toolbars.
  288.  */
  289. function wrapToolbarItem(aToolbarItem)
  290. {
  291.   var wrapper = createWrapper(aToolbarItem.id);
  292.   
  293.   cleanupItemForToolbar(aToolbarItem, wrapper);
  294.   wrapper.flex = aToolbarItem.flex;
  295.  
  296.   if (aToolbarItem.parentNode)
  297.     aToolbarItem.parentNode.removeChild(aToolbarItem);
  298.   
  299.   wrapper.appendChild(aToolbarItem);
  300.   
  301.   return wrapper;
  302. }
  303.  
  304. /**
  305.  * Get the list of ids for the current set of items on each toolbar.
  306.  */
  307. function getCurrentItemIds()
  308. {
  309.   var currentItems = {};
  310.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  311.     var toolbar = getToolbarAt(i);
  312.     if (isCustomizableToolbar(toolbar)) {
  313.       var child = toolbar.firstChild;
  314.       while (child) {
  315.         if (isToolbarItem(child))
  316.           currentItems[child.id] = 1;
  317.         child = child.nextSibling;
  318.       }
  319.     }
  320.   }
  321.   return currentItems;
  322. }
  323.  
  324. /**
  325.  * Builds the palette of draggable items that are not yet in a toolbar.
  326.  */
  327. function buildPalette()
  328. {
  329.   // Empty the palette first.
  330.   var paletteBox = document.getElementById("palette-box");
  331.   while (paletteBox.lastChild)
  332.     paletteBox.removeChild(paletteBox.lastChild);
  333.  
  334.   var currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  335.                                             "hbox");
  336.   currentRow.setAttribute("class", "paletteRow");
  337.  
  338.   // Add the toolbar separator item.
  339.   var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  340.                                               "toolbarseparator");
  341.   templateNode.id = "separator";
  342.   wrapPaletteItem(templateNode, currentRow, null);
  343.  
  344.   // Add the toolbar spring item.
  345.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  346.                                               "toolbarspring");
  347.   templateNode.id = "spring";
  348.   templateNode.flex = 1;
  349.   wrapPaletteItem(templateNode, currentRow, null);
  350.  
  351.   // Add the toolbar spacer item.
  352.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  353.                                               "toolbarspacer");
  354.   templateNode.id = "spacer";
  355.   templateNode.flex = 1;
  356.   wrapPaletteItem(templateNode, currentRow, null);
  357.  
  358.   var rowSlot = 3;
  359.  
  360.   var currentItems = getCurrentItemIds();
  361.   templateNode = gToolbox.palette.firstChild;
  362.   while (templateNode) {
  363.     // Check if the item is already in a toolbar before adding it to the palette.
  364.     if (!(templateNode.id in currentItems)) {
  365.       var paletteItem = templateNode.cloneNode(true);
  366.  
  367.       if (rowSlot == kRowMax) {
  368.         // Append the old row.
  369.         paletteBox.appendChild(currentRow);
  370.  
  371.         // Make a new row.
  372.         currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  373.                                               "hbox");
  374.         currentRow.setAttribute("class", "paletteRow");
  375.         rowSlot = 0;
  376.       }
  377.  
  378.       ++rowSlot;
  379.       wrapPaletteItem(paletteItem, currentRow, null);
  380.     }
  381.     
  382.     templateNode = templateNode.nextSibling;
  383.   }
  384.  
  385.   if (currentRow) { 
  386.     fillRowWithFlex(currentRow);
  387.     paletteBox.appendChild(currentRow);
  388.   }
  389. }
  390.  
  391. /**
  392.  * Creates a new palette item for a cloned template node and
  393.  * adds it to the last slot in the palette.
  394.  */
  395. function appendPaletteItem(aItem)
  396. {
  397.   var paletteBox = document.getElementById("palette-box");
  398.   var lastRow = paletteBox.lastChild;
  399.   var lastSpacer = lastRow.lastChild;
  400.    
  401.   if (lastSpacer.localName != "spacer") {
  402.     // The current row is full, so we have to create a new row.
  403.     lastRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  404.                                         "hbox");
  405.     lastRow.setAttribute("class", "paletteRow");
  406.     paletteBox.appendChild(lastRow);
  407.     
  408.     wrapPaletteItem(aItem, lastRow, null);
  409.  
  410.     fillRowWithFlex(lastRow);
  411.   } else {
  412.     // Decrement the flex of the last spacer or remove it entirely.
  413.     var flex = lastSpacer.getAttribute("flex");
  414.     if (flex == 1) {
  415.       lastRow.removeChild(lastSpacer);
  416.       lastSpacer = null;
  417.     } else
  418.       lastSpacer.setAttribute("flex", --flex);
  419.  
  420.     // Insert the wrapper where the last spacer was.
  421.     wrapPaletteItem(aItem, lastRow, lastSpacer);
  422.   }
  423. }
  424.  
  425. function fillRowWithFlex(aRow)
  426. {
  427.   var remainingFlex = kRowMax - aRow.childNodes.length;
  428.   if (remainingFlex > 0) {
  429.     var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  430.                                           "spacer");
  431.     spacer.setAttribute("flex", remainingFlex);
  432.     aRow.appendChild(spacer);
  433.   }
  434. }
  435.  
  436. /**
  437.  * Makes sure that an item that has been cloned from a template
  438.  * is stripped of all properties that may adversely affect it's
  439.  * appearance in the palette.
  440.  */
  441. function cleanUpItemForPalette(aItem, aWrapper)
  442. {
  443.   aWrapper.setAttribute("place", "palette");
  444.   setWrapperType(aItem, aWrapper);
  445.  
  446.   if (aItem.hasAttribute("title"))
  447.     aWrapper.setAttribute("title", aItem.getAttribute("title"));
  448.   else if (isSpecialItem(aItem)) {
  449.     var stringBundle = document.getElementById("stringBundle");
  450.     var title = stringBundle.getString(aItem.id + "Title");
  451.     aWrapper.setAttribute("title", title);
  452.   }
  453.   
  454.   // Remove attributes that screw up our appearance.
  455.   aItem.removeAttribute("command");
  456.   aItem.removeAttribute("observes");
  457.   aItem.removeAttribute("disabled");
  458.   aItem.removeAttribute("type");
  459.   
  460.   if (aItem.localName == "toolbaritem" && aItem.firstChild) {
  461.     aItem.firstChild.removeAttribute("observes");
  462.  
  463.     // So the throbber doesn't throb in the dialog,
  464.     // cute as that may be...
  465.     aItem.firstChild.removeAttribute("busy");
  466.   }
  467. }
  468.  
  469. /**
  470.  * Makes sure that an item that has been cloned from a template
  471.  * is stripped of all properties that may adversely affect it's
  472.  * appearance in the toolbar.  Store critical properties on the 
  473.  * wrapper so they can be put back on the item when we're done.
  474.  */
  475. function cleanupItemForToolbar(aItem, aWrapper)
  476. {
  477.   setWrapperType(aItem, aWrapper);
  478.   aWrapper.setAttribute("place", "toolbar");
  479.  
  480.   if (aItem.hasAttribute("command")) {
  481.     aWrapper.setAttribute("itemcommand", aItem.getAttribute("command"));
  482.     aItem.removeAttribute("command");
  483.   }
  484.  
  485.   if (aItem.hasAttribute("observes"))
  486.   {
  487.     aWrapper.setAttribute("itemobserves", aItem.getAttribute("observes"));
  488.     aItem.removeAttribute("observes");
  489.   }
  490.  
  491.   if (aItem.disabled) {
  492.     aWrapper.setAttribute("itemdisabled", "true");
  493.     aItem.disabled = false;
  494.   }
  495. }
  496.  
  497. function setWrapperType(aItem, aWrapper)
  498. {
  499.   if (aItem.localName == "toolbarseparator") {
  500.     aWrapper.setAttribute("type", "separator");
  501.   } else if (aItem.localName == "toolbarspring") {
  502.     aWrapper.setAttribute("type", "spring");
  503.   } else if (aItem.localName == "toolbarspacer") {
  504.     aWrapper.setAttribute("type", "spacer");
  505.   } else if (aItem.localName == "toolbaritem" && aItem.firstChild) {
  506.     aWrapper.setAttribute("type", aItem.firstChild.localName);
  507.   }
  508. }
  509.  
  510. function setDragActive(aItem, aValue)
  511. {
  512.   var node = aItem;
  513.   var value = "left";
  514.   if (aItem.localName == "toolbar") {
  515.     node = aItem.lastChild;
  516.     value = "right";
  517.   }
  518.   
  519.   if (!node)
  520.     return;
  521.   
  522.   if (aValue) {
  523.     if (!node.hasAttribute("dragover"))
  524.       node.setAttribute("dragover", value);
  525.   } else {
  526.     node.removeAttribute("dragover");
  527.   }
  528. }
  529.  
  530.  
  531. /**
  532.  * Restore the default set of buttons to fixed toolbars,
  533.  * remove all custom toolbars, and rebuild the palette.
  534.  */
  535. function restoreDefaultSet()
  536. {
  537.   // Restore the defaultset for fixed toolbars.
  538.   var toolbar = gToolbox.firstChild;
  539.   while (toolbar) {
  540.     if (isCustomizableToolbar(toolbar)) {
  541.       if (!toolbar.hasAttribute("customindex")) {
  542.         var defaultSet = toolbar.getAttribute("defaultset");
  543.         if (defaultSet)
  544.         {
  545.           toolbar.currentSet = defaultSet;
  546.         }
  547.       }
  548.     }
  549.     toolbar = toolbar.nextSibling;
  550.   }
  551.  
  552.   // Remove all of the customized toolbars.
  553.   var child = gToolbox.lastChild;
  554.   while (child) {
  555.     if (child.hasAttribute("customindex")) {
  556.       var thisChild = child;
  557.       child = child.previousSibling;
  558.       gToolbox.removeChild(thisChild);
  559.     } else {
  560.       child = child.previousSibling;
  561.     }
  562.   }
  563.   
  564.   // Now rebuild the palette.
  565.   buildPalette();
  566.  
  567.   // Now re-wrap the items on the toolbar.
  568.   wrapToolbarItems();
  569.  
  570.   repositionDialog();
  571.   gToolboxChanged = true;
  572. }
  573.  
  574. function updateIconSize(aUseSmallIcons)
  575. {
  576.   var val = aUseSmallIcons ? "small" : null;
  577.   
  578.   setAttribute(gToolbox, "iconsize", val);
  579.   gToolboxDocument.persist(gToolbox.id, "iconsize");
  580.   
  581.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  582.     var toolbar = getToolbarAt(i);
  583.     if (isCustomizableToolbar(toolbar)) {
  584.       setAttribute(toolbar, "iconsize", val);
  585.       gToolboxDocument.persist(toolbar.id, "iconsize");
  586.     }
  587.   }
  588.  
  589.   repositionDialog();
  590. }
  591.  
  592. function updateToolbarMode(aModeValue)
  593. {
  594.   setAttribute(gToolbox, "mode", aModeValue);
  595.   gToolboxDocument.persist(gToolbox.id, "mode");
  596.  
  597.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  598.     var toolbar = getToolbarAt(i);
  599.     if (isCustomizableToolbar(toolbar)) {
  600.       setAttribute(toolbar, "mode", aModeValue);
  601.       gToolboxDocument.persist(toolbar.id, "mode");
  602.     }
  603.   }
  604.  
  605.   var iconSizeCheckbox = document.getElementById("smallicons");
  606.   if (iconSizeCheckbox)
  607.   {
  608.     if (aModeValue == "text") {
  609.       iconSizeCheckbox.disabled = true;
  610.       iconSizeCheckbox.checked = false;
  611.       updateIconSize(false);
  612.     }
  613.     else {
  614.       iconSizeCheckbox.disabled = false;
  615.     }
  616.   }
  617.  
  618.   repositionDialog();
  619. }
  620.  
  621.  
  622. function setAttribute(aElt, aAttr, aVal)
  623. {
  624.  if (aVal)
  625.     aElt.setAttribute(aAttr, aVal);
  626.   else
  627.     aElt.removeAttribute(aAttr);
  628. }
  629.  
  630. function isCustomizableToolbar(aElt)
  631. {
  632.   return aElt.localName == "toolbar" &&
  633.          aElt.getAttribute("customizable") == "true";
  634. }
  635.  
  636. function isSpecialItem(aElt)
  637. {
  638.   return aElt.localName == "toolbarseparator" ||
  639.          aElt.localName == "toolbarspring" ||
  640.          aElt.localName == "toolbarspacer";
  641. }
  642.  
  643. function isToolbarItem(aElt)
  644. {
  645.   return aElt.localName == "toolbarbutton" ||
  646.          aElt.localName == "toolbaritem" ||
  647.          aElt.localName == "toolbarseparator" ||
  648.          aElt.localName == "toolbarspring" ||
  649.          aElt.localName == "toolbarspacer";
  650. }
  651.  
  652. ///////////////////////////////////////////////////////////////////////////
  653. //// Drag and Drop observers
  654.  
  655. function onToolbarDragGesture(aEvent)
  656. {
  657.   nsDragAndDrop.startDrag(aEvent, dragStartObserver);
  658. }
  659.  
  660. function onToolbarDragOver(aEvent)
  661. {
  662.   nsDragAndDrop.dragOver(aEvent, toolbarDNDObserver);
  663. }
  664.  
  665. function onToolbarDragDrop(aEvent)
  666. {
  667.   nsDragAndDrop.drop(aEvent, toolbarDNDObserver);
  668. }
  669.  
  670. function onToolbarDragExit(aEvent)
  671. {
  672.   if (gCurrentDragOverItem)
  673.     setDragActive(gCurrentDragOverItem, false);
  674. }
  675.  
  676. var dragStartObserver =
  677. {
  678.   onDragStart: function (aEvent, aXferData, aDragAction) {
  679.     var documentId = gToolboxDocument.documentElement.id;
  680.     
  681.     var item = aEvent.target;
  682.     while (item && item.localName != "toolbarpaletteitem")
  683.       item = item.parentNode;
  684.     
  685.     item.setAttribute("dragactive", "true");
  686.     
  687.     aXferData.data = new TransferDataSet();
  688.     var data = new TransferData();
  689.     data.addDataForFlavour("text/toolbarwrapper-id/"+documentId, item.firstChild.id);
  690.     aXferData.data.push(data);
  691.   }
  692. }
  693.  
  694. var toolbarDNDObserver =
  695. {
  696.   onDragOver: function (aEvent, aFlavour, aDragSession)
  697.   {
  698.     var toolbar = aEvent.target;
  699.     var dropTarget = aEvent.target;
  700.     while (toolbar && toolbar.localName != "toolbar") {
  701.       dropTarget = toolbar;
  702.       toolbar = toolbar.parentNode;
  703.     }
  704.     
  705.     var previousDragItem = gCurrentDragOverItem;
  706.  
  707.     // Make sure we are dragging over a customizable toolbar.
  708.     if (!isCustomizableToolbar(toolbar)) {
  709.       gCurrentDragOverItem = null;
  710.       return;
  711.     }
  712.     
  713.     if (dropTarget.localName == "toolbar") {
  714.       gCurrentDragOverItem = dropTarget;
  715.     } else {
  716.       var dropTargetWidth = dropTarget.boxObject.width;
  717.       var dropTargetX = dropTarget.boxObject.x;
  718.  
  719.       gCurrentDragOverItem = null;
  720.       if (aEvent.clientX > (dropTargetX + (dropTargetWidth / 2))) {
  721.         gCurrentDragOverItem = dropTarget.nextSibling;
  722.         if (!gCurrentDragOverItem)
  723.           gCurrentDragOverItem = toolbar;
  724.       } else
  725.         gCurrentDragOverItem = dropTarget;
  726.     }    
  727.  
  728.     if (previousDragItem && gCurrentDragOverItem != previousDragItem) {
  729.       setDragActive(previousDragItem, false);
  730.     }
  731.     
  732.     setDragActive(gCurrentDragOverItem, true);
  733.     
  734.     aDragSession.canDrop = true;
  735.   },
  736.   
  737.   onDrop: function (aEvent, aXferData, aDragSession)
  738.   {
  739.     if (!gCurrentDragOverItem)
  740.       return;
  741.     
  742.     setDragActive(gCurrentDragOverItem, false);
  743.  
  744.     var draggedItemId = aXferData.data;
  745.     if (gCurrentDragOverItem.id == draggedItemId)
  746.       return;
  747.  
  748.     var toolbar = aEvent.target;
  749.     while (toolbar.localName != "toolbar")
  750.       toolbar = toolbar.parentNode;
  751.  
  752.     var draggedPaletteWrapper = document.getElementById("wrapper-"+draggedItemId);       
  753.     if (!draggedPaletteWrapper) {
  754.       // The wrapper has been dragged from the toolbar.
  755.       
  756.       // Get the wrapper from the toolbar document and make sure that
  757.       // it isn't being dropped on itself.
  758.       var wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId);
  759.       if (wrapper == gCurrentDragOverItem)
  760.         return;
  761.  
  762.       // Don't allow static kids (e.g., the menubar) to move.
  763.       if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id)
  764.         return;
  765.       if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id)
  766.         return;
  767.  
  768.       // Remove the item from it's place in the toolbar.
  769.       wrapper.parentNode.removeChild(wrapper);
  770.  
  771.       // Determine which toolbar we are dropping on.
  772.       var dropToolbar = null;
  773.       if (gCurrentDragOverItem.localName == "toolbar")
  774.         dropToolbar = gCurrentDragOverItem;
  775.       else
  776.         dropToolbar = gCurrentDragOverItem.parentNode;
  777.       
  778.       // Insert the item into the toolbar.
  779.       if (gCurrentDragOverItem != dropToolbar)
  780.         dropToolbar.insertBefore(wrapper, gCurrentDragOverItem);
  781.       else
  782.         dropToolbar.appendChild(wrapper);
  783.     } else {
  784.       // The item has been dragged from the palette
  785.       
  786.       // Create a new wrapper for the item. We don't know the id yet.
  787.       var wrapper = createWrapper("");
  788.  
  789.       // Ask the toolbar to clone the item's template, place it inside the wrapper, and insert it in the toolbar.
  790.       var newItem = toolbar.insertItem(draggedItemId, gCurrentDragOverItem == toolbar ? null : gCurrentDragOverItem, wrapper);
  791.       
  792.       // Prepare the item and wrapper to look good on the toolbar.
  793.       cleanupItemForToolbar(newItem, wrapper);
  794.       wrapper.id = "wrapper-"+newItem.id;
  795.       wrapper.flex = newItem.flex;
  796.  
  797.       // Remove the wrapper from the palette.
  798.       var currentRow = draggedPaletteWrapper.parentNode;
  799.       if (draggedItemId != "separator" &&
  800.           draggedItemId != "spring" &&
  801.           draggedItemId != "spacer")
  802.       {
  803.         currentRow.removeChild(draggedPaletteWrapper);
  804.  
  805.         while (currentRow) {
  806.           // Pull the first child of the next row up
  807.           // into this row.
  808.           var nextRow = currentRow.nextSibling;
  809.           
  810.           if (!nextRow) {
  811.             var last = currentRow.lastChild;
  812.             var first = currentRow.firstChild;
  813.             if (first == last) {
  814.               // Kill the row.
  815.               currentRow.parentNode.removeChild(currentRow);
  816.               break;
  817.             }
  818.  
  819.             if (last.localName == "spacer") {
  820.               var flex = last.getAttribute("flex");
  821.               last.setAttribute("flex", ++flex);
  822.               // Reflow doesn't happen for some reason.  Trigger it with a hide/show. ICK! -dwh
  823.               last.hidden = true;
  824.               last.hidden = false;
  825.               break;
  826.             } else {
  827.               // Make a spacer and give it a flex of 1.
  828.               var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  829.                                                     "spacer");
  830.               spacer.setAttribute("flex", "1");
  831.               currentRow.appendChild(spacer);
  832.             }
  833.             break;
  834.           }
  835.           
  836.           currentRow.appendChild(nextRow.firstChild);
  837.           currentRow = currentRow.nextSibling;
  838.         }
  839.       }
  840.     }
  841.     
  842.     gCurrentDragOverItem = null;
  843.  
  844.     repositionDialog();
  845.     gToolboxChanged = true;
  846.   },
  847.   
  848.   _flavourSet: null,
  849.   
  850.   getSupportedFlavours: function ()
  851.   {
  852.     if (!this._flavourSet) {
  853.       this._flavourSet = new FlavourSet();
  854.       var documentId = gToolboxDocument.documentElement.id;
  855.       this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId);
  856.     }
  857.     return this._flavourSet;
  858.   }
  859. }
  860.  
  861. var paletteDNDObserver =
  862. {
  863.   onDragOver: function (aEvent, aFlavour, aDragSession)
  864.   {
  865.     aDragSession.canDrop = true;
  866.   },
  867.   
  868.   onDrop: function(aEvent, aXferData, aDragSession)
  869.   {
  870.     var itemId = aXferData.data;
  871.     
  872.     var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId);
  873.     if (wrapper) {
  874.       // Don't allow static kids (e.g., the menubar) to move.
  875.       if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id)
  876.         return;
  877.       if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id)
  878.         return;
  879.  
  880.       // The item was dragged out of the toolbar.
  881.       wrapper.parentNode.removeChild(wrapper);
  882.       
  883.       var wrapperType = wrapper.getAttribute("type");
  884.       if (wrapperType != "separator" && wrapperType != "spacer" && wrapperType != "spring") {
  885.         // Find the template node in the toolbox palette
  886.         var templateNode = gToolbox.palette.firstChild;
  887.         while (templateNode) {
  888.           if (templateNode.id == itemId)
  889.             break;
  890.           templateNode = templateNode.nextSibling;
  891.         }
  892.         if (!templateNode)
  893.           return;
  894.         
  895.         // Clone the template and add it to our palette.
  896.         var paletteItem = templateNode.cloneNode(true);
  897.         appendPaletteItem(paletteItem);
  898.       }
  899.     }
  900.     
  901.     repositionDialog();
  902.     gToolboxChanged = true;
  903.   },
  904.   
  905.   _flavourSet: null,
  906.   
  907.   getSupportedFlavours: function ()
  908.   {
  909.     if (!this._flavourSet) {
  910.       this._flavourSet = new FlavourSet();
  911.       var documentId = gToolboxDocument.documentElement.id;
  912.       this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId);
  913.     }
  914.     return this._flavourSet;
  915.   }
  916. }
  917.  
  918. function addNewToolbar()
  919. {
  920.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  921.                                 .getService(Components.interfaces.nsIPromptService);
  922.  
  923.   var stringBundle = document.getElementById("stringBundle");
  924.   var message = stringBundle.getString("enterToolbarName");
  925.   var title = stringBundle.getString("enterToolbarTitle");
  926.  
  927.   var name = {};
  928.   while (1) {
  929.     if (!promptService.prompt(window, title, message, name, null, {})) {
  930.       return;
  931.     } else {
  932.       // Check for an existing toolbar with the same name and prompt again
  933.       // if a conflict is found
  934.       var nameToId = "__customToolbar_" + name.value.replace(" ", "");
  935.       var existingToolbar = gToolboxDocument.getElementById(nameToId);
  936.       if (existingToolbar) {
  937.         message = stringBundle.getFormattedString("enterToolbarDup", [name.value]);
  938.       } else {
  939.         break;
  940.       }
  941.     }
  942.   }
  943.  
  944.   gToolbox.appendCustomToolbar(name.value, "");
  945.  
  946.   repositionDialog();
  947.   gToolboxChanged = true;
  948. }
  949.