Browse Source

[Navigator] Override customizeToolbar.xul with a private version that is consistent with the application

custom-older
Matt A. Tobin 2 years ago committed by Roy Tam
parent
commit
d7e8a2dfa6
  1. 50
      navigator/comm/content/utilityOverlay.js
  2. 1
      navigator/components/moz.build
  3. 58
      navigator/components/toolbar/content/customizeToolbar.css
  4. 832
      navigator/components/toolbar/content/customizeToolbar.js
  5. 64
      navigator/components/toolbar/content/customizeToolbar.xul
  6. 13
      navigator/components/toolbar/jar.mn
  7. 10
      navigator/components/toolbar/locale/customizeToolbar.dtd
  8. 12
      navigator/components/toolbar/locale/customizeToolbar.properties
  9. 6
      navigator/components/toolbar/moz.build

50
navigator/comm/content/utilityOverlay.js

@ -267,8 +267,6 @@ function goToggleToolbar(id, elementID)
}
var gCustomizeSheet = false;
function SuiteCustomizeToolbar(aMenuItem)
{
let toolbar = aMenuItem.parentNode.triggerNode;
@ -288,41 +286,10 @@ function goCustomizeToolbar(toolbox)
if ("customizeInit" in toolbox)
toolbox.customizeInit();
var customizeURL = "chrome://global/content/customizeToolbar.xul";
gCustomizeSheet = GetBoolPref("toolbar.customization.usesheet", false);
if (gCustomizeSheet) {
var sheetFrame = document.getElementById("customizeToolbarSheetIFrame");
var panel = document.getElementById("customizeToolbarSheetPopup");
sheetFrame.hidden = false;
sheetFrame.toolbox = toolbox;
sheetFrame.panel = panel;
// The document might not have been loaded yet, if this is the first time.
// If it is already loaded, reload it so that the onload initialization
// code re-runs.
if (sheetFrame.getAttribute("src") == customizeURL)
sheetFrame.contentWindow.location.reload();
else
sheetFrame.setAttribute("src", customizeURL);
// Open the panel, but make it invisible until the iframe has loaded so
// that the user doesn't see a white flash.
panel.style.visibility = "hidden";
toolbox.addEventListener("beforecustomization", function toolboxBeforeCustom() {
toolbox.removeEventListener("beforecustomization", toolboxBeforeCustom, false);
panel.style.removeProperty("visibility");
}, false);
panel.openPopup(toolbox, "after_start", 0, 0);
return sheetFrame.contentWindow;
}
else {
return window.openDialog(customizeURL,
"",
"chrome,all,dependent",
toolbox);
}
return window.openDialog("chrome://global/content/customizeToolbar.xul",
"",
"chrome,all,dependent,centerscreen",
toolbox);
}
function onViewToolbarsPopupShowing(aEvent, aInsertPoint)
@ -521,14 +488,7 @@ function toolboxCustomizeInit(menubarID)
function toolboxCustomizeDone(menubarID, toolbox, aToolboxChanged)
{
if (gCustomizeSheet) {
document.getElementById("customizeToolbarSheetIFrame").hidden = true;
document.getElementById("customizeToolbarSheetPopup").hidePopup();
if (content)
content.focus();
else
window.focus();
}
window.focus();
// Re-enable parts of the UI we disabled during the dialog
var menubar = document.getElementById(menubarID);

1
navigator/components/moz.build

@ -19,6 +19,7 @@ DIRS += [
'shell',
'sidebar',
'smile',
'toolbar',
]
XPIDL_SOURCES += [

58
navigator/components/toolbar/content/customizeToolbar.css

@ -0,0 +1,58 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
@namespace html url("http://www.w3.org/1999/xhtml"); /* namespace for HTML elements */
#main-box > box {
overflow: hidden;
margin-top: 9px;
margin-right: 8px;
margin-bottom: 5px;
margin-left: 8px;
}
#palette-box {
-moz-appearance: listbox;
overflow: auto;
display: block;
min-height: 3em;
margin-top: 8px;
margin-right: 8px;
margin-left: 8px;
}
#palette-box > toolbarpaletteitem {
width: 110px;
height: 94px;
overflow: hidden;
display: inline-block;
padding: 8px 2px;
margin: 0 8px;
}
#palette-box > toolbarpaletteitem > label {
text-align: center;
}
.toolbarpaletteitem-box {
-moz-box-pack: center;
-moz-box-flex: 1;
width: 110px;
max-width: 110px;
}
/* Hide the toolbarbutton label because we replicate it on the wrapper */
.toolbarbutton-text {
display: none;
}
separator {
margin-left: 8px;
margin-right: 8px;
}
.actionButtons {
margin: 0 3px 6px !important;
}

832
navigator/components/toolbar/content/customizeToolbar.js

@ -0,0 +1,832 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const gToolbarInfoSeparators = ["|", "-"];
var gToolboxDocument = null;
var gToolbox = null;
var gCurrentDragOverItem = null;
var gToolboxChanged = false;
var gToolboxSheet = false;
var gPaletteBox = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function onLoad()
{
if ("arguments" in window && window.arguments[0]) {
InitWithToolbox(window.arguments[0]);
repositionDialog(window);
}
else if (window.frameElement &&
"toolbox" in window.frameElement) {
gToolboxSheet = true;
InitWithToolbox(window.frameElement.toolbox);
repositionDialog(window.frameElement.panel);
}
}
function InitWithToolbox(aToolbox)
{
gToolbox = aToolbox;
dispatchCustomizationEvent("beforecustomization");
gToolboxDocument = gToolbox.ownerDocument;
gToolbox.customizing = true;
forEachCustomizableToolbar(function (toolbar) {
toolbar.setAttribute("customizing", "true");
});
gPaletteBox = document.getElementById("palette-box");
var elts = getRootElements();
for (let i=0; i < elts.length; i++) {
elts[i].addEventListener("dragstart", onToolbarDragStart, true);
elts[i].addEventListener("dragover", onToolbarDragOver, true);
elts[i].addEventListener("dragexit", onToolbarDragExit, true);
elts[i].addEventListener("drop", onToolbarDrop, true);
}
initDialog();
}
function onClose()
{
if (!gToolboxSheet)
window.close();
else
finishToolbarCustomization();
}
function onUnload()
{
if (!gToolboxSheet)
finishToolbarCustomization();
}
function finishToolbarCustomization()
{
removeToolboxListeners();
unwrapToolbarItems();
persistCurrentSets();
gToolbox.customizing = false;
forEachCustomizableToolbar(function (toolbar) {
toolbar.removeAttribute("customizing");
});
notifyParentComplete();
}
function initDialog()
{
if (!gToolbox.toolbarset) {
document.getElementById("newtoolbar").hidden = true;
}
// Build up the palette of other items.
buildPalette();
// Wrap all the items on the toolbar in toolbarpaletteitems.
wrapToolbarItems();
}
function repositionDialog(aWindow)
{
// Position the dialog touching the bottom of the toolbox and centered with
// it.
if (!aWindow)
return;
var width;
if (aWindow != window)
width = aWindow.getBoundingClientRect().width;
else 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;
aWindow.moveTo(screenX, screenY);
}
function removeToolboxListeners()
{
var elts = getRootElements();
for (let i=0; i < elts.length; i++) {
elts[i].removeEventListener("dragstart", onToolbarDragStart, true);
elts[i].removeEventListener("dragover", onToolbarDragOver, true);
elts[i].removeEventListener("dragexit", onToolbarDragExit, true);
elts[i].removeEventListener("drop", onToolbarDrop, true);
}
}
/**
* 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);
dispatchCustomizationEvent("aftercustomization");
}
function toolboxChanged(aType)
{
gToolboxChanged = true;
if ("customizeChange" in gToolbox)
gToolbox.customizeChange(aType);
dispatchCustomizationEvent("customizationchange");
}
function dispatchCustomizationEvent(aEventName) {
var evt = document.createEvent("Events");
evt.initEvent(aEventName, true, true);
gToolbox.dispatchEvent(evt);
}
/**
* Persist the current set of buttons in all customizable toolbars to
* localstore.
*/
function persistCurrentSets()
{
if (!gToolboxChanged || gToolboxDocument.defaultView.closed)
return;
var customCount = 0;
forEachCustomizableToolbar(function (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.hasChildNodes()) {
// Remove custom toolbars whose contents have been removed.
gToolbox.removeChild(toolbar);
} else if (gToolbox.toolbarset) {
var hidingAttribute = toolbar.getAttribute("type") == "menubar" ?
"autohide" : "collapsed";
// Persist custom toolbar info on the <toolbarset/>
// Attributes:
// Names: "toolbarX" (X - the number of the toolbar)
// Values: "Name|HidingAttributeName-HidingAttributeValue|CurrentSet"
gToolbox.toolbarset.setAttribute("toolbar" + (++customCount),
toolbar.toolbarName
+ gToolbarInfoSeparators[0]
+ hidingAttribute
+ gToolbarInfoSeparators[1]
+ toolbar.getAttribute(hidingAttribute)
+ gToolbarInfoSeparators[0]
+ 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 && 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()
{
forEachCustomizableToolbar(function (toolbar) {
Array.forEach(toolbar.childNodes, function (item) {
#ifdef XP_MACOSX
if (item.firstChild && item.firstChild.localName == "menubar")
return;
#endif
if (isToolbarItem(item)) {
let wrapper = wrapToolbarItem(item);
cleanupItemForToolbar(item, wrapper);
}
});
});
}
function getRootElements()
{
return [gToolbox].concat(gToolbox.externalToolbars);
}
/**
* Unwraps all items in all customizable toolbars in a toolbox.
*/
function unwrapToolbarItems()
{
let elts = getRootElements();
for (let i=0; i < elts.length; i++) {
let paletteItems = elts[i].getElementsByTagName("toolbarpaletteitem");
let paletteItem;
while ((paletteItem = paletteItems.item(0)) != null) {
let toolbarItem = paletteItem.firstChild;
restoreItemForToolbar(toolbarItem, paletteItem);
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, aDocument)
{
var wrapper = aDocument.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 the palette.
*/
function wrapPaletteItem(aPaletteItem)
{
var wrapper = createWrapper(aPaletteItem.id, document);
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);
gPaletteBox.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, gToolboxDocument);
wrapper.flex = aToolbarItem.flex;
aToolbarItem.parentNode.replaceChild(wrapper, aToolbarItem);
wrapper.appendChild(aToolbarItem);
return wrapper;
}
/**
* Get the list of ids for the current set of items on each toolbar.
*/
function getCurrentItemIds()
{
var currentItems = {};
forEachCustomizableToolbar(function (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.
while (gPaletteBox.lastChild)
gPaletteBox.removeChild(gPaletteBox.lastChild);
// 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);
// 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);
// 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);
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 = document.importNode(templateNode, true);
wrapPaletteItem(paletteItem);
}
templateNode = templateNode.nextSibling;
}
}
/**
* Makes sure that an item that has been cloned from a template
* is stripped of any attributes that may adversely affect its
* 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 (aItem.hasAttribute("label"))
aWrapper.setAttribute("title", aItem.getAttribute("label"));
else if (isSpecialItem(aItem)) {
var stringBundle = document.getElementById("stringBundle");
// Remove the common "toolbar" prefix to generate the string name.
var title = stringBundle.getString(aItem.localName.slice(7) + "Title");
aWrapper.setAttribute("title", title);
}
aWrapper.setAttribute("tooltiptext", aWrapper.getAttribute("title"));
// Remove attributes that screw up our appearance.
aItem.removeAttribute("command");
aItem.removeAttribute("observes");
aItem.removeAttribute("type");
aItem.removeAttribute("width");
Array.forEach(aWrapper.querySelectorAll("[disabled]"), function(aNode) {
aNode.removeAttribute("disabled");
});
}
/**
* Makes sure that an item that has been cloned from a template
* is stripped of all properties that may adversely affect its
* 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.checked) {
aWrapper.setAttribute("itemchecked", "true");
aItem.checked = false;
}
if (aItem.disabled) {
aWrapper.setAttribute("itemdisabled", "true");
aItem.disabled = false;
}
}
/**
* Restore all the properties that we stripped off above.
*/
function restoreItemForToolbar(aItem, aWrapper)
{
if (aWrapper.hasAttribute("itemdisabled"))
aItem.disabled = true;
if (aWrapper.hasAttribute("itemchecked"))
aItem.checked = true;
if (aWrapper.hasAttribute("itemcommand")) {
let commandID = aWrapper.getAttribute("itemcommand");
aItem.setAttribute("command", commandID);
// XXX Bug 309953 - toolbarbuttons aren't in sync with their commands after customizing
let command = gToolboxDocument.getElementById(commandID);
if (command && command.hasAttribute("disabled"))
aItem.setAttribute("disabled", command.getAttribute("disabled"));
}
}
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 = Services.prompt;
var stringBundle = document.getElementById("stringBundle");
var message = stringBundle.getString("enterToolbarName");
var title = stringBundle.getString("enterToolbarTitle");
var name = {};
// Quitting from the toolbar dialog while the new toolbar prompt is up
// can cause things to become unresponsive on the Mac. Until dialog modality
// is fixed (395465), disable the "Done" button explicitly.
var doneButton = document.getElementById("donebutton");
doneButton.disabled = true;
while (true) {
if (!promptService.prompt(window, title, message, name, null, {})) {
doneButton.disabled = false;
return;
}
if (!name.value) {
message = stringBundle.getFormattedString("enterToolbarBlank", [name.value]);
continue;
}
if (name.value.includes(gToolbarInfoSeparators[0])) {
message = stringBundle.getFormattedString("enterToolbarIllegalChars", [name.value]);
continue;
}
var dupeFound = false;
// Check for an existing toolbar with the same display name
for (let 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, "", [null, null]);
toolboxChanged();
doneButton.disabled = false;
}
/**
* Restore the default set of buttons to fixed toolbars,
* remove all custom toolbars, and rebuild the palette.
*/
function restoreDefaultSet()
{
// Unwrap the items on the toolbar.
unwrapToolbarItems();
// Remove all of the customized toolbars.
var child = gToolbox.lastChild;
while (child) {
if (child.hasAttribute("customindex")) {
var thisChild = child;
child = child.previousSibling;
thisChild.currentSet = "__empty";
gToolbox.removeChild(thisChild);
} else {
child = child.previousSibling;
}
}
// Restore the defaultset for fixed toolbars.
forEachCustomizableToolbar(function (toolbar) {
var defaultSet = toolbar.getAttribute("defaultset");
if (defaultSet)
toolbar.currentSet = defaultSet;
});
// Now rebuild the palette.
buildPalette();
// Now re-wrap the items on the toolbar.
wrapToolbarItems();
toolboxChanged("reset");
}
function updateToolboxProperty(aProp, aValue, aToolkitDefault) {
var toolboxDefault = gToolbox.getAttribute("default" + aProp) ||
aToolkitDefault;
gToolbox.setAttribute(aProp, aValue || toolboxDefault);
gToolboxDocument.persist(gToolbox.id, aProp);
forEachCustomizableToolbar(function (toolbar) {
var toolbarDefault = toolbar.getAttribute("default" + aProp) ||
toolboxDefault;
if (toolbar.getAttribute("lock" + aProp) == "true" &&
toolbar.getAttribute(aProp) == toolbarDefault)
return;
toolbar.setAttribute(aProp, aValue || toolbarDefault);
gToolboxDocument.persist(toolbar.id, aProp);
});
toolboxChanged(aProp);
return aValue || toolboxDefault;
}
function forEachCustomizableToolbar(callback) {
Array.filter(gToolbox.childNodes, isCustomizableToolbar).forEach(callback);
Array.filter(gToolbox.externalToolbars, isCustomizableToolbar).forEach(callback);
}
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 onToolbarDragExit(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
if (gCurrentDragOverItem)
setDragActive(gCurrentDragOverItem, false);
}
function onToolbarDragStart(aEvent)
{
var item = aEvent.target;
while (item && item.localName != "toolbarpaletteitem") {
if (item.localName == "toolbar")
return;
item = item.parentNode;
}
item.setAttribute("dragactive", "true");
var dt = aEvent.dataTransfer;
var documentId = gToolboxDocument.documentElement.id;
dt.setData("text/toolbarwrapper-id/" + documentId, item.firstChild.id);
dt.effectAllowed = "move";
}
function onToolbarDragOver(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
var documentId = gToolboxDocument.documentElement.id;
if (!aEvent.dataTransfer.types.includes("text/toolbarwrapper-id/" + documentId.toLowerCase()))
return;
var toolbar = aEvent.target;
var dropTarget = aEvent.target;
while (toolbar && toolbar.localName != "toolbar") {
dropTarget = toolbar;
toolbar = toolbar.parentNode;
}
// Make sure we are dragging over a customizable toolbar.
if (!toolbar || !isCustomizableToolbar(toolbar)) {
gCurrentDragOverItem = null;
return;
}
var previousDragItem = gCurrentDragOverItem;
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);
var dragAfter;
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);
aEvent.preventDefault();
aEvent.stopPropagation();
}
function onToolbarDrop(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
if (!gCurrentDragOverItem)
return;
setDragActive(gCurrentDragOverItem, false);
var documentId = gToolboxDocument.documentElement.id;
var draggedItemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
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.
let wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId);
if (wrapper == gCurrentDragOverItem)
return;
// Don't allow non-removable kids (e.g., the menubar) to move.
if (wrapper.firstChild.getAttribute("removable") != "true")
return;
// Remove the item from its 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.
let wrapper = createWrapper("", gToolboxDocument);
// 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.
if (draggedItemId != "separator" &&
draggedItemId != "spring" &&
draggedItemId != "spacer")
gPaletteBox.removeChild(draggedPaletteWrapper);
}
gCurrentDragOverItem = null;
toolboxChanged();
}
function onPaletteDragOver(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
var documentId = gToolboxDocument.documentElement.id;
if (aEvent.dataTransfer.types.includes("text/toolbarwrapper-id/" + documentId.toLowerCase()))
aEvent.preventDefault();
}
function onPaletteDrop(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
var documentId = gToolboxDocument.documentElement.id;
var itemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId);
if (wrapper) {
// Don't allow non-removable kids (e.g., the menubar) to move.
if (wrapper.firstChild.getAttribute("removable") != "true")
return;
var wrapperType = wrapper.getAttribute("type");
if (wrapperType != "separator" &&
wrapperType != "spacer" &&
wrapperType != "spring") {
restoreItemForToolbar(wrapper.firstChild, wrapper);
wrapPaletteItem(document.importNode(wrapper.firstChild, true));
gToolbox.palette.appendChild(wrapper.firstChild);
}
// The item was dragged out of the toolbar.
wrapper.parentNode.removeChild(wrapper);
}
toolboxChanged();
}
function isUnwantedDragEvent(aEvent) {
try {
if (Services.prefs.getBoolPref("toolkit.customization.unsafe_drag_events")) {
return false;
}
} catch (ex) {}
/* Discard drag events that originated from a separate window to
prevent content->chrome privilege escalations. */
let mozSourceNode = aEvent.dataTransfer.mozSourceNode;
// mozSourceNode is null in the dragStart event handler or if
// the drag event originated in an external application.
if (!mozSourceNode) {
return true;
}
let sourceWindow = mozSourceNode.ownerDocument.defaultView;
return sourceWindow != window && sourceWindow != gToolboxDocument.defaultView;
}

64
navigator/components/toolbar/content/customizeToolbar.xul

@ -0,0 +1,64 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE dialog [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % customizeToolbarDTD SYSTEM "chrome://navigator/locale/toolbar/customizeToolbar.dtd">
%customizeToolbarDTD;
]>
<?xml-stylesheet href="chrome://communicator/skin" type="text/css"?>
<?xml-stylesheet href="chrome://navigator/content/toolbar/customizeToolbar.css" type="text/css"?>
<window id="CustomizeToolbarWindow"
title="&dialog.title;"
onload="onLoad();"
onunload="onUnload();"
style="&dialog.dimensions;"
persist="width height"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://navigator/content/toolbar/customizeToolbar.js"/>
<stringbundle id="stringBundle" src="chrome://navigator/locale/toolbar/customizeToolbar.properties"/>
<keyset id="CustomizeToolbarKeyset">
<key id="cmd_close1" keycode="VK_ESCAPE" oncommand="onClose();"/>
<key id="cmd_close2" keycode="VK_RETURN" oncommand="onClose();"/>
</keyset>
<dialogheader class="header-large"
id="header"
style="margin-top: 0px; margin-left: 0px;"
title="&brandFullName;"
description="&header.description;"/>
<vbox id="main-box" flex="1">
<vbox flex="1" id="palette-box"
ondragstart="onToolbarDragStart(event)"
ondragover="onPaletteDragOver(event)"
ondrop="onPaletteDrop(event)"/>
<box align="left">
<button id="newtoolbar" label="&addNewToolbar.label;" oncommand="addNewToolbar();" icon="add"/>
<button id="restoreDefault" label="&restoreDefaultSet.label;" oncommand="restoreDefaultSet();" icon="revert"/>
</box>
</vbox>
<separator class="groove"/>
<hbox align="end">
<hbox class="actionButtons" align="right" flex="1">
<button id="donebutton"
label="&saveChanges.label;"
oncommand="onClose();"
default="true"
icon="close"/>
</hbox>
<resizer type="window" dir="bottomend"/>
</hbox>
</window>

13
navigator/components/toolbar/jar.mn

@ -0,0 +1,13 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
navigator.jar:
% override chrome://global/content/customizeToolbar.xul chrome://navigator/content/toolbar/customizeToolbar.xul
content/navigator/toolbar/customizeToolbar.css (content/customizeToolbar.css)
* content/navigator/toolbar/customizeToolbar.js (content/customizeToolbar.js)
content/navigator/toolbar/customizeToolbar.xul (content/customizeToolbar.xul)
en-US.jar:
locale/en-US/navigator/toolbar/customizeToolbar.dtd (locale/customizeToolbar.dtd)
locale/en-US/navigator/toolbar/customizeToolbar.properties (locale/customizeToolbar.properties)

10
navigator/components/toolbar/locale/customizeToolbar.dtd

@ -0,0 +1,10 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY dialog.title "Customize Toolbars">
<!ENTITY dialog.dimensions "width: 92ch; height: 36em;">
<!ENTITY header.description "Add or Remove Toolbar Items by Dragging and Dropping">
<!ENTITY restoreDefaultSet.label "Restore Default Set">
<!ENTITY addNewToolbar.label "Add New Toolbar">
<!ENTITY saveChanges.label "Done">

12
navigator/components/toolbar/locale/customizeToolbar.properties

@ -0,0 +1,12 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
enterToolbarTitle=New Toolbar
enterToolbarName=Enter a name for this toolbar:
enterToolbarDup=There is already a toolbar with the name “%S”. Please enter a different name.
enterToolbarIllegalChars=The name contains illegal character "|". Please enter a different name.
enterToolbarBlank=You must enter a name to create a new toolbar.
separatorTitle=Separator
springTitle=Flexible Space
spacerTitle=Space

6
navigator/components/toolbar/moz.build

@ -0,0 +1,6 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JAR_MANIFESTS += ['jar.mn']
Loading…
Cancel
Save