зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound a=merge
This commit is contained in:
Коммит
6c41020ae8
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1087560 changed a mochitest manifest without touching its moz.build.
|
||||
Bug 1095234 - Bug 1091260 stopped packaging a devtools file with EXTRA_JS_MODULES while making it require pre-processing.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -19,7 +19,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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
|
|
@ -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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -19,7 +19,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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "1380aa2d9459bc1711cb5504c4c806038107428e",
|
||||
"revision": "ce1789cc91feafe53596cfd0360cd12f7cc69d3b",
|
||||
"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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
|
||||
|
|
|
@ -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="1b974ce130eed3988ff5d012c7bd8431c4aba93b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62c9bd93341fbfa8bf850c21e73465708f93b503"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
# TODO Uncomment after Mulet ships with the fonts (bug 1011562).
|
||||
#MOZTTDIR=$topsrcdir/moztt
|
||||
|
|
|
@ -21,4 +21,8 @@ ac_add_options --enable-warnings-as-errors
|
|||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
# TODO Uncomment after Mulet ships with the fonts (bug 1011562).
|
||||
#MOZTTDIR=$topsrcdir/moztt
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
. "$topsrcdir/browser/config/mozconfigs/win32/nightly"
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
# TODO Uncomment after Mulet ships with the fonts (bug 1011562).
|
||||
#MOZTTDIR=$topsrcdir/moztt
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
[
|
||||
{
|
||||
"size": 82,
|
||||
"digest": "70a6126249e40aa1da32248bf6bfe45e0d8c87334579ec0cf69403e61b635e27c766d9bf08d530978286552f158ee24c74b0168a57cc6b734dcfed4fc5e09cff",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 168320,
|
||||
"digest": "c0f4a2da0b07ca6fc69290fbc5ed68f56c6b1ba4d593b220fd49b14ac4885e6ec949e695fd9a7ac464e0e86b652e99f6bd4af849fec072264b29a8f9686d2fc4",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,30 @@
|
|||
[
|
||||
{
|
||||
"clang_version": "r183744"
|
||||
},
|
||||
{
|
||||
"size": 88,
|
||||
"digest": "0d2ae9bcd7cea34ec0b768270725e98410dbb3bc150c7381e0dcf3eb5dbb3e69ac76dbb0f46b056151d6a6fa8681cab06da68173ae8598f3397b8f7628e67381",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 59602619,
|
||||
"digest": "86662ebc0ef650490559005948c4f0cb015dad72c7cac43732c2bf2995247081e30c139cf8008d19670a0009fc302c4eee2676981ee3f9ff4a15c01af22b783b",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 168320,
|
||||
"digest": "c0f4a2da0b07ca6fc69290fbc5ed68f56c6b1ba4d593b220fd49b14ac4885e6ec949e695fd9a7ac464e0e86b652e99f6bd4af849fec072264b29a8f9686d2fc4",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,27 @@
|
|||
[
|
||||
{
|
||||
"size": 266240,
|
||||
"digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
|
||||
"algorithm": "sha512",
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"size": 51,
|
||||
"digest": "c8e40edb314eeabfb92c77cf5ff9a7857033f15dd65a00349bcf9e3e5b75624afc71f733b2ff7e029c20a78313038409c2bd022bf7e5a7e0c487fc2c2d640986",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 168320,
|
||||
"digest": "c0f4a2da0b07ca6fc69290fbc5ed68f56c6b1ba4d593b220fd49b14ac4885e6ec949e695fd9a7ac464e0e86b652e99f6bd4af849fec072264b29a8f9686d2fc4",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
|
@ -1650,7 +1650,7 @@ 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.do_not_disturb", false);
|
||||
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
|
||||
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/ringtone.ogg");
|
||||
pref("loop.retry_delay.start", 60000);
|
||||
pref("loop.retry_delay.limit", 300000);
|
||||
pref("loop.feedback.baseUrl", "https://input.mozilla.org/api/v1/feedback");
|
||||
|
@ -1660,9 +1660,9 @@ pref("loop.debug.dispatcher", false);
|
|||
pref("loop.debug.websocket", false);
|
||||
pref("loop.debug.sdk", false);
|
||||
#ifdef DEBUG
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*");
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
|
||||
#else
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net");
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
|
||||
#endif
|
||||
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
||||
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
||||
|
|
|
@ -787,9 +787,6 @@ statuspanel[inactive][previoustype=overLink] {
|
|||
max-width: 32em;
|
||||
}
|
||||
|
||||
/* highlighter */
|
||||
%include highlighter.css
|
||||
|
||||
/* gcli */
|
||||
|
||||
html|*#gcli-tooltip-frame,
|
||||
|
|
|
@ -4551,15 +4551,14 @@ function nsBrowserAccess() { }
|
|||
nsBrowserAccess.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
|
||||
|
||||
_openURIInNewTab: function(aURI, aOpener, aIsExternal) {
|
||||
_openURIInNewTab: function(aURI, aReferrer, aIsPrivate, aIsExternal) {
|
||||
let win, needToFocusWin;
|
||||
|
||||
// try the current window. if we're in a popup, fall back on the most recent browser window
|
||||
if (window.toolbar.visible)
|
||||
win = window;
|
||||
else {
|
||||
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(aOpener || window);
|
||||
win = RecentWindow.getMostRecentBrowserWindow({private: isPrivate});
|
||||
win = RecentWindow.getMostRecentBrowserWindow({private: aIsPrivate});
|
||||
needToFocusWin = true;
|
||||
}
|
||||
|
||||
|
@ -4575,10 +4574,9 @@ nsBrowserAccess.prototype = {
|
|||
}
|
||||
|
||||
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
|
||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||
|
||||
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
|
||||
referrerURI: referrer,
|
||||
referrerURI: aReferrer,
|
||||
fromExternal: aIsExternal,
|
||||
inBackground: loadInBackground});
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
|
@ -4615,7 +4613,9 @@ nsBrowserAccess.prototype = {
|
|||
newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null);
|
||||
break;
|
||||
case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB :
|
||||
let browser = this._openURIInNewTab(aURI, aOpener, isExternal);
|
||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(aOpener || window);
|
||||
let browser = this._openURIInNewTab(aURI, referrer, isPrivate, isExternal);
|
||||
if (browser)
|
||||
newWindow = browser.contentWindow;
|
||||
break;
|
||||
|
@ -4634,14 +4634,14 @@ nsBrowserAccess.prototype = {
|
|||
return newWindow;
|
||||
},
|
||||
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aOpener, aWhere, aContext) {
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aParams, aWhere, aContext) {
|
||||
if (aWhere != Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
|
||||
dump("Error: openURIInFrame can only open in new tabs");
|
||||
return null;
|
||||
}
|
||||
|
||||
var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
let browser = this._openURIInNewTab(aURI, aOpener, isExternal);
|
||||
let browser = this._openURIInNewTab(aURI, aParams.referrer, aParams.isPrivate, isExternal);
|
||||
if (browser)
|
||||
return browser.QueryInterface(Ci.nsIFrameLoaderOwner);
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ chatBrowserAccess.prototype = {
|
|||
return browser ? browser.contentWindow : null;
|
||||
},
|
||||
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aOpener, aWhere, aContext) {
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aParams, aWhere, aContext) {
|
||||
let browser = this._openURIInNewTab(aURI, aWhere);
|
||||
return browser ? browser.QueryInterface(Ci.nsIFrameLoaderOwner) : null;
|
||||
},
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.highlighter-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Box model highlighter
|
||||
*/
|
||||
svg|svg.box-model-root[hidden],
|
||||
svg|line.box-model-guide-top[hidden],
|
||||
svg|line.box-model-guide-right[hidden],
|
||||
svg|line.box-model-guide-left[hidden],
|
||||
svg|line.box-model-guide-bottom[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Node Infobar
|
||||
*/
|
||||
.highlighter-nodeinfobar-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner {
|
||||
position: absolute;
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[hidden] {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-text {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
html|*.highlighter-nodeinfobar-id,
|
||||
html|*.highlighter-nodeinfobar-classes,
|
||||
html|*.highlighter-nodeinfobar-pseudo-classes,
|
||||
html|*.highlighter-nodeinfobar-dimensions,
|
||||
html|*.highlighter-nodeinfobar-tagname {
|
||||
-moz-user-select: text;
|
||||
-moz-user-focus: normal;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[position="top"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-bottom {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[position="bottom"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-top {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[disabled] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
html|*.highlighter-nodeinfobar-tagname {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
/*
|
||||
* Css transform highlighter
|
||||
*/
|
||||
svg|svg.css-transform-root[hidden] {
|
||||
display: none;
|
||||
}
|
|
@ -74,7 +74,7 @@ Sanitizer.prototype = {
|
|||
itemsToClear.splice(openWindowsIndex, 1);
|
||||
let item = this.items.openWindows;
|
||||
|
||||
function onWindowsCleaned() {
|
||||
let ok = item.clear(() => {
|
||||
try {
|
||||
let clearedPromise = this.sanitize(itemsToClear);
|
||||
clearedPromise.then(deferred.resolve, deferred.reject);
|
||||
|
@ -83,9 +83,7 @@ Sanitizer.prototype = {
|
|||
Cu.reportError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
let ok = item.clear(onWindowsCleaned.bind(this));
|
||||
});
|
||||
// When cancelled, reject immediately
|
||||
if (!ok) {
|
||||
deferred.reject("Sanitizer canceled closing windows");
|
||||
|
|
|
@ -2,6 +2,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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
let chatbar = document.getElementById("pinnedchats");
|
||||
|
||||
add_chat_task(function* testOpenCloseChat() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// Tests the focus functionality.
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/chat.html";
|
||||
|
||||
// Is the currently opened tab focused?
|
||||
|
|
|
@ -2,6 +2,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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
let chatbar = document.getElementById("pinnedchats");
|
||||
|
||||
function promiseNewWindowLoaded() {
|
||||
|
|
|
@ -300,11 +300,11 @@ skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and
|
|||
skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
||||
[browser_bug1064280_changeUrlInPinnedTab.js]
|
||||
[browser_canonizeURL.js]
|
||||
skip-if = e10s # Bug ?????? - [JavaScript Error: "Error in AboutHome.sendAboutHomeData TypeError: target.messageManager is undefined" {file: "resource:///modules/AboutHome.jsm" line: 208}]
|
||||
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
|
||||
[browser_contentAreaClick.js]
|
||||
skip-if = e10s
|
||||
[browser_contextSearchTabPosition.js]
|
||||
skip-if = os == "mac" || e10s # bug 967013, bug 926729
|
||||
skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the network in e10s, causing next test to crash
|
||||
[browser_ctrlTab.js]
|
||||
skip-if = e10s # Bug ????? - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
|
||||
[browser_customize_popupNotification.js]
|
||||
|
|
|
@ -49,6 +49,11 @@ let check_history = Task.async(function*() {
|
|||
}
|
||||
});
|
||||
|
||||
function clear_history() {
|
||||
gExpectedHistory.index = -1;
|
||||
gExpectedHistory.entries = [];
|
||||
}
|
||||
|
||||
// Waits for a load and updates the known history
|
||||
let waitForLoad = Task.async(function*(uri) {
|
||||
info("Loading " + uri);
|
||||
|
@ -63,6 +68,28 @@ let waitForLoad = Task.async(function*(uri) {
|
|||
});
|
||||
});
|
||||
|
||||
// Waits for a load and updates the known history
|
||||
let waitForLoadWithFlags = Task.async(function*(uri, flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE) {
|
||||
info("Loading " + uri + " flags = " + flags);
|
||||
gBrowser.selectedBrowser.loadURIWithFlags(uri, flags, null, null, null);
|
||||
|
||||
yield waitForDocLoadComplete();
|
||||
if (!(flags & Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY)) {
|
||||
|
||||
if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY) {
|
||||
gExpectedHistory.entries.pop();
|
||||
}
|
||||
else {
|
||||
gExpectedHistory.index++;
|
||||
}
|
||||
|
||||
gExpectedHistory.entries.push({
|
||||
uri: gBrowser.currentURI.spec,
|
||||
title: gBrowser.contentTitle
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let back = Task.async(function*() {
|
||||
info("Going back");
|
||||
gBrowser.goBack();
|
||||
|
@ -80,10 +107,7 @@ let forward = Task.async(function*() {
|
|||
// Tests that navigating from a page that should be in the remote process and
|
||||
// a page that should be in the main process works and retains history
|
||||
add_task(function* test_navigation() {
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
|
||||
let expectedRemote = remoting ? "true" : "";
|
||||
let expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
info("1");
|
||||
// Create a tab and load a remote page in it
|
||||
|
@ -154,13 +178,13 @@ add_task(function* test_navigation() {
|
|||
|
||||
info("11");
|
||||
gBrowser.removeCurrentTab();
|
||||
clear_history();
|
||||
});
|
||||
|
||||
// Tests that calling gBrowser.loadURI or browser.loadURI to load a page in a
|
||||
// different process updates the browser synchronously
|
||||
add_task(function* test_synchronous() {
|
||||
let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
|
||||
let expectedRemote = remoting ? "true" : "";
|
||||
let expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
info("1");
|
||||
// Create a tab and load a remote page in it
|
||||
|
@ -194,4 +218,42 @@ add_task(function* test_synchronous() {
|
|||
|
||||
info("4");
|
||||
gBrowser.removeCurrentTab();
|
||||
clear_history();
|
||||
});
|
||||
|
||||
// Tests that load flags are correctly passed through to the child process with
|
||||
// normal loads
|
||||
add_task(function* test_loadflags() {
|
||||
let expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
info("1");
|
||||
// Create a tab and load a remote page in it
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
|
||||
yield waitForLoadWithFlags("about:robots");
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
info("2");
|
||||
// Load a page in the remote process with some custom flags
|
||||
yield waitForLoadWithFlags("http://example.com/" + DUMMY_PATH, Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY);
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
info("3");
|
||||
// Load a non-remote page
|
||||
yield waitForLoadWithFlags("about:robots");
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
info("4");
|
||||
// Load another remote page
|
||||
yield waitForLoadWithFlags("http://example.org/" + DUMMY_PATH, Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY);
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
is(gExpectedHistory.entries.length, 2, "Should end with the right number of history entries");
|
||||
|
||||
info("5");
|
||||
gBrowser.removeCurrentTab();
|
||||
clear_history();
|
||||
});
|
||||
|
|
|
@ -10,11 +10,20 @@
|
|||
* ALL need to match an error in order for that error not to cause a test
|
||||
* failure. */
|
||||
const kWhitelist = [
|
||||
{sourceName: /cleopatra.*(tree|ui)\.css/i}, /* Cleopatra is imported as-is, see bug 1004421 */
|
||||
{sourceName: /codemirror\.css/i}, /* CodeMirror is imported as-is, see bug 1004423 */
|
||||
{sourceName: /web\/viewer\.css/i, errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i }, /* PDFjs is futureproofing its pseudoselectors, and those rules are dropped. */
|
||||
{sourceName: /aboutaccounts\/(main|normalize)\.css/i}, /* Tracked in bug 1004428 */
|
||||
{sourceName: /loop\/.*sdk-content\/.*\.css$/i /* TokBox SDK assets, see bug 1032469 */}
|
||||
// Cleopatra is imported as-is, see bug 1004421.
|
||||
{sourceName: /cleopatra.*(tree|ui)\.css/i},
|
||||
// CodeMirror is imported as-is, see bug 1004423.
|
||||
{sourceName: /codemirror\.css/i},
|
||||
// PDFjs is futureproofing its pseudoselectors, and those rules are dropped.
|
||||
{sourceName: /web\/viewer\.css/i,
|
||||
errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i},
|
||||
// Tracked in bug 1004428.
|
||||
{sourceName: /aboutaccounts\/(main|normalize)\.css/i},
|
||||
// TokBox SDK assets, see bug 1032469.
|
||||
{sourceName: /loop\/.*sdk-content\/.*\.css$/i},
|
||||
// Highlighter CSS uses chrome-only pseudo-class, see bug 985597.
|
||||
{sourceName: /highlighter\.css/i,
|
||||
errorMessage: /Unknown pseudo-class.*moz-native-anonymous/i}
|
||||
];
|
||||
|
||||
let moduleLocation = gTestPath.replace(/\/[^\/]*$/i, "/parsingTestHelpers.jsm");
|
||||
|
|
|
@ -27,7 +27,8 @@ add_task(function testWrapUnwrap() {
|
|||
// Creating and destroying a widget should correctly deal with panel placeholders
|
||||
add_task(function testPanelPlaceholders() {
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 1 : 2, "The number of placeholders should be correct.");
|
||||
let expectedPlaceholders = (isInWin8() ? 1 : 2) + (isInDevEdition() ? 1 : 0);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
|
||||
CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
|
||||
let elem = document.getElementById(kTestWidget2);
|
||||
let wrapper = document.getElementById("wrapper-" + kTestWidget2);
|
||||
|
@ -35,7 +36,8 @@ add_task(function testPanelPlaceholders() {
|
|||
ok(wrapper, "There should be a wrapper");
|
||||
is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
|
||||
is(wrapper.parentNode, panel, "Wrapper should be in panel");
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 3 : 1, "The number of placeholders should be correct.");
|
||||
expectedPlaceholders = (isInWin8() ? 3 : 1) + (isInDevEdition() ? 1 : 0);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
|
||||
CustomizableUI.destroyWidget(kTestWidget2);
|
||||
wrapper = document.getElementById("wrapper-" + kTestWidget2);
|
||||
ok(!wrapper, "There should be a wrapper");
|
||||
|
|
|
@ -18,6 +18,9 @@ XPCOMUtils.defineLazyGetter(this, "eventEmitter", function() {
|
|||
|
||||
this.EXPORTED_SYMBOLS = ["LoopRooms", "roomsPushNotification"];
|
||||
|
||||
// The maximum number of clients that we support currently.
|
||||
const CLIENT_MAX_SIZE = 2;
|
||||
|
||||
const roomsPushNotification = function(version, channelID) {
|
||||
return LoopRoomsInternal.onNotification(version, channelID);
|
||||
};
|
||||
|
@ -271,6 +274,81 @@ let LoopRoomsInternal = {
|
|||
}, error => callback(error)).catch(error => callback(error));
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal function to handle POSTs to a room.
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {Object} postData The data to post to the room.
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
_postToRoom(roomToken, postData, callback) {
|
||||
let url = "/rooms/" + encodeURIComponent(roomToken);
|
||||
MozLoopService.hawkRequest(this.sessionType, url, "POST", postData).then(response => {
|
||||
// Delete doesn't have a body return.
|
||||
var joinData = response.body ? JSON.parse(response.body) : {};
|
||||
callback(null, joinData);
|
||||
}, error => callback(error)).catch(error => callback(error));
|
||||
},
|
||||
|
||||
/**
|
||||
* Joins a room
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
join: function(roomToken, callback) {
|
||||
this._postToRoom(roomToken, {
|
||||
action: "join",
|
||||
displayName: MozLoopService.userProfile.email,
|
||||
clientMaxSize: CLIENT_MAX_SIZE
|
||||
}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes a room
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {String} sessionToken The session token for the session that has been
|
||||
* joined
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
refreshMembership: function(roomToken, sessionToken, callback) {
|
||||
this._postToRoom(roomToken, {
|
||||
action: "refresh",
|
||||
sessionToken: sessionToken
|
||||
}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Leaves a room. Although this is an sync function, no data is returned
|
||||
* from the server.
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {String} sessionToken The session token for the session that has been
|
||||
* joined
|
||||
* @param {Function} callback Optional. Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
leave: function(roomToken, sessionToken, callback) {
|
||||
if (!callback) {
|
||||
callback = function(error) {
|
||||
if (error) {
|
||||
MozLoopService.log.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
this._postToRoom(roomToken, {
|
||||
action: "leave",
|
||||
sessionToken: sessionToken
|
||||
}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback used to indicate changes to rooms data on the LoopServer.
|
||||
|
@ -322,6 +400,19 @@ this.LoopRooms = {
|
|||
return LoopRoomsInternal.delete(roomToken, callback);
|
||||
},
|
||||
|
||||
join: function(roomToken, callback) {
|
||||
return LoopRoomsInternal.join(roomToken, callback);
|
||||
},
|
||||
|
||||
refreshMembership: function(roomToken, sessionToken, callback) {
|
||||
return LoopRoomsInternal.refreshMembership(roomToken, sessionToken,
|
||||
callback);
|
||||
},
|
||||
|
||||
leave: function(roomToken, sessionToken, callback) {
|
||||
return LoopRoomsInternal.leave(roomToken, sessionToken, callback);
|
||||
},
|
||||
|
||||
promise: function(method, ...params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this[method](...params, (error, result) => {
|
||||
|
|
|
@ -13,6 +13,7 @@ Cu.import("resource:///modules/loop/LoopCalls.jsm");
|
|||
Cu.import("resource:///modules/loop/MozLoopService.jsm");
|
||||
Cu.import("resource:///modules/loop/LoopRooms.jsm");
|
||||
Cu.import("resource:///modules/loop/LoopContacts.jsm");
|
||||
Cu.importGlobalProperties(["Blob"]);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
|
||||
"resource:///modules/loop/LoopContacts.jsm");
|
||||
|
@ -685,6 +686,31 @@ function injectLoopAPI(targetWindow) {
|
|||
return MozLoopService.generateUUID();
|
||||
}
|
||||
},
|
||||
|
||||
getAudioBlob: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(name, callback) {
|
||||
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
let url = `chrome://browser/content/loop/shared/sounds/${name}.ogg`;
|
||||
|
||||
request.open("GET", url, true);
|
||||
request.responseType = "arraybuffer";
|
||||
request.onload = () => {
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
let error = new Error(request.status + " " + request.statusText);
|
||||
callback(cloneValueInto(error, targetWindow));
|
||||
return;
|
||||
}
|
||||
|
||||
let blob = new Blob([request.response], {type: "audio/ogg"});
|
||||
callback(null, cloneValueInto(blob, targetWindow));
|
||||
};
|
||||
|
||||
request.send();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onStatusChanged(aSubject, aTopic, aData) {
|
||||
|
|
|
@ -21,7 +21,7 @@ loop.conversation = (function(mozL10n) {
|
|||
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
||||
|
||||
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
model: React.PropTypes.object.isRequired,
|
||||
|
@ -185,10 +185,16 @@ loop.conversation = (function(mozL10n) {
|
|||
* incoming call views (bug 1088672).
|
||||
*/
|
||||
var GenericFailureView = React.createClass({displayName: 'GenericFailureView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
cancelCall: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
|
||||
|
@ -665,7 +671,11 @@ loop.conversation = (function(mozL10n) {
|
|||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
// XXX Move to the conversation models, when we transition
|
||||
// incoming calls to flux (bug 1088672).
|
||||
navigator.mozLoop.calls.clearCallInProgress(windowId);
|
||||
|
||||
dispatcher.dispatch(new sharedActions.WindowUnload());
|
||||
});
|
||||
|
||||
React.renderComponent(AppControllerView({
|
||||
|
|
|
@ -21,7 +21,7 @@ loop.conversation = (function(mozL10n) {
|
|||
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
||||
|
||||
var IncomingCallView = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
model: React.PropTypes.object.isRequired,
|
||||
|
@ -185,10 +185,16 @@ loop.conversation = (function(mozL10n) {
|
|||
* incoming call views (bug 1088672).
|
||||
*/
|
||||
var GenericFailureView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
cancelCall: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
|
||||
|
@ -665,7 +671,11 @@ loop.conversation = (function(mozL10n) {
|
|||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
// XXX Move to the conversation models, when we transition
|
||||
// incoming calls to flux (bug 1088672).
|
||||
navigator.mozLoop.calls.clearCallInProgress(windowId);
|
||||
|
||||
dispatcher.dispatch(new sharedActions.WindowUnload());
|
||||
});
|
||||
|
||||
React.renderComponent(<AppControllerView
|
||||
|
|
|
@ -14,6 +14,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sharedViews = loop.shared.views;
|
||||
var sharedMixins = loop.shared.mixins;
|
||||
|
||||
// This duplicates a similar function in contacts.jsx that isn't used in the
|
||||
// conversation window. If we get too many of these, we might want to consider
|
||||
|
@ -133,6 +134,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* pending/ringing strings.
|
||||
*/
|
||||
var PendingConversationView = React.createClass({displayName: 'PendingConversationView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
callState: React.PropTypes.string,
|
||||
|
@ -146,6 +149,10 @@ loop.conversationViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("ringtone", {loop: true});
|
||||
},
|
||||
|
||||
cancelCall: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
||||
},
|
||||
|
@ -186,7 +193,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* Call failed view. Displayed when a call fails.
|
||||
*/
|
||||
var CallFailedView = React.createClass({displayName: 'CallFailedView',
|
||||
mixins: [Backbone.Events],
|
||||
mixins: [Backbone.Events, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -205,6 +212,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
this.listenTo(this.props.store, "change:emailLink",
|
||||
this._onEmailLinkReceived);
|
||||
this.listenTo(this.props.store, "error:emailLink",
|
||||
|
|
|
@ -14,6 +14,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sharedViews = loop.shared.views;
|
||||
var sharedMixins = loop.shared.mixins;
|
||||
|
||||
// This duplicates a similar function in contacts.jsx that isn't used in the
|
||||
// conversation window. If we get too many of these, we might want to consider
|
||||
|
@ -133,6 +134,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* pending/ringing strings.
|
||||
*/
|
||||
var PendingConversationView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
callState: React.PropTypes.string,
|
||||
|
@ -146,6 +149,10 @@ loop.conversationViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("ringtone", {loop: true});
|
||||
},
|
||||
|
||||
cancelCall: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
||||
},
|
||||
|
@ -186,7 +193,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* Call failed view. Displayed when a call fails.
|
||||
*/
|
||||
var CallFailedView = React.createClass({
|
||||
mixins: [Backbone.Events],
|
||||
mixins: [Backbone.Events, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -205,6 +212,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
this.listenTo(this.props.store, "change:emailLink",
|
||||
this._onEmailLinkReceived);
|
||||
this.listenTo(this.props.store, "error:emailLink",
|
||||
|
|
|
@ -10,6 +10,8 @@ var loop = loop || {};
|
|||
loop.roomViews = (function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var DesktopRoomView = React.createClass({displayName: 'DesktopRoomView',
|
||||
mixins: [Backbone.Events, loop.shared.mixins.DocumentTitleMixin],
|
||||
|
||||
|
@ -19,7 +21,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.roomStore.getStoreState();
|
||||
return this.props.roomStore.getStoreState("activeRoom");
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
|
@ -41,13 +43,28 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the window if the cancel button is pressed in the generic failure view.
|
||||
*/
|
||||
closeWindow: function() {
|
||||
window.close();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.serverData && this.state.serverData.roomName) {
|
||||
this.setTitle(this.state.serverData.roomName);
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
}
|
||||
|
||||
if (this.state.roomState === ROOM_STATES.FAILED) {
|
||||
return (loop.conversation.GenericFailureView({
|
||||
cancelCall: this.closeWindow}
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
React.DOM.div({className: "goat"})
|
||||
React.DOM.div(null,
|
||||
React.DOM.div(null, mozL10n.get("invite_header_text"))
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,6 +10,8 @@ var loop = loop || {};
|
|||
loop.roomViews = (function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var DesktopRoomView = React.createClass({
|
||||
mixins: [Backbone.Events, loop.shared.mixins.DocumentTitleMixin],
|
||||
|
||||
|
@ -19,7 +21,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.roomStore.getStoreState();
|
||||
return this.props.roomStore.getStoreState("activeRoom");
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
|
@ -41,13 +43,28 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the window if the cancel button is pressed in the generic failure view.
|
||||
*/
|
||||
closeWindow: function() {
|
||||
window.close();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.serverData && this.state.serverData.roomName) {
|
||||
this.setTitle(this.state.serverData.roomName);
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
}
|
||||
|
||||
if (this.state.roomState === ROOM_STATES.FAILED) {
|
||||
return (<loop.conversation.GenericFailureView
|
||||
cancelCall={this.closeWindow}
|
||||
/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="goat"/>
|
||||
<div>
|
||||
<div>{mozL10n.get("invite_header_text")}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -67,6 +67,12 @@ loop.shared.actions = (function() {
|
|||
windowType: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Used to signal when the window is being unloaded.
|
||||
*/
|
||||
WindowUnload: Action.define("windowUnload", {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Fetch a new call url from the server, intended to be sent over email when
|
||||
* a contact can't be reached.
|
||||
|
@ -227,6 +233,46 @@ loop.shared.actions = (function() {
|
|||
*/
|
||||
CopyRoomUrl: Action.define("copyRoomUrl", {
|
||||
roomUrl: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
RoomFailure: Action.define("roomFailure", {
|
||||
error: Object
|
||||
}),
|
||||
|
||||
/**
|
||||
* Updates the room information when it is received.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*
|
||||
* @see https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D
|
||||
*/
|
||||
UpdateRoomInfo: Action.define("updateRoomInfo", {
|
||||
roomName: String,
|
||||
roomOwner: String,
|
||||
roomToken: String,
|
||||
roomUrl: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Starts the process for the user to join the room.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
JoinRoom: Action.define("joinRoom", {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Signals the user has successfully joined the room on the loop-server.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*
|
||||
* @see https://wiki.mozilla.org/Loop/Architecture/Rooms#Joining_a_Room
|
||||
*/
|
||||
JoinedRoom: Action.define("joinedRoom", {
|
||||
apiKey: String,
|
||||
sessionToken: String,
|
||||
sessionId: String,
|
||||
expires: Number
|
||||
})
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -11,6 +11,19 @@ loop.store.ActiveRoomStore = (function() {
|
|||
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES = {
|
||||
// The initial state of the room
|
||||
INIT: "room-init",
|
||||
// The store is gathering the room data
|
||||
GATHER: "room-gather",
|
||||
// The store has got the room data
|
||||
READY: "room-ready",
|
||||
// The room is known to be joined on the loop-server
|
||||
JOINED: "room-joined",
|
||||
// There was an issue with the room
|
||||
FAILED: "room-failed"
|
||||
};
|
||||
|
||||
/**
|
||||
* Store for things that are local to this instance (in this profile, on
|
||||
* this machine) of this roomRoom store, in addition to a mirror of some
|
||||
|
@ -29,53 +42,78 @@ loop.store.ActiveRoomStore = (function() {
|
|||
if (!options.dispatcher) {
|
||||
throw new Error("Missing option dispatcher");
|
||||
}
|
||||
this.dispatcher = options.dispatcher;
|
||||
this._dispatcher = options.dispatcher;
|
||||
|
||||
if (!options.mozLoop) {
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this.mozLoop = options.mozLoop;
|
||||
this._mozLoop = options.mozLoop;
|
||||
|
||||
this.dispatcher.register(this, [
|
||||
"setupWindowData"
|
||||
this._dispatcher.register(this, [
|
||||
"roomFailure",
|
||||
"setupWindowData",
|
||||
"updateRoomInfo",
|
||||
"joinRoom",
|
||||
"joinedRoom",
|
||||
"windowUnload"
|
||||
]);
|
||||
}
|
||||
|
||||
ActiveRoomStore.prototype = _.extend({
|
||||
|
||||
/**
|
||||
* Stored data reflecting the local state of a given room, used to drive
|
||||
* the room's views.
|
||||
*
|
||||
* @property {Object} serverData - local cache of the data returned by
|
||||
* MozLoop.getRoomData for this room.
|
||||
* @see https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D
|
||||
* for the main data. Additional properties below.
|
||||
*
|
||||
* @property {ROOM_STATES} roomState - the state of the room.
|
||||
* @property {Error=} error - if the room is an error state, this will be
|
||||
* set to an Error object reflecting the problem;
|
||||
* otherwise it will be unset.
|
||||
*/
|
||||
_storeState: {
|
||||
},
|
||||
this._storeState = {
|
||||
roomState: ROOM_STATES.INIT
|
||||
};
|
||||
}
|
||||
|
||||
ActiveRoomStore.prototype = _.extend({
|
||||
/**
|
||||
* The time factor to adjust the expires time to ensure that we send a refresh
|
||||
* before the expiry. Currently set as 90%.
|
||||
*/
|
||||
expiresTimeFactor: 0.9,
|
||||
|
||||
getStoreState: function() {
|
||||
return this._storeState;
|
||||
},
|
||||
|
||||
setStoreState: function(state) {
|
||||
this._storeState = state;
|
||||
setStoreState: function(newState) {
|
||||
for (var key in newState) {
|
||||
this._storeState[key] = newState[key];
|
||||
}
|
||||
this.trigger("change");
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute setupWindowData event action from the dispatcher. This primes
|
||||
* the store with the roomToken, and calls MozLoop.getRoomData on that
|
||||
* ID. This will return either a reflection of state on the server, or,
|
||||
* if the createRoom call hasn't yet returned, it will have at least the
|
||||
* roomName as specified to the createRoom method.
|
||||
* Handles a room failure. Currently this prints the error to the console
|
||||
* and sets the roomState to failed.
|
||||
*
|
||||
* When the room name gets set, that will trigger the view to display
|
||||
* that name.
|
||||
* @param {sharedActions.RoomFailure} actionData
|
||||
*/
|
||||
roomFailure: function(actionData) {
|
||||
console.error("Error in state `" + this._storeState.roomState + "`:",
|
||||
actionData.error);
|
||||
|
||||
this.setStoreState({
|
||||
error: actionData.error,
|
||||
roomState: ROOM_STATES.FAILED
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute setupWindowData event action from the dispatcher. This gets
|
||||
* the room data from the mozLoop api, and dispatches an UpdateRoomInfo event.
|
||||
* It also dispatches JoinRoom as this action is only applicable to the desktop
|
||||
* client, and needs to auto-join.
|
||||
*
|
||||
* @param {sharedActions.SetupWindowData} actionData
|
||||
*/
|
||||
|
@ -85,14 +123,144 @@ loop.store.ActiveRoomStore = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
this.mozLoop.rooms.get(actionData.roomToken,
|
||||
this.setStoreState({
|
||||
roomState: ROOM_STATES.GATHER
|
||||
});
|
||||
|
||||
// Get the window data from the mozLoop api.
|
||||
this._mozLoop.rooms.get(actionData.roomToken,
|
||||
function(error, roomData) {
|
||||
this.setStoreState({
|
||||
error: error,
|
||||
if (error) {
|
||||
this._dispatcher.dispatch(new sharedActions.RoomFailure({
|
||||
error: error
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatcher.dispatch(
|
||||
new sharedActions.UpdateRoomInfo({
|
||||
roomToken: actionData.roomToken,
|
||||
serverData: roomData
|
||||
});
|
||||
roomName: roomData.roomName,
|
||||
roomOwner: roomData.roomOwner,
|
||||
roomUrl: roomData.roomUrl
|
||||
}));
|
||||
|
||||
// For the conversation window, we need to automatically
|
||||
// join the room.
|
||||
this._dispatcher.dispatch(new sharedActions.JoinRoom());
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the updateRoomInfo action. Updates the room data and
|
||||
* sets the state to `READY`.
|
||||
*
|
||||
* @param {sharedActions.UpdateRoomInfo} actionData
|
||||
*/
|
||||
updateRoomInfo: function(actionData) {
|
||||
this.setStoreState({
|
||||
roomName: actionData.roomName,
|
||||
roomOwner: actionData.roomOwner,
|
||||
roomState: ROOM_STATES.READY,
|
||||
roomToken: actionData.roomToken,
|
||||
roomUrl: actionData.roomUrl
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the action to join to a room.
|
||||
*/
|
||||
joinRoom: function() {
|
||||
this._mozLoop.rooms.join(this._storeState.roomToken,
|
||||
function(error, responseData) {
|
||||
if (error) {
|
||||
this._dispatcher.dispatch(
|
||||
new sharedActions.RoomFailure({error: error}));
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatcher.dispatch(new sharedActions.JoinedRoom({
|
||||
apiKey: responseData.apiKey,
|
||||
sessionToken: responseData.sessionToken,
|
||||
sessionId: responseData.sessionId,
|
||||
expires: responseData.expires
|
||||
}));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the data received from joining a room. It stores the relevant
|
||||
* data, and sets up the refresh timeout for ensuring membership of the room
|
||||
* is refreshed regularly.
|
||||
*
|
||||
* @param {sharedActions.JoinedRoom} actionData
|
||||
*/
|
||||
joinedRoom: function(actionData) {
|
||||
this.setStoreState({
|
||||
apiKey: actionData.apiKey,
|
||||
sessionToken: actionData.sessionToken,
|
||||
sessionId: actionData.sessionId,
|
||||
roomState: ROOM_STATES.JOINED
|
||||
});
|
||||
|
||||
this._setRefreshTimeout(actionData.expires);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the window being unloaded. Ensures the room is left.
|
||||
*/
|
||||
windowUnload: function() {
|
||||
this._leaveRoom();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles setting of the refresh timeout callback.
|
||||
*
|
||||
* @param {Integer} expireTime The time until expiry (in seconds).
|
||||
*/
|
||||
_setRefreshTimeout: function(expireTime) {
|
||||
this._timeout = setTimeout(this._refreshMembership.bind(this),
|
||||
expireTime * this.expiresTimeFactor * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes the membership of the room with the server, and then
|
||||
* sets up the refresh for the next cycle.
|
||||
*/
|
||||
_refreshMembership: function() {
|
||||
this._mozLoop.rooms.refreshMembership(this._storeState.roomToken,
|
||||
this._storeState.sessionToken,
|
||||
function(error, responseData) {
|
||||
if (error) {
|
||||
this._dispatcher.dispatch(
|
||||
new sharedActions.RoomFailure({error: error}));
|
||||
return;
|
||||
}
|
||||
|
||||
this._setRefreshTimeout(responseData.expires);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles leaving a room. Clears any membership timeouts, then
|
||||
* signals to the server the leave of the room.
|
||||
*/
|
||||
_leaveRoom: function() {
|
||||
if (this._storeState.roomState !== ROOM_STATES.JOINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
delete this._timeout;
|
||||
}
|
||||
|
||||
this._mozLoop.rooms.leave(this._storeState.roomToken,
|
||||
this._storeState.sessionToken);
|
||||
|
||||
this.setStoreState({
|
||||
roomState: ROOM_STATES.READY
|
||||
});
|
||||
}
|
||||
|
||||
}, Backbone.Events);
|
||||
|
|
|
@ -141,6 +141,7 @@ loop.shared.mixins = (function() {
|
|||
*/
|
||||
var AudioMixin = {
|
||||
audio: null,
|
||||
_audioRequest: null,
|
||||
|
||||
_isLoopDesktop: function() {
|
||||
return typeof rootObject.navigator.mozLoop === "object";
|
||||
|
@ -149,27 +150,62 @@ loop.shared.mixins = (function() {
|
|||
/**
|
||||
* Starts playing an audio file, stopping any audio that is already in progress.
|
||||
*
|
||||
* @param {String} filename The filename to play (excluding the extension).
|
||||
* @param {String} name The filename to play (excluding the extension).
|
||||
*/
|
||||
play: function(filename, options) {
|
||||
if (this._isLoopDesktop()) {
|
||||
// XXX: We need navigator.mozLoop.playSound(name), see Bug 1089585.
|
||||
return;
|
||||
}
|
||||
|
||||
play: function(name, options) {
|
||||
options = options || {};
|
||||
options.loop = options.loop || false;
|
||||
|
||||
this._ensureAudioStopped();
|
||||
this.audio = new Audio('shared/sounds/' + filename + ".ogg");
|
||||
this.audio.loop = options.loop;
|
||||
this.audio.play();
|
||||
this._getAudioBlob(name, function(error, blob) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var url = URL.createObjectURL(blob);
|
||||
this.audio = new Audio(url);
|
||||
this.audio.loop = options.loop;
|
||||
this.audio.play();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_getAudioBlob: function(name, callback) {
|
||||
if (this._isLoopDesktop()) {
|
||||
rootObject.navigator.mozLoop.getAudioBlob(name, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
var url = "shared/sounds/" + name + ".ogg";
|
||||
this._audioRequest = new XMLHttpRequest();
|
||||
this._audioRequest.open("GET", url, true);
|
||||
this._audioRequest.responseType = "arraybuffer";
|
||||
this._audioRequest.onload = function() {
|
||||
var request = this._audioRequest;
|
||||
var error;
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
error = new Error(request.status + " " + request.statusText);
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var type = request.getResponseHeader("Content-Type");
|
||||
var blob = new Blob([request.response], {type: type});
|
||||
callback(null, blob);
|
||||
}.bind(this);
|
||||
|
||||
this._audioRequest.send(null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures audio is stopped playing, and removes the object from memory.
|
||||
*/
|
||||
_ensureAudioStopped: function() {
|
||||
if (this._audioRequest) {
|
||||
this._audioRequest.abort();
|
||||
delete this._audioRequest;
|
||||
}
|
||||
|
||||
if (this.audio) {
|
||||
this.audio.pause();
|
||||
this.audio.removeAttribute("src");
|
||||
|
|
|
@ -99,10 +99,10 @@ loop.store = loop.store || {};
|
|||
maxRoomCreationSize: 2,
|
||||
|
||||
/**
|
||||
* The number of hours for which the room will exist.
|
||||
* The number of hours for which the room will exist - default 8 weeks
|
||||
* @type {Number}
|
||||
*/
|
||||
defaultExpiresIn: 5,
|
||||
defaultExpiresIn: 24 * 7 * 8,
|
||||
|
||||
/**
|
||||
* Internal store state representation.
|
||||
|
|
|
@ -540,6 +540,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
* Feedback view.
|
||||
*/
|
||||
var FeedbackView = React.createClass({displayName: 'FeedbackView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
// A loop.FeedbackAPIClient instance
|
||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||
|
@ -556,6 +558,10 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
return {step: "start"};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.setState(this.getInitialState());
|
||||
},
|
||||
|
|
|
@ -540,6 +540,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
* Feedback view.
|
||||
*/
|
||||
var FeedbackView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
// A loop.FeedbackAPIClient instance
|
||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||
|
@ -556,6 +558,10 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
return {step: "start"};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.setState(this.getInitialState());
|
||||
},
|
||||
|
|
Двоичные данные
browser/components/loop/content/shared/sounds/Firefox-Long.ogg
Двоичные данные
browser/components/loop/content/shared/sounds/Firefox-Long.ogg
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -81,7 +81,11 @@ browser.jar:
|
|||
content/browser/loop/shared/libs/backbone-1.1.2.js (content/shared/libs/backbone-1.1.2.js)
|
||||
|
||||
# Shared sounds
|
||||
content/browser/loop/shared/sounds/Firefox-Long.ogg (content/shared/sounds/Firefox-Long.ogg)
|
||||
content/browser/loop/shared/sounds/ringtone.ogg (content/shared/sounds/ringtone.ogg)
|
||||
content/browser/loop/shared/sounds/connecting.ogg (content/shared/sounds/connecting.ogg)
|
||||
content/browser/loop/shared/sounds/connected.ogg (content/shared/sounds/connected.ogg)
|
||||
content/browser/loop/shared/sounds/terminated.ogg (content/shared/sounds/terminated.ogg)
|
||||
content/browser/loop/shared/sounds/failure.ogg (content/shared/sounds/failure.ogg)
|
||||
|
||||
# Partner SDK assets
|
||||
content/browser/loop/libs/sdk.js (content/shared/libs/sdk.js)
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<script type="text/javascript" src="shared/js/validate.js"></script>
|
||||
<script type="text/javascript" src="shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="shared/js/websocket.js"></script>
|
||||
<script type="text/javascript" src="shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneAppStore.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneClient.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneRoomViews.js"></script>
|
||||
|
|
|
@ -11,8 +11,42 @@ loop.standaloneRoomViews = (function() {
|
|||
"use strict";
|
||||
|
||||
var StandaloneRoomView = React.createClass({displayName: 'StandaloneRoomView',
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.activeRoomStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.activeRoomStore, "change",
|
||||
this._onActiveRoomStateChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a "change" event on the roomStore, and updates this.state
|
||||
* to match the store.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onActiveRoomStateChanged: function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.activeRoomStore);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (React.DOM.div(null, "Room"));
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
React.DOM.div(null, this.state.roomState)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -11,8 +11,42 @@ loop.standaloneRoomViews = (function() {
|
|||
"use strict";
|
||||
|
||||
var StandaloneRoomView = React.createClass({
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.activeRoomStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.activeRoomStore, "change",
|
||||
this._onActiveRoomStateChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a "change" event on the roomStore, and updates this.state
|
||||
* to match the store.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onActiveRoomStateChanged: function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.activeRoomStore);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (<div>Room</div>);
|
||||
return (
|
||||
<div>
|
||||
<div>{this.state.roomState}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -286,7 +286,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
},
|
||||
|
||||
_handleRingingProgress: function() {
|
||||
this.play("ringing", {loop: true});
|
||||
this.play("ringtone", {loop: true});
|
||||
this.setState({callState: "ringing"});
|
||||
},
|
||||
|
||||
|
@ -534,8 +534,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
* Ended conversation view.
|
||||
*/
|
||||
var EndedConversationView = React.createClass({displayName: 'EndedConversationView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
||||
.isRequired,
|
||||
|
@ -544,10 +542,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("standalone_title_with_status",
|
||||
{clientShortname: mozL10n.get("clientShortname2"),
|
||||
|
@ -897,7 +891,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -939,7 +935,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
);
|
||||
}
|
||||
case "room": {
|
||||
return loop.standaloneRoomViews.StandaloneRoomView(null);
|
||||
return (
|
||||
loop.standaloneRoomViews.StandaloneRoomView({
|
||||
activeRoomStore: this.props.activeRoomStore}
|
||||
)
|
||||
);
|
||||
}
|
||||
case "home": {
|
||||
return HomeView(null);
|
||||
|
@ -989,6 +989,12 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
// XXX Bug 1074702 will introduce a mozLoop compatible object for
|
||||
// the standalone rooms.
|
||||
mozLoop: {}
|
||||
});
|
||||
|
||||
React.renderComponent(WebappRootView({
|
||||
client: client,
|
||||
|
@ -997,7 +1003,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
notifications: notifications,
|
||||
sdk: OT,
|
||||
feedbackApiClient: feedbackApiClient,
|
||||
standaloneAppStore: standaloneAppStore}
|
||||
standaloneAppStore: standaloneAppStore,
|
||||
activeRoomStore: activeRoomStore}
|
||||
), document.querySelector("#main"));
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
|
|
|
@ -286,7 +286,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
},
|
||||
|
||||
_handleRingingProgress: function() {
|
||||
this.play("ringing", {loop: true});
|
||||
this.play("ringtone", {loop: true});
|
||||
this.setState({callState: "ringing"});
|
||||
},
|
||||
|
||||
|
@ -534,8 +534,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
* Ended conversation view.
|
||||
*/
|
||||
var EndedConversationView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
||||
.isRequired,
|
||||
|
@ -544,10 +542,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("standalone_title_with_status",
|
||||
{clientShortname: mozL10n.get("clientShortname2"),
|
||||
|
@ -897,7 +891,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -939,7 +935,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
);
|
||||
}
|
||||
case "room": {
|
||||
return <loop.standaloneRoomViews.StandaloneRoomView/>;
|
||||
return (
|
||||
<loop.standaloneRoomViews.StandaloneRoomView
|
||||
activeRoomStore={this.props.activeRoomStore}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "home": {
|
||||
return <HomeView />;
|
||||
|
@ -989,6 +989,12 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
// XXX Bug 1074702 will introduce a mozLoop compatible object for
|
||||
// the standalone rooms.
|
||||
mozLoop: {}
|
||||
});
|
||||
|
||||
React.renderComponent(<WebappRootView
|
||||
client={client}
|
||||
|
@ -998,6 +1004,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
sdk={OT}
|
||||
feedbackApiClient={feedbackApiClient}
|
||||
standaloneAppStore={standaloneAppStore}
|
||||
activeRoomStore={activeRoomStore}
|
||||
/>, document.querySelector("#main"));
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
|
|
|
@ -7,7 +7,7 @@ describe("loop.conversationViews", function () {
|
|||
"use strict";
|
||||
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sandbox, oldTitle, view, dispatcher, contact;
|
||||
var sandbox, oldTitle, view, dispatcher, contact, fakeAudioXHR;
|
||||
|
||||
var CALL_STATES = loop.store.CALL_STATES;
|
||||
|
||||
|
@ -30,11 +30,39 @@ describe("loop.conversationViews", function () {
|
|||
pref: true
|
||||
}]
|
||||
};
|
||||
fakeAudioXHR = {
|
||||
open: sinon.spy(),
|
||||
send: function() {},
|
||||
abort: function() {},
|
||||
getResponseHeader: function(header) {
|
||||
if (header === "Content-Type")
|
||||
return "audio/ogg";
|
||||
},
|
||||
responseType: null,
|
||||
response: new ArrayBuffer(10),
|
||||
onload: null
|
||||
};
|
||||
|
||||
navigator.mozLoop = {
|
||||
getLoopCharPref: sinon.stub().returns("http://fakeurl"),
|
||||
composeEmail: sinon.spy(),
|
||||
get appVersionInfo() {
|
||||
return {
|
||||
version: "42",
|
||||
channel: "test",
|
||||
platform: "test"
|
||||
};
|
||||
},
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
callback(null, new Blob([new ArrayBuffer(10)], {type: "audio/ogg"}));
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
document.title = oldTitle;
|
||||
view = undefined;
|
||||
delete navigator.mozLoop;
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
|
@ -202,7 +230,7 @@ describe("loop.conversationViews", function () {
|
|||
});
|
||||
|
||||
describe("CallFailedView", function() {
|
||||
var store;
|
||||
var store, fakeAudio;
|
||||
|
||||
function mountTestComponent(props) {
|
||||
return TestUtils.renderIntoDocument(
|
||||
|
@ -219,6 +247,12 @@ describe("loop.conversationViews", function () {
|
|||
client: {},
|
||||
sdkDriver: {}
|
||||
});
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
});
|
||||
|
||||
it("should dispatch a retryCall action when the retry button is pressed",
|
||||
|
@ -306,6 +340,16 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
expect(view.getDOMNode().querySelector(".btn-email").disabled).eql(false);
|
||||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
"failure", sinon.match.func);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("OngoingConversationView", function() {
|
||||
|
@ -412,11 +456,6 @@ describe("loop.conversationViews", function () {
|
|||
}
|
||||
|
||||
beforeEach(function() {
|
||||
navigator.mozLoop = {
|
||||
getLoopCharPref: function() { return "fake"; },
|
||||
appVersionInfo: sinon.spy()
|
||||
};
|
||||
|
||||
store = new loop.store.ConversationStore({}, {
|
||||
dispatcher: dispatcher,
|
||||
client: {},
|
||||
|
@ -424,10 +463,6 @@ describe("loop.conversationViews", function () {
|
|||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
delete navigator.mozLoop;
|
||||
});
|
||||
|
||||
it("should render the CallFailedView when the call state is 'terminated'",
|
||||
function() {
|
||||
store.set({callState: CALL_STATES.TERMINATED});
|
||||
|
|
|
@ -57,7 +57,10 @@ describe("loop.conversation", function() {
|
|||
channel: "test",
|
||||
platform: "test"
|
||||
};
|
||||
}
|
||||
},
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
callback(null, new Blob([new ArrayBuffer(10)], {type: 'audio/ogg'}));
|
||||
})
|
||||
};
|
||||
|
||||
// XXX These stubs should be hoisted in a common file
|
||||
|
@ -690,8 +693,8 @@ describe("loop.conversation", function() {
|
|||
function() {
|
||||
conversation.trigger("session:network-disconnected");
|
||||
|
||||
TestUtils.findRenderedComponentWithType(icView,
|
||||
loop.conversation.GenericFailureView);
|
||||
TestUtils.findRenderedComponentWithType(icView,
|
||||
loop.conversation.GenericFailureView);
|
||||
});
|
||||
|
||||
it("should update the conversation window toolbar title",
|
||||
|
@ -747,7 +750,7 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
|
||||
describe("IncomingCallView", function() {
|
||||
var view, model;
|
||||
var view, model, fakeAudio;
|
||||
|
||||
beforeEach(function() {
|
||||
var Model = Backbone.Model.extend({
|
||||
|
@ -757,6 +760,13 @@ describe("loop.conversation", function() {
|
|||
sandbox.spy(model, "trigger");
|
||||
sandbox.stub(model, "set");
|
||||
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
|
||||
view = TestUtils.renderIntoDocument(loop.conversation.IncomingCallView({
|
||||
model: model,
|
||||
video: true
|
||||
|
@ -896,4 +906,32 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GenericFailureView", function() {
|
||||
var view, fakeAudio;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
|
||||
view = TestUtils.renderIntoDocument(
|
||||
loop.conversation.GenericFailureView({
|
||||
cancelCall: function() {}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
"failure", sinon.match.func);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(false);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,17 +3,32 @@ var expect = chai.expect;
|
|||
describe("loop.roomViews", function () {
|
||||
"use strict";
|
||||
|
||||
var sandbox, dispatcher, roomStore, activeRoomStore, fakeWindow, fakeMozLoop,
|
||||
fakeRoomId;
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var sandbox, dispatcher, roomStore, activeRoomStore, fakeWindow;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
|
||||
fakeWindow = { document: {} };
|
||||
fakeWindow = {
|
||||
document: {},
|
||||
navigator: {
|
||||
mozLoop: {
|
||||
getAudioBlob: sinon.stub()
|
||||
}
|
||||
}
|
||||
};
|
||||
loop.shared.mixins.setRootObject(fakeWindow);
|
||||
|
||||
// XXX These stubs should be hoisted in a common file
|
||||
// Bug 1040968
|
||||
sandbox.stub(document.mozL10n, "get", function(x) {
|
||||
return x;
|
||||
});
|
||||
|
||||
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {}
|
||||
|
@ -26,11 +41,13 @@ describe("loop.roomViews", function () {
|
|||
});
|
||||
|
||||
afterEach(function() {
|
||||
sinon.sandbox.restore();
|
||||
sandbox.restore();
|
||||
loop.shared.mixins.setRootObject(window);
|
||||
});
|
||||
|
||||
describe("DesktopRoomView", function() {
|
||||
var view;
|
||||
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
new loop.roomViews.DesktopRoomView({
|
||||
|
@ -43,10 +60,22 @@ describe("loop.roomViews", function () {
|
|||
it("should set document.title to store.serverData.roomName", function() {
|
||||
mountTestComponent();
|
||||
|
||||
activeRoomStore.setStoreState({serverData: {roomName: "fakeName"}});
|
||||
activeRoomStore.setStoreState({roomName: "fakeName"});
|
||||
|
||||
expect(fakeWindow.document.title).to.equal("fakeName");
|
||||
});
|
||||
|
||||
it("should render the GenericFailureView if the roomState is `FAILED`", function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.FAILED});
|
||||
|
||||
view = mountTestComponent();
|
||||
|
||||
TestUtils.findRenderedComponentWithType(view,
|
||||
loop.conversation.GenericFailureView);
|
||||
});
|
||||
|
||||
// XXX Implement this when we do the rooms views in bug 1074686 and others.
|
||||
it("should display the main view");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_appVersionInfo() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_doNotDisturb() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_pluralStrings() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_charPref() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
/*
|
||||
* This file contains tests for the mozLoop telemetry API.
|
||||
*/
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
registerCleanupFunction(function*() {
|
||||
MozLoopService.doNotDisturb = false;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
|
|
|
@ -6,11 +6,27 @@ var sharedActions = loop.shared.actions;
|
|||
describe("loop.store.ActiveRoomStore", function () {
|
||||
"use strict";
|
||||
|
||||
var sandbox, dispatcher;
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
var sandbox, dispatcher, store, fakeMozLoop;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.useFakeTimers();
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
fakeMozLoop = {
|
||||
rooms: {
|
||||
get: sandbox.stub(),
|
||||
join: sandbox.stub(),
|
||||
refreshMembership: sandbox.stub(),
|
||||
leave: sandbox.stub()
|
||||
}
|
||||
};
|
||||
|
||||
store = new loop.store.ActiveRoomStore(
|
||||
{mozLoop: fakeMozLoop, dispatcher: dispatcher});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
@ -31,73 +47,96 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#roomFailure", function() {
|
||||
var fakeError;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(console, "error");
|
||||
|
||||
fakeError = new Error("fake");
|
||||
|
||||
store.setStoreState({
|
||||
roomState: ROOM_STATES.READY
|
||||
});
|
||||
});
|
||||
|
||||
it("should log the error", function() {
|
||||
store.roomFailure({error: fakeError});
|
||||
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error,
|
||||
sinon.match(ROOM_STATES.READY), fakeError);
|
||||
});
|
||||
|
||||
it("should set the state to `FAILED`", function() {
|
||||
store.roomFailure({error: fakeError});
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.FAILED);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#setupWindowData", function() {
|
||||
var store, fakeMozLoop, fakeToken, fakeRoomName;
|
||||
var fakeToken, fakeRoomData;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeToken = "337-ff-54";
|
||||
fakeRoomName = "Monkeys";
|
||||
fakeMozLoop = {
|
||||
rooms: { get: sandbox.stub() }
|
||||
fakeRoomData = {
|
||||
roomName: "Monkeys",
|
||||
roomOwner: "Alfred",
|
||||
roomUrl: "http://invalid"
|
||||
};
|
||||
|
||||
store = new loop.store.ActiveRoomStore(
|
||||
{mozLoop: fakeMozLoop, dispatcher: dispatcher});
|
||||
fakeMozLoop.rooms.get.
|
||||
withArgs(fakeToken).
|
||||
callsArgOnWith(1, // index of callback argument
|
||||
store, // |this| to call it on
|
||||
null, // args to call the callback with...
|
||||
{roomName: fakeRoomName}
|
||||
fakeRoomData
|
||||
);
|
||||
});
|
||||
|
||||
it("should trigger a change event", function(done) {
|
||||
store.on("change", function() {
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
});
|
||||
|
||||
it("should set roomToken on the store from the action data",
|
||||
function(done) {
|
||||
|
||||
store.once("change", function () {
|
||||
expect(store.getStoreState()).
|
||||
to.have.property('roomToken', fakeToken);
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
it("should set the state to `GATHER`",
|
||||
function() {
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
|
||||
expect(store.getStoreState()).
|
||||
to.have.property('roomState', ROOM_STATES.GATHER);
|
||||
});
|
||||
|
||||
it("should set serverData.roomName from the getRoomData callback",
|
||||
function(done) {
|
||||
|
||||
store.once("change", function () {
|
||||
expect(store.getStoreState()).to.have.deep.property(
|
||||
'serverData.roomName', fakeRoomName);
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
it("should dispatch an UpdateRoomInfo action if the get is successful",
|
||||
function() {
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
|
||||
sinon.assert.calledTwice(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.UpdateRoomInfo(_.extend({
|
||||
roomToken: fakeToken
|
||||
}, fakeRoomData)));
|
||||
});
|
||||
|
||||
it("should set error on the store when getRoomData calls back an error",
|
||||
function(done) {
|
||||
it("should dispatch a JoinRoom action if the get is successful",
|
||||
function() {
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
|
||||
sinon.assert.calledTwice(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.JoinRoom());
|
||||
});
|
||||
|
||||
it("should dispatch a RoomFailure action if the get fails",
|
||||
function() {
|
||||
|
||||
var fakeError = new Error("fake error");
|
||||
fakeMozLoop.rooms.get.
|
||||
|
@ -106,17 +145,201 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
store, // |this| to call it on
|
||||
fakeError); // args to call the callback with...
|
||||
|
||||
store.once("change", function() {
|
||||
expect(this.getStoreState()).to.have.property('error', fakeError);
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.RoomFailure({
|
||||
error: fakeError
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#updateRoomInfo", function() {
|
||||
var fakeRoomInfo;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeRoomInfo = {
|
||||
roomName: "Its a room",
|
||||
roomOwner: "Me",
|
||||
roomToken: "fakeToken",
|
||||
roomUrl: "http://invalid"
|
||||
};
|
||||
});
|
||||
|
||||
it("should set the state to READY", function() {
|
||||
store.updateRoomInfo(fakeRoomInfo);
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.READY);
|
||||
});
|
||||
|
||||
it("should save the room information", function() {
|
||||
store.updateRoomInfo(fakeRoomInfo);
|
||||
|
||||
var state = store.getStoreState();
|
||||
expect(state.roomName).eql(fakeRoomInfo.roomName);
|
||||
expect(state.roomOwner).eql(fakeRoomInfo.roomOwner);
|
||||
expect(state.roomToken).eql(fakeRoomInfo.roomToken);
|
||||
expect(state.roomUrl).eql(fakeRoomInfo.roomUrl);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#joinRoom", function() {
|
||||
beforeEach(function() {
|
||||
store.setStoreState({roomToken: "tokenFake"});
|
||||
});
|
||||
|
||||
it("should call rooms.join on mozLoop", function() {
|
||||
store.joinRoom();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.join);
|
||||
sinon.assert.calledWith(fakeMozLoop.rooms.join, "tokenFake");
|
||||
});
|
||||
|
||||
it("should dispatch `JoinedRoom` on success", function() {
|
||||
var responseData = {
|
||||
apiKey: "keyFake",
|
||||
sessionToken: "14327659860",
|
||||
sessionId: "1357924680",
|
||||
expires: 8
|
||||
};
|
||||
|
||||
fakeMozLoop.rooms.join.callsArgWith(1, null, responseData);
|
||||
|
||||
store.joinRoom();
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.JoinedRoom(responseData));
|
||||
});
|
||||
|
||||
it("should dispatch `RoomFailure` on error", function() {
|
||||
var fakeError = new Error("fake");
|
||||
|
||||
fakeMozLoop.rooms.join.callsArgWith(1, fakeError);
|
||||
|
||||
store.joinRoom();
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.RoomFailure({error: fakeError}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#joinedRoom", function() {
|
||||
var fakeJoinedData;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeJoinedData = {
|
||||
apiKey: "9876543210",
|
||||
sessionToken: "12563478",
|
||||
sessionId: "15263748",
|
||||
expires: 20
|
||||
};
|
||||
|
||||
store.setStoreState({
|
||||
roomToken: "fakeToken"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the state to `JOINED`", function() {
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.JOINED);
|
||||
});
|
||||
|
||||
it("should store the session and api values", function() {
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
var state = store.getStoreState();
|
||||
expect(state.apiKey).eql(fakeJoinedData.apiKey);
|
||||
expect(state.sessionToken).eql(fakeJoinedData.sessionToken);
|
||||
expect(state.sessionId).eql(fakeJoinedData.sessionId);
|
||||
});
|
||||
|
||||
it("should call mozLoop.rooms.refreshMembership before the expiresTime",
|
||||
function() {
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
sandbox.clock.tick(fakeJoinedData.expires * 1000);
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.refreshMembership);
|
||||
sinon.assert.calledWith(fakeMozLoop.rooms.refreshMembership,
|
||||
"fakeToken", "12563478");
|
||||
});
|
||||
|
||||
it("should call mozLoop.rooms.refreshMembership before the next expiresTime",
|
||||
function() {
|
||||
fakeMozLoop.rooms.refreshMembership.callsArgWith(2,
|
||||
null, {expires: 40});
|
||||
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
// Clock tick for the first expiry time (which
|
||||
// sets up the refreshMembership).
|
||||
sandbox.clock.tick(fakeJoinedData.expires * 1000);
|
||||
|
||||
// Clock tick for expiry time in the refresh membership response.
|
||||
sandbox.clock.tick(40000);
|
||||
|
||||
sinon.assert.calledTwice(fakeMozLoop.rooms.refreshMembership);
|
||||
sinon.assert.calledWith(fakeMozLoop.rooms.refreshMembership,
|
||||
"fakeToken", "12563478");
|
||||
});
|
||||
|
||||
it("should dispatch `RoomFailure` if the refreshMembership call failed",
|
||||
function() {
|
||||
var fakeError = new Error("fake");
|
||||
fakeMozLoop.rooms.refreshMembership.callsArgWith(2, fakeError);
|
||||
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
// Clock tick for the first expiry time (which
|
||||
// sets up the refreshMembership).
|
||||
sandbox.clock.tick(fakeJoinedData.expires * 1000);
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.RoomFailure({
|
||||
error: fakeError
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#windowUnload", function() {
|
||||
beforeEach(function() {
|
||||
store.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomToken: "fakeToken",
|
||||
sessionToken: "1627384950"
|
||||
});
|
||||
});
|
||||
|
||||
it("should clear any existing timeout", function() {
|
||||
sandbox.stub(window, "clearTimeout");
|
||||
store._timeout = {};
|
||||
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(clearTimeout);
|
||||
});
|
||||
|
||||
it("should call mozLoop.rooms.leave", function() {
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.leave);
|
||||
sinon.assert.calledWithExactly(fakeMozLoop.rooms.leave,
|
||||
"fakeToken", "1627384950");
|
||||
});
|
||||
|
||||
it("should set the state to ready", function() {
|
||||
store.windowUnload();
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.READY);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,7 +15,7 @@ describe("loop.shared.views", function() {
|
|||
var sharedModels = loop.shared.models,
|
||||
sharedViews = loop.shared.views,
|
||||
getReactElementByClass = TestUtils.findRenderedDOMComponentWithClass,
|
||||
sandbox;
|
||||
sandbox, fakeAudioXHR;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
@ -23,6 +23,18 @@ describe("loop.shared.views", function() {
|
|||
sandbox.stub(l10n, "get", function(x) {
|
||||
return "translated:" + x;
|
||||
});
|
||||
fakeAudioXHR = {
|
||||
open: sinon.spy(),
|
||||
send: function() {},
|
||||
abort: function() {},
|
||||
getResponseHeader: function(header) {
|
||||
if (header === "Content-Type")
|
||||
return "audio/ogg";
|
||||
},
|
||||
responseType: null,
|
||||
response: new ArrayBuffer(10),
|
||||
onload: null
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
@ -368,16 +380,55 @@ describe("loop.shared.views", function() {
|
|||
|
||||
it("should play a connected sound, once, on session:connected",
|
||||
function() {
|
||||
var url = "shared/sounds/connected.ogg";
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
model.trigger("session:connected");
|
||||
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(
|
||||
window.Audio, "shared/sounds/connected.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(fakeAudioXHR.open, "GET", url, true);
|
||||
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.not.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("for desktop", function() {
|
||||
var origMozLoop;
|
||||
|
||||
beforeEach(function() {
|
||||
origMozLoop = navigator.mozLoop;
|
||||
navigator.mozLoop = {
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
var data = new ArrayBuffer(10);
|
||||
callback(null, new Blob([data], {type: "audio/ogg"}));
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
navigator.mozLoop = origMozLoop;
|
||||
});
|
||||
|
||||
it("should play a connected sound, once, on session:connected",
|
||||
function() {
|
||||
var url = "chrome://browser/content/loop/shared/sounds/connected.ogg";
|
||||
model.trigger("session:connected");
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
"connected", sinon.match.func);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.not.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("for both (standalone and desktop)", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
});
|
||||
|
||||
it("should start streaming on session:connected", function() {
|
||||
model.trigger("session:connected");
|
||||
|
||||
|
@ -458,6 +509,7 @@ describe("loop.shared.views", function() {
|
|||
|
||||
beforeEach(function() {
|
||||
fakeFeedbackApiClient = {send: sandbox.stub()};
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
comp = TestUtils.renderIntoDocument(sharedViews.FeedbackView({
|
||||
feedbackApiClient: fakeFeedbackApiClient
|
||||
}));
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<script src="../../content/shared/js/actions.js"></script>
|
||||
<script src="../../content/shared/js/validate.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../standalone/content/js/multiplexGum.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneAppStore.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneClient.js"></script>
|
||||
|
|
|
@ -18,7 +18,8 @@ describe("loop.webapp", function() {
|
|||
sandbox,
|
||||
notifications,
|
||||
feedbackApiClient,
|
||||
stubGetPermsAndCacheMedia;
|
||||
stubGetPermsAndCacheMedia,
|
||||
fakeAudioXHR;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
@ -29,6 +30,19 @@ describe("loop.webapp", function() {
|
|||
|
||||
stubGetPermsAndCacheMedia = sandbox.stub(
|
||||
loop.standaloneMedia._MultiplexGum.prototype, "getPermsAndCacheMedia");
|
||||
|
||||
fakeAudioXHR = {
|
||||
open: sinon.spy(),
|
||||
send: function() {},
|
||||
abort: function() {},
|
||||
getResponseHeader: function(header) {
|
||||
if (header === "Content-Type")
|
||||
return "audio/ogg";
|
||||
},
|
||||
responseType: null,
|
||||
response: new ArrayBuffer(10),
|
||||
onload: null
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
@ -219,6 +233,7 @@ describe("loop.webapp", function() {
|
|||
describe("state: terminate, reason: reject", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(notifications, "errorL10n");
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
});
|
||||
|
||||
it("should display the FailedConversationView", function() {
|
||||
|
@ -307,6 +322,7 @@ describe("loop.webapp", function() {
|
|||
promiseConnectStub =
|
||||
sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect");
|
||||
promiseConnectStub.returns(new Promise(function(resolve, reject) {}));
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
});
|
||||
|
||||
describe("call:outgoing", function() {
|
||||
|
@ -526,6 +542,8 @@ describe("loop.webapp", function() {
|
|||
var view, conversation, client, fakeAudio;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
|
@ -541,6 +559,7 @@ describe("loop.webapp", function() {
|
|||
});
|
||||
conversation.set("loopToken", "fakeToken");
|
||||
|
||||
sandbox.stub(client, "requestCallUrlInfo");
|
||||
view = React.addons.TestUtils.renderIntoDocument(
|
||||
loop.webapp.FailedConversationView({
|
||||
conversation: conversation,
|
||||
|
@ -550,9 +569,12 @@ describe("loop.webapp", function() {
|
|||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(window.Audio,
|
||||
"shared/sounds/failure.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/failure.ogg", true);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
@ -560,7 +582,7 @@ describe("loop.webapp", function() {
|
|||
|
||||
describe("WebappRootView", function() {
|
||||
var helper, sdk, conversationModel, client, props, standaloneAppStore;
|
||||
var dispatcher;
|
||||
var dispatcher, activeRoomStore;
|
||||
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
|
@ -571,7 +593,8 @@ describe("loop.webapp", function() {
|
|||
sdk: sdk,
|
||||
conversation: conversationModel,
|
||||
feedbackApiClient: feedbackApiClient,
|
||||
standaloneAppStore: standaloneAppStore
|
||||
standaloneAppStore: standaloneAppStore,
|
||||
activeRoomStore: activeRoomStore
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -587,6 +610,10 @@ describe("loop.webapp", function() {
|
|||
baseServerUrl: "fakeUrl"
|
||||
});
|
||||
dispatcher = new loop.Dispatcher();
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {}
|
||||
});
|
||||
standaloneAppStore = new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
sdk: sdk,
|
||||
|
@ -678,6 +705,7 @@ describe("loop.webapp", function() {
|
|||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
|
||||
view = React.addons.TestUtils.renderIntoDocument(
|
||||
loop.webapp.PendingConversationView({
|
||||
|
@ -689,8 +717,12 @@ describe("loop.webapp", function() {
|
|||
describe("#componentDidMount", function() {
|
||||
|
||||
it("should play a looped connecting sound", function() {
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/connecting.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/connecting.ogg", true);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(true);
|
||||
});
|
||||
|
||||
|
@ -727,8 +759,13 @@ describe("loop.webapp", function() {
|
|||
|
||||
it("should play a looped ringing sound", function() {
|
||||
websocket.trigger("progress:alerting");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/ringing.ogg");
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/ringtone.ogg", true);
|
||||
|
||||
sinon.assert.called(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
@ -997,6 +1034,7 @@ describe("loop.webapp", function() {
|
|||
conversation = new sharedModels.ConversationModel({}, {
|
||||
sdk: {}
|
||||
});
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
view = React.addons.TestUtils.renderIntoDocument(
|
||||
loop.webapp.EndedConversationView({
|
||||
conversation: conversation,
|
||||
|
@ -1018,8 +1056,13 @@ describe("loop.webapp", function() {
|
|||
describe("#componentDidMount", function() {
|
||||
|
||||
it("should play a terminating sound, once", function() {
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/terminated.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/terminated.ogg", true);
|
||||
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.not.equal(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -212,7 +212,16 @@ add_task(function* setup_server() {
|
|||
// Add a request handler for each room in the list.
|
||||
[...kRooms.values()].forEach(function(room) {
|
||||
loopServer.registerPathHandler("/rooms/" + encodeURIComponent(room.roomToken), (req, res) => {
|
||||
returnRoomDetails(res, room.roomName);
|
||||
if (req.method == "POST") {
|
||||
let body = CommonUtils.readBytesFromInputStream(req.bodyInputStream);
|
||||
let data = JSON.parse(body);
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write(JSON.stringify(data));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
} else {
|
||||
returnRoomDetails(res, room.roomName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -321,6 +330,39 @@ add_task(function* test_roomUpdates() {
|
|||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedJoins).length === 0);
|
||||
});
|
||||
|
||||
// Test if joining a room works as expected.
|
||||
add_task(function* test_joinRoom() {
|
||||
// We need these set up for getting the email address.
|
||||
Services.prefs.setCharPref("loop.fxa_oauth.profile", JSON.stringify({
|
||||
email: "fake@invalid.com"
|
||||
}));
|
||||
Services.prefs.setCharPref("loop.fxa_oauth.tokendata", JSON.stringify({
|
||||
token_type: "bearer"
|
||||
}));
|
||||
|
||||
let roomToken = "_nxD4V4FflQ";
|
||||
let joinedData = yield LoopRooms.promise("join", roomToken);
|
||||
Assert.equal(joinedData.action, "join");
|
||||
Assert.equal(joinedData.displayName, "fake@invalid.com");
|
||||
});
|
||||
|
||||
// Test if refreshing a room works as expected.
|
||||
add_task(function* test_refreshMembership() {
|
||||
let roomToken = "_nxD4V4FflQ";
|
||||
let refreshedData = yield LoopRooms.promise("refreshMembership", roomToken,
|
||||
"fakeSessionToken");
|
||||
Assert.equal(refreshedData.action, "refresh");
|
||||
Assert.equal(refreshedData.sessionToken, "fakeSessionToken");
|
||||
});
|
||||
|
||||
// Test if leaving a room works as expected.
|
||||
add_task(function* test_leaveRoom() {
|
||||
let roomToken = "_nxD4V4FflQ";
|
||||
let leaveData = yield LoopRooms.promise("leave", roomToken, "fakeLeaveSessionToken");
|
||||
Assert.equal(leaveData.action, "leave");
|
||||
Assert.equal(leaveData.sessionToken, "fakeLeaveSessionToken");
|
||||
});
|
||||
|
||||
// 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");
|
||||
|
@ -339,6 +381,9 @@ function run_test() {
|
|||
// Revert original Chat.open implementation
|
||||
Chat.open = openChatOrig;
|
||||
|
||||
Services.prefs.clearUserPref("loop.fxa_oauth.profile");
|
||||
Services.prefs.clearUserPref("loop.fxa_oauth.tokendata");
|
||||
|
||||
LoopRooms.off("add", onRoomAdded);
|
||||
LoopRooms.off("update", onRoomUpdated);
|
||||
LoopRooms.off("joined", onRoomJoined);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// This test makes sure that the URL bar is focused when entering the private window.
|
||||
|
||||
"use strict";
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function checkUrlbarFocus(win) {
|
||||
let urlbar = win.gURLBar;
|
||||
|
|
|
@ -198,7 +198,7 @@ ContentRestoreInternal.prototype = {
|
|||
}
|
||||
let referrer = loadArguments.referrer ?
|
||||
Utils.makeURI(loadArguments.referrer) : null;
|
||||
webNavigation.loadURI(loadArguments.uri, loadArguments.loadFlags,
|
||||
webNavigation.loadURI(loadArguments.uri, loadArguments.flags,
|
||||
referrer, null, null);
|
||||
} else if (tabData.userTypedValue && tabData.userTypedClear) {
|
||||
// If the user typed a URL into the URL bar and hit enter right before
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
newWindowWithTabView(onTabViewWindowLoaded);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
let cw;
|
||||
let win;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
let cw;
|
||||
let win;
|
||||
|
|
|
@ -15,6 +15,8 @@ const TEST_URL = 'data:text/html,<script>window.onbeforeunload=' +
|
|||
let contentWindow;
|
||||
let activeGroup;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
let cw;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(2);
|
||||
waitForExplicitFinish();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
const STATE = {
|
||||
windows: [{
|
||||
|
|
|
@ -14,28 +14,29 @@ function test() {
|
|||
|
||||
info("highlighting the body node");
|
||||
yield runCommand("highlight body", options);
|
||||
is(getHighlighters().length, 1, "The highlighter element exists for body");
|
||||
is(getHighlighterNumber(), 1, "The highlighter element exists for body");
|
||||
|
||||
info("highlighting the div node");
|
||||
yield runCommand("highlight div", options);
|
||||
is(getHighlighters().length, 1, "The highlighter element exists for div");
|
||||
is(getHighlighterNumber(), 1, "The highlighter element exists for div");
|
||||
|
||||
info("highlighting the body node again, asking to keep the div");
|
||||
yield runCommand("highlight body --keep", options);
|
||||
is(getHighlighters().length, 2, "2 highlighter elements have been created");
|
||||
is(getHighlighterNumber(), 2, "2 highlighter elements have been created");
|
||||
|
||||
info("unhighlighting all nodes");
|
||||
yield runCommand("unhighlight", options);
|
||||
is(getHighlighters().length, 0, "All highlighters have been removed");
|
||||
is(getHighlighterNumber(), 0, "All highlighters have been removed");
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
}).then(finish, helpers.handleError);
|
||||
}
|
||||
|
||||
function getHighlighters() {
|
||||
return gBrowser.selectedBrowser.parentNode
|
||||
.querySelectorAll(".highlighter-container");
|
||||
function getHighlighterNumber() {
|
||||
// Note that this only works as long as gcli tests aren't run with e10s on.
|
||||
// To make this e10s ready, execute this in a content frame script instead.
|
||||
return require("gcli/commands/highlight").highlighters.length;
|
||||
}
|
||||
|
||||
function* runCommand(cmd, options) {
|
||||
|
|
|
@ -215,6 +215,8 @@ let DebuggerController = {
|
|||
yield this._startTracingTab(traceActor);
|
||||
}
|
||||
}
|
||||
|
||||
this._hideUnsupportedFeatures();
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -231,6 +233,16 @@ let DebuggerController = {
|
|||
this.activeThread = null;
|
||||
},
|
||||
|
||||
_hideUnsupportedFeatures: function() {
|
||||
if (this.client.mainRoot.traits.noPrettyPrinting) {
|
||||
DebuggerView.Sources.hidePrettyPrinting();
|
||||
}
|
||||
|
||||
if (this.client.mainRoot.traits.noBlackBoxing) {
|
||||
DebuggerView.Sources.hideBlackBoxing();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called for each location change in the debugged tab.
|
||||
*
|
||||
|
|
|
@ -546,6 +546,24 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
}
|
||||
},
|
||||
|
||||
hidePrettyPrinting: function() {
|
||||
this._prettyPrintButton.style.display = 'none';
|
||||
|
||||
if (this._blackBoxButton.style.display === 'none') {
|
||||
let sep = document.querySelector('#sources-toolbar .devtools-separator');
|
||||
sep.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
hideBlackBoxing: function() {
|
||||
this._blackBoxButton.style.display = 'none';
|
||||
|
||||
if (this._prettyPrintButton.style.display === 'none') {
|
||||
let sep = document.querySelector('#sources-toolbar .devtools-separator');
|
||||
sep.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Marks a breakpoint as selected in this sources container.
|
||||
*
|
||||
|
|
|
@ -235,6 +235,8 @@ skip-if = e10s
|
|||
skip-if = e10s
|
||||
[browser_dbg_globalactor.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_hide-toolbar-buttons.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_hit-counts-01.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_hit-counts-02.js]
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 1093349: Test that the pretty-printing and blackboxing buttons
|
||||
* are hidden if the server doesn't support them
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-01.html";
|
||||
|
||||
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||
let { RootActor } = devtools.require("devtools/server/actors/root");
|
||||
|
||||
function test() {
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;
|
||||
|
||||
RootActor.prototype.traits.noBlackBoxing = true;
|
||||
RootActor.prototype.traits.noPrettyPrinting = true;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
let document = aPanel.panelWin.document;
|
||||
let ppButton = document.querySelector('#pretty-print');
|
||||
let bbButton = document.querySelector('#black-box');
|
||||
let sep = document.querySelector('#sources-toolbar .devtools-separator');
|
||||
|
||||
is(ppButton.style.display, 'none', 'The pretty-print button is hidden');
|
||||
is(bbButton.style.display, 'none', 'The blackboxing button is hidden');
|
||||
is(sep.style.display, 'none', 'The separator is hidden');
|
||||
closeDebuggerAndFinish(aPanel)
|
||||
});
|
||||
}
|
|
@ -2,6 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
window {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#doorhanger-container {
|
||||
width: 450px;
|
||||
}
|
||||
|
@ -10,7 +15,20 @@
|
|||
padding: 20px;
|
||||
background: #343c45; /* toolbars */
|
||||
color: #8fa1b2; /* body text */
|
||||
/*
|
||||
* Sloppy preprocessing since UNIX_BUT_NOT_MAC is only defined
|
||||
* in `browser/app/profile/firefox.js`, which this file cannot
|
||||
* depend on. Must style font-size to target linux.
|
||||
*/
|
||||
%ifdef XP_UNIX
|
||||
%ifndef XP_MACOSX
|
||||
font-size: 13px;
|
||||
%else
|
||||
font-size: 15px;
|
||||
%endif
|
||||
%else
|
||||
font-size: 15px;
|
||||
%endif
|
||||
line-height: 19px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
@ -60,6 +78,8 @@
|
|||
border-radius: 5px;
|
||||
height: 30px;
|
||||
width: 450px;
|
||||
/* Override embossed borders on Windows/Linux */
|
||||
border: none;
|
||||
}
|
||||
|
||||
#close {
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
skip-if = e10s # Bug 1074836 - inspector tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_frame_script.js
|
||||
doc_inspector_breadcrumbs.html
|
||||
doc_inspector_delete-selected-node-01.html
|
||||
doc_inspector_delete-selected-node-02.html
|
||||
doc_inspector_gcli-inspect-command.html
|
||||
doc_inspector_highlight_after_transition.html
|
||||
doc_inspector_highlighter-comments.html
|
||||
doc_inspector_highlighter_csstransform.html
|
||||
doc_inspector_highlighter.html
|
||||
browser_inspector_infobar_01.html
|
||||
browser_inspector_infobar_02.html
|
||||
doc_inspector_infobar_01.html
|
||||
doc_inspector_infobar_02.html
|
||||
doc_inspector_menu.html
|
||||
doc_inspector_remove-iframe-during-load.html
|
||||
doc_inspector_search.html
|
||||
doc_inspector_search-suggestions.html
|
||||
doc_inspector_select-last-selected-01.html
|
||||
doc_inspector_select-last-selected-02.html
|
||||
browser_inspector_highlight_after_transition.html
|
||||
head.js
|
||||
|
||||
[browser_inspector_breadcrumbs.js]
|
||||
|
@ -29,11 +31,20 @@ support-files =
|
|||
[browser_inspector_highlighter-01.js]
|
||||
[browser_inspector_highlighter-02.js]
|
||||
[browser_inspector_highlighter-03.js]
|
||||
[browser_inspector_highlighter-04.js]
|
||||
[browser_inspector_highlighter-by-type.js]
|
||||
[browser_inspector_highlighter-comments.js]
|
||||
[browser_inspector_highlighter-csstransform_01.js]
|
||||
[browser_inspector_highlighter-csstransform_02.js]
|
||||
[browser_inspector_highlighter-hover_01.js]
|
||||
[browser_inspector_highlighter-hover_02.js]
|
||||
[browser_inspector_highlighter-hover_03.js]
|
||||
[browser_inspector_highlighter-iframes.js]
|
||||
[browser_inspector_highlighter-options.js]
|
||||
[browser_inspector_highlighter-selector_01.js]
|
||||
[browser_inspector_highlighter-selector_02.js]
|
||||
[browser_inspector_iframe-navigation.js]
|
||||
[browser_inspector_infobar_01.js]
|
||||
[browser_inspector_infobar_02.js]
|
||||
[browser_inspector_initialization.js]
|
||||
[browser_inspector_inspect-object-element.js]
|
||||
[browser_inspector_invalidate.js]
|
||||
|
@ -57,4 +68,3 @@ support-files =
|
|||
[browser_inspector_sidebarstate.js]
|
||||
[browser_inspector_switch-to-inspector-on-pick.js]
|
||||
[browser_inspector_update-on-navigation.js]
|
||||
|
||||
|
|
|
@ -7,70 +7,67 @@
|
|||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_inspector_breadcrumbs.html";
|
||||
const NODES = [
|
||||
{nodeId: "#i1111", result: "i1 i11 i111 i1111"},
|
||||
{nodeId: "#i22", result: "i2 i22 i221"},
|
||||
{nodeId: "#i2111", result: "i2 i21 i211 i2111"},
|
||||
{nodeId: "#i21", result: "i2 i21 i211 i2111"},
|
||||
{nodeId: "#i22211", result: "i2 i22 i222 i2221 i22211"},
|
||||
{nodeId: "#i22", result: "i2 i22 i222 i2221 i22211"},
|
||||
{selector: "#i1111", result: "i1 i11 i111 i1111"},
|
||||
{selector: "#i22", result: "i2 i22 i221"},
|
||||
{selector: "#i2111", result: "i2 i21 i211 i2111"},
|
||||
{selector: "#i21", result: "i2 i21 i211 i2111"},
|
||||
{selector: "#i22211", result: "i2 i22 i222 i2221 i22211"},
|
||||
{selector: "#i22", result: "i2 i22 i222 i2221 i22211"},
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
add_task(function*() {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URI);
|
||||
let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
|
||||
|
||||
for (let node of NODES) {
|
||||
info("Testing node " + node.nodeId);
|
||||
|
||||
let documentNode = getNode(node.nodeId);
|
||||
info("Testing node " + node.selector);
|
||||
|
||||
info("Selecting node and waiting for breadcrumbs to update");
|
||||
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
|
||||
let nodeSelected = selectNode(documentNode, inspector);
|
||||
yield selectNode(node.selector, inspector);
|
||||
yield breadcrumbsUpdated;
|
||||
|
||||
yield Promise.all([breadcrumbsUpdated, nodeSelected]);
|
||||
|
||||
info("Performing checks for node " + node.nodeId);
|
||||
info("Performing checks for node " + node.selector);
|
||||
let buttonsLabelIds = node.result.split(" ");
|
||||
|
||||
// html > body > …
|
||||
is(container.childNodes.length, buttonsLabelIds.length + 2,
|
||||
"Node " + node.nodeId + ": Items count");
|
||||
"Node " + node.selector + ": Items count");
|
||||
|
||||
for (let i = 2; i < container.childNodes.length; i++) {
|
||||
let expectedId = "#" + buttonsLabelIds[i - 2];
|
||||
let button = container.childNodes[i];
|
||||
let labelId = button.querySelector(".breadcrumbs-widget-item-id");
|
||||
is(labelId.textContent, expectedId,
|
||||
"Node #" + node.nodeId + ": button " + i + " matches");
|
||||
"Node #" + node.selector + ": button " + i + " matches");
|
||||
}
|
||||
|
||||
let checkedButton = container.querySelector("button[checked]");
|
||||
let labelId = checkedButton.querySelector(".breadcrumbs-widget-item-id");
|
||||
let id = inspector.selection.node.id;
|
||||
let id = inspector.selection.nodeFront.id;
|
||||
is(labelId.textContent, "#" + id,
|
||||
"Node #" + node.nodeId + ": selection matches");
|
||||
"Node #" + node.selector + ": selection matches");
|
||||
}
|
||||
|
||||
yield testPseudoElements(inspector, container);
|
||||
});
|
||||
|
||||
function *testPseudoElements(inspector, container) {
|
||||
function* testPseudoElements(inspector, container) {
|
||||
info ("Checking for pseudo elements");
|
||||
|
||||
let pseudoParent = getNodeFront(getNode("#pseudo-container"));
|
||||
let pseudoParent = yield getNodeFront("#pseudo-container", inspector);
|
||||
let children = yield inspector.walker.children(pseudoParent);
|
||||
is (children.nodes.length, 2, "Pseudo children returned from walker");
|
||||
|
||||
let beforeElement = children.nodes[0];
|
||||
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
|
||||
let nodeSelected = selectNode(beforeElement, inspector);
|
||||
yield Promise.all([breadcrumbsUpdated, nodeSelected]);
|
||||
yield selectNode(beforeElement, inspector);
|
||||
yield breadcrumbsUpdated;
|
||||
is(container.childNodes[3].textContent, "::before", "::before shows up in breadcrumb");
|
||||
|
||||
let afterElement = children.nodes[1];
|
||||
breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
|
||||
nodeSelected = selectNode(afterElement, inspector);
|
||||
yield Promise.all([breadcrumbsUpdated, nodeSelected]);
|
||||
yield selectNode(afterElement, inspector);
|
||||
yield breadcrumbsUpdated;
|
||||
is(container.childNodes[3].textContent, "::after", "::before shows up in breadcrumb");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
// Test that hovering over nodes on the breadcrumb buttons in the inspector shows the highlighter over
|
||||
// those nodes
|
||||
let test = asyncTest(function*() {
|
||||
add_task(function*() {
|
||||
info("Loading the test document and opening the inspector");
|
||||
yield addTab("data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
|
||||
let {toolbox, inspector} = yield openInspector();
|
||||
|
@ -18,15 +18,23 @@ let test = asyncTest(function*() {
|
|||
let button = bcButtons.childNodes[1];
|
||||
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
|
||||
yield onNodeHighlighted;
|
||||
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
|
||||
is(getHighlitNode(), getNode("body"), "The highlighter highlights the right node");
|
||||
|
||||
let isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown on a markup container hover");
|
||||
|
||||
let highlightedNode = yield getHighlitNode(toolbox);
|
||||
is(highlightedNode, getNode("body"), "The highlighter highlights the right node");
|
||||
|
||||
onNodeHighlighted = toolbox.once("node-highlight");
|
||||
button = bcButtons.childNodes[2];
|
||||
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
|
||||
yield onNodeHighlighted;
|
||||
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
|
||||
is(getHighlitNode(), getNode("span"), "The highlighter highlights the right node");
|
||||
|
||||
isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown on a markup container hover");
|
||||
|
||||
highlightedNode = yield getHighlitNode(toolbox);
|
||||
is(highlightedNode, getNode("span"), "The highlighter highlights the right node");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -7,22 +7,18 @@
|
|||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_delete-selected-node-01.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URL);
|
||||
let iframe = getNode("iframe");
|
||||
let span = getNode("span", { document: iframe.contentDocument });
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
let span = yield getNodeFrontInFrame("span", "iframe", inspector);
|
||||
yield selectNode(span, inspector);
|
||||
|
||||
info("Removing selected <span> element.");
|
||||
let parentNode = span.parentNode;
|
||||
span.remove();
|
||||
|
||||
let lh = new LayoutHelpers(window.content);
|
||||
ok(!lh.isNodeConnected(span), "Node considered as disconnected.");
|
||||
let parentNode = span.parentNode();
|
||||
yield inspector.walker.removeNode(span);
|
||||
|
||||
// Wait for the inspector to process the mutation
|
||||
yield inspector.once("inspector-updated");
|
||||
is(inspector.selection.node, parentNode,
|
||||
is(inspector.selection.nodeFront, parentNode,
|
||||
"Parent node of selected <span> got selected.");
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
const TEST_PAGE = TEST_URL_ROOT +
|
||||
"doc_inspector_delete-selected-node-02.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_PAGE);
|
||||
|
||||
yield testManuallyDeleteSelectedNode();
|
||||
|
@ -23,11 +23,10 @@ let test = asyncTest(function* () {
|
|||
info("Selecting a node, deleting it via context menu and checking that " +
|
||||
"its parent node is selected and breadcrumbs are updated.");
|
||||
|
||||
let div = getNode("#deleteManually");
|
||||
yield selectNode(div, inspector);
|
||||
yield selectNode("#deleteManually", inspector);
|
||||
|
||||
info("Getting the node container in the markup view.");
|
||||
let container = getContainerForRawNode(inspector.markup, div);
|
||||
let container = yield getContainerForSelector("#deleteManually", inspector);
|
||||
|
||||
info("Simulating right-click on the markup view container.");
|
||||
EventUtils.synthesizeMouse(container.tagLine, 2, 2,
|
||||
|
@ -43,26 +42,24 @@ let test = asyncTest(function* () {
|
|||
yield inspector.once("inspector-updated");
|
||||
|
||||
info("Inspector updated, performing checks.");
|
||||
let parent = getNode("#deleteChildren");
|
||||
assertNodeSelectedAndPanelsUpdated(parent, "ul#deleteChildren");
|
||||
yield assertNodeSelectedAndPanelsUpdated("#deleteChildren", "ul#deleteChildren");
|
||||
}
|
||||
|
||||
function* testAutomaticallyDeleteSelectedNode() {
|
||||
info("Selecting a node, deleting it via javascript and checking that " +
|
||||
"its parent node is selected and breadcrumbs are updated.");
|
||||
|
||||
let div = getNode("#deleteAutomatically");
|
||||
let div = yield getNodeFront("#deleteAutomatically", inspector);
|
||||
yield selectNode(div, inspector);
|
||||
|
||||
info("Deleting selected node via javascript.");
|
||||
div.remove();
|
||||
yield inspector.walker.removeNode(div);
|
||||
|
||||
info("Waiting for inspector to update.");
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
info("Inspector updated, performing checks.");
|
||||
let parent = getNode("#deleteChildren");
|
||||
assertNodeSelectedAndPanelsUpdated(parent, "ul#deleteChildren");
|
||||
yield assertNodeSelectedAndPanelsUpdated("#deleteChildren", "ul#deleteChildren");
|
||||
}
|
||||
|
||||
function* testDeleteSelectedNodeContainerFrame() {
|
||||
|
@ -71,23 +68,23 @@ let test = asyncTest(function* () {
|
|||
"breadcrumbs are updated.");
|
||||
|
||||
info("Selecting an element inside iframe.");
|
||||
let iframe = getNode("#deleteIframe");
|
||||
let div = iframe.contentDocument.getElementById("deleteInIframe");
|
||||
let iframe = yield getNodeFront("#deleteIframe", inspector);
|
||||
let div = yield getNodeFrontInFrame("#deleteInIframe", iframe, inspector);
|
||||
yield selectNode(div, inspector);
|
||||
|
||||
info("Deleting selected node via javascript.");
|
||||
iframe.remove();
|
||||
yield inspector.walker.removeNode(iframe);
|
||||
|
||||
info("Waiting for inspector to update.");
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
info("Inspector updated, performing checks.");
|
||||
assertNodeSelectedAndPanelsUpdated(getNode("body"), "body");
|
||||
yield assertNodeSelectedAndPanelsUpdated("body", "body");
|
||||
}
|
||||
|
||||
function assertNodeSelectedAndPanelsUpdated(node, crumbLabel) {
|
||||
is(inspector.selection.nodeFront, getNodeFront(node),
|
||||
"The right node is selected");
|
||||
function* assertNodeSelectedAndPanelsUpdated(selector, crumbLabel) {
|
||||
let nodeFront = yield getNodeFront(selector, inspector);
|
||||
is(inspector.selection.nodeFront, nodeFront, "The right node is selected");
|
||||
|
||||
let breadcrumbs = inspector.panelDoc.getElementById("inspector-breadcrumbs");
|
||||
is(breadcrumbs.querySelector("button[checked=true]").textContent, crumbLabel,
|
||||
|
|
|
@ -8,19 +8,18 @@
|
|||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_delete-selected-node-01.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
let iframe = getNode("iframe");
|
||||
let node = getNode("span", { document: iframe.contentDocument });
|
||||
let iframe = yield getNodeFront("iframe", inspector);
|
||||
let node = yield getNodeFrontInFrame("span", iframe, inspector);
|
||||
yield selectNode(node, inspector);
|
||||
|
||||
info("Removing iframe.");
|
||||
iframe.remove();
|
||||
yield inspector.walker.removeNode(iframe);
|
||||
|
||||
let lh = new LayoutHelpers(window.content);
|
||||
ok(!lh.isNodeConnected(node), "Node considered as disconnected.");
|
||||
ok(!inspector.selection.isConnected(), "Selection considered as disconnected.");
|
||||
let body = yield getNodeFront("body", inspector);
|
||||
is(inspector.selection.nodeFront, body, "Selection is now the body node");
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
const URL_1 = "data:text/plain;charset=UTF-8,abcde";
|
||||
const URL_2 = "data:text/plain;charset=UTF-8,12345";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { toolbox } = yield openInspectorForURL(URL_1);
|
||||
|
||||
info("Navigating to different URL.");
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_inspector_gcli-inspect-command.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
return helpers.addTabWithToolbar(TEST_URI, function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
|
|
|
@ -6,23 +6,28 @@
|
|||
|
||||
// Test that hovering over nodes in the markup-view shows the highlighter over
|
||||
// those nodes
|
||||
let test = asyncTest(function*() {
|
||||
add_task(function*() {
|
||||
info("Loading the test document and opening the inspector");
|
||||
yield addTab("data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
|
||||
let {toolbox, inspector} = yield openInspector();
|
||||
|
||||
let isVisible = yield isHighlighting(toolbox);
|
||||
ok(!isVisible, "The highlighter is hidden by default");
|
||||
|
||||
info("Selecting the test node");
|
||||
yield selectNode("span", inspector);
|
||||
|
||||
let container = getContainerForRawNode(inspector.markup, getNode("h1"));
|
||||
let container = yield getContainerForSelector("h1", inspector);
|
||||
|
||||
let onHighlighterReady = toolbox.once("highlighter-ready");
|
||||
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
|
||||
inspector.markup.doc.defaultView);
|
||||
yield onHighlighterReady;
|
||||
|
||||
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
|
||||
is(getHighlitNode(), getNode("h1"), "The highlighter highlights the right node");
|
||||
isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown on a markup container hover");
|
||||
|
||||
let node = yield getHighlitNode(toolbox);
|
||||
is(node, getNode("h1"), "The highlighter highlights the right node");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -10,70 +10,33 @@
|
|||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_inspector_highlighter.html";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URI);
|
||||
add_task(function*() {
|
||||
let {toolbox, inspector} = yield openInspectorForURL(TEST_URI);
|
||||
|
||||
info("Selecting the simple, non-transformed DIV");
|
||||
let div = getNode("#simple-div");
|
||||
yield selectAndHighlightNode(div, inspector);
|
||||
yield selectAndHighlightNode("#simple-div", inspector);
|
||||
|
||||
testSimpleDivHighlighted(div);
|
||||
yield zoomTo(2);
|
||||
testZoomedSimpleDivHighlighted(div);
|
||||
yield zoomTo(1);
|
||||
let isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown");
|
||||
let highlightedNode = yield getHighlitNode(toolbox);
|
||||
is(highlightedNode, getNode("#simple-div"),
|
||||
"The highlighter's outline corresponds to the simple div");
|
||||
yield isNodeCorrectlyHighlighted(getNode("#simple-div"), toolbox,
|
||||
"non-zoomed");
|
||||
|
||||
info("Selecting the rotated DIV");
|
||||
let rotated = getNode("#rotated-div");
|
||||
let onBoxModelUpdate = waitForBoxModelUpdate();
|
||||
yield selectAndHighlightNode(rotated, inspector);
|
||||
yield onBoxModelUpdate;
|
||||
yield selectAndHighlightNode("#rotated-div", inspector);
|
||||
|
||||
testMouseOverRotatedHighlights(rotated);
|
||||
isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown");
|
||||
yield isNodeCorrectlyHighlighted(getNode("#rotated-div"), toolbox,
|
||||
"rotated");
|
||||
|
||||
info("Selecting the zero width height DIV");
|
||||
let zeroWidthHeight = getNode("#widthHeightZero-div");
|
||||
onBoxModelUpdate = waitForBoxModelUpdate();
|
||||
yield selectAndHighlightNode(zeroWidthHeight, inspector);
|
||||
yield onBoxModelUpdate;
|
||||
|
||||
testMouseOverWidthHeightZeroDiv(zeroWidthHeight);
|
||||
yield selectAndHighlightNode("#widthHeightZero-div", inspector);
|
||||
|
||||
isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown");
|
||||
yield isNodeCorrectlyHighlighted(getNode("#widthHeightZero-div"), toolbox,
|
||||
"zero width height");
|
||||
});
|
||||
|
||||
function testSimpleDivHighlighted(div) {
|
||||
ok(isHighlighting(), "The highlighter is shown");
|
||||
is(getHighlitNode(), div, "The highlighter's outline corresponds to the simple div");
|
||||
|
||||
info("Checking that the simple div is correctly highlighted");
|
||||
isNodeCorrectlyHighlighted(div, "non-zoomed");
|
||||
}
|
||||
|
||||
function testZoomedSimpleDivHighlighted(div) {
|
||||
info("Checking that the simple div is correctly highlighted, " +
|
||||
"even when the page is zoomed");
|
||||
isNodeCorrectlyHighlighted(div, "zoomed");
|
||||
}
|
||||
|
||||
function zoomTo(level) {
|
||||
info("Zooming page to " + level);
|
||||
let def = promise.defer();
|
||||
|
||||
waitForBoxModelUpdate().then(def.resolve);
|
||||
let contentViewer = gBrowser.selectedBrowser.docShell.contentViewer;
|
||||
contentViewer.fullZoom = level;
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
function testMouseOverRotatedHighlights(rotated) {
|
||||
ok(isHighlighting(), "The highlighter is shown");
|
||||
info("Checking that the rotated div is correctly highlighted");
|
||||
isNodeCorrectlyHighlighted(rotated, "rotated");
|
||||
}
|
||||
|
||||
function testMouseOverWidthHeightZeroDiv(zeroHeightWidthDiv) {
|
||||
ok(isHighlighting(), "The highlighter is shown");
|
||||
info("Checking that the zero width height div is correctly highlighted");
|
||||
isNodeCorrectlyHighlighted(zeroHeightWidthDiv, "zero width height");
|
||||
|
||||
}
|
||||
|
|
|
@ -24,20 +24,19 @@ const DOCUMENT_SRC = "<style>" +
|
|||
"}" +
|
||||
"</style>" +
|
||||
"<body>" +
|
||||
"<iframe src='data:text/html," + IFRAME_SRC + "'></iframe>" +
|
||||
"<iframe src='data:text/html;charset=utf-8," + IFRAME_SRC + "'></iframe>" +
|
||||
"</body>";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8," + DOCUMENT_SRC;
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { inspector, toolbox } = yield openInspectorForURL(TEST_URI);
|
||||
let outerDocument = content.document;
|
||||
|
||||
let iframeNode = getNode("iframe");
|
||||
let iframeBodyNode = getNode("body", { document: iframeNode.contentDocument });
|
||||
|
||||
info("Waiting for box mode to show.");
|
||||
yield toolbox.highlighter.showBoxModel(getNodeFront(outerDocument.body));
|
||||
let body = yield getNodeFront("body", inspector);
|
||||
yield toolbox.highlighter.showBoxModel(body);
|
||||
|
||||
info("Waiting for element picker to become active.");
|
||||
yield toolbox.highlighterUtils.startPicker();
|
||||
|
@ -46,25 +45,28 @@ let test = asyncTest(function* () {
|
|||
yield moveMouseOver(iframeNode, 1, 1);
|
||||
|
||||
info("Performing checks");
|
||||
isNodeCorrectlyHighlighted(iframeNode);
|
||||
yield isNodeCorrectlyHighlighted(iframeNode, toolbox);
|
||||
|
||||
info("Scrolling the document");
|
||||
iframeNode.style.marginBottom = outerDocument.defaultView.innerHeight + "px";
|
||||
outerDocument.defaultView.scrollBy(0, 40);
|
||||
iframeNode.style.marginBottom = content.innerHeight + "px";
|
||||
content.scrollBy(0, 40);
|
||||
|
||||
let iframeBodyNode = iframeNode.contentDocument.body;
|
||||
|
||||
info("Moving mouse over iframe body");
|
||||
yield moveMouseOver(iframeNode, 40, 40);
|
||||
|
||||
is(getHighlitNode(), iframeBodyNode, "highlighter shows the right node");
|
||||
isNodeCorrectlyHighlighted(iframeBodyNode);
|
||||
let highlightedNode = yield getHighlitNode(toolbox);
|
||||
is(highlightedNode, iframeBodyNode, "highlighter shows the right node");
|
||||
yield isNodeCorrectlyHighlighted(iframeBodyNode, toolbox);
|
||||
|
||||
info("Waiting for the element picker to deactivate.");
|
||||
yield inspector.toolbox.highlighterUtils.stopPicker();
|
||||
|
||||
function moveMouseOver(aElement, x, y) {
|
||||
info("Waiting for element " + aElement + " to be highlighted");
|
||||
EventUtils.synthesizeMouse(aElement, x, y, {type: "mousemove"},
|
||||
aElement.ownerDocument.defaultView);
|
||||
function moveMouseOver(node, x, y) {
|
||||
info("Waiting for element " + node + " to be highlighted");
|
||||
executeInContent("Test:SynthesizeMouse", {x, y, type: "mousemove"},
|
||||
{node}, false);
|
||||
return inspector.toolbox.once("picker-node-hovered");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Check that various highlighter elements exist.
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,<div>test</div>";
|
||||
|
||||
// IDs of all highlighter elements that we expect to find in the canvasFrame.
|
||||
const ELEMENTS = ["box-model-root",
|
||||
"box-model-margin",
|
||||
"box-model-border",
|
||||
"box-model-padding",
|
||||
"box-model-content",
|
||||
"box-model-guide-top",
|
||||
"box-model-guide-right",
|
||||
"box-model-guide-bottom",
|
||||
"box-model-guide-left",
|
||||
"box-model-nodeinfobar-container",
|
||||
"box-model-nodeinfobar-tagname",
|
||||
"box-model-nodeinfobar-id",
|
||||
"box-model-nodeinfobar-classes",
|
||||
"box-model-nodeinfobar-pseudo-classes",
|
||||
"box-model-nodeinfobar-dimensions"];
|
||||
|
||||
add_task(function*() {
|
||||
let {inspector, toolbox} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
info("Show the box-model highlighter");
|
||||
let divFront = yield getNodeFront("div", inspector);
|
||||
yield toolbox.highlighter.showBoxModel(divFront);
|
||||
|
||||
for (let id of ELEMENTS) {
|
||||
let {data: foundId} = yield executeInContent("Test:GetHighlighterAttribute", {
|
||||
nodeID: id,
|
||||
name: "id",
|
||||
actorID: getHighlighterActorID(toolbox)
|
||||
});
|
||||
is(foundId, id, "Element " + id + " found");
|
||||
}
|
||||
|
||||
info("Hide the box-model highlighter");
|
||||
yield toolbox.highlighter.hideBoxModel();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Check that custom highlighters can be retrieved by type and that they expose
|
||||
// the expected API.
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,custom highlighters";
|
||||
|
||||
add_task(function*() {
|
||||
let {inspector, toolbox} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
yield onlyOneInstanceOfMainHighlighter(inspector);
|
||||
yield manyInstancesOfCustomHighlighters(inspector);
|
||||
yield showHideMethodsAreAvailable(inspector);
|
||||
yield unknownHighlighterTypeShouldntBeAccepted(inspector);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function* onlyOneInstanceOfMainHighlighter({inspector}) {
|
||||
info("Check that the inspector always sends back the same main highlighter");
|
||||
|
||||
let h1 = yield inspector.getHighlighter(false);
|
||||
let h2 = yield inspector.getHighlighter(false);
|
||||
is(h1, h2, "The same highlighter front was returned");
|
||||
|
||||
is(h1.typeName, "highlighter", "The right front type was returned");
|
||||
}
|
||||
|
||||
function* manyInstancesOfCustomHighlighters({inspector}) {
|
||||
let h1 = yield inspector.getHighlighterByType("BoxModelHighlighter");
|
||||
let h2 = yield inspector.getHighlighterByType("BoxModelHighlighter");
|
||||
ok(h1 !== h2, "getHighlighterByType returns new instances every time (1)");
|
||||
|
||||
let h3 = yield inspector.getHighlighterByType("CssTransformHighlighter");
|
||||
let h4 = yield inspector.getHighlighterByType("CssTransformHighlighter");
|
||||
ok(h3 !== h4, "getHighlighterByType returns new instances every time (2)");
|
||||
ok(h3 !== h1 && h3 !== h2,
|
||||
"getHighlighterByType returns new instances every time (3)");
|
||||
ok(h4 !== h1 && h4 !== h2,
|
||||
"getHighlighterByType returns new instances every time (4)");
|
||||
|
||||
yield h1.finalize();
|
||||
yield h2.finalize();
|
||||
yield h3.finalize();
|
||||
yield h4.finalize();
|
||||
}
|
||||
|
||||
function* showHideMethodsAreAvailable({inspector}) {
|
||||
let h1 = yield inspector.getHighlighterByType("BoxModelHighlighter");
|
||||
let h2 = yield inspector.getHighlighterByType("CssTransformHighlighter");
|
||||
|
||||
ok("show" in h1, "Show method is present on the front API");
|
||||
ok("show" in h2, "Show method is present on the front API");
|
||||
ok("hide" in h1, "Hide method is present on the front API");
|
||||
ok("hide" in h2, "Hide method is present on the front API");
|
||||
|
||||
yield h1.finalize();
|
||||
yield h2.finalize();
|
||||
}
|
||||
|
||||
function* unknownHighlighterTypeShouldntBeAccepted({inspector}) {
|
||||
let h = yield inspector.getHighlighterByType("whatever");
|
||||
ok(!h, "No highlighter was returned for the invalid type");
|
||||
}
|
|
@ -18,38 +18,38 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("false");
|
|||
const TEST_PAGE = TEST_URL_ROOT +
|
||||
"doc_inspector_highlighter-comments.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_PAGE);
|
||||
add_task(function* () {
|
||||
let {toolbox, inspector} = yield openInspectorForURL(TEST_PAGE);
|
||||
let markupView = inspector.markup;
|
||||
yield selectNode("p", inspector);
|
||||
|
||||
info("Hovering over #id1 and waiting for highlighter to appear.");
|
||||
yield hoverElement("#id1");
|
||||
assertHighlighterShownOn("#id1");
|
||||
yield assertHighlighterShownOn("#id1");
|
||||
|
||||
info("Hovering over comment node and ensuring highlighter doesn't appear.");
|
||||
yield hoverComment();
|
||||
assertHighlighterHidden();
|
||||
yield assertHighlighterHidden();
|
||||
|
||||
info("Hovering over #id1 again and waiting for highlighter to appear.");
|
||||
yield hoverElement("#id1");
|
||||
assertHighlighterShownOn("#id1");
|
||||
yield assertHighlighterShownOn("#id1");
|
||||
|
||||
info("Hovering over #id2 and waiting for highlighter to appear.");
|
||||
yield hoverElement("#id2");
|
||||
assertHighlighterShownOn("#id2");
|
||||
yield assertHighlighterShownOn("#id2");
|
||||
|
||||
info("Hovering over <script> and ensuring highlighter doesn't appear.");
|
||||
yield hoverElement("script");
|
||||
assertHighlighterHidden();
|
||||
yield assertHighlighterHidden();
|
||||
|
||||
info("Hovering over #id3 and waiting for highlighter to appear.");
|
||||
yield hoverElement("#id3");
|
||||
assertHighlighterShownOn("#id3");
|
||||
yield assertHighlighterShownOn("#id3");
|
||||
|
||||
info("Hovering over hidden #id4 and ensuring highlighter doesn't appear.");
|
||||
yield hoverElement("#id4");
|
||||
assertHighlighterHidden();
|
||||
yield assertHighlighterHidden();
|
||||
|
||||
function hoverContainer(container) {
|
||||
let promise = inspector.toolbox.once("node-highlight");
|
||||
|
@ -59,9 +59,9 @@ let test = asyncTest(function* () {
|
|||
return promise;
|
||||
}
|
||||
|
||||
function hoverElement(selector) {
|
||||
function* hoverElement(selector) {
|
||||
info("Hovering node " + selector + " in the markup view");
|
||||
let container = getContainerForRawNode(markupView, getNode(selector));
|
||||
let container = yield getContainerForSelector(selector, inspector);
|
||||
return hoverContainer(container);
|
||||
}
|
||||
|
||||
|
@ -74,13 +74,14 @@ let test = asyncTest(function* () {
|
|||
}
|
||||
}
|
||||
|
||||
function assertHighlighterShownOn(selector) {
|
||||
function* assertHighlighterShownOn(selector) {
|
||||
let node = getNode(selector);
|
||||
let highlightNode = getHighlitNode();
|
||||
let highlightNode = yield getHighlitNode(toolbox);
|
||||
is(node, highlightNode, "Highlighter is shown on the right node: " + selector);
|
||||
}
|
||||
|
||||
function assertHighlighterHidden() {
|
||||
ok(!isHighlighting(), "Highlighter is hidden");
|
||||
function* assertHighlighterHidden() {
|
||||
let isVisible = yield isHighlighting(toolbox);
|
||||
ok(!isVisible, "Highlighter is hidden");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test the creation of the SVG highlighter elements of the css transform
|
||||
// highlighter.
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8," +
|
||||
"<div id='transformed' style='border:1px solid red;width:100px;height:100px;transform:skew(13deg);'></div>" +
|
||||
"<div id='untransformed' style='border:1px solid blue;width:100px;height:100px;'></div>" +
|
||||
"<span id='inline' style='transform:rotate(90deg);'>this is an inline transformed element</span>";
|
||||
|
||||
add_task(function*() {
|
||||
let {inspector, toolbox} = yield openInspectorForURL(TEST_URL);
|
||||
let front = inspector.inspector;
|
||||
|
||||
let highlighter = yield front.getHighlighterByType("CssTransformHighlighter");
|
||||
|
||||
yield isHiddenByDefault(highlighter, inspector);
|
||||
yield has2PolygonsAnd4Lines(highlighter, inspector);
|
||||
yield isNotShownForUntransformed(highlighter, inspector);
|
||||
yield isNotShownForInline(highlighter, inspector);
|
||||
yield isVisibleWhenShown(highlighter, inspector);
|
||||
yield linesLinkThePolygons(highlighter, inspector);
|
||||
|
||||
yield highlighter.finalize();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function* isHiddenByDefault(highlighterFront, inspector) {
|
||||
info("Checking that the highlighter is hidden by default");
|
||||
|
||||
let hidden = yield getAttribute("css-transform-root", "hidden", highlighterFront);
|
||||
ok(hidden, "The highlighter is hidden by default");
|
||||
}
|
||||
|
||||
function* has2PolygonsAnd4Lines(highlighterFront, inspector) {
|
||||
info("Checking that the highlighter is made up of 4 lines and 2 polygons");
|
||||
|
||||
let value = yield getAttribute("css-transform-untransformed", "class", highlighterFront);
|
||||
is(value, "css-transform-untransformed", "The untransformed polygon exists");
|
||||
|
||||
value = yield getAttribute("css-transform-transformed", "class", highlighterFront);
|
||||
is(value, "css-transform-transformed", "The transformed polygon exists");
|
||||
|
||||
for (let nb of ["1", "2", "3", "4"]) {
|
||||
value = yield getAttribute("css-transform-line" + nb, "class", highlighterFront);
|
||||
is(value, "css-transform-line", "The line " + nb + " exists");
|
||||
}
|
||||
}
|
||||
|
||||
function* isNotShownForUntransformed(highlighterFront, inspector) {
|
||||
info("Asking to show the highlighter on the untransformed test node");
|
||||
|
||||
let node = yield getNodeFront("#untransformed", inspector);
|
||||
yield highlighterFront.show(node);
|
||||
|
||||
let hidden = yield getAttribute("css-transform-root", "hidden", highlighterFront);
|
||||
ok(hidden, "The highlighter is still hidden");
|
||||
}
|
||||
|
||||
function* isNotShownForInline(highlighterFront, inspector) {
|
||||
info("Asking to show the highlighter on the inline test node");
|
||||
|
||||
let node = yield getNodeFront("#inline", inspector);
|
||||
yield highlighterFront.show(node);
|
||||
|
||||
let hidden = yield getAttribute("css-transform-root", "hidden", highlighterFront);
|
||||
ok(hidden, "The highlighter is still hidden");
|
||||
}
|
||||
|
||||
function* isVisibleWhenShown(highlighterFront, inspector) {
|
||||
info("Asking to show the highlighter on the test node");
|
||||
|
||||
let node = yield getNodeFront("#transformed", inspector);
|
||||
yield highlighterFront.show(node);
|
||||
|
||||
let hidden = yield getAttribute("css-transform-root", "hidden", highlighterFront);
|
||||
ok(!hidden, "The highlighter is visible");
|
||||
|
||||
info("Hiding the highlighter");
|
||||
yield highlighterFront.hide();
|
||||
|
||||
hidden = yield getAttribute("css-transform-root", "hidden", highlighterFront);
|
||||
ok(hidden, "The highlighter is hidden");
|
||||
}
|
||||
|
||||
function* linesLinkThePolygons(highlighterFront, inspector) {
|
||||
info("Showing the highlighter on the transformed node");
|
||||
|
||||
let node = yield getNodeFront("#transformed", inspector);
|
||||
yield highlighterFront.show(node);
|
||||
|
||||
info("Checking that the 4 lines do link the 2 shape's corners");
|
||||
|
||||
let lines = [];
|
||||
for (let nb of ["1", "2", "3", "4"]) {
|
||||
let x1 = yield getAttribute("css-transform-line" + nb, "x1", highlighterFront);
|
||||
let y1 = yield getAttribute("css-transform-line" + nb, "y1", highlighterFront);
|
||||
let x2 = yield getAttribute("css-transform-line" + nb, "x2", highlighterFront);
|
||||
let y2 = yield getAttribute("css-transform-line" + nb, "y2", highlighterFront);
|
||||
lines.push({x1, y1, x2, y2});
|
||||
}
|
||||
|
||||
let points1 = yield getAttribute("css-transform-untransformed", "points", highlighterFront);
|
||||
points1 = points1.split(" ");
|
||||
|
||||
let points2 = yield getAttribute("css-transform-transformed", "points", highlighterFront);
|
||||
points2 = points2.split(" ");
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
info("Checking line nb " + i);
|
||||
let line = lines[i];
|
||||
|
||||
let p1 = points1[i].split(",");
|
||||
is(p1[0], line.x1, "line " + i + "'s first point matches the untransformed x coordinate");
|
||||
is(p1[1], line.y1, "line " + i + "'s first point matches the untransformed y coordinate");
|
||||
|
||||
let p2 = points2[i].split(",");
|
||||
is(p2[0], line.x2, "line " + i + "'s first point matches the transformed x coordinate");
|
||||
is(p2[1], line.y2, "line " + i + "'s first point matches the transformed y coordinate");
|
||||
}
|
||||
|
||||
yield highlighterFront.hide();
|
||||
}
|
||||
|
||||
function* getAttribute(nodeID, name, {actorID}) {
|
||||
let {data} = yield executeInContent("Test:GetHighlighterAttribute",
|
||||
{nodeID, name, actorID});
|
||||
return data;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Bug 1014547 - CSS transforms highlighter
|
||||
Test that the highlighter elements created have the right size and coordinates.
|
||||
|
||||
Note that instead of hard-coding values here, the assertions are made by
|
||||
comparing with the result of LayoutHelpers.getAdjustedQuads.
|
||||
|
||||
There's a separate test for checking that getAdjustedQuads actually returns
|
||||
sensible values
|
||||
(browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js),
|
||||
so the present test doesn't care about that, it just verifies that the css
|
||||
transform highlighter applies those values correctly to the SVG elements
|
||||
*/
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_highlighter_csstransform.html";
|
||||
|
||||
add_task(function*() {
|
||||
let {inspector, toolbox} = yield openInspectorForURL(TEST_URL);
|
||||
let front = inspector.inspector;
|
||||
|
||||
let highlighter = yield front.getHighlighterByType("CssTransformHighlighter");
|
||||
|
||||
let node = getNode("#test-node");
|
||||
let nodeFront = yield getNodeFront("#test-node", inspector);
|
||||
|
||||
info("Displaying the transform highlighter on test node");
|
||||
yield highlighter.show(nodeFront);
|
||||
|
||||
let {data} = yield executeInContent("Test:GetAllAdjustedQuads", null, {node});
|
||||
let expected = data.border;
|
||||
|
||||
let points = yield getAttribute("css-transform-transformed", "points", highlighter);
|
||||
let polygonPoints = points.split(" ").map(p => {
|
||||
return {
|
||||
x: +p.substring(0, p.indexOf(",")),
|
||||
y: +p.substring(p.indexOf(",")+1)
|
||||
};
|
||||
});
|
||||
|
||||
for (let i = 1; i < 5; i ++) {
|
||||
is(polygonPoints[i - 1].x, expected["p" + i].x,
|
||||
"p" + i + " x coordinate is correct");
|
||||
is(polygonPoints[i - 1].y, expected["p" + i].y,
|
||||
"p" + i + " y coordinate is correct");
|
||||
}
|
||||
|
||||
info("Hiding the transform highlighter");
|
||||
yield highlighter.hide();
|
||||
yield highlighter.finalize();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function* getAttribute(nodeID, name, {actorID}) {
|
||||
let {data} = yield executeInContent("Test:GetHighlighterAttribute",
|
||||
{nodeID, name, actorID});
|
||||
return data;
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче