home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / code / Firefox_1.0.5.exe / browser.xpi / bin / chrome / toolkit.jar / content / global / customizeToolbar.js < prev    next >
Encoding:
Text File  |  2004-10-05  |  28.7 KB  |  946 lines

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