Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-11-24 14:18:59 +01:00
commit 2492fdb8a7
391 changed files with 8220 additions and 2957 deletions

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
REVIEWBOARD_URL = 'https://reviewboard.allizom.org/'

View File

@ -508,7 +508,7 @@ HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
const bool kIsKeyboardSelect = true; // is keyboard selection
const bool kIsVisualBidi = false; // use visual order for bidi text
nsPeekOffsetStruct pos(aAmount, aDirection, innerContentOffset,
0, kIsJumpLinesOk, kIsScrollViewAStop,
nsPoint(0, 0), kIsJumpLinesOk, kIsScrollViewAStop,
kIsKeyboardSelect, kIsVisualBidi,
aWordMovementType);
nsresult rv = frameAtOffset->PeekOffset(&pos);

View File

@ -434,6 +434,8 @@ pref("dom.ipc.processCount", 100000);
pref("dom.ipc.browser_frames.oop_by_default", false);
pref("dom.meta-viewport.enabled", true);
// SMS/MMS
pref("dom.sms.enabled", true);

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1416004676000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1416506840000">
<emItems>
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
<versionRange minVersion="0" maxVersion="*">
@ -451,10 +451,8 @@
<prefs>
</prefs>
</emItem>
<emItem blockID="i502" id="{df6bb2ec-333b-4267-8c4f-3f27dc8c6e07}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
<versionRange minVersion="0" maxVersion="*" severity="3">
<emItem blockID="i346" id="{a6e67e6f-8615-4fe0-a599-34a73fc3fba5}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
<prefs>
</prefs>
@ -546,8 +544,10 @@
<prefs>
</prefs>
</emItem>
<emItem blockID="i346" id="{a6e67e6f-8615-4fe0-a599-34a73fc3fba5}">
<versionRange minVersion="0" maxVersion="*" severity="1">
<emItem blockID="i502" id="{df6bb2ec-333b-4267-8c4f-3f27dc8c6e07}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
<prefs>
</prefs>
@ -1469,6 +1469,12 @@
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i788" id="{729c9605-0626-4792-9584-4cbe65b243e6}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i750" id="{46eddf51-a4f6-4476-8d6c-31c5187b2a2f}">
<versionRange minVersion="0" maxVersion="*" severity="1">
@ -2037,6 +2043,12 @@
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i786" id="{63eb5ed4-e1b3-47ec-a253-f8462f205350}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i342" id="lbmsrvfvxcblvpane@lpaezhjez.org">
<versionRange minVersion="0" maxVersion="*" severity="1">

View File

@ -1642,10 +1642,10 @@ pref("shumway.disabled", true);
pref("image.mem.max_decoded_image_kb", 256000);
pref("loop.enabled", true);
pref("loop.server", "https://loop.services.mozilla.com");
pref("loop.server", "https://loop.services.mozilla.com/v0");
pref("loop.seenToS", "unseen");
pref("loop.gettingStarted.seen", false);
pref("loop.gettingStarted.url", "https://bugzilla.mozilla.org/show_bug.cgi?id=1099462");
pref("loop.gettingStarted.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/hello/start");
pref("loop.learnMoreUrl", "https://www.firefox.com/hello/");
pref("loop.legal.ToS_url", "https://hello.firefox.com/legal/terms/");
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/");
@ -1810,7 +1810,7 @@ pref("privacy.trackingprotection.ui.enabled", false);
#endif
#ifdef NIGHTLY_BUILD
pref("browser.tabs.remote.autostart.1", true);
pref("browser.tabs.remote.autostart.1", false);
#endif
// Temporary pref to allow printing in e10s windows on some platforms.
@ -1820,4 +1820,9 @@ pref("print.enable_e10s_testing", false);
pref("print.enable_e10s_testing", true);
#endif
#ifdef NIGHTLY_BUILD
// Enable e10s add-on interposition by default.
pref("extensions.interposition.enabled", true);
#endif
pref("browser.defaultbrowser.notificationbar", false);

View File

@ -99,16 +99,6 @@ let wrapper = {
iframe: null,
init: function (url, urlParams) {
let weave = Cc["@mozilla.org/weave/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
// Don't show about:accounts with FxA disabled.
if (!weave.fxAccountsEnabled) {
document.body.remove();
return;
}
// If a master-password is enabled, we want to encourage the user to
// unlock it. Things still work if not, but the user will probably need
// to re-auth next startup (in which case we will get here again and

View File

@ -720,7 +720,6 @@
enablehistory="true"
maxrows="6"
newlines="stripsurroundingwhitespace"
oninput="gBrowser.userTypedValue = this.value;"
ontextentered="this.handleCommand(param);"
ontextreverted="return this.handleRevert();"
pageproxystate="invalid"

View File

@ -193,6 +193,9 @@
() => {
this.swapDocShells(cb);
chatbar.focus();
this.close();
// chatboxForURL is a map of URL -> chatbox used to avoid opening
// duplicate chat windows. Ensure reattached chat windows aren't
// registered with about:blank as their URL, otherwise reattaching
@ -200,8 +203,6 @@
chatbar.chatboxForURL.delete("about:blank");
chatbar.chatboxForURL.set(this.src, Cu.getWeakReference(cb));
chatbar.focus();
this.close();
deferred.resolve(cb);
}
);
@ -527,7 +528,9 @@
let cb = this.chatboxForURL.get(aURL);
if (cb) {
cb = cb.get();
if (cb.parentNode) {
// A chatbox is still alive to us when it's parented and still has
// content.
if (cb.parentNode && cb.contentWindow) {
this.showChat(cb, aMode);
if (aCallback) {
if (cb._callbacks == null) {
@ -646,6 +649,7 @@
<parameter name="aOptions"/>
<body><![CDATA[
let deferred = Promise.defer();
let chatbar = this;
let options = "";
for (let name in aOptions)
options += "," + name + "=" + aOptions[name];
@ -661,6 +665,8 @@
let otherChatbox = otherWin.document.getElementById("chatter");
aChatbox.swapDocShells(otherChatbox);
aChatbox.close();
chatbar.chatboxForURL.set(aChatbox.src, Cu.getWeakReference(otherChatbox));
deferred.resolve(otherChatbox);
}, true);
return deferred.promise;

View File

@ -122,6 +122,10 @@ skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test un
[browser_alltabslistener.js]
[browser_autocomplete_a11y_label.js]
skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir (works on its own)
[browser_autocomplete_no_title.js]
skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_autocomplete_autoselect.js]
skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_backButtonFitts.js]
skip-if = os != "win" || e10s # The Fitts Law back button is only supported on Windows (bug 571454) / e10s - Bug 1099154: test touches content (attempts to add an event listener directly to the contentWindow)
[browser_blob-channelname.js]
@ -288,6 +292,8 @@ skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and
[browser_bug1015721.js]
skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
[browser_bug1064280_changeUrlInPinnedTab.js]
[browser_bug1070778.js]
skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_canonizeURL.js]
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
[browser_contentAreaClick.js]

View File

@ -31,7 +31,7 @@ let tests = [
function revert(next) {
loadTabInWindow(window, function (tab) {
gURLBar.handleRevert();
is(gURLBar.value, "example.com", "URL bar had user/pass stripped after reverting");
is(gURLBar.textValue, "example.com", "URL bar had user/pass stripped after reverting");
gBrowser.removeTab(tab);
next();
});
@ -44,7 +44,7 @@ let tests = [
loadTabInWindow(win, function () {
openToolbarCustomizationUI(function () {
closeToolbarCustomizationUI(function () {
is(win.gURLBar.value, "example.com", "URL bar had user/pass stripped after customize");
is(win.gURLBar.textValue, "example.com", "URL bar had user/pass stripped after customize");
win.close();
next();
}, win);
@ -59,7 +59,7 @@ let tests = [
// error.
tab.linkedBrowser.loadURI("http://test1.example.com");
tab.linkedBrowser.stop();
is(gURLBar.value, "example.com", "URL bar had user/pass stripped after load error");
is(gURLBar.textValue, "example.com", "URL bar had user/pass stripped after load error");
gBrowser.removeTab(tab);
next();
});
@ -76,7 +76,7 @@ function loadTabInWindow(win, callback) {
return;
tab.linkedBrowser.removeEventListener("load", listener, true);
is(win.gURLBar.value, "example.com", "URL bar had user/pass stripped initially");
is(win.gURLBar.textValue, "example.com", "URL bar had user/pass stripped initially");
callback(tab);
}, true);
}

View File

@ -43,11 +43,14 @@ add_task(function* () {
let result = yield promise_first_result("open a search");
isnot(result, null, "Should have a result");
is(result.getAttribute("url"),
`moz-action:searchengine,{"engineName":"MozSearch","input":"open a search","searchQuery":"open a search"}`,
"Result should be a moz-action: for the correct search engine");
is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute");
let tabPromise = promiseTabLoaded(gBrowser.selectedTab);
EventUtils.synthesizeMouseAtCenter(result, {});
yield tabPromise;
is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search");
is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search", "Correct URL should be loaded");
});

View File

@ -0,0 +1,59 @@
function repeat(limit, func) {
for (let i = 0; i < limit; i++) {
func(i);
}
}
function* promiseAutoComplete(inputText) {
gURLBar.focus();
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1), {});
yield promiseSearchComplete();
}
function is_selected(index) {
is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
}
add_task(function*() {
registerCleanupFunction(promiseClearHistory);
let visits = [];
repeat(10, i => {
visits.push({
uri: makeURI("http://example.com/autocomplete/?" + i),
});
});
yield PlacesTestUtils.addVisits(visits);
yield promiseAutoComplete("example.com/autocomplete");
let popup = gURLBar.popup;
let results = popup.richlistbox.children;
// 1 extra for the current search engine match
is(results.length, 11, "Should get 11 results");
is_selected(0);
info("Key Down to select the next item");
EventUtils.synthesizeKey("VK_DOWN", {});
is_selected(1);
info("Key Down 11 times should wrap around all the way around");
repeat(11, () => EventUtils.synthesizeKey("VK_DOWN", {}));
is_selected(1);
info("Key Up 11 times should wrap around the other way");
repeat(11, () => EventUtils.synthesizeKey("VK_UP", {}));
is_selected(1);
info("Page Up will go up the list, but not wrap");
EventUtils.synthesizeKey("VK_PAGE_UP", {})
is_selected(0);
info("Page Up again will wrap around to the end of the list");
EventUtils.synthesizeKey("VK_PAGE_UP", {})
is_selected(10);
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield promisePopupHidden(gURLBar.popup);
});

View File

@ -0,0 +1,27 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function* check_title(inputText, expectedTitle) {
gURLBar.focus();
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
yield promiseSearchComplete();
ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
let result = gURLBar.popup.richlistbox.children[1];
is(result._title.textContent, expectedTitle, "Result title should be as expected");
}
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
return;
let uri = NetUtil.newURI("http://bug1060642.example.com/beards/are/pretty/great");
yield PlacesTestUtils.addVisits([{uri: uri, title: ""}]);
yield check_title("bug1060642", "bug1060642.example.com");
gURLBar.popup.hidePopup();
yield promisePopupHidden(gURLBar.popup);
});

View File

@ -35,7 +35,7 @@ add_task(function* test_switchtab_override() {
onSearchComplete.apply(gURLBar);
deferred.resolve();
}
gURLBar.focus();
gURLBar.value = "dummy_pag";
EventUtils.synthesizeKey("e" , {});
@ -43,7 +43,6 @@ add_task(function* test_switchtab_override() {
info("Select second autocomplete popup entry");
EventUtils.synthesizeKey("VK_DOWN" , {});
EventUtils.synthesizeKey("VK_DOWN" , {});
ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");
info("Override switch-to-tab");
@ -61,6 +60,7 @@ add_task(function* test_switchtab_override() {
EventUtils.synthesizeKey("VK_SHIFT" , { type: "keydown" });
EventUtils.synthesizeKey("VK_RETURN" , { });
info(`gURLBar.value = ${gURLBar.value}`);
EventUtils.synthesizeKey("VK_SHIFT" , { type: "keyup" });
yield deferred.promise;

View File

@ -21,26 +21,13 @@ add_task(function* test_switchtab_override_keynav() {
return promiseClearHistory();
});
info("Wait for autocomplete")
let searchDeferred = Promise.defer();
let onSearchComplete = gURLBar.onSearchComplete;
registerCleanupFunction(() => {
gURLBar.onSearchComplete = onSearchComplete;
});
gURLBar.onSearchComplete = function () {
ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
onSearchComplete.apply(gURLBar);
searchDeferred.resolve();
}
gURLBar.focus();
gURLBar.value = "dummy_pag";
EventUtils.synthesizeKey("e" , {});
yield searchDeferred.promise;
yield promiseSearchComplete();
info("Select second autocomplete popup entry");
EventUtils.synthesizeKey("VK_DOWN" , {});
EventUtils.synthesizeKey("VK_DOWN" , {});
ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");
info("Shift+left on switch-to-tab entry");

View File

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function* promiseAutoComplete(inputText) {
gURLBar.focus();
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
yield promiseSearchComplete();
}
function is_selected(index) {
is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
}
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
return;
registerCleanupFunction(() => {
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
});
let itemId =
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
NetUtil.newURI("http://example.com/?q=%s"),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"test");
PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
// This item only needed so we can select the keyword item, select something
// else, then select the keyword item again.
itemId =
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
NetUtil.newURI("http://example.com/keyword"),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"keyword abc");
yield promiseAutoComplete("keyword a");
// First item should already be selected
is_selected(0);
// Select next one (important!)
EventUtils.synthesizeKey("VK_DOWN", {});
is_selected(1);
// Re-select keyword item
EventUtils.synthesizeKey("VK_UP", {});
is_selected(0);
EventUtils.synthesizeKey("b", {});
yield promiseSearchComplete();
is(gURLBar.value, "keyword ab", "urlbar should have expected input");
let result = gURLBar.popup.richlistbox.firstChild;
isnot(result, null, "Should have first item");
let uri = NetUtil.newURI(result.getAttribute("url"));
is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=ab", input: "keyword ab"}).spec, "Expect correct url");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield promisePopupHidden(gURLBar.popup);
});

View File

@ -21,16 +21,15 @@ function test() {
function cycleTabs() {
gBrowser.selectedTab = fullURLTab;
is(gURLBar.value, testURL, 'gURLBar.value should be testURL after switching back to fullURLTab');
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after switching back to fullURLTab');
gBrowser.selectedTab = partialURLTab;
is(gURLBar.value, testPartialURL, 'gURLBar.value should be testPartialURL after switching back to partialURLTab');
is(gURLBar.textValue, testPartialURL, 'gURLBar.textValue should be testPartialURL after switching back to partialURLTab');
gBrowser.selectedTab = deletedURLTab;
is(gURLBar.value, '', 'gURLBar.value should be "" after switching back to deletedURLTab');
is(gURLBar.textValue, '', 'gURLBar.textValue should be "" after switching back to deletedURLTab');
gBrowser.selectedTab = fullURLTab;
is(gURLBar.value, testURL, 'gURLBar.value should be testURL after switching back to fullURLTab');
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after switching back to fullURLTab');
}
// function borrowed from browser_bug386835.js
@ -59,13 +58,13 @@ function test() {
function prepareDeletedURLTab(cb) {
gBrowser.selectedTab = deletedURLTab;
is(gURLBar.value, testURL, 'gURLBar.value should be testURL after initial switch to deletedURLTab');
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to deletedURLTab');
// simulate the user removing the whole url from the location bar
gPrefService.setBoolPref("browser.urlbar.clickSelectsAll", true);
urlbarBackspace(function () {
is(gURLBar.value, "", 'gURLBar.value should be "" (just set)');
is(gURLBar.textValue, "", 'gURLBar.textValue should be "" (just set)');
if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll"))
gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
cb();
@ -74,13 +73,13 @@ function test() {
function prepareFullURLTab(cb) {
gBrowser.selectedTab = fullURLTab;
is(gURLBar.value, testURL, 'gURLBar.value should be testURL after initial switch to fullURLTab');
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to fullURLTab');
cb();
}
function preparePartialURLTab(cb) {
gBrowser.selectedTab = partialURLTab;
is(gURLBar.value, testURL, 'gURLBar.value should be testURL after initial switch to partialURLTab');
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to partialURLTab');
// simulate the user removing part of the url from the location bar
gPrefService.setBoolPref("browser.urlbar.clickSelectsAll", false);
@ -91,7 +90,7 @@ function test() {
if (deleted < charsToDelete) {
urlbarBackspace(arguments.callee);
} else {
is(gURLBar.value, testPartialURL, "gURLBar.value should be testPartialURL (just set)");
is(gURLBar.textValue, testPartialURL, "gURLBar.textValue should be testPartialURL (just set)");
if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll"))
gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
cb();

View File

@ -31,7 +31,8 @@ let tests = [
setup: function() {
gURLBar.value = testActionURL;
gURLBar.valueIsTyped = true;
is(gURLBar.value, testActionURL, "gURLBar.value starts with correct value");
is(gURLBar.value, testActionURL, "gURLBar starts with the correct real value");
is(gURLBar.textValue, testURL, "gURLBar starts with the correct display value");
// Focus the urlbar so we can select it all & copy
gURLBar.focus();
@ -73,7 +74,8 @@ let tests = [
gURLBar.value = testActionURL;
gURLBar.valueIsTyped = true;
// Sanity check that we have the right value
is(gURLBar.value, testActionURL, "gURLBar.value starts with correct value");
is(gURLBar.value, testActionURL, "gURLBar starts with the correct real value");
is(gURLBar.textValue, testURL, "gURLBar starts with the correct display value");
// Now just select part of the value & cut that.
gURLBar.selectionStart = testURL.length - 10;

View File

@ -45,10 +45,12 @@ function testNext() {
gURLBar.addEventListener("focus", function onFocus() {
gURLBar.removeEventListener("focus", onFocus);
gURLBar.inputField.value = inputValue.slice(0, -1);
EventUtils.synthesizeKey(inputValue.slice(-1) , {});
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
});
gBrowser.selectedBrowser.focus();
gURLBar.inputField.value = inputValue;
gURLBar.focus();
}

View File

@ -37,10 +37,10 @@ function runShiftLeftClickTest() {
addPageShowListener(aWindow.gBrowser.selectedBrowser, function() {
executeSoon(function () {
info("URL should be loaded in a new window");
is(gURLBar.value, "", "Urlbar reverted to original value");
is(gURLBar.value, "", "Urlbar reverted to original value");
is(gFocusManager.focusedElement, null, "There should be no focused element");
is(gFocusManager.focusedWindow, aWindow.gBrowser.contentWindow, "Content window should be focused");
is(aWindow.gURLBar.value, TEST_VALUE, "New URL is loaded in new window");
is(aWindow.gURLBar.textValue, TEST_VALUE, "New URL is loaded in new window");
aWindow.close();
@ -61,7 +61,7 @@ function runNextTest() {
finish();
return;
}
info("Running test: " + test.desc);
// Tab will be blank if test.startValue is null
let tab = gBrowser.selectedTab = gBrowser.addTab(test.startValue);
@ -106,7 +106,7 @@ let gTests = [
is(gURLBar.value, "", "Urlbar reverted to original value");
ok(!gURLBar.focused, "Urlbar is no longer focused after urlbar command");
is(gBrowser.selectedTab, aTab, "Focus did not change to the new tab");
// Select the new background tab
gBrowser.selectedTab = gBrowser.selectedTab.nextSibling;
is(gURLBar.value, TEST_VALUE, "New URL is loaded in new tab");
@ -143,7 +143,7 @@ function triggerCommand(aClick, aEvent) {
if (aClick) {
is(gURLBar.getAttribute("pageproxystate"), "invalid",
"page proxy state must be invalid for go button to be visible");
EventUtils.synthesizeMouseAtCenter(gGoButton, aEvent);
EventUtils.synthesizeMouseAtCenter(gGoButton, aEvent);
}
else
EventUtils.synthesizeKey("VK_RETURN", aEvent);

View File

@ -41,7 +41,7 @@ function testNext() {
gURLBar.focus();
paste(inputValue, function() {
is(gURLBar.value, expectedURL, "entering '" + inputValue + "' strips relevant bits.");
is(gURLBar.textValue, expectedURL, "entering '" + inputValue + "' strips relevant bits.");
setTimeout(testNext, 0);
});

View File

@ -27,7 +27,7 @@ function test() {
};
let history = Cc["@mozilla.org/browser/history;1"]
.getService(Ci.mozIAsyncHistory);
history.updatePlaces({ uri: NetUtil.newURI("http://www.autofilltrimurl.com/")
history.updatePlaces({ uri: NetUtil.newURI("http://www.autofilltrimurl.com/whatever")
, visits: [ { transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED
, visitDate: Date.now() * 1000
} ]
@ -44,7 +44,8 @@ function continue_test() {
EventUtils.synthesizeKey(aTyped.substr(-1), {});
waitForSearchComplete(function () {
is(gURLBar.value, aExpected, "trim was applied correctly");
info(`Got value: ${gURLBar.value}`);
is(gURLBar.value, aExpected, "Autofilled value is as expected");
aCallback();
});
}
@ -53,9 +54,9 @@ function continue_test() {
test_autoFill("http://au", "http://autofilltrimurl.com/", function () {
test_autoFill("http://www.autofilltrimurl.com", "http://www.autofilltrimurl.com/", function () {
// Now ensure selecting from the popup correctly trims.
is(gURLBar.controller.matchCount, 1, "Found the expected number of matches");
is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
EventUtils.synthesizeKey("VK_DOWN", {});
is(gURLBar.value, "www.autofilltrimurl.com", "trim was applied correctly");
is(gURLBar.textValue, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
gURLBar.closePopup();
waitForClearHistory(finish);
});

View File

@ -156,7 +156,7 @@ function runTest(test, cb) {
function doCheck() {
if (test.setURL || test.loadURL) {
gURLBar.valueIsTyped = !!test.setURL;
is(gURLBar.value, test.expectedURL, "url bar value set");
is(gURLBar.textValue, test.expectedURL, "url bar value set");
}
testCopy(test.copyVal, test.copyExpected, cb);
@ -180,7 +180,7 @@ function testCopy(copyVal, targetValue, cb) {
let endBracket = copyVal.indexOf(">");
if (startBracket == -1 || endBracket == -1 ||
startBracket > endBracket ||
copyVal.replace("<", "").replace(">", "") != gURLBar.value) {
copyVal.replace("<", "").replace(">", "") != gURLBar.textValue) {
ok(false, "invalid copyVal: " + copyVal);
}
gURLBar.selectionStart = startBracket;

View File

@ -51,12 +51,12 @@ let gTests = [
]
function checkCurrent(aTab) {
is(gURLBar.value, TEST_VALUE, "Urlbar should preserve the value on return keypress");
is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
is(gBrowser.selectedTab, aTab, "New URL was loaded in the current tab");
}
function checkNewTab(aTab) {
is(gURLBar.value, TEST_VALUE, "Urlbar should preserve the value on return keypress");
is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
isnot(gBrowser.selectedTab, aTab, "New URL was loaded in a new tab");
}

View File

@ -11,23 +11,23 @@ function test() {
function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
is(gURLBar.value, gURLBar.trimValue(goodURL), "location bar reflects loaded page");
is(gURLBar.textValue, gURLBar.trimValue(goodURL), "location bar reflects loaded page");
typeAndSubmit(badURL);
is(gURLBar.value, gURLBar.trimValue(badURL), "location bar reflects loading page");
is(gURLBar.textValue, gURLBar.trimValue(badURL), "location bar reflects loading page");
gBrowser.contentWindow.stop();
is(gURLBar.value, gURLBar.trimValue(goodURL), "location bar reflects loaded page after stop()");
is(gURLBar.textValue, gURLBar.trimValue(goodURL), "location bar reflects loaded page after stop()");
gBrowser.removeCurrentTab();
gBrowser.selectedTab = gBrowser.addTab("about:blank");
is(gURLBar.value, "", "location bar is empty");
is(gURLBar.textValue, "", "location bar is empty");
typeAndSubmit(badURL);
is(gURLBar.value, gURLBar.trimValue(badURL), "location bar reflects loading page");
is(gURLBar.textValue, gURLBar.trimValue(badURL), "location bar reflects loading page");
gBrowser.contentWindow.stop();
is(gURLBar.value, gURLBar.trimValue(badURL), "location bar reflects stopped page in an empty tab");
is(gURLBar.textValue, gURLBar.trimValue(badURL), "location bar reflects stopped page in an empty tab");
gBrowser.removeCurrentTab();
finish();

View File

@ -5,7 +5,7 @@
function testVal(originalValue, targetValue) {
gURLBar.value = originalValue;
gURLBar.valueIsTyped = false;
is(gURLBar.value, targetValue || originalValue, "url bar value set");
is(gURLBar.textValue, targetValue || originalValue, "url bar value set");
}
function test() {
@ -96,7 +96,7 @@ function test() {
function testCopy(originalValue, targetValue, cb) {
waitForClipboard(targetValue, function () {
is(gURLBar.value, originalValue, "url bar copy value set");
is(gURLBar.textValue, originalValue, "url bar copy value set");
gURLBar.focus();
gURLBar.select();

View File

@ -6,6 +6,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm");
function closeAllNotifications () {
let notificationBox = document.getElementById("global-notificationbox");

View File

@ -132,9 +132,7 @@
-->
<method name="onBeforeValueGet">
<body><![CDATA[
if (this.hasAttribute("actiontype"))
return {value: this._value};
return null;
return {value: this._value};
]]></body>
</method>
@ -285,31 +283,31 @@
var mayInheritPrincipal = false;
var postData = null;
var action = this._parseActionUrl(url);
let action = this._parseActionUrl(this._value);
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
let matchLastLocationChange = true;
if (action) {
if (this.hasAttribute("actiontype")) {
if (action.type == "switchtab") {
url = action.params.url;
if (action.type == "switchtab") {
url = action.params.url;
if (this.hasAttribute("actiontype")) {
this.handleRevert();
let prevTab = gBrowser.selectedTab;
if (switchToTabHavingURI(url) &&
isTabEmpty(prevTab))
gBrowser.removeTab(prevTab);
return;
} else if (action.type == "keyword") {
url = action.params.url;
} else if (action.type == "searchengine") {
let engine = Services.search.getEngineByName(action.params.engineName);
let submission = engine.getSubmission(action.params.searchQuery);
url = submission.uri.spec;
postData = submission.postData;
} else if (action.type == "visiturl") {
url = action.params.url;
}
} else if (action.type == "keyword") {
url = action.params.url;
} else if (action.type == "searchengine") {
let engine = Services.search.getEngineByName(action.params.engineName);
let submission = engine.getSubmission(action.params.searchQuery);
url = submission.uri.spec;
postData = submission.postData;
} else if (action.type == "visiturl") {
url = action.params.url;
}
continueOperation.call(this);
}
@ -584,7 +582,11 @@
urlbar.inputField.value = urlbar.inputField.value.substring(0, start) +
urlbar.inputField.value.substring(end);
urlbar.selectionStart = urlbar.selectionEnd = start;
urlbar.removeAttribute("actiontype");
let event = document.createEvent("UIEvents");
event.initUIEvent("input", true, false, window, 0);
urlbar.dispatchEvent(event);
SetPageProxyState("invalid");
}
@ -704,8 +706,10 @@
]]></body>
</method>
<property name="textValue"
onget="return this.value;">
<property name="textValue">
<getter><![CDATA[
return this.inputField.value;
]]></getter>
<setter>
<![CDATA[
try {
@ -714,8 +718,10 @@
// Trim popup selected values, but never trim results coming from
// autofill.
if (this.popup.selectedIndex == -1)
if (this.popup.selectedIndex == -1 ||
this.mController.getStyleAt(this.popup.selectedIndex) == "autofill") {
this._disableTrim = true;
}
this.value = val;
this._disableTrim = false;
@ -740,7 +746,6 @@
// URL is in the format moz-action:ACTION,PARAMS
// Where PARAMS is a JSON encoded object.
aUrl = decodeURI(aUrl);
let [, type, params] = aUrl.match(/^moz-action:([^,]+),(.*)$/);
let action = {
@ -786,6 +791,19 @@
this.inputField.setSelectionRange(aStartIndex, aEndIndex);
]]></body>
</method>
<method name="onInput">
<parameter name="aEvent"/>
<body><![CDATA[
if (!this.mIgnoreInput && this.mController.input == this) {
this._value = this.inputField.value;
gBrowser.userTypedValue = this.value;
this.valueIsTyped = true;
this.mController.handleText();
}
this.resetActionType();
]]></body>
</method>
</implementation>
<handlers>
@ -819,7 +837,7 @@
<handler event="dragstart" phase="capturing"><![CDATA[
// Drag only if the gesture starts from the input field.
if (this.inputField != event.originalTarget &&
if (this.inputField != event.originalTarget &&
!(this.inputField.compareDocumentPosition(event.originalTarget) &
Node.DOCUMENT_POSITION_CONTAINED_BY))
return;
@ -943,6 +961,35 @@
createBundle("chrome://browser/locale/places/places.properties");
</field>
<!-- Override this so that navigating between items results in an item
always being selected. This is contrary to the normal behaviour where
if you navigate beyond either end of the list, no item will be
selected. -->
<method name="getNextIndex">
<parameter name="reverse"/>
<parameter name="amount"/>
<parameter name="index"/>
<parameter name="maxRow"/>
<body><![CDATA[
if (maxRow < 0)
return -1;
let newIndex = index + (reverse ? -1 : 1) * amount;
// We don't want to wrap if navigation in any direction by one item.
// Otherwise we clamp to one end of the list.
// ie, hitting page-down will only cause is to wrap if we're already
// at one end of the list.
if (newIndex < 0) {
newIndex = index > 0 ? 0 : maxRow;
} else if (newIndex > maxRow) {
newIndex = index < maxRow ? maxRow : 0;
}
return newIndex;
]]></body>
</method>
<property name="maxResults" readonly="true">
<getter>
<![CDATA[
@ -1050,6 +1097,18 @@
</body>
</method>
<method name="onResultsAdded">
<body>
<![CDATA[
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
return;
if (this._matchCount > 0 && this.selectedIndex == -1)
this.selectedIndex = 0;
]]>
</body>
</method>
</implementation>
</binding>

View File

@ -413,13 +413,12 @@ this.DownloadsCommon = {
if (shouldApplySmoothing) {
// Apply hysteresis to favor downward over upward swings. Trust only 30%
// of the new value if lower, and 10% if higher (exponential smoothing).
let (diff = aSeconds - aLastSeconds) {
aSeconds = aLastSeconds + (diff < 0 ? .3 : .1) * diff;
}
let diff = aSeconds - aLastSeconds;
aSeconds = aLastSeconds + (diff < 0 ? .3 : .1) * diff;
// If the new time is similar, reuse something close to the last time
// left, but subtract a little to provide forward progress.
let diff = aSeconds - aLastSeconds;
diff = aSeconds - aLastSeconds;
let diffPercent = diff / aLastSeconds * 100;
if (Math.abs(diff) < 5 || Math.abs(diffPercent) < 5) {
aSeconds = aLastSeconds - (diff < 0 ? .4 : .2);

View File

@ -21,6 +21,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "LOOP_SESSION_TYPE",
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
"resource:///modules/loop/LoopContacts.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
/**
* Attempts to open a websocket.
@ -326,6 +328,50 @@ let LoopCallsInternal = {
return true;
},
/**
* Block a caller so it will show up in the contacts list as a blocked contact.
* If the contact is not yet part of the users' contacts list, it will be added
* as a blocked contact directly.
*
* @param {String} callerId Email address or phone number that may identify
* the caller as an existing contact
* @param {Function} callback Function that will be invoked once the operation
* has completed. When an error occurs, it will be
* passed as its first argument
*/
blockDirectCaller: function(callerId, callback) {
let field = callerId.contains("@") ? "email" : "tel";
Task.spawn(function* () {
// See if we can find the caller in our database.
let contacts = yield LoopContacts.promise("search", {
q: callerId,
field: field
});
let contact;
if (contacts.length) {
for (contact of contacts) {
yield LoopContacts.promise("block", contact._guid);
}
} else {
// If the contact doesn't exist yet, add it as a blocked contact.
contact = {
id: MozLoopService.generateUUID(),
name: [callerId],
category: ["local"],
blocked: true
};
// Add the phone OR email field to the contact.
contact[field] = [{
pref: true,
value: callerId
}];
yield LoopContacts.promise("add", contact);
}
}).then(callback, callback);
},
/**
* Open call progress websocket and terminate with a reason of busy
* the server.
@ -400,6 +446,13 @@ this.LoopCalls = {
*/
startDirectCall: function(contact, callType) {
LoopCallsInternal.startDirectCall(contact, callType);
},
/**
* @see LoopCallsInternal#blockDirectCaller
*/
blockDirectCaller: function(callerId, callback) {
return LoopCallsInternal.blockDirectCaller(callerId, callback);
}
};
Object.freeze(LoopCalls);

View File

@ -774,7 +774,14 @@ let MozLoopServiceInternal = {
openChatWindow: function(conversationWindowData) {
// So I guess the origin is the loop server!?
let origin = this.loopServerUri;
let windowId = gLastWindowId++;
// Try getting a window ID that can (re-)identify this conversation, or resort
// to a globally unique one as a last resort.
// XXX We can clean this up once rooms and direct contact calling are the only
// two modes left.
let windowId = ("contact" in conversationWindowData) ?
conversationWindowData.contact._guid || gLastWindowId++ :
conversationWindowData.roomToken || conversationWindowData.callId ||
gLastWindowId++;
// Store the id as a string, as that's what we use elsewhere.
windowId = windowId.toString();
@ -1421,9 +1428,12 @@ this.MozLoopService = {
*/
openGettingStartedTour: Task.async(function(aSrc = null) {
try {
let url = new URL(Services.prefs.getCharPref("loop.gettingStarted.url"));
let urlStr = Services.prefs.getCharPref("loop.gettingStarted.url");
let url = new URL(Services.urlFormatter.formatURL(urlStr));
if (aSrc) {
url.searchParams.set("source", aSrc);
url.searchParams.set("utm_source", "firefox-browser");
url.searchParams.set("utm_medium", "firefox-browser");
url.searchParams.set("utm_campaign", aSrc);
}
let win = Services.wm.getMostRecentWindow("navigator:browser");
win.switchToTabHavingURI(url, true, {replaceQueryString: true});

View File

@ -20,6 +20,9 @@ loop.conversation = (function(mozL10n) {
var CallIdentifierView = loop.conversationViews.CallIdentifierView;
var DesktopRoomConversationView = loop.roomViews.DesktopRoomConversationView;
// Matches strings of the form "<nonspaces>@<nonspaces>" or "+<digits>"
var EMAIL_OR_PHONE_RE = /^(:?\S+@\S+|\+\d+)$/;
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
@ -505,14 +508,27 @@ loop.conversation = (function(mozL10n) {
declineAndBlock: function() {
navigator.mozLoop.stopAlerting();
var token = this.props.conversation.get("callToken");
this.props.client.deleteCallUrl(token,
this.props.conversation.get("sessionType"),
function(error) {
var callerId = this.props.conversation.get("callerId");
// If this is a direct call, we'll need to block the caller directly.
if (callerId && EMAIL_OR_PHONE_RE.test(callerId)) {
navigator.mozLoop.calls.blockDirectCaller(callerId, function(err) {
// XXX The conversation window will be closed when this cb is triggered
// figure out if there is a better way to report the error to the user
// (bug 1048909).
console.log(error);
// (bug 1103150).
console.log(err.fileName + ":" + err.lineNumber + ": " + err.message);
});
} else {
this.props.client.deleteCallUrl(token,
this.props.conversation.get("sessionType"),
function(error) {
// XXX The conversation window will be closed when this cb is triggered
// figure out if there is a better way to report the error to the user
// (bug 1048909).
console.log(error);
});
}
this._declineCall();
},

View File

@ -20,6 +20,9 @@ loop.conversation = (function(mozL10n) {
var CallIdentifierView = loop.conversationViews.CallIdentifierView;
var DesktopRoomConversationView = loop.roomViews.DesktopRoomConversationView;
// Matches strings of the form "<nonspaces>@<nonspaces>" or "+<digits>"
var EMAIL_OR_PHONE_RE = /^(:?\S+@\S+|\+\d+)$/;
var IncomingCallView = React.createClass({
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
@ -505,14 +508,27 @@ loop.conversation = (function(mozL10n) {
declineAndBlock: function() {
navigator.mozLoop.stopAlerting();
var token = this.props.conversation.get("callToken");
this.props.client.deleteCallUrl(token,
this.props.conversation.get("sessionType"),
function(error) {
var callerId = this.props.conversation.get("callerId");
// If this is a direct call, we'll need to block the caller directly.
if (callerId && EMAIL_OR_PHONE_RE.test(callerId)) {
navigator.mozLoop.calls.blockDirectCaller(callerId, function(err) {
// XXX The conversation window will be closed when this cb is triggered
// figure out if there is a better way to report the error to the user
// (bug 1048909).
console.log(error);
// (bug 1103150).
console.log(err.fileName + ":" + err.lineNumber + ": " + err.message);
});
} else {
this.props.client.deleteCallUrl(token,
this.props.conversation.get("sessionType"),
function(error) {
// XXX The conversation window will be closed when this cb is triggered
// figure out if there is a better way to report the error to the user
// (bug 1048909).
console.log(error);
});
}
this._declineCall();
},

View File

@ -165,12 +165,11 @@ loop.panel = (function(_, mozL10n) {
});
var GettingStartedView = React.createClass({displayName: 'GettingStartedView',
componentDidMount: function() {
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
},
handleButtonClick: function() {
navigator.mozLoop.openGettingStartedTour();
navigator.mozLoop.openGettingStartedTour("getting-started");
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
var event = new CustomEvent("GettingStartedSeen");
window.dispatchEvent(event);
},
render: function() {
@ -287,7 +286,7 @@ loop.panel = (function(_, mozL10n) {
},
openGettingStartedTour: function() {
navigator.mozLoop.openGettingStartedTour("settingsMenu");
navigator.mozLoop.openGettingStartedTour("settings-menu");
},
render: function() {
@ -694,6 +693,7 @@ loop.panel = (function(_, mozL10n) {
getInitialState: function() {
return {
userProfile: this.props.userProfile || navigator.mozLoop.userProfile,
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
};
},
@ -741,6 +741,12 @@ loop.panel = (function(_, mozL10n) {
this.updateServiceErrors();
},
_gettingStartedSeen: function() {
this.setState({
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
});
},
/**
* The rooms feature is hidden by default for now. Once it gets mainstream,
* this method can be simplified.
@ -750,7 +756,6 @@ loop.panel = (function(_, mozL10n) {
return (
Tab({name: "call"},
React.DOM.div({className: "content-area"},
GettingStartedView(null),
CallUrlResult({client: this.props.client,
notifications: this.props.notifications,
callUrl: this.props.callUrl}),
@ -762,7 +767,6 @@ loop.panel = (function(_, mozL10n) {
return (
Tab({name: "rooms"},
GettingStartedView(null),
RoomList({dispatcher: this.props.dispatcher,
store: this.props.roomStore,
userDisplayName: this._getUserDisplayName()}),
@ -786,10 +790,12 @@ loop.panel = (function(_, mozL10n) {
componentDidMount: function() {
window.addEventListener("LoopStatusChanged", this._onStatusChanged);
window.addEventListener("GettingStartedSeen", this._gettingStartedSeen);
},
componentWillUnmount: function() {
window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
window.removeEventListener("GettingStartedSeen", this._gettingStartedSeen);
},
_getUserDisplayName: function() {
@ -800,6 +806,17 @@ loop.panel = (function(_, mozL10n) {
render: function() {
var NotificationListView = sharedViews.NotificationListView;
if (!this.state.gettingStartedSeen) {
return (
React.DOM.div(null,
NotificationListView({notifications: this.props.notifications,
clearOnDocumentHidden: true}),
GettingStartedView(null),
ToSView(null)
)
);
}
return (
React.DOM.div(null,
NotificationListView({notifications: this.props.notifications,

View File

@ -165,12 +165,11 @@ loop.panel = (function(_, mozL10n) {
});
var GettingStartedView = React.createClass({
componentDidMount: function() {
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
},
handleButtonClick: function() {
navigator.mozLoop.openGettingStartedTour();
navigator.mozLoop.openGettingStartedTour("getting-started");
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
var event = new CustomEvent("GettingStartedSeen");
window.dispatchEvent(event);
},
render: function() {
@ -287,7 +286,7 @@ loop.panel = (function(_, mozL10n) {
},
openGettingStartedTour: function() {
navigator.mozLoop.openGettingStartedTour("settingsMenu");
navigator.mozLoop.openGettingStartedTour("settings-menu");
},
render: function() {
@ -694,6 +693,7 @@ loop.panel = (function(_, mozL10n) {
getInitialState: function() {
return {
userProfile: this.props.userProfile || navigator.mozLoop.userProfile,
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
};
},
@ -741,6 +741,12 @@ loop.panel = (function(_, mozL10n) {
this.updateServiceErrors();
},
_gettingStartedSeen: function() {
this.setState({
gettingStartedSeen: navigator.mozLoop.getLoopPref("gettingStarted.seen"),
});
},
/**
* The rooms feature is hidden by default for now. Once it gets mainstream,
* this method can be simplified.
@ -750,7 +756,6 @@ loop.panel = (function(_, mozL10n) {
return (
<Tab name="call">
<div className="content-area">
<GettingStartedView />
<CallUrlResult client={this.props.client}
notifications={this.props.notifications}
callUrl={this.props.callUrl} />
@ -762,7 +767,6 @@ loop.panel = (function(_, mozL10n) {
return (
<Tab name="rooms">
<GettingStartedView />
<RoomList dispatcher={this.props.dispatcher}
store={this.props.roomStore}
userDisplayName={this._getUserDisplayName()}/>
@ -786,10 +790,12 @@ loop.panel = (function(_, mozL10n) {
componentDidMount: function() {
window.addEventListener("LoopStatusChanged", this._onStatusChanged);
window.addEventListener("GettingStartedSeen", this._gettingStartedSeen);
},
componentWillUnmount: function() {
window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
window.removeEventListener("GettingStartedSeen", this._gettingStartedSeen);
},
_getUserDisplayName: function() {
@ -800,6 +806,17 @@ loop.panel = (function(_, mozL10n) {
render: function() {
var NotificationListView = sharedViews.NotificationListView;
if (!this.state.gettingStartedSeen) {
return (
<div>
<NotificationListView notifications={this.props.notifications}
clearOnDocumentHidden={true} />
<GettingStartedView />
<ToSView />
</div>
);
}
return (
<div>
<NotificationListView notifications={this.props.notifications}

View File

@ -107,7 +107,6 @@ body {
#fte-getstarted {
padding-top: 1em;
padding-bottom: 1em;
border-bottom: 1px solid #ccc;
margin-bottom: 1em;
}
@ -499,7 +498,7 @@ body[dir=rtl] .generate-url-spinner {
}
#powered-by-logo.en-GB,
#powered-by-logo.de-DE {
#powered-by-logo.de {
background-image: url("../img/02.png");
background-size: 21px 20px;
width: 21px;
@ -526,7 +525,7 @@ body[dir=rtl] .generate-url-spinner {
}
#powered-by-logo.en-GB,
#powered-by-logo.de-DE {
#powered-by-logo.de {
background-image: url("../img/02@2x.png");
}

View File

@ -75,6 +75,8 @@ loop.store.ConversationStore = (function() {
// Call Connection information
// The call id from the loop-server
callId: undefined,
// The caller id of the contacting side
callerId: undefined,
// The connection progress url to connect the websocket
progressURL: undefined,
// The websocket token that allows connection to the progress url

View File

@ -12,7 +12,7 @@
# Bug 1066176 tracks moving all functionality currently here
# to the Gruntfile and getting rid of this Makefile entirely.
LOOP_SERVER_URL := $(shell echo $${LOOP_SERVER_URL-http://localhost:5000})
LOOP_SERVER_URL := $(shell echo $${LOOP_SERVER_URL-http://localhost:5000/v0})
LOOP_FEEDBACK_API_URL := $(shell echo $${LOOP_FEEDBACK_API_URL-"https://input.allizom.org/api/v1/feedback"})
LOOP_FEEDBACK_PRODUCT_NAME := $(shell echo $${LOOP_FEEDBACK_PRODUCT_NAME-Loop})
LOOP_BRAND_WEBSITE_URL := $(shell echo $${LOOP_BRAND_WEBSITE_URL-"https://www.mozilla.org/firefox/"})

View File

@ -18,7 +18,7 @@ function getConfigFile(req, res) {
res.send([
"var loop = loop || {};",
"loop.config = loop.config || {};",
"loop.config.serverUrl = 'http://localhost:" + loopServerPort + "';",
"loop.config.serverUrl = 'http://localhost:" + loopServerPort + "/v0';",
"loop.config.feedbackApiUrl = '" + feedbackApiUrl + "';",
"loop.config.feedbackProductName = '" + feedbackProductName + "';",
// XXX Update with the real marketplace url once the FxOS Loop app is

View File

@ -175,7 +175,8 @@ describe("loop.panel", function() {
describe("loop.rooms.enabled on", function() {
beforeEach(function() {
navigator.mozLoop.getLoopPref = function(pref) {
if (pref === "rooms.enabled") {
if (pref === "rooms.enabled" ||
pref === "gettingStarted.seen") {
return true;
}
};
@ -208,6 +209,8 @@ describe("loop.panel", function() {
navigator.mozLoop.getLoopPref = function(pref) {
if (pref === "rooms.enabled") {
return false;
} else if (pref === "gettingStarted.seen") {
return true;
}
};
@ -373,6 +376,9 @@ describe("loop.panel", function() {
});
it("should render a GettingStarted view", function() {
navigator.mozLoop.getLoopPref = function(pref) {
return false;
};
var view = createTestPanelView();
TestUtils.findRenderedComponentWithType(view, loop.panel.GettingStartedView);

View File

@ -40,6 +40,7 @@ function* checkFxA401() {
add_task(function* setup() {
Services.prefs.setCharPref("loop.server", BASE_URL);
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
MozLoopServiceInternal.mocks.pushHandler = mockPushHandler;
// Normally the same pushUrl would be registered but we change it in the test
// to be able to check for success on the second registration.
@ -51,6 +52,7 @@ add_task(function* setup() {
yield promiseDeletedOAuthParams(BASE_URL);
Services.prefs.clearUserPref("loop.server");
Services.prefs.clearUserPref("services.push.serverURL");
Services.prefs.clearUserPref("loop.gettingStarted.seen");
MozLoopServiceInternal.mocks.pushHandler = undefined;
delete mockPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA];
delete mockPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA];

View File

@ -9,11 +9,13 @@
Components.utils.import("resource://gre/modules/Promise.jsm", this);
const {LoopRoomsInternal} = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
registerCleanupFunction(function*() {
MozLoopService.doNotDisturb = false;
MozLoopServiceInternal.fxAOAuthProfile = null;
yield MozLoopServiceInternal.clearError("testing");
Services.prefs.clearUserPref("loop.gettingStarted.seen");
});
add_task(function* test_doNotDisturb() {

View File

@ -299,8 +299,8 @@ add_task(function* test_openRoom() {
Assert.ok(openedUrl, "should open a chat window");
// Stop the busy kicking in for following tests.
let windowId = openedUrl.match(/about:loopconversation\#(\d+)$/)[1];
// Stop the busy kicking in for following tests. (note: windowId can be 'fakeToken')
let windowId = openedUrl.match(/about:loopconversation\#(\w+)$/)[1];
let windowData = MozLoopService.getConversationWindowData(windowId);
Assert.equal(windowData.type, "room", "window data should contain room as the type");

View File

@ -123,14 +123,16 @@ function doOnloadOnce(aCallback) {
}
function* promiseOnLoad() {
let deferred = Promise.defer();
gBrowser.addEventListener("load", function onLoadListener(aEvent) {
info("onLoadListener: " + aEvent.originalTarget.location);
gBrowser.removeEventListener("load", onLoadListener, true);
deferred.resolve(aEvent);
}, true);
return deferred.promise;
return new Promise(resolve => {
gBrowser.addEventListener("load", function onLoadListener(aEvent) {
let cw = aEvent.target.defaultView;
let tab = gBrowser._getTabForContentWindow(cw);
if (tab) {
info("onLoadListener: " + aEvent.originalTarget.location);
gBrowser.removeEventListener("load", onLoadListener, true);
resolve(aEvent);
}
}, true);
});
}

View File

@ -648,8 +648,21 @@ let SessionStoreInternal = {
let uri = activePageData ? activePageData.url || null : null;
browser.userTypedValue = uri;
// Update tab label and icon again after the tab history was updated.
this.updateTabLabelAndIcon(tab, tabData);
// If the page has a title, set it.
if (activePageData) {
if (activePageData.title) {
tab.label = activePageData.title;
tab.crop = "end";
} else if (activePageData.url != "about:blank") {
tab.label = activePageData.url;
tab.crop = "center";
}
}
// Restore the tab icon.
if ("image" in tabData) {
win.gBrowser.setIcon(tab, tabData.image);
}
let event = win.document.createEvent("Events");
event.initEvent("SSTabRestoring", true, false);
@ -1860,26 +1873,6 @@ let SessionStoreInternal = {
}
},
updateTabLabelAndIcon(tab, tabData) {
let activePageData = tabData.entries[tabData.index - 1] || null;
// If the page has a title, set it.
if (activePageData) {
if (activePageData.title) {
tab.label = activePageData.title;
tab.crop = "end";
} else if (activePageData.url != "about:blank") {
tab.label = activePageData.url;
tab.crop = "center";
}
}
// Restore the tab icon.
if ("image" in tabData) {
tab.ownerDocument.defaultView.gBrowser.setIcon(tab, tabData.image);
}
},
/**
* Restores the session state stored in LastSession. This will attempt
* to merge data into the current session. If a window was opened at startup
@ -2552,17 +2545,9 @@ let SessionStoreInternal = {
this._windows[aWindow.__SSi].selected = aSelectTab;
}
// If we restore the selected tab, make sure it goes first.
let selectedIndex = aTabs.indexOf(tabbrowser.selectedTab);
if (selectedIndex > -1) {
this.restoreTab(tabbrowser.selectedTab, aTabData[selectedIndex]);
}
// Restore all tabs.
for (let t = 0; t < aTabs.length; t++) {
if (t != selectedIndex) {
this.restoreTab(aTabs[t], aTabData[t]);
}
this.restoreTab(aTabs[t], aTabData[t]);
}
},
@ -2668,10 +2653,6 @@ let SessionStoreInternal = {
browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory",
{tabData: tabData, epoch: epoch});
// Update tab label and icon to show something
// while we wait for the messages to be processed.
this.updateTabLabelAndIcon(tab, tabData);
// Restore tab attributes.
if ("attributes" in tabData) {
TabAttributes.set(tab, tabData.attributes);

View File

@ -193,16 +193,16 @@ function test() {
is(browser.userTypedValue, null, "userTypedValue is empty to start");
is(browser.userTypedClear, 0, "userTypedClear is 0 to start");
gURLBar.value = "example.org";
let event = document.createEvent("Events");
event.initEvent("input", true, false);
gURLBar.dispatchEvent(event);
let inputText = "example.org";
gURLBar.focus();
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
executeSoon(function () {
is(browser.userTypedValue, "example.org",
"userTypedValue was set when changing gURLBar.value");
"userTypedValue was set when changing URLBar value");
is(browser.userTypedClear, 0,
"userTypedClear was not changed when changing gURLBar.value");
"userTypedClear was not changed when changing URLBar value");
// Now make sure ss gets these values too
let newState = JSON.parse(ss.getBrowserState());
@ -235,7 +235,7 @@ function test() {
"userTypedValue was null after loading a URI");
is(browser.userTypedClear, 0,
"userTypeClear reset to 0");
is(gURLBar.value, gURLBar.trimValue("http://example.com/"),
is(gURLBar.textValue, gURLBar.trimValue("http://example.com/"),
"Address bar's value set after loading URI");
runNextTest();
});

View File

@ -98,25 +98,25 @@ support-files =
testactors.js
[browser_dbg_aaa_run_first_leaktest.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_addonactor.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_addon-sources.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_addon-modules.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_addon-modules-unpacked.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_addon-panels.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_addon-console.js]
skip-if = e10s || os == 'win' # bug 1005274
skip-if = e10s && debug || os == 'win' # bug 1005274
[browser_dbg_auto-pretty-print-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_auto-pretty-print-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_bfcache.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_blackboxing-01.js]
skip-if = e10s && debug
[browser_dbg_blackboxing-02.js]
@ -130,9 +130,9 @@ skip-if = e10s && debug
[browser_dbg_blackboxing-06.js]
skip-if = e10s && debug
[browser_dbg_breadcrumbs-access.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_break-on-dom-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_break-on-dom-02.js]
skip-if = e10s && debug
[browser_dbg_break-on-dom-03.js]
@ -150,7 +150,7 @@ skip-if = e10s && debug
[browser_dbg_break-on-dom-event-01.js]
skip-if = e10s || os == "mac" || e10s # Bug 895426
[browser_dbg_break-on-dom-event-02.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_breakpoints-actual-location.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-actual-location2.js]
@ -180,21 +180,21 @@ skip-if = e10s && debug
[browser_dbg_breakpoints-reload.js]
skip-if = e10s && debug
[browser_dbg_chrome-create.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_chrome-debugging.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_clean-exit-window.js]
skip-if = true # Bug 933950 (leaky test)
[browser_dbg_clean-exit.js]
skip-if = true # Bug 1044985 (racy test)
[browser_dbg_closure-inspection.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_cmd-blackbox.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_cmd-break.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_cmd-dbg.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_conditional-breakpoints-01.js]
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-02.js]
@ -212,73 +212,73 @@ skip-if = e10s && debug
[browser_dbg_server-conditional-bp-04.js]
skip-if = e10s && debug
[browser_dbg_controller-evaluate-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_controller-evaluate-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_debugger-statement.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_editor-contextmenu.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_editor-mode.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_event-listeners-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_event-listeners-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_event-listeners-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_file-reload.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_function-display-name.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_global-method-override.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_globalactor.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_hide-toolbar-buttons.js]
skip-if = e10s
[browser_dbg_hit-counts-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_hit-counts-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_host-layout.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_iframes.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_instruments-pane-collapse.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_interrupts.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_listaddons.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_listtabs-01.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_listtabs-02.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_listtabs-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_location-changes-01-simple.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_location-changes-02-blank.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_location-changes-03-new.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_location-changes-04-breakpoint.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_multiple-windows.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_navigation.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_no-page-sources.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_on-pause-highlight.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_on-pause-raise.js]
skip-if = e10s || os == "linux" || e10s # Bug 888811 & bug 891176
skip-if = e10s && debug || os == "linux" # Bug 888811 & bug 891176
[browser_dbg_optimized-out-vars.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_panel-size.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_parser-01.js]
skip-if = e10s && debug
[browser_dbg_parser-02.js]
@ -300,13 +300,13 @@ skip-if = e10s && debug
[browser_dbg_parser-10.js]
skip-if = e10s && debug
[browser_dbg_pause-exceptions-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_pause-exceptions-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_pause-resume.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_pause-warning.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_paused-keybindings.js]
skip-if = e10s
[browser_dbg_pretty-print-01.js]
@ -338,21 +338,21 @@ skip-if = e10s && debug
[browser_dbg_pretty-print-on-paused.js]
skip-if = e10s && debug
[browser_dbg_progress-listener-bug.js]
skip-if = e10s
skip-if = e10a && debug
[browser_dbg_reload-preferred-script-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_reload-preferred-script-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_reload-preferred-script-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_reload-same-script.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_scripts-switching-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_scripts-switching-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_scripts-switching-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_search-autofill-identifier.js]
skip-if = e10s && debug
[browser_dbg_search-basic-01.js]
@ -400,13 +400,13 @@ skip-if = e10s && debug
[browser_dbg_source-maps-04.js]
skip-if = e10s # Bug 1093535
[browser_dbg_sources-cache.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_sources-labels.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_sources-sorting.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_split-console-paused-reload.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_stack-01.js]
skip-if = e10s && debug
[browser_dbg_stack-02.js]
@ -422,13 +422,13 @@ skip-if = e10s && debug
[browser_dbg_stack-07.js]
skip-if = e10s && debug
[browser_dbg_step-out.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tabactor-01.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_tabactor-02.js]
skip-if = e10s
skip-if = e10s # TODO
[browser_dbg_terminate-on-tab-close.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-01.js]
skip-if = e10s && debug
[browser_dbg_tracing-02.js]

View File

@ -14,15 +14,14 @@ function test() {
// GC from previous tests does not interfere with the debugger suite.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
ok(aTab, "Should have a tab available.");
ok(aDebuggee, "Should have a debuggee available.");
ok(aPanel, "Should have a debugger pane available.");
waitForSourceAndCaretAndScopes(aPanel, "-02.js", 1).then(() => {
resumeDebuggerThenCloseAndFinish(aPanel);
});
aDebuggee.firstCall();
callInTab(aTab, "firstCall");
});
}

View File

@ -5,7 +5,7 @@
const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gPrefs, gOptions, gView;
let gFirstSourceLabel = "code_ugly-5.js";
@ -15,9 +15,8 @@ let gOriginalPref = Services.prefs.getBoolPref("devtools.debugger.auto-pretty-pr
Services.prefs.setBoolPref("devtools.debugger.auto-pretty-print", true);
function test(){
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -99,7 +98,6 @@ function testSourceIsPretty() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gFrames;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
@ -28,7 +27,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
function checkNavigationWhileNotFocused() {

View File

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;
let gEvents = gView.EventListeners;

View File

@ -5,14 +5,13 @@
* Test that closing a tab with the debugger in a paused state exits cleanly.
*/
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -28,12 +27,11 @@ function testCleanExit() {
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED);
}).then(() => closeDebuggerAndFinish(gPanel, { whilePaused: true }));
gDebuggee.runDebuggerStatement();
callInTab(gTab, "runDebuggerStatement");
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -6,14 +6,12 @@ const TAB_URL = EXAMPLE_URL + "doc_closures.html";
// Test that inspecting a closure works as expected.
function test() {
let gPanel, gTab, gDebuggee, gDebugger;
let gPanel, gTab, gDebugger;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gDebuggee.gRecurseLimit = 2;
waitForSourceShown(gPanel, ".html")
.then(testClosure)
@ -24,13 +22,7 @@ function test() {
});
function testClosure() {
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
let gVars = gDebugger.DebuggerView.Variables;

View File

@ -9,7 +9,7 @@ const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
Task.spawn(function() {
let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
let [tab,, panel] = yield initDebugger(TAB_URL);
let win = panel.panelWin;
let frames = win.DebuggerController.StackFrames;
let framesView = win.DebuggerView.StackFrames;
@ -45,8 +45,7 @@ function test() {
"Evaluating shouldn't work while the debuggee isn't paused.");
}
// Allow this generator function to yield first.
executeSoon(() => debuggee.firstCall());
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 1);
checkView(0, 1, 1, [/secondCall/, 118]);

View File

@ -9,7 +9,7 @@ const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
Task.spawn(function() {
let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
let [tab,, panel] = yield initDebugger(TAB_URL);
let win = panel.panelWin;
let frames = win.DebuggerController.StackFrames;
let framesView = win.DebuggerView.StackFrames;
@ -38,7 +38,7 @@ function test() {
is(sources._cache.size, 2, "There should be two cached sources in the cache.");
// Allow this generator function to yield first.
executeSoon(() => debuggee.firstCall());
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 1);
checkView(0, 1, 1, [/secondCall/, 118]);

View File

@ -8,6 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
let gClient;
let gTab;
function test() {
if (!DebuggerServer.initialized) {
@ -22,7 +23,10 @@ function test() {
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachTabActorForUrl(gClient, TAB_URL))
.then((aTab) => {
gTab = aTab;
return attachTabActorForUrl(gClient, TAB_URL)
})
.then(testEarlyDebuggerStatement)
.then(testDebuggerStatement)
.then(closeConnection)
@ -45,8 +49,7 @@ function testEarlyDebuggerStatement([aGrip, aResponse]) {
// This should continue without nesting an event loop and calling
// the onPaused hook, because we haven't attached yet.
let debuggee = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
debuggee.runDebuggerStatement();
callInTab(gTab, "runDebuggerStatement");
gClient.removeListener("paused", onPaused);
@ -72,8 +75,7 @@ function testDebuggerStatement([aGrip, aResponse]) {
});
// Reach around the debugging protocol and execute the debugger statement.
let debuggee = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
debuggee.runDebuggerStatement();
callInTab(gTab, "runDebuggerStatement");
}
function closeConnection() {

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gContextMenu;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -21,7 +20,7 @@ function test() {
gContextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1).then(performTest).then(null, info);
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
function performTest() {

View File

@ -8,13 +8,12 @@
const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -29,7 +28,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
}
@ -85,7 +84,6 @@ function testSwitch2() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;

View File

@ -8,6 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-01.html";
let gClient;
let gTab;
function test() {
if (!DebuggerServer.initialized) {
@ -22,7 +23,10 @@ function test() {
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
.then((aTab) => {
gTab = aTab;
return attachThreadActorForUrl(gClient, TAB_URL)
})
.then(pauseDebuggee)
.then(testEventListeners)
.then(closeConnection)
@ -45,13 +49,7 @@ function pauseDebuggee(aThreadClient) {
deferred.resolve(aThreadClient);
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return deferred.promise;
}

View File

@ -9,6 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-03.html";
let gClient;
let gTab;
function test() {
if (!DebuggerServer.initialized) {
@ -23,7 +24,10 @@ function test() {
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
.then((aTab) => {
gTab = aTab;
return attachThreadActorForUrl(gClient, TAB_URL);
})
.then(pauseDebuggee)
.then(testEventListeners)
.then(closeConnection)
@ -46,13 +50,7 @@ function pauseDebuggee(aThreadClient) {
deferred.resolve(aThreadClient);
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return deferred.promise;
}

View File

@ -9,6 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_native-event-handler.html";
let gClient;
let gTab;
function test() {
if (!DebuggerServer.initialized) {
@ -23,7 +24,10 @@ function test() {
"Root actor should identify itself as a browser.");
addTab(TAB_URL)
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
.then((aTab) => {
gTab = aTab;
return attachThreadActorForUrl(gClient, TAB_URL)
})
.then(pauseDebuggee)
.then(testEventListeners)
.then(closeConnection)
@ -46,13 +50,7 @@ function pauseDebuggee(aThreadClient) {
deferred.resolve(aThreadClient);
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return deferred.promise;
}

View File

@ -9,7 +9,7 @@ const TAB_URL = EXAMPLE_URL + "doc_random-javascript.html";
const JS_URL = EXAMPLE_URL + "sjs_random-javascript.sjs";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gEditor = gDebugger.DebuggerView.editor;
let gSources = gDebugger.DebuggerView.Sources;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_function-display-name.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -35,7 +34,7 @@ function testAnonCall() {
testInferredName();
});
gDebuggee.evalCall();
callInTab(gTab, "evalCall");
}
function testInferredName() {
@ -57,7 +56,6 @@ function testInferredName() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -10,7 +10,7 @@
const TAB_URL = EXAMPLE_URL + "doc_global-method-override.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let gDebugger = aPanel.panelWin;
ok(gDebugger, "Should have a debugger available.");
is(gDebugger.gThreadClient.state, "attached", "Debugger should be attached.");

View File

@ -9,16 +9,15 @@
const TAB_URL = EXAMPLE_URL + "doc_same-line-functions.html";
const CODE_URL = "code_same-line-functions.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor;
function test() {
Task.async(function* () {
yield pushPrefs(["devtools.debugger.tracer", true]);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -44,9 +43,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function testHitCounts() {
@ -58,8 +55,7 @@ function testHitCounts() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
});
});

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_same-line-functions.html";
const CODE_URL = "code_same-line-functions.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor;
function test() {
Task.async(function* () {
yield pushPrefs(["devtools.debugger.tracer", true]);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -46,9 +45,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function testHitCountsBeforeStopping() {
@ -63,8 +60,7 @@ function testHitCountsAfterStopping() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
});
});

View File

@ -27,14 +27,14 @@ function testHosts(aHostTypes, aLayoutTypes) {
return Task.spawn(function() {
let [tab, debuggee, panel] = yield initDebugger("about:blank");
yield testHost(tab, debuggee, panel, firstHost, firstLayout);
yield switchAndTestHost(tab, debuggee, panel, secondHost, secondLayout);
yield switchAndTestHost(tab, debuggee, panel, thirdHost, thirdLayout);
yield testHost(tab, panel, firstHost, firstLayout);
yield switchAndTestHost(tab, panel, secondHost, secondLayout);
yield switchAndTestHost(tab, panel, thirdHost, thirdLayout);
yield teardown(panel);
});
}
function switchAndTestHost(aTab, aDebuggee, aPanel, aHostType, aLayoutType) {
function switchAndTestHost(aTab, aPanel, aHostType, aLayoutType) {
let gToolbox = aPanel._toolbox;
let gDebugger = aPanel.panelWin;
@ -48,7 +48,7 @@ function switchAndTestHost(aTab, aDebuggee, aPanel, aHostType, aLayoutType) {
yield layoutChanged;
ok(true, "The debugger's layout has changed.");
yield testHost(aTab, aDebuggee, aPanel, aHostType, aLayoutType);
yield testHost(aTab, aPanel, aHostType, aLayoutType);
});
function once(aTarget, aEvent) {
@ -58,7 +58,7 @@ function switchAndTestHost(aTab, aDebuggee, aPanel, aHostType, aLayoutType) {
}
}
function testHost(aTab, aDebuggee, aPanel, aHostType, aLayoutType) {
function testHost(aTab, aPanel, aHostType, aLayoutType) {
let gDebugger = aPanel.panelWin;
let gView = gDebugger.DebuggerView;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gPrefs, gOptions;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gPrefs = gDebugger.Prefs;
@ -146,7 +145,6 @@ function testPanesStartupPref() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gPrefs = null;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints, gTarget, gResumeButton, gResumeKey, gThreadClient;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -21,7 +20,7 @@ function test() {
gFrames = gDebugger.DebuggerView.StackFrames;
waitForSourceAndCaretAndScopes(gPanel, ".html", 14).then(performTest);
gDebuggee.simpleCall();
callInTab(gTab, "simpleCall");
});
}
@ -62,7 +61,6 @@ function testLocationChange() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -21,7 +20,7 @@ function test() {
gFrames = gDebugger.DebuggerView.StackFrames;
waitForSourceAndCaretAndScopes(gPanel, ".html", 14).then(testLocationChange);
gDebuggee.simpleCall();
callInTab(gTab, "simpleCall");
});
}
@ -53,7 +52,6 @@ function testLocationChange() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;

View File

@ -8,13 +8,12 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gToolbox, gToolboxTab;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gToolbox = gPanel._toolbox;
@ -69,7 +68,6 @@ function testResume() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gToolbox = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gNewTab, gFocusedWindow, gToolbox, gToolboxTab;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gToolbox = gPanel._toolbox;
@ -132,7 +131,6 @@ registerCleanupFunction(function() {
Services.prefs.setCharPref("devtools.toolbox.host", devtools.Toolbox.HostType.BOTTOM);
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;

View File

@ -8,7 +8,7 @@ function test() {
const TAB_URL = EXAMPLE_URL + "doc_closure-optimized-out.html";
let gDebugger, sources;
let [, debuggee, panel] = yield initDebugger(TAB_URL);
let [tab,, panel] = yield initDebugger(TAB_URL);
gDebugger = panel.panelWin;
sources = gDebugger.DebuggerView.Sources;
@ -18,11 +18,7 @@ function test() {
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
debuggee.document.querySelector("button"),
debuggee);
});
sendMouseClickToTab(tab, content.document.querySelector("button"));
yield waitForDebuggerEvents(panel, gDebugger.EVENTS.FETCHED_SCOPES);
let gVars = gDebugger.DebuggerView.Variables;

View File

@ -9,12 +9,11 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gPrefs, gSources, gInstruments;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gPrefs = gDebugger.Prefs;

View File

@ -7,14 +7,13 @@
const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gFrames, gVariables, gPrefs, gOptions;
function test() {
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
@ -78,9 +77,7 @@ function testPauseOnExceptionsDisabled() {
return finished;
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return finished;
}
@ -151,9 +148,7 @@ function testPauseOnExceptionsEnabled() {
return finished;
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return finished;
}
@ -236,7 +231,6 @@ function disableIgnoreCaughtExceptions() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gFrames = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gFrames, gVariables, gPrefs, gOptions;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
@ -105,13 +104,7 @@ function testPauseOnExceptionsAfterReload() {
return finished;
});
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee.window);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return finished;
}
@ -194,7 +187,6 @@ function disableIgnoreCaughtExceptions() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gFrames = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_pause-exceptions.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gResumeButton, gResumeKey, gFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gResumeButton = gDebugger.document.getElementById("resume");
@ -69,7 +68,6 @@ function testResume() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gResumeButton = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gTarget, gToolbox;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gTarget = gPanel.target;
@ -90,7 +89,6 @@ function testResume() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gTarget = null;

View File

@ -6,7 +6,7 @@
* WebProgress argument's DOMWindow property in onStateChange() (bug 771655).
*/
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gOldListener;
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
@ -14,9 +14,8 @@ const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
function test() {
installListener();
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -37,7 +36,7 @@ function testPause() {
resumeDebuggerThenCloseAndFinish(gPanel);
});
gDebuggee.runDebuggerStatement();
callInTab(gTab, "runDebuggerStatement");
}
// This is taken almost verbatim from bug 771655.
@ -80,7 +79,6 @@ registerCleanupFunction(function() {
}
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gOldListener = null;

View File

@ -9,13 +9,12 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
const PREFERRED_URL = EXAMPLE_URL + "code_script-switching-02.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
@ -39,7 +38,6 @@ function finishTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gSources = null;

View File

@ -10,13 +10,12 @@ const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
const FIRST_URL = EXAMPLE_URL + "code_script-switching-01.js";
const SECOND_URL = EXAMPLE_URL + "code_script-switching-02.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
@ -52,7 +51,6 @@ function switchToSource(aUrl) {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gSources = null;

View File

@ -13,12 +13,11 @@ function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gStep;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = aPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -32,7 +31,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
}
@ -187,7 +186,6 @@ function testSwitchRunning() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-02.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -29,7 +28,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
}
@ -176,7 +175,6 @@ function testSwitchRunning() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gView, gEditor, gL10N;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gView = gDebugger.DebuggerView;
@ -43,7 +42,6 @@ function testDebuggerLoadingError() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gView = null;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gUtils;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gUtils;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
@ -129,7 +128,6 @@ function checkSourcesOrder(aMethod) {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gSources = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_step-out.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVars;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVars = gDebugger.DebuggerView.Variables;
@ -41,9 +40,7 @@ function testNormalReturn() {
gDebugger);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.getElementById("return"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.getElementById("return"));
}
function testReturnWithException() {
@ -65,9 +62,7 @@ function testReturnWithException() {
gDebugger);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.getElementById("throw"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.getElementById("throw"));
}
function resumeDebuggee() {
@ -78,7 +73,6 @@ function resumeDebuggee() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVars = null;

View File

@ -7,12 +7,11 @@
const TAB_URL = EXAMPLE_URL + "doc_terminate-on-tab-close.html";
let gTab, gDebuggee, gDebugger, gPanel;
let gTab, gDebugger, gPanel;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -27,12 +26,11 @@ function testTerminate() {
});
});
gDebuggee.debuggerThenThrow();
callInTab(gTab, "debuggerThenThrow");
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -251,7 +251,7 @@ Selection.prototype = {
isHTMLNode: function() {
let xhtml_ns = "http://www.w3.org/1999/xhtml";
return this.isNode() && this.node.namespaceURI == xhtml_ns;
return this.isNode() && this.nodeFront.namespaceURI == xhtml_ns;
},
// Node type
@ -300,6 +300,24 @@ Selection.prototype = {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE;
},
/**
* @returns true if the selection is the <body> HTML element.
*/
isBodyNode: function() {
return this.isHTMLNode() &&
this.isConnected() &&
this.nodeFront.nodeName === "BODY";
},
/**
* @returns true if the selection is the <head> HTML element.
*/
isHeadNode: function() {
return this.isHTMLNode() &&
this.isConnected() &&
this.nodeFront.nodeName === "HEAD";
},
isDocumentTypeNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.DOCUMENT_TYPE_NODE;
},

View File

@ -57,7 +57,6 @@ function InspectorPanel(iframeWindow, toolbox) {
this.panelDoc = iframeWindow.document;
this.panelWin = iframeWindow;
this.panelWin.inspector = this;
this._inspector = null;
this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
this._target.on("will-navigate", this._onBeforeNavigate);
@ -109,6 +108,10 @@ InspectorPanel.prototype = {
return this._target.client.traits.getUniqueSelector;
},
get canPasteInnerOrAdjacentHTML() {
return this._target.client.traits.pasteHTML;
},
_deferredOpen: function(defaultSelection) {
let deferred = promise.defer();
@ -573,7 +576,7 @@ InspectorPanel.prototype = {
* Returns the clipboard content if it is appropriate for pasting
* into the current node's outer HTML, otherwise returns null.
*/
_getClipboardContentForOuterHTML: function Inspector_getClipboardContentForOuterHTML() {
_getClipboardContentForPaste: function Inspector_getClipboardContentForPaste() {
let flavors = clipboard.currentFlavors;
if (flavors.indexOf("text") != -1 ||
(flavors.indexOf("html") != -1 && flavors.indexOf("image") == -1)) {
@ -642,15 +645,34 @@ InspectorPanel.prototype = {
editHTML.setAttribute("disabled", "true");
}
// Enable the "paste outer HTML" item if the selection is an element and
// the root actor has the appropriate trait (isOuterHTMLEditable) and if
// the clipbard content is appropriate.
let pasteOuterHTML = this.panelDoc.getElementById("node-menu-pasteouterhtml");
if (isEditableElement && this.isOuterHTMLEditable &&
this._getClipboardContentForOuterHTML()) {
pasteOuterHTML.removeAttribute("disabled");
let pasteInnerHTML = this.panelDoc.getElementById("node-menu-pasteinnerhtml");
let pasteBefore = this.panelDoc.getElementById("node-menu-pastebefore");
let pasteAfter = this.panelDoc.getElementById("node-menu-pasteafter");
let pasteFirstChild = this.panelDoc.getElementById("node-menu-pastefirstchild");
let pasteLastChild = this.panelDoc.getElementById("node-menu-pastelastchild");
// Is the clipboard content appropriate? Is the element editable?
if (isEditableElement && this._getClipboardContentForPaste()) {
pasteInnerHTML.disabled = !this.canPasteInnerOrAdjacentHTML;
// Enable the "paste outer HTML" item if the selection is an element and
// the root actor has the appropriate trait (isOuterHTMLEditable).
pasteOuterHTML.disabled = !this.isOuterHTMLEditable;
// Don't paste before / after a root or a BODY or a HEAD element.
pasteBefore.disabled = pasteAfter.disabled =
!this.canPasteInnerOrAdjacentHTML || this.selection.isRoot() ||
this.selection.isBodyNode() || this.selection.isHeadNode();
// Don't paste as a first / last child of a HTML document element.
pasteFirstChild.disabled = pasteLastChild.disabled =
!this.canPasteInnerOrAdjacentHTML || (this.selection.isHTMLNode() &&
this.selection.isRoot());
} else {
pasteOuterHTML.setAttribute("disabled", "true");
pasteOuterHTML.disabled = true;
pasteInnerHTML.disabled = true;
pasteBefore.disabled = true;
pasteAfter.disabled = true;
pasteFirstChild.disabled = true;
pasteLastChild.disabled = true;
}
// Enable the "copy image data-uri" item if the selection is previewable
@ -690,7 +712,7 @@ InspectorPanel.prototype = {
this._markupBox.setAttribute("collapsed", true);
this._markupBox.appendChild(this._markupFrame);
this._markupFrame.setAttribute("src", "chrome://browser/content/devtools/markup-view.xhtml");
this._markupFrame.setAttribute("aria-label", this.strings.GetStringFromName("inspector.panelLabel.markupView"))
this._markupFrame.setAttribute("aria-label", this.strings.GetStringFromName("inspector.panelLabel.markupView"));
},
_onMarkupFrameLoad: function InspectorPanel__onMarkupFrameLoad() {
@ -773,8 +795,7 @@ InspectorPanel.prototype = {
/**
* Edit the outerHTML of the selected Node.
*/
editHTML: function InspectorPanel_editHTML()
{
editHTML: function InspectorPanel_editHTML() {
if (!this.selection.isNode()) {
return;
}
@ -786,22 +807,49 @@ InspectorPanel.prototype = {
/**
* Paste the contents of the clipboard into the selected Node's outer HTML.
*/
pasteOuterHTML: function InspectorPanel_pasteOuterHTML()
{
let content = this._getClipboardContentForOuterHTML();
if (content) {
let node = this.selection.nodeFront;
this.markup.getNodeOuterHTML(node).then((oldContent) => {
this.markup.updateNodeOuterHTML(node, content, oldContent);
});
}
pasteOuterHTML: function InspectorPanel_pasteOuterHTML() {
let content = this._getClipboardContentForPaste();
if (!content)
return promise.reject("No clipboard content for paste");
let node = this.selection.nodeFront;
return this.markup.getNodeOuterHTML(node).then(oldContent => {
this.markup.updateNodeOuterHTML(node, content, oldContent);
});
},
/**
* Paste the contents of the clipboard into the selected Node's inner HTML.
*/
pasteInnerHTML: function InspectorPanel_pasteInnerHTML() {
let content = this._getClipboardContentForPaste();
if (!content)
return promise.reject("No clipboard content for paste");
let node = this.selection.nodeFront;
return this.markup.getNodeInnerHTML(node).then(oldContent => {
this.markup.updateNodeInnerHTML(node, content, oldContent);
});
},
/**
* Paste the contents of the clipboard as adjacent HTML to the selected Node.
* @param position The position as specified for Element.insertAdjacentHTML
* (i.e. "beforeBegin", "afterBegin", "beforeEnd", "afterEnd").
*/
pasteAdjacentHTML: function InspectorPanel_pasteAdjacent(position) {
let content = this._getClipboardContentForPaste();
if (!content)
return promise.reject("No clipboard content for paste");
let node = this.selection.nodeFront;
return this.markup.insertAdjacentHTMLToNode(node, position, content);
},
/**
* Copy the innerHTML of the selected Node to the clipboard.
*/
copyInnerHTML: function InspectorPanel_copyInnerHTML()
{
copyInnerHTML: function InspectorPanel_copyInnerHTML() {
if (!this.selection.isNode()) {
return;
}

View File

@ -59,10 +59,36 @@
label="&inspectorShowDOMProperties.label;"
oncommand="inspector.showDOMProperties()"/>
<menuseparator/>
<menuitem id="node-menu-pasteinnerhtml"
label="&inspectorHTMLPasteInner.label;"
accesskey="&inspectorHTMLPasteInner.accesskey;"
oncommand="inspector.pasteInnerHTML()"/>
<menuitem id="node-menu-pasteouterhtml"
label="&inspectorHTMLPasteOuter.label;"
accesskey="&inspectorHTMLPasteOuter.accesskey;"
oncommand="inspector.pasteOuterHTML()"/>
<menu id="node-menu-paste-extra-submenu"
label="&inspectorHTMLPasteExtraSubmenu.label;"
accesskey="&inspectorHTMLPasteExtraSubmenu.accesskey;">
<menupopup>
<menuitem id="node-menu-pastebefore"
label="&inspectorHTMLPasteBefore.label;"
accesskey="&inspectorHTMLPasteBefore.accesskey;"
oncommand="inspector.pasteAdjacentHTML('beforeBegin')"/>
<menuitem id="node-menu-pasteafter"
label="&inspectorHTMLPasteAfter.label;"
accesskey="&inspectorHTMLPasteAfter.accesskey;"
oncommand="inspector.pasteAdjacentHTML('afterEnd')"/>
<menuitem id="node-menu-pastefirstchild"
label="&inspectorHTMLPasteFirstChild.label;"
accesskey="&inspectorHTMLPasteFirstChild.accesskey;"
oncommand="inspector.pasteAdjacentHTML('afterBegin')"/>
<menuitem id="node-menu-pastelastchild"
label="&inspectorHTMLPasteLastChild.label;"
accesskey="&inspectorHTMLPasteLastChild.accesskey;"
oncommand="inspector.pasteAdjacentHTML('beforeEnd')"/>
</menupopup>
</menu>
<menuseparator/>
<menuitem id="node-menu-delete"
label="&inspectorHTMLDelete.label;"

View File

@ -15,7 +15,8 @@ support-files =
doc_inspector_highlighter_rect_iframe.html
doc_inspector_infobar_01.html
doc_inspector_infobar_02.html
doc_inspector_menu.html
doc_inspector_menu-01.html
doc_inspector_menu-02.html
doc_inspector_remove-iframe-during-load.html
doc_inspector_search.html
doc_inspector_search-suggestions.html
@ -54,7 +55,8 @@ support-files =
[browser_inspector_inspect-object-element.js]
[browser_inspector_invalidate.js]
[browser_inspector_keyboard-shortcuts.js]
[browser_inspector_menu.js]
[browser_inspector_menu-01.js]
[browser_inspector_menu-02.js]
[browser_inspector_navigation.js]
[browser_inspector_picker-stop-on-destroy.js]
[browser_inspector_picker-stop-on-tool-change.js]

View File

@ -14,7 +14,7 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: jsterm.focusInput is
// 1) menu items are disabled/enabled depending on the clicked node
// 2) actions triggered by the items work correctly
const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu.html";
const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu-01.html";
const MENU_SENSITIVITY_TEST_DATA = [
{
desc: "doctype node",
@ -28,41 +28,6 @@ const MENU_SENSITIVITY_TEST_DATA = [
}
];
const PASTE_OUTER_HTML_TEST_DATA = [
{
desc: "some text",
clipboardData: "some text",
clipboardDataType: undefined,
disabled: false
},
{
desc: "base64 encoded image data uri",
clipboardData:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABC" +
"AAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==",
clipboardDataType: undefined,
disabled: true
},
{
desc: "html",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
disabled: false
},
{
desc: "empty string",
clipboardData: "",
clipboardDataType: undefined,
disabled: true
},
{
desc: "whitespace only",
clipboardData: " \n\n\t\n\n \n",
clipboardDataType: undefined,
disabled: true
},
];
const COPY_ITEMS_TEST_DATA = [
{
desc: "copy inner html",
@ -90,30 +55,25 @@ add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
yield testMenuItemSensitivity();
yield testPasteOuterHTMLMenuItemSensitivity();
yield testCopyMenuItems();
yield testShowDOMProperties();
yield testPasteOuterHTMLMenu();
yield testDeleteNode();
yield testDeleteRootNode();
function* testMenuItemSensitivity() {
info("Testing sensitivity of menu items for different elements.");
// The sensibility for paste options are described in browser_inspector_menu-02.js
const MENU_ITEMS = [
"node-menu-copyinner",
"node-menu-copyouter",
"node-menu-copyuniqueselector",
"node-menu-delete",
"node-menu-pasteouterhtml",
"node-menu-pseudo-hover",
"node-menu-pseudo-active",
"node-menu-pseudo-focus"
];
// To ensure clipboard contains something to paste.
clipboard.set("<p>test</p>", "html");
for (let {desc, selector, disabled} of MENU_SENSITIVITY_TEST_DATA) {
info("Testing context menu entries for " + desc);
@ -135,25 +95,6 @@ add_task(function* () {
}
}
function* testPasteOuterHTMLMenuItemSensitivity() {
info("Checking 'Paste Outer HTML' menu item sensitivity for different types" +
"of data");
let nodeFront = yield getNodeFront("p", inspector);
let markupTagLine = getContainerForNodeFront(nodeFront, inspector).tagLine;
for (let data of PASTE_OUTER_HTML_TEST_DATA) {
let { desc, clipboardData, clipboardDataType, disabled } = data;
info("Checking 'Paste Outer HTML' for " + desc);
clipboard.set(clipboardData, clipboardDataType);
yield selectNode(nodeFront, inspector);
contextMenuClick(markupTagLine);
checkMenuItem("node-menu-pasteouterhtml", disabled);
}
}
function* testCopyMenuItems() {
info("Testing various copy actions of context menu.");
for (let {desc, id, text} of COPY_ITEMS_TEST_DATA) {
@ -190,27 +131,6 @@ add_task(function* () {
yield toolbox.toggleSplitConsole();
}
function* testPasteOuterHTMLMenu() {
info("Testing that 'Paste Outer HTML' menu item works.");
clipboard.set("this was pasted");
let nodeFront = yield getNodeFront("h1", inspector);
yield selectNode(nodeFront, inspector);
contextMenuClick(getContainerForNodeFront(nodeFront, inspector).tagLine);
let onNodeReselected = inspector.markup.once("reselectedonremoved");
let menu = inspector.panelDoc.getElementById("node-menu-pasteouterhtml");
dispatchCommandEvent(menu);
info("Waiting for inspector selection to update");
yield onNodeReselected;
ok(content.document.body.outerHTML.contains(clipboard.get()),
"Clipboard content was pasted into the node's outer HTML.");
ok(!getNode("h1", { expectNoMatch: true }), "The original node was removed.");
}
function* testDeleteNode() {
info("Testing 'Delete Node' menu item for normal elements.");

View File

@ -0,0 +1,326 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test context menu functionality:
// 1) menu items are disabled/enabled depending on the clicked node
// 2) actions triggered by the items work correctly
///////////////////
//
// Whitelisting this test.
// As part of bug 1077403, the leaking uncaught rejection should be fixed.
//
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: jsterm.focusInput is not a function");
const MENU_SENSITIVITY_TEST_DATA = [
{
desc: "doctype node",
selector: null,
disabled: true,
},
{
desc: "element node",
selector: "#sensitivity",
disabled: false,
},
{
desc: "document element",
selector: "html",
disabled: {
"node-menu-pastebefore": true,
"node-menu-pasteafter": true,
"node-menu-pastefirstchild": true,
"node-menu-pastelastchild": true,
}
},
{
desc: "body",
selector: "body",
disabled: {
"node-menu-pastebefore": true,
"node-menu-pasteafter": true,
}
},
{
desc: "head",
selector: "head",
disabled: {
"node-menu-pastebefore": true,
"node-menu-pasteafter": true,
}
}
];
const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu-02.html";
const PASTE_HTML_TEST_SENSITIVITY_DATA = [
{
desc: "some text",
clipboardData: "some text",
clipboardDataType: undefined,
disabled: false
},
{
desc: "base64 encoded image data uri",
clipboardData:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABC" +
"AAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==",
clipboardDataType: undefined,
disabled: true
},
{
desc: "html",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
disabled: false
},
{
desc: "empty string",
clipboardData: "",
clipboardDataType: undefined,
disabled: true
},
{
desc: "whitespace only",
clipboardData: " \n\n\t\n\n \n",
clipboardDataType: undefined,
disabled: true
},
];
const PASTE_ADJACENT_HTML_DATA = [
{
desc: "As First Child",
clipboardData: "2",
menuId: "node-menu-pastefirstchild",
},
{
desc: "As Last Child",
clipboardData: "4",
menuId: "node-menu-pastelastchild",
},
{
desc: "Before",
clipboardData: "1",
menuId: "node-menu-pastebefore",
},
{
desc: "After",
clipboardData: "<span>5</span>",
menuId: "node-menu-pasteafter",
},
];
let clipboard = require("sdk/clipboard");
registerCleanupFunction(() => {
clipboard = null;
});
add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
yield testMenuItemSensitivity();
yield testPasteHTMLMenuItemsSensitivity();
yield testPasteOuterHTMLMenu();
yield testPasteInnerHTMLMenu();
yield testPasteAdjacentHTMLMenu();
function* testMenuItemSensitivity() {
info("Testing sensitivity of menu items for different elements.");
const MENU_ITEMS = [
"node-menu-pasteinnerhtml",
"node-menu-pasteouterhtml",
"node-menu-pastebefore",
"node-menu-pasteafter",
"node-menu-pastefirstchild",
"node-menu-pastelastchild",
];
// To ensure clipboard contains something to paste.
clipboard.set("<p>test</p>", "html");
for (let {desc, selector, disabled} of MENU_SENSITIVITY_TEST_DATA) {
info("Testing context menu entries for " + desc);
let front;
if (selector) {
front = yield getNodeFront(selector, inspector);
} else {
// Select the docType if no selector is provided
let {nodes} = yield inspector.walker.children(inspector.walker.rootNode);
front = nodes[0];
}
yield selectNode(front, inspector);
contextMenuClick(getContainerForNodeFront(front, inspector).tagLine);
for (let name of MENU_ITEMS) {
let disabledForMenu = typeof disabled === "object" ?
disabled[name] : disabled;
info(`${name} should be ${disabledForMenu ? "disabled" : "enabled"} ` +
`for ${desc}`);
checkMenuItem(name, disabledForMenu);
}
}
}
function* testPasteHTMLMenuItemsSensitivity() {
let menus = [
"node-menu-pasteinnerhtml",
"node-menu-pasteouterhtml",
"node-menu-pastebefore",
"node-menu-pasteafter",
"node-menu-pastefirstchild",
"node-menu-pastelastchild",
];
info("Checking Paste menu items sensitivity for different types" +
"of data");
let nodeFront = yield getNodeFront("#paste-area", inspector);
let markupTagLine = getContainerForNodeFront(nodeFront, inspector).tagLine;
for (let menuId of menus) {
for (let data of PASTE_HTML_TEST_SENSITIVITY_DATA) {
let { desc, clipboardData, clipboardDataType, disabled } = data;
let menuLabel = getLabelFor("#" + menuId);
info(`Checking ${menuLabel} for ${desc}`);
clipboard.set(clipboardData, clipboardDataType);
yield selectNode(nodeFront, inspector);
contextMenuClick(markupTagLine);
checkMenuItem(menuId, disabled);
}
}
}
function* testPasteOuterHTMLMenu() {
info("Testing that 'Paste Outer HTML' menu item works.");
clipboard.set("this was pasted (outerHTML)");
let outerHTMLSelector = "#paste-area h1";
let nodeFront = yield getNodeFront(outerHTMLSelector, inspector);
yield selectNode(nodeFront, inspector);
contextMenuClick(getContainerForNodeFront(nodeFront, inspector).tagLine);
let onNodeReselected = inspector.markup.once("reselectedonremoved");
let menu = inspector.panelDoc.getElementById("node-menu-pasteouterhtml");
dispatchCommandEvent(menu);
info("Waiting for inspector selection to update");
yield onNodeReselected;
ok(content.document.body.outerHTML.contains(clipboard.get()),
"Clipboard content was pasted into the node's outer HTML.");
ok(!getNode(outerHTMLSelector, { expectNoMatch: true }),
"The original node was removed.");
}
function* testPasteInnerHTMLMenu() {
info("Testing that 'Paste Inner HTML' menu item works.");
clipboard.set("this was pasted (innerHTML)");
let innerHTMLSelector = "#paste-area .inner";
let getInnerHTML = () => content.document.querySelector(innerHTMLSelector).innerHTML;
let origInnerHTML = getInnerHTML();
let nodeFront = yield getNodeFront(innerHTMLSelector, inspector);
yield selectNode(nodeFront, inspector);
contextMenuClick(getContainerForNodeFront(nodeFront, inspector).tagLine);
let onMutation = inspector.once("markupmutation");
let menu = inspector.panelDoc.getElementById("node-menu-pasteinnerhtml");
dispatchCommandEvent(menu);
info("Waiting for mutation to occur");
yield onMutation;
ok(getInnerHTML() === clipboard.get(),
"Clipboard content was pasted into the node's inner HTML.");
ok(getNode(innerHTMLSelector), "The original node has been preserved.");
yield undoChange(inspector);
ok(getInnerHTML() === origInnerHTML, "Previous innerHTML has been " +
"restored after undo");
}
function* testPasteAdjacentHTMLMenu() {
let refSelector = "#paste-area .adjacent .ref";
let adjacentNode = content.document.querySelector(refSelector).parentNode;
let nodeFront = yield getNodeFront(refSelector, inspector);
yield selectNode(nodeFront, inspector);
let markupTagLine = getContainerForNodeFront(nodeFront, inspector).tagLine;
for (let { desc, clipboardData, menuId } of PASTE_ADJACENT_HTML_DATA) {
let menu = inspector.panelDoc.getElementById(menuId);
info(`Testing ${getLabelFor(menu)} for ${clipboardData}`);
clipboard.set(clipboardData);
contextMenuClick(markupTagLine);
let onMutation = inspector.once("markupmutation");
dispatchCommandEvent(menu);
info("Waiting for mutation to occur");
yield onMutation;
}
ok(adjacentNode.innerHTML.trim() === "1<span class=\"ref\">234</span>" +
"<span>5</span>", "The Paste as Last Child / as First Child / Before " +
"/ After worked as expected");
yield undoChange(inspector);
ok(adjacentNode.innerHTML.trim() === "1<span class=\"ref\">234</span>",
"Undo works for paste adjacent HTML");
}
function checkMenuItem(elementId, disabled) {
if (disabled) {
checkDisabled(elementId);
} else {
checkEnabled(elementId);
}
}
function checkEnabled(elementId) {
let elt = inspector.panelDoc.getElementById(elementId);
ok(!elt.hasAttribute("disabled"),
'"' + elt.label + '" context menu option is not disabled');
}
function checkDisabled(elementId) {
let elt = inspector.panelDoc.getElementById(elementId);
ok(elt.hasAttribute("disabled"),
'"' + elt.label + '" context menu option is disabled');
}
function dispatchCommandEvent(node) {
info("Dispatching command event on " + node);
let commandEvent = document.createEvent("XULCommandEvent");
commandEvent.initCommandEvent("command", true, true, window, 0, false, false,
false, false, null);
node.dispatchEvent(commandEvent);
}
function contextMenuClick(element) {
info("Simulating contextmenu event on " + element);
let evt = element.ownerDocument.createEvent('MouseEvents');
let button = 2; // right click
evt.initMouseEvent('contextmenu', true, true,
element.ownerDocument.defaultView, 1, 0, 0, 0, 0, false,
false, false, false, button, null);
element.dispatchEvent(evt);
}
function getLabelFor(elt) {
if (typeof elt === "string")
elt = inspector.panelDoc.querySelector(elt);
let isInPasteSubMenu = elt.matches("#node-menu-paste-extra-submenu *");
return `"${isInPasteSubMenu ? "Paste > " : ""}${elt.label}"`;
}
});

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Inspector Tree Menu Test</title>
<meta charset="utf-8">
</head>
<body>
<div>
<div id="paste-area">
<h1>Inspector Tree Menu Test</h1>
<p class="inner">Unset</p>
<p class="adjacent">
<span class="ref">3</span>
</p>
</div>
<p data-id="copy">Paragraph for testing copy</p>
<p id="sensitivity">Paragraph for sensitivity</p>
<p id="delete">This has to be deleted</p>
</div>
</body>
</html>

View File

@ -664,3 +664,43 @@ function executeInContent(name, data={}, objects={}, expectResponse=true) {
return promise.resolve();
}
}
/**
* Undo the last markup-view action and wait for the corresponding mutation to
* occur
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return a promise that resolves when the markup-mutation has been treated or
* rejects if no undo action is possible
*/
function undoChange(inspector) {
let canUndo = inspector.markup.undo.canUndo();
ok(canUndo, "The last change in the markup-view can be undone");
if (!canUndo) {
return promise.reject();
}
let mutated = inspector.once("markupmutation");
inspector.markup.undo.undo();
return mutated;
}
/**
* Redo the last markup-view action and wait for the corresponding mutation to
* occur
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return a promise that resolves when the markup-mutation has been treated or
* rejects if no redo action is possible
*/
function redoChange(inspector) {
let canRedo = inspector.markup.undo.canRedo();
ok(canRedo, "The last change in the markup-view can be redone");
if (!canRedo) {
return promise.reject();
}
let mutated = inspector.once("markupmutation");
inspector.markup.undo.redo();
return mutated;
}

View File

@ -33,7 +33,7 @@ loader.lazyGetter(this, "DOMParser", function() {
return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
});
loader.lazyGetter(this, "AutocompletePopup", () => {
return require("devtools/shared/autocomplete-popup").AutocompletePopup
return require("devtools/shared/autocomplete-popup").AutocompletePopup;
});
/**
@ -521,16 +521,17 @@ MarkupView.prototype = {
// Retain the node so we can undo this...
this.walker.retainNode(aNode).then(() => {
let parent = aNode.parentNode();
let sibling = null;
let nextSibling = null;
this.undo.do(() => {
if (container.selected) {
this.navigate(this.getContainer(parent));
}
this.walker.removeNode(aNode).then(nextSibling => {
sibling = nextSibling;
this.walker.removeNode(aNode).then(siblings => {
let focusNode = siblings.previousSibling || parent;
nextSibling = siblings.nextSibling;
if (container.selected) {
this.navigate(this.getContainer(focusNode));
}
});
}, () => {
this.walker.insertBefore(aNode, parent, sibling);
this.walker.insertBefore(aNode, parent, nextSibling);
});
}).then(null, console.error);
},
@ -701,16 +702,19 @@ MarkupView.prototype = {
removedContainers.add(container);
}
// If there has been additions, flash the nodes
// If there has been additions, flash the nodes if their associated
// container exist (so if their parent is expanded in the inspector).
added.forEach(added => {
let addedContainer = this.getContainer(added);
addedOrEditedContainers.add(addedContainer);
if (addedContainer) {
addedOrEditedContainers.add(addedContainer);
// The node may be added as a result of an append, in which case it
// it will have been removed from another container first, but in
// these cases we don't want to flash both the removal and the
// addition
removedContainers.delete(container);
// The node may be added as a result of an append, in which case
// it will have been removed from another container first, but in
// these cases we don't want to flash both the removal and the
// addition
removedContainers.delete(container);
}
});
}
}
@ -799,20 +803,46 @@ MarkupView.prototype = {
container.expanded = false;
},
/**
* Returns either the innerHTML or the outerHTML for a remote node.
* @param aNode The NodeFront to get the outerHTML / innerHTML for.
* @param isOuter A boolean that, if true, makes the function return the
* outerHTML, otherwise the innerHTML.
* @returns A promise that will be resolved with the outerHTML / innerHTML.
*/
_getNodeHTML: function(aNode, isOuter) {
let walkerPromise = null;
if (isOuter) {
walkerPromise = this.walker.outerHTML(aNode);
} else {
walkerPromise = this.walker.innerHTML(aNode);
}
return walkerPromise.then(longstr => {
return longstr.string().then(html => {
longstr.release().then(null, console.error);
return html;
});
});
},
/**
* Retrieve the outerHTML for a remote node.
* @param aNode The NodeFront to get the outerHTML for.
* @returns A promise that will be resolved with the outerHTML.
*/
getNodeOuterHTML: function(aNode) {
let def = promise.defer();
this.walker.outerHTML(aNode).then(longstr => {
longstr.string().then(outerHTML => {
longstr.release().then(null, console.error);
def.resolve(outerHTML);
});
});
return def.promise;
return this._getNodeHTML(aNode, true);
},
/**
* Retrieve the innerHTML for a remote node.
* @param aNode The NodeFront to get the innerHTML for.
* @returns A promise that will be resolved with the innerHTML.
*/
getNodeInnerHTML: function(aNode) {
return this._getNodeHTML(aNode);
},
/**
@ -885,31 +915,89 @@ MarkupView.prototype = {
/**
* Replace the outerHTML of any node displayed in the inspector with
* some other HTML code
* @param aNode node which outerHTML will be replaced.
* @param newValue The new outerHTML to set on the node.
* @param oldValue The old outerHTML that will be used if the user undos the update.
* @param {NodeFront} node node which outerHTML will be replaced.
* @param {string} newValue The new outerHTML to set on the node.
* @param {string} oldValue The old outerHTML that will be used if the
* user undoes the update.
* @returns A promise that will resolve when the outer HTML has been updated.
*/
updateNodeOuterHTML: function(aNode, newValue, oldValue) {
let container = this._containers.get(aNode);
updateNodeOuterHTML: function(node, newValue, oldValue) {
let container = this.getContainer(node);
if (!container) {
return promise.reject();
}
// Changing the outerHTML removes the node which outerHTML was changed.
// Listen to this removal to reselect the right node afterwards.
this.reselectOnRemoved(aNode, "outerhtml");
return this.walker.setOuterHTML(aNode, newValue).then(null, () => {
this.reselectOnRemoved(node, "outerhtml");
return this.walker.setOuterHTML(node, newValue).then(null, () => {
this.cancelReselectOnRemoved();
});
},
/**
* Replace the innerHTML of any node displayed in the inspector with
* some other HTML code
* @param {Node} node node which innerHTML will be replaced.
* @param {string} newValue The new innerHTML to set on the node.
* @param {string} oldValue The old innerHTML that will be used if the user
* undoes the update.
* @returns A promise that will resolve when the inner HTML has been updated.
*/
updateNodeInnerHTML: function(node, newValue, oldValue) {
let container = this.getContainer(node);
if (!container) {
return promise.reject();
}
let def = promise.defer();
container.undo.do(() => {
this.walker.setInnerHTML(node, newValue).then(def.resolve, def.reject);
}, () => {
this.walker.setInnerHTML(node, oldValue);
});
return def.promise;
},
/**
* Insert adjacent HTML to any node displayed in the inspector.
*
* @param {NodeFront} node The reference node.
* @param {string} position The position as specified for Element.insertAdjacentHTML
* (i.e. "beforeBegin", "afterBegin", "beforeEnd", "afterEnd").
* @param {string} newValue The adjacent HTML.
* @returns A promise that will resolve when the adjacent HTML has
* been inserted.
*/
insertAdjacentHTMLToNode: function(node, position, value) {
let container = this.getContainer(node);
if (!container) {
return promise.reject();
}
let def = promise.defer();
let injectedNodes = [];
container.undo.do(() => {
this.walker.insertAdjacentHTML(node, position, value).then(nodeArray => {
injectedNodes = nodeArray.nodes;
return nodeArray;
}).then(def.resolve, def.reject);
}, () => {
this.walker.removeNodes(injectedNodes);
});
return def.promise;
},
/**
* Open an editor in the UI to allow editing of a node's outerHTML.
* @param aNode The NodeFront to edit.
*/
beginEditingOuterHTML: function(aNode) {
this.getNodeOuterHTML(aNode).then((oldValue)=> {
this.getNodeOuterHTML(aNode).then(oldValue => {
let container = this.getContainer(aNode);
if (!container) {
return;
@ -1216,7 +1304,7 @@ MarkupView.prototype = {
this._inspector.selection.off("new-node-front", this._boundOnNewSelection);
this._boundOnNewSelection = null;
this.walker.off("mutations", this._boundMutationObserver)
this.walker.off("mutations", this._boundMutationObserver);
this._boundMutationObserver = null;
this.walker.off("display-change", this._boundOnDisplayChange);
@ -1923,7 +2011,7 @@ function TextEditor(aContainer, aNode, aTemplate) {
}, () => {
this.node.setNodeValue(oldValue).then(() => {
this.markup.nodeChanged(this.node);
})
});
});
});
});
@ -2154,7 +2242,7 @@ ElementEditor.prototype = {
doMods.apply();
}, () => {
undoMods.apply();
})
});
} catch(ex) {
console.error(ex);
}

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