# ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is Mozilla Communicator client code, released # March 31, 1998. # # The Initial Developer of the Original Code is # David Hyatt. # Portions created by the Initial Developer are Copyright (C) 2002 # the Initial Developer. All Rights Reserved. # # Contributor(s): # David Hyatt (hyatt@apple.com) # Blake Ross (blaker@netscape.com) # Joe Hewitt (hewitt@netscape.com) # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** const kRowMax = 4; var gToolboxDocument = null; var gToolbox = null; var gCurrentDragOverItem = null; var gToolboxChanged = false; var gToolboxIconSize = false; function onLoad() { InitWithToolbox(window.arguments[0]); repositionDialog(); } function InitWithToolbox(aToolbox) { gToolbox = aToolbox; gToolboxDocument = gToolbox.ownerDocument; gToolbox.addEventListener("draggesture", onToolbarDragGesture, false); gToolbox.addEventListener("dragover", onToolbarDragOver, false); gToolbox.addEventListener("dragexit", onToolbarDragExit, false); gToolbox.addEventListener("dragdrop", onToolbarDragDrop, false); initDialog(); } function finishToolbarCustomization() { removeToolboxListeners(); unwrapToolbarItems(); persistCurrentSets(); notifyParentComplete(); } function onUnload(aEvent) { finishToolbarCustomization(); window.close(); } function onAccept(aEvent) { document.getElementById("main-box").collapsed = true; window.close(); } function initDialog() { document.getElementById("main-box").collapsed = false; var mode = gToolbox.getAttribute("mode"); document.getElementById("modelist").value = mode; gToolboxIconSize = gToolbox.getAttribute("iconsize"); var smallIconsCheckbox = document.getElementById("smallicons"); if (mode == "text") smallIconsCheckbox.disabled = true; else smallIconsCheckbox.checked = gToolboxIconSize == "small"; // Build up the palette of other items. buildPalette(); // Wrap all the items on the toolbar in toolbarpaletteitems. wrapToolbarItems(); } function repositionDialog() { // Position the dialog touching the bottom of the toolbox and centered with // it. var width; if (document.documentElement.hasAttribute("width")) width = document.documentElement.getAttribute("width"); else width = parseInt(document.documentElement.style.width); var screenX = gToolbox.boxObject.screenX + ((gToolbox.boxObject.width - width) / 2); var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height; window.moveTo(screenX, screenY); } function removeToolboxListeners() { gToolbox.removeEventListener("draggesture", onToolbarDragGesture, false); gToolbox.removeEventListener("dragover", onToolbarDragOver, false); gToolbox.removeEventListener("dragexit", onToolbarDragExit, false); gToolbox.removeEventListener("dragdrop", onToolbarDragDrop, false); } /** * Invoke a callback on the toolbox to notify it that the dialog is done * and going away. */ function notifyParentComplete() { if ("customizeDone" in gToolbox) gToolbox.customizeDone(gToolboxChanged); } function getToolbarAt(i) { return gToolbox.childNodes[i]; } /** * Persist the current set of buttons in all customizable toolbars to * localstore. */ function persistCurrentSets() { if (!gToolboxChanged) return; var customCount = 0; for (var i = 0; i < gToolbox.childNodes.length; ++i) { // Look for customizable toolbars that need to be persisted. var toolbar = getToolbarAt(i); if (isCustomizableToolbar(toolbar)) { // Calculate currentset and store it in the attribute. var currentSet = toolbar.currentSet; toolbar.setAttribute("currentset", currentSet); var customIndex = toolbar.hasAttribute("customindex"); if (customIndex) { if (!toolbar.firstChild) { // Remove custom toolbars whose contents have been removed. gToolbox.removeChild(toolbar); --i; } else { // Persist custom toolbar info on the gToolbox.toolbarset.setAttribute("toolbar"+(++customCount), toolbar.toolbarName + ":" + currentSet); gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount); } } if (!customIndex) { // Persist the currentset attribute directly on hardcoded toolbars. gToolboxDocument.persist(toolbar.id, "currentset"); } } } // Remove toolbarX attributes for removed toolbars. while (gToolbox.toolbarset.hasAttribute("toolbar"+(++customCount))) { gToolbox.toolbarset.removeAttribute("toolbar"+customCount); gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount); } } /** * Wraps all items in all customizable toolbars in a toolbox. */ function wrapToolbarItems() { for (var i = 0; i < gToolbox.childNodes.length; ++i) { var toolbar = getToolbarAt(i); if (isCustomizableToolbar(toolbar)) { for (var k = 0; k < toolbar.childNodes.length; ++k) { var item = toolbar.childNodes[k]; if (isToolbarItem(item)) { var nextSibling = item.nextSibling; var wrapper = wrapToolbarItem(item); if (nextSibling) toolbar.insertBefore(wrapper, nextSibling); else toolbar.appendChild(wrapper); } } } } } /** * Unwraps all items in all customizable toolbars in a toolbox. */ function unwrapToolbarItems() { var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem"); var paletteItem; while ((paletteItem = paletteItems.item(0)) != null) { var toolbarItem = paletteItem.firstChild; if (paletteItem.hasAttribute("itemdisabled")) toolbarItem.disabled = true; if (paletteItem.hasAttribute("itemcommand")) toolbarItem.setAttribute("command", paletteItem.getAttribute("itemcommand")); // We need the removeChild here because replaceChild and XBL no workee // together. See bug 193298. paletteItem.removeChild(toolbarItem); paletteItem.parentNode.replaceChild(toolbarItem, paletteItem); } } /** * Creates a wrapper that can be used to contain a toolbaritem and prevent * it from receiving UI events. */ function createWrapper(aId) { var wrapper = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "toolbarpaletteitem"); wrapper.id = "wrapper-"+aId; return wrapper; } /** * Wraps an item that has been cloned from a template and adds * it to the end of a row in the palette. */ function wrapPaletteItem(aPaletteItem, aCurrentRow, aSpacer) { var wrapper = createWrapper(aPaletteItem.id); wrapper.setAttribute("flex", 1); wrapper.setAttribute("align", "center"); wrapper.setAttribute("pack", "center"); wrapper.setAttribute("minheight", "0"); wrapper.setAttribute("minwidth", "0"); wrapper.appendChild(aPaletteItem); // XXX We need to call this AFTER the palette item has been appended // to the wrapper or else we crash dropping certain buttons on the // palette due to removal of the command and disabled attributes - JRH cleanUpItemForPalette(aPaletteItem, wrapper); if (aSpacer) aCurrentRow.insertBefore(wrapper, aSpacer); else aCurrentRow.appendChild(wrapper); } /** * Wraps an item that is currently on a toolbar and replaces the item * with the wrapper. This is not used when dropping items from the palette, * only when first starting the dialog and wrapping everything on the toolbars. */ function wrapToolbarItem(aToolbarItem) { var wrapper = createWrapper(aToolbarItem.id); cleanupItemForToolbar(aToolbarItem, wrapper); wrapper.flex = aToolbarItem.flex; if (aToolbarItem.parentNode) aToolbarItem.parentNode.removeChild(aToolbarItem); wrapper.appendChild(aToolbarItem); return wrapper; } /** * Get the list of ids for the current set of items on each toolbar. */ function getCurrentItemIds() { var currentItems = {}; for (var i = 0; i < gToolbox.childNodes.length; ++i) { var toolbar = getToolbarAt(i); if (isCustomizableToolbar(toolbar)) { var child = toolbar.firstChild; while (child) { if (isToolbarItem(child)) currentItems[child.id] = 1; child = child.nextSibling; } } } return currentItems; } /** * Builds the palette of draggable items that are not yet in a toolbar. */ function buildPalette() { // Empty the palette first. var paletteBox = document.getElementById("palette-box"); while (paletteBox.lastChild) paletteBox.removeChild(paletteBox.lastChild); var currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox"); currentRow.setAttribute("class", "paletteRow"); // Add the toolbar separator item. var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "toolbarseparator"); templateNode.id = "separator"; wrapPaletteItem(templateNode, currentRow, null); // Add the toolbar spring item. templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "toolbarspring"); templateNode.id = "spring"; templateNode.flex = 1; wrapPaletteItem(templateNode, currentRow, null); // Add the toolbar spacer item. templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "toolbarspacer"); templateNode.id = "spacer"; templateNode.flex = 1; wrapPaletteItem(templateNode, currentRow, null); var rowSlot = 3; var currentItems = getCurrentItemIds(); templateNode = gToolbox.palette.firstChild; while (templateNode) { // Check if the item is already in a toolbar before adding it to the palette. if (!(templateNode.id in currentItems)) { var paletteItem = templateNode.cloneNode(true); if (rowSlot == kRowMax) { // Append the old row. paletteBox.appendChild(currentRow); // Make a new row. currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox"); currentRow.setAttribute("class", "paletteRow"); rowSlot = 0; } ++rowSlot; wrapPaletteItem(paletteItem, currentRow, null); } templateNode = templateNode.nextSibling; } if (currentRow) { fillRowWithFlex(currentRow); paletteBox.appendChild(currentRow); } } /** * Creates a new palette item for a cloned template node and * adds it to the last slot in the palette. */ function appendPaletteItem(aItem) { var paletteBox = document.getElementById("palette-box"); var lastRow = paletteBox.lastChild; var lastSpacer = lastRow.lastChild; if (lastSpacer.localName != "spacer") { // The current row is full, so we have to create a new row. lastRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox"); lastRow.setAttribute("class", "paletteRow"); paletteBox.appendChild(lastRow); wrapPaletteItem(aItem, lastRow, null); fillRowWithFlex(lastRow); } else { // Decrement the flex of the last spacer or remove it entirely. var flex = lastSpacer.getAttribute("flex"); if (flex == 1) { lastRow.removeChild(lastSpacer); lastSpacer = null; } else lastSpacer.setAttribute("flex", --flex); // Insert the wrapper where the last spacer was. wrapPaletteItem(aItem, lastRow, lastSpacer); } } function fillRowWithFlex(aRow) { var remainingFlex = kRowMax - aRow.childNodes.length; if (remainingFlex > 0) { var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "spacer"); spacer.setAttribute("flex", remainingFlex); aRow.appendChild(spacer); } } /** * Makes sure that an item that has been cloned from a template * is stripped of all properties that may adversely affect it's * appearance in the palette. */ function cleanUpItemForPalette(aItem, aWrapper) { aWrapper.setAttribute("place", "palette"); setWrapperType(aItem, aWrapper); if (aItem.hasAttribute("title")) aWrapper.setAttribute("title", aItem.getAttribute("title")); else if (isSpecialItem(aItem)) { var stringBundle = document.getElementById("stringBundle"); var title = stringBundle.getString(aItem.id + "Title"); aWrapper.setAttribute("title", title); } // Remove attributes that screw up our appearance. aItem.removeAttribute("command"); aItem.removeAttribute("observes"); aItem.removeAttribute("disabled"); aItem.removeAttribute("type"); if (aItem.localName == "toolbaritem" && aItem.firstChild) { aItem.firstChild.removeAttribute("observes"); // So the throbber doesn't throb in the dialog, // cute as that may be... aItem.firstChild.removeAttribute("busy"); } } /** * Makes sure that an item that has been cloned from a template * is stripped of all properties that may adversely affect it's * appearance in the toolbar. Store critical properties on the * wrapper so they can be put back on the item when we're done. */ function cleanupItemForToolbar(aItem, aWrapper) { setWrapperType(aItem, aWrapper); aWrapper.setAttribute("place", "toolbar"); if (aItem.hasAttribute("command")) { aWrapper.setAttribute("itemcommand", aItem.getAttribute("command")); aItem.removeAttribute("command"); } if (aItem.disabled) { aWrapper.setAttribute("itemdisabled", "true"); aItem.disabled = false; } } function setWrapperType(aItem, aWrapper) { if (aItem.localName == "toolbarseparator") { aWrapper.setAttribute("type", "separator"); } else if (aItem.localName == "toolbarspring") { aWrapper.setAttribute("type", "spring"); } else if (aItem.localName == "toolbarspacer") { aWrapper.setAttribute("type", "spacer"); } else if (aItem.localName == "toolbaritem" && aItem.firstChild) { aWrapper.setAttribute("type", aItem.firstChild.localName); } } function setDragActive(aItem, aValue) { var node = aItem; var direction = window.getComputedStyle(aItem, null).direction; var value = direction == "ltr"? "left" : "right"; if (aItem.localName == "toolbar") { node = aItem.lastChild; value = direction == "ltr"? "right" : "left"; } if (!node) return; if (aValue) { if (!node.hasAttribute("dragover")) node.setAttribute("dragover", value); } else { node.removeAttribute("dragover"); } } function addNewToolbar() { var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService); var stringBundle = document.getElementById("stringBundle"); var message = stringBundle.getString("enterToolbarName"); var title = stringBundle.getString("enterToolbarTitle"); var name = {}; while (true) { if (!promptService.prompt(window, title, message, name, null, {})) return; if (!name.value) { message = stringBundle.getFormattedString("enterToolbarBlank", [name.value]); continue; } var dupeFound = false; // Check for an existing toolbar with the same display name for (i = 0; i < gToolbox.childNodes.length; ++i) { var toolbar = gToolbox.childNodes[i]; var toolbarName = toolbar.getAttribute("toolbarname"); if (toolbarName == name.value && toolbar.getAttribute("type") != "menubar" && toolbar.nodeName == 'toolbar') { dupeFound = true; break; } } if (!dupeFound) break; message = stringBundle.getFormattedString("enterToolbarDup", [name.value]); } gToolbox.appendCustomToolbar(name.value, ""); gToolboxChanged = true; } /** * Restore the default set of buttons to fixed toolbars, * remove all custom toolbars, and rebuild the palette. */ function restoreDefaultSet() { // Save disabled/command states, because we're // going to recreate the wrappers and lose this var savedAttributes = saveItemAttributes(["itemdisabled", "itemcommand"]); // Restore the defaultset for fixed toolbars. var toolbar = gToolbox.firstChild; while (toolbar) { if (isCustomizableToolbar(toolbar)) { if (!toolbar.hasAttribute("customindex")) { var defaultSet = toolbar.getAttribute("defaultset"); if (defaultSet) toolbar.currentSet = defaultSet; } } toolbar = toolbar.nextSibling; } // Restore the default icon size (large) and mode (icons only). updateIconSize(false); document.getElementById("smallicons").checked = false; updateToolbarMode("icons"); document.getElementById("modelist").value = "icons"; // Remove all of the customized toolbars. var child = gToolbox.lastChild; while (child) { if (child.hasAttribute("customindex")) { var thisChild = child; child = child.previousSibling; gToolbox.removeChild(thisChild); } else { child = child.previousSibling; } } // Now rebuild the palette. buildPalette(); // Now re-wrap the items on the toolbar. wrapToolbarItems(); // Restore the disabled and command states restoreItemAttributes(["itemdisabled", "itemcommand"], savedAttributes); gToolboxChanged = true; } function saveItemAttributes(aAttributeList) { var items = []; var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem"); for (var i = 0; i < paletteItems.length; i++) { var paletteItem = paletteItems.item(i); for (var j = 0; j < aAttributeList.length; j++) { var attr = aAttributeList[j]; if (paletteItem.hasAttribute(attr)) { items.push([paletteItem.id, attr, paletteItem.getAttribute(attr)]); } } } return items; } function restoreItemAttributes(aAttributeList, aSavedAttrList) { var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem"); for (var i = 0; i < paletteItems.length; i++) { var paletteItem = paletteItems.item(i); // if the item is supposed to have this, it'll get // restored from the saved list for (var j = 0; j < aAttributeList.length; j++) paletteItem.removeAttribute(aAttributeList[j]); for (var j = 0; j < aSavedAttrList.length; j++) { var savedAttr = aSavedAttrList[j]; if (paletteItem.id == savedAttr[0]) { paletteItem.setAttribute(savedAttr[1], savedAttr[2]); } } } } function updateIconSize(aUseSmallIcons) { gToolboxIconSize = aUseSmallIcons ? "small" : "large"; setAttribute(gToolbox, "iconsize", gToolboxIconSize); gToolboxDocument.persist(gToolbox.id, "iconsize"); for (var i = 0; i < gToolbox.childNodes.length; ++i) { var toolbar = getToolbarAt(i); if (isCustomizableToolbar(toolbar)) { setAttribute(toolbar, "iconsize", gToolboxIconSize); gToolboxDocument.persist(toolbar.id, "iconsize"); } } } function updateToolbarMode(aModeValue) { setAttribute(gToolbox, "mode", aModeValue); gToolboxDocument.persist(gToolbox.id, "mode"); for (var i = 0; i < gToolbox.childNodes.length; ++i) { var toolbar = getToolbarAt(i); if (isCustomizableToolbar(toolbar)) { setAttribute(toolbar, "mode", aModeValue); gToolboxDocument.persist(toolbar.id, "mode"); } } var iconSizeCheckbox = document.getElementById("smallicons"); iconSizeCheckbox.disabled = aModeValue == "text"; } function setAttribute(aElt, aAttr, aVal) { if (aVal) aElt.setAttribute(aAttr, aVal); else aElt.removeAttribute(aAttr); } function isCustomizableToolbar(aElt) { return aElt.localName == "toolbar" && aElt.getAttribute("customizable") == "true"; } function isSpecialItem(aElt) { return aElt.localName == "toolbarseparator" || aElt.localName == "toolbarspring" || aElt.localName == "toolbarspacer"; } function isToolbarItem(aElt) { return aElt.localName == "toolbarbutton" || aElt.localName == "toolbaritem" || aElt.localName == "toolbarseparator" || aElt.localName == "toolbarspring" || aElt.localName == "toolbarspacer"; } /////////////////////////////////////////////////////////////////////////// //// Drag and Drop observers function onToolbarDragGesture(aEvent) { nsDragAndDrop.startDrag(aEvent, dragStartObserver); } function onToolbarDragOver(aEvent) { nsDragAndDrop.dragOver(aEvent, toolbarDNDObserver); } function onToolbarDragDrop(aEvent) { nsDragAndDrop.drop(aEvent, toolbarDNDObserver); } function onToolbarDragExit(aEvent) { if (gCurrentDragOverItem) setDragActive(gCurrentDragOverItem, false); } var dragStartObserver = { onDragStart: function (aEvent, aXferData, aDragAction) { var documentId = gToolboxDocument.documentElement.id; var item = aEvent.target; while (item && item.localName != "toolbarpaletteitem") item = item.parentNode; item.setAttribute("dragactive", "true"); aXferData.data = new TransferDataSet(); var data = new TransferData(); data.addDataForFlavour("text/toolbarwrapper-id/"+documentId, item.firstChild.id); aXferData.data.push(data); aDragAction.action = Components.interfaces.nsIDragService.DRAGDROP_ACTION_MOVE; } } var toolbarDNDObserver = { onDragOver: function (aEvent, aFlavour, aDragSession) { var toolbar = aEvent.target; var dropTarget = aEvent.target; while (toolbar && toolbar.localName != "toolbar") { dropTarget = toolbar; toolbar = toolbar.parentNode; } var previousDragItem = gCurrentDragOverItem; // Make sure we are dragging over a customizable toolbar. if (!isCustomizableToolbar(toolbar)) { gCurrentDragOverItem = null; return; } if (dropTarget.localName == "toolbar") { gCurrentDragOverItem = dropTarget; } else { gCurrentDragOverItem = null; var direction = window.getComputedStyle(dropTarget.parentNode, null).direction; var dropTargetCenter = dropTarget.boxObject.x + (dropTarget.boxObject.width / 2); if (direction == "ltr") dragAfter = aEvent.clientX > dropTargetCenter; else dragAfter = aEvent.clientX < dropTargetCenter; if (dragAfter) { gCurrentDragOverItem = dropTarget.nextSibling; if (!gCurrentDragOverItem) gCurrentDragOverItem = toolbar; } else gCurrentDragOverItem = dropTarget; } if (previousDragItem && gCurrentDragOverItem != previousDragItem) { setDragActive(previousDragItem, false); } setDragActive(gCurrentDragOverItem, true); aDragSession.canDrop = true; }, onDrop: function (aEvent, aXferData, aDragSession) { if (!gCurrentDragOverItem) return; setDragActive(gCurrentDragOverItem, false); var draggedItemId = aXferData.data; if (gCurrentDragOverItem.id == draggedItemId) return; var toolbar = aEvent.target; while (toolbar.localName != "toolbar") toolbar = toolbar.parentNode; var draggedPaletteWrapper = document.getElementById("wrapper-"+draggedItemId); if (!draggedPaletteWrapper) { // The wrapper has been dragged from the toolbar. // Get the wrapper from the toolbar document and make sure that // it isn't being dropped on itself. var wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId); if (wrapper == gCurrentDragOverItem) return; // Don't allow static kids (e.g., the menubar) to move. if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id) return; if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id) return; // Remove the item from it's place in the toolbar. wrapper.parentNode.removeChild(wrapper); // Determine which toolbar we are dropping on. var dropToolbar = null; if (gCurrentDragOverItem.localName == "toolbar") dropToolbar = gCurrentDragOverItem; else dropToolbar = gCurrentDragOverItem.parentNode; // Insert the item into the toolbar. if (gCurrentDragOverItem != dropToolbar) dropToolbar.insertBefore(wrapper, gCurrentDragOverItem); else dropToolbar.appendChild(wrapper); } else { // The item has been dragged from the palette // Create a new wrapper for the item. We don't know the id yet. var wrapper = createWrapper(""); // Ask the toolbar to clone the item's template, place it inside the wrapper, and insert it in the toolbar. var newItem = toolbar.insertItem(draggedItemId, gCurrentDragOverItem == toolbar ? null : gCurrentDragOverItem, wrapper); // Prepare the item and wrapper to look good on the toolbar. cleanupItemForToolbar(newItem, wrapper); wrapper.id = "wrapper-"+newItem.id; wrapper.flex = newItem.flex; // Remove the wrapper from the palette. var currentRow = draggedPaletteWrapper.parentNode; if (draggedItemId != "separator" && draggedItemId != "spring" && draggedItemId != "spacer") { currentRow.removeChild(draggedPaletteWrapper); while (currentRow) { // Pull the first child of the next row up // into this row. var nextRow = currentRow.nextSibling; if (!nextRow) { var last = currentRow.lastChild; var first = currentRow.firstChild; if (first == last) { // Kill the row. currentRow.parentNode.removeChild(currentRow); break; } if (last.localName == "spacer") { var flex = last.getAttribute("flex"); last.setAttribute("flex", ++flex); // Reflow doesn't happen for some reason. Trigger it with a hide/show. ICK! -dwh last.hidden = true; last.hidden = false; break; } else { // Make a spacer and give it a flex of 1. var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "spacer"); spacer.setAttribute("flex", "1"); currentRow.appendChild(spacer); } break; } currentRow.appendChild(nextRow.firstChild); currentRow = currentRow.nextSibling; } } } gCurrentDragOverItem = null; gToolboxChanged = true; }, _flavourSet: null, getSupportedFlavours: function () { if (!this._flavourSet) { this._flavourSet = new FlavourSet(); var documentId = gToolboxDocument.documentElement.id; this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId); } return this._flavourSet; } } var paletteDNDObserver = { onDragOver: function (aEvent, aFlavour, aDragSession) { aDragSession.canDrop = true; }, onDrop: function(aEvent, aXferData, aDragSession) { var itemId = aXferData.data; var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId); if (wrapper) { // Don't allow static kids (e.g., the menubar) to move. if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id) return; if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id) return; // The item was dragged out of the toolbar. wrapper.parentNode.removeChild(wrapper); var wrapperType = wrapper.getAttribute("type"); if (wrapperType != "separator" && wrapperType != "spacer" && wrapperType != "spring") { // Find the template node in the toolbox palette var templateNode = gToolbox.palette.firstChild; while (templateNode) { if (templateNode.id == itemId) break; templateNode = templateNode.nextSibling; } if (!templateNode) return; // Clone the template and add it to our palette. var paletteItem = templateNode.cloneNode(true); appendPaletteItem(paletteItem); } } gToolboxChanged = true; }, _flavourSet: null, getSupportedFlavours: function () { if (!this._flavourSet) { this._flavourSet = new FlavourSet(); var documentId = gToolboxDocument.documentElement.id; this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId); } return this._flavourSet; } }