This commit is contained in:
Ryan VanderMeulen 2014-11-26 21:43:23 -05:00
Родитель 102bd52983 b3ebe654a9
Коммит 9e581b1d56
382 изменённых файлов: 6592 добавлений и 3365 удалений

Просмотреть файл

@ -89,10 +89,16 @@ let SystemAppProxy = {
},
// Now deprecated, use sendCustomEvent with a custom event name
dispatchEvent: function systemApp_sendChromeEvent(details, target) {
dispatchEvent: function systemApp_dispatchEvent(details, target) {
return this._sendCustomEvent('mozChromeEvent', details, false, target);
},
dispatchKeyboardEvent: function systemApp_dispatchKeyboardEvent(type, details) {
let content = this._frame ? this._frame.contentWindow : null;
let e = new content.KeyboardEvent(type, details);
content.dispatchEvent(e);
},
// Listen for dom events on the system app
addEventListener: function systemApp_addEventListener() {
let content = this._frame ? this._frame.contentWindow : null;

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

Просмотреть файл

@ -19,11 +19,11 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a47dd04f8f66e42fd331711140f2c3e2fed0767d"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8b13bfc1d7d25cee4de55f332654fdba25b8460b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>
<!-- Stock Android things -->

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

Просмотреть файл

@ -19,11 +19,11 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a47dd04f8f66e42fd331711140f2c3e2fed0767d"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8b13bfc1d7d25cee4de55f332654fdba25b8460b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>
<!-- Stock Android things -->

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>

Просмотреть файл

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "2a664cbb4d735d9c55fc5b6cf3e39a24bcfbe551",
"revision": "05f40074f94c58315e6c353089d31e8e20ea3c1a",
"repo_path": "integration/gaia-central"
}

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>

Просмотреть файл

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0f7bb156969c5c838ff90ebc88d7691fc4d94310"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="76e1789f081a811416c95e25213ca63976486af6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

Просмотреть файл

@ -323,7 +323,7 @@ pref("browser.urlbar.autoFill", true);
pref("browser.urlbar.autoFill.typed", true);
// Use the new unifiedComplete component
pref("browser.urlbar.unifiedcomplete", true);
pref("browser.urlbar.unifiedcomplete", false);
// 0: Match anywhere (e.g., middle of words)
// 1: Match on word boundaries and then try matching anywhere
@ -1647,8 +1647,8 @@ pref("loop.seenToS", "unseen");
pref("loop.gettingStarted.seen", false);
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/");
pref("loop.legal.ToS_url", "https://www.mozilla.org/about/legal/terms/firefox-hello/");
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/firefox-hello/");
pref("loop.do_not_disturb", false);
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/ringtone.ogg");
pref("loop.retry_delay.start", 60000);

Просмотреть файл

@ -1099,6 +1099,7 @@
}
if (!this._previewMode) {
this.mCurrentTab.lastAccessed = Infinity;
this.mCurrentTab.removeAttribute("unread");
oldTab.lastAccessed = Date.now();
@ -1638,6 +1639,7 @@
t.linkedBrowser = b;
this._tabForBrowser.set(b, t);
t._tPos = position;
t.lastAccessed = Date.now();
this.tabContainer._setPositionalAttributes();
// Prevent the superfluous initial load of a blank document
@ -3133,6 +3135,7 @@
this.mCurrentTab.linkedPanel = uniqueId;
this.mCurrentTab._tPos = 0;
this.mCurrentTab._fullyOpen = true;
this.mCurrentTab.lastAccessed = Infinity;
this.mCurrentTab.linkedBrowser = this.mCurrentBrowser;
this._tabForBrowser.set(this.mCurrentBrowser, this.mCurrentTab);
@ -4944,13 +4947,12 @@
<property name="lastAccessed">
<getter>
return this.selected ? Date.now() : this._lastAccessed;
return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed;
</getter>
<setter>
this._lastAccessed = val;
</setter>
</property>
<field name="_lastAccessed">0</field>
<field name="mOverCloseButton">false</field>
<field name="mCorrespondingMenuitem">null</field>

Просмотреть файл

@ -413,7 +413,7 @@ skip-if = buildapp == 'mulet' || e10s
[browser_tabMatchesInAwesomebar.js]
skip-if = e10s # Bug 1093206 - need to re-enable tests relying on swapFrameLoaders et al for e10s (test calls gBrowser.swapBrowsersAndCloseOther)
[browser_tabMatchesInAwesomebar_perwindowpb.js]
skip-if = e10s # Bug 1093373 - relies on browser.sessionHistory
skip-if = e10s || true # Bug 1093373, Bug 1104755
[browser_tab_drag_drop_perwindow.js]
skip-if = buildapp == 'mulet'
[browser_tab_dragdrop.js]

Просмотреть файл

@ -16,8 +16,10 @@ function* promise_first_result(inputText) {
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla");
let tabs = [tab];

Просмотреть файл

@ -18,8 +18,10 @@ function* promise_first_result(inputText) {
add_task(function* () {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
"http://example.com/?q={searchTerms}");

Просмотреть файл

@ -15,8 +15,10 @@ function* check_a11y_label(inputText, expectedLabel) {
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
let tab = gBrowser.addTab("about:about");
yield promiseTabLoaded(tab);

Просмотреть файл

@ -16,6 +16,12 @@ function is_selected(index) {
}
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
registerCleanupFunction(promiseClearHistory);
let visits = [];

Просмотреть файл

@ -14,8 +14,10 @@ function* check_title(inputText, expectedTitle) {
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
let uri = NetUtil.newURI("http://bug1060642.example.com/beards/are/pretty/great");
yield PlacesTestUtils.addVisits([{uri: uri, title: ""}]);

Просмотреть файл

@ -4,8 +4,10 @@
add_task(function* test_switchtab_override() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";

Просмотреть файл

@ -14,8 +14,10 @@ function is_selected(index) {
add_task(function*() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
todo(false, "Stop supporting old autocomplete components.");
return;
}
registerCleanupFunction(() => {
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);

Просмотреть файл

@ -1,24 +1,35 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let originalTab;
let newTab;
function test() {
let originalTab = gBrowser.selectedTab;
isnot(originalTab.lastAccessed, 0, "selectedTab has been selected");
ok(originalTab.lastAccessed <= Date.now(), "selectedTab has a valid timestamp");
waitForExplicitFinish();
let newTab = gBrowser.addTab("about:blank", {skipAnimation: true});
is(newTab.lastAccessed, 0, "newTab hasn't been selected so far");
originalTab = gBrowser.selectedTab;
setTimeout(step2, 100);
}
function step2() {
is(originalTab.lastAccessed, Date.now(), "selected tab has the current timestamp");
newTab = gBrowser.addTab("about:blank", {skipAnimation: true});
setTimeout(step3, 100);
}
function step3() {
ok(newTab.lastAccessed < Date.now(), "new tab hasn't been selected so far");
gBrowser.selectedTab = newTab;
is(newTab.lastAccessed, Date.now(), "new tab has the current timestamp after being selected");
setTimeout(step4, 100);
}
isnot(newTab.lastAccessed, 0, "newTab has been selected");
ok(newTab.lastAccessed <= Date.now(), "newTab has a valid timestamp");
isnot(originalTab.lastAccessed, 0, "originalTab has been selected");
ok(originalTab.lastAccessed <= Date.now(), "originalTab has a valid timestamp");
ok(originalTab.lastAccessed <= newTab.lastAccessed,
"originalTab's timestamp must be lower than newTab's");
function step4() {
ok(originalTab.lastAccessed < Date.now(),
"original tab has old timestamp after being deselected");
is(newTab.lastAccessed, Date.now(),
"new tab has the current timestamp since it's still selected");
gBrowser.removeTab(newTab);
finish();
}

Просмотреть файл

@ -54,7 +54,10 @@ 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, 2, "Found the expected number of matches");
if (Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
else
is(gURLBar.controller.matchCount, 1, "Found the expected number of matches");
EventUtils.synthesizeKey("VK_DOWN", {});
is(gURLBar.textValue, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
gURLBar.closePopup();

Просмотреть файл

@ -4,9 +4,8 @@
* 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/. */
// We don't have pages ready for this, so leave these prefs empty for now (bug 648330)
pref("startup.homepage_override_url","");
pref("startup.homepage_welcome_url","");
pref("startup.homepage_welcome_url","https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/firstrun/");
// The time interval between checks for a new version (in seconds)
pref("app.update.interval", 28800); // 8 hours
// The time interval between the downloading of mar file chunks in the

Просмотреть файл

@ -176,18 +176,31 @@ let LoopRoomsInternal = {
for (let room of roomsList) {
// See if we already have this room in our cache.
let orig = this.rooms.get(room.roomToken);
if (orig) {
checkForParticipantsUpdate(orig, room);
}
// Remove the `currSize` for posterity.
if ("currSize" in room) {
delete room.currSize;
}
this.rooms.set(room.roomToken, room);
let eventName = orig ? "update" : "add";
eventEmitter.emit(eventName, room);
eventEmitter.emit(eventName + ":" + room.roomToken, room);
if (room.deleted) {
// If this client deleted the room, then we'll already have
// deleted the room in the function below.
if (orig) {
this.rooms.delete(room.roomToken);
}
eventEmitter.emit("delete", room);
eventEmitter.emit("delete:" + room.roomToken, room);
} else {
if (orig) {
checkForParticipantsUpdate(orig, room);
}
// Remove the `currSize` for posterity.
if ("currSize" in room) {
delete room.currSize;
}
this.rooms.set(room.roomToken, room);
let eventName = orig ? "update" : "add";
eventEmitter.emit(eventName, room);
eventEmitter.emit(eventName + ":" + room.roomToken, room);
}
}
// If there's no rooms in the list, remove the guest created room flag, so that
@ -230,13 +243,22 @@ let LoopRoomsInternal = {
let data = JSON.parse(response.body);
room.roomToken = roomToken;
checkForParticipantsUpdate(room, data);
extend(room, data);
this.rooms.set(roomToken, room);
let eventName = !needsUpdate ? "update" : "add";
eventEmitter.emit(eventName, room);
eventEmitter.emit(eventName + ":" + roomToken, room);
if (data.deleted) {
this.rooms.delete(room.roomToken);
extend(room, data);
eventEmitter.emit("delete", room);
eventEmitter.emit("delete:" + room.roomToken, room);
} else {
checkForParticipantsUpdate(room, data);
extend(room, data);
this.rooms.set(roomToken, room);
let eventName = !needsUpdate ? "update" : "add";
eventEmitter.emit(eventName, room);
eventEmitter.emit(eventName + ":" + roomToken, room);
}
callback(null, room);
}, err => callback(err)).catch(err => callback(err));
},
@ -323,8 +345,8 @@ let LoopRoomsInternal = {
MozLoopService.hawkRequest(this.sessionType, url, "DELETE")
.then(response => {
this.rooms.delete(roomToken);
eventEmitter.emit("delete", room);
callback(null, room);
// We'll emit an update when the push notification is received.
}, error => callback(error)).catch(error => callback(error));
},

Просмотреть файл

@ -124,6 +124,10 @@ const injectObjectAPI = function(api, targetWindow) {
// closing a window, we want to circumvent a JS error.
if (callbackIsFunction && typeof lastParam != "function") {
MozLoopService.log.debug(func + ": callback function was lost.");
// Assume the presence of a first result argument to be an error.
if (results[0]) {
MozLoopService.log.error(func + " error:", results[0]);
}
return;
}
lastParam(...[cloneValueInto(r, targetWindow) for (r of results)]);
@ -517,7 +521,7 @@ function injectLoopAPI(targetWindow) {
// When the function was garbage collected due to async events, like
// closing a window, we want to circumvent a JS error.
if (callbackIsFunction && typeof callback != "function") {
MozLoopService.log.debug("hawkRequest: callback function was lost.");
MozLoopService.log.error("hawkRequest: callback function was lost.", hawkError);
return;
}
// The hawkError.error property, while usually a string representing

Просмотреть файл

@ -635,7 +635,7 @@ loop.contacts = (function(_, mozL10n) {
React.DOM.input({ref: "email", type: "email", required: phoneOrEmailRequired,
className: cx({pristine: this.state.pristine}),
valueLink: this.linkState("email")}),
React.DOM.label(null, mozL10n.get("new_contact_phone_placeholder")),
React.DOM.label(null, mozL10n.get("new_contact_fxos_phone_placeholder")),
React.DOM.input({ref: "tel", type: "tel", required: phoneOrEmailRequired,
className: cx({pristine: this.state.pristine}),
valueLink: this.linkState("tel")}),

Просмотреть файл

@ -635,7 +635,7 @@ loop.contacts = (function(_, mozL10n) {
<input ref="email" type="email" required={phoneOrEmailRequired}
className={cx({pristine: this.state.pristine})}
valueLink={this.linkState("email")} />
<label>{mozL10n.get("new_contact_phone_placeholder")}</label>
<label>{mozL10n.get("new_contact_fxos_phone_placeholder")}</label>
<input ref="tel" type="tel" required={phoneOrEmailRequired}
className={cx({pristine: this.state.pristine})}
valueLink={this.linkState("tel")} />

Просмотреть файл

@ -214,7 +214,7 @@ loop.panel = (function(_, mozL10n) {
)
),
});
return React.DOM.div(null,
return React.DOM.div({id: "powered-by-wrapper"},
React.DOM.p({id: "powered-by"},
mozL10n.get("powered_by_beforeLogo"),
React.DOM.img({id: "powered-by-logo", className: locale}),

Просмотреть файл

@ -214,7 +214,7 @@ loop.panel = (function(_, mozL10n) {
</a>
),
});
return <div>
return <div id="powered-by-wrapper">
<p id="powered-by">
{mozL10n.get("powered_by_beforeLogo")}
<img id="powered-by-logo" className={locale} />

Просмотреть файл

@ -28,7 +28,7 @@
.contact,
.contact-separator {
padding: 5px 10px;
padding: .5rem 1rem;
font-size: 13px;
}
@ -41,7 +41,6 @@
}
.contact-separator {
height: 24px;
background-color: #eee;
color: #888;
}
@ -123,7 +122,7 @@
.contact > .details > .username > i.icon-google {
position: absolute;
right: 10px;
right: 1rem;
top: 35%;
width: 14px;
height: 14px;
@ -228,5 +227,5 @@
}
.contact-form > .button-group {
margin-top: 14px;
margin-top: 1rem;
}

Просмотреть файл

@ -847,3 +847,8 @@ html, .fx-embedded, #main,
.standalone .room-conversation .conversation-toolbar .btn-hangup-entry {
display: block;
}
.standalone .room-conversation-wrapper .ended-conversation {
position: relative;
height: auto;
}

Просмотреть файл

@ -34,7 +34,7 @@ body {
.tab-view {
display: flex;
flex-direction: row;
padding: 10px;
padding: 10px 0;
border-bottom: 1px solid #ccc;
color: #000;
border-top-right-radius: 2px;
@ -97,7 +97,7 @@ body {
/* Content area and input fields */
.content-area {
padding: 14px;
padding: .5rem 1rem;
}
.content-area header {
@ -105,14 +105,13 @@ body {
}
#fte-getstarted {
padding-top: 1em;
padding-bottom: 1em;
margin-bottom: 1em;
padding-top: .5rem;
padding-bottom: .5rem;
}
#fte-title {
text-align: center;
margin-bottom: .5em;
margin-bottom: .5rem;
}
#fte-button {
@ -125,6 +124,11 @@ body {
height: auto; /* Needed to override .button's height:26px; */
}
#fte-getstarted + #powered-by-wrapper {
position: absolute;
bottom: 0;
}
/* Need to remove when these rules when the Beta tag is removed */
#share-link-header {
-moz-padding-start: 20px;
@ -172,12 +176,10 @@ body {
font-weight: bold;
color: #999;
padding: .5rem 1rem;
border-bottom: 1px solid #ddd;
}
.rooms > p {
border-top: 1px solid #ddd;
padding: 1rem 0;
padding: .5rem 0;
margin: 0;
}
@ -192,10 +194,16 @@ body {
.room-list {
max-height: 335px; /* XXX better computation needed */
overflow: auto;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.room-list:empty {
border-bottom-width: 0;
}
.room-list > .room-entry {
padding: 1rem 1rem 0 .5rem;
padding: .5rem 1rem;
}
.room-list > .room-entry > h2 {
@ -209,8 +217,8 @@ body {
}
.room-list > .room-entry > h2 > .room-notification {
display: inline-block;
background: transparent;
display: none;
background: #00a0ec;
width: 8px;
height: 8px;
border-radius: 50%;
@ -218,7 +226,7 @@ body {
}
.room-list > .room-entry.room-active > h2 > .room-notification {
background-color: #00a0ec;
display: inline-block;
}
.room-list > .room-entry:hover {
@ -226,12 +234,12 @@ body {
}
.room-list > .room-entry:not(:last-child) {
border-bottom: 1px solid #ddd;
border-bottom: 1px solid #ccc;
}
.room-list > .room-entry > p {
margin: 0;
padding: .2em 0 1rem .8rem;
padding: .2rem 0;
}
.room-list > .room-entry > p > a {
@ -475,15 +483,14 @@ body[dir=rtl] .generate-url-spinner {
#powered-by,
.terms-service {
color: #888;
text-align: center;
font-size: .9em;
}
#powered-by {
border-top: 1px solid #ccc;
padding-top: 1em;
margin-left: -14px;
margin-right: -14px;
padding-top: .5rem;
text-align: center;
margin-top: 0;
}
#powered-by-logo {
@ -538,6 +545,12 @@ body[dir=rtl] .generate-url-spinner {
}
}
.terms-service {
padding-left: 1rem;
padding-right: 1rem;
padding-bottom: .5rem;
}
.terms-service > a {
color: #00caee;
}
@ -557,7 +570,7 @@ body[dir=rtl] .generate-url-spinner {
}
.dnd-status:hover {
border: 1px solid #DDD;
border-color: #ddd;
background-color: #f1f1f1;
}
@ -676,13 +689,12 @@ body[dir=rtl] .generate-url-spinner {
border-top: 1px solid #D1D1D1;
background-color: #eaeaea;
color: #7f7f7f;
padding: 14px;
padding: .5rem 1rem;
}
.footer .signin-details {
align-items: center;
display: flex;
-moz-margin-start: 5px;
}
.footer .user-identity {

Просмотреть файл

@ -162,6 +162,12 @@ loop.shared.actions = (function() {
getRemoteElementFunc: Function
}),
/**
* Used for notifying that local media has been obtained.
*/
GotMediaPermission: Action.define("gotMediaPermission", {
}),
/**
* Used for notifying that the media is now up for the call.
*/
@ -324,6 +330,13 @@ loop.shared.actions = (function() {
expires: Number
}),
/**
* Used to indicate that the feedback cycle is completed and the countdown
* finished.
*/
FeedbackComplete: Action.define("feedbackComplete", {
}),
/**
* Used to indicate the user wishes to leave the room.
*/

Просмотреть файл

@ -28,6 +28,8 @@ loop.store.ActiveRoomStore = (function() {
GATHER: "room-gather",
// The store has got the room data
READY: "room-ready",
// Obtaining media from the user
MEDIA_WAIT: "room-media-wait",
// The room is known to be joined on the loop-server
JOINED: "room-joined",
// The room is connected to the sdk server.
@ -112,10 +114,11 @@ loop.store.ActiveRoomStore = (function() {
this.setStoreState({
error: actionData.error,
failureReason: getReason(actionData.error.errno),
roomState: actionData.error.errno === SERVER_CODES.ROOM_FULL ?
ROOM_STATES.FULL : ROOM_STATES.FAILED
failureReason: getReason(actionData.error.errno)
});
this._leaveRoom(actionData.error.errno === SERVER_CODES.ROOM_FULL ?
ROOM_STATES.FULL : ROOM_STATES.FAILED);
},
/**
@ -127,6 +130,7 @@ loop.store.ActiveRoomStore = (function() {
"roomFailure",
"setupRoomInfo",
"updateRoomInfo",
"gotMediaPermission",
"joinRoom",
"joinedRoom",
"connectedToSdkServers",
@ -135,7 +139,8 @@ loop.store.ActiveRoomStore = (function() {
"remotePeerDisconnected",
"remotePeerConnected",
"windowUnload",
"leaveRoom"
"leaveRoom",
"feedbackComplete"
]);
},
@ -260,6 +265,14 @@ loop.store.ActiveRoomStore = (function() {
this.setStoreState({failureReason: undefined});
}
this.setStoreState({roomState: ROOM_STATES.MEDIA_WAIT});
},
/**
* Handles the action that signifies when media permission has been
* granted and starts joining the room.
*/
gotMediaPermission: function() {
this._mozLoop.rooms.join(this._storeState.roomToken,
function(error, responseData) {
if (error) {
@ -293,6 +306,21 @@ loop.store.ActiveRoomStore = (function() {
this._setRefreshTimeout(actionData.expires);
this._sdkDriver.connectSession(actionData);
// If we haven't got a room name yet, go and get one. We typically
// need to do this in the case of the standalone window.
// XXX When bug 1103331 lands this can be moved to earlier.
if (!this._storeState.roomName) {
this._mozLoop.rooms.get(this._storeState.roomToken,
function(err, result) {
if (err) {
console.error("Failed to get room data:", err);
return;
}
this.dispatcher.dispatch(new sharedActions.UpdateRoomInfo(result));
}.bind(this));
}
},
/**
@ -335,23 +363,19 @@ loop.store.ActiveRoomStore = (function() {
* Handles recording when a remote peer has connected to the servers.
*/
remotePeerConnected: function() {
this.setStoreState({
roomState: ROOM_STATES.HAS_PARTICIPANTS
});
this.setStoreState({roomState: ROOM_STATES.HAS_PARTICIPANTS});
// We've connected with a third-party, therefore stop displaying the ToS etc.
this._mozLoop.setLoopPref("seenToS", "seen");
},
/**
* Handles a remote peer disconnecting from the session.
* Handles a remote peer disconnecting from the session. As we currently only
* support 2 participants, we declare the room as SESSION_CONNECTED as soon as
* one participantleaves.
*/
remotePeerDisconnected: function() {
// As we only support two users at the moment, we just set this
// back to joined.
this.setStoreState({
roomState: ROOM_STATES.SESSION_CONNECTED
});
this.setStoreState({roomState: ROOM_STATES.SESSION_CONNECTED});
},
/**
@ -425,9 +449,16 @@ loop.store.ActiveRoomStore = (function() {
this._storeState.sessionToken);
}
this.setStoreState({
roomState: nextState ? nextState : ROOM_STATES.ENDED
});
this.setStoreState({roomState: nextState || ROOM_STATES.ENDED});
},
/**
* When feedback is complete, we reset the room to the initial state.
*/
feedbackComplete: function() {
// Note, that we want some values, such as the windowId, so we don't
// do a full reset here.
this.setStoreState(this.getInitialStoreState());
}
});

Просмотреть файл

@ -37,7 +37,8 @@ loop.store.FeedbackStore = (function() {
actions: [
"requireFeedbackDetails",
"sendFeedback",
"sendFeedbackError"
"sendFeedbackError",
"feedbackComplete"
],
initialize: function(options) {
@ -91,6 +92,14 @@ loop.store.FeedbackStore = (function() {
feedbackState: FEEDBACK_STATES.FAILED,
error: actionData.error
});
},
/**
* Resets the store to its initial state as feedback has been completed,
* i.e. ready for the next round of feedback.
*/
feedbackComplete: function() {
this.resetStoreState();
}
});

Просмотреть файл

@ -15,7 +15,8 @@ loop.shared.views.FeedbackView = (function(l10n) {
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS = 5;
var WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS =
loop.shared.views.WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS = 5;
var FEEDBACK_STATES = loop.store.FEEDBACK_STATES;
/**

Просмотреть файл

@ -15,7 +15,8 @@ loop.shared.views.FeedbackView = (function(l10n) {
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS = 5;
var WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS =
loop.shared.views.WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS = 5;
var FEEDBACK_STATES = loop.store.FEEDBACK_STATES;
/**

Просмотреть файл

@ -207,6 +207,9 @@ loop.OTSdkDriver = (function() {
_onPublishComplete: function(event) {
event.preventDefault();
this._publisherReady = true;
this.dispatcher.dispatch(new sharedActions.GotMediaPermission());
this._maybePublishLocalStream();
},

Просмотреть файл

@ -54,6 +54,17 @@ loop.store.createStore = (function() {
this.trigger("change:" + key);
}
this.trigger("change");
},
/**
* Resets the store state to the initially defined state.
*/
resetStoreState: function() {
if (typeof this.getInitialStoreState === "function") {
this._storeState = this.getInitialStoreState();
} else {
this._storeState = {};
}
}
};

Просмотреть файл

@ -16,8 +16,8 @@ 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/"})
LOOP_PRIVACY_WEBSITE_URL := $(shell echo $${LOOP_PRIVACY_WEBSITE_URL-"https://www.mozilla.org/privacy"})
LOOP_LEGAL_WEBSITE_URL := $(shell echo $${LOOP_LEGAL_WEBSITE_URL-"/legal/terms"})
LOOP_PRIVACY_WEBSITE_URL := $(shell echo $${LOOP_PRIVACY_WEBSITE_URL-"https://www.mozilla.org/privacy/firefox-hello/"})
LOOP_LEGAL_WEBSITE_URL := $(shell echo $${LOOP_LEGAL_WEBSITE_URL-"https://www.mozilla.org/about/legal/terms/firefox-hello/"})
LOOP_PRODUCT_HOMEPAGE_URL := $(shell echo $${LOOP_PRODUCT_HOMEPAGE_URL-"https://www.firefox.com/hello/"})
NODE_LOCAL_BIN=./node_modules/.bin

Просмотреть файл

@ -68,6 +68,44 @@ loop.StandaloneMozLoop = (function(mozL10n) {
};
StandaloneMozLoopRooms.prototype = {
/**
* Request information about a specific room from the server.
*
* @param {String} roomToken Room identifier
* @param {Function} callback Function that will be invoked once the operation
* finished. The first argument passed will be an
* `Error` object or `null`. The second argument will
* be the list of rooms, if it was fetched successfully.
*/
get: function(roomToken, callback) {
var req = $.ajax({
url: this._baseServerUrl + "/rooms/" + roomToken,
method: "GET",
contentType: "application/json",
beforeSend: function(xhr) {
if (this.sessionToken) {
xhr.setRequestHeader("Authorization", "Basic " + btoa(this.sessionToken));
}
}.bind(this)
});
req.done(function(responseData) {
try {
// We currently only require things we need rather than everything possible.
callback(null, validate(responseData, {
roomName: String,
roomOwner: String,
roomUrl: String
}));
} catch (err) {
console.error("Error requesting call info", err.message);
callback(err);
}
}.bind(this));
req.fail(failureHandler.bind(this, callback));
},
/**
* Internal function to actually perform a post to a room.
*
@ -115,6 +153,16 @@ loop.StandaloneMozLoop = (function(mozL10n) {
* `Error` object or `null`.
*/
join: function(roomToken, callback) {
function callbackWrapper(err, result) {
// XXX Save the sessionToken for purposes of get.
// When bug 1103331 this can probably be removed.
if (result) {
this.sessionToken = result.sessionToken;
}
callback(err, result);
}
this._postToRoom(roomToken, null, {
action: "join",
displayName: mozL10n.get("rooms_display_name_guest"),
@ -124,7 +172,7 @@ loop.StandaloneMozLoop = (function(mozL10n) {
sessionId: String,
sessionToken: String,
expires: Number
}, callback);
}, callbackWrapper.bind(this));
},
/**

Просмотреть файл

@ -19,7 +19,18 @@ loop.standaloneRoomViews = (function(mozL10n) {
var StandaloneRoomInfoArea = React.createClass({displayName: 'StandaloneRoomInfoArea',
propTypes: {
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired,
activeRoomStore:
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
feedbackStore:
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired
},
onFeedbackSent: function() {
// We pass a tick to prevent React warnings regarding nested updates.
setTimeout(function() {
this.props.activeRoomStore.dispatchAction(new sharedActions.FeedbackComplete());
}.bind(this));
},
_renderCallToActionLink: function() {
@ -55,53 +66,75 @@ loop.standaloneRoomViews = (function(mozL10n) {
}
},
_renderContent: function() {
render: function() {
switch(this.props.roomState) {
case ROOM_STATES.INIT:
case ROOM_STATES.READY:
case ROOM_STATES.ENDED: {
case ROOM_STATES.READY: {
// XXX: In ENDED state, we should rather display the feedback form.
return (
React.DOM.button({className: "btn btn-join btn-info",
onClick: this.props.joinRoom},
mozL10n.get("rooms_room_join_label")
React.DOM.div({className: "room-inner-info-area"},
React.DOM.button({className: "btn btn-join btn-info",
onClick: this.props.joinRoom},
mozL10n.get("rooms_room_join_label")
)
)
);
}
case ROOM_STATES.MEDIA_WAIT: {
var msg = mozL10n.get("call_progress_getting_media_description",
{clientShortname: mozL10n.get("clientShortname2")});
// XXX Bug 1047040 will add images to help prompt the user.
return (
React.DOM.div({className: "room-inner-info-area"},
React.DOM.p({className: "prompt-media-message"},
msg
)
)
);
}
case ROOM_STATES.JOINED:
case ROOM_STATES.SESSION_CONNECTED: {
return (
React.DOM.p({className: "empty-room-message"},
mozL10n.get("rooms_only_occupant_label")
React.DOM.div({className: "room-inner-info-area"},
React.DOM.p({className: "empty-room-message"},
mozL10n.get("rooms_only_occupant_label")
)
)
);
}
case ROOM_STATES.FULL:
case ROOM_STATES.FULL: {
return (
React.DOM.div(null,
React.DOM.div({className: "room-inner-info-area"},
React.DOM.p({className: "full-room-message"},
mozL10n.get("rooms_room_full_label")
),
React.DOM.p(null, this._renderCallToActionLink())
)
);
case ROOM_STATES.FAILED:
}
case ROOM_STATES.ENDED: {
return (
React.DOM.p({className: "failed-room-message"},
this._getFailureString()
React.DOM.div({className: "ended-conversation"},
sharedViews.FeedbackView({
feedbackStore: this.props.feedbackStore,
onAfterFeedbackReceived: this.onFeedbackSent}
)
)
);
default:
}
case ROOM_STATES.FAILED: {
return (
React.DOM.div({className: "room-inner-info-area"},
React.DOM.p({className: "failed-room-message"},
this._getFailureString()
)
)
);
}
default: {
return null;
}
}
},
render: function() {
return (
React.DOM.div({className: "room-inner-info-area"},
this._renderContent()
)
);
}
});
@ -154,6 +187,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
propTypes: {
activeRoomStore:
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
feedbackStore:
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired,
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired
},
@ -211,7 +246,31 @@ loop.standaloneRoomViews = (function(mozL10n) {
};
},
/**
* Used to update the video container whenever the orientation or size of the
* display area changes.
*/
updateVideoContainer: function() {
var localStreamParent = this._getElement('.local .OT_publisher');
var remoteStreamParent = this._getElement('.remote .OT_subscriber');
if (localStreamParent) {
localStreamParent.style.width = "100%";
}
if (remoteStreamParent) {
remoteStreamParent.style.height = "100%";
}
},
componentDidMount: function() {
/**
* OT inserts inline styles into the markup. Using a listener for
* resize events helps us trigger a full width/height on the element
* so that they update to the correct dimensions.
* XXX: this should be factored as a mixin, bug 1104930
*/
window.addEventListener('orientationchange', this.updateVideoContainer);
window.addEventListener('resize', this.updateVideoContainer);
// Adding a class to the document body element from here to ease styling it.
document.body.classList.add("is-standalone-room");
},
@ -228,14 +287,22 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @param {Object} nextState Next state object.
*/
componentWillUpdate: function(nextProps, nextState) {
if (this.state.roomState !== ROOM_STATES.JOINED &&
nextState.roomState === ROOM_STATES.JOINED) {
if (this.state.roomState !== ROOM_STATES.MEDIA_WAIT &&
nextState.roomState === ROOM_STATES.MEDIA_WAIT) {
this.props.dispatcher.dispatch(new sharedActions.SetupStreamElements({
publisherConfig: this._getPublisherConfig(),
getLocalElementFunc: this._getElement.bind(this, ".local"),
getRemoteElementFunc: this._getElement.bind(this, ".remote")
}));
}
if (this.state.roomState !== ROOM_STATES.JOINED &&
nextState.roomState === ROOM_STATES.JOINED) {
// This forces the video size to update - creating the publisher
// first, and then connecting to the session doesn't seem to set the
// initial size correctly.
this.updateVideoContainer();
}
},
joinRoom: function() {
@ -284,7 +351,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
StandaloneRoomInfoArea({roomState: this.state.roomState,
failureReason: this.state.failureReason,
joinRoom: this.joinRoom,
helper: this.props.helper}),
helper: this.props.helper,
activeRoomStore: this.props.activeRoomStore,
feedbackStore: this.props.feedbackStore}),
React.DOM.div({className: "video-layout-wrapper"},
React.DOM.div({className: "conversation room-conversation"},
React.DOM.h2({className: "room-name"}, this.state.roomName),

Просмотреть файл

@ -19,7 +19,18 @@ loop.standaloneRoomViews = (function(mozL10n) {
var StandaloneRoomInfoArea = React.createClass({
propTypes: {
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired,
activeRoomStore:
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
feedbackStore:
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired
},
onFeedbackSent: function() {
// We pass a tick to prevent React warnings regarding nested updates.
setTimeout(function() {
this.props.activeRoomStore.dispatchAction(new sharedActions.FeedbackComplete());
}.bind(this));
},
_renderCallToActionLink: function() {
@ -55,53 +66,75 @@ loop.standaloneRoomViews = (function(mozL10n) {
}
},
_renderContent: function() {
render: function() {
switch(this.props.roomState) {
case ROOM_STATES.INIT:
case ROOM_STATES.READY:
case ROOM_STATES.ENDED: {
case ROOM_STATES.READY: {
// XXX: In ENDED state, we should rather display the feedback form.
return (
<button className="btn btn-join btn-info"
onClick={this.props.joinRoom}>
{mozL10n.get("rooms_room_join_label")}
</button>
<div className="room-inner-info-area">
<button className="btn btn-join btn-info"
onClick={this.props.joinRoom}>
{mozL10n.get("rooms_room_join_label")}
</button>
</div>
);
}
case ROOM_STATES.MEDIA_WAIT: {
var msg = mozL10n.get("call_progress_getting_media_description",
{clientShortname: mozL10n.get("clientShortname2")});
// XXX Bug 1047040 will add images to help prompt the user.
return (
<div className="room-inner-info-area">
<p className="prompt-media-message">
{msg}
</p>
</div>
);
}
case ROOM_STATES.JOINED:
case ROOM_STATES.SESSION_CONNECTED: {
return (
<p className="empty-room-message">
{mozL10n.get("rooms_only_occupant_label")}
</p>
<div className="room-inner-info-area">
<p className="empty-room-message">
{mozL10n.get("rooms_only_occupant_label")}
</p>
</div>
);
}
case ROOM_STATES.FULL:
case ROOM_STATES.FULL: {
return (
<div>
<div className="room-inner-info-area">
<p className="full-room-message">
{mozL10n.get("rooms_room_full_label")}
</p>
<p>{this._renderCallToActionLink()}</p>
</div>
);
case ROOM_STATES.FAILED:
}
case ROOM_STATES.ENDED: {
return (
<p className="failed-room-message">
{this._getFailureString()}
</p>
<div className="ended-conversation">
<sharedViews.FeedbackView
feedbackStore={this.props.feedbackStore}
onAfterFeedbackReceived={this.onFeedbackSent}
/>
</div>
);
default:
}
case ROOM_STATES.FAILED: {
return (
<div className="room-inner-info-area">
<p className="failed-room-message">
{this._getFailureString()}
</p>
</div>
);
}
default: {
return null;
}
}
},
render: function() {
return (
<div className="room-inner-info-area">
{this._renderContent()}
</div>
);
}
});
@ -154,6 +187,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
propTypes: {
activeRoomStore:
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
feedbackStore:
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired,
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired
},
@ -211,7 +246,31 @@ loop.standaloneRoomViews = (function(mozL10n) {
};
},
/**
* Used to update the video container whenever the orientation or size of the
* display area changes.
*/
updateVideoContainer: function() {
var localStreamParent = this._getElement('.local .OT_publisher');
var remoteStreamParent = this._getElement('.remote .OT_subscriber');
if (localStreamParent) {
localStreamParent.style.width = "100%";
}
if (remoteStreamParent) {
remoteStreamParent.style.height = "100%";
}
},
componentDidMount: function() {
/**
* OT inserts inline styles into the markup. Using a listener for
* resize events helps us trigger a full width/height on the element
* so that they update to the correct dimensions.
* XXX: this should be factored as a mixin, bug 1104930
*/
window.addEventListener('orientationchange', this.updateVideoContainer);
window.addEventListener('resize', this.updateVideoContainer);
// Adding a class to the document body element from here to ease styling it.
document.body.classList.add("is-standalone-room");
},
@ -228,14 +287,22 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @param {Object} nextState Next state object.
*/
componentWillUpdate: function(nextProps, nextState) {
if (this.state.roomState !== ROOM_STATES.JOINED &&
nextState.roomState === ROOM_STATES.JOINED) {
if (this.state.roomState !== ROOM_STATES.MEDIA_WAIT &&
nextState.roomState === ROOM_STATES.MEDIA_WAIT) {
this.props.dispatcher.dispatch(new sharedActions.SetupStreamElements({
publisherConfig: this._getPublisherConfig(),
getLocalElementFunc: this._getElement.bind(this, ".local"),
getRemoteElementFunc: this._getElement.bind(this, ".remote")
}));
}
if (this.state.roomState !== ROOM_STATES.JOINED &&
nextState.roomState === ROOM_STATES.JOINED) {
// This forces the video size to update - creating the publisher
// first, and then connecting to the session doesn't seem to set the
// initial size correctly.
this.updateVideoContainer();
}
},
joinRoom: function() {
@ -284,7 +351,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
<StandaloneRoomInfoArea roomState={this.state.roomState}
failureReason={this.state.failureReason}
joinRoom={this.joinRoom}
helper={this.props.helper} />
helper={this.props.helper}
activeRoomStore={this.props.activeRoomStore}
feedbackStore={this.props.feedbackStore} />
<div className="video-layout-wrapper">
<div className="conversation room-conversation">
<h2 className="room-name">{this.state.roomName}</h2>

Просмотреть файл

@ -690,9 +690,10 @@ loop.webapp = (function($, _, OT, mozL10n) {
return nextState.callStatus !== this.state.callStatus;
},
callStatusSwitcher: function(status) {
resetCallStatus: function() {
this.props.feedbackStore.dispatchAction(new sharedActions.FeedbackComplete());
return function() {
this.setState({callStatus: status});
this.setState({callStatus: "start"});
}.bind(this);
},
@ -744,7 +745,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
sdk: this.props.sdk,
conversation: this.props.conversation,
feedbackStore: this.props.feedbackStore,
onAfterFeedbackReceived: this.callStatusSwitcher("start")}
onAfterFeedbackReceived: this.resetCallStatus()}
)
);
}
@ -1010,6 +1011,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
return (
loop.standaloneRoomViews.StandaloneRoomView({
activeRoomStore: this.props.activeRoomStore,
feedbackStore: this.props.feedbackStore,
dispatcher: this.props.dispatcher,
helper: this.props.helper}
)

Просмотреть файл

@ -690,9 +690,10 @@ loop.webapp = (function($, _, OT, mozL10n) {
return nextState.callStatus !== this.state.callStatus;
},
callStatusSwitcher: function(status) {
resetCallStatus: function() {
this.props.feedbackStore.dispatchAction(new sharedActions.FeedbackComplete());
return function() {
this.setState({callStatus: status});
this.setState({callStatus: "start"});
}.bind(this);
},
@ -744,7 +745,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
sdk={this.props.sdk}
conversation={this.props.conversation}
feedbackStore={this.props.feedbackStore}
onAfterFeedbackReceived={this.callStatusSwitcher("start")}
onAfterFeedbackReceived={this.resetCallStatus()}
/>
);
}
@ -1010,6 +1011,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
return (
<loop.standaloneRoomViews.StandaloneRoomView
activeRoomStore={this.props.activeRoomStore}
feedbackStore={this.props.feedbackStore}
dispatcher={this.props.dispatcher}
helper={this.props.helper}
/>

Просмотреть файл

@ -25,9 +25,9 @@ function getConfigFile(req, res) {
// uploaded to the marketplace bug 1053424
"loop.config.marketplaceUrl = 'http://fake-market.herokuapp.com/iframe-install.html'",
"loop.config.brandWebsiteUrl = 'https://www.mozilla.org/firefox/';",
"loop.config.privacyWebsiteUrl = 'https://www.mozilla.org/privacy';",
"loop.config.privacyWebsiteUrl = 'https://www.mozilla.org/privacy/firefox-hello/';",
"loop.config.learnMoreUrl = 'https://www.mozilla.org/hello/';",
"loop.config.legalWebsiteUrl = '/legal/terms';",
"loop.config.legalWebsiteUrl = 'https://www.mozilla.org/about/legal/terms/firefox-hello/';",
"loop.config.fxosApp = loop.config.fxosApp || {};",
"loop.config.fxosApp.name = 'Loop';",
"loop.config.fxosApp.manifestUrl = 'http://fake-market.herokuapp.com/apps/packagedApp/manifest.webapp';",

Просмотреть файл

@ -77,7 +77,9 @@ describe("loop.store.ActiveRoomStore", function () {
fakeError = new Error("fake");
store.setStoreState({
roomState: ROOM_STATES.READY
roomState: ROOM_STATES.JOINED,
roomToken: "fakeToken",
sessionToken: "1627384950"
});
});
@ -86,7 +88,7 @@ describe("loop.store.ActiveRoomStore", function () {
sinon.assert.calledOnce(console.error);
sinon.assert.calledWith(console.error,
sinon.match(ROOM_STATES.READY), fakeError);
sinon.match(ROOM_STATES.JOINED), fakeError);
});
it("should set the state to `FULL` on server error room full", function() {
@ -123,6 +125,35 @@ describe("loop.store.ActiveRoomStore", function () {
expect(store._storeState.roomState).eql(ROOM_STATES.FAILED);
expect(store._storeState.failureReason).eql(FAILURE_REASONS.EXPIRED_OR_INVALID);
});
it("should reset the multiplexGum", function() {
store.roomFailure({error: fakeError});
sinon.assert.calledOnce(fakeMultiplexGum.reset);
});
it("should disconnect from the servers via the sdk", function() {
store.roomFailure({error: fakeError});
sinon.assert.calledOnce(fakeSdkDriver.disconnectSession);
});
it("should clear any existing timeout", function() {
sandbox.stub(window, "clearTimeout");
store._timeout = {};
store.roomFailure({error: fakeError});
sinon.assert.calledOnce(clearTimeout);
});
it("should call mozLoop.rooms.leave", function() {
store.roomFailure({error: fakeError});
sinon.assert.calledOnce(fakeMozLoop.rooms.leave);
sinon.assert.calledWithExactly(fakeMozLoop.rooms.leave,
"fakeToken", "1627384950");
});
});
describe("#setupWindowData", function() {
@ -233,6 +264,22 @@ describe("loop.store.ActiveRoomStore", function () {
});
});
describe("#feedbackComplete", function() {
it("should reset the room store state", function() {
var initialState = store.getInitialStoreState();
store.setStoreState({
roomState: ROOM_STATES.ENDED,
audioMuted: true,
videoMuted: true,
failureReason: "foo"
});
store.feedbackComplete(new sharedActions.FeedbackComplete());
expect(store.getStoreState()).eql(initialState);
});
});
describe("#setupRoomInfo", function() {
var fakeRoomInfo;
@ -284,10 +331,6 @@ describe("loop.store.ActiveRoomStore", function () {
});
describe("#joinRoom", function() {
beforeEach(function() {
store.setStoreState({roomToken: "tokenFake"});
});
it("should reset failureReason", function() {
store.setStoreState({failureReason: "Test"});
@ -296,9 +339,23 @@ describe("loop.store.ActiveRoomStore", function () {
expect(store.getStoreState().failureReason).eql(undefined);
});
it("should call rooms.join on mozLoop", function() {
it("should set the state to MEDIA_WAIT", function() {
store.setStoreState({roomState: ROOM_STATES.READY});
store.joinRoom();
expect(store.getStoreState().roomState).eql(ROOM_STATES.MEDIA_WAIT);
});
});
describe("#gotMediaPermission", function() {
beforeEach(function() {
store.setStoreState({roomToken: "tokenFake"});
});
it("should call rooms.join on mozLoop", function() {
store.gotMediaPermission();
sinon.assert.calledOnce(fakeMozLoop.rooms.join);
sinon.assert.calledWith(fakeMozLoop.rooms.join, "tokenFake");
});
@ -313,7 +370,7 @@ describe("loop.store.ActiveRoomStore", function () {
fakeMozLoop.rooms.join.callsArgWith(1, null, responseData);
store.joinRoom();
store.gotMediaPermission();
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWith(dispatcher.dispatch,
@ -325,7 +382,7 @@ describe("loop.store.ActiveRoomStore", function () {
fakeMozLoop.rooms.join.callsArgWith(1, fakeError);
store.joinRoom();
store.gotMediaPermission();
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWith(dispatcher.dispatch,
@ -374,6 +431,34 @@ describe("loop.store.ActiveRoomStore", function () {
actionData);
});
it("should call mozLoop.rooms.get to get the room data if the roomName" +
"is not known", function() {
store.setStoreState({roomName: undefined});
store.joinedRoom(new sharedActions.JoinedRoom(fakeJoinedData));
sinon.assert.calledOnce(fakeMozLoop.rooms.get);
});
it("should dispatch UpdateRoomInfo if mozLoop.rooms.get is successful",
function() {
var roomDetails = {
roomName: "fakeName",
roomUrl: "http://invalid",
roomOwner: "gavin"
};
fakeMozLoop.rooms.get.callsArgWith(1, null, roomDetails);
store.setStoreState({roomName: undefined});
store.joinedRoom(new sharedActions.JoinedRoom(fakeJoinedData));
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.UpdateRoomInfo(roomDetails));
});
it("should call mozLoop.rooms.refreshMembership before the expiresTime",
function() {
store.joinedRoom(new sharedActions.JoinedRoom(fakeJoinedData));
@ -546,7 +631,7 @@ describe("loop.store.ActiveRoomStore", function () {
});
it("should reset the multiplexGum", function() {
store.leaveRoom();
store.windowUnload();
sinon.assert.calledOnce(fakeMultiplexGum.reset);
});

Просмотреть файл

@ -105,4 +105,16 @@ describe("loop.store.FeedbackStore", function () {
store.sendFeedback(new sharedActions.SendFeedback(sadFeedbackData));
});
});
describe("feedbackComplete", function() {
it("should reset the store state", function() {
store.setStoreState({feedbackState: FEEDBACK_STATES.SENT});
store.feedbackComplete();
expect(store.getStoreState()).eql({
feedbackState: FEEDBACK_STATES.INIT
});
});
});
});

Просмотреть файл

@ -295,6 +295,14 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(session.publish);
});
it("should dispatch a GotMediaPermission action", function() {
publisher.trigger("accessAllowed", fakeEvent);
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.GotMediaPermission());
});
});
describe("accessDenied", function() {

Просмотреть файл

@ -76,6 +76,42 @@ describe("loop.StandaloneMozLoop", function() {
});
});
describe("#rooms.get", function() {
it("should GET to the server", function() {
mozLoop.rooms.get("fakeToken", callback);
expect(requests).to.have.length.of(1);
expect(requests[0].url).eql(fakeBaseServerUrl + "/rooms/fakeToken");
expect(requests[0].method).eql("GET");
});
it("should call the callback with success parameters", function() {
mozLoop.rooms.get("fakeToken", callback);
var roomDetails = {
roomName: "fakeName",
roomUrl: "http://invalid",
roomOwner: "gavin"
};
requests[0].respond(200, {"Content-Type": "application/json"},
JSON.stringify(roomDetails));
sinon.assert.calledOnce(callback);
sinon.assert.calledWithExactly(callback, null, roomDetails);
});
it("should call the callback with failure parameters", function() {
mozLoop.rooms.get("fakeToken", callback);
requests[0].respond(401, {"Content-Type": "application/json"},
JSON.stringify(fakeServerErrorDescription));
sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
return /HTTP 401 Unauthorized/.test(err.message);
}));
});
});
describe("#rooms.join", function() {
it("should POST to the server", function() {
mozLoop.rooms.join("fakeToken", callback);

Просмотреть файл

@ -10,9 +10,10 @@ describe("loop.standaloneRoomViews", function() {
"use strict";
var ROOM_STATES = loop.store.ROOM_STATES;
var FEEDBACK_STATES = loop.store.FEEDBACK_STATES;
var sharedActions = loop.shared.actions;
var sandbox, dispatcher, activeRoomStore, dispatch;
var sandbox, dispatcher, activeRoomStore, feedbackStore, dispatch;
beforeEach(function() {
sandbox = sinon.sandbox.create();
@ -22,18 +23,27 @@ describe("loop.standaloneRoomViews", function() {
mozLoop: {},
sdkDriver: {}
});
feedbackStore = new loop.store.FeedbackStore(dispatcher, {
feedbackClient: {}
});
sandbox.useFakeTimers();
// Prevents audio request errors in the test console.
sandbox.useFakeXMLHttpRequest();
});
afterEach(function() {
sandbox.restore();
});
describe("standaloneRoomView", function() {
describe("StandaloneRoomView", function() {
function mountTestComponent() {
return TestUtils.renderIntoDocument(
loop.standaloneRoomViews.StandaloneRoomView({
dispatcher: dispatcher,
activeRoomStore: activeRoomStore,
feedbackStore: feedbackStore,
helper: new loop.shared.utils.Helper()
}));
}
@ -53,27 +63,49 @@ describe("loop.standaloneRoomViews", function() {
}
describe("#componentWillUpdate", function() {
it("should dispatch a `SetupStreamElements` action on room joined",
function() {
it("should dispatch a `SetupStreamElements` action when the MEDIA_WAIT state " +
"is entered", function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.READY});
var view = mountTestComponent();
sinon.assert.notCalled(dispatch);
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
activeRoomStore.setStoreState({roomState: ROOM_STATES.MEDIA_WAIT});
expectActionDispatched(view);
});
it("should dispatch a `SetupStreamElements` action on room rejoined",
function() {
it("should dispatch a `SetupStreamElements` action on MEDIA_WAIT state is " +
"re-entered", function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.ENDED});
var view = mountTestComponent();
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
activeRoomStore.setStoreState({roomState: ROOM_STATES.MEDIA_WAIT});
expectActionDispatched(view);
});
it("should updateVideoContainer when the JOINED state is entered", function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.READY});
var view = mountTestComponent();
sandbox.stub(view, "updateVideoContainer");
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
sinon.assert.calledOnce(view.updateVideoContainer);
});
it("should updateVideoContainer when the JOINED state is re-entered", function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.ENDED});
var view = mountTestComponent();
sandbox.stub(view, "updateVideoContainer");
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
sinon.assert.calledOnce(view.updateVideoContainer);
});
});
describe("#publishStream", function() {
@ -143,6 +175,16 @@ describe("loop.standaloneRoomViews", function() {
});
});
describe("Prompt media message", function() {
it("should display a prompt for user media on MEDIA_WAIT",
function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.MEDIA_WAIT});
expect(view.getDOMNode().querySelector(".prompt-media-message"))
.not.eql(null);
});
});
describe("Full room message", function() {
it("should display a full room message on FULL",
function() {
@ -247,6 +289,28 @@ describe("loop.standaloneRoomViews", function() {
sinon.assert.calledWithExactly(dispatch, new sharedActions.LeaveRoom());
});
});
describe("Feedback", function() {
beforeEach(function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.ENDED});
});
it("should display a feedback form when the user leaves the room",
function() {
expect(view.getDOMNode().querySelector(".faces")).not.eql(null);
});
it("should dispatch a `FeedbackComplete` action after feedback is sent",
function() {
feedbackStore.setStoreState({feedbackState: FEEDBACK_STATES.SENT});
sandbox.clock.tick(
loop.shared.views.WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS * 1000 + 1000);
sinon.assert.calledOnce(dispatch);
sinon.assert.calledWithExactly(dispatch, new sharedActions.FeedbackComplete());
});
});
});
});
});

Просмотреть файл

@ -17,7 +17,6 @@ describe("loop.webapp", function() {
standaloneMedia = loop.standaloneMedia,
sandbox,
notifications,
feedbackApiClient,
stubGetPermsAndCacheMedia,
fakeAudioXHR,
dispatcher,
@ -27,9 +26,6 @@ describe("loop.webapp", function() {
sandbox = sinon.sandbox.create();
dispatcher = new loop.Dispatcher();
notifications = new sharedModels.NotificationCollection();
feedbackApiClient = new loop.FeedbackAPIClient("http://invalid", {
product: "Loop"
});
feedbackStore = new loop.store.FeedbackStore(dispatcher, {
feedbackClient: {}
});
@ -650,15 +646,15 @@ describe("loop.webapp", function() {
function mountTestComponent() {
return TestUtils.renderIntoDocument(
loop.webapp.WebappRootView({
client: client,
helper: helper,
notifications: notifications,
sdk: sdk,
conversation: conversationModel,
feedbackApiClient: feedbackApiClient,
standaloneAppStore: standaloneAppStore,
activeRoomStore: activeRoomStore
}));
client: client,
helper: helper,
notifications: notifications,
sdk: sdk,
conversation: conversationModel,
standaloneAppStore: standaloneAppStore,
activeRoomStore: activeRoomStore,
feedbackStore: feedbackStore
}));
}
beforeEach(function() {

Просмотреть файл

@ -83,6 +83,9 @@ const kRoomUpdates = {
displayName: "Ruharb",
roomConnectionId: "5de6281c-6568-455f-af08-c0b0a973100e"
}]
},
"5": {
deleted: true
}
};
@ -118,6 +121,7 @@ const compareRooms = function(room1, room2) {
// LoopRooms emits various events. Test if they work as expected here.
let gExpectedAdds = [];
let gExpectedUpdates = [];
let gExpectedDeletes = [];
let gExpectedJoins = {};
let gExpectedLeaves = {};
@ -136,6 +140,12 @@ const onRoomUpdated = function(e, room) {
gExpectedUpdates.splice(idx, 1);
};
const onRoomDeleted = function(e, room) {
let idx = gExpectedDeletes.indexOf(room.roomToken);
Assert.ok(idx > -1, "Deleted room should be expected");
gExpectedDeletes.splice(idx, 1);
}
const onRoomJoined = function(e, roomToken, participant) {
let participants = gExpectedJoins[roomToken];
Assert.ok(participants, "Participant should be expected to join");
@ -191,6 +201,7 @@ add_task(function* setup_server() {
let qs = parseQueryString(req.queryString);
let room = kRooms.get("_nxD4V4FflQ");
room.participants = kRoomUpdates[qs.version].participants;
room.deleted = kRoomUpdates[qs.version].deleted;
res.write(JSON.stringify([room]));
} else {
res.write(JSON.stringify([...kRooms.values()]));
@ -386,10 +397,17 @@ add_task(function* test_renameRoom() {
Assert.equal(renameData.roomName, "fakeName");
});
add_task(function* test_roomDeleteNotifications() {
gExpectedDeletes.push("_nxD4V4FflQ");
roomsPushNotification("5");
yield waitForCondition(() => gExpectedDeletes.length === 0);
});
// Test if the event emitter implementation doesn't leak and is working as expected.
add_task(function* () {
Assert.strictEqual(gExpectedAdds.length, 0, "No room additions should be expected anymore");
Assert.strictEqual(gExpectedUpdates.length, 0, "No room updates should be expected anymore");
Assert.strictEqual(gExpectedDeletes.length, 0, "No room deletes should be expected anymore");
});
function run_test() {
@ -397,6 +415,7 @@ function run_test() {
LoopRooms.on("add", onRoomAdded);
LoopRooms.on("update", onRoomUpdated);
LoopRooms.on("delete", onRoomDeleted);
LoopRooms.on("joined", onRoomJoined);
LoopRooms.on("left", onRoomLeft);
@ -409,6 +428,7 @@ function run_test() {
LoopRooms.off("add", onRoomAdded);
LoopRooms.off("update", onRoomUpdated);
LoopRooms.off("delete", onRoomDeleted);
LoopRooms.off("joined", onRoomJoined);
LoopRooms.off("left", onRoomLeft);
});

Просмотреть файл

@ -20,7 +20,11 @@ function test() {
content.location = "http://www.itisatrap.org/firefox/its-an-attack.html";
}
function testMalware() {
function testMalware(event) {
if (event.target != gBrowser.selectedBrowser.contentDocument) {
return;
}
window.removeEventListener("DOMContentLoaded", testMalware, true);
// Confirm that "Ignore this warning" is visible - bug 422410
@ -35,7 +39,11 @@ function testMalware() {
content.location = "http://www.itisatrap.org/firefox/its-a-trap.html";
}
function testPhishing() {
function testPhishing(event) {
if (event.target != gBrowser.selectedBrowser.contentDocument) {
return;
}
window.removeEventListener("DOMContentLoaded", testPhishing, true);
var el = content.document.getElementById("ignoreWarningButton");

Просмотреть файл

@ -1253,8 +1253,9 @@ function getThumbnailForCall(thumbnails, index) {
*/
function viewSourceInDebugger(url, line) {
let showSource = ({ DebuggerView }) => {
if (DebuggerView.Sources.containsValue(url)) {
DebuggerView.setEditorLocation(url, line, { noDebug: true }).then(() => {
let item = DebuggerView.Sources.getItemForAttachment(a => a.source.url === url);
if (item) {
DebuggerView.setEditorLocation(item.attachment.source.actor, line, { noDebug: true }).then(() => {
window.emit(EVENTS.SOURCE_SHOWN_IN_JS_DEBUGGER);
}, () => {
window.emit(EVENTS.SOURCE_NOT_FOUND_IN_JS_DEBUGGER);

Просмотреть файл

@ -64,7 +64,7 @@ function ifTestingSupported() {
let toolbox = yield gDevTools.getToolbox(target);
let { panelWin: { DebuggerView: view } } = toolbox.getPanel("jsdebugger");
is(view.Sources.selectedValue, SIMPLE_CANVAS_DEEP_STACK_URL,
is(view.Sources.selectedValue, getSourceActor(view.Sources, SIMPLE_CANVAS_DEEP_STACK_URL),
"The expected source was shown in the debugger.");
is(view.editor.getCursor().line, 25,
"The expected source line is highlighted in the debugger.");

Просмотреть файл

@ -39,7 +39,7 @@ function ifTestingSupported() {
let toolbox = yield gDevTools.getToolbox(target);
let { panelWin: { DebuggerView: view } } = toolbox.getPanel("jsdebugger");
is(view.Sources.selectedValue, SIMPLE_CANVAS_DEEP_STACK_URL,
is(view.Sources.selectedValue, getSourceActor(view.Sources, SIMPLE_CANVAS_DEEP_STACK_URL),
"The expected source was shown in the debugger.");
is(view.editor.getCursor().line, 23,
"The expected source line is highlighted in the debugger.");

Просмотреть файл

@ -270,3 +270,8 @@ function evalInDebuggee (script) {
return deferred.promise;
}
function getSourceActor(aSources, aURL) {
let item = aSources.getItemForAttachment(a => a.source.url === aURL);
return item ? item.value : null;
}

Просмотреть файл

@ -36,7 +36,7 @@ function getAllBreakpoints(dbg) {
for (let source of sources) {
for (let { attachment: breakpoint } of source) {
breakpoints.push({
url: source.value,
url: source.attachment.source.url,
label: source.attachment.label + ":" + breakpoint.line,
lineNumber: breakpoint.line,
lineText: breakpoint.text,
@ -48,6 +48,20 @@ function getAllBreakpoints(dbg) {
return breakpoints;
}
function getAllSources(dbg) {
if (!dbg) {
return [];
}
let items = dbg._view.Sources.items;
return items
.filter(item => !!item.attachment.source.url)
.map(item => ({
name: item.attachment.source.url,
value: item.attachment.source.actor
}));
}
/**
* 'break' command
*/
@ -142,12 +156,8 @@ exports.items.push({
name: "file",
type: {
name: "selection",
data: function(context) {
let dbg = getPanel(context, "jsdebugger");
if (dbg) {
return dbg._view.Sources.values;
}
return [];
lookup: function(context) {
return getAllSources(getPanel(context, "jsdebugger"));
}
},
description: gcli.lookup("breakaddlineFileDesc")
@ -166,7 +176,10 @@ exports.items.push({
}
let deferred = context.defer();
let position = { url: args.file, line: args.line };
let item = dbg._view.Sources.getItemForAttachment(a => {
return a.source && a.source.actor === args.file;
})
let position = { actor: item.value, line: args.line };
dbg.addBreakpoint(position).then(() => {
deferred.resolve(gcli.lookup("breakaddAdded"));
@ -211,8 +224,13 @@ exports.items.push({
return gcli.lookup("debuggerStopped");
}
let source = dbg._view.Sources.getItemForAttachment(a => {
return a.source && a.source.url === args.breakpoint.url
});
let deferred = context.defer();
let position = { url: args.breakpoint.url, line: args.breakpoint.lineNumber };
let position = { actor: source.attachment.source.actor,
line: args.breakpoint.lineNumber };
dbg.removeBreakpoint(position).then(() => {
deferred.resolve(gcli.lookup("breakdelRemoved"));
@ -390,14 +408,14 @@ exports.items.push({
return gcli.lookup("debuggerClosed");
}
let sources = dbg._view.Sources.values;
let sources = getAllSources(dbg);
let doc = context.environment.chromeDocument;
let div = createXHTMLElement(doc, "div");
let ol = createXHTMLElement(doc, "ol");
sources.forEach(source => {
let li = createXHTMLElement(doc, "li");
li.textContent = source;
li.textContent = source.name;
ol.appendChild(li);
});
div.appendChild(ol);
@ -433,12 +451,8 @@ exports.items.push({
name: "source",
type: {
name: "selection",
data: function(context) {
let dbg = getPanel(context, "jsdebugger");
if (dbg) {
return dbg._view.Sources.values;
}
return [];
lookup: function(context) {
return getAllSources(getPanel(context, "jsdebugger"));
}
},
description: lookup("SourceDesc"),
@ -472,7 +486,7 @@ exports.items.push({
function shouldBlackBox(source) {
var value = globRegExp && globRegExp.test(source.url)
|| args.source && source.url == args.source;
|| args.source && source.actor == args.source;
return args.invert ? !value : value;
}

Просмотреть файл

@ -664,10 +664,12 @@ StackFrames.prototype = {
_refillFrames: function() {
// Make sure all the previous stackframes are removed before re-adding them.
DebuggerView.StackFrames.empty();
for (let frame of this.activeThread.cachedFrames) {
let { depth, where: { url, line }, source } = frame;
let { depth, source, where: { line } } = frame;
let isBlackBoxed = source ? this.activeThread.source(source).isBlackBoxed : false;
let location = NetworkHelper.convertToUnicode(unescape(url));
let location = NetworkHelper.convertToUnicode(unescape(source.url || source.introductionUrl));
let title = StackFrameUtils.getFrameTitle(frame);
DebuggerView.StackFrames.addFrame(title, location, line, depth, isBlackBoxed);
}
@ -762,7 +764,7 @@ StackFrames.prototype = {
}
// Check if the frame does not represent the evaluation of debuggee code.
let { environment, where } = frame;
let { environment, where, source } = frame;
if (!environment) {
return;
}
@ -774,10 +776,10 @@ StackFrames.prototype = {
let isPopupShown = DebuggerView.VariableBubble.contentsShown();
if (!isClientEval && !isPopupShown) {
// Move the editor's caret to the proper url and line.
DebuggerView.setEditorLocation(where.url, where.line);
DebuggerView.setEditorLocation(source.actor, where.line);
} else {
// Highlight the line where the execution is paused in the editor.
DebuggerView.setEditorLocation(where.url, where.line, { noCaret: true });
DebuggerView.setEditorLocation(source.actor, where.line, { noCaret: true });
}
// Highlight the breakpoint at the line and column if it exists.
@ -933,6 +935,7 @@ StackFrames.prototype = {
if (!breakLocation) {
return;
}
let breakpointPromise = DebuggerController.Breakpoints._getAdded(breakLocation);
if (!breakpointPromise) {
return;
@ -1245,8 +1248,8 @@ SourceScripts.prototype = {
/**
* Handler for the debugger client's 'blackboxchange' notification.
*/
_onBlackBoxChange: function (aEvent, { url, isBlackBoxed }) {
const item = DebuggerView.Sources.getItemByValue(url);
_onBlackBoxChange: function (aEvent, { actor, isBlackBoxed }) {
const item = DebuggerView.Sources.getItemByValue(actor);
if (item) {
item.prebuiltNode.classList.toggle("black-boxed", isBlackBoxed);
}
@ -1312,13 +1315,13 @@ SourceScripts.prototype = {
const deferred = promise.defer();
deferred.promise.pretty = wantPretty;
this._cache.set(aSource.url, deferred.promise);
this._cache.set(aSource.actor, deferred.promise);
const afterToggle = ({ error, message, source: text, contentType }) => {
if (error) {
// Revert the rejected promise from the cache, so that the original
// source's text may be shown when the source is selected.
this._cache.set(aSource.url, textPromise);
this._cache.set(aSource.actor, textPromise);
deferred.reject([aSource, message || error]);
return;
}
@ -1360,13 +1363,13 @@ SourceScripts.prototype = {
*/
getText: function(aSource, aOnTimeout, aDelay = FETCH_SOURCE_RESPONSE_DELAY) {
// Fetch the source text only once.
let textPromise = this._cache.get(aSource.url);
let textPromise = this._cache.get(aSource.actor);
if (textPromise) {
return textPromise;
}
let deferred = promise.defer();
this._cache.set(aSource.url, deferred.promise);
this._cache.set(aSource.actor, deferred.promise);
// If the source text takes a long time to fetch, invoke a callback.
if (aOnTimeout) {
@ -1397,9 +1400,9 @@ SourceScripts.prototype = {
* @return object
* A promise that is resolved after source texts have been fetched.
*/
getTextForSources: function(aUrls) {
getTextForSources: function(aActors) {
let deferred = promise.defer();
let pending = new Set(aUrls);
let pending = new Set(aActors);
let fetched = [];
// Can't use promise.all, because if one fetch operation is rejected, then
@ -1408,8 +1411,8 @@ SourceScripts.prototype = {
// would work like a charm here.
// Try to fetch as many sources as possible.
for (let url of aUrls) {
let sourceItem = DebuggerView.Sources.getItemByValue(url);
for (let actor of aActors) {
let sourceItem = DebuggerView.Sources.getItemByValue(actor);
let sourceForm = sourceItem.attachment.source;
this.getText(sourceForm, onTimeout).then(onFetch, onError);
}
@ -1422,17 +1425,17 @@ SourceScripts.prototype = {
/* Called if fetching a source finishes successfully. */
function onFetch([aSource, aText, aContentType]) {
// If fetching the source has previously timed out, discard it this time.
if (!pending.has(aSource.url)) {
if (!pending.has(aSource.actor)) {
return;
}
pending.delete(aSource.url);
fetched.push([aSource.url, aText, aContentType]);
pending.delete(aSource.actor);
fetched.push([aSource.actor, aText, aContentType]);
maybeFinish();
}
/* Called if fetching a source failed because of an error. */
function onError([aSource, aError]) {
pending.delete(aSource.url);
pending.delete(aSource.actor);
maybeFinish();
}
@ -1778,7 +1781,7 @@ EventListeners.prototype = {
const msg = "Error getting function definition site: " + aResponse.message;
DevToolsUtils.reportException("_getDefinitionSite", msg);
}
deferred.resolve(aResponse.url);
deferred.resolve(aResponse.source.url);
});
return deferred.promise;
@ -1838,25 +1841,26 @@ Breakpoints.prototype = {
* Line number where breakpoint was set.
*/
_onEditorBreakpointAdd: Task.async(function*(_, aLine) {
let url = DebuggerView.Sources.selectedValue;
let location = { url: url, line: aLine + 1 };
let breakpointClient = yield this.addBreakpoint(location, { noEditorUpdate: true });
let actor = DebuggerView.Sources.selectedValue;
let location = { actor: actor, line: aLine + 1 };
// Initialize the breakpoint, but don't update the editor, since this
// callback is invoked because a breakpoint was added in the editor itself.
this.addBreakpoint(location, { noEditorUpdate: true }).then(aBreakpointClient => {
// If the breakpoint client has a "requestedLocation" attached, then
// the original requested placement for the breakpoint wasn't accepted.
// In this case, we need to update the editor with the new location.
if (breakpointClient.requestedLocation) {
DebuggerView.editor.moveBreakpoint(
breakpointClient.requestedLocation.line - 1,
breakpointClient.location.line - 1
);
}
// Notify that we've shown a breakpoint in the source editor.
window.emit(EVENTS.BREAKPOINT_SHOWN_IN_EDITOR);
});
// callback is invoked because a breakpoint was added in the
// editor itself.
let breakpointClient = yield this.addBreakpoint(location, { noEditorUpdate: true });
// If the breakpoint client has a "requestedLocation" attached, then
// the original requested placement for the breakpoint wasn't accepted.
// In this case, we need to update the editor with the new location.
if (breakpointClient.requestedLocation) {
DebuggerView.editor.moveBreakpoint(
breakpointClient.requestedLocation.line - 1,
breakpointClient.location.line - 1
);
}
// Notify that we've shown a breakpoint in the source editor.
window.emit(EVENTS.BREAKPOINT_SHOWN_IN_EDITOR);
}),
/**
@ -1866,8 +1870,8 @@ Breakpoints.prototype = {
* Line number where breakpoint was removed.
*/
_onEditorBreakpointRemove: Task.async(function*(_, aLine) {
let url = DebuggerView.Sources.selectedValue;
let location = { url: url, line: aLine + 1 };
let actor = DebuggerView.Sources.selectedValue;
let location = { actor: actor, line: aLine + 1 };
yield this.removeBreakpoint(location, { noEditorUpdate: true });
// Notify that we've hidden a breakpoint in the source editor.
@ -1883,11 +1887,13 @@ Breakpoints.prototype = {
updateEditorBreakpoints: Task.async(function*() {
for (let breakpointPromise of this._addedOrDisabled) {
let breakpointClient = yield breakpointPromise;
let currentSourceUrl = DebuggerView.Sources.selectedValue;
let breakpointUrl = breakpointClient.location.url;
let location = breakpointClient.location;
let currentSourceActor = DebuggerView.Sources.selectedValue;
let sourceActor = DebuggerView.Sources.getActorForLocation(location);
// Update the view only if the breakpoint is in the currently shown source.
if (currentSourceUrl == breakpointUrl) {
// Update the view only if the breakpoint is in the currently
// shown source.
if (currentSourceActor === sourceActor) {
yield this._showBreakpoint(breakpointClient, { noPaneUpdate: true });
}
}
@ -1903,10 +1909,10 @@ Breakpoints.prototype = {
for (let breakpointPromise of this._addedOrDisabled) {
let breakpointClient = yield breakpointPromise;
let container = DebuggerView.Sources;
let breakpointUrl = breakpointClient.location.url;
let sourceActor = breakpointClient.location.actor;
// Update the view only if the breakpoint exists in a known source.
if (container.containsValue(breakpointUrl)) {
if (container.containsValue(sourceActor)) {
yield this._showBreakpoint(breakpointClient, { noEditorUpdate: true });
}
}
@ -1956,8 +1962,11 @@ Breakpoints.prototype = {
let identifier = this.getIdentifier(aLocation);
this._added.set(identifier, deferred.promise);
// Try adding the breakpoint.
gThreadClient.setBreakpoint(aLocation, Task.async(function*(aResponse, aBreakpointClient) {
let source = gThreadClient.source(
DebuggerView.Sources.getItemByValue(aLocation.actor).attachment.source
);
source.setBreakpoint(aLocation, Task.async(function*(aResponse, aBreakpointClient) {
// If the breakpoint response has an "actualLocation" attached, then
// the original requested placement for the breakpoint wasn't accepted.
if (aResponse.actualLocation) {
@ -1988,8 +1997,10 @@ Breakpoints.prototype = {
if (aResponse.actualLocation) {
// Store the originally requested location in case it's ever needed
// and update the breakpoint client with the actual location.
let actualLoc = aResponse.actualLocation;
aBreakpointClient.requestedLocation = aLocation;
aBreakpointClient.location = aResponse.actualLocation;
aBreakpointClient.location = actualLoc;
aBreakpointClient.location.actor = actualLoc.source ? actualLoc.source.actor : null;
}
// Preserve information about the breakpoint's line text, to display it
@ -1999,7 +2010,8 @@ Breakpoints.prototype = {
let line = aBreakpointClient.location.line - 1;
aBreakpointClient.text = DebuggerView.editor.getText(line).trim();
// Show the breakpoint in the editor and breakpoints pane, and resolve.
// Show the breakpoint in the editor and breakpoints pane, and
// resolve.
yield this._showBreakpoint(aBreakpointClient, aOptions);
// Notify that we've added a breakpoint.
@ -2142,30 +2154,31 @@ Breakpoints.prototype = {
/**
* Update the editor and breakpoints pane to show a specified breakpoint.
*
* @param object aBreakpointData
* Information about the breakpoint to be shown.
* This object must have the following properties:
* - location: the breakpoint's source location and line number
* @param object aBreakpointClient
* A BreakpointClient instance.
* This object has additional properties dynamically added by
* our code:
* - disabled: the breakpoint's disabled state, boolean
* - text: the breakpoint's line text to be displayed
* @param object aOptions [optional]
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_showBreakpoint: function(aBreakpointData, aOptions = {}) {
_showBreakpoint: function(aBreakpointClient, aOptions = {}) {
let tasks = [];
let currentSourceUrl = DebuggerView.Sources.selectedValue;
let location = aBreakpointData.location;
let currentSourceActor = DebuggerView.Sources.selectedValue;
let location = aBreakpointClient.location;
let actor = DebuggerView.Sources.getActorForLocation(location);
// Update the editor if required.
if (!aOptions.noEditorUpdate && !aBreakpointData.disabled) {
if (location.url == currentSourceUrl) {
if (!aOptions.noEditorUpdate && !aBreakpointClient.disabled) {
if (currentSourceActor === actor) {
tasks.push(DebuggerView.editor.addBreakpoint(location.line - 1));
}
}
// Update the breakpoints pane if required.
if (!aOptions.noPaneUpdate) {
DebuggerView.Sources.addBreakpoint(aBreakpointData, aOptions);
DebuggerView.Sources.addBreakpoint(aBreakpointClient, aOptions);
}
return promise.all(tasks);
@ -2180,11 +2193,12 @@ Breakpoints.prototype = {
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_hideBreakpoint: function(aLocation, aOptions = {}) {
let currentSourceUrl = DebuggerView.Sources.selectedValue;
let currentSourceActor = DebuggerView.Sources.selectedValue;
let actor = DebuggerView.Sources.getActorForLocation(aLocation);
// Update the editor if required.
if (!aOptions.noEditorUpdate) {
if (aLocation.url == currentSourceUrl) {
if (currentSourceActor === actor) {
DebuggerView.editor.removeBreakpoint(aLocation.line - 1);
}
}
@ -2233,7 +2247,8 @@ Breakpoints.prototype = {
* The identifier string.
*/
getIdentifier: function(aLocation) {
return aLocation.url + ":" + aLocation.line;
return (aLocation.source ? aLocation.source.actor : aLocation.actor) +
":" + aLocation.line;
}
};
@ -2262,13 +2277,15 @@ function HitCounts() {
HitCounts.prototype = {
set: function({url, line, column}, aHitCount) {
if (!this._hitCounts[url]) {
this._hitCounts[url] = Object.create(null);
if (url) {
if (!this._hitCounts[url]) {
this._hitCounts[url] = Object.create(null);
}
if (!this._hitCounts[url][line]) {
this._hitCounts[url][line] = Object.create(null);
}
this._hitCounts[url][line][column] = aHitCount;
}
if (!this._hitCounts[url][line]) {
this._hitCounts[url][line] = Object.create(null);
}
this._hitCounts[url][line][column] = aHitCount;
},
/**
@ -2301,7 +2318,8 @@ HitCounts.prototype = {
// No need to do anything if the counter's source is not being shown in the
// editor.
if (DebuggerView.Sources.selectedValue != url) {
if (url &&
DebuggerView.Sources.selectedItem.attachment.source.url != url) {
return;
}

Просмотреть файл

@ -133,11 +133,13 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* - staged: true to stage the item to be appended later
*/
addSource: function(aSource, aOptions = {}) {
let fullUrl = aSource.url;
let url = fullUrl.split(" -> ").pop();
let label = aSource.addonPath ? aSource.addonPath : SourceUtils.getSourceLabel(url);
let group = aSource.addonID ? aSource.addonID : SourceUtils.getSourceGroup(url);
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(fullUrl));
if (!(aSource.url || aSource.introductionUrl)) {
// These would be most likely eval scripts introduced in inline
// JavaScript in HTML, and we don't show those yet (bug 1097873)
return;
}
let { label, group, unicodeUrl } = this._parseUrl(aSource);
let contents = document.createElement("label");
contents.className = "plain dbg-source-item";
@ -152,7 +154,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
}
// Append a source item to this container.
this.push([contents, fullUrl], {
this.push([contents, aSource.actor], {
staged: aOptions.staged, /* stage the item to be appended later? */
attachment: {
label: label,
@ -164,20 +166,32 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
});
},
_parseUrl: function(aSource) {
let fullUrl = aSource.url || aSource.introductionUrl;
let url = fullUrl.split(" -> ").pop();
let label = aSource.addonPath ? aSource.addonPath : SourceUtils.getSourceLabel(url);
if (aSource.introductionUrl) {
label += ' > eval';
}
return {
label: label,
group: aSource.addonID ? aSource.addonID : SourceUtils.getSourceGroup(url),
unicodeUrl: NetworkHelper.convertToUnicode(unescape(fullUrl))
};
},
/**
* Adds a breakpoint to this sources container.
*
* @param object aBreakpointData
* Information about the breakpoint to be shown.
* This object must have the following properties:
* - location: the breakpoint's source location and line number
* - disabled: the breakpoint's disabled state, boolean
* - text: the breakpoint's line text to be displayed
* @param object aBreakpointClient
* See Breakpoints.prototype._showBreakpoint
* @param object aOptions [optional]
* @see DebuggerController.Breakpoints.addBreakpoint
*/
addBreakpoint: function(aBreakpointData, aOptions = {}) {
let { location, disabled } = aBreakpointData;
addBreakpoint: function(aBreakpointClient, aOptions = {}) {
let { location, disabled } = aBreakpointClient;
// Make sure we're not duplicating anything. If a breakpoint at the
// specified source url and line already exists, just toggle it.
@ -187,17 +201,17 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
}
// Get the source item to which the breakpoint should be attached.
let sourceItem = this.getItemByValue(location.url);
let sourceItem = this.getItemByValue(this.getActorForLocation(location));
// Create the element node and menu popup for the breakpoint item.
let breakpointArgs = Heritage.extend(aBreakpointData, aOptions);
let breakpointArgs = Heritage.extend(aBreakpointClient, aOptions);
let breakpointView = this._createBreakpointView.call(this, breakpointArgs);
let contextMenu = this._createContextMenu.call(this, breakpointArgs);
// Append a breakpoint child item to the corresponding source item.
sourceItem.append(breakpointView.container, {
attachment: Heritage.extend(breakpointArgs, {
url: location.url,
actor: location.actor,
line: location.line,
view: breakpointView,
popup: contextMenu
@ -210,7 +224,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
finalize: this._onBreakpointRemoved
});
// Highlight the newly appended breakpoint child item if necessary.
// Highlight the newly appended breakpoint child item if
// necessary.
if (aOptions.openPopup || !aOptions.noEditorUpdate) {
this.highlightBreakpoint(location, aOptions);
}
@ -228,7 +243,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
removeBreakpoint: function(aLocation) {
// When a parent source item is removed, all the child breakpoint items are
// also automagically removed.
let sourceItem = this.getItemByValue(aLocation.url);
let sourceItem = this.getItemByValue(aLocation.actor);
if (!sourceItem) {
return;
}
@ -253,7 +268,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
*/
getBreakpoint: function(aLocation) {
return this.getItemForPredicate(aItem =>
aItem.attachment.url == aLocation.url &&
aItem.attachment.actor == aLocation.actor &&
aItem.attachment.line == aLocation.line);
},
@ -280,8 +295,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
getOtherBreakpoints: function(aLocation = {}, aStore = []) {
for (let source of this) {
for (let breakpointItem of source) {
let { url, line } = breakpointItem.attachment;
if (url != aLocation.url || line != aLocation.line) {
let { actor, line } = breakpointItem.attachment;
if (actor != aLocation.actor || line != aLocation.line) {
aStore.push(breakpointItem);
}
}
@ -404,7 +419,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
// Update the editor location if necessary.
if (!aOptions.noEditorUpdate) {
DebuggerView.setEditorLocation(aLocation.url, aLocation.line, { noDebug: true });
DebuggerView.setEditorLocation(aLocation.actor, aLocation.line, { noDebug: true });
}
// If the breakpoint requires a new conditional expression, display
@ -421,9 +436,10 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* if it exists.
*/
highlightBreakpointAtCursor: function() {
let url = DebuggerView.Sources.selectedValue;
let actor = DebuggerView.Sources.selectedValue;
let line = DebuggerView.editor.getCursor().line + 1;
let location = { url: url, line: line };
let location = { actor: actor, line: line };
this.highlightBreakpoint(location, { noEditorUpdate: true });
},
@ -466,10 +482,10 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
return;
}
const resetEditor = ([{ url }]) => {
const resetEditor = ([{ actor }]) => {
// Only set the text when the source is still selected.
if (url == this.selectedValue) {
DebuggerView.setEditorLocation(url, 0, { force: true });
if (actor == this.selectedValue) {
DebuggerView.setEditorLocation(actor, 0, { force: true });
}
};
@ -564,6 +580,31 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
}
},
/**
* Look up a source actor id for a location. This is necessary for
* backwards compatibility; otherwise we could just use the `actor`
* property. Older servers don't use the same actor ids for sources
* across reloads, so we resolve a url to the current actor if a url
* exists.
*
* @param object aLocation
* An object with the following properties:
* - actor: the source actor id
* - url: a url (might be null)
*/
getActorForLocation: function(aLocation) {
if (aLocation.url) {
for (var item of this) {
let source = item.attachment.source;
if (aLocation.url === source.url) {
return source.actor;
}
}
}
return aLocation.actor;
},
/**
* Marks a breakpoint as selected in this sources container.
*
@ -575,6 +616,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
return;
}
this._unselectBreakpoint();
this._selectedBreakpointItem = aItem;
this._selectedBreakpointItem.target.classList.add("selected");
@ -820,9 +862,9 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let editor = DebuggerView.editor;
let start = editor.getCursor("start").line + 1;
let end = editor.getCursor().line + 1;
let url = this.selectedValue;
let actor = this.selectedValue;
let location = { url: url, line: start };
let location = { actor: actor, line: start };
if (this.getBreakpoint(location) && start == end) {
this.highlightBreakpoint(location, { noEditorUpdate: true });
@ -854,7 +896,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
// Set window title. No need to split the url by " -> " here, because it was
// already sanitized when the source was added.
document.title = L10N.getFormatStr("DebuggerWindowScriptTitle", sourceItem.value);
document.title = L10N.getFormatStr("DebuggerWindowScriptTitle",
sourceItem.attachment.source.url);
DebuggerView.maybeShowBlackBoxMessage();
this.updateToolbarButtonsState();
@ -974,11 +1017,11 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* Called when the add breakpoint key sequence was pressed.
*/
_onCmdAddBreakpoint: function(e) {
let url = DebuggerView.Sources.selectedValue;
let actor = DebuggerView.Sources.selectedValue;
let line = (e && e.sourceEvent.target.tagName == 'menuitem' ?
DebuggerView.clickedLine + 1 :
DebuggerView.editor.getCursor().line + 1);
let location = { url: url, line: line };
let location = { actor, line };
let breakpointItem = this.getBreakpoint(location);
// If a breakpoint already existed, remove it now.
@ -995,11 +1038,11 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* Called when the add conditional breakpoint key sequence was pressed.
*/
_onCmdAddConditionalBreakpoint: function(e) {
let url = DebuggerView.Sources.selectedValue;
let actor = DebuggerView.Sources.selectedValue;
let line = (e && e.sourceEvent.target.tagName == 'menuitem' ?
DebuggerView.clickedLine + 1 :
DebuggerView.editor.getCursor().line + 1);
let location = { url: url, line: line };
let location = { actor, line };
let breakpointItem = this.getBreakpoint(location);
// If a breakpoint already existed or wasn't a conditional, morph it now.
@ -1313,7 +1356,11 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
const data = traceItem.attachment.trace;
const { location: { url, line } } = data;
DebuggerView.setEditorLocation(url, line, { noDebug: true });
DebuggerView.setEditorLocation(
DebuggerView.Sources.getActorForLocation({ url }),
line,
{ noDebug: true }
);
DebuggerView.Variables.empty();
const scope = DebuggerView.Variables.addScope();
@ -1538,7 +1585,7 @@ let SourceUtils = {
* True if the source is likely javascript.
*/
isJavaScript: function(aUrl, aContentType = "") {
return /\.jsm?$/.test(this.trimUrlQuery(aUrl)) ||
return (aUrl && /\.jsm?$/.test(this.trimUrlQuery(aUrl))) ||
aContentType.contains("javascript");
},
@ -2744,8 +2791,8 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
// Allow requests to settle down first.
setNamedTimeout("global-search", delay, () => {
// Start fetching as many sources as possible, then perform the search.
let urls = DebuggerView.Sources.values;
let sourcesFetched = DebuggerController.SourceScripts.getTextForSources(urls);
let actors = DebuggerView.Sources.values;
let sourcesFetched = DebuggerController.SourceScripts.getTextForSources(actors);
sourcesFetched.then(aSources => this._doSearch(aToken, aSources));
});
},
@ -2774,13 +2821,19 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
let globalResults = new GlobalResults();
// Search for the specified token in each source's text.
for (let [url, text] of aSources) {
for (let [actor, text] of aSources) {
let item = DebuggerView.Sources.getItemByValue(actor);
let url = item.attachment.source.url;
if (!url) {
continue;
}
// Verify that the search token is found anywhere in the source.
if (!text.toLowerCase().contains(lowerCaseToken)) {
continue;
}
// ...and if so, create a Map containing search details for each line.
let sourceResults = new SourceResults(url, globalResults);
let sourceResults = new SourceResults(actor, globalResults);
// Search for the specified token in each line's text.
text.split("\n").forEach((aString, aLine) => {
@ -2917,10 +2970,10 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
this._scrollMatchIntoViewIfNeeded(target);
this._bounceMatch(target);
let url = sourceResultsItem.instance.url;
let actor = sourceResultsItem.instance.actor;
let line = lineResultsItem.instance.line;
DebuggerView.setEditorLocation(url, line + 1, { noDebug: true });
DebuggerView.setEditorLocation(actor, line + 1, { noDebug: true });
let range = lineResultsItem.lineData.range;
let cursor = DebuggerView.editor.getOffset({ line: line, ch: 0 });
@ -2995,13 +3048,15 @@ GlobalResults.prototype = {
* An object containing all the matched lines for a specific source.
* Iterable via "for (let [lineNumber, lineResults] of sourceResults) { }".
*
* @param string aUrl
* The target source url.
* @param string aActor
* The target source actor id.
* @param GlobalResults aGlobalResults
* An object containing all source results, grouped by source location.
*/
function SourceResults(aUrl, aGlobalResults) {
this.url = aUrl;
function SourceResults(aActor, aGlobalResults) {
let item = DebuggerView.Sources.getItemByValue(aActor);
this.actor = aActor;
this.label = item.attachment.source.url;
this._globalResults = aGlobalResults;
this._store = [];
}
@ -3083,7 +3138,7 @@ SourceResults.prototype = {
let locationNode = document.createElement("label");
locationNode.className = "plain dbg-results-header-location";
locationNode.setAttribute("value", this.url);
locationNode.setAttribute("value", this.label);
let matchCountNode = document.createElement("label");
matchCountNode.className = "plain dbg-results-header-match-count";
@ -3116,14 +3171,14 @@ SourceResults.prototype = {
resultsBox.appendChild(resultsHeader);
resultsBox.appendChild(resultsContainer);
aElementNode.id = "source-results-" + this.url;
aElementNode.id = "source-results-" + this.actor;
aElementNode.className = "dbg-source-results";
aElementNode.appendChild(resultsBox);
SourceResults._itemsByElement.set(aElementNode, { instance: this });
},
url: "",
actor: "",
_globalResults: null,
_store: null,
_target: null,

Просмотреть файл

@ -936,7 +936,7 @@ FilterView.prototype = {
DebuggerView.GlobalSearch.scheduleSearch(this.searchArguments[0]);
break;
case SEARCH_FUNCTION_FLAG:
// Schedule a function search for when the user stops typing.
// Schedule a function search for when the user stops typing.
DebuggerView.FilteredFunctions.scheduleSearch(this.searchArguments[0]);
break;
case SEARCH_VARIABLE_FLAG:
@ -1117,7 +1117,7 @@ FilterView.prototype = {
if (SEARCH_AUTOFILL.indexOf(aOperator) != -1) {
let cursor = DebuggerView.editor.getCursor();
let content = DebuggerView.editor.getText();
let location = DebuggerView.Sources.selectedValue;
let location = DebuggerView.Sources.selectedItem.attachment.source.url;
let source = DebuggerController.Parser.get(content, location);
let identifier = source.getIdentifierAt({ line: cursor.line+1, column: cursor.ch });
@ -1306,19 +1306,23 @@ FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype,
}
for (let item of aSearchResults) {
// Create the element node for the location item.
let itemView = this._createItemView(
SourceUtils.trimUrlLength(item.attachment.label),
SourceUtils.trimUrlLength(item.value, 0, "start")
);
let url = item.attachment.source.url;
// Append a location item to this container for each match.
this.push([itemView], {
index: -1, /* specifies on which position should the item be appended */
attachment: {
url: item.value
}
});
if (url) {
// Create the element node for the location item.
let itemView = this._createItemView(
SourceUtils.trimUrlLength(item.attachment.label),
SourceUtils.trimUrlLength(url, 0, "start")
);
// Append a location item to this container for each match.
this.push([itemView], {
index: -1, /* specifies on which position should the item be appended */
attachment: {
url: url
}
});
}
}
// There's at least one item displayed in this container. Don't select it
@ -1351,7 +1355,8 @@ FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype,
*/
_onSelect: function({ detail: locationItem }) {
if (locationItem) {
DebuggerView.setEditorLocation(locationItem.attachment.url, undefined, {
let actor = DebuggerView.Sources.getActorForLocation({ url: locationItem.attachment.url });
DebuggerView.setEditorLocation(actor, undefined, {
noCaret: true,
noDebug: true
});
@ -1408,8 +1413,8 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
// Allow requests to settle down first.
setNamedTimeout("function-search", delay, () => {
// Start fetching as many sources as possible, then perform the search.
let urls = DebuggerView.Sources.values;
let sourcesFetched = DebuggerController.SourceScripts.getTextForSources(urls);
let actors = DebuggerView.Sources.values;
let sourcesFetched = DebuggerController.SourceScripts.getTextForSources(actors);
sourcesFetched.then(aSources => this._doSearch(aToken, aSources));
});
},
@ -1429,8 +1434,8 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
// Make sure the currently displayed source is parsed first. Once the
// maximum allowed number of results are found, parsing will be halted.
let currentUrl = DebuggerView.Sources.selectedValue;
let currentSource = aSources.filter(([sourceUrl]) => sourceUrl == currentUrl)[0];
let currentActor = DebuggerView.Sources.selectedValue;
let currentSource = aSources.filter(([actor]) => actor == currentActor)[0];
aSources.splice(aSources.indexOf(currentSource), 1);
aSources.unshift(currentSource);
@ -1440,8 +1445,14 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
aSources.splice(1);
}
for (let [location, contents] of aSources) {
let parsedSource = DebuggerController.Parser.get(contents, location);
for (let [actor, contents] of aSources) {
let item = DebuggerView.Sources.getItemByValue(actor);
let url = item.attachment.source.url;
if (!url) {
continue;
}
let parsedSource = DebuggerController.Parser.get(contents, url);
let sourceResults = parsedSource.getNamedFunctionDefinitions(aToken);
for (let scriptResult of sourceResults) {
@ -1553,10 +1564,11 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
_onSelect: function({ detail: functionItem }) {
if (functionItem) {
let sourceUrl = functionItem.attachment.sourceUrl;
let actor = DebuggerView.Sources.getActorForLocation({ url: sourceUrl });
let scriptOffset = functionItem.attachment.scriptOffset;
let actualLocation = functionItem.attachment.actualLocation;
DebuggerView.setEditorLocation(sourceUrl, actualLocation.start.line, {
DebuggerView.setEditorLocation(actor, actualLocation.start.line, {
charOffset: scriptOffset,
columnOffset: actualLocation.start.column,
align: "center",

Просмотреть файл

@ -246,7 +246,7 @@ let DebuggerView = {
this.editor.on("gutterClick", (ev, line, button) => {
// A right-click shouldn't do anything but keep track of where
// it was clicked.
if(button == 2) {
if (button == 2) {
this.clickedLine = line;
}
else {
@ -390,7 +390,7 @@ let DebuggerView = {
*/
_setEditorSource: function(aSource, aFlags={}) {
// Avoid setting the same source text in the editor again.
if (this._editorSource.url == aSource.url && !aFlags.force) {
if (this._editorSource.actor == aSource.actor && !aFlags.force) {
return this._editorSource.promise;
}
let transportType = gClient.localTransport ? "_LOCAL" : "_REMOTE";
@ -401,20 +401,21 @@ let DebuggerView = {
let deferred = promise.defer();
this._setEditorText(L10N.getStr("loadingText"));
this._editorSource = { url: aSource.url, promise: deferred.promise };
this._editorSource = { actor: aSource.actor, promise: deferred.promise };
DebuggerController.SourceScripts.getText(aSource).then(([, aText, aContentType]) => {
// Avoid setting an unexpected source. This may happen when switching
// very fast between sources that haven't been fetched yet.
if (this._editorSource.url != aSource.url) {
if (this._editorSource.actor != aSource.actor) {
return;
}
this._setEditorText(aText);
this._setEditorMode(aSource.url, aContentType, aText);
// Synchronize any other components with the currently displayed source.
DebuggerView.Sources.selectedValue = aSource.url;
// Synchronize any other components with the currently displayed
// source.
DebuggerView.Sources.selectedValue = aSource.actor;
DebuggerController.Breakpoints.updateEditorBreakpoints();
DebuggerController.HitCounts.updateEditorHitCounts();
@ -442,8 +443,8 @@ let DebuggerView = {
* Update the source editor's current caret and debug location based on
* a requested url and line.
*
* @param string aUrl
* The target source url.
* @param string aActor
* The target actor id.
* @param number aLine [optional]
* The target line in the source.
* @param object aFlags [optional]
@ -459,9 +460,9 @@ let DebuggerView = {
* @return object
* A promise that is resolved after the source text has been set.
*/
setEditorLocation: function(aUrl, aLine = 0, aFlags = {}) {
setEditorLocation: function(aActor, aLine = 0, aFlags = {}) {
// Avoid trying to set a source for a url that isn't known yet.
if (!this.Sources.containsValue(aUrl)) {
if (!this.Sources.containsValue(aActor)) {
return promise.reject(new Error("Unknown source for the specified URL."));
}
@ -471,17 +472,23 @@ let DebuggerView = {
let cachedFrames = DebuggerController.activeThread.cachedFrames;
let currentDepth = DebuggerController.StackFrames.currentFrameDepth;
let frame = cachedFrames[currentDepth];
if (frame && frame.where.url == aUrl) {
if (frame && frame.source.actor == aActor) {
aLine = frame.where.line;
}
}
let sourceItem = this.Sources.getItemByValue(aUrl);
let sourceItem = this.Sources.getItemByValue(aActor);
let sourceForm = sourceItem.attachment.source;
this._editorLoc = { actor: sourceForm.actor };
// Make sure the requested source client is shown in the editor, then
// update the source editor's caret position and debug location.
return this._setEditorSource(sourceForm, aFlags).then(([,, aContentType]) => {
if (this._editorLoc.actor !== sourceForm.actor) {
return;
}
// Record the contentType learned from fetching
sourceForm.contentType = aContentType;
// Line numbers in the source editor should start from 1. If invalid

Просмотреть файл

@ -25,6 +25,7 @@ support-files =
code_math.min.js
code_math_bogus_map.js
code_same-line-functions.js
code_script-eval.js
code_script-switching-01.js
code_script-switching-02.js
code_test-editor-mode
@ -84,6 +85,7 @@ support-files =
doc_scope-variable-2.html
doc_scope-variable-3.html
doc_scope-variable-4.html
doc_script-eval.html
doc_script-switching-01.html
doc_script-switching-02.html
doc_split-console-paused-reload.html
@ -169,6 +171,8 @@ skip-if = e10s && debug
skip-if = e10s # Bug 1093535
[browser_dbg_breakpoints-editor.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-eval.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-highlight.js]
skip-if = e10s && debug
[browser_dbg_breakpoints-new-script.js]
@ -401,6 +405,8 @@ skip-if = e10s && debug
skip-if = e10s # Bug 1093535
[browser_dbg_sources-cache.js]
skip-if = e10s && debug
[browser_dbg_sources-eval.js]
skip-if = e10s && debug
[browser_dbg_sources-labels.js]
skip-if = e10s && debug
[browser_dbg_sources-sorting.js]

Просмотреть файл

@ -5,6 +5,7 @@
// addon itself, or the SDK, with proper groups and labels.
const ADDON_URL = EXAMPLE_URL + "addon3.xpi";
let gClient;
function test() {
Task.spawn(function () {

Просмотреть файл

@ -25,8 +25,8 @@ function test() {
.then(attachAddonThread)
.then(testDebugger)
.then(testSources)
.then(uninstallAddon)
.then(closeConnection)
.then(uninstallAddon)
.then(finish)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
@ -72,10 +72,9 @@ function testSources() {
gThreadClient.getSources(aResponse => {
// source URLs contain launch-specific temporary directory path,
// hence the ".contains" call.
const matches = aResponse.sources.filter(s =>
s.url.contains(ADDON_MODULE_URL));
is(matches.length, 1,
"the main script of the addon is present in the source list");
const matches = aResponse.sources.filter(s => s.url.contains(ADDON_MODULE_URL));
ok(matches.length > 0,
"the main script of the addon is present in the source list");
deferred.resolve();
});

Просмотреть файл

@ -36,12 +36,12 @@ function test(){
.then(testAutoPrettyPrintOff)
.then(() => {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
gSources.selectedIndex = 1;
return finished;
gSources.selectedIndex = 1;
return finished;
})
.then(testSecondSourceLabel)
.then(testSourceIsUgly)
// Re-enable auto pretty printing for browser_dbg_auto-pretty-print-02.js
// Re-enable auto pretty printing for browser_dbg_auto-pretty-print-02.js
.then(enableAutoPrettyPrint)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
@ -56,7 +56,8 @@ function testSourceIsUgly() {
}
function testSecondSourceLabel(){
ok(gSources.containsValue(EXAMPLE_URL + gSecondSourceLabel),
let source = gSources.selectedItem.attachment.source;
ok(source.url === EXAMPLE_URL + gSecondSourceLabel,
"Second source url is correct.");
}

Просмотреть файл

@ -68,12 +68,14 @@ function testSourceIsUgly() {
}
function testFirstSourceLabel(){
ok(gSources.containsValue(EXAMPLE_URL + gFirstSourceLabel),
let source = gSources.selectedItem.attachment.source;
ok(source.url === EXAMPLE_URL + gFirstSourceLabel,
"First source url is correct.");
}
function testSecondSourceLabel(){
ok(gSources.containsValue(EXAMPLE_URL + gSecondSourceLabel),
let source = gSources.selectedItem.attachment.source;
ok(source.url === EXAMPLE_URL + gSecondSourceLabel,
"Second source url is correct.");
}

Просмотреть файл

@ -10,7 +10,7 @@ const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js"
let gTab, gPanel, gDebugger;
let gFrames;
let gFrames, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
@ -18,6 +18,7 @@ function test() {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gSources = gDebugger.DebuggerView.Sources;
waitForSourceAndCaretAndScopes(gPanel, ".html", 21)
.then(testBlackBoxStack)
@ -39,7 +40,7 @@ function testBlackBoxStack() {
}
function testBlackBoxSource() {
return toggleBlackBoxing(gPanel, BLACKBOXME_URL).then(aSource => {
return toggleBlackBoxing(gPanel, getSourceActor(gSources, BLACKBOXME_URL)).then(aSource => {
ok(aSource.isBlackBoxed, "The source should be black boxed now.");
is(gFrames.itemCount, 3,
@ -54,4 +55,5 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gFrames = null;
gSources = null;
});

Просмотреть файл

@ -10,7 +10,7 @@ const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
const BLACKBOXME_URL = EXAMPLE_URL + "code_blackboxing_blackboxme.js"
let gTab, gPanel, gDebugger;
let gFrames;
let gFrames, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
@ -18,6 +18,7 @@ function test() {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gSources = gDebugger.DebuggerView.Sources;
waitForSourceShown(gPanel, BLACKBOXME_URL)
.then(blackBoxSources)
@ -31,9 +32,10 @@ function test() {
function blackBoxSources() {
let finished = waitForThreadEvents(gPanel, "blackboxchange", 3);
toggleBlackBoxing(gPanel, EXAMPLE_URL + "code_blackboxing_one.js");
toggleBlackBoxing(gPanel, EXAMPLE_URL + "code_blackboxing_two.js");
toggleBlackBoxing(gPanel, EXAMPLE_URL + "code_blackboxing_three.js");
toggleBlackBoxing(gPanel, getSourceActor(gSources, EXAMPLE_URL + "code_blackboxing_one.js"));
toggleBlackBoxing(gPanel, getSourceActor(gSources, EXAMPLE_URL + "code_blackboxing_two.js"));
toggleBlackBoxing(gPanel, getSourceActor(gSources, EXAMPLE_URL + "code_blackboxing_three.js"));
return finished;
}
@ -54,4 +56,5 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gFrames = null;
gSources = null;
});

Просмотреть файл

@ -30,15 +30,15 @@ function test() {
}
function testBlackBox() {
const selectedUrl = gSources.selectedValue;
const selectedActor = gSources.selectedValue;
let finished = waitForSourceShown(gPanel, "blackboxme.js").then(() => {
const newSelectedUrl = gSources.selectedValue;
isnot(selectedUrl, newSelectedUrl,
const newSelectedActor = gSources.selectedValue;
isnot(selectedActor, newSelectedActor,
"Should not have the same url selected.");
return toggleBlackBoxing(gPanel).then(() => {
is(gSources.selectedValue, newSelectedUrl,
is(gSources.selectedValue, newSelectedActor,
"The selected source did not change.");
});
});

Просмотреть файл

@ -18,7 +18,7 @@ function test() {
gSources = gDebugger.DebuggerView.Sources;
gFrames = gDebugger.DebuggerView.StackFrames;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
.then(checkNavigationWhileNotFocused)
.then(focusCurrentStackFrame)
.then(checkNavigationWhileFocused)
@ -31,13 +31,13 @@ function test() {
});
function checkNavigationWhileNotFocused() {
checkState({ frame: 3, source: 1, line: 1 });
checkState({ frame: 1, source: 1, line: 6 });
EventUtils.sendKey("DOWN", gDebugger);
checkState({ frame: 3, source: 1, line: 2 });
checkState({ frame: 1, source: 1, line: 7 });
EventUtils.sendKey("UP", gDebugger);
checkState({ frame: 3, source: 1, line: 1 });
checkState({ frame: 1, source: 1, line: 6 });
}
function focusCurrentStackFrame() {
@ -50,45 +50,37 @@ function test() {
return Task.spawn(function() {
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 2, source: 1, line: 1 });
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 1),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 1, source: 0, line: 1 });
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 5),
waitForEditorLocationSet(gPanel),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 0, source: 0, line: 5 });
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-02.js", 1),
waitForSourceAndCaret(gPanel, "-02.js", 6),
waitForEditorLocationSet(gPanel),
EventUtils.sendKey("END", gDebugger)
]);
checkState({ frame: 3, source: 1, line: 1 });
checkState({ frame: 1, source: 1, line: 6 });
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 1),
waitForSourceAndCaret(gPanel, "-01.js", 5),
waitForEditorLocationSet(gPanel),
EventUtils.sendKey("HOME", gDebugger)
]);
checkState({ frame: 0, source: 0, line: 5 });
});
}
function checkState({ frame, source, line }) {
function checkState({ frame, source, line, column }) {
is(gFrames.selectedIndex, frame,
"The currently selected stackframe is incorrect.");
is(gSources.selectedIndex, source,
"The currently selected source is incorrect.");
ok(isCaretPos(gPanel, line),
ok(isCaretPos(gPanel, line, column),
"The source editor caret position was incorrect.");
}
}

Просмотреть файл

@ -35,7 +35,7 @@ function test() {
"No breakpoints currently shown in the editor.");
gEditor.on("breakpointAdded", onEditorBreakpointAdd);
gPanel.addBreakpoint({ url: gSources.selectedValue, line: 4 }).then(onBreakpointAdd);
gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 4 }).then(onBreakpointAdd);
}
let onBpDebuggerAdd = false;
@ -44,12 +44,12 @@ function test() {
function onBreakpointAdd(aBreakpointClient) {
ok(aBreakpointClient,
"Breakpoint added, client received.");
is(aBreakpointClient.location.url, gSources.selectedValue,
is(aBreakpointClient.location.actor, gSources.selectedValue,
"Breakpoint client url is the same.");
is(aBreakpointClient.location.line, 6,
"Breakpoint client line is new.");
is(aBreakpointClient.requestedLocation.url, gSources.selectedValue,
is(aBreakpointClient.requestedLocation.actor, gSources.selectedValue,
"Requested location url is correct");
is(aBreakpointClient.requestedLocation.line, 4,
"Requested location line is correct");
@ -64,19 +64,19 @@ function test() {
is(gEditor.getBreakpoints().length, 1,
"There is only one breakpoint in the editor");
ok(!gBreakpoints._getAdded({ url: gSources.selectedValue, line: 4 }),
ok(!gBreakpoints._getAdded({ actor: gSources.selectedValue, line: 4 }),
"There isn't any breakpoint added on an invalid line.");
ok(!gBreakpoints._getRemoving({ url: gSources.selectedValue, line: 4 }),
ok(!gBreakpoints._getRemoving({ actor: gSources.selectedValue, line: 4 }),
"There isn't any breakpoint removed from an invalid line.");
ok(gBreakpoints._getAdded({ url: gSources.selectedValue, line: 6 }),
ok(gBreakpoints._getAdded({ actor: gSources.selectedValue, line: 6 }),
"There is a breakpoint added on the actual line.");
ok(!gBreakpoints._getRemoving({ url: gSources.selectedValue, line: 6 }),
ok(!gBreakpoints._getRemoving({ actor: gSources.selectedValue, line: 6 }),
"There isn't any breakpoint removed from the actual line.");
gBreakpoints._getAdded({ url: gSources.selectedValue, line: 6 }).then(aBreakpointClient => {
is(aBreakpointClient.location.url, gSources.selectedValue,
"Breakpoint client location url is correct.");
gBreakpoints._getAdded({ actor: gSources.selectedValue, line: 6 }).then(aBreakpointClient => {
is(aBreakpointClient.location.actor, gSources.selectedValue,
"Breakpoint client location actor is correct.");
is(aBreakpointClient.location.line, 6,
"Breakpoint client location line is correct.");

Просмотреть файл

@ -37,16 +37,16 @@ function test() {
Task.spawn(function*() {
let bpClient = yield gPanel.addBreakpoint({
url: gSources.selectedValue,
actor: gSources.selectedValue,
line: 19
});
yield gPanel.addBreakpoint({
url: gSources.selectedValue,
actor: gSources.selectedValue,
line: 20
});
let movedBpClient = yield gPanel.addBreakpoint({
url: gSources.selectedValue,
actor: gSources.selectedValue,
line: 17
});
testMovedLocation(movedBpClient);
@ -54,7 +54,7 @@ function test() {
yield resumeAndTestBreakpoint(19);
yield gPanel.removeBreakpoint({
url: gSources.selectedValue,
actor: gSources.selectedValue,
line: 19
});
@ -89,12 +89,12 @@ function test() {
function testMovedLocation(breakpointClient) {
ok(breakpointClient,
"Breakpoint added, client received.");
is(breakpointClient.location.url, gSources.selectedValue,
is(breakpointClient.location.actor, gSources.selectedValue,
"Breakpoint client url is the same.");
is(breakpointClient.location.line, 19,
"Breakpoint client line is new.");
is(breakpointClient.requestedLocation.url, gSources.selectedValue,
is(breakpointClient.requestedLocation.actor, gSources.selectedValue,
"Requested location url is correct");
is(breakpointClient.requestedLocation.line, 17,
"Requested location line is correct");

Просмотреть файл

@ -13,13 +13,14 @@ function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
let gPanel, gDebugger, gThreadClient, gEvents;
let gPanel, gDebugger, gThreadClient, gEvents, gSources;
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gThreadClient = gDebugger.gThreadClient;
gEvents = gDebugger.EVENTS;
gSources = gDebugger.DebuggerView.Sources;
Task.spawn(function* () {
try {
@ -92,8 +93,11 @@ function test() {
});
function setBreakpoint(location) {
let item = gSources.getItemByValue(getSourceActor(gSources, location.url));
let source = gThreadClient.source(item.attachment.source);
let deferred = promise.defer();
gThreadClient.setBreakpoint(location, ({ error, message }, bpClient) => {
source.setBreakpoint(location, ({ error, message }, bpClient) => {
if (error) {
deferred.reject(error + ": " + message);
}

Просмотреть файл

@ -31,9 +31,9 @@ function test() {
function addBreakpoints() {
return promise.resolve(null)
.then(() => gPanel.addBreakpoint({ url: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 7 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 7 }))
.then(() => ensureThreadClientState(gPanel, "resumed"));
}

Просмотреть файл

@ -33,16 +33,16 @@ function test() {
function addBreakpoints() {
return promise.resolve(null)
.then(() => gPanel.addBreakpoint({ url: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 7 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 7 }))
.then(() => ensureThreadClientState(gPanel, "resumed"));
}
function disableSomeBreakpoints() {
return promise.all([
gSources.disableBreakpoint({ url: gSources.values[0], line: 5 }),
gSources.disableBreakpoint({ url: gSources.values[1], line: 6 })
gSources.disableBreakpoint({ actor: gSources.values[0], line: 5 }),
gSources.disableBreakpoint({ actor: gSources.values[1], line: 6 })
]);
}

Просмотреть файл

@ -66,7 +66,7 @@ function test() {
"1 breakpoint correctly added");
is(gEditor.getBreakpoints().length, 1,
"1 breakpoint currently shown in the editor.");
ok(gBreakpoints._getAdded({ url: gSources.values[1], line: 7 }),
ok(gBreakpoints._getAdded({ actor: gSources.values[1], line: 7 }),
"Breakpoint on line 7 exists");
});
}
@ -88,7 +88,7 @@ function test() {
"2 breakpoints correctly added");
is(gEditor.getBreakpoints().length, 2,
"2 breakpoints currently shown in the editor.");
ok(gBreakpoints._getAdded({ url: gSources.values[1], line: 8 }),
ok(gBreakpoints._getAdded({ actor: gSources.values[1], line: 8 }),
"Breakpoint on line 8 exists");
});
}

Просмотреть файл

@ -32,11 +32,11 @@ function test() {
function addBreakpoints() {
return promise.resolve(null)
.then(() => gPanel.addBreakpoint({ url: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 7 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 8 }))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 9 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 7 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 8 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 9 }))
.then(() => ensureThreadClientState(gPanel, "resumed"));
}
@ -79,7 +79,8 @@ function test() {
function pauseAndCheck() {
let finished = waitForSourceAndCaretAndScopes(gPanel, "-01.js", 5).then(() => {
is(gSources.selectedValue, EXAMPLE_URL + "code_script-switching-01.js",
let source = gSources.selectedItem.attachment.source;
is(source.url, EXAMPLE_URL + "code_script-switching-01.js",
"The currently selected source is incorrect (3).");
is(gSources.selectedIndex, 0,
"The currently selected source is incorrect (4).");
@ -87,7 +88,8 @@ function test() {
"The editor location is correct after pausing.");
});
is(gSources.selectedValue, EXAMPLE_URL + "code_script-switching-02.js",
let source = gSources.selectedItem.attachment.source;
is(source.url, EXAMPLE_URL + "code_script-switching-02.js",
"The currently selected source is incorrect (1).");
is(gSources.selectedIndex, 1,
"The currently selected source is incorrect (2).");

Просмотреть файл

@ -15,10 +15,12 @@ function test() {
let gEditor = gDebugger.DebuggerView.editor;
let gSources = gDebugger.DebuggerView.Sources;
let gBreakpoints = gDebugger.DebuggerController.Breakpoints;
let gBreakpointLocation = { url: EXAMPLE_URL + "code_script-switching-01.js", line: 5 };
let gBreakpointLocation;
Task.spawn(function() {
yield waitForSourceShown(aPanel, "-01.js");
gBreakpointLocation = { actor: getSourceActor(gSources, EXAMPLE_URL + "code_script-switching-01.js"),
line: 5 };
yield aPanel.addBreakpoint(gBreakpointLocation);
yield ensureThreadClientState(aPanel, "resumed");
@ -102,13 +104,13 @@ function test() {
callInTab(gTab, "firstCall");
yield waitForDebuggerEvents(aPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(aPanel, "-02.js");
yield ensureCaretAt(aPanel, 1);
yield ensureCaretAt(aPanel, 6);
yield verifyView({ disabled: true, visible: false });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForDebuggerEvents(aPanel, gEvents.AFTER_FRAMES_CLEARED);
yield ensureSourceIs(aPanel, "-02.js");
yield ensureCaretAt(aPanel, 1);
yield ensureCaretAt(aPanel, 6);
yield verifyView({ disabled: true, visible: false });
});
}

Просмотреть файл

@ -31,7 +31,7 @@ function test() {
"Should only be getting stack frames while paused.");
is(gSources.itemCount, 2,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("debugger"), 172,
is(gEditor.getText().indexOf("debugger"), 166,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[1],
"The correct source is selected.");
@ -52,7 +52,7 @@ function test() {
"The second source should be currently selected.");
info("Add the first breakpoint.");
let location = { url: gSources.selectedValue, line: 6 };
let location = { actor: gSources.selectedValue, line: 6 };
gEditor.once("breakpointAdded", onEditorBreakpointAddFirst);
gPanel.addBreakpoint(location).then(onBreakpointAddFirst);
}
@ -78,7 +78,7 @@ function test() {
ok(aBreakpointClient,
"breakpoint1 added, client received.");
is(aBreakpointClient.location.url, gSources.selectedValue,
is(aBreakpointClient.location.actor, gSources.selectedValue,
"breakpoint1 client url is correct.");
is(aBreakpointClient.location.line, 6,
"breakpoint1 client line is correct.");
@ -123,7 +123,7 @@ function test() {
ok(aLocation,
"breakpoint1 removed");
is(aLocation.url, gSources.selectedValue,
is(aLocation.actor, gSources.selectedValue,
"breakpoint1 removal url is correct.");
is(aLocation.line, 6,
"breakpoint1 removal line is correct.");
@ -139,16 +139,16 @@ function test() {
is(gEditor.getBreakpoints().length, 0,
"No breakpoints currently shown in the editor.");
ok(!gBreakpoints._getAdded({ url: gSources.selectedValue, line: 6 }),
ok(!gBreakpoints._getAdded({ actor: gSources.selectedValue, line: 6 }),
"_getAdded('gSources.selectedValue', 6) returns falsey.");
ok(!gBreakpoints._getRemoving({ url: gSources.selectedValue, line: 6 }),
ok(!gBreakpoints._getRemoving({ actor: gSources.selectedValue, line: 6 }),
"_getRemoving('gSources.selectedValue', 6) returns falsey.");
is(gSources.values[1], gSources.selectedValue,
"The second source should be currently selected.");
info("Add a breakpoint to the first source, which is not selected.");
let location = { url: gSources.values[0], line: 5 };
let location = { actor: gSources.values[0], line: 5 };
let options = { noEditorUpdate: true };
gEditor.on("breakpointAdded", onEditorBreakpointAddBackgroundTrap);
gPanel.addBreakpoint(location, options).then(onBreakpointAddBackground);
@ -166,7 +166,7 @@ function test() {
ok(aBreakpointClient,
"breakpoint2 added, client received");
is(aBreakpointClient.location.url, gSources.values[0],
is(aBreakpointClient.location.actor, gSources.values[0],
"breakpoint2 client url is correct.");
is(aBreakpointClient.location.line, 5,
"breakpoint2 client line is correct.");
@ -276,19 +276,19 @@ function test() {
is(gEditor.getBreakpoints().length, 0,
"No breakpoints currently shown in the editor.");
ok(!gBreakpoints._getAdded({ url: gSources.values[0], line: 5 }),
ok(!gBreakpoints._getAdded({ actor: gSources.values[0], line: 5 }),
"_getAdded('gSources.values[0]', 5) returns falsey.");
ok(!gBreakpoints._getRemoving({ url: gSources.values[0], line: 5 }),
ok(!gBreakpoints._getRemoving({ actor: gSources.values[0], line: 5 }),
"_getRemoving('gSources.values[0]', 5) returns falsey.");
ok(!gBreakpoints._getAdded({ url: gSources.values[1], line: 6 }),
ok(!gBreakpoints._getAdded({ actor: gSources.values[1], line: 6 }),
"_getAdded('gSources.values[1]', 6) returns falsey.");
ok(!gBreakpoints._getRemoving({ url: gSources.values[1], line: 6 }),
ok(!gBreakpoints._getRemoving({ actor: gSources.values[1], line: 6 }),
"_getRemoving('gSources.values[1]', 6) returns falsey.");
ok(!gBreakpoints._getAdded({ url: "foo", line: 3 }),
ok(!gBreakpoints._getAdded({ actor: "foo", line: 3 }),
"_getAdded('foo', 3) returns falsey.");
ok(!gBreakpoints._getRemoving({ url: "bar", line: 3 }),
ok(!gBreakpoints._getRemoving({ actor: "bar", line: 3 }),
"_getRemoving('bar', 3) returns falsey.");
is(breakpointsAdded, 2,

Просмотреть файл

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test setting breakpoints on an eval script
*/
const TAB_URL = EXAMPLE_URL + "doc_script-eval.html";
function test() {
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints;
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
waitForSourceShown(gPanel, "-eval.js")
.then(run)
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
});
function run() {
return Task.spawn(function*() {
let newSource = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.NEW_SOURCE);
callInTab(gTab, "evalSource");
yield newSource;
yield gPanel.addBreakpoint({ actor: gSources.values[1], line: 2 });
yield ensureThreadClientState(gPanel, "resumed");
const paused = waitForThreadEvents(gPanel, "paused");
callInTab(gTab, "bar");
let frame = (yield paused).frame;
is(frame.where.source.actor, gSources.values[1], "Should have broken on the eval'ed source");
is(frame.where.line, 2, "Should break on line 2");
yield resumeDebuggerThenCloseAndFinish(gPanel);
});
}
}

Просмотреть файл

@ -35,17 +35,17 @@ function test() {
function addBreakpoints() {
return promise.resolve(null)
.then(() => initialChecks(0, 1))
.then(() => gPanel.addBreakpoint({ url: gSources.values[0], line: 5 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[0], line: 5 }))
.then(() => initialChecks(0, 5))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 6 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 6 }))
.then(() => waitForSourceShown(gPanel, "-02.js"))
.then(() => waitForCaretUpdated(gPanel, 6))
.then(() => initialChecks(1, 6))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 7 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 7 }))
.then(() => initialChecks(1, 7))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 8 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 8 }))
.then(() => initialChecks(1, 8))
.then(() => gPanel.addBreakpoint({ url: gSources.values[1], line: 9 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.values[1], line: 9 }))
.then(() => initialChecks(1, 9));
}
@ -80,10 +80,10 @@ function test() {
return finished;
}
function checkHighlight(aUrl, aLine) {
is(gSources._selectedBreakpointItem, gSources.getBreakpoint({ url: aUrl, line: aLine }),
function checkHighlight(aActor, aLine) {
is(gSources._selectedBreakpointItem, gSources.getBreakpoint({ actor: aActor, line: aLine }),
"The currently selected breakpoint item is incorrect.");
is(gSources._selectedBreakpointItem.attachment.url, aUrl,
is(gSources._selectedBreakpointItem.attachment.actor, aActor,
"The selected breakpoint item's source location attachment is incorrect.");
is(gSources._selectedBreakpointItem.attachment.line, aLine,
"The selected breakpoint item's source line number is incorrect.");
@ -96,7 +96,7 @@ function test() {
is(gEditor.getText().indexOf("firstCall"), 118,
"The first source is correctly displayed.");
} else {
is(gEditor.getText().indexOf("debugger"), 172,
is(gEditor.getText().indexOf("debugger"), 166,
"The second source is correctly displayed.");
}
}

Просмотреть файл

@ -8,13 +8,14 @@
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
let gTab, gPanel, gDebugger;
let gTab, gPanel, gDebugger, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
addBreakpoint();
});
@ -27,7 +28,7 @@ function addBreakpoint() {
ok(isCaretPos(gPanel, 16),
"The source editor caret position is incorrect (1).");
gPanel.addBreakpoint({ url: TAB_URL, line: 20 }).then(() => {
gPanel.addBreakpoint({ actor: getSourceActor(gSources, TAB_URL), line: 20 }).then(() => {
testResume();
});
});
@ -83,4 +84,5 @@ registerCleanupFunction(function() {
gTab = null;
gPanel = null;
gDebugger = null;
gSources = null;
});

Просмотреть файл

@ -17,7 +17,7 @@ let test = Task.async(function* () {
const sources = panel1.panelWin.DebuggerView.Sources;
yield panel1.addBreakpoint({
url: sources.selectedValue,
actor: sources.selectedValue,
line: 2
});

Просмотреть файл

@ -35,7 +35,7 @@ function test() {
"Should only be getting stack frames while paused.");
is(gSources.itemCount, 2,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("debugger"), 172,
is(gEditor.getText().indexOf("debugger"), 166,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[1],
"The correct source is selected.");
@ -135,21 +135,21 @@ function test() {
function addBreakpoints(aIncrementFlag) {
let deferred = promise.defer();
gPanel.addBreakpoint({ url: gSources.selectedValue, line: 6 }).then(aClient => {
gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 6 }).then(aClient => {
onBreakpointAdd(aClient, {
increment: aIncrementFlag,
line: 6,
text: "eval(\"debugger;\");"
text: "debugger;"
});
gPanel.addBreakpoint({ url: gSources.selectedValue, line: 7 }).then(aClient => {
gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 7 }).then(aClient => {
onBreakpointAdd(aClient, {
increment: aIncrementFlag,
line: 7,
text: "function foo() {}"
});
gPanel.addBreakpoint({ url: gSources.selectedValue, line: 9 }).then(aClient => {
gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 9 }).then(aClient => {
onBreakpointAdd(aClient, {
increment: aIncrementFlag,
line: 9,

Просмотреть файл

@ -16,9 +16,8 @@ let test = Task.async(function* () {
yield ensureSourceIs(panel, "doc_breakpoints-reload.html", true);
const sources = panel.panelWin.DebuggerView.Sources;
yield panel.addBreakpoint({
url: sources.selectedValue,
actor: sources.selectedValue,
line: 10 // "break on me" string
});
@ -31,5 +30,6 @@ let test = Task.async(function* () {
is(packet.frame.where.line, 10,
"Should have stopped at line 10, where we set the breakpoint");
yield waitForDebuggerEvents(panel, panel.panelWin.EVENTS.SOURCE_SHOWN)
yield resumeDebuggerThenCloseAndFinish(panel);
});

Просмотреть файл

@ -20,11 +20,12 @@ function test() {
}
function testCleanExit() {
waitForSourceAndCaretAndScopes(gPanel, ".html", 16).then(() => {
promise.all([
waitForSourceAndCaretAndScopes(gPanel, ".html", 16),
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED)
]).then(() => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after the debugger statement.");
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_REFILLED);
}).then(() => closeDebuggerAndFinish(gPanel, { whilePaused: true }));
callInTab(gTab, "runDebuggerStatement");

Просмотреть файл

@ -6,14 +6,20 @@
*/
const TAB_URL = EXAMPLE_URL + "doc_cmd-break.html";
let TAB_URL_ACTOR;
function test() {
let gPanel, gDebugger, gThreadClient;
let gPanel, gDebugger, gThreadClient, gSources;
let gLineNumber;
let expectedActorObj = {
value: null,
message: ''
};
helpers.addTabWithToolbar(TAB_URL, aOptions => {
return helpers.audit(aOptions, [
{
return Task.spawn(function() {
yield helpers.audit(aOptions, [{
setup: 'break',
check: {
input: 'break',
@ -21,8 +27,9 @@ function test() {
markup: 'IIIII',
status: 'ERROR',
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break add',
check: {
input: 'break add',
@ -30,8 +37,9 @@ function test() {
markup: 'IIIIIVIII',
status: 'ERROR'
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break add line',
check: {
input: 'break add line',
@ -39,8 +47,9 @@ function test() {
markup: 'VVVVVVVVVVVVVV',
status: 'ERROR'
}
},
{
}]);
yield helpers.audit(aOptions, [{
name: 'open toolbox',
setup: function() {
return initDebugger(gBrowser.selectedTab).then(([aTab, aDebuggee, aPanel]) => {
@ -53,15 +62,19 @@ function test() {
gDebugger = gPanel.panelWin;
gThreadClient = gPanel.panelWin.gThreadClient;
gLineNumber = '' + aOptions.window.wrappedJSObject.gLineNumber;
gSources = gDebugger.DebuggerView.Sources;
expectedActorObj.value = getSourceActor(gSources, TAB_URL);
});
});
},
post: function() {
ok(gThreadClient, "Debugger client exists.");
is(gLineNumber, 1, "gLineNumber is correct.");
is(gLineNumber, 14, "gLineNumber is correct.");
},
},
{
}]);
yield helpers.audit(aOptions, [{
name: 'break add line .../doc_cmd-break.html 14',
setup: function() {
// We have to setup in a function to allow gLineNumber to be initialized.
@ -73,30 +86,32 @@ function test() {
status: 'VALID',
message: '',
args: {
file: { value: TAB_URL, message: '' },
line: { value: 1 }
file: expectedActorObj,
line: { value: 14 }
}
},
exec: {
output: 'Added breakpoint'
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break add line ' + TAB_URL + ' 17',
check: {
hints: '',
status: 'VALID',
message: '',
args: {
file: { value: TAB_URL, message: '' },
file: expectedActorObj,
line: { value: 17 }
}
},
exec: {
output: 'Added breakpoint'
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break list',
check: {
input: 'break list',
@ -107,25 +122,27 @@ function test() {
exec: {
output: [
/Source/, /Remove/,
/doc_cmd-break\.html:1/,
/doc_cmd-break\.html:1/
/doc_cmd-break\.html:14/,
/doc_cmd-break\.html:17/
]
}
},
{
}]);
yield helpers.audit(aOptions, [{
name: 'cleanup',
setup: function() {
let deferred = promise.defer();
gThreadClient.resume(deferred.resolve);
return deferred.promise;
}
},
{
setup: 'break del 1',
}]);
yield helpers.audit(aOptions, [{
setup: 'break del 14',
check: {
input: 'break del 1',
hints: ' -> doc_cmd-break.html:1',
markup: 'VVVVVVVVVVI',
input: 'break del 14',
hints: ' -> doc_cmd-break.html:14',
markup: 'VVVVVVVVVVII',
status: 'ERROR',
args: {
breakpoint: {
@ -134,23 +151,25 @@ function test() {
}
}
}
},
{
setup: 'break del doc_cmd-break.html:1',
}]);
yield helpers.audit(aOptions, [{
setup: 'break del doc_cmd-break.html:14',
check: {
input: 'break del doc_cmd-break.html:1',
input: 'break del doc_cmd-break.html:14',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID',
args: {
breakpoint: { arg: ' doc_cmd-break.html:1' },
breakpoint: { arg: ' doc_cmd-break.html:14' },
}
},
exec: {
output: 'Breakpoint removed'
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break list',
check: {
input: 'break list',
@ -164,8 +183,9 @@ function test() {
/doc_cmd-break\.html:17/
]
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break del doc_cmd-break.html:17',
check: {
input: 'break del doc_cmd-break.html:17',
@ -179,8 +199,9 @@ function test() {
exec: {
output: 'Breakpoint removed'
}
},
{
}]);
yield helpers.audit(aOptions, [{
setup: 'break list',
check: {
input: 'break list',
@ -194,7 +215,7 @@ function test() {
post: function() {
return teardown(gPanel, { noTabRemoval: true });
}
},
]);
}]);
});
}).then(finish);
}

Просмотреть файл

@ -71,31 +71,31 @@ function test() {
function addBreakpoints() {
return promise.resolve(null)
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 18 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 18 }))
.then(aClient => aClient.conditionalExpression = "undefined")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 19 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 19 }))
.then(aClient => aClient.conditionalExpression = "null")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 20 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 20 }))
.then(aClient => aClient.conditionalExpression = "42")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 21 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 21 }))
.then(aClient => aClient.conditionalExpression = "true")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 22 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 22 }))
.then(aClient => aClient.conditionalExpression = "'nasu'")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 23 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 23 }))
.then(aClient => aClient.conditionalExpression = "/regexp/")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 24 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 24 }))
.then(aClient => aClient.conditionalExpression = "({})")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 25 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 25 }))
.then(aClient => aClient.conditionalExpression = "(function() {})")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 26 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 26 }))
.then(aClient => aClient.conditionalExpression = "(function() { return false; })()")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 27 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 27 }))
.then(aClient => aClient.conditionalExpression = "a")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 28 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 28 }))
.then(aClient => aClient.conditionalExpression = "a !== undefined")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 29 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 29 }))
.then(aClient => aClient.conditionalExpression = "b")
.then(() => gPanel.addBreakpoint({ url: gSources.selectedValue, line: 30 }))
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 30 }))
.then(aClient => aClient.conditionalExpression = "a !== null");
}
@ -163,19 +163,21 @@ function test() {
// Highlight the breakpoint only if required.
if (aHighlightBreakpoint) {
let finished = waitForCaretUpdated(gPanel, aLine).then(() => testBreakpoint(aLine));
gSources.highlightBreakpoint({ url: gSources.selectedValue, line: aLine });
gSources.highlightBreakpoint({ actor: gSources.selectedValue, line: aLine });
return finished;
}
let selectedUrl = gSources.selectedValue;
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpointItem;
ok(selectedUrl,
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected breakpoint in the sources pane.");
is(selectedBreakpoint.attachment.url, selectedUrl,
let source = gSources.selectedItem.attachment.source;
is(selectedBreakpoint.attachment.actor, source.actor,
"The breakpoint on line " + aLine + " wasn't added on the correct source.");
is(selectedBreakpoint.attachment.line, aLine,
"The breakpoint on line " + aLine + " wasn't found.");
@ -187,7 +189,7 @@ function test() {
"The breakpoint conditional expression popup should not have been shown.");
return gBreakpoints._getAdded(selectedBreakpoint.attachment).then(aBreakpointClient => {
is(aBreakpointClient.location.url, selectedUrl,
is(aBreakpointClient.location.url, source.url,
"The breakpoint's client url is correct");
is(aBreakpointClient.location.line, aLine,
"The breakpoint's client line is correct");
@ -200,10 +202,10 @@ function test() {
}
function testAfterReload() {
let selectedUrl = gSources.selectedValue;
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpointItem;
ok(selectedUrl,
ok(selectedActor,
"There should be a selected item in the sources pane after reload.");
ok(!selectedBreakpoint,
"There should be no selected breakpoint in the sources pane after reload.");

Просмотреть файл

@ -86,15 +86,15 @@ function test() {
is(gEditor.getBreakpoints().length, 0,
"No breakpoints currently shown in the editor.");
ok(!gBreakpoints._getAdded({ url: "foo", line: 3 }),
ok(!gBreakpoints._getAdded({ actor: "foo", line: 3 }),
"_getAdded('foo', 3) returns falsey.");
ok(!gBreakpoints._getRemoving({ url: "bar", line: 3 }),
ok(!gBreakpoints._getRemoving({ actor: "bar", line: 3 }),
"_getRemoving('bar', 3) returns falsey.");
}
function addBreakpoint1() {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.BREAKPOINT_ADDED);
gPanel.addBreakpoint({ url: gSources.selectedValue, line: 18 });
gPanel.addBreakpoint({ actor: gSources.selectedValue, line: 18 });
return finished;
}
@ -141,15 +141,17 @@ function test() {
}
function testBreakpoint(aLine, aOpenPopupFlag, aPopupVisible, aConditionalExpression) {
let selectedUrl = gSources.selectedValue;
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpointItem;
ok(selectedUrl,
ok(selectedActor,
"There should be a selected item in the sources pane.");
ok(selectedBreakpoint,
"There should be a selected brekapoint in the sources pane.");
"There should be a selected brekapoint in the sources pane.");
is(selectedBreakpoint.attachment.url, selectedUrl,
let source = gSources.selectedItem.attachment.source;
is(selectedBreakpoint.attachment.actor, source.actor,
"The breakpoint on line " + aLine + " wasn't added on the correct source.");
is(selectedBreakpoint.attachment.line, aLine,
"The breakpoint on line " + aLine + " wasn't found.");
@ -161,8 +163,8 @@ function test() {
"The breakpoint on line " + aLine + " should have a correct popup state (2).");
return gBreakpoints._getAdded(selectedBreakpoint.attachment).then(aBreakpointClient => {
is(aBreakpointClient.location.url, selectedUrl,
"The breakpoint's client url is correct");
is(aBreakpointClient.location.actor, selectedActor,
"The breakpoint's client actor is correct");
is(aBreakpointClient.location.line, aLine,
"The breakpoint's client line is correct");
is(aBreakpointClient.conditionalExpression, aConditionalExpression,
@ -176,10 +178,10 @@ function test() {
}
function testNoBreakpoint(aLine) {
let selectedUrl = gSources.selectedValue;
let selectedActor = gSources.selectedValue;
let selectedBreakpoint = gSources._selectedBreakpointItem;
ok(selectedUrl,
ok(selectedActor,
"There should be a selected item in the sources pane for line " + aLine + ".");
ok(!selectedBreakpoint,
"There should be no selected brekapoint in the sources pane for line " + aLine + ".");

Просмотреть файл

@ -23,7 +23,7 @@ function test() {
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
gLocation = { url: gSources.selectedValue, line: 18 };
gLocation = { actor: gSources.selectedValue, line: 18 };
waitForSourceAndCaretAndScopes(gPanel, ".html", 17)
.then(addBreakpoint)

Просмотреть файл

@ -24,7 +24,7 @@ function test() {
var client = gPanel.target.client;
client.mainRoot.traits.conditionalBreakpoints = false;
gLocation = { url: gSources.selectedValue, line: 18 };
gLocation = { actor: gSources.selectedValue, line: 18 };
waitForSourceAndCaretAndScopes(gPanel, ".html", 17)
.then(addBreakpoint)

Просмотреть файл

@ -21,7 +21,7 @@ function test() {
function checkView(frameDepth, selectedSource, caretLine, editorText) {
is(win.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(framesView.itemCount, 4,
is(framesView.itemCount, 2,
"Should have four frames.");
is(framesView.selectedDepth, frameDepth,
"The correct frame is selected in the widget.");
@ -46,8 +46,8 @@ function test() {
}
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 1);
checkView(0, 1, 1, [/secondCall/, 118]);
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 6);
checkView(0, 1, 6, [/secondCall/, 118]);
// Eval in the topmost frame, while paused.
let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
@ -57,13 +57,13 @@ function test() {
is(result.return.class, "Function", "The evaluation return class is correct.");
yield updatedView;
checkView(0, 1, 1, [/secondCall/, 118]);
checkView(0, 1, 6, [/secondCall/, 118]);
ok(true, "Evaluating in the topmost frame works properly.");
// Eval in a different frame, while paused.
updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
try {
yield frames.evaluate("foo", { depth: 3 }); // oldest frame
yield frames.evaluate("foo", { depth: 1 }); // oldest frame
} catch (result) {
is(result.return.type, "object", "The evaluation thrown type is correct.");
is(result.return.class, "Error", "The evaluation thrown class is correct.");
@ -71,7 +71,7 @@ function test() {
}
yield updatedView;
checkView(0, 1, 1, [/secondCall/, 118]);
checkView(0, 1, 6, [/secondCall/, 118]);
ok(true, "Evaluating in a custom frame works properly.");
// Eval in a non-existent frame, while paused.

Просмотреть файл

@ -21,7 +21,7 @@ function test() {
function checkView(selectedFrame, selectedSource, caretLine, editorText) {
is(win.gThreadClient.state, "paused",
"Should only be getting stack frames while paused.");
is(framesView.itemCount, 4,
is(framesView.itemCount, 2,
"Should have four frames.");
is(framesView.selectedDepth, selectedFrame,
"The correct frame is selected in the widget.");
@ -39,14 +39,14 @@ function test() {
// Allow this generator function to yield first.
callInTab(tab, "firstCall");
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 1);
checkView(0, 1, 1, [/secondCall/, 118]);
yield waitForSourceAndCaretAndScopes(panel, "-02.js", 6);
checkView(0, 1, 6, [/secondCall/, 118]);
// Change the selected frame and eval inside it.
let updatedFrame = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
framesView.selectedDepth = 3; // oldest frame
framesView.selectedDepth = 1; // oldest frame
yield updatedFrame;
checkView(3, 0, 5, [/firstCall/, 118]);
checkView(1, 0, 5, [/firstCall/, 118]);
let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
try {
@ -58,7 +58,7 @@ function test() {
}
yield updatedView;
checkView(3, 0, 5, [/firstCall/, 118]);
checkView(1, 0, 5, [/firstCall/, 118]);
ok(true, "Evaluating while in a user-selected frame works properly.");
yield resumeDebuggerThenCloseAndFinish(panel);

Просмотреть файл

@ -28,7 +28,7 @@ function test() {
"Should only be getting stack frames while paused.");
is(gSources.itemCount, 2,
"Found the expected number of sources.");
is(gEditor.getText().indexOf("debugger"), 172,
is(gEditor.getText().indexOf("debugger"), 166,
"The correct source was loaded initially.");
is(gSources.selectedValue, gSources.values[1],
"The correct source is selected.");

Просмотреть файл

@ -40,7 +40,7 @@ function testInitialSource() {
"Found the expected editor mode.");
is(gEditor.getText().search(/firstCall/), -1,
"The first source is not displayed.");
is(gEditor.getText().search(/debugger/), 141,
is(gEditor.getText().search(/debugger/), 135,
"The second source is displayed.");
is(gEditor.getText().search(/banana/), -1,
"The third source is not displayed.");

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше