Merge mozilla-central to services-central.

This commit is contained in:
Richard Newman 2011-08-22 08:03:23 -07:00
commit 697a053b1c
796 changed files with 17973 additions and 19722 deletions

View File

@ -203,6 +203,21 @@ codesighs:
# defined in package-name.mk
export MOZ_SOURCE_STAMP
#XXX: this is a hack, since we don't want to clobber for MSVC
# PGO support, but we can't do this test in client.mk
ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
# No point in clobbering if PGO has been explicitly disabled.
ifndef NO_PROFILE_GUIDED_OPTIMIZE
maybe_clobber_profiledbuild: clean
else
maybe_clobber_profiledbuild:
endif
else
maybe_clobber_profiledbuild:
endif
.PHONY: maybe_clobber_profiledbuild
# Look for R_386_PC32 relocations in shared libs, these
# break x86_64 builds and SELinux users.
ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)

View File

@ -881,7 +881,7 @@ pref("browser.privatebrowsing.dont_prompt_on_enter", false);
pref("browser.bookmarks.editDialog.firstEditField", "namePicker");
// base url for the wifi geolocation network provider
pref("geo.wifi.uri", "https://www.google.com/loc/json");
pref("geo.wifi.uri", "https://maps.googleapis.com/maps/api/browserlocation/json");
pref("geo.wifi.protocol", 0);
// Whether to use a panel that looks like an OS X sheet for customization

View File

@ -1631,7 +1631,7 @@ BaseTemplates.AttrTag =
" ",
domplate.SPAN({"class": "nodeName editable"}, "$attr.nodeName"),
"="",
domplate.SPAN({"class": "nodeValue editable"}, "$attr.nodeValue"),
domplate.SPAN({"class": "nodeValue editable", "data-attributeName": "$attr.nodeName"}, "$attr.nodeValue"),
""");
BaseTemplates.TextTag =

View File

@ -7,5 +7,8 @@
<link rel="stylesheet" href="chrome://browser/skin/inspector.css" type="text/css"/>
</head>
<body role="application">
<div id="attribute-editor">
<input id="attribute-editor-input" />
</div>
</body>
</html>

View File

@ -26,6 +26,7 @@
* Mihai Șucan <mihai.sucan@gmail.com>
* Julian Viereck <jviereck@mozilla.com>
* Paul Rouget <paul@mozilla.com>
* Kyle Simpson <ksimpson@mozilla.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
@ -70,6 +71,11 @@ const INSPECTOR_NOTIFICATIONS = {
// Fires once the Inspector is closed.
CLOSED: "inspector-closed",
// Event notifications for the attribute-value editor
EDITOR_OPENED: "inspector-editor-opened",
EDITOR_CLOSED: "inspector-editor-closed",
EDITOR_SAVED: "inspector-editor-saved",
};
///////////////////////////////////////////////////////////////////////////
@ -591,6 +597,8 @@ var InspectorUI = {
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
this.ioBox.createObjectBox(this.win.document.documentElement);
this.treeLoaded = true;
this.editingContext = null;
this.editingEvents = {};
// initialize the highlighter
this.initializeHighlighter();
@ -614,6 +622,7 @@ var InspectorUI = {
this.treeIFrame.setAttribute("flex", "1");
this.treeIFrame.setAttribute("type", "content");
this.treeIFrame.setAttribute("onclick", "InspectorUI.onTreeClick(event)");
this.treeIFrame.setAttribute("ondblclick", "InspectorUI.onTreeDblClick(event);");
this.treeIFrame = this.treePanel.insertBefore(this.treeIFrame, resizerBox);
}
@ -817,6 +826,11 @@ var InspectorUI = {
*/
closeInspectorUI: function IUI_closeInspectorUI(aKeepStore)
{
// if currently editing an attribute value, closing the
// highlighter/HTML panel dismisses the editor
if (this.editingContext)
this.closeEditor();
if (this.closing || !this.win || !this.browser) {
return;
}
@ -854,8 +868,11 @@ var InspectorUI = {
delete this.treeBrowserDocument;
}
if (this.treeIFrame)
if (this.treeIFrame) {
let parent = this.treeIFrame.parentNode;
parent.removeChild(this.treeIFrame);
delete this.treeIFrame;
}
delete this.ioBox;
if (this.domplate) {
@ -879,6 +896,8 @@ var InspectorUI = {
this.treeLoaded = false;
this.treePanel.addEventListener("popuphidden", function treePanelHidden() {
this.removeEventListener("popuphidden", treePanelHidden, false);
InspectorUI.closing = false;
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
}, false);
@ -893,6 +912,11 @@ var InspectorUI = {
*/
startInspecting: function IUI_startInspecting()
{
// if currently editing an attribute value, starting
// "live inspection" mode closes the editor
if (this.editingContext)
this.closeEditor();
document.getElementById("inspector-inspect-toolbutton").checked = true;
this.attachPageListeners();
this.inspecting = true;
@ -933,6 +957,11 @@ var InspectorUI = {
*/
select: function IUI_select(aNode, forceUpdate, aScroll)
{
// if currently editing an attribute value, using the
// highlighter dismisses the editor
if (this.editingContext)
this.closeEditor();
if (!aNode)
aNode = this.defaultSelection;
@ -1044,6 +1073,17 @@ var InspectorUI = {
*/
onTreeClick: function IUI_onTreeClick(aEvent)
{
// if currently editing an attribute value, clicking outside
// the editor dismisses the editor
if (this.editingContext) {
this.closeEditor();
// clicking outside the editor ONLY closes the editor
// so, cancel the rest of the processing of this event
aEvent.preventDefault();
return;
}
let node;
let target = aEvent.target;
let hitTwisty = false;
@ -1068,6 +1108,220 @@ var InspectorUI = {
}
},
/**
* Handle double-click events in the html tree panel.
* (double-clicking an attribute value allows it to be edited)
* @param aEvent
* The mouse event.
*/
onTreeDblClick: function IUI_onTreeDblClick(aEvent)
{
// if already editing an attribute value, double-clicking elsewhere
// in the tree is the same as a click, which dismisses the editor
if (this.editingContext)
this.closeEditor();
let target = aEvent.target;
if (this.hasClass(target, "nodeValue")) {
let repObj = this.getRepObject(target);
let attrName = target.getAttribute("data-attributeName");
let attrVal = target.innerHTML;
this.editAttributeValue(target, repObj, attrName, attrVal);
}
},
/**
* Starts the editor for an attribute value.
* @param aAttrObj
* The DOM object representing the attribute value in the HTML Tree
* @param aRepObj
* The original DOM (target) object being inspected/edited
* @param aAttrName
* The name of the attribute being edited
* @param aAttrVal
* The current value of the attribute being edited
*/
editAttributeValue:
function IUI_editAttributeValue(aAttrObj, aRepObj, aAttrName, aAttrVal)
{
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
let attrDims = aAttrObj.getBoundingClientRect();
// figure out actual viewable viewport dimensions (sans scrollbars)
let viewportWidth = this.treeBrowserDocument.documentElement.clientWidth;
let viewportHeight = this.treeBrowserDocument.documentElement.clientHeight;
// saves the editing context for use when the editor is saved/closed
this.editingContext = {
attrObj: aAttrObj,
repObj: aRepObj,
attrName: aAttrName
};
// highlight attribute-value node in tree while editing
this.addClass(aAttrObj, "editingAttributeValue");
// show the editor
this.addClass(editor, "editing");
// offset the editor below the attribute-value node being edited
let editorVeritcalOffset = 2;
// keep the editor comfortably within the bounds of the viewport
let editorViewportBoundary = 5;
// outer editor is sized based on the <input> box inside it
editorInput.style.width = Math.min(attrDims.width, viewportWidth -
editorViewportBoundary) + "px";
editorInput.style.height = Math.min(attrDims.height, viewportHeight -
editorViewportBoundary) + "px";
let editorDims = editor.getBoundingClientRect();
// calculate position for the editor according to the attribute node
let editorLeft = attrDims.left + this.treeIFrame.contentWindow.scrollX -
// center the editor against the attribute value
((editorDims.width - attrDims.width) / 2);
let editorTop = attrDims.top + this.treeIFrame.contentWindow.scrollY +
attrDims.height + editorVeritcalOffset;
// but, make sure the editor stays within the visible viewport
editorLeft = Math.max(0, Math.min(
(this.treeIFrame.contentWindow.scrollX +
viewportWidth - editorDims.width),
editorLeft)
);
editorTop = Math.max(0, Math.min(
(this.treeIFrame.contentWindow.scrollY +
viewportHeight - editorDims.height),
editorTop)
);
// position the editor
editor.style.left = editorLeft + "px";
editor.style.top = editorTop + "px";
// set and select the text
editorInput.value = aAttrVal;
editorInput.select();
// listen for editor specific events
this.bindEditorEvent(editor, "click", function(aEvent) {
aEvent.stopPropagation();
});
this.bindEditorEvent(editor, "dblclick", function(aEvent) {
aEvent.stopPropagation();
});
this.bindEditorEvent(editor, "keypress",
this.handleEditorKeypress.bind(this));
// event notification
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED,
null);
},
/**
* Handle binding an event handler for the editor.
* (saves the callback for easier unbinding later)
* @param aEditor
* The DOM object for the editor
* @param aEventName
* The name of the event to listen for
* @param aEventCallback
* The callback to bind to the event (and also to save for later
* unbinding)
*/
bindEditorEvent:
function IUI_bindEditorEvent(aEditor, aEventName, aEventCallback)
{
this.editingEvents[aEventName] = aEventCallback;
aEditor.addEventListener(aEventName, aEventCallback, false);
},
/**
* Handle unbinding an event handler from the editor.
* (unbinds the previously bound and saved callback)
* @param aEditor
* The DOM object for the editor
* @param aEventName
* The name of the event being listened for
*/
unbindEditorEvent: function IUI_unbindEditorEvent(aEditor, aEventName)
{
aEditor.removeEventListener(aEventName, this.editingEvents[aEventName],
false);
this.editingEvents[aEventName] = null;
},
/**
* Handle keypress events in the editor.
* @param aEvent
* The keyboard event.
*/
handleEditorKeypress: function IUI_handleEditorKeypress(aEvent)
{
if (aEvent.which == KeyEvent.DOM_VK_RETURN) {
this.saveEditor();
} else if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) {
this.closeEditor();
}
},
/**
* Close the editor and cleanup.
*/
closeEditor: function IUI_closeEditor()
{
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
// remove highlight from attribute-value node in tree
this.removeClass(this.editingContext.attrObj, "editingAttributeValue");
// hide editor
this.removeClass(editor, "editing");
// stop listening for editor specific events
this.unbindEditorEvent(editor, "click");
this.unbindEditorEvent(editor, "dblclick");
this.unbindEditorEvent(editor, "keypress");
// clean up after the editor
editorInput.value = "";
editorInput.blur();
this.editingContext = null;
this.editingEvents = {};
// event notification
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
null);
},
/**
* Commit the edits made in the editor, then close it.
*/
saveEditor: function IUI_saveEditor()
{
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
// set the new attribute value on the original target DOM element
this.editingContext.repObj.setAttribute(this.editingContext.attrName,
editorInput.value);
// update the HTML tree attribute value
this.editingContext.attrObj.innerHTML = editorInput.value;
// event notification
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
null);
this.closeEditor();
},
/**
* Attach event listeners to content window and child windows to enable
* highlighting and click to stop inspection.

View File

@ -79,7 +79,8 @@ nsContextMenu.prototype = {
this.hasPageMenu = false;
if (!aIsShift) {
this.hasPageMenu = PageMenu.init(this.target, aXulMenu);
this.hasPageMenu = PageMenu.maybeBuildAndAttachMenu(this.target,
aXulMenu);
}
this.isFrameImage = document.getElementById("isFrameImage");

View File

@ -0,0 +1,46 @@
/* ***** 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 content.js.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Tim Taubert <ttaubert@mozilla.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 ***** */
addEventListener("DOMWillOpenModalDialog", function (event) {
// (event.isTrusted == true) when the event is generated by a user action
// and does not originate from a script.
if (event.isTrusted) {
// we're intentionally sending a synchronous message to handle this event
// as quick as possible, switch the selected tab and hide the tabview
// before the modal dialog is shown
sendSyncMessage("Panorama:DOMWillOpenModalDialog");
}
}, true);

View File

@ -231,7 +231,7 @@ function GroupItem(listOfEls, options) {
.appendTo(appTabTrayContainer);
AllTabs.tabs.forEach(function(xulTab) {
if (xulTab.pinned && xulTab.ownerDocument.defaultView == gWindow)
if (xulTab.pinned)
self.addAppTab(xulTab, {dontAdjustTray: true});
});
@ -744,9 +744,13 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// ----------
// Function: _unhide
// Shows the hidden group.
_unhide: function GroupItem__unhide() {
let self = this;
//
// Parameters:
// options - various options (see below)
//
// Possible options:
// immediately - true when no animations should be used
_unhide: function GroupItem__unhide(options) {
this._cancelFadeAwayUndoButtonTimer();
this.hidden = false;
this.$undoContainer.remove();
@ -754,20 +758,31 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.droppable(true);
this.setTrenches(this.bounds);
iQ(this.container).show().animate({
"-moz-transform": "scale(1)",
"opacity": 1
}, {
duration: 170,
complete: function() {
self._children.forEach(function(child) {
iQ(child.container).show();
});
let self = this;
UI.setActive(self);
self._sendToSubscribers("groupShown", { groupItemId: self.id });
}
});
let finalize = function () {
self._children.forEach(function(child) {
iQ(child.container).show();
});
UI.setActive(self);
self._sendToSubscribers("groupShown", { groupItemId: self.id });
};
let $container = iQ(this.container).show();
if (!options || !options.immediately) {
$container.animate({
"-moz-transform": "scale(1)",
"opacity": 1
}, {
duration: 170,
complete: finalize
});
} else {
$container.css({"-moz-transform": "none", opacity: 1});
finalize();
}
GroupItems.updateGroupCloseButtons();
},
@ -785,15 +800,29 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let remainingGroups = GroupItems.groupItems.filter(function (groupItem) {
return (groupItem != self && groupItem.getChildren().length);
});
let tab = null;
if (!gBrowser._numPinnedTabs && !remainingGroups.length) {
let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
return (groupItem != self && !groupItem.getChildren().length);
});
let group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
group.newTab(null, { closedLastTab: true });
tab = group.newTab(null, {dontZoomIn: true});
}
this.destroy();
let closed = this.destroy();
if (!tab)
return;
if (closed) {
// Let's make the new tab the selected tab.
UI.goToTab(tab);
} else {
// Remove the new tab and group, if this group is no longer closed.
tab._tabViewTabItem.parent.destroy({immediately: true});
}
},
// ----------
@ -806,6 +835,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
//
// Options:
// immediately - (bool) if true, no animation will be used
//
// Returns true if the groupItem has been closed, or false otherwise. A group
// could not have been closed due to a tab with an onUnload handler (that
// waits for user interaction).
destroy: function GroupItem_destroy(options) {
let self = this;
@ -814,14 +847,11 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// In other words, the group "close" event is fired before all browser
// tabs in the group are closed. The below code would fire the group "close"
// event only after all browser tabs in that group are closed.
let shouldRemoveTabItems = [];
let toClose = this._children.concat();
toClose.forEach(function(child) {
this._children.concat().forEach(function(child) {
child.removeSubscriber("close", self._onChildClose);
let removed = child.close(true);
if (removed) {
shouldRemoveTabItems.push(child);
if (child.close(true)) {
self.remove(child, { dontArrange: true });
} else {
// child.removeSubscriber() must be called before child.close(),
// therefore we call child.addSubscriber() if the tab is not removed.
@ -829,15 +859,14 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
}
});
if (shouldRemoveTabItems.length != toClose.length) {
// remove children without the assiciated tab and show the group item
shouldRemoveTabItems.forEach(function(child) {
self.remove(child, { dontArrange: true });
});
if (this._children.length) {
if (this.hidden)
this.$undoContainer.fadeOut(function() { self._unhide() });
this.$undoContainer.fadeOut(function() { self._unhide() });
return false;
} else {
this.close(options);
return true;
}
},
@ -1818,13 +1847,16 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Parameters:
// url - the new tab should open this url as well
// options - the options object
// dontZoomIn - set to true to not zoom into the newly created tab
// closedLastTab - boolean indicates the last tab has just been closed
newTab: function GroupItem_newTab(url, options) {
if (options && options.closedLastTab)
UI.closedLastTabInTabView = true;
UI.setActive(this, { dontSetActiveTabInGroup: true });
gBrowser.loadOneTab(url || "about:blank", { inBackground: false });
let dontZoomIn = !!(options && options.dontZoomIn);
return gBrowser.loadOneTab(url || "about:blank", { inBackground: dontZoomIn });
},
// ----------
@ -1926,13 +1958,13 @@ let GroupItems = {
let self = this;
// setup attr modified handler, and prepare for its uninit
function handleAttrModified(xulTab) {
self._handleAttrModified(xulTab);
function handleAttrModified(event) {
self._handleAttrModified(event.target);
}
// make sure any closed tabs are removed from the delay update list
function handleClose(xulTab) {
let idx = self._delayedModUpdates.indexOf(xulTab);
function handleClose(event) {
let idx = self._delayedModUpdates.indexOf(event.target);
if (idx != -1)
self._delayedModUpdates.splice(idx, 1);
}
@ -2040,7 +2072,7 @@ let GroupItems = {
// Function: _updateAppTabIcons
// Update images of any apptab icons that point to passed in xultab
_updateAppTabIcons: function GroupItems__updateAppTabIcons(xulTab) {
if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
if (!xulTab.pinned)
return;
let iconUrl = this.getAppTabFavIconUrl(xulTab);

View File

@ -1,183 +0,0 @@
/* ***** 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 TabView AllTabs.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Edward Lee <edilee@mozilla.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 ***** */
"use strict";
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
let EXPORTED_SYMBOLS = ["AllTabs"];
let AllTabs = {
// ----------
// Function: toString
// Prints [AllTabs] for debug use
toString: function AllTabs_toString() {
return "[AllTabs]";
},
/**
* Get an array of all tabs from all tabbrowser windows.
*
* @usage let numAllTabs = AllTabs.tabs.length;
* AllTabs.tabs.forEach(handleAllTabs);
*/
get tabs() {
// Get tabs from each browser window and flatten them into one array
return Array.concat.apply(null, browserWindows.map(function(browserWindow) {
return Array.filter(browserWindow.gBrowser.tabs, function (tab) !tab.closing);
}));
},
/**
* Attach a callback for a given tab event.
*
* @param eventName
* Name of the corresponding Tab* Event; one of "attrModified",
* "close", "move", "open", "select", "pinned", "unpinned".
* @param callback
* Callback that gets called with the tab as the first argument and
* the event as the second argument.
* @usage AllTabs.register("change", function handleChange(tab, event) {});
*/
register: function register(eventName, callback) {
// Either add additional callbacks or create the first entry
let listeners = eventListeners[events[eventName]];
if (listeners)
listeners.push(callback);
else
eventListeners[events[eventName]] = [callback];
},
/**
* Remove a callback for a given tab event.
*
* @param eventName
* Name of the corresponding Tab* Event; one of "attrModified",
* "close", "move", "open", "select", "pinned", "unpinned".
* @param callback
* The callback given for the original AllTabs.register call.
* @usage AllTabs.unregister("close", handleClose);
*/
unregister: function unregister(eventName, callback) {
// Nothing to remove for this event
let listeners = eventListeners[events[eventName]];
if (!listeners)
return;
// Can only remove a callback if we have it
let index = listeners.indexOf(callback);
if (index == -1)
return;
listeners.splice(index, 1);
}
};
__defineGetter__("browserWindows", function browserWindows() {
let browserWindows = [];
let windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements())
browserWindows.push(windows.getNext());
return browserWindows;
});
let events = {
attrModified: "TabAttrModified",
close: "TabClose",
move: "TabMove",
open: "TabOpen",
select: "TabSelect",
pinned: "TabPinned",
unpinned: "TabUnpinned"
};
let eventListeners = {};
function registerBrowserWindow(browserWindow) {
for each (let event in events)
browserWindow.addEventListener(event, tabEventListener, true);
browserWindow.addEventListener("unload", unregisterBrowserWindow, false);
}
function unregisterBrowserWindow(unloadEvent) {
let browserWindow = unloadEvent.currentTarget;
for each (let event in events)
browserWindow.removeEventListener(event, tabEventListener, true);
browserWindow.removeEventListener("unload", unregisterBrowserWindow, false);
}
function tabEventListener(event) {
// Make sure we've gotten listeners before trying to call
let listeners = eventListeners[event.type];
if (!listeners)
return;
let tab = event.target;
// Make a copy of the listeners, so it can't change as we call back
listeners.slice().forEach(function (callback) {
try {
callback(tab, event);
}
// Don't let failing callbacks stop us but report the failure
catch (ex) {
Cu.reportError(ex);
}
});
}
function observer(subject, topic, data) {
switch (topic) {
case "domwindowopened":
subject.addEventListener("load", function onLoad() {
subject.removeEventListener("load", onLoad, false);
// Now that the window has loaded, only register on browser windows
let doc = subject.document.documentElement;
if (doc.getAttribute("windowtype") == "navigator:browser")
registerBrowserWindow(subject);
}, false);
break;
}
}
// Register listeners on all browser windows and future ones
browserWindows.forEach(registerBrowserWindow);
Services.obs.addObserver(observer, "domwindowopened", false);

View File

@ -520,6 +520,9 @@ function createSearchTabMacher() {
}
function hideSearch(event) {
if (!isSearchEnabled())
return;
iQ("#searchbox").val("");
iQ("#searchshade").hide();
iQ("#search").hide();

View File

@ -79,9 +79,6 @@ let Storage = {
// ___ Tabs
AllTabs.tabs.forEach(function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
self.saveTab(tab, null);
});

View File

@ -478,29 +478,22 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// closing tab doesn't belong to a group and no empty group, create a new
// one for the new tab.
if (!groupClose && gBrowser.tabs.length == 1) {
let group;
if (this.tab._tabViewTabItem.parent) {
group = this.tab._tabViewTabItem.parent;
} else {
let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
return (!groupItem.getChildren().length);
});
group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
}
let group = this.tab._tabViewTabItem.parent;
group.newTab(null, { closedLastTab: true });
}
// when "TabClose" event is fired, the browser tab is about to close and our
// item "close" is fired before the browser tab actually get closed.
// Therefore, we need "tabRemoved" event below.
gBrowser.removeTab(this.tab);
let tabNotClosed =
Array.some(gBrowser.tabs, function(tab) { return tab == this.tab; }, this);
if (!tabNotClosed)
let tabClosed = !this.tab;
if (tabClosed)
this._sendToSubscribers("tabRemoved");
// No need to explicitly delete the tab data, becasue sessionstore data
// associated with the tab will automatically go away
return !tabNotClosed;
return tabClosed;
},
// ----------
@ -746,27 +739,26 @@ let TabItems = {
this.tempCanvas.height = 112;
// When a tab is opened, create the TabItem
this._eventListeners["open"] = function(tab) {
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
return;
this._eventListeners.open = function (event) {
let tab = event.target;
self.link(tab);
if (!tab.pinned)
self.link(tab);
}
// When a tab's content is loaded, show the canvas and hide the cached data
// if necessary.
this._eventListeners["attrModified"] = function(tab) {
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
return;
this._eventListeners.attrModified = function (event) {
let tab = event.target;
self.update(tab);
if (!tab.pinned)
self.update(tab);
}
// When a tab is closed, unlink.
this._eventListeners["close"] = function(tab) {
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
return;
this._eventListeners.close = function (event) {
let tab = event.target;
// XXX bug #635975 - don't unlink the tab if the dom window is closing.
if (!UI.isDOMWindowClosing)
if (!tab.pinned && !UI.isDOMWindowClosing)
self.unlink(tab);
}
for (let name in this._eventListeners) {
@ -774,8 +766,8 @@ let TabItems = {
}
// For each tab, create the link.
AllTabs.tabs.forEach(function(tab) {
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
AllTabs.tabs.forEach(function (tab) {
if (tab.pinned)
return;
self.link(tab, {immediately: true});

View File

@ -5,7 +5,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource:///modules/tabview/AllTabs.jsm");
Cu.import("resource:///modules/tabview/utils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -44,6 +43,30 @@ var gTabViewDeck = gWindow.document.getElementById("tab-view-deck");
var gBrowserPanel = gWindow.document.getElementById("browser-panel");
var gTabViewFrame = gWindow.document.getElementById("tab-view");
let AllTabs = {
_events: {
attrModified: "TabAttrModified",
close: "TabClose",
move: "TabMove",
open: "TabOpen",
select: "TabSelect",
pinned: "TabPinned",
unpinned: "TabUnpinned"
},
get tabs() {
return Array.filter(gBrowser.tabs, function (tab) !tab.closing);
},
register: function AllTabs_register(eventName, callback) {
gBrowser.tabContainer.addEventListener(this._events[eventName], callback, false);
},
unregister: function AllTabs_unregister(eventName, callback) {
gBrowser.tabContainer.removeEventListener(this._events[eventName], callback, false);
}
};
# NB: Certain files need to evaluate before others
#include iq.js

View File

@ -26,6 +26,7 @@
* Raymond Lee <raymond@appcoast.com>
* Sean Dunn <seanedunn@yahoo.com>
* Tim Taubert <tim.taubert@gmx.de>
* Mihai Sucan <mihai.sucan@gmail.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
@ -80,6 +81,10 @@ let UI = {
// If true, a closed tab has just been restored.
restoredClosedTab: false,
// Variable: _isChangingVisibility
// Tracks whether we're currently in the process of showing/hiding the tabview.
_isChangingVisibility: false,
// Variable: _reorderTabItemsOnShow
// Keeps track of the <GroupItem>s which their tab items' tabs have been moved
// and re-orders the tab items when switching to TabView.
@ -234,6 +239,15 @@ let UI = {
self.uninit();
});
// ___ setup DOMWillOpenModalDialog message handler
let mm = gWindow.messageManager;
let callback = this._onDOMWillOpenModalDialog.bind(this);
mm.addMessageListener("Panorama:DOMWillOpenModalDialog", callback);
this._cleanupFunctions.push(function () {
mm.removeMessageListener("Panorama:DOMWillOpenModalDialog", callback);
});
// ___ setup key handlers
this._setTabViewFrameKeyHandlers();
@ -276,6 +290,10 @@ let UI = {
self._save();
}, false);
// ___ load frame script
let frameScript = "chrome://browser/content/tabview-content.js";
gWindow.messageManager.loadFrameScript(frameScript, true);
// ___ Done
this._frameInitialized = true;
this._save();
@ -481,9 +499,11 @@ let UI = {
// Parameters:
// zoomOut - true for zoom out animation, false for nothing.
showTabView: function UI_showTabView(zoomOut) {
if (this.isTabViewVisible())
if (this.isTabViewVisible() || this._isChangingVisibility)
return;
this._isChangingVisibility = true;
// initialize the direction of the page
this._initPageDirection();
@ -526,6 +546,7 @@ let UI = {
self.setActive(item);
self._resize(true);
self._isChangingVisibility = false;
dispatchEvent(event);
// Flush pending updates
@ -535,6 +556,7 @@ let UI = {
});
} else {
self.clearActiveTab();
self._isChangingVisibility = false;
dispatchEvent(event);
// Flush pending updates
@ -551,9 +573,11 @@ let UI = {
// Function: hideTabView
// Hides TabView and shows the main browser UI.
hideTabView: function UI_hideTabView() {
if (!this.isTabViewVisible())
if (!this.isTabViewVisible() || this._isChangingVisibility)
return;
this._isChangingVisibility = true;
// another tab might be select if user decides to stay on a page when
// a onclose confirmation prompts.
GroupItems.removeHiddenGroups();
@ -580,6 +604,8 @@ let UI = {
#endif
Storage.saveVisibilityData(gWindow, "false");
this._isChangingVisibility = false;
let event = document.createEvent("Events");
event.initEvent("tabviewhidden", true, false);
dispatchEvent(event);
@ -685,6 +711,7 @@ let UI = {
}
} else if (topic == "private-browsing-change-granted") {
if (data == "enter" || data == "exit") {
hideSearch();
self._privateBrowsing.transitionMode = data;
self.storageBusy();
}
@ -710,9 +737,8 @@ let UI = {
});
// TabOpen
this._eventListeners.open = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
this._eventListeners.open = function (event) {
let tab = event.target;
// if it's an app tab, add it to all the group items
if (tab.pinned)
@ -722,9 +748,8 @@ let UI = {
};
// TabClose
this._eventListeners.close = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
this._eventListeners.close = function (event) {
let tab = event.target;
// if it's an app tab, remove it from all the group items
if (tab.pinned)
@ -756,21 +781,14 @@ let UI = {
groupItem._children.length == 1 &&
groupItem._children[0].tab == tab);
// 2) Take care of the case where you've closed the last tab in
// an un-named groupItem, which means that the groupItem is gone (null) and
// there are no visible tabs.
let closingUnnamedGroup = (groupItem == null &&
gBrowser.visibleTabs.length <= 1);
// 3) When a blank tab is active while restoring a closed tab the
// 2) When a blank tab is active while restoring a closed tab the
// blank tab gets removed. The active group is not closed as this is
// where the restored tab goes. So do not show the TabView.
let tabItem = tab && tab._tabViewTabItem;
let closingBlankTabAfterRestore =
(tabItem && tabItem.isRemovedAfterRestore);
if ((closingLastOfGroup || closingUnnamedGroup) &&
!closingBlankTabAfterRestore) {
if (closingLastOfGroup && !closingBlankTabAfterRestore) {
// for the tab focus event to pick up.
self._closedLastVisibleTab = true;
self.showTabView();
@ -780,9 +798,8 @@ let UI = {
};
// TabMove
this._eventListeners.move = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
this._eventListeners.move = function (event) {
let tab = event.target;
if (GroupItems.groupItems.length > 0) {
if (tab.pinned) {
@ -797,26 +814,21 @@ let UI = {
};
// TabSelect
this._eventListeners.select = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
self.onTabSelect(tab);
this._eventListeners.select = function (event) {
self.onTabSelect(event.target);
};
// TabPinned
this._eventListeners.pinned = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
this._eventListeners.pinned = function (event) {
let tab = event.target;
TabItems.handleTabPin(tab);
GroupItems.addAppTab(tab);
};
// TabUnpinned
this._eventListeners.unpinned = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
this._eventListeners.unpinned = function (event) {
let tab = event.target;
TabItems.handleTabUnpin(tab);
GroupItems.removeAppTab(tab);
@ -890,8 +902,14 @@ let UI = {
// if TabView is visible but we didn't just close the last tab or
// selected tab, show chrome.
if (this.isTabViewVisible())
if (this.isTabViewVisible()) {
// Unhide the group of the tab the user is activating.
if (tab && tab._tabViewTabItem && tab._tabViewTabItem.parent &&
tab._tabViewTabItem.parent.hidden)
tab._tabViewTabItem.parent._unhide({immediately: true});
this.hideTabView();
}
// another tab might be selected when hideTabView() is invoked so a
// validation is needed.
@ -925,6 +943,27 @@ let UI = {
}
},
// ----------
// Function: _onDOMWillOpenModalDialog
// Called when a web page is about to show a modal dialog.
_onDOMWillOpenModalDialog: function UI__onDOMWillOpenModalDialog(cx) {
if (!this.isTabViewVisible())
return;
let index = gBrowser.browsers.indexOf(cx.target);
if (index == -1)
return;
let tab = gBrowser.tabs[index];
// When TabView is visible, we need to call onTabSelect to make sure that
// TabView is hidden and that the correct group is activated. When a modal
// dialog is shown for currently selected tab the onTabSelect event handler
// is not called, so we need to do it.
if (gBrowser.selectedTab == tab && this._currentTab == tab)
this.onTabSelect(tab);
},
// ----------
// Function: setReorderTabsOnHide
// Sets the groupItem which the tab items' tabs should be re-ordered when

View File

@ -177,6 +177,7 @@ _BROWSER_FILES = \
browser_bug647886.js \
browser_bug655584.js \
browser_bug664672.js \
browser_canonizeURL.js \
browser_findbarClose.js \
browser_keywordBookmarklets.js \
browser_contextSearchTabPosition.js \

View File

@ -0,0 +1,54 @@
function test() {
waitForExplicitFinish();
testNext();
}
var pairs = [
["example", "http://www.example.net/"],
["ex-ample", "http://www.ex-ample.net/"],
[" example ", "http://www.example.net/"],
[" example/foo ", "http://www.example.net/foo"],
[" example/foo bar ", "http://www.example.net/foo%20bar"],
["example.net", "http://example.net/"],
["http://example", "http://example/"],
["example:8080", "http://example:8080/"],
["ex-ample.foo", "http://ex-ample.foo/"],
["example.foo/bar ", "http://example.foo/bar"],
["1.1.1.1", "http://1.1.1.1/"],
["ftp://example", "ftp://example/"],
["ftp.example.bar", "ftp://ftp.example.bar/"],
["ex ample", Services.search.originalDefaultEngine.getSubmission("ex ample").uri.spec],
];
function testNext() {
if (!pairs.length) {
finish();
return;
}
let [inputValue, expectedURL] = pairs.shift();
gBrowser.addProgressListener({
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
is(aRequest.originalURI.spec, expectedURL,
"entering '" + inputValue + "' loads expected URL");
gBrowser.removeProgressListener(this);
gBrowser.stop();
executeSoon(testNext);
}
}
});
gURLBar.addEventListener("focus", function onFocus() {
gURLBar.removeEventListener("focus", onFocus);
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
});
gBrowser.selectedBrowser.focus();
gURLBar.inputField.value = inputValue;
gURLBar.focus();
}

View File

@ -56,6 +56,7 @@ _BROWSER_FILES = \
browser_inspector_treePanel_result.html \
browser_inspector_registertools.js \
browser_inspector_bug_665880.js \
browser_inspector_editor.js \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -0,0 +1,233 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com>
* Mihai Sucan <mihai.sucan@gmail.com>
* Kyle Simpson <ksimpson@mozilla.com>
*
* ***** END LICENSE BLOCK ***** */
let doc;
let div;
let editorTestSteps;
function doNextStep() {
editorTestSteps.next();
}
function setupEditorTests()
{
div = doc.createElement("div");
div.setAttribute("id", "foobar");
div.setAttribute("class", "barbaz");
doc.body.appendChild(div);
Services.obs.addObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runEditorTests()
{
Services.obs.removeObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.stopInspecting();
// setup generator for async test steps
editorTestSteps = doEditorTestSteps();
// add step listeners
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
// start the tests
doNextStep();
}
function doEditorTestSteps()
{
let editor = InspectorUI.treeBrowserDocument.getElementById("attribute-editor");
let editorInput = InspectorUI.treeBrowserDocument.getElementById("attribute-editor-input");
// Step 1: grab and test the attribute-value nodes in the HTML panel, then open editor
let attrValNode_id = InspectorUI.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='id']")[0];
let attrValNode_class = InspectorUI.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='class']")[0];
is(attrValNode_id.innerHTML, "foobar", "Step 1: we have the correct `id` attribute-value node in the HTML panel");
is(attrValNode_class.innerHTML, "barbaz", "we have the correct `class` attribute-value node in the HTML panel");
// double-click the `id` attribute-value node to open the editor
executeSoon(function() {
// firing 2 clicks right in a row to simulate a double-click
EventUtils.synthesizeMouse(attrValNode_id, 2, 2, {clickCount: 2}, attrValNode_id.ownerDocument.defaultView);
});
yield; // End of Step 1
// Step 2: validate editing session, enter new attribute value into editor, and save input
ok(InspectorUI.editingContext, "Step 2: editor session started");
let editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible");
// check if the editor popup is "near" the correct position
let editorDims = editor.getBoundingClientRect();
let attrValNodeDims = attrValNode_id.getBoundingClientRect();
let editorPositionOK = (editorDims.left >= (attrValNodeDims.left - editorDims.width - 5)) &&
(editorDims.right <= (attrValNodeDims.right + editorDims.width + 5)) &&
(editorDims.top >= (attrValNodeDims.top - editorDims.height - 5)) &&
(editorDims.bottom <= (attrValNodeDims.bottom + editorDims.height + 5));
ok(editorPositionOK, "editor position acceptable");
// check to make sure the attribute-value node being edited is properly highlighted
let attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
ok(attrValNodeHighlighted, "`id` attribute-value node is editor-highlighted");
is(InspectorUI.editingContext.repObj, div, "editor session has correct reference to div");
is(InspectorUI.editingContext.attrObj, attrValNode_id, "editor session has correct reference to `id` attribute-value node in HTML panel");
is(InspectorUI.editingContext.attrName, "id", "editor session knows correct attribute-name");
editorInput.value = "Hello World";
editorInput.focus();
// hit <enter> to save the inputted value
executeSoon(function() {
EventUtils.synthesizeKey("VK_RETURN", {}, attrValNode_id.ownerDocument.defaultView);
});
// two `yield` statements, to trap both the "SAVED" and "CLOSED" events that will be triggered
yield;
yield; // End of Step 2
// Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value
ok(!InspectorUI.editingContext, "Step 3: editor session ended");
editorVisible = editor.classList.contains("editing");
ok(!editorVisible, "editor popup hidden");
attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
ok(!attrValNodeHighlighted, "`id` attribute-value node is no longer editor-highlighted");
is(div.getAttribute("id"), "Hello World", "`id` attribute-value successfully updated");
is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel successfully updated");
// double-click the `class` attribute-value node to open the editor
executeSoon(function() {
// firing 2 clicks right in a row to simulate a double-click
EventUtils.synthesizeMouse(attrValNode_class, 2, 2, {clickCount: 2}, attrValNode_class.ownerDocument.defaultView);
});
yield; // End of Step 3
// Step 4: enter value into editor, then hit <escape> to discard it
ok(InspectorUI.editingContext, "Step 4: editor session started");
editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible");
is(InspectorUI.editingContext.attrObj, attrValNode_class, "editor session has correct reference to `class` attribute-value node in HTML panel");
is(InspectorUI.editingContext.attrName, "class", "editor session knows correct attribute-name");
editorInput.value = "Hello World";
editorInput.focus();
// hit <escape> to discard the inputted value
executeSoon(function() {
EventUtils.synthesizeKey("VK_ESCAPE", {}, attrValNode_class.ownerDocument.defaultView);
});
yield; // End of Step 4
// Step 5: validate that the previous editing session discarded correctly, then open editor on `id` attribute value again
ok(!InspectorUI.editingContext, "Step 5: editor session ended");
editorVisible = editor.classList.contains("editing");
ok(!editorVisible, "editor popup hidden");
is(div.getAttribute("class"), "barbaz", "`class` attribute-value *not* updated");
is(attrValNode_class.innerHTML, "barbaz", "attribute-value node in HTML panel *not* updated");
// double-click the `id` attribute-value node to open the editor
executeSoon(function() {
// firing 2 clicks right in a row to simulate a double-click
EventUtils.synthesizeMouse(attrValNode_id, 2, 2, {clickCount: 2}, attrValNode_id.ownerDocument.defaultView);
});
yield; // End of Step 5
// Step 6: validate that editor opened again, then test double-click inside of editor (should do nothing)
ok(InspectorUI.editingContext, "Step 6: editor session started");
editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible");
// double-click on the editor input box
executeSoon(function() {
// firing 2 clicks right in a row to simulate a double-click
EventUtils.synthesizeMouse(editorInput, 2, 2, {clickCount: 2}, editorInput.ownerDocument.defaultView);
// since the previous double-click is supposed to do nothing,
// wait a brief moment, then move on to the next step
executeSoon(function() {
doNextStep();
});
});
yield; // End of Step 6
// Step 7: validate that editing session is still correct, then enter a value and try a click
// outside of editor (should cancel the editing session)
ok(InspectorUI.editingContext, "Step 7: editor session still going");
editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup still visible");
editorInput.value = "all your base are belong to us";
// single-click the `class` attribute-value node
executeSoon(function() {
EventUtils.synthesizeMouse(attrValNode_class, 2, 2, {}, attrValNode_class.ownerDocument.defaultView);
});
yield; // End of Step 7
// Step 8: validate that the editor was closed and that the editing was not saved
ok(!InspectorUI.editingContext, "Step 8: editor session ended");
editorVisible = editor.classList.contains("editing");
ok(!editorVisible, "editor popup hidden");
is(div.getAttribute("id"), "Hello World", "`id` attribute-value *not* updated");
is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated");
// End of Step 8
// end of all steps, so clean up
Services.obs.removeObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
Services.obs.removeObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
Services.obs.removeObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
executeSoon(finishUp);
}
function finishUp() {
doc = div = null;
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(setupEditorTests, content);
}, true);
content.location = "data:text/html,basic tests for html panel attribute-value editor";
}

File diff suppressed because one or more lines are too long

View File

@ -111,6 +111,7 @@ _BROWSER_FILES = \
browser_tabview_bug625269.js \
browser_tabview_bug625424.js \
browser_tabview_bug626368.js \
browser_tabview_bug626455.js \
browser_tabview_bug626525.js \
browser_tabview_bug626791.js \
browser_tabview_bug627239.js \
@ -139,6 +140,7 @@ _BROWSER_FILES = \
browser_tabview_bug649006.js \
browser_tabview_bug649307.js \
browser_tabview_bug649319.js \
browser_tabview_bug650280.js \
browser_tabview_bug650573.js \
browser_tabview_bug651311.js \
browser_tabview_bug654721.js \

View File

@ -1,15 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/tabview/AllTabs.jsm");
function test() {
waitForExplicitFinish();
let AllTabs;
let newTab = gBrowser.addTab();
// TabPinned
let pinned = function(tab) {
let pinned = function (event) {
let tab = event.target;
is(tab, newTab, "The tabs are the same after the tab is pinned");
ok(tab.pinned, "The tab gets pinned");
@ -17,7 +18,9 @@ function test() {
};
// TabUnpinned
let unpinned = function(tab) {
let unpinned = function (event) {
let tab = event.target;
AllTabs.unregister("pinned", pinned);
AllTabs.unregister("unpinned", unpinned);
@ -26,13 +29,17 @@ function test() {
// clean up and finish
gBrowser.removeTab(tab);
finish();
hideTabView(finish);
};
AllTabs.register("pinned", pinned);
AllTabs.register("unpinned", unpinned);
showTabView(function () {
AllTabs = TabView.getContentWindow().AllTabs;
ok(!newTab.pinned, "The tab is not pinned");
gBrowser.pinTab(newTab);
AllTabs.register("pinned", pinned);
AllTabs.register("unpinned", unpinned);
ok(!newTab.pinned, "The tab is not pinned");
gBrowser.pinTab(newTab);
});
}

View File

@ -22,7 +22,7 @@ function setupOne(win) {
afterAllTabsLoaded(function () setupTwo(win), win);
}
let restoreWin;
let restoredWin;
function setupTwo(win) {
let contentWindow = win.TabView.getContentWindow();

View File

@ -10,7 +10,7 @@ function test() {
function part1(win) {
registerCleanupFunction(function() win.close());
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let contentWindow = win.TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
let originalTab = win.gBrowser.selectedTab;
@ -71,15 +71,12 @@ function part2(win) {
// switch the selected tab to new tab
win.gBrowser.selectedTab = newTab;
whenTabViewIsHidden(function () {
is(win.gBrowser.selectedTab, newTab, "The seleted tab should be the same as before (new tab)");
win.close();
finish();
});
// show tabview
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
// hide tabview
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
})
showTabView(function () {
hideTabView(function () {
is(win.gBrowser.selectedTab, newTab,
"The selected tab should be the same as before (new tab)");
waitForFocus(finish);
}, win);
}, win);
}, win);
}

View File

@ -21,9 +21,7 @@ function onTabViewShown() {
function testStayOnPage(contentWindow, groupItemOne, groupItemTwo) {
whenDialogOpened(function (dialog) {
groupItemTwo.addSubscriber("groupShown", function onShown() {
groupItemTwo.removeSubscriber("groupShown", onShown);
executeSoon(function () {
is(gBrowser.tabs.length, 2,
"The total number of tab is 2 when staying on the page");
is(contentWindow.TabItems.getItems().length, 2,

View File

@ -25,6 +25,7 @@ function test1() {
is(groupItems.length, 1, "there is one groupItem");
whenTabViewIsHidden(function() {
gBrowser.selectedTab = gBrowser.tabs[0];
is(groupItems.length, 2, "there are two groupItems");
closeGroupItem(groupItems[1], finish);
});

View File

@ -18,6 +18,6 @@ function test() {
cw.GroupItems.resumeArrange();
ok(groupItem.isStacked(), 'groupItem is now stacked');
closeGroupItem(groupItem, finish);
closeGroupItem(groupItem, function () hideTabView(finish));
});
}

View File

@ -34,7 +34,7 @@ function test() {
ok(!document.getElementById("context_openTabInWindow").disabled, "The 'Move to New Window' menu item is enabled");
let newTabTwo = gBrowser.selectedTab;
gBrowser.selected = originalTab;
gBrowser.selectedTab = originalTab;
gBrowser.removeTab(newTabOne);
gBrowser.removeTab(newTabTwo);

View File

@ -0,0 +1,127 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Contributor(s):
* Mihai Sucan <mihai.sucan@gmail.com>
* Raymond Lee <raymond@appcoast.com>
*/
const TEST_URL = 'data:text/html,<script>window.onbeforeunload=' +
'function(e){e.returnValue="?"}</script><body ' +
'onunload="alert(\'onunload\')" onpagehide="' +
'alert(\'onpagehide\')"></body>';
let contentWindow;
let activeGroup;
function test() {
waitForExplicitFinish();
showTabView(function () {
contentWindow = TabView.getContentWindow();
activeGroup = contentWindow.GroupItems.getActiveGroupItem();
gBrowser.browsers[0].contentWindow.location =
"data:text/html,<p>test for bug 626455, tab1";
gBrowser.addTab(TEST_URL);
afterAllTabsLoaded(testStayOnPage);
});
}
function testStayOnPage() {
whenDialogOpened(function (dialog) {
// stay on page
dialog.cancelDialog();
executeSoon(function () {
showTabView(function () {
is(gBrowser.tabs.length, 1,
"The total number of tab is 1 when staying on the page");
let location = gBrowser.browsers[0].contentWindow.location.toString();
isnot(location.indexOf("onbeforeunload"), -1,
"The open tab is the expected one");
is(contentWindow.GroupItems.getActiveGroupItem(), activeGroup,
"Active group is still the same");
is(contentWindow.GroupItems.groupItems.length, 1,
"Only one group is open");
// start the next test
testLeavePage();
});
});
});
closeGroupItem(activeGroup);
}
function testLeavePage() {
let dialogsAccepted = 0;
whenDialogOpened(function onDialogOpened(dialog) {
if (++dialogsAccepted < 3)
whenDialogOpened(onDialogOpened);
// Leave page
dialog.acceptDialog();
});
whenGroupClosed(activeGroup, finishTest);
closeGroupItem(activeGroup);
}
function finishTest() {
is(gBrowser.tabs.length, 1,
"The total number of tab is 1 after leaving the page");
is(contentWindow.TabItems.getItems().length, 1,
"The total number of tab items is 1 after leaving the page");
let location = gBrowser.browsers[0].contentWindow.location.toString();
is(location, "about:blank", "The open tab is the expected one");
isnot(contentWindow.GroupItems.getActiveGroupItem(), activeGroup,
"Active group is no longer the same");
is(contentWindow.GroupItems.groupItems.length, 1,
"Only one group is open");
finish();
}
// ----------
function whenGroupClosed(group, callback) {
group.addSubscriber("close", function onClose() {
group.removeSubscriber("close", onClose);
callback();
});
}
// ----------
function whenDialogOpened(callback) {
let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
let listener = {
onCloseWindow: function () {},
onWindowTitleChange: function () {},
onOpenWindow: function (xulWin) {
let domWin = xulWin.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
whenWindowLoaded(domWin, function () {
let dialog = domWin.document.querySelector("dialog");
if (dialog) {
wm.removeListener(listener);
callback(dialog);
}
});
}
};
wm.addListener(listener);
}

View File

@ -15,7 +15,7 @@ function loadTabs (win) {
function testTopOfStack(win) {
registerCleanupFunction(function () { win.close(); });
let cw = win.TabView.getContentWindow();
groupItem = cw.GroupItems.getActiveGroupItem();
let groupItem = cw.GroupItems.getActiveGroupItem();
ok(!groupItem.isStacked(), 'groupItem is not stacked');
groupItem.setSize(150, 150);
groupItem.setUserSize();

View File

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
function test() {
let cw;
registerCleanupFunction(function() {
if (cw)
cw.hideSearch();
TabView.hide();
pb.privateBrowsingEnabled = false;
});
let enableSearch = function (callback) {
if (cw.isSearchEnabled()) {
callback();
return;
}
cw.addEventListener("tabviewsearchenabled", function onSearchEnabled() {
cw.removeEventListener("tabviewsearchenabled", onSearchEnabled, false);
executeSoon(callback);
}, false);
cw.ensureSearchShown();
};
let getSearchboxValue = function () {
return cw.iQ("#searchbox").val();
};
let prepareSearchbox = function (callback) {
ok(!cw.isSearchEnabled(), "search is disabled");
enableSearch(function () {
cw.iQ("#searchbox").val("moz");
callback();
});
};
let searchAndSwitchPBMode = function (callback) {
prepareSearchbox(function () {
togglePrivateBrowsing(function () {
showTabView(function () {
ok(!cw.isSearchEnabled(), "search is disabled");
is(getSearchboxValue(), "", "search box is empty");
callback();
});
});
});
};
waitForExplicitFinish();
showTabView(function () {
cw = TabView.getContentWindow();
searchAndSwitchPBMode(function () {
searchAndSwitchPBMode(function () {
hideTabView(finish);
});
});
});
}

View File

@ -67,7 +67,7 @@ function test() {
EventUtils.synthesizeMouse(target, 600, 5, {type: "mouseup"}, cw);
checkNumberOfGroupItems(2);
next();
closeGroupItem(cw.GroupItems.groupItems[1], next);
}, win);
}

View File

@ -3,49 +3,32 @@
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
showTabView(onTabViewShown);
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
function onTabViewShown() {
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let contentWindow = TabView.getContentWindow();
let [originalTab] = gBrowser.visibleTabs;
let createGroupItem = function (left, top, width, height) {
let box = new contentWindow.Rect(left, top, width, height);
let groupItem = new contentWindow.GroupItem([], {bounds: box, immediately: true});
contentWindow.UI.setActive(groupItem);
gBrowser.loadOneTab("about:blank", {inBackground: true});
return groupItem;
};
// create group one and two
let boxOne = new contentWindow.Rect(20, 20, 300, 300);
let groupOne = new contentWindow.GroupItem([], { bounds: boxOne });
ok(groupOne.isEmpty(), "This group is empty");
let groupOne = createGroupItem(20, 20, 300, 300);
let groupTwo = createGroupItem(20, 400, 300, 300);
let boxTwo = new contentWindow.Rect(20, 400, 300, 300);
let groupTwo = new contentWindow.GroupItem([], { bounds: boxTwo });
groupOne.addSubscriber("childAdded", function onChildAdded() {
groupOne.removeSubscriber("childAdded", onChildAdded);
groupTwo.newTab();
waitForFocus(function () {
addTest(contentWindow, groupOne.id, groupTwo.id, originalTab);
});
let count = 0;
let onTabViewShown = function() {
if (count == 2) {
window.removeEventListener("tabviewshown", onTabViewShown, false);
addTest(contentWindow, groupOne.id, groupTwo.id, originalTab);
}
};
let onTabViewHidden = function() {
TabView.toggle();
if (++count == 2)
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
};
window.addEventListener("tabviewshown", onTabViewShown, false);
window.addEventListener("tabviewhidden", onTabViewHidden, false);
// open tab in group
groupOne.newTab();
}
function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
@ -74,24 +57,13 @@ function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
"The number of children in group one is decreased by 1");
is(groupTwo.getChildren().length, ++groupTwoTabItemCount,
"The number of children in group two is increased by 1");
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
groupTwo.closeAll();
// close undo group
let closeButton = groupTwo.$undoContainer.find(".close");
EventUtils.sendMouseEvent(
{ type: "click" }, closeButton[0], contentWindow);
};
groupTwo.addSubscriber("close", function onClose() {
groupTwo.removeSubscriber("close", onClose);
finish();
closeGroupItem(groupOne, function () {
closeGroupItem(groupTwo, function () hideTabView(finish));
});
window.addEventListener("tabviewhidden", onTabViewHidden, false);
gBrowser.selectedTab = originalTab;
}
groupTwo.addSubscriber("childAdded", endGame);
simulateDragDrop(tabItem.container, offsetX, offsetY, contentWindow);
}

View File

@ -1,15 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let timerId;
let newWin;
// ----------
function test() {
waitForExplicitFinish();
// launch tab view for the first time
newWindowWithTabView(function() {}, function(win) {
let panelSelected = false;
registerCleanupFunction(function () ok(panelSelected, "panel is selected"));
let onLoad = function (win) {
registerCleanupFunction(function () win.close());
newWin = win;
let onSelect = function(event) {
@ -21,27 +24,26 @@ function test() {
return;
deck.removeEventListener("select", onSelect, true);
whenTabViewIsShown(function() {
executeSoon(function() {
testMethodToHideAndShowTabView(function() {
newWin.document.getElementById("menu_tabview").doCommand();
}, function() {
testMethodToHideAndShowTabView(function() {
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, newWin);
}, finish);
});
});
}, win);
panelSelected = true;
};
let deck = win.document.getElementById("tab-view-deck");
deck.addEventListener("select", onSelect, true);
});
};
registerCleanupFunction(function () {
newWin.close();
});
let onShow = function (win) {
executeSoon(function() {
testMethodToHideAndShowTabView(function() {
newWin.document.getElementById("menu_tabview").doCommand();
}, function() {
testMethodToHideAndShowTabView(function() {
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, newWin);
}, finish);
});
});
};
newWindowWithTabView(onShow, onLoad);
}
function testMethodToHideAndShowTabView(executeFunc, callback) {

View File

@ -49,9 +49,10 @@ function executeCopyCommand(command, expectedValue)
is(input.value, expectedValue, "paste for command " + command);
}
function invokeItemAction(ident)
function invokeItemAction(generatedItemId)
{
var item = contextMenu.getElementsByAttribute("ident", ident)[0];
var item = contextMenu.getElementsByAttribute("generateditemid",
generatedItemId)[0];
ok(item, "Got generated XUL menu item");
item.doCommand();
is(pagemenu.hasAttribute("hopeless"), false, "attribute got removed");
@ -69,7 +70,7 @@ function getVisibleMenuItems(aMenu, aData) {
if (key)
key = key.toLowerCase();
var isGenerated = item.hasAttribute("generated");
var isGenerated = item.hasAttribute("generateditemid");
if (item.nodeName == "menuitem") {
var isSpellSuggestion = item.className == "spell-suggestion";

View File

@ -367,7 +367,7 @@
// Only add the suffix when the URL bar value isn't already "URL-like",
// and only if we get a keyboard event, to match user expectations.
if (!/^\s*(www|https?)\b|\/\s*$/i.test(url) &&
if (/^\s*[^.:\/\s]+(?:\/.*|\s*)$/i.test(url) &&
(aTriggeringEvent instanceof KeyEvent)) {
#ifdef XP_MACOSX
let accel = aTriggeringEvent.metaKey;
@ -402,24 +402,15 @@
// Tack www. and suffix on. If user has appended directories, insert
// suffix before them (bug 279035). Be careful not to get two slashes.
// Also, don't add the suffix if it's in the original url (bug 233853).
let firstSlash = url.indexOf("/");
let existingSuffix = url.indexOf(suffix.substring(0, suffix.length - 1));
// * Logic for slash and existing suffix (example)
// No slash, no suffix: Add suffix (mozilla)
// No slash, yes suffix: Add slash (mozilla.com)
// Yes slash, no suffix: Insert suffix (mozilla/stuff)
// Yes slash, suffix before slash: Do nothing (mozilla.com/stuff)
// Yes slash, suffix after slash: Insert suffix (mozilla/?stuff=.com)
if (firstSlash >= 0) {
if (existingSuffix == -1 || existingSuffix > firstSlash)
url = url.substring(0, firstSlash) + suffix +
url.substring(firstSlash + 1);
} else
url = url + (existingSuffix == -1 ? suffix : "/");
url = url.substring(0, firstSlash) + suffix +
url.substring(firstSlash + 1);
} else {
url = url + suffix;
}
url = "http://www." + url;
}

View File

@ -53,6 +53,7 @@ browser.jar:
content/browser/tabview.css (content/tabview/tabview.css)
* content/browser/tabview.js (content/tabview/tabview.js)
content/browser/tabview.html (content/tabview/tabview.html)
content/browser/tabview-content.js (content/tabview/content.js)
* content/browser/urlbarBindings.xml (content/urlbarBindings.xml)
* content/browser/utilityOverlay.js (content/utilityOverlay.js)
* content/browser/web-panels.js (content/web-panels.js)

View File

@ -53,7 +53,6 @@
#if !defined(XP_OS2)
#include "nsOperaProfileMigrator.h"
#endif
#include "nsSeamonkeyProfileMigrator.h"
#if defined(XP_WIN) && !defined(__MINGW32__)
#include "nsIEProfileMigrator.h"
#elif defined(XP_MACOSX)
@ -85,7 +84,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsOperaProfileMigrator)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsProfileMigrator)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSeamonkeyProfileMigrator)
#if defined(XP_WIN) && !defined(__MINGW32__)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEProfileMigrator)
#elif defined(XP_MACOSX)
@ -114,7 +112,6 @@ NS_DEFINE_NAMED_CID(NS_SAFARIPROFILEMIGRATOR_CID);
#if !defined(XP_OS2)
NS_DEFINE_NAMED_CID(NS_OPERAPROFILEMIGRATOR_CID);
#endif
NS_DEFINE_NAMED_CID(NS_SEAMONKEYPROFILEMIGRATOR_CID);
NS_DEFINE_NAMED_CID(NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID);
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
@ -136,7 +133,6 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
#if !defined(XP_OS2)
{ &kNS_OPERAPROFILEMIGRATOR_CID, false, NULL, nsOperaProfileMigratorConstructor },
#endif
{ &kNS_SEAMONKEYPROFILEMIGRATOR_CID, false, NULL, nsSeamonkeyProfileMigratorConstructor },
{ &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID, false, NULL, nsPrivateBrowsingServiceWrapperConstructor },
{ NULL }
};
@ -173,7 +169,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
#if !defined(XP_OS2)
{ NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "opera", &kNS_OPERAPROFILEMIGRATOR_CID },
#endif
{ NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey", &kNS_SEAMONKEYPROFILEMIGRATOR_CID },
{ NS_PRIVATE_BROWSING_SERVICE_CONTRACTID, &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID },
{ NULL }
};

View File

@ -256,7 +256,8 @@ FeedWriter.prototype = {
__contentSandbox: null,
get _contentSandbox() {
if (!this.__contentSandbox)
this.__contentSandbox = new Cu.Sandbox(this._window);
this.__contentSandbox = new Cu.Sandbox(this._window,
{sandboxName: 'FeedWriter'});
return this.__contentSandbox;
},

View File

@ -340,9 +340,6 @@ var MigrationWizard = {
case "safari":
source = "sourceNameSafari";
break;
case "seamonkey":
source = "sourceNameSeamonkey";
break;
}
// semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places

View File

@ -70,19 +70,14 @@
browser/components/migration/src/nsProfileMigrator.cpp -->
#ifdef XP_MACOSX
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
<radio id="seamonkey" label="&importFromSeamonkey.label;" accesskey="&importFromSeamonkey.accesskey;"/>
<radio id="opera" label="&importFromOpera.label;" accesskey="&importFromOpera.accesskey;"/>
#elifdef XP_UNIX
<radio id="seamonkey" label="&importFromSeamonkey.label;" accesskey="&importFromSeamonkey.accesskey;"/>
<radio id="opera" label="&importFromOpera.label;" accesskey="&importFromOpera.accesskey;"/>
#elifdef XP_WIN
#ifndef NO_IE_MIGRATOR
<radio id="ie" label="&importFromIE.label;" accesskey="&importFromIE.accesskey;"/>
#endif
<radio id="seamonkey" label="&importFromSeamonkey.label;" accesskey="&importFromSeamonkey.accesskey;"/>
<radio id="opera" label="&importFromOpera.label;" accesskey="&importFromOpera.accesskey;"/>
#else
<radio id="seamonkey" label="&importFromSeamonkey.label;" accesskey="&importFromSeamonkey.accesskey;"/>
#endif
<radio id="fromfile" label="&importFromHTMLFile.label;" accesskey="&importFromHTMLFile.accesskey;" hidden="true"/>
<radio id="nothing" label="&importFromNothing.label;" accesskey="&importFromNothing.accesskey;" hidden="true"/>

View File

@ -52,8 +52,6 @@ endif
CPPSRCS = nsProfileMigrator.cpp \
nsBrowserProfileMigratorUtils.cpp \
nsNetscapeProfileMigratorBase.cpp \
nsSeamonkeyProfileMigrator.cpp \
$(NULL)
ifneq ($(OS_ARCH),OS2)

View File

@ -1,469 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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 The Browser Profile Migrator.
*
* The Initial Developer of the Original Code is Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@bengoodger.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 ***** */
#include "nsAppDirectoryServiceDefs.h"
#include "nsBrowserProfileMigratorUtils.h"
#include "nsICookieManager2.h"
#include "nsIFile.h"
#include "nsILineInputStream.h"
#include "nsIOutputStream.h"
#include "nsIPrefBranch.h"
#include "nsIPrefLocalizedString.h"
#include "nsIPrefService.h"
#include "NSReg.h"
#include "nsIServiceManager.h"
#include "nsISupportsPrimitives.h"
#include "nsIURL.h"
#include "nsNetscapeProfileMigratorBase.h"
#include "nsNetUtil.h"
#include "prtime.h"
#include "prprf.h"
#ifdef XP_MACOSX
#define NEED_TO_FIX_4X_COOKIES 1
#define SECONDS_BETWEEN_1900_AND_1970 2208988800UL
#endif /* XP_MACOSX */
#define FILE_NAME_PREFS_5X NS_LITERAL_STRING("prefs.js")
///////////////////////////////////////////////////////////////////////////////
// nsNetscapeProfileMigratorBase
nsNetscapeProfileMigratorBase::nsNetscapeProfileMigratorBase()
{
}
static nsresult
regerr2nsresult(REGERR errCode)
{
switch (errCode) {
case REGERR_PARAM:
case REGERR_BADTYPE:
case REGERR_BADNAME:
return NS_ERROR_INVALID_ARG;
case REGERR_MEMORY:
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_ERROR_FAILURE;
}
nsresult
nsNetscapeProfileMigratorBase::GetProfileDataFromRegistry(nsILocalFile* aRegistryFile,
nsISupportsArray* aProfileNames,
nsISupportsArray* aProfileLocations)
{
nsresult rv;
REGERR errCode;
// Ensure aRegistryFile exists before open it
PRBool regFileExists = PR_FALSE;
rv = aRegistryFile->Exists(&regFileExists);
NS_ENSURE_SUCCESS(rv, rv);
if (!regFileExists)
return NS_ERROR_FILE_NOT_FOUND;
// Open It
nsCAutoString regPath;
rv = aRegistryFile->GetNativePath(regPath);
NS_ENSURE_SUCCESS(rv, rv);
if ((errCode = NR_StartupRegistry()))
return regerr2nsresult(errCode);
HREG reg;
if ((errCode = NR_RegOpen(regPath.get(), &reg))) {
NR_ShutdownRegistry();
return regerr2nsresult(errCode);
}
RKEY profilesTree;
if ((errCode = NR_RegGetKey(reg, ROOTKEY_COMMON, "Profiles", &profilesTree))) {
NR_RegClose(reg);
NR_ShutdownRegistry();
return regerr2nsresult(errCode);
}
char profileStr[MAXREGPATHLEN];
REGENUM enumState = nsnull;
while (!NR_RegEnumSubkeys(reg, profilesTree, &enumState, profileStr,
sizeof(profileStr), REGENUM_CHILDREN))
{
RKEY profileKey;
if (NR_RegGetKey(reg, profilesTree, profileStr, &profileKey))
continue;
// "migrated" is "yes" for all valid Seamonkey profiles. It is only "no"
// for 4.x profiles.
char migratedStr[3];
errCode = NR_RegGetEntryString(reg, profileKey, (char *)"migrated",
migratedStr, sizeof(migratedStr));
if ((errCode != REGERR_OK && errCode != REGERR_BUFTOOSMALL) ||
strcmp(migratedStr, "no") == 0)
continue;
// Get the profile location and add it to the locations array
REGINFO regInfo;
regInfo.size = sizeof(REGINFO);
if (NR_RegGetEntryInfo(reg, profileKey, (char *)"directory", &regInfo))
continue;
nsCAutoString dirStr;
dirStr.SetLength(regInfo.entryLength);
errCode = NR_RegGetEntryString(reg, profileKey, (char *)"directory",
dirStr.BeginWriting(), regInfo.entryLength);
// Remove trailing \0
dirStr.SetLength(regInfo.entryLength-1);
nsCOMPtr<nsILocalFile> dir;
#ifdef XP_MACOSX
rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(dir));
if (NS_FAILED(rv)) break;
dir->SetPersistentDescriptor(dirStr);
#else
rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(dirStr), PR_TRUE,
getter_AddRefs(dir));
if (NS_FAILED(rv)) break;
#endif
PRBool exists;
dir->Exists(&exists);
if (exists) {
aProfileLocations->AppendElement(dir);
// Get the profile name and add it to the names array
nsString profileName;
CopyUTF8toUTF16(nsDependentCString(profileStr), profileName);
nsCOMPtr<nsISupportsString> profileNameString(
do_CreateInstance("@mozilla.org/supports-string;1"));
profileNameString->SetData(profileName);
aProfileNames->AppendElement(profileNameString);
}
}
NR_RegClose(reg);
NR_ShutdownRegistry();
return rv;
}
#define GETPREF(xform, method, value) \
nsresult rv = aBranch->method(xform->sourcePrefName, value); \
if (NS_SUCCEEDED(rv)) \
xform->prefHasValue = PR_TRUE; \
return rv;
#define SETPREF(xform, method, value) \
if (xform->prefHasValue) { \
return aBranch->method(xform->targetPrefName ? xform->targetPrefName : xform->sourcePrefName, value); \
} \
return NS_OK;
nsresult
nsNetscapeProfileMigratorBase::GetString(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
GETPREF(xform, GetCharPref, &xform->stringValue);
}
nsresult
nsNetscapeProfileMigratorBase::SetString(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
SETPREF(xform, SetCharPref, xform->stringValue);
}
nsresult
nsNetscapeProfileMigratorBase::GetWString(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
nsCOMPtr<nsIPrefLocalizedString> prefValue;
nsresult rv = aBranch->GetComplexValue(xform->sourcePrefName,
NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(prefValue));
if (NS_SUCCEEDED(rv) && prefValue) {
nsString data;
prefValue->ToString(getter_Copies(data));
xform->stringValue = ToNewCString(NS_ConvertUTF16toUTF8(data));
xform->prefHasValue = PR_TRUE;
}
return rv;
}
nsresult
nsNetscapeProfileMigratorBase::SetWStringFromASCII(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
if (xform->prefHasValue) {
nsCOMPtr<nsIPrefLocalizedString> pls(do_CreateInstance("@mozilla.org/pref-localizedstring;1"));
NS_ConvertUTF8toUTF16 data(xform->stringValue);
pls->SetData(data.get());
return aBranch->SetComplexValue(xform->targetPrefName ? xform->targetPrefName : xform->sourcePrefName, NS_GET_IID(nsIPrefLocalizedString), pls);
}
return NS_OK;
}
nsresult
nsNetscapeProfileMigratorBase::SetWString(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
if (xform->prefHasValue) {
nsCOMPtr<nsIPrefLocalizedString> pls(do_CreateInstance("@mozilla.org/pref-localizedstring;1"));
nsAutoString data = NS_ConvertUTF8toUTF16(xform->stringValue);
pls->SetData(data.get());
return aBranch->SetComplexValue(xform->targetPrefName ? xform->targetPrefName : xform->sourcePrefName, NS_GET_IID(nsIPrefLocalizedString), pls);
}
return NS_OK;
}
nsresult
nsNetscapeProfileMigratorBase::GetBool(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
GETPREF(xform, GetBoolPref, &xform->boolValue);
}
nsresult
nsNetscapeProfileMigratorBase::SetBool(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
SETPREF(xform, SetBoolPref, xform->boolValue);
}
nsresult
nsNetscapeProfileMigratorBase::GetInt(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
GETPREF(xform, GetIntPref, &xform->intValue);
}
nsresult
nsNetscapeProfileMigratorBase::SetInt(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
SETPREF(xform, SetIntPref, xform->intValue);
}
nsresult
nsNetscapeProfileMigratorBase::CopyFile(const nsAString& aSourceFileName, const nsAString& aTargetFileName)
{
nsCOMPtr<nsIFile> sourceFile;
mSourceProfile->Clone(getter_AddRefs(sourceFile));
sourceFile->Append(aSourceFileName);
PRBool exists = PR_FALSE;
sourceFile->Exists(&exists);
if (!exists)
return NS_OK;
nsCOMPtr<nsIFile> targetFile;
mTargetProfile->Clone(getter_AddRefs(targetFile));
targetFile->Append(aTargetFileName);
targetFile->Exists(&exists);
if (exists)
targetFile->Remove(PR_FALSE);
return sourceFile->CopyTo(mTargetProfile, aTargetFileName);
}
nsresult
nsNetscapeProfileMigratorBase::ImportNetscapeBookmarks(const nsAString& aBookmarksFileName,
const PRUnichar* aImportSourceNameKey)
{
nsCOMPtr<nsIFile> bookmarksFile;
mSourceProfile->Clone(getter_AddRefs(bookmarksFile));
bookmarksFile->Append(aBookmarksFileName);
return ImportBookmarksHTML(bookmarksFile, PR_FALSE, PR_FALSE, aImportSourceNameKey);
}
nsresult
nsNetscapeProfileMigratorBase::ImportNetscapeCookies(nsIFile* aCookiesFile)
{
nsresult rv;
nsCOMPtr<nsIInputStream> cookiesStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(cookiesStream), aCookiesFile);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsILineInputStream> lineInputStream(do_QueryInterface(cookiesStream));
// This code is copied from mozilla/netwerk/cookie/src/nsCookieManager.cpp
static NS_NAMED_LITERAL_CSTRING(kTrue, "TRUE");
nsCAutoString buffer;
PRBool isMore = PR_TRUE;
PRInt32 hostIndex = 0, isDomainIndex, pathIndex, secureIndex, expiresIndex, nameIndex, cookieIndex;
PRInt32 numInts;
PRInt64 expires;
PRBool isDomain;
PRInt64 currentTime = PR_Now() / PR_USEC_PER_SEC;
nsCOMPtr<nsICookieManager2> cookieManager(do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv));
if (NS_FAILED(rv)) return rv;
/* file format is:
*
* host \t isDomain \t path \t secure \t expires \t name \t cookie
*
* if this format isn't respected we move onto the next line in the file.
* isDomain is "TRUE" or "FALSE" (default to "FALSE")
* isSecure is "TRUE" or "FALSE" (default to "TRUE")
* expires is a PRInt64 integer
* note 1: cookie can contain tabs.
* note 2: cookies are written in order of lastAccessed time:
* most-recently used come first; least-recently-used come last.
*/
while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
if (buffer.IsEmpty() || buffer.First() == '#')
continue;
// this is a cheap, cheesy way of parsing a tab-delimited line into
// string indexes, which can be lopped off into substrings. just for
// purposes of obfuscation, it also checks that each token was found.
// todo: use iterators?
if ((isDomainIndex = buffer.FindChar('\t', hostIndex) + 1) == 0 ||
(pathIndex = buffer.FindChar('\t', isDomainIndex) + 1) == 0 ||
(secureIndex = buffer.FindChar('\t', pathIndex) + 1) == 0 ||
(expiresIndex = buffer.FindChar('\t', secureIndex) + 1) == 0 ||
(nameIndex = buffer.FindChar('\t', expiresIndex) + 1) == 0 ||
(cookieIndex = buffer.FindChar('\t', nameIndex) + 1) == 0)
continue;
// check the expirytime first - if it's expired, ignore
// nullstomp the trailing tab, to avoid copying the string
char *iter = buffer.BeginWriting();
*(iter += nameIndex - 1) = char(0);
numInts = PR_sscanf(buffer.get() + expiresIndex, "%lld", &expires);
if (numInts != 1 || expires < currentTime)
continue;
isDomain = Substring(buffer, isDomainIndex, pathIndex - isDomainIndex - 1).Equals(kTrue);
const nsDependentCSubstring host =
Substring(buffer, hostIndex, isDomainIndex - hostIndex - 1);
// check for bad legacy cookies (domain not starting with a dot, or containing a port),
// and discard
if (isDomain && !host.IsEmpty() && host.First() != '.' ||
host.FindChar(':') != -1)
continue;
// create a new nsCookie and assign the data.
rv = cookieManager->Add(host,
Substring(buffer, pathIndex, secureIndex - pathIndex - 1),
Substring(buffer, nameIndex, cookieIndex - nameIndex - 1),
Substring(buffer, cookieIndex, buffer.Length() - cookieIndex),
Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).Equals(kTrue),
PR_FALSE, // isHttpOnly
PR_FALSE, // isSession
expires);
}
return rv;
}
nsresult
nsNetscapeProfileMigratorBase::GetSignonFileName(PRBool aReplace, char** aFileName)
{
nsresult rv;
if (aReplace) {
// Find out what the signons file was called, this is stored in a pref
// in Seamonkey.
nsCOMPtr<nsIPrefService> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
psvc->ResetPrefs();
nsCOMPtr<nsIFile> sourcePrefsName;
mSourceProfile->Clone(getter_AddRefs(sourcePrefsName));
sourcePrefsName->Append(FILE_NAME_PREFS_5X);
psvc->ReadUserPrefs(sourcePrefsName);
nsCOMPtr<nsIPrefBranch> branch(do_QueryInterface(psvc));
rv = branch->GetCharPref("signon.SignonFileName", aFileName);
}
else
rv = LocateSignonsFile(aFileName);
return rv;
}
nsresult
nsNetscapeProfileMigratorBase::LocateSignonsFile(char** aResult)
{
nsCOMPtr<nsISimpleEnumerator> entries;
nsresult rv = mSourceProfile->GetDirectoryEntries(getter_AddRefs(entries));
if (NS_FAILED(rv)) return rv;
nsCAutoString fileName;
do {
PRBool hasMore = PR_FALSE;
rv = entries->HasMoreElements(&hasMore);
if (NS_FAILED(rv) || !hasMore) break;
nsCOMPtr<nsISupports> supp;
rv = entries->GetNext(getter_AddRefs(supp));
if (NS_FAILED(rv)) break;
nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
nsCOMPtr<nsIURI> uri;
rv = NS_NewFileURI(getter_AddRefs(uri), currFile);
if (NS_FAILED(rv)) break;
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
nsCAutoString extn;
url->GetFileExtension(extn);
if (extn.Equals("s", CaseInsensitiveCompare)) {
url->GetFileName(fileName);
break;
}
}
while (1);
*aResult = ToNewCString(fileName);
return NS_OK;
}

View File

@ -1,101 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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 The Browser Profile Migrator.
*
* The Initial Developer of the Original Code is Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@bengoodger.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 ***** */
#ifndef netscapeprofilemigratorbase___h___
#define netscapeprofilemigratorbase___h___
#include "nsILocalFile.h"
#include "nsIStringBundle.h"
#include "nsISupportsArray.h"
#include "nsStringAPI.h"
class nsIFile;
class nsIPrefBranch;
class nsNetscapeProfileMigratorBase
{
public:
nsNetscapeProfileMigratorBase();
virtual ~nsNetscapeProfileMigratorBase() { }
public:
typedef nsresult(*prefConverter)(void*, nsIPrefBranch*);
struct PrefTransform {
const char* sourcePrefName;
const char* targetPrefName;
prefConverter prefGetterFunc;
prefConverter prefSetterFunc;
PRBool prefHasValue;
union {
PRInt32 intValue;
PRBool boolValue;
char* stringValue;
};
};
static nsresult GetString(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetString(void* aTransform, nsIPrefBranch* aBranch);
static nsresult GetWString(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetWString(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetWStringFromASCII(void* aTransform, nsIPrefBranch* aBranch);
static nsresult GetBool(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetBool(void* aTransform, nsIPrefBranch* aBranch);
static nsresult GetInt(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetInt(void* aTransform, nsIPrefBranch* aBranch);
protected:
nsresult GetProfileDataFromRegistry(nsILocalFile* aRegistryFile,
nsISupportsArray* aProfileNames,
nsISupportsArray* aProfileLocations);
nsresult CopyFile(const nsAString& aSourceFileName, const nsAString& aTargetFileName);
nsresult ImportNetscapeBookmarks(const nsAString& aBookmarksFileName,
const PRUnichar* aImportSourceNameKey);
nsresult ImportNetscapeCookies(nsIFile* aCookiesFile);
nsresult GetSignonFileName(PRBool aReplace, char** aFileName);
nsresult LocateSignonsFile(char** aResult);
protected:
nsCOMPtr<nsILocalFile> mSourceProfile;
nsCOMPtr<nsIFile> mTargetProfile;
};
#endif

View File

@ -162,7 +162,6 @@ NS_IMPL_ISUPPORTS1(nsProfileMigrator, nsIProfileMigrator)
#define INTERNAL_NAME_IEXPLORE "iexplore"
#define INTERNAL_NAME_MOZILLA_SUITE "apprunner"
#define INTERNAL_NAME_SEAMONKEY "seamonkey"
#define INTERNAL_NAME_OPERA "opera"
#endif
@ -243,12 +242,7 @@ nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey,
aKey = "ie";
return NS_OK;
}
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_MOZILLA_SUITE) ||
internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_SEAMONKEY)) {
aKey = "seamonkey";
return NS_OK;
}
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_OPERA)) {
else if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_OPERA)) {
aKey = "opera";
return NS_OK;
}
@ -267,7 +261,6 @@ nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey,
#if defined(XP_MACOSX)
CHECK_MIGRATOR("safari");
#endif
CHECK_MIGRATOR("seamonkey");
CHECK_MIGRATOR("opera");
#undef CHECK_MIGRATOR

View File

@ -1,721 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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 The Browser Profile Migrator.
*
* The Initial Developer of the Original Code is Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@bengoodger.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 ***** */
#include "nsBrowserProfileMigratorUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIObserverService.h"
#include "nsILoginInfo.h"
#include "nsILoginManager.h"
#include "nsILoginManagerStorage.h"
#include "nsIPrefLocalizedString.h"
#include "nsIPrefService.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsISupportsPrimitives.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsSeamonkeyProfileMigrator.h"
#include "nsIProfileMigrator.h"
///////////////////////////////////////////////////////////////////////////////
// nsSeamonkeyProfileMigrator
#define FILE_NAME_BOOKMARKS NS_LITERAL_STRING("bookmarks.html")
#define FILE_NAME_COOKIES NS_LITERAL_STRING("cookies.txt")
#define FILE_NAME_SITEPERM_OLD NS_LITERAL_STRING("cookperm.txt")
#define FILE_NAME_SITEPERM_NEW NS_LITERAL_STRING("hostperm.1")
#define FILE_NAME_CERT8DB NS_LITERAL_STRING("cert8.db")
#define FILE_NAME_KEY3DB NS_LITERAL_STRING("key3.db")
#define FILE_NAME_SECMODDB NS_LITERAL_STRING("secmod.db")
#define FILE_NAME_MIMETYPES NS_LITERAL_STRING("mimeTypes.rdf")
#define FILE_NAME_DOWNLOADS NS_LITERAL_STRING("downloads.rdf")
#define FILE_NAME_PREFS NS_LITERAL_STRING("prefs.js")
#define FILE_NAME_USER_PREFS NS_LITERAL_STRING("user.js")
#define FILE_NAME_USERCONTENT NS_LITERAL_STRING("userContent.css")
#define DIR_NAME_CHROME NS_LITERAL_STRING("chrome")
NS_IMPL_ISUPPORTS1(nsSeamonkeyProfileMigrator, nsIBrowserProfileMigrator)
nsSeamonkeyProfileMigrator::nsSeamonkeyProfileMigrator()
{
mObserverService = do_GetService("@mozilla.org/observer-service;1");
}
nsSeamonkeyProfileMigrator::~nsSeamonkeyProfileMigrator()
{
}
///////////////////////////////////////////////////////////////////////////////
// nsIBrowserProfileMigrator
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::Migrate(PRUint16 aItems, nsIProfileStartup* aStartup, const PRUnichar* aProfile)
{
nsresult rv = NS_OK;
PRBool aReplace = aStartup ? PR_TRUE : PR_FALSE;
if (!mTargetProfile) {
GetProfilePath(aStartup, mTargetProfile);
if (!mTargetProfile) return NS_ERROR_FAILURE;
}
if (!mSourceProfile)
GetSourceProfile(aProfile);
NOTIFY_OBSERVERS(MIGRATION_STARTED, nsnull);
COPY_DATA(CopyPreferences, aReplace, nsIBrowserProfileMigrator::SETTINGS);
COPY_DATA(CopyCookies, aReplace, nsIBrowserProfileMigrator::COOKIES);
COPY_DATA(CopyPasswords, aReplace, nsIBrowserProfileMigrator::PASSWORDS);
COPY_DATA(CopyOtherData, aReplace, nsIBrowserProfileMigrator::OTHERDATA);
// Need to do startup before trying to copy bookmarks, since bookmarks
// import requires a profile. Can't do it earlier because services might
// end up creating the files we try to copy above.
if (aStartup) {
rv = aStartup->DoStartup();
NS_ENSURE_SUCCESS(rv, rv);
}
COPY_DATA(CopyBookmarks, aReplace, nsIBrowserProfileMigrator::BOOKMARKS);
if (aReplace &&
(aItems & nsIBrowserProfileMigrator::SETTINGS ||
aItems & nsIBrowserProfileMigrator::COOKIES ||
aItems & nsIBrowserProfileMigrator::PASSWORDS ||
!aItems)) {
// Permissions (Images, Cookies, Popups)
rv |= CopyFile(FILE_NAME_SITEPERM_NEW, FILE_NAME_SITEPERM_NEW);
rv |= CopyFile(FILE_NAME_SITEPERM_OLD, FILE_NAME_SITEPERM_OLD);
}
NOTIFY_OBSERVERS(MIGRATION_ENDED, nsnull);
return rv;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetMigrateData(const PRUnichar* aProfile,
PRBool aReplace,
PRUint16* aResult)
{
*aResult = 0;
if (!mSourceProfile) {
GetSourceProfile(aProfile);
if (!mSourceProfile)
return NS_ERROR_FILE_NOT_FOUND;
}
MigrationData data[] = { { ToNewUnicode(FILE_NAME_PREFS),
nsIBrowserProfileMigrator::SETTINGS,
PR_TRUE },
{ ToNewUnicode(FILE_NAME_USER_PREFS),
nsIBrowserProfileMigrator::SETTINGS,
PR_TRUE },
{ ToNewUnicode(FILE_NAME_COOKIES),
nsIBrowserProfileMigrator::COOKIES,
PR_FALSE },
{ ToNewUnicode(FILE_NAME_BOOKMARKS),
nsIBrowserProfileMigrator::BOOKMARKS,
PR_FALSE },
{ ToNewUnicode(FILE_NAME_DOWNLOADS),
nsIBrowserProfileMigrator::OTHERDATA,
PR_TRUE },
{ ToNewUnicode(FILE_NAME_MIMETYPES),
nsIBrowserProfileMigrator::OTHERDATA,
PR_TRUE } };
// Frees file name strings allocated above.
GetMigrateDataFromArray(data, sizeof(data)/sizeof(MigrationData),
aReplace, mSourceProfile, aResult);
// Now locate passwords
nsCString signonsFileName;
GetSignonFileName(aReplace, getter_Copies(signonsFileName));
if (!signonsFileName.IsEmpty()) {
NS_ConvertASCIItoUTF16 fileName(signonsFileName);
nsCOMPtr<nsIFile> sourcePasswordsFile;
mSourceProfile->Clone(getter_AddRefs(sourcePasswordsFile));
sourcePasswordsFile->Append(fileName);
PRBool exists;
sourcePasswordsFile->Exists(&exists);
if (exists)
*aResult |= nsIBrowserProfileMigrator::PASSWORDS;
}
return NS_OK;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetSourceExists(PRBool* aResult)
{
nsCOMPtr<nsISupportsArray> profiles;
GetSourceProfiles(getter_AddRefs(profiles));
if (profiles) {
PRUint32 count;
profiles->Count(&count);
*aResult = count > 0;
}
else
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetSourceHasMultipleProfiles(PRBool* aResult)
{
nsCOMPtr<nsISupportsArray> profiles;
GetSourceProfiles(getter_AddRefs(profiles));
if (profiles) {
PRUint32 count;
profiles->Count(&count);
*aResult = count > 1;
}
else
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
{
if (!mProfileNames && !mProfileLocations) {
mProfileNames = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
mProfileLocations = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
NS_ENSURE_TRUE(mProfileNames && mProfileLocations, NS_ERROR_UNEXPECTED);
// Fills mProfileNames and mProfileLocations
FillProfileDataFromSeamonkeyRegistry();
}
NS_IF_ADDREF(*aResult = mProfileNames);
return NS_OK;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
{
// Load the source pref file
nsCOMPtr<nsIPrefService> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
psvc->ResetPrefs();
nsCOMPtr<nsIFile> sourcePrefsFile;
mSourceProfile->Clone(getter_AddRefs(sourcePrefsFile));
sourcePrefsFile->Append(FILE_NAME_PREFS);
psvc->ReadUserPrefs(sourcePrefsFile);
nsCOMPtr<nsIPrefBranch> branch(do_QueryInterface(psvc));
PRBool hasUserValue;
nsCOMPtr<nsIPrefLocalizedString> prefValue;
nsresult rv = branch->PrefHasUserValue("browser.startup.homepage", &hasUserValue);
if (NS_SUCCEEDED(rv) && hasUserValue) {
rv = branch->GetComplexValue("browser.startup.homepage",
NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(prefValue));
if (NS_SUCCEEDED(rv) && prefValue) {
nsString data;
prefValue->ToString(getter_Copies(data));
nsCAutoString val;
val = ToNewCString(NS_ConvertUTF16toUTF8(data));
aResult.Assign(val);
}
}
psvc->ResetPrefs();
psvc->ReadUserPrefs(nsnull);
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsSeamonkeyProfileMigrator
nsresult
nsSeamonkeyProfileMigrator::GetSourceProfile(const PRUnichar* aProfile)
{
PRUint32 count;
mProfileNames->Count(&count);
for (PRUint32 i = 0; i < count; ++i) {
nsCOMPtr<nsISupportsString> str;
mProfileNames->QueryElementAt(i, NS_GET_IID(nsISupportsString),
getter_AddRefs(str));
nsString profileName;
str->GetData(profileName);
if (profileName.Equals(aProfile)) {
mProfileLocations->QueryElementAt(i, NS_GET_IID(nsILocalFile),
getter_AddRefs(mSourceProfile));
break;
}
}
return NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::FillProfileDataFromSeamonkeyRegistry()
{
// Find the Seamonkey Registry
nsCOMPtr<nsIProperties> fileLocator(do_GetService("@mozilla.org/file/directory_service;1"));
nsCOMPtr<nsILocalFile> seamonkeyRegistry;
#ifdef XP_WIN
fileLocator->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
seamonkeyRegistry->Append(NS_LITERAL_STRING("Mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("registry.dat"));
#elif defined(XP_MACOSX)
fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
seamonkeyRegistry->Append(NS_LITERAL_STRING("Mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("Application Registry"));
#elif defined(XP_UNIX)
fileLocator->Get(NS_UNIX_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
seamonkeyRegistry->Append(NS_LITERAL_STRING(".mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("appreg"));
#elif defined(XP_OS2)
fileLocator->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
seamonkeyRegistry->Append(NS_LITERAL_STRING("Mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("registry.dat"));
#endif
return GetProfileDataFromRegistry(seamonkeyRegistry, mProfileNames, mProfileLocations);
}
#define F(a) nsSeamonkeyProfileMigrator::a
#define MAKEPREFTRANSFORM(pref, newpref, getmethod, setmethod) \
{ pref, newpref, F(Get##getmethod), F(Set##setmethod), PR_FALSE, { -1 } }
#define MAKESAMETYPEPREFTRANSFORM(pref, method) \
{ pref, 0, F(Get##method), F(Set##method), PR_FALSE, { -1 } }
static
nsSeamonkeyProfileMigrator::PrefTransform gTransforms[] = {
MAKESAMETYPEPREFTRANSFORM("signon.SignonFileName", String),
MAKESAMETYPEPREFTRANSFORM("browser.tabs.autoHide", Bool),
MAKESAMETYPEPREFTRANSFORM("browser.tabs.loadInBackground", Bool),
MAKESAMETYPEPREFTRANSFORM("browser.enable_automatic_image_resizing", Bool),
MAKESAMETYPEPREFTRANSFORM("network.cookie.warnAboutCookies", Bool),
MAKESAMETYPEPREFTRANSFORM("network.cookie.lifetime.enabled", Bool),
MAKESAMETYPEPREFTRANSFORM("network.cookie.lifetime.behavior", Int),
MAKESAMETYPEPREFTRANSFORM("dom.disable_open_during_load", Bool),
MAKESAMETYPEPREFTRANSFORM("signon.rememberSignons", Bool),
MAKESAMETYPEPREFTRANSFORM("security.enable_ssl3", Bool),
MAKESAMETYPEPREFTRANSFORM("security.enable_tls", Bool),
MAKESAMETYPEPREFTRANSFORM("security.warn_entering_secure", Bool),
MAKESAMETYPEPREFTRANSFORM("security.warn_entering_weak", Bool),
MAKESAMETYPEPREFTRANSFORM("security.warn_leaving_secure", Bool),
MAKESAMETYPEPREFTRANSFORM("security.warn_submit_insecure", Bool),
MAKESAMETYPEPREFTRANSFORM("security.warn_viewing_mixed", Bool),
MAKESAMETYPEPREFTRANSFORM("security.default_personal_cert", String),
MAKESAMETYPEPREFTRANSFORM("security.OSCP.enabled", Int),
MAKESAMETYPEPREFTRANSFORM("security.OSCP.signingCA", String),
MAKESAMETYPEPREFTRANSFORM("security.OSCP.URL", String),
MAKESAMETYPEPREFTRANSFORM("javascript.enabled", Bool),
MAKESAMETYPEPREFTRANSFORM("dom.disable_window_move_resize", Bool),
MAKESAMETYPEPREFTRANSFORM("dom.disable_window_flip", Bool),
MAKESAMETYPEPREFTRANSFORM("dom.disable_window_open_feature.status", Bool),
MAKESAMETYPEPREFTRANSFORM("dom.disable_window_status_change", Bool),
MAKESAMETYPEPREFTRANSFORM("dom.disable_image_src_set", Bool),
MAKESAMETYPEPREFTRANSFORM("accessibility.typeaheadfind.autostart", Bool),
MAKESAMETYPEPREFTRANSFORM("accessibility.typeaheadfind.linksonly", Bool),
MAKESAMETYPEPREFTRANSFORM("network.proxy.type", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.http", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.http_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ftp", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ftp_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ssl", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ssl_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.socks", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.socks_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.no_proxies_on", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.autoconfig_url", String),
MAKESAMETYPEPREFTRANSFORM("browser.display.foreground_color", String),
MAKESAMETYPEPREFTRANSFORM("browser.display.background_color", String),
MAKESAMETYPEPREFTRANSFORM("browser.anchor_color", String),
MAKESAMETYPEPREFTRANSFORM("browser.visited_color", String),
MAKESAMETYPEPREFTRANSFORM("browser.underline_anchors", Bool),
MAKESAMETYPEPREFTRANSFORM("browser.display.use_system_colors", Bool),
MAKESAMETYPEPREFTRANSFORM("browser.display.use_document_colors", Bool),
MAKESAMETYPEPREFTRANSFORM("browser.display.use_document_fonts", Bool),
MAKESAMETYPEPREFTRANSFORM("intl.charset.default", String),
MAKESAMETYPEPREFTRANSFORM("intl.accept_languages", String),
MAKEPREFTRANSFORM("network.image.imageBehavior", 0, Int, Image),
MAKEPREFTRANSFORM("network.cookie.cookieBehavior", 0, Int, Cookie),
MAKEPREFTRANSFORM("browser.downloadmanager.behavior", 0, Int, DownloadManager),
MAKEPREFTRANSFORM("wallet.captureForms", "formfill.enabled", Bool, Bool)
};
nsresult
nsSeamonkeyProfileMigrator::SetImage(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
nsresult rv = NS_OK;
if (xform->prefHasValue)
rv = aBranch->SetIntPref("network.image.imageBehavior", xform->intValue == 1 ? 0 : xform->intValue);
return rv;
}
nsresult
nsSeamonkeyProfileMigrator::SetCookie(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
nsresult rv = NS_OK;
if (xform->prefHasValue)
rv = aBranch->SetIntPref("network.cookie.cookieBehavior", xform->intValue == 3 ? 0 : xform->intValue);
return rv;
}
nsresult
nsSeamonkeyProfileMigrator::SetDownloadManager(void* aTransform, nsIPrefBranch* aBranch)
{
PrefTransform* xform = (PrefTransform*)aTransform;
nsresult rv = NS_OK;
if (xform->prefHasValue) {
// Seamonkey's download manager uses a single pref to control behavior:
// 0 - show download manager window
// 1 - show individual progress dialogs
// 2 - show nothing
//
// Firefox has only a download manager window, but it can behave like a progress dialog, thus:
// 0 || 1 -> show downloads window when a download starts
// 2 -> don't show anything when a download starts
// 1 -> close the downloads window as if it were a progress window when downloads complete.
//
rv |= aBranch->SetBoolPref("browser.download.manager.showWhenStarting", xform->intValue != 2);
rv |= aBranch->SetBoolPref("browser.download.manager.closeWhenDone", xform->intValue == 1);
}
return NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::TransformPreferences(const nsAString& aSourcePrefFileName,
const nsAString& aTargetPrefFileName)
{
PrefTransform* transform;
PrefTransform* end = gTransforms + sizeof(gTransforms)/sizeof(PrefTransform);
// Load the source pref file
nsCOMPtr<nsIPrefService> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
psvc->ResetPrefs();
nsCOMPtr<nsIFile> sourcePrefsFile;
mSourceProfile->Clone(getter_AddRefs(sourcePrefsFile));
sourcePrefsFile->Append(aSourcePrefFileName);
psvc->ReadUserPrefs(sourcePrefsFile);
nsCOMPtr<nsIPrefBranch> branch(do_QueryInterface(psvc));
for (transform = gTransforms; transform < end; ++transform)
transform->prefGetterFunc(transform, branch);
nsTArray<FontPref> fontPrefs;
ReadFontsBranch(psvc, &fontPrefs);
// Now that we have all the pref data in memory, load the target pref file,
// and write it back out
psvc->ResetPrefs();
for (transform = gTransforms; transform < end; ++transform)
transform->prefSetterFunc(transform, branch);
WriteFontsBranch(psvc, &fontPrefs);
nsCOMPtr<nsIFile> targetPrefsFile;
mTargetProfile->Clone(getter_AddRefs(targetPrefsFile));
targetPrefsFile->Append(aTargetPrefFileName);
psvc->SavePrefFile(targetPrefsFile);
psvc->ResetPrefs();
psvc->ReadUserPrefs(nsnull);
return NS_OK;
}
void
nsSeamonkeyProfileMigrator::ReadFontsBranch(nsIPrefService* aPrefService,
nsTArray<FontPref>* aPrefs)
{
// Enumerate the branch
nsCOMPtr<nsIPrefBranch> branch;
aPrefService->GetBranch("font.", getter_AddRefs(branch));
PRUint32 count;
char** prefs = nsnull;
nsresult rv = branch->GetChildList("", &count, &prefs);
if (NS_FAILED(rv)) return;
for (PRUint32 i = 0; i < count; ++i) {
// Save each pref's value into an array
char* currPref = prefs[i];
PRInt32 type;
branch->GetPrefType(currPref, &type);
FontPref* pref = aPrefs->AppendElement();
pref->prefName = currPref;
pref->type = type;
switch (type) {
case nsIPrefBranch::PREF_STRING:
rv = branch->GetCharPref(currPref, &pref->stringValue);
break;
case nsIPrefBranch::PREF_BOOL:
rv = branch->GetBoolPref(currPref, &pref->boolValue);
break;
case nsIPrefBranch::PREF_INT:
rv = branch->GetIntPref(currPref, &pref->intValue);
break;
case nsIPrefBranch::PREF_INVALID:
{
nsCOMPtr<nsIPrefLocalizedString> str;
rv = branch->GetComplexValue(currPref,
NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(str));
if (NS_SUCCEEDED(rv) && str)
str->ToString(&pref->wstringValue);
}
break;
}
if (NS_FAILED(rv))
aPrefs->RemoveElementAt(aPrefs->Length()-1);
}
}
void
nsSeamonkeyProfileMigrator::WriteFontsBranch(nsIPrefService* aPrefService,
nsTArray<FontPref>* aPrefs)
{
nsresult rv;
// Enumerate the branch
nsCOMPtr<nsIPrefBranch> branch;
aPrefService->GetBranch("font.", getter_AddRefs(branch));
PRUint32 count = aPrefs->Length();
for (PRUint32 i = 0; i < count; ++i) {
FontPref &pref = aPrefs->ElementAt(i);
switch (pref.type) {
case nsIPrefBranch::PREF_STRING:
rv = branch->SetCharPref(pref.prefName, pref.stringValue);
NS_Free(pref.stringValue);
pref.stringValue = nsnull;
break;
case nsIPrefBranch::PREF_BOOL:
rv = branch->SetBoolPref(pref.prefName, pref.boolValue);
break;
case nsIPrefBranch::PREF_INT:
rv = branch->SetIntPref(pref.prefName, pref.intValue);
break;
case nsIPrefBranch::PREF_INVALID:
nsCOMPtr<nsIPrefLocalizedString> pls(do_CreateInstance("@mozilla.org/pref-localizedstring;1"));
pls->SetData(pref.wstringValue);
rv = branch->SetComplexValue(pref.prefName,
NS_GET_IID(nsIPrefLocalizedString),
pls);
NS_Free(pref.wstringValue);
pref.wstringValue = nsnull;
break;
}
NS_Free(pref.prefName);
}
aPrefs->Clear();
}
nsresult
nsSeamonkeyProfileMigrator::CopyPreferences(PRBool aReplace)
{
nsresult rv = NS_OK;
if (!aReplace)
return rv;
rv |= TransformPreferences(FILE_NAME_PREFS, FILE_NAME_PREFS);
rv |= CopyFile(FILE_NAME_USER_PREFS, FILE_NAME_USER_PREFS);
// Security Stuff
rv |= CopyFile(FILE_NAME_CERT8DB, FILE_NAME_CERT8DB);
rv |= CopyFile(FILE_NAME_KEY3DB, FILE_NAME_KEY3DB);
rv |= CopyFile(FILE_NAME_SECMODDB, FILE_NAME_SECMODDB);
// User MIME Type overrides
rv |= CopyFile(FILE_NAME_MIMETYPES, FILE_NAME_MIMETYPES);
rv |= CopyUserContentSheet();
return rv;
}
nsresult
nsSeamonkeyProfileMigrator::CopyUserContentSheet()
{
nsCOMPtr<nsIFile> sourceUserContent;
mSourceProfile->Clone(getter_AddRefs(sourceUserContent));
sourceUserContent->Append(DIR_NAME_CHROME);
sourceUserContent->Append(FILE_NAME_USERCONTENT);
PRBool exists = PR_FALSE;
sourceUserContent->Exists(&exists);
if (!exists)
return NS_OK;
nsCOMPtr<nsIFile> targetUserContent;
mTargetProfile->Clone(getter_AddRefs(targetUserContent));
targetUserContent->Append(DIR_NAME_CHROME);
nsCOMPtr<nsIFile> targetChromeDir;
targetUserContent->Clone(getter_AddRefs(targetChromeDir));
targetUserContent->Append(FILE_NAME_USERCONTENT);
targetUserContent->Exists(&exists);
if (exists)
targetUserContent->Remove(PR_FALSE);
return sourceUserContent->CopyTo(targetChromeDir, FILE_NAME_USERCONTENT);
}
nsresult
nsSeamonkeyProfileMigrator::CopyCookies(PRBool aReplace)
{
nsresult rv;
if (aReplace)
rv = CopyFile(FILE_NAME_COOKIES, FILE_NAME_COOKIES);
else {
nsCOMPtr<nsIFile> seamonkeyCookiesFile;
mSourceProfile->Clone(getter_AddRefs(seamonkeyCookiesFile));
seamonkeyCookiesFile->Append(FILE_NAME_COOKIES);
rv = ImportNetscapeCookies(seamonkeyCookiesFile);
}
return rv;
}
nsresult
nsSeamonkeyProfileMigrator::CopyPasswords(PRBool aReplace)
{
nsresult rv;
nsCString signonsFileName;
GetSignonFileName(aReplace, getter_Copies(signonsFileName));
if (signonsFileName.IsEmpty())
return NS_ERROR_FILE_NOT_FOUND;
NS_ConvertASCIItoUTF16 fileName(signonsFileName);
if (aReplace)
rv = CopyFile(fileName, fileName);
else {
// Get the password manager, which is the destination for the passwords
// being migrated. Also create a new instance of the legacy password
// storage component, which we'll use to slurp in the signons from
// Seamonkey's signons.txt.
nsCOMPtr<nsILoginManager> pwmgr(
do_GetService("@mozilla.org/login-manager;1"));
nsCOMPtr<nsILoginManagerStorage> importer(
do_CreateInstance("@mozilla.org/login-manager/storage/legacy;1"));
nsCOMPtr<nsIFile> signonsFile;
mSourceProfile->Clone(getter_AddRefs(signonsFile));
signonsFile->Append(fileName);
importer->InitWithFile(signonsFile, nsnull);
PRUint32 count;
nsILoginInfo **logins;
rv = importer->GetAllLogins(&count, &logins);
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < count; i++) {
pwmgr->AddLogin(logins[i]);
}
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, logins);
PRUnichar **hostnames;
rv = importer->GetAllDisabledHosts(&count, &hostnames);
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < count; i++) {
pwmgr->SetLoginSavingEnabled(nsDependentString(hostnames[i]),
PR_FALSE);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, hostnames);
}
return rv;
}
nsresult
nsSeamonkeyProfileMigrator::CopyBookmarks(PRBool aReplace)
{
nsresult rv;
if (aReplace) {
// Initialize the default bookmarks
rv = InitializeBookmarks(mTargetProfile);
NS_ENSURE_SUCCESS(rv, rv);
// Merge in the bookmarks from the source profile
nsCOMPtr<nsIFile> sourceFile;
mSourceProfile->Clone(getter_AddRefs(sourceFile));
sourceFile->Append(FILE_NAME_BOOKMARKS);
rv = ImportBookmarksHTML(sourceFile, PR_TRUE, PR_FALSE, EmptyString().get());
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = ImportNetscapeBookmarks(FILE_NAME_BOOKMARKS,
NS_LITERAL_STRING("sourceNameSeamonkey").get());
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::CopyOtherData(PRBool aReplace)
{
return aReplace ? CopyFile(FILE_NAME_DOWNLOADS, FILE_NAME_DOWNLOADS) : NS_OK;
}

View File

@ -1,105 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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 The Browser Profile Migrator.
*
* The Initial Developer of the Original Code is Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@bengoodger.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 ***** */
#ifndef seamonkeyprofilemigrator___h___
#define seamonkeyprofilemigrator___h___
#include "nsIBrowserProfileMigrator.h"
#include "nsILocalFile.h"
#include "nsIObserverService.h"
#include "nsISupportsArray.h"
#include "nsNetscapeProfileMigratorBase.h"
#include "nsStringAPI.h"
#include "nsTArray.h"
class nsIFile;
class nsIPrefBranch;
class nsIPrefService;
struct FontPref {
char* prefName;
PRInt32 type;
union {
char* stringValue;
PRInt32 intValue;
PRBool boolValue;
PRUnichar* wstringValue;
};
};
class nsSeamonkeyProfileMigrator : public nsNetscapeProfileMigratorBase,
public nsIBrowserProfileMigrator
{
public:
NS_DECL_NSIBROWSERPROFILEMIGRATOR
NS_DECL_ISUPPORTS
nsSeamonkeyProfileMigrator();
virtual ~nsSeamonkeyProfileMigrator();
public:
static nsresult SetImage(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetCookie(void* aTransform, nsIPrefBranch* aBranch);
static nsresult SetDownloadManager(void* aTransform, nsIPrefBranch* aBranch);
protected:
nsresult FillProfileDataFromSeamonkeyRegistry();
nsresult GetSourceProfile(const PRUnichar* aProfile);
nsresult CopyPreferences(PRBool aReplace);
nsresult TransformPreferences(const nsAString& aSourcePrefFileName,
const nsAString& aTargetPrefFileName);
void ReadFontsBranch(nsIPrefService* aPrefService,
nsTArray<FontPref>* aPrefs);
void WriteFontsBranch(nsIPrefService* aPrefService,
nsTArray<FontPref>* aPrefs);
nsresult CopyUserContentSheet();
nsresult CopyCookies(PRBool aReplace);
nsresult CopyPasswords(PRBool aReplace);
nsresult LocateSignonsFile(char** aResult);
nsresult CopyBookmarks(PRBool aReplace);
nsresult CopyOtherData(PRBool aReplace);
private:
nsCOMPtr<nsISupportsArray> mProfileNames;
nsCOMPtr<nsISupportsArray> mProfileLocations;
nsCOMPtr<nsIObserverService> mObserverService;
};
#endif

View File

@ -277,17 +277,30 @@ var PlacesOrganizer = {
* the node to set up scope from
*/
_setSearchScopeForNode: function PO__setScopeForNode(aNode) {
var itemId = aNode.itemId;
let itemId = aNode.itemId;
// Set default buttons status.
let bookmarksButton = document.getElementById("scopeBarAll");
bookmarksButton.hidden = false;
let downloadsButton = document.getElementById("scopeBarDownloads");
downloadsButton.hidden = true;
if (PlacesUtils.nodeIsHistoryContainer(aNode) ||
itemId == PlacesUIUtils.leftPaneQueries["History"]) {
PlacesQueryBuilder.setScope("history");
}
// Default to All Bookmarks for all other nodes, per bug 469437.
else
else if (itemId == PlacesUIUtils.leftPaneQueries["Downloads"]) {
downloadsButton.hidden = false;
bookmarksButton.hidden = true;
PlacesQueryBuilder.setScope("downloads");
}
else {
// Default to All Bookmarks for all other nodes, per bug 469437.
PlacesQueryBuilder.setScope("bookmarks");
}
// Enable or disable the folder scope button.
var folderButton = document.getElementById("scopeBarFolder");
let folderButton = document.getElementById("scopeBarFolder");
folderButton.hidden = !PlacesUtils.nodeIsFolder(aNode) ||
itemId == PlacesUIUtils.allBookmarksFolderId;
},
@ -901,9 +914,21 @@ var PlacesSearchBox = {
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
content.load([query], options);
}
else
else {
content.applyFilter(filterString);
}
break;
case "downloads": {
let query = PlacesUtils.history.getNewQuery();
query.searchTerms = filterString;
query.setTransitions([Ci.nsINavHistoryService.TRANSITION_DOWNLOAD], 1);
let options = currentOptions.clone();
// Make sure we're getting uri results.
options.resultType = currentOptions.RESULT_TYPE_URI;
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
content.load([query], options);
break;
}
default:
throw "Invalid filterCollection on search";
break;
@ -933,17 +958,28 @@ var PlacesSearchBox = {
/**
* Updates the display with the title of the current collection.
* @param title
* @param aTitle
* The title of the current collection.
*/
updateCollectionTitle: function PSB_updateCollectionTitle(title) {
if (title)
this.searchFilter.placeholder =
PlacesUIUtils.getFormattedString("searchCurrentDefault", [title]);
else
this.searchFilter.placeholder = this.filterCollection == "history" ?
PlacesUIUtils.getString("searchHistory") :
PlacesUIUtils.getString("searchBookmarks");
updateCollectionTitle: function PSB_updateCollectionTitle(aTitle) {
let title = "";
if (aTitle) {
title = PlacesUIUtils.getFormattedString("searchCurrentDefault",
[aTitle]);
}
else {
switch(this.filterCollection) {
case "history":
title = PlacesUIUtils.getString("searchHistory");
break;
case "downloads":
title = PlacesUIUtils.getString("searchDownloads");
break;
default:
title = PlacesUIUtils.getString("searchBookmarks");
}
}
this.searchFilter.placeholder = title;
},
/**
@ -1025,6 +1061,9 @@ var PlacesQueryBuilder = {
case "scopeBarFolder":
this.setScope("collection");
break;
case "scopeBarDownloads":
this.setScope("downloads");
break;
case "scopeBarAll":
this.setScope("bookmarks");
break;
@ -1040,7 +1079,8 @@ var PlacesQueryBuilder = {
* PSB_search()). If there is an active search, it's performed again to
* update the content tree.
* @param aScope
* the search scope, "bookmarks", "collection", or "history"
* The search scope: "bookmarks", "collection", "downloads" or
* "history".
*/
setScope: function PQB_setScope(aScope) {
// Determine filterCollection, folders, and scopeButtonId based on aScope.
@ -1072,6 +1112,10 @@ var PlacesQueryBuilder = {
PlacesUtils.toolbarFolderId,
PlacesUtils.unfiledBookmarksFolderId);
break;
case "downloads":
filterCollection = "downloads";
scopeButtonId = "scopeBarDownloads";
break;
default:
throw "Invalid search scope";
break;

View File

@ -412,18 +412,16 @@
oncommand="PlacesQueryBuilder.onScopeSelected(this);"
label="&search.scopeBookmarks.label;"
accesskey="&search.scopeBookmarks.accesskey;"/>
<!--
<toolbarbutton id="scopeBarDownloads" class="small-margin"
type="radio" group="scopeBar"
oncommand="PlacesQueryBuilder.onScopeSelected(this);"
label="&search.scopeDownloads.label;"
accesskey="&search.scopeDownloads.accesskey;"/>
-->
<toolbarbutton id="scopeBarHistory" class="small-margin"
type="radio" group="scopeBar"
oncommand="PlacesQueryBuilder.onScopeSelected(this);"
label="&search.scopeHistory.label;"
accesskey="&search.scopeHistory.accesskey;"/>
<toolbarbutton id="scopeBarDownloads" class="small-margin"
type="radio" group="scopeBar"
oncommand="PlacesQueryBuilder.onScopeSelected(this);"
label="&search.scopeDownloads.label;"
accesskey="&search.scopeDownloads.accesskey;"/>
<toolbarbutton id="scopeBarFolder" class="small-margin"
type="radio" group="scopeBar"
oncommand="PlacesQueryBuilder.onScopeSelected(this);"

View File

@ -139,18 +139,3 @@ let tests = {
is(unsortedNode.uri, MOZURISPEC, "node uri's are the same");
},
};
/**
* Clears history invoking callback when done.
*/
function waitForClearHistory(aCallback) {
const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
let observer = {
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
aCallback();
}
};
Services.obs.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}

View File

@ -37,25 +37,6 @@
// This test makes sure that the Forget This Site command is hidden for multiple
// selections.
/**
* Clears history invoking callback when done.
*/
function waitForClearHistory(aCallback) {
const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
let observer = {
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
aCallback();
}
};
Services.obs.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
hs.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
}
function test() {
// initialization
waitForExplicitFinish();

View File

@ -48,20 +48,6 @@ function uri(spec) {
return ios.newURI(spec, null, null);
}
/**
* Clears history invoking callback when done.
*/
function waitForClearHistory(aCallback) {
let observer = {
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
aCallback(aSubject, aTopic, aData);
}
};
Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}
var sidebar = document.getElementById("sidebar");
function add_visit(aURI, aDate) {

View File

@ -83,14 +83,3 @@ function test() {
openLibrary(onLibraryReady);
}
function waitForClearHistory(aCallback) {
let observer = {
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
aCallback(aSubject, aTopic, aData);
}
};
Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}

View File

@ -61,67 +61,74 @@
*/
const TEST_URL = "http://dummy.mozilla.org/";
const TEST_DOWNLOAD_URL = "http://dummy.mozilla.org/dummy.pdf";
// Add your tests here. Each is a function that's called by testHelper().
var testCases = [
let gLibrary;
// All Bookmarks
function () {
var defScope = getDefaultScope(PlacesUIUtils.allBookmarksFolderId);
let testCases = [
function allBookmarksScope() {
let defScope = getDefaultScope(PlacesUIUtils.allBookmarksFolderId);
search(PlacesUIUtils.allBookmarksFolderId, "dummy", defScope);
is(selectScope("scopeBarFolder"), false,
ok(!selectScope("scopeBarFolder"),
"Folder scope should be disabled for All Bookmarks");
resetSearch(defScope);
ok(selectScope("scopeBarAll"),
"Bookmarks scope should be enabled for All Bookmarks");
resetSearch("scopeBarAll");
},
// History
function () {
var defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["History"]);
function historyScope() {
let defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["History"]);
search(PlacesUIUtils.leftPaneQueries["History"], "dummy", defScope);
is(selectScope("scopeBarFolder"), false,
ok(!selectScope("scopeBarFolder"),
"Folder scope should be disabled for History");
ok(selectScope("scopeBarAll"),
"Bookmarks scope should be enabled for History");
resetSearch("scopeBarAll");
},
function downloadsScope() {
let defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["Downloads"]);
search(PlacesUIUtils.leftPaneQueries["Downloads"], "dummy", defScope);
ok(!selectScope("scopeBarFolder"),
"Folder scope should be disabled for Downloads");
ok(!selectScope("scopeBarAll"),
"Bookmarks scope should be disabled for Downloads");
resetSearch(defScope);
},
// Toolbar folder
function () {
var defScope = getDefaultScope(bmsvc.toolbarFolder);
search(bmsvc.toolbarFolder, "dummy", defScope);
is(selectScope("scopeBarFolder"), true,
function toolbarFolderScope() {
let defScope = getDefaultScope(PlacesUtils.toolbarFolderId);
search(PlacesUtils.toolbarFolderId, "dummy", defScope);
ok(selectScope("scopeBarAll"),
"Bookmarks scope should be enabled for toolbar folder");
ok(selectScope("scopeBarFolder"),
"Folder scope should be enabled for toolbar folder");
// Ensure that folder scope is still selected after resetting and searching
// again.
resetSearch("scopeBarFolder");
search(bmsvc.toolbarFolder, "dummy", "scopeBarFolder");
search(PlacesUtils.toolbarFolderId, "dummy", "scopeBarFolder");
},
// A regular non-root subfolder
function () {
var folderId = bmsvc.createFolder(bmsvc.toolbarFolder,
"dummy folder",
bmsvc.DEFAULT_INDEX);
var defScope = getDefaultScope(folderId);
function subFolderScope() {
let folderId = PlacesUtils.bookmarks.createFolder(PlacesUtils.toolbarFolderId,
"dummy folder",
PlacesUtils.bookmarks.DEFAULT_INDEX);
let defScope = getDefaultScope(folderId);
search(folderId, "dummy", defScope);
is(selectScope("scopeBarFolder"), true,
ok(selectScope("scopeBarAll"),
"Bookmarks scope should be enabled for regularfolder");
ok(selectScope("scopeBarFolder"),
"Folder scope should be enabled for regular subfolder");
// Ensure that folder scope is still selected after resetting and searching
// again.
resetSearch("scopeBarFolder");
search(folderId, "dummy", "scopeBarFolder");
bmsvc.removeItem(folderId);
PlacesUtils.bookmarks.removeItem(folderId);
},
];
///////////////////////////////////////////////////////////////////////////////
var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
var libraryWin;
///////////////////////////////////////////////////////////////////////////////
/**
* Returns the default search scope for a given folder.
*
@ -130,9 +137,14 @@ var libraryWin;
* @return the default scope when the folder is newly selected
*/
function getDefaultScope(aFolderId) {
return aFolderId === PlacesUIUtils.leftPaneQueries["History"] ?
"scopeBarHistory" :
"scopeBarAll";
switch (aFolderId) {
case PlacesUIUtils.leftPaneQueries["History"]:
return "scopeBarHistory"
case PlacesUIUtils.leftPaneQueries["Downloads"]:
return "scopeBarDownloads";
default:
return "scopeBarAll";
}
}
/**
@ -141,8 +153,8 @@ function getDefaultScope(aFolderId) {
* @return the ID of the selected scope folder button
*/
function getSelectedScopeButtonId() {
var doc = libraryWin.document;
var scopeButtons = doc.getElementById("organizerScopeBar").childNodes;
let doc = gLibrary.document;
let scopeButtons = doc.getElementById("organizerScopeBar").childNodes;
for (let i = 0; i < scopeButtons.length; i++) {
if (scopeButtons[i].checked)
return scopeButtons[i].id;
@ -158,8 +170,8 @@ function getSelectedScopeButtonId() {
* @return an nsINavHistoryQuery object
*/
function queryStringToQuery(aPlaceURI) {
var queries = {};
histsvc.queryStringToQueries(aPlaceURI, queries, {}, {});
let queries = {};
PlacesUtils.history.queryStringToQueries(aPlaceURI, queries, {}, {});
return queries.value[0];
}
@ -188,9 +200,9 @@ function resetSearch(aExpectedScopeButtonId) {
* after searching the selected scope button should be this
*/
function search(aFolderId, aSearchStr, aExpectedScopeButtonId) {
var doc = libraryWin.document;
var folderTree = doc.getElementById("placesList");
var contentTree = doc.getElementById("placeContent");
let doc = gLibrary.document;
let folderTree = doc.getElementById("placesList");
let contentTree = doc.getElementById("placeContent");
// First, ensure that selecting the folder in the left pane updates the
// content tree properly.
@ -201,10 +213,11 @@ function search(aFolderId, aSearchStr, aExpectedScopeButtonId) {
// getFolders() on a History query returns an empty array, so no use
// comparing against aFolderId in that case.
if (aFolderId !== PlacesUIUtils.leftPaneQueries["History"]) {
if (aFolderId !== PlacesUIUtils.leftPaneQueries["History"] &&
aFolderId !== PlacesUIUtils.leftPaneQueries["Downloads"]) {
// contentTree.place should be equal to contentTree.result.root.uri,
// but it's not until bug 476952 is fixed.
var query = queryStringToQuery(contentTree.result.root.uri);
let query = queryStringToQuery(contentTree.result.root.uri);
is(query.getFolders()[0], aFolderId,
"Content tree's folder should be what was selected in the left pane");
}
@ -212,27 +225,41 @@ function search(aFolderId, aSearchStr, aExpectedScopeButtonId) {
// Second, ensure that searching updates the content tree and search UI
// properly.
var searchBox = doc.getElementById("searchFilter");
let searchBox = doc.getElementById("searchFilter");
searchBox.value = aSearchStr;
libraryWin.PlacesSearchBox.search(searchBox.value);
query = queryStringToQuery(contentTree.result.root.uri);
gLibrary.PlacesSearchBox.search(searchBox.value);
let query = queryStringToQuery(contentTree.result.root.uri);
if (aSearchStr) {
is(query.searchTerms, aSearchStr,
"Content tree's searchTerms should be text in search box");
is(doc.getElementById("searchModifiers").hidden, false,
"Scope bar should not be hidden after searching");
if (getSelectedScopeButtonId() == "scopeBarHistory" ||
getSelectedScopeButtonId() == "scopeBarAll" ||
aFolderId == PlacesUtils.bookmarks.unfiledBookmarksFolder) {
let scopeButtonId = getSelectedScopeButtonId();
if (scopeButtonId == "scopeBarDownloads" ||
scopeButtonId == "scopeBarHistory" ||
scopeButtonId == "scopeBarAll" ||
aFolderId == PlacesUtils.unfiledBookmarksFolderId) {
// Check that the target node exists in the tree's search results.
var node = null;
for (var i = 0; i < contentTree.view.rowCount; i++) {
let url, count;
if (scopeButtonId == "scopeBarDownloads") {
url = TEST_DOWNLOAD_URL;
count = 1;
}
else {
url = TEST_URL;
count = scopeButtonId == "scopeBarHistory" ? 2 : 1;
}
is(contentTree.view.rowCount, count, "Found correct number of results");
let node = null;
for (let i = 0; i < contentTree.view.rowCount; i++) {
node = contentTree.view.nodeForTreeIndex(i);
if (node.uri === TEST_URL)
if (node.uri === url)
break;
}
isnot(node, null, "At least the target node should be in the tree");
is(node.uri, TEST_URL, "URI of node should match target URL");
is(node.uri, url, "URI of node should match target URL");
}
}
else {
@ -253,10 +280,10 @@ function search(aFolderId, aSearchStr, aExpectedScopeButtonId) {
* @return true if the button is enabled, false otherwise
*/
function selectScope(aScopeButtonId) {
var doc = libraryWin.document;
var button = doc.getElementById(aScopeButtonId);
let doc = gLibrary.document;
let button = doc.getElementById(aScopeButtonId);
isnot(button, null,
"Sanity check: scope button with ID " + aScopeButtonId + "should exist");
"Sanity check: scope button with ID " + aScopeButtonId + " should exist");
// Bug 469436 may hide an inappropriate scope button instead of disabling it.
if (button.disabled || button.hidden)
return false;
@ -267,21 +294,17 @@ function selectScope(aScopeButtonId) {
/**
* test() contains window-launching boilerplate that calls this to really kick
* things off. Add functions to the testCases array, and this will call them.
*
* @param aLibraryWin
* the Places Library window
*/
function testHelper(aLibraryWin) {
libraryWin = aLibraryWin;
function onLibraryAvailable() {
testCases.forEach(function (aTest) aTest());
aLibraryWin.close();
gLibrary.close();
gLibrary = null;
// Cleanup.
PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.unfiledBookmarksFolder);
PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
finish();
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
waitForClearHistory(finish);
}
///////////////////////////////////////////////////////////////////////////////
@ -291,15 +314,19 @@ function test() {
// Sanity:
ok(PlacesUtils, "PlacesUtils in context");
// Add a visit, a bookmark and a tag.
// Add visits, a bookmark and a tag.
PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_URL),
Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_TYPED, false, 0);
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.unfiledBookmarksFolder,
PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_DOWNLOAD_URL),
Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_DOWNLOAD, false, 0);
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
PlacesUtils._uri(TEST_URL),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"dummy");
PlacesUtils.tagging.tagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
openLibrary(testHelper);
gLibrary = openLibrary(onLibraryAvailable);
}

View File

@ -173,14 +173,6 @@ function test() {
sidebar.contentDocument.documentElement.style.direction = aDirection;
}
function waitForClearHistory(aCallback) {
Services.obs.addObserver(function(aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
aCallback(aSubject, aTopic, aData);
}, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}
function runNextTest() {
// Remove eventual tabs created by previous sub-tests.
while (gBrowser.tabs.length > 1) {

View File

@ -59,7 +59,7 @@ window.onload = function() {
gStateObject = JSON.parse(sessionData.value);
}
catch (exJSON) {
var s = new Cu.Sandbox("about:blank");
var s = new Cu.Sandbox("about:blank", {sandboxName: 'aboutSessionRestore'});
gStateObject = Cu.evalInSandbox("(" + sessionData.value + ")", s);
// If we couldn't parse the string with JSON.parse originally, make sure
// that the value in the textbox will be parsable.

View File

@ -135,7 +135,7 @@ SessionStartup.prototype = {
this._initialState = JSON.parse(iniString);
}
catch (exJSON) {
var s = new Cu.Sandbox("about:blank");
var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
}

View File

@ -4014,7 +4014,7 @@ SessionStoreService.prototype = {
this._restoreCount = -1;
},
/**
/**
* Set the given window's busy state
* @param aWindow the window
* @param aValue the window's busy state

View File

@ -178,7 +178,8 @@ var Scratchpad = {
this._previousLocation != this.gBrowser.contentWindow.location.href) {
let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
this._contentSandbox = new Cu.Sandbox(contentWindow,
{ sandboxPrototype: contentWindow, wantXrays: false });
{ sandboxPrototype: contentWindow, wantXrays: false,
sandboxName: 'scratchpad-content'});
this._previousBrowserWindow = this.browserWindow;
this._previousBrowser = this.gBrowser.selectedBrowser;
@ -211,7 +212,8 @@ var Scratchpad = {
if (!this._chromeSandbox ||
this.browserWindow != this._previousBrowserWindow) {
this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
{ sandboxPrototype: this.browserWindow, wantXrays: false });
{ sandboxPrototype: this.browserWindow, wantXrays: false,
sandboxName: 'scratchpad-chrome'});
this._previousBrowserWindow = this.browserWindow;
}

View File

@ -48,4 +48,4 @@ _BROWSER_TEST_FILES = \
browser_sourceeditor_initialization.js \
libs:: $(_BROWSER_TEST_FILES)
# $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -19,21 +19,15 @@ function test()
" title='test for bug 660784' width='600' height='500'><hbox flex='1'/></window>";
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onTabLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onTabLoad, true);
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", initEditor, false);
}, true);
content.location = "data:text/html,<p>bug 660784 - test the SourceEditor";
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", function onWindowLoad() {
testWin.removeEventListener("load", onWindowLoad, false);
waitForFocus(initEditor, testWin);
}, false);
}
function initEditor()
{
testWin.removeEventListener("load", initEditor, false);
testDoc = testWin.document;
let hbox = testDoc.querySelector("hbox");
@ -327,10 +321,7 @@ function editorLoaded()
testWin = testDoc = editor = null;
waitForFocus(function() {
gBrowser.removeCurrentTab();
finish();
}, content);
waitForFocus(finish, window);
}
function testBackspaceKey()

View File

@ -2708,6 +2708,12 @@ HUD_SERVICE.prototype =
let _browser = gBrowser.
getBrowserForDocument(aContentWindow.top.document);
// ignore newly created documents that don't belong to a tab's browser
if (!_browser) {
return;
}
let nBox = gBrowser.getNotificationBox(_browser);
let nBoxId = nBox.getAttribute("id");
let hudId = "hud_" + nBoxId;

View File

@ -144,6 +144,7 @@ _BROWSER_TEST_FILES = \
browser_webconsole_bug_651501_document_body_autocomplete.js \
browser_webconsole_bug_653531_highlighter_console_helper.js \
browser_webconsole_bug_659907_console_dir.js \
browser_webconsole_bug_678816.js \
head.js \
$(NULL)
@ -212,6 +213,7 @@ _BROWSER_TEST_PAGES = \
test-bug-644419-log-limits.html \
test-bug-632275-getters.html \
test-bug-646025-console-file-location.html \
test-bug-678816-content.js \
test-file-location.js \
$(NULL)

View File

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html";
const FRAME_SCRIPT_URI ="chrome://mochitests/content/browser/browser/devtools/webconsole/test/browser/test-bug-678816-content.js";
let HUD;
let outputItem;
function tabLoad1(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
HUD = HUDService.getHudByWindow(content);
browser.addEventListener("load", tabLoad2, true);
// Reload so we get some output in the console.
browser.contentWindow.location.reload();
}
function tabLoad2(aEvent) {
browser.removeEventListener(aEvent.type, tabLoad2, true);
outputItem = HUD.outputNode.querySelector(".hud-networkinfo .hud-clickable");
ok(outputItem, "found a network message");
document.addEventListener("popupshown", networkPanelShown, false);
// Click the network message to open the network panel.
EventUtils.synthesizeMouseAtCenter(outputItem, {});
}
function networkPanelShown(aEvent) {
document.removeEventListener(aEvent.type, networkPanelShown, false);
executeSoon(function() {
aEvent.target.addEventListener("popuphidden", networkPanelHidden, false);
aEvent.target.hidePopup();
});
}
function networkPanelHidden(aEvent) {
this.removeEventListener(aEvent.type, networkPanelHidden, false);
is(HUD.contentWindow, browser.contentWindow,
"console has not been re-attached to the wrong window");
finishTest();
}
function test() {
messageManager.loadFrameScript(FRAME_SCRIPT_URI, true);
registerCleanupFunction(function () {
// There's no way to unload a frameScript so send a kill signal to
// unregister the frame script's webProgressListener
messageManager.sendAsyncMessage("bug-678816-kill-webProgressListener");
});
addTab(TEST_URI);
browser.addEventListener("load", tabLoad1, true);
}

View File

@ -0,0 +1,28 @@
(function () {
let ifaceReq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
let webProgress = ifaceReq.getInterface(Ci.nsIWebProgress);
let WebProgressListener = {
onStateChange: function WebProgressListener_onStateChange(
webProgress, request, flag, status) {
if (flag & Ci.nsIWebProgressListener.STATE_START &&
flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
// ensure the dom window is the top one
return (webProgress.DOMWindow.parent == webProgress.DOMWindow);
}
},
// ----------
// Implements progress listener interface.
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference])
};
// add web progress listener
webProgress.addProgressListener(WebProgressListener, Ci.nsIWebProgress.NOTIFY_STATE_ALL);
addMessageListener("bug-678816-kill-webProgressListener", function () {
webProgress.removeProgressListener(WebProgressListener);
});
})();

View File

@ -42,6 +42,7 @@ view.sortBy.tags.accesskey=T
searchBookmarks=Search Bookmarks
searchHistory=Search History
searchDownloads=Search Downloads
searchCurrentDefault=Search in '%S'
findInPrefix=Find in '%S'…

View File

@ -375,3 +375,26 @@ code {
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
.editingAttributeValue {
background-color: #492;
}
#attribute-editor {
visibility: hidden;
position: absolute;
z-index: 5000;
background-color: #fff;
border: 1px solid #000;
}
#attribute-editor.editing {
visibility: visible;
}
#attribute-editor-input {
border: none;
padding: 2px 5px;
font-family: Menlo, Andale Mono, monospace;
font-size: 11px;
}

View File

@ -363,3 +363,26 @@ code {
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
.editingAttributeValue {
background-color: #492;
}
#attribute-editor {
visibility: hidden;
position: absolute;
z-index: 5000;
background-color: #fff;
border: 1px solid #000;
}
#attribute-editor.editing {
visibility: visible;
}
#attribute-editor-input {
border: none;
padding: 2px 5px;
font-family: Menlo, Andale Mono, monospace;
font-size: 11px;
}

View File

@ -348,3 +348,25 @@ code {
background-image: url("chrome://global/skin/tree/twisty-open.png") !important;
}
.editingAttributeValue {
background-color: #492;
}
#attribute-editor {
visibility: hidden;
position: absolute;
z-index: 5000;
background-color: #fff;
border: 1px solid #000;
}
#attribute-editor.editing {
visibility: visible;
}
#attribute-editor-input {
border: none;
padding: 2px 5px;
font-family: Menlo, Andale Mono, monospace;
font-size: 11px;
}

View File

@ -5,12 +5,17 @@ import os
class DeviceManagerADB(DeviceManager):
def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = "org.mozilla.fennec_unofficial"):
def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = None):
self.host = host
self.port = port
self.retrylimit = retrylimit
self.retries = 0
self._sock = None
if packageName == None:
if os.getenv('USER'):
packageName = 'org.mozilla.fennec_' + os.getenv('USER')
else:
packageName = 'org.mozilla.fennec_'
self.Init(packageName)
def Init(self, packageName):
@ -27,7 +32,11 @@ class DeviceManagerADB(DeviceManager):
self.tmpDir = None
try:
# a test to see if we have root privs
self.checkCmd(["shell", "ls", "/sbin"])
files = self.listFiles("/data/data")
if (len(files) == 1):
if (files[0].find("Permission denied") != -1):
print "NOT running as root"
raise Exception("not running as root")
except:
try:
self.checkCmd(["root"])
@ -98,7 +107,7 @@ class DeviceManagerADB(DeviceManager):
try:
if (not self.dirExists(remoteDir)):
self.mkDirs(remoteDir+"/x")
for root, dirs, files in os.walk(localDir):
for root, dirs, files in os.walk(localDir, followlinks='true'):
relRoot = os.path.relpath(root, localDir)
for file in files:
localFile = os.path.join(root, file)
@ -134,8 +143,12 @@ class DeviceManagerADB(DeviceManager):
# success: True
# failure: False
def fileExists(self, filepath):
self.checkCmd(["shell", "ls", filepath])
return True
p = self.runCmd(["shell", "ls", "-a", filepath])
data = p.stdout.readlines()
if (len(data) == 1):
if (data[0].rstrip() == filepath):
return True
return False
def removeFile(self, filename):
return self.runCmd(["shell", "rm", filename]).stdout.read()
@ -381,18 +394,11 @@ class DeviceManagerADB(DeviceManager):
return devroot + '/fennec'
elif (self.dirExists(devroot + '/firefox')):
return devroot + '/firefox'
elif (self.dirExists('/data/data/org.mozilla.fennec')):
return '/data/data/org.mozilla.fennec'
elif (self.dirExists('/data/data/org.mozilla.firefox')):
return '/data/data/org.mozilla.firefox'
elif (self.dirExists('/data/data/org.mozilla.fennec_unofficial')):
return '/data/data/org.mozilla.fennec_unofficial'
elif (self.dirExists('/data/data/org.mozilla.fennec_aurora')):
return '/data/data/org.mozilla.fennec_aurora'
elif (self.dirExists('/data/data/org.mozilla.firefox_beta')):
return '/data/data/org.mozilla.firefox_beta'
elif (self.packageName and self.dirExists('/data/data/' + self.packageName)):
return '/data/data/' + self.packageName
# Failure (either not installed or not a recognized platform)
print "devicemanagerADB: getAppRoot failed"
return None
# Gets the directory location on the device for a specific test type

View File

@ -107,7 +107,6 @@ public class WatcherService extends Service
private IWatcherService.Stub stub = new IWatcherService.Stub() {
@Override
public int UpdateApplication(String sAppName, String sFileName, String sOutFile, int bReboot) throws RemoteException
{
return UpdtApp(sAppName, sFileName, sOutFile, bReboot);
@ -874,7 +873,6 @@ public class WatcherService extends Service
runner.start();
}
@Override
public void run() {
bInstalling = true;
UpdtApp(msPkgName, msPkgFileName, msOutFile, mbReboot);

View File

@ -1737,7 +1737,8 @@ nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
{
#ifdef DEBUG
{
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, (JSObject *)aFunObj);
JS_ASSERT(JS_ObjectIsFunction(aCx, (JSObject *)aFunObj));
JSFunction *fun = (JSFunction *)JS_GetPrivate(aCx, (JSObject *)aFunObj);
JSScript *script = JS_GetFunctionScript(aCx, fun);
NS_ASSERTION(!script, "Null principal for non-native function!");
@ -2218,7 +2219,7 @@ nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
return result;
}
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
JSScript *script = JS_GetFunctionScript(cx, fun);
if (!script)
@ -2284,7 +2285,7 @@ nsScriptSecurityManager::GetFramePrincipal(JSContext *cx,
#ifdef DEBUG
if (NS_SUCCEEDED(*rv) && !result)
{
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
JSScript *script = JS_GetFunctionScript(cx, fun);
NS_ASSERTION(!script, "Null principal for non-native function!");

View File

@ -212,6 +212,7 @@ profiledbuild::
$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_GENERATE=1
$(MAKE) -C $(PGO_OBJDIR) package
OBJDIR=${PGO_OBJDIR} JARLOG_DIR=${PGO_OBJDIR}/jarlog/en-US $(PROFILE_GEN_SCRIPT)
$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild
$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_USE=1
#####################################################
@ -253,7 +254,7 @@ endif
# loop through them.
ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_BUILD_PROJECTS),,1))
configure depend realbuild install export libs clean realclean distclean alldep preflight postflight upload sdk::
configure depend realbuild install export libs clean realclean distclean alldep preflight postflight maybe_clobber_profiledbuild upload sdk::
set -e; \
for app in $(MOZ_BUILD_PROJECTS); do \
$(MAKE) -f $(TOPSRCDIR)/client.mk $@ MOZ_CURRENT_PROJECT=$$app; \
@ -353,7 +354,7 @@ realbuild:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
# Other targets
# Pass these target onto the real build system
install export libs clean realclean distclean alldep upload sdk:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
install export libs clean realclean distclean alldep maybe_clobber_profiledbuild upload sdk:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
$(MOZ_MAKE) $@
####################################
@ -412,4 +413,4 @@ echo-variable-%:
# in parallel.
.NOTPARALLEL:
.PHONY: checkout real_checkout depend realbuild build profiledbuild export libs alldep install clean realclean distclean cleansrcdir pull_all build_all clobber clobber_all pull_and_build_all everything configure preflight_all preflight postflight postflight_all upload sdk
.PHONY: checkout real_checkout depend realbuild build profiledbuild maybe_clobber_profiledbuild export libs alldep install clean realclean distclean cleansrcdir pull_all build_all clobber clobber_all pull_and_build_all everything configure preflight_all preflight postflight postflight_all upload sdk

View File

@ -223,7 +223,6 @@ MOZ_XUL = @MOZ_XUL@
MOZ_RDF = @MOZ_RDF@
NECKO_PROTOCOLS = @NECKO_PROTOCOLS@
NECKO_DISK_CACHE = @NECKO_DISK_CACHE@
NECKO_COOKIES = @NECKO_COOKIES@
NECKO_WIFI = @NECKO_WIFI@
MOZ_AUTH_EXTENSION = @MOZ_AUTH_EXTENSION@

File diff suppressed because it is too large Load Diff

View File

@ -153,6 +153,20 @@ xpcshell-tests:
$(LIBXUL_DIST)/bin/xpcshell \
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
xpcshell-tests-remote: DM_TRANS?=adb
xpcshell-tests-remote:
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
-I$(topsrcdir)/build \
-I$(topsrcdir)/build/mobile \
$(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
--symbols-path=$(DIST)/crashreporter-symbols \
--build-info-json=$(DEPTH)/mozinfo.json \
$(EXTRA_TEST_ARGS) \
--dm_trans=$(DM_TRANS) \
--deviceIP=${TEST_DEVICE} \
--objdir=$(DEPTH) \
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
# Execute a single test, specified in $(SOLO_FILE), but don't automatically
# start the test. Instead, present the xpcshell prompt so the user can
# attach a debugger and then start the test.
@ -182,6 +196,23 @@ check-one:
$(LIBXUL_DIST)/bin/xpcshell \
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
check-one-remote: DM_TRANS?=adb
check-one-remote:
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
-I$(topsrcdir)/build \
-I$(topsrcdir)/build/mobile \
$(testxpcsrcdir)/remotexpcshelltests.py \
--symbols-path=$(DIST)/crashreporter-symbols \
--build-info-json=$(DEPTH)/mozinfo.json \
--test-path=$(SOLO_FILE) \
--profile-name=$(MOZ_APP_NAME) \
--verbose \
$(EXTRA_TEST_ARGS) \
--dm_trans=$(DM_TRANS) \
--deviceIP=${TEST_DEVICE} \
--objdir=$(DEPTH) \
--noSetup \
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
endif # XPCSHELL_TESTS
ifdef CPP_UNIT_TESTS
@ -898,9 +929,6 @@ ifdef SHARED_LIBRARY
$(SHARED_LIBRARY_NAME) $(DIST)/$(MOZ_APP_NAME)
endif
endif # SHARED_LIBRARY || PROGRAM
else # ! WINNT_
# Force rebuilding all objects on the second pass
$(OBJS): FORCE
endif # WINNT_
endif # MOZ_PROFILE_USE
ifdef MOZ_PROFILE_GENERATE

View File

@ -970,6 +970,7 @@ if test -n "$_WIN32_MSVC"; then
AC_DEFINE(HAVE_IO_H)
AC_DEFINE(HAVE_SETBUF)
AC_DEFINE(HAVE_ISATTY)
AC_DEFINE(HAVE_STDCALL)
fi
fi # COMPILE_ENVIRONMENT
@ -2107,6 +2108,8 @@ case "$target" in
# logging code in nsObjCExceptions.h. Currently we only use that in debug
# builds.
MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling"
# Debug builds should always have frame pointers
MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
if test "x$lto_is_enabled" = "xyes"; then
echo "Skipping -dead_strip because lto is enabled."
@ -2253,6 +2256,8 @@ ia64*-hpux*)
else
MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer"
fi
# Debug builds should always have frame pointers
MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
;;
*-*linux*)
@ -2278,7 +2283,8 @@ ia64*-hpux*)
fi
MOZ_PGO_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS"
MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK $MOZ_FRAMEPTR_FLAGS"
MOZ_DEBUG_FLAGS="-g"
# Debug builds should always have frame pointers
MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
fi
TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"'
@ -2371,7 +2377,8 @@ ia64*-hpux*)
CFLAGS="$CFLAGS -we4553"
CXXFLAGS="$CXXFLAGS -we4553"
LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib"
MOZ_DEBUG_FLAGS='-Zi'
# Debug builds should always have frame pointers
MOZ_DEBUG_FLAGS='-Zi -Oy-'
MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
WARNINGS_AS_ERRORS='-WX'
# If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer.
@ -3588,53 +3595,6 @@ then
LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}"
fi
dnl ========================================================
dnl See if mmap sees writes
dnl For cross compiling, just define it as no, which is a safe default
dnl ========================================================
AC_MSG_CHECKING(whether mmap() sees write()s)
changequote(,)
mmap_test_prog='
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char fname[] = "conftest.file";
char zbuff[1024]; /* Fractional page is probably worst case */
int main() {
char *map;
int fd;
int i;
unlink(fname);
fd = open(fname, O_RDWR | O_CREAT, 0660);
if(fd<0) return 1;
unlink(fname);
write(fd, zbuff, sizeof(zbuff));
lseek(fd, 0, SEEK_SET);
map = (char*)mmap(0, sizeof(zbuff), PROT_READ, MAP_SHARED, fd, 0);
if(map==(char*)-1) return 2;
for(i=0; fname[i]; i++) {
int rc = write(fd, &fname[i], 1);
if(map[i]!=fname[i]) return 4;
}
return 0;
}
'
changequote([,])
AC_TRY_RUN($mmap_test_prog , result="yes", result="no", result="yes")
AC_MSG_RESULT("$result")
if test "$result" = "no"; then
AC_DEFINE(MMAP_MISSES_WRITES)
fi
dnl Checks for library functions.
dnl ========================================================
@ -4778,7 +4738,6 @@ MOZ_DISABLE_DOMCRYPTO=
NSS_DISABLE_DBM=
NECKO_WIFI=1
NECKO_COOKIES=1
NECKO_DISK_CACHE=1
NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciwyg"
USE_ARM_KUSER=
BUILD_CTYPES=1
@ -5194,7 +5153,7 @@ incorrect])
fi
MOZ_ENABLE_QTMOBILITY=
PKG_CHECK_MODULES(_QTMOBILITY, QtSensors QtFeedback,
PKG_CHECK_MODULES(_QTMOBILITY, QtSensors QtFeedback QtLocation,
MOZ_ENABLE_QTMOBILITY=1,
MOZ_ENABLE_QTMOBILITY=)
if test "$MOZ_ENABLE_QTMOBILITY"; then
@ -5202,12 +5161,13 @@ incorrect])
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS $_QTMOBILITY_CFLAGS"
MOZ_QT_LIBS="$MOZ_QT_LIBS $_QTMOBILITY_LIBS"
else
AC_CHECK_LIB(QtSensors QtFeedback, main, [
AC_CHECK_LIB(QtSensors QtFeedback QtLocation, main, [
MOZ_ENABLE_QTMOBILITY=1
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtMobility"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtSensors"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtFeedback"
MOZ_QT_LIBS="$MOZ_QT_LIBS -lQtSensors -lQtFeedback"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtLocation"
MOZ_QT_LIBS="$MOZ_QT_LIBS -lQtSensors -lQtFeedback -lQtLocation"
])
fi
if test "$MOZ_ENABLE_QTMOBILITY"; then
@ -8764,19 +8724,6 @@ for p in $NECKO_PROTOCOLS; do
AC_DEFINE_UNQUOTED(NECKO_PROTOCOL_$p)
done
dnl
dnl option to disable necko's disk cache
dnl
MOZ_ARG_DISABLE_BOOL(necko-disk-cache,
[ --disable-necko-disk-cache
Disable necko disk cache],
NECKO_DISK_CACHE=,
NECKO_DISK_CACHE=1)
AC_SUBST(NECKO_DISK_CACHE)
if test "$NECKO_DISK_CACHE"; then
AC_DEFINE(NECKO_DISK_CACHE)
fi
dnl
dnl option to disable necko's wifi scanner
dnl

View File

@ -118,8 +118,15 @@ interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
[notxpcom] nsIContent getOwnerContent();
};
[scriptable, uuid(ed6522fd-ffb6-4920-b50d-cf629309616b)]
interface nsIChromeFrameMessageManager : nsIFrameMessageManager
[scriptable, uuid(6331bbca-2c9f-4766-b3c7-ae75554bf1ec)]
interface nsITreeItemFrameMessageManager : nsIFrameMessageManager
{
readonly attribute unsigned long childCount;
nsITreeItemFrameMessageManager getChildAt(in unsigned long aIndex);
};
[scriptable, uuid(23e6ef7b-8cc5-4e8b-9391-453440a3b858)]
interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager
{
/*
* Load a script in the (remote) frame. aURL must be the absolute URL.

View File

@ -95,6 +95,7 @@ CPPSRCS = \
nsDOMAttribute.cpp \
nsDOMAttributeMap.cpp \
nsDOMBlobBuilder.cpp \
nsDOMCaretPosition.cpp \
nsDOMDocumentType.cpp \
nsDOMEventTargetWrapperCache.cpp \
nsDOMFile.cpp \

View File

@ -0,0 +1,77 @@
/* ***** 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.org.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brad Lassey <blassey@mozilla.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 ***** */
#include "nsDOMCaretPosition.h"
#include "nsDOMClassInfoID.h"
#include "nsIDOMClassInfo.h"
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCaretPosition)
NS_INTERFACE_MAP_ENTRY(nsIDOMCaretPosition)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMCaretPosition)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CaretPosition)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_1(nsDOMCaretPosition, mNode)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCaretPosition)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCaretPosition)
DOMCI_DATA(CaretPosition, nsDOMCaretPosition)
nsDOMCaretPosition::nsDOMCaretPosition(nsIDOMNode* aNode, PRUint32 aOffset)
: mNode(aNode), mOffset(aOffset)
{
}
nsDOMCaretPosition::~nsDOMCaretPosition()
{
}
NS_IMETHODIMP nsDOMCaretPosition::GetOffsetNode(nsIDOMNode** aOffsetNode)
{
nsCOMPtr<nsIDOMNode> node = mNode;
node.forget(aOffsetNode);
return NS_OK;
}
NS_IMETHODIMP nsDOMCaretPosition::GetOffset(PRUint32* aOffset)
{
*aOffset = mOffset;
return NS_OK;
}

View File

@ -0,0 +1,59 @@
/* ***** 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.org.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brad Lassey <blassey@mozilla.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 ***** */
#ifndef nsDOMCaretPosition_h
#define nsDOMCaretPosition_h
#include "nsIDOMCaretPosition.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
class nsDOMCaretPosition : public nsIDOMCaretPosition
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMCaretPosition)
NS_DECL_NSIDOMCARETPOSITION
nsDOMCaretPosition(nsIDOMNode* aNode, PRUint32 aOffset);
protected:
virtual ~nsDOMCaretPosition();
PRUint32 mOffset;
nsCOMPtr<nsIDOMNode> mNode;
};
#endif

View File

@ -202,9 +202,13 @@
#include "nsDOMTouchEvent.h"
#include "mozilla/Preferences.h"
#include "nsFrame.h"
#include "imgILoader.h"
#include "nsDOMCaretPosition.h"
#include "nsIDOMHTMLTextAreaElement.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -8394,6 +8398,58 @@ nsDocument::CreateTouchList(nsIVariant* aPoints,
return NS_OK;
}
NS_IMETHODIMP
nsDocument::CaretPositionFromPoint(float aX, float aY, nsIDOMCaretPosition** aCaretPos)
{
NS_ENSURE_ARG_POINTER(aCaretPos);
*aCaretPos = nsnull;
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
nsIPresShell *ps = GetShell();
if (!ps) {
return NS_OK;
}
nsIFrame *rootFrame = ps->GetRootFrame();
// XUL docs, unlike HTML, have no frame tree until everything's done loading
if (!rootFrame) {
return NS_OK; // return null to premature XUL callers as a reminder to wait
}
nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, PR_TRUE,
PR_FALSE);
if (!ptFrame) {
return NS_OK;
}
nsFrame::ContentOffsets offsets = ptFrame->GetContentOffsetsFromPoint(pt);
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(offsets.content);
nsIContent* ptContent = offsets.content;
PRInt32 offset = offsets.offset;
if (ptContent && ptContent->IsInNativeAnonymousSubtree()) {
nsIContent* nonanon = ptContent->FindFirstNonNativeAnonymous();
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(nonanon);
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
PRBool isText;
if (textArea || (input &&
NS_SUCCEEDED(input->MozIsTextField(PR_FALSE, &isText)) &&
isText)) {
node = do_QueryInterface(nonanon);
} else {
node = nsnull;
offset = 0;
}
}
*aCaretPos = new nsDOMCaretPosition(node, offset);
NS_ADDREF(*aCaretPos);
return NS_OK;
}
PRInt64
nsIDocument::SizeOf() const
{

View File

@ -1791,7 +1791,7 @@ nsFrameLoader::TryRemoteBrowser()
return false;
}
ContentParent* parent = ContentParent::GetSingleton();
ContentParent* parent = ContentParent::GetNewOrUsed();
NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
mRemoteBrowser = parent->CreateTab(chromeFlags);
if (mRemoteBrowser) {

View File

@ -98,6 +98,8 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
!mChrome && !mIsProcessManager)
/* Message managers in child process support nsISyncMessageSender. */
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISyncMessageSender, !mChrome)
/* Message managers in chrome process support nsITreeItemFrameMessageManager. */
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITreeItemFrameMessageManager, mChrome)
/* Process message manager doesn't support nsIChromeFrameMessageManager. */
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIChromeFrameMessageManager,
mChrome && !mIsProcessManager)
@ -323,6 +325,24 @@ nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
return NS_OK;
}
NS_IMETHODIMP
nsFrameMessageManager::GetChildCount(PRUint32* aChildCount)
{
*aChildCount = static_cast<PRUint32>(mChildManagers.Count());
return NS_OK;
}
NS_IMETHODIMP
nsFrameMessageManager::GetChildAt(PRUint32 aIndex,
nsITreeItemFrameMessageManager** aMM)
{
*aMM = nsnull;
nsCOMPtr<nsITreeItemFrameMessageManager> mm =
do_QueryInterface(mChildManagers.SafeObjectAt(static_cast<PRUint32>(aIndex)));
mm.swap(*aMM);
return NS_OK;
}
NS_IMETHODIMP
nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
nsAString& aAsciiBase64String)
@ -823,7 +843,7 @@ bool SendAsyncMessageToChildProcess(void* aCallbackData,
const nsAString& aJSON)
{
mozilla::dom::ContentParent* cp =
mozilla::dom::ContentParent::GetSingleton(PR_FALSE);
static_cast<mozilla::dom::ContentParent*>(aCallbackData);
NS_WARN_IF_FALSE(cp, "No child process!");
if (cp) {
return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
@ -857,6 +877,7 @@ bool SendAsyncMessageToParentProcess(void* aCallbackData,
return true;
}
// This creates the global parent process message manager.
nsresult
NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult)
{
@ -865,9 +886,9 @@ NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult)
NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
nsFrameMessageManager* mm = new nsFrameMessageManager(PR_TRUE,
nsnull,
SendAsyncMessageToChildProcess,
nsnull,
&nsFrameMessageManager::sParentProcessManager,
nsnull,
nsnull,
nsnull,
nsnull,
PR_FALSE,
@ -877,6 +898,25 @@ NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult)
return CallQueryInterface(mm, aResult);
}
nsFrameMessageManager*
nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
{
if (!nsFrameMessageManager::sParentProcessManager) {
nsCOMPtr<nsIFrameMessageManager> dummy;
NS_NewParentProcessMessageManager(getter_AddRefs(dummy));
}
nsFrameMessageManager* mm = new nsFrameMessageManager(PR_TRUE,
nsnull,
SendAsyncMessageToChildProcess,
nsnull,
aProcess,
nsFrameMessageManager::sParentProcessManager,
nsnull,
PR_FALSE,
PR_TRUE);
return mm;
}
nsresult
NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)

View File

@ -52,6 +52,12 @@
#include "mozilla/Services.h"
#include "nsIObserverService.h"
namespace mozilla {
namespace dom {
class ContentParent;
}
}
class nsAXPCNativeCallContext;
struct JSContext;
struct JSObject;
@ -125,6 +131,10 @@ public:
NS_DECL_NSISYNCMESSAGESENDER
NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
NS_DECL_NSICHROMEFRAMEMESSAGEMANAGER
NS_DECL_NSITREEITEMFRAMEMESSAGEMANAGER
static nsFrameMessageManager*
NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
PRBool aSync, const nsAString& aJSON,

View File

@ -1059,8 +1059,9 @@ nsINode::AddEventListener(const nsAString& aType,
nsEventListenerManager* listener_manager = GetListenerManager(PR_TRUE);
NS_ENSURE_STATE(listener_manager);
return listener_manager->AddEventListener(aType, aListener, aUseCapture,
aWantsUntrusted);
listener_manager->AddEventListener(aType, aListener, aUseCapture,
aWantsUntrusted);
return NS_OK;
}
NS_IMETHODIMP

View File

@ -70,6 +70,7 @@ GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after")
GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image")
GK_ATOM(_moz_original_size, "_moz_original_size")
GK_ATOM(_moz_target, "_moz_target")
GK_ATOM(_moz_type, "_moz-type")
GK_ATOM(menuactive, "_moz-menuactive")
@ -1873,6 +1874,7 @@ GK_ATOM(images_in_menus, "images-in-menus")
GK_ATOM(images_in_buttons, "images-in-buttons")
GK_ATOM(windows_default_theme, "windows-default-theme")
GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
GK_ATOM(mac_lion_theme, "mac-lion-theme")
GK_ATOM(windows_compositor, "windows-compositor")
GK_ATOM(touch_enabled, "touch-enabled")
GK_ATOM(maemo_classic, "maemo-classic")
@ -1898,6 +1900,7 @@ GK_ATOM(_moz_images_in_menus, "-moz-images-in-menus")
GK_ATOM(_moz_images_in_buttons, "-moz-images-in-buttons")
GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
GK_ATOM(_moz_mac_lion_theme, "-moz-mac-lion-theme")
GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
GK_ATOM(_moz_windows_theme, "-moz-windows-theme")

View File

@ -503,6 +503,7 @@ _TEST_FILES2 = \
test_bug666604.html \
test_bug675121.html \
file_bug675121.sjs \
test_bug654352.html \
$(NULL)
_CHROME_FILES = \

View File

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=654352
-->
<head>
<title>Test for Bug 654352</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=654352">Mozilla Bug 654352</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 654352 **/
SimpleTest.waitForExplicitFinish();
function afterLoad() {
var testpre = document.getElementById("testpre");
var rect1 = testpre.getBoundingClientRect();
dump(rect1 + "\n");
var caret1 = document.caretPositionFromPoint(rect1.right - 5, rect1.top + 10);
ok(caret1.offsetNode == testpre.firstChild, "node in CaretPosition not correct (" + caret1.offsetNode + " == " + testpre.firstChild + ")")
ok(caret1.offset == 9, "offset in CaretPosition not correct (" + caret1.offset + "== 9)")
var testinput = document.getElementById("testinput");
var rect2 = testinput.getBoundingClientRect();
dump(rect2.top +", " + rect2.left + "\n");
var caret2 = document.caretPositionFromPoint( rect2.right - 5, rect2.top + 10);
ok(caret2.offsetNode == testinput, "node in CaretPosition not correct (" + caret2.offsetNode + " == " + testinput + ")")
ok(caret2.offset == 9, "offset in CaretPosition not correct (" + caret2.offset + "== 9)")
SimpleTest.finish();
};
addLoadEvent(afterLoad);
</script>
</pre>
<span id="testdiv">
<pre id="testpre">test text</pre>
</span>
<br>
<br>
</div>
<input id="testinput" type="text" value="test text"></input>
</div>
</body>
</html>

View File

@ -53,8 +53,8 @@ function testCopyPaste () {
function copySelectionToClipboard() {
documentViewer.copySelection();
is(clipboard.hasDataMatchingFlavors(["text/unicode"], 1,1), true);
is(clipboard.hasDataMatchingFlavors(["text/html"], 1,1), true);
ok(clipboard.hasDataMatchingFlavors(["text/unicode"], 1,1), "check text/unicode");
ok(clipboard.hasDataMatchingFlavors(["text/html"], 1,1), "check text/html");
}
function copyToClipboard(node) {
textarea.blur();

View File

@ -126,7 +126,8 @@ nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
nsEventListenerManager* elm = GetListenerManager(PR_TRUE);
NS_ENSURE_STATE(elm);
return elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
return NS_OK;
}
NS_IMETHODIMP

View File

@ -103,9 +103,11 @@ nsDOMMessageEvent::UnrootData()
}
NS_IMETHODIMP
nsDOMMessageEvent::GetData(jsval* aData)
nsDOMMessageEvent::GetData(JSContext* aCx, jsval* aData)
{
*aData = mData;
if (!JS_WrapValue(aCx, aData))
return NS_ERROR_FAILURE;
return NS_OK;
}

View File

@ -209,14 +209,17 @@ nsEventListenerManager::GetInnerWindowForTarget()
return nsnull;
}
nsresult
void
nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
PRUint32 aType,
nsIAtom* aTypeAtom,
PRInt32 aFlags)
{
NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(aType, NS_ERROR_FAILURE);
NS_ABORT_IF_FALSE(aType && aTypeAtom, "Missing type");
if (!aListener) {
return;
}
nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = aListener;
@ -226,7 +229,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
ls = &mListeners.ElementAt(i);
if (ls->mListener == aListener && ls->mFlags == aFlags &&
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom)) {
return NS_OK;
return;
}
}
@ -291,8 +294,6 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
if (window)
window->SetHasTouchEventListeners();
}
return NS_OK;
}
void
@ -334,14 +335,14 @@ ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
(aLs->mEventType == aEvent->message);
}
nsresult
void
nsEventListenerManager::AddEventListenerByType(nsIDOMEventListener *aListener,
const nsAString& aType,
PRInt32 aFlags)
{
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
PRUint32 type = nsContentUtils::GetEventId(atom);
return AddEventListener(aListener, type, atom, aFlags);
AddEventListener(aListener, type, atom, aFlags);
}
void
@ -943,8 +944,7 @@ nsEventListenerManager::Disconnect()
RemoveAllListeners();
}
// nsIDOMEventTarget interface
nsresult
void
nsEventListenerManager::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,

View File

@ -84,10 +84,10 @@ public:
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsEventListenerManager)
nsresult AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted);
void AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted);
void RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
@ -96,9 +96,9 @@ public:
* Sets events listeners of all types.
* @param an event listener
*/
nsresult AddEventListenerByType(nsIDOMEventListener *aListener,
const nsAString& type,
PRInt32 aFlags);
void AddEventListenerByType(nsIDOMEventListener *aListener,
const nsAString& type,
PRInt32 aFlags);
void RemoveEventListenerByType(nsIDOMEventListener *aListener,
const nsAString& type,
PRInt32 aFlags);
@ -210,10 +210,10 @@ protected:
void *aScopeGlobal,
nsIAtom* aName, PRBool aIsString,
PRBool aPermitUntrustedEvents);
nsresult AddEventListener(nsIDOMEventListener *aListener,
PRUint32 aType,
nsIAtom* aTypeAtom,
PRInt32 aFlags);
void AddEventListener(nsIDOMEventListener *aListener,
PRUint32 aType,
nsIAtom* aTypeAtom,
PRInt32 aFlags);
void RemoveEventListener(nsIDOMEventListener *aListener,
PRUint32 aType,
nsIAtom* aUserType,

View File

@ -280,7 +280,8 @@ nsEventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget,
NS_EVENT_FLAG_SYSTEM_EVENT :
NS_EVENT_FLAG_BUBBLE |
NS_EVENT_FLAG_SYSTEM_EVENT;
return manager->AddEventListenerByType(aListener, aType, flags);
manager->AddEventListenerByType(aListener, aType, flags);
return NS_OK;
}
NS_IMETHODIMP

View File

@ -107,6 +107,8 @@ _TEST_FILES = \
test_bug662678.html \
test_bug667919-1.html \
test_bug667919-2.html \
test_bug667612.html \
empty.js \
$(NULL)
#bug 585630
@ -135,6 +137,8 @@ _CHROME_FILES = \
test_bug602962.xul \
test_bug617528.xul \
window_bug617528.xul \
test_bug679494.xul \
file_bug679494.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>Test for Bug 679494</title>
</head>
<body>
There and back again.
</body>
</html>

View File

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=667612
-->
<head>
<title>Test for Bug 667612</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=667612">Mozilla Bug 667612</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
xhr = new XMLHttpRequest;
w = new Worker("empty.js");
window.addEventListener("load", null, false);
document.addEventListener("load", null, false);
document.body.addEventListener("load", null, false);
xhr.addEventListener("load", null, false);
w.addEventListener("load", null, false);
window.addEventListener("load", undefined, false);
document.addEventListener("load", undefined, false);
document.body.addEventListener("load", undefined, false);
xhr.addEventListener("load", undefined, false);
w.addEventListener("load", undefined, false);
ok(true, "didn't throw");
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=67949
-->
<window title="Mozilla Bug 67949" onload="doTest();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 67949</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=67949">Mozilla Bug 67949</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="contentframe" src="http://mochi.test:8888/tests/content/event/test/file_679494.html"></iframe>
</div>
</body>
<script class="testbody" type="application/javascript;version=1.8"><![CDATA[
/* Test for bug 679494 */
function doTest() {
SimpleTest.waitForExplicitFinish();
var w = document.getElementById("contentframe").contentWindow;
w.addEventListener("message", function(e) {
is("test", e.data, "We got the data without a compartment mismatch assertion!");
SimpleTest.finish();
}, false);
w.postMessage("test", "*");
}
]]></script>
</window>

View File

@ -36,6 +36,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMHTMLTableCellElement.h"
#include "nsIDOMHTMLTableRowElement.h"
#include "nsHTMLTableElement.h"
#include "nsIDOMHTMLCollection.h"
#include "nsIDOMEventTarget.h"
#include "nsMappedAttributes.h"
@ -44,6 +45,7 @@
#include "nsStyleConsts.h"
#include "nsPresContext.h"
#include "nsRuleData.h"
#include "nsRuleWalker.h"
#include "nsIDocument.h"
#include "celldata.h"
@ -203,19 +205,15 @@ nsHTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
nsresult rv = nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
NS_ENSURE_SUCCESS(rv, rv);
// Add style information from the mapped attributes of the table
// element. This depends on the strange behavior of the
// |MapAttributesIntoRule| in nsHTMLTableElement.cpp, which is
// technically incorrect since it's violating the nsIStyleRule
// contract. However, things are OK (except for the incorrect
// dependence on display type rather than tag) since tables and cells
// match different, less specific, rules.
nsIContent* table = GetTable();
if (table) {
rv = table->WalkContentStyleRules(aRuleWalker);
nsIContent* node = GetTable();
if (node && node->IsHTML() && node->NodeInfo()->Equals(nsGkAtoms::table)) {
nsHTMLTableElement* table = static_cast<nsHTMLTableElement*>(node);
nsMappedAttributes* tableInheritedAttributes =
table->GetAttributesMappedForCell();
if (tableInheritedAttributes)
aRuleWalker->Forward(tableInheritedAttributes);
}
return rv;
return NS_OK;
}

Some files were not shown because too many files have changed in this diff Show More