mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Merge m-c to inbound. a=merge
This commit is contained in:
commit
4dd66991b6
@ -15,15 +15,15 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,15 +15,15 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -15,15 +15,15 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "d937413f736efd995436c211649f930191429b66",
|
||||
"revision": "9e971d42c915f999f3e352fe43fca7ba0a5245b4",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
@ -15,8 +15,8 @@
|
||||
<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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -17,12 +17,12 @@
|
||||
<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="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2650bae535e15eef5f299cc80d4fab460f78ada7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8374a0d66ca9228269e860089c1535fcda9f9c5f"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
@ -353,7 +353,7 @@ input[type=button] {
|
||||
}
|
||||
|
||||
@media not all and (max-resolution: 1dppx) {
|
||||
#newtab-search-icon.magnifier {
|
||||
#newtab-search-logo.magnifier {
|
||||
background-image: url("chrome://browser/skin/magnifier@2x.png");
|
||||
}
|
||||
}
|
||||
|
@ -1040,6 +1040,8 @@
|
||||
[currentEngine.name], 1);
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine-name")
|
||||
.setAttribute("value", headerText);
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine")
|
||||
.engine = currentEngine;
|
||||
|
||||
// Update the 'Search for <keywords> with:" header.
|
||||
let headerSearchText =
|
||||
@ -1198,11 +1200,13 @@
|
||||
return; // ignore right clicks.
|
||||
|
||||
let button = event.originalTarget;
|
||||
if (button.localName != "button" || !button.engine)
|
||||
let engine = button.engine || button.parentNode.engine;
|
||||
|
||||
if (!engine)
|
||||
return;
|
||||
|
||||
let searchbar = document.getElementById("searchbar");
|
||||
searchbar.handleSearchCommand(event, button.engine);
|
||||
searchbar.handleSearchCommand(event, engine);
|
||||
]]></handler>
|
||||
|
||||
<handler event="command"><![CDATA[
|
||||
|
@ -115,6 +115,10 @@ static RedirEntry kRedirMap[] = {
|
||||
nsIAboutModule::ENABLE_INDEXED_DB,
|
||||
// Shares an IndexedDB origin with about:loopconversation.
|
||||
"loopconversation" },
|
||||
{ "reader", "chrome://global/content/reader/aboutReader.html",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
||||
};
|
||||
static const int kRedirTotal = ArrayLength(kRedirMap);
|
||||
|
||||
|
@ -115,6 +115,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "loopconversation", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
#if defined(XP_WIN)
|
||||
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
|
||||
#elif defined(XP_MACOSX)
|
||||
|
@ -42,7 +42,11 @@ add_task(function() {
|
||||
FullZoom.enlarge();
|
||||
yield zoomChangePromise;
|
||||
is(parseInt(zoomResetButton.label, 10), 110, "Zoom is changed to 110% for about:mozilla");
|
||||
let attributeChangePromise = promiseAttributeMutation(zoomResetButton, "label", (v) => {
|
||||
return parseInt(v, 10) == 100;
|
||||
});
|
||||
yield promiseTabLoadEvent(tab1, "about:home");
|
||||
yield attributeChangePromise;
|
||||
is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:home");
|
||||
yield promiseTabHistoryNavigation(-1, function() {
|
||||
return parseInt(zoomResetButton.label, 10) == 110;
|
||||
|
@ -461,6 +461,34 @@ function promiseTabHistoryNavigation(aDirection = -1, aConditionFn) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for an attribute on a node to change
|
||||
*
|
||||
* @param aNode Node on which the mutation is expected
|
||||
* @param aAttribute The attribute we're interested in
|
||||
* @param aFilterFn A function to check if the new value is what we want.
|
||||
* @return {Promise} resolved when the requisite mutation shows up.
|
||||
*/
|
||||
function promiseAttributeMutation(aNode, aAttribute, aFilterFn) {
|
||||
return new Promise((resolve, reject) => {
|
||||
info("waiting for mutation of attribute '" + aAttribute + "'.");
|
||||
let obs = new MutationObserver((mutations) => {
|
||||
for (let mut of mutations) {
|
||||
let attr = mut.attributeName;
|
||||
let newValue = mut.target.getAttribute(attr);
|
||||
if (aFilterFn(newValue)) {
|
||||
ok(true, "mutation occurred: attribute '" + attr + "' changed to '" + newValue + "' from '" + mut.oldValue + "'.");
|
||||
obs.disconnect();
|
||||
resolve();
|
||||
} else {
|
||||
info("Ignoring mutation that produced value " + newValue + " because of filter.");
|
||||
}
|
||||
}
|
||||
});
|
||||
obs.observe(aNode, {attributeFilter: [aAttribute]});
|
||||
});
|
||||
}
|
||||
|
||||
function popupShown(aPopup) {
|
||||
return promisePopupEvent(aPopup, "shown");
|
||||
}
|
||||
|
@ -37,6 +37,8 @@
|
||||
<script type="text/javascript" src="loop/shared/js/store.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/conversationStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStates.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/feedbackStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/feedbackViews.js"></script>
|
||||
|
@ -730,6 +730,15 @@ loop.panel = (function(_, mozL10n) {
|
||||
this.stopListening(this.props.store);
|
||||
},
|
||||
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
// If we've just created a room, close the panel - the store will open
|
||||
// the room.
|
||||
if (this.state.pendingCreation &&
|
||||
!nextState.pendingCreation && !nextState.error) {
|
||||
this.closeWindow();
|
||||
}
|
||||
},
|
||||
|
||||
_onStoreStateChanged: function() {
|
||||
this.setState(this.props.store.getStoreState());
|
||||
},
|
||||
@ -747,8 +756,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
handleCreateButtonClick: function() {
|
||||
this.closeWindow();
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.CreateRoom({
|
||||
nameTemplate: mozL10n.get("rooms_default_room_name_template"),
|
||||
roomOwner: this.props.userDisplayName
|
||||
@ -1003,7 +1010,8 @@ loop.panel = (function(_, mozL10n) {
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var roomStore = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop
|
||||
mozLoop: navigator.mozLoop,
|
||||
notifications: notifications
|
||||
});
|
||||
|
||||
React.renderComponent(PanelView({
|
||||
|
@ -730,6 +730,15 @@ loop.panel = (function(_, mozL10n) {
|
||||
this.stopListening(this.props.store);
|
||||
},
|
||||
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
// If we've just created a room, close the panel - the store will open
|
||||
// the room.
|
||||
if (this.state.pendingCreation &&
|
||||
!nextState.pendingCreation && !nextState.error) {
|
||||
this.closeWindow();
|
||||
}
|
||||
},
|
||||
|
||||
_onStoreStateChanged: function() {
|
||||
this.setState(this.props.store.getStoreState());
|
||||
},
|
||||
@ -747,8 +756,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
handleCreateButtonClick: function() {
|
||||
this.closeWindow();
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.CreateRoom({
|
||||
nameTemplate: mozL10n.get("rooms_default_room_name_template"),
|
||||
roomOwner: this.props.userDisplayName
|
||||
@ -1003,7 +1010,8 @@ loop.panel = (function(_, mozL10n) {
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var roomStore = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop
|
||||
mozLoop: navigator.mozLoop,
|
||||
notifications: notifications
|
||||
});
|
||||
|
||||
React.renderComponent(<PanelView
|
||||
|
@ -29,6 +29,8 @@
|
||||
<script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/store.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStates.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/js/client.js"></script>
|
||||
<script type="text/javascript;version=1.8" src="loop/js/contacts.js"></script>
|
||||
|
@ -197,12 +197,23 @@ loop.shared.actions = (function() {
|
||||
roomOwner: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* When a room has been created.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
CreatedRoom: Action.define("createdRoom", {
|
||||
roomToken: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Rooms creation error.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
CreateRoomError: Action.define("createRoomError", {
|
||||
error: Error
|
||||
// There's two types of error possible - one thrown by our code (and Error)
|
||||
// and the other is an Object about the error codes from the server as
|
||||
// returned by the Hawk request.
|
||||
error: Object
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -218,7 +229,10 @@ loop.shared.actions = (function() {
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
DeleteRoomError: Action.define("deleteRoomError", {
|
||||
error: Error
|
||||
// There's two types of error possible - one thrown by our code (and Error)
|
||||
// and the other is an Object about the error codes from the server as
|
||||
// returned by the Hawk request.
|
||||
error: Object
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -21,31 +21,7 @@ loop.store.ActiveRoomStore = (function() {
|
||||
ROOM_FULL: 202
|
||||
};
|
||||
|
||||
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",
|
||||
// Obtaining media from the user
|
||||
MEDIA_WAIT: "room-media-wait",
|
||||
// The room is known to be joined on the loop-server
|
||||
JOINED: "room-joined",
|
||||
// The room is connected to the sdk server.
|
||||
SESSION_CONNECTED: "room-session-connected",
|
||||
// There are participants in the room.
|
||||
HAS_PARTICIPANTS: "room-has-participants",
|
||||
// There was an issue with the room
|
||||
FAILED: "room-failed",
|
||||
// The room is full
|
||||
FULL: "room-full",
|
||||
// The room conversation has ended
|
||||
ENDED: "room-ended",
|
||||
// The window is closing
|
||||
CLOSING: "room-closing"
|
||||
};
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
/**
|
||||
* Active room store.
|
||||
*
|
||||
|
164
browser/components/loop/content/shared/js/fxOSActiveRoomStore.js
Normal file
164
browser/components/loop/content/shared/js/fxOSActiveRoomStore.js
Normal file
@ -0,0 +1,164 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
|
||||
loop.store.FxOSActiveRoomStore = (function() {
|
||||
"use strict";
|
||||
var sharedActions = loop.shared.actions;
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var FxOSActiveRoomStore = loop.store.createStore({
|
||||
actions: [
|
||||
"fetchServerData"
|
||||
],
|
||||
|
||||
initialize: function(options) {
|
||||
if (!options.mozLoop) {
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this._mozLoop = options.mozLoop;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns initial state data for this active room.
|
||||
*/
|
||||
getInitialStoreState: function() {
|
||||
return {
|
||||
roomState: ROOM_STATES.INIT,
|
||||
audioMuted: false,
|
||||
videoMuted: false,
|
||||
failureReason: undefined
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers the actions with the dispatcher that this store is interested
|
||||
* in after the initial setup has been performed.
|
||||
*/
|
||||
_registerPostSetupActions: function() {
|
||||
this.dispatcher.register(this, [
|
||||
"joinRoom"
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute fetchServerData event action from the dispatcher. Although
|
||||
* this is to fetch the server data - for rooms on the standalone client,
|
||||
* we don't actually need to get any data. Therefore we just save the
|
||||
* data that is given to us for when the user chooses to join the room.
|
||||
*
|
||||
* @param {sharedActions.FetchServerData} actionData
|
||||
*/
|
||||
fetchServerData: function(actionData) {
|
||||
if (actionData.windowType !== "room") {
|
||||
// Nothing for us to do here, leave it to other stores.
|
||||
return;
|
||||
}
|
||||
|
||||
this._registerPostSetupActions();
|
||||
|
||||
this.setStoreState({
|
||||
roomToken: actionData.token,
|
||||
roomState: ROOM_STATES.READY
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the action to join to a room.
|
||||
*/
|
||||
joinRoom: function() {
|
||||
// Reset the failure reason if necessary.
|
||||
if (this.getStoreState().failureReason) {
|
||||
this.setStoreState({failureReason: undefined});
|
||||
}
|
||||
|
||||
this._setupOutgoingRoom(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up an outgoing room. It will try launching the activity to let the
|
||||
* FirefoxOS loop app handle the call. If the activity fails:
|
||||
* - if installApp is true, then it'll try to install the FirefoxOS loop
|
||||
* app.
|
||||
* - if installApp is false, then it'll just log and error and fail.
|
||||
*
|
||||
* @param {boolean} installApp
|
||||
*/
|
||||
_setupOutgoingRoom: function(installApp) {
|
||||
var request = new MozActivity({
|
||||
name: "room-call",
|
||||
data: {
|
||||
type: "loop/rToken",
|
||||
token: this.getStoreState("roomToken")
|
||||
}
|
||||
});
|
||||
|
||||
request.onsuccess = function() {};
|
||||
|
||||
request.onerror = (function(event) {
|
||||
if (!installApp) {
|
||||
// This really should not happen ever.
|
||||
console.error(
|
||||
"Unexpected activity launch error after the app has been installed");
|
||||
return;
|
||||
}
|
||||
if (event.target.error.name !== "NO_PROVIDER") {
|
||||
console.error ("Unexpected " + event.target.error.name);
|
||||
return;
|
||||
}
|
||||
// We need to install the FxOS app.
|
||||
this.setStoreState({
|
||||
marketplaceSrc: loop.config.marketplaceUrl,
|
||||
onMarketplaceMessage: this._onMarketplaceMessage.bind(this)
|
||||
});
|
||||
}).bind(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method will handle events generated on the marketplace frame. It
|
||||
* will launch the FirefoxOS loop app installation, and receive the result
|
||||
* of the installation.
|
||||
*
|
||||
* @param {DOMEvent} event
|
||||
*/
|
||||
_onMarketplaceMessage: function(event) {
|
||||
var message = event.data;
|
||||
switch (message.name) {
|
||||
case "loaded":
|
||||
var marketplace = window.document.getElementById("marketplace");
|
||||
// Once we have it loaded, we request the installation of the FxOS
|
||||
// Loop client app. We will be receiving the result of this action
|
||||
// via postMessage from the child iframe.
|
||||
marketplace.contentWindow.postMessage({
|
||||
"name": "install-package",
|
||||
"data": {
|
||||
"product": {
|
||||
"name": loop.config.fxosApp.name,
|
||||
"manifest_url": loop.config.fxosApp.manifestUrl,
|
||||
"is_packaged": true
|
||||
}
|
||||
}
|
||||
}, "*");
|
||||
break;
|
||||
case "install-package":
|
||||
window.removeEventListener("message", this.onMarketplaceMessage);
|
||||
if (message.error) {
|
||||
console.error(message.error.error);
|
||||
return;
|
||||
}
|
||||
// We installed the FxOS app, so we can continue with the call
|
||||
// process.
|
||||
this._setupOutgoingRoom(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return FxOSActiveRoomStore;
|
||||
})();
|
33
browser/components/loop/content/shared/js/roomStates.js
Normal file
33
browser/components/loop/content/shared/js/roomStates.js
Normal file
@ -0,0 +1,33 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
|
||||
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",
|
||||
// Obtaining media from the user
|
||||
MEDIA_WAIT: "room-media-wait",
|
||||
// The room is known to be joined on the loop-server
|
||||
JOINED: "room-joined",
|
||||
// The room is connected to the sdk server.
|
||||
SESSION_CONNECTED: "room-session-connected",
|
||||
// There are participants in the room.
|
||||
HAS_PARTICIPANTS: "room-has-participants",
|
||||
// There was an issue with the room
|
||||
FAILED: "room-failed",
|
||||
// The room is full
|
||||
FULL: "room-full",
|
||||
// The room conversation has ended
|
||||
ENDED: "room-ended",
|
||||
// The window is closing
|
||||
CLOSING: "room-closing"
|
||||
};
|
@ -7,7 +7,7 @@
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
|
||||
(function() {
|
||||
(function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
@ -67,6 +67,8 @@ loop.store = loop.store || {};
|
||||
* - {mozLoop} mozLoop The MozLoop API object.
|
||||
* - {ActiveRoomStore} activeRoomStore An optional substore for active room
|
||||
* state.
|
||||
* - {Notifications} notifications An optional notifications item that is
|
||||
* required if create actions are to be used
|
||||
*/
|
||||
loop.store.RoomStore = loop.store.createStore({
|
||||
/**
|
||||
@ -89,6 +91,7 @@ loop.store = loop.store || {};
|
||||
*/
|
||||
actions: [
|
||||
"createRoom",
|
||||
"createdRoom",
|
||||
"createRoomError",
|
||||
"copyRoomUrl",
|
||||
"deleteRoom",
|
||||
@ -107,6 +110,7 @@ loop.store = loop.store || {};
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this._mozLoop = options.mozLoop;
|
||||
this._notifications = options.notifications;
|
||||
|
||||
if (options.activeRoomStore) {
|
||||
this.activeRoomStore = options.activeRoomStore;
|
||||
@ -257,7 +261,10 @@ loop.store = loop.store || {};
|
||||
* @param {sharedActions.CreateRoom} actionData The new room information.
|
||||
*/
|
||||
createRoom: function(actionData) {
|
||||
this.setStoreState({pendingCreation: true});
|
||||
this.setStoreState({
|
||||
pendingCreation: true,
|
||||
error: null,
|
||||
});
|
||||
|
||||
var roomCreationData = {
|
||||
roomName: this._generateNewRoomName(actionData.nameTemplate),
|
||||
@ -266,19 +273,32 @@ loop.store = loop.store || {};
|
||||
expiresIn: this.defaultExpiresIn
|
||||
};
|
||||
|
||||
this._notifications.remove("create-room-error");
|
||||
|
||||
this._mozLoop.rooms.create(roomCreationData, function(err, createdRoom) {
|
||||
this.setStoreState({pendingCreation: false});
|
||||
if (err) {
|
||||
this.dispatchAction(new sharedActions.CreateRoomError({error: err}));
|
||||
return;
|
||||
}
|
||||
// Opens the newly created room
|
||||
this.dispatchAction(new sharedActions.OpenRoom({
|
||||
|
||||
this.dispatchAction(new sharedActions.CreatedRoom({
|
||||
roomToken: createdRoom.roomToken
|
||||
}));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Executed when a room has been created
|
||||
*/
|
||||
createdRoom: function(actionData) {
|
||||
this.setStoreState({pendingCreation: false});
|
||||
|
||||
// Opens the newly created room
|
||||
this.dispatchAction(new sharedActions.OpenRoom({
|
||||
roomToken: actionData.roomToken
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Executed when a room creation error occurs.
|
||||
*
|
||||
@ -289,6 +309,13 @@ loop.store = loop.store || {};
|
||||
error: actionData.error,
|
||||
pendingCreation: false
|
||||
});
|
||||
|
||||
// XXX Needs a more descriptive error - bug 1109151.
|
||||
this._notifications.set({
|
||||
id: "create-room-error",
|
||||
level: "error",
|
||||
message: mozL10n.get("generic_failure_title")
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -406,4 +433,4 @@ loop.store = loop.store || {};
|
||||
this.setStoreState({error: actionData.error});
|
||||
}
|
||||
});
|
||||
})();
|
||||
})(document.mozL10n || navigator.mozL10n);
|
||||
|
@ -66,22 +66,24 @@ browser.jar:
|
||||
content/browser/loop/shared/img/telefonica@2x.png (content/shared/img/telefonica@2x.png)
|
||||
|
||||
# Shared scripts
|
||||
content/browser/loop/shared/js/actions.js (content/shared/js/actions.js)
|
||||
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
|
||||
content/browser/loop/shared/js/store.js (content/shared/js/store.js)
|
||||
content/browser/loop/shared/js/roomStore.js (content/shared/js/roomStore.js)
|
||||
content/browser/loop/shared/js/activeRoomStore.js (content/shared/js/activeRoomStore.js)
|
||||
content/browser/loop/shared/js/feedbackStore.js (content/shared/js/feedbackStore.js)
|
||||
content/browser/loop/shared/js/dispatcher.js (content/shared/js/dispatcher.js)
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
content/browser/loop/shared/js/models.js (content/shared/js/models.js)
|
||||
content/browser/loop/shared/js/mixins.js (content/shared/js/mixins.js)
|
||||
content/browser/loop/shared/js/otSdkDriver.js (content/shared/js/otSdkDriver.js)
|
||||
content/browser/loop/shared/js/views.js (content/shared/js/views.js)
|
||||
content/browser/loop/shared/js/feedbackViews.js (content/shared/js/feedbackViews.js)
|
||||
content/browser/loop/shared/js/utils.js (content/shared/js/utils.js)
|
||||
content/browser/loop/shared/js/validate.js (content/shared/js/validate.js)
|
||||
content/browser/loop/shared/js/websocket.js (content/shared/js/websocket.js)
|
||||
content/browser/loop/shared/js/actions.js (content/shared/js/actions.js)
|
||||
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
|
||||
content/browser/loop/shared/js/store.js (content/shared/js/store.js)
|
||||
content/browser/loop/shared/js/roomStore.js (content/shared/js/roomStore.js)
|
||||
content/browser/loop/shared/js/roomStates.js (content/shared/js/roomStates.js)
|
||||
content/browser/loop/shared/js/fxOSActiveRoomStore.js (content/shared/js/fxOSActiveRoomStore.js)
|
||||
content/browser/loop/shared/js/activeRoomStore.js (content/shared/js/activeRoomStore.js)
|
||||
content/browser/loop/shared/js/feedbackStore.js (content/shared/js/feedbackStore.js)
|
||||
content/browser/loop/shared/js/dispatcher.js (content/shared/js/dispatcher.js)
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
content/browser/loop/shared/js/models.js (content/shared/js/models.js)
|
||||
content/browser/loop/shared/js/mixins.js (content/shared/js/mixins.js)
|
||||
content/browser/loop/shared/js/otSdkDriver.js (content/shared/js/otSdkDriver.js)
|
||||
content/browser/loop/shared/js/views.js (content/shared/js/views.js)
|
||||
content/browser/loop/shared/js/feedbackViews.js (content/shared/js/feedbackViews.js)
|
||||
content/browser/loop/shared/js/utils.js (content/shared/js/utils.js)
|
||||
content/browser/loop/shared/js/validate.js (content/shared/js/validate.js)
|
||||
content/browser/loop/shared/js/websocket.js (content/shared/js/websocket.js)
|
||||
|
||||
# Shared libs
|
||||
#ifdef DEBUG
|
||||
|
@ -83,6 +83,7 @@ config:
|
||||
@echo "loop.config.learnMoreUrl = '`echo $(LOOP_PRODUCT_HOMEPAGE_URL)`';" >> content/config.js
|
||||
@echo "loop.config.fxosApp = loop.config.fxosApp || {};" >> content/config.js
|
||||
@echo "loop.config.fxosApp.name = 'Loop';" >> content/config.js
|
||||
@echo "loop.config.fxosApp.rooms = true;" >> content/config.js
|
||||
@echo "loop.config.fxosApp.manifestUrl = 'http://fake-market.herokuapp.com/apps/packagedApp/manifest.webapp';" >> content/config.js
|
||||
@echo "loop.config.roomsSupportUrl = 'https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc';" >> content/config.js
|
||||
@echo "loop.config.guestSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';" >> content/config.js
|
||||
|
@ -98,12 +98,15 @@
|
||||
<script type="text/javascript" src="shared/js/websocket.js"></script>
|
||||
<script type="text/javascript" src="shared/js/otSdkDriver.js"></script>
|
||||
<script type="text/javascript" src="shared/js/store.js"></script>
|
||||
<script type="text/javascript" src="shared/js/roomStates.js"></script>
|
||||
<script type="text/javascript" src="shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script type="text/javascript" src="shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="shared/js/feedbackStore.js"></script>
|
||||
<script type="text/javascript" src="shared/js/feedbackViews.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/standaloneMozLoop.js"></script>
|
||||
<script type="text/javascript" src="js/fxOSMarketplace.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneRoomViews.js"></script>
|
||||
<script type="text/javascript" src="js/webapp.js"></script>
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.fxOSMarketplaceViews = (function() {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplaceView = React.createClass({displayName: 'FxOSHiddenMarketplaceView',
|
||||
render: function() {
|
||||
return React.DOM.iframe({id: "marketplace", src: this.props.marketplaceSrc, hidden: true});
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
// XXX Bug 1097703: This should be changed to an action when the old
|
||||
// style URLs go away.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
FxOSHiddenMarketplaceView: FxOSHiddenMarketplaceView
|
||||
};
|
||||
|
||||
})();
|
@ -0,0 +1,37 @@
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.fxOSMarketplaceViews = (function() {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplaceView = React.createClass({
|
||||
render: function() {
|
||||
return <iframe id="marketplace" src={this.props.marketplaceSrc} hidden/>;
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
// XXX Bug 1097703: This should be changed to an action when the old
|
||||
// style URLs go away.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
FxOSHiddenMarketplaceView: FxOSHiddenMarketplaceView
|
||||
};
|
||||
|
||||
})();
|
@ -20,8 +20,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
var StandaloneRoomInfoArea = React.createClass({displayName: 'StandaloneRoomInfoArea',
|
||||
propTypes: {
|
||||
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired,
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired
|
||||
},
|
||||
@ -189,8 +191,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
@ -379,6 +383,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
enableHangup: this._roomIsActive()})
|
||||
)
|
||||
),
|
||||
loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView({
|
||||
marketplaceSrc: this.state.marketplaceSrc,
|
||||
onMarketplaceMessage: this.state.onMarketplaceMessage}),
|
||||
StandaloneRoomFooter(null)
|
||||
)
|
||||
);
|
||||
|
@ -20,8 +20,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
var StandaloneRoomInfoArea = React.createClass({
|
||||
propTypes: {
|
||||
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired,
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired
|
||||
},
|
||||
@ -189,8 +191,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
@ -379,6 +383,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
enableHangup={this._roomIsActive()} />
|
||||
</div>
|
||||
</div>
|
||||
<loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView
|
||||
marketplaceSrc={this.state.marketplaceSrc}
|
||||
onMarketplaceMessage={this.state.onMarketplaceMessage} />
|
||||
<StandaloneRoomFooter />
|
||||
</div>
|
||||
);
|
||||
|
@ -127,32 +127,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplace = React.createClass({displayName: 'FxOSHiddenMarketplace',
|
||||
render: function() {
|
||||
return React.DOM.iframe({id: "marketplace", src: this.props.marketplaceSrc, hidden: true});
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var FxOSConversationModel = Backbone.Model.extend({
|
||||
setupOutgoingCall: function() {
|
||||
setupOutgoingCall: function(selectedCallType) {
|
||||
if (selectedCallType) {
|
||||
this.set("selectedCallType", selectedCallType);
|
||||
}
|
||||
// The FxOS Loop client exposes a "loop-call" activity. If we get the
|
||||
// activity onerror callback it means that there is no "loop-call"
|
||||
// activity handler available and so no FxOS Loop client installed.
|
||||
@ -162,7 +141,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
type: "loop/token",
|
||||
token: this.get("loopToken"),
|
||||
callerId: this.get("callerId"),
|
||||
callType: this.get("callType")
|
||||
video: this.get("selectedCallType") === "audio-video"
|
||||
}
|
||||
});
|
||||
|
||||
@ -565,7 +544,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dangerouslySetInnerHTML: {__html: tosHTML}})
|
||||
),
|
||||
|
||||
FxOSHiddenMarketplace({
|
||||
loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView({
|
||||
marketplaceSrc: this.state.marketplaceSrc,
|
||||
onMarketplaceMessage: this.state.onMarketplaceMessage}),
|
||||
|
||||
@ -959,8 +938,10 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
feedbackStore: React.PropTypes.instanceOf(loop.store.FeedbackStore)
|
||||
},
|
||||
@ -1036,14 +1017,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
|
||||
// Older non-flux based items.
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var conversation
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
conversation = new FxOSConversationModel();
|
||||
} else {
|
||||
conversation = new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
}
|
||||
|
||||
var feedbackApiClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
@ -1061,6 +1034,29 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dispatcher: dispatcher,
|
||||
sdk: OT
|
||||
});
|
||||
var conversation;
|
||||
var activeRoomStore;
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
if (loop.config.fxosApp) {
|
||||
conversation = new FxOSConversationModel();
|
||||
if (loop.config.fxosApp.rooms) {
|
||||
activeRoomStore = new loop.store.FxOSActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conversation = conversation ||
|
||||
new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
activeRoomStore = activeRoomStore ||
|
||||
new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
|
||||
var feedbackClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
product: loop.config.feedbackProductName,
|
||||
@ -1075,10 +1071,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
var feedbackStore = new loop.store.FeedbackStore(dispatcher, {
|
||||
feedbackClient: feedbackClient
|
||||
});
|
||||
|
@ -127,32 +127,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplace = React.createClass({
|
||||
render: function() {
|
||||
return <iframe id="marketplace" src={this.props.marketplaceSrc} hidden/>;
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var FxOSConversationModel = Backbone.Model.extend({
|
||||
setupOutgoingCall: function() {
|
||||
setupOutgoingCall: function(selectedCallType) {
|
||||
if (selectedCallType) {
|
||||
this.set("selectedCallType", selectedCallType);
|
||||
}
|
||||
// The FxOS Loop client exposes a "loop-call" activity. If we get the
|
||||
// activity onerror callback it means that there is no "loop-call"
|
||||
// activity handler available and so no FxOS Loop client installed.
|
||||
@ -162,7 +141,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
type: "loop/token",
|
||||
token: this.get("loopToken"),
|
||||
callerId: this.get("callerId"),
|
||||
callType: this.get("callType")
|
||||
video: this.get("selectedCallType") === "audio-video"
|
||||
}
|
||||
});
|
||||
|
||||
@ -565,7 +544,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dangerouslySetInnerHTML={{__html: tosHTML}}></p>
|
||||
</div>
|
||||
|
||||
<FxOSHiddenMarketplace
|
||||
<loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView
|
||||
marketplaceSrc={this.state.marketplaceSrc}
|
||||
onMarketplaceMessage= {this.state.onMarketplaceMessage} />
|
||||
|
||||
@ -959,8 +938,10 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
feedbackStore: React.PropTypes.instanceOf(loop.store.FeedbackStore)
|
||||
},
|
||||
@ -1036,14 +1017,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
|
||||
// Older non-flux based items.
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var conversation
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
conversation = new FxOSConversationModel();
|
||||
} else {
|
||||
conversation = new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
}
|
||||
|
||||
var feedbackApiClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
@ -1061,6 +1034,29 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dispatcher: dispatcher,
|
||||
sdk: OT
|
||||
});
|
||||
var conversation;
|
||||
var activeRoomStore;
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
if (loop.config.fxosApp) {
|
||||
conversation = new FxOSConversationModel();
|
||||
if (loop.config.fxosApp.rooms) {
|
||||
activeRoomStore = new loop.store.FxOSActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conversation = conversation ||
|
||||
new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
activeRoomStore = activeRoomStore ||
|
||||
new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
|
||||
var feedbackClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
product: loop.config.feedbackProductName,
|
||||
@ -1075,10 +1071,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
var feedbackStore = new loop.store.FeedbackStore(dispatcher, {
|
||||
feedbackClient: feedbackClient
|
||||
});
|
||||
|
@ -30,6 +30,7 @@ function getConfigFile(req, res) {
|
||||
"loop.config.legalWebsiteUrl = 'https://www.mozilla.org/about/legal/terms/firefox-hello/';",
|
||||
"loop.config.fxosApp = loop.config.fxosApp || {};",
|
||||
"loop.config.fxosApp.name = 'Loop';",
|
||||
"loop.config.fxosApp.rooms = true;",
|
||||
"loop.config.fxosApp.manifestUrl = 'http://fake-market.herokuapp.com/apps/packagedApp/manifest.webapp';",
|
||||
"loop.config.roomsSupportUrl = 'https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc';",
|
||||
"loop.config.guestSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';",
|
||||
|
@ -52,6 +52,8 @@
|
||||
<script src="../../content/shared/js/store.js"></script>
|
||||
<script src="../../content/shared/js/conversationStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStates.js"></script>
|
||||
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackViews.js"></script>
|
||||
|
@ -946,11 +946,15 @@ describe("loop.panel", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
it("should close the panel when 'Start a Conversation' is clicked",
|
||||
it("should close the panel once a room is created and there is no error",
|
||||
function() {
|
||||
var view = createTestComponent();
|
||||
|
||||
TestUtils.Simulate.click(view.getDOMNode().querySelector("button"));
|
||||
roomStore.setStoreState({pendingCreation: true});
|
||||
|
||||
sinon.assert.notCalled(fakeWindow.close);
|
||||
|
||||
roomStore.setStoreState({pendingCreation: false});
|
||||
|
||||
sinon.assert.calledOnce(fakeWindow.close);
|
||||
});
|
||||
|
212
browser/components/loop/test/shared/fxOSActiveRoomStore_test.js
Normal file
212
browser/components/loop/test/shared/fxOSActiveRoomStore_test.js
Normal file
@ -0,0 +1,212 @@
|
||||
/* global chai, loop */
|
||||
|
||||
var expect = chai.expect;
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
describe("loop.store.FxOSActiveRoomStore", function () {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var sandbox;
|
||||
var dispatcher;
|
||||
var fakeMozLoop;
|
||||
var store;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.useFakeTimers();
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
fakeMozLoop = {
|
||||
setLoopPref: sandbox.stub(),
|
||||
rooms: {
|
||||
join: sinon.stub()
|
||||
}
|
||||
};
|
||||
|
||||
store = new loop.store.FxOSActiveRoomStore(dispatcher, {
|
||||
mozLoop: fakeMozLoop
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - constructor", function() {
|
||||
it("should throw an error if mozLoop is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.FxOSActiveRoomStore(dispatcher);
|
||||
}).to.Throw(/mozLoop/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - fetchServerData", function() {
|
||||
it("should save the token", function() {
|
||||
store.fetchServerData(new sharedActions.FetchServerData({
|
||||
windowType: "room",
|
||||
token: "fakeToken"
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().roomToken).eql("fakeToken");
|
||||
});
|
||||
|
||||
it("should set the state to `READY`", function() {
|
||||
store.fetchServerData(new sharedActions.FetchServerData({
|
||||
windowType: "room",
|
||||
token: "fakeToken"
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().roomState).eql(ROOM_STATES.READY);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - setupOutgoingRoom", function() {
|
||||
var realMozActivity;
|
||||
var _activityDetail;
|
||||
var _onerror;
|
||||
|
||||
function fireError(errorName) {
|
||||
_onerror({
|
||||
target: {
|
||||
error: {
|
||||
name: errorName
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
before(function() {
|
||||
realMozActivity = window.MozActivity;
|
||||
|
||||
window.MozActivity = function(activityDetail) {
|
||||
_activityDetail = activityDetail;
|
||||
return {
|
||||
set onerror(cbk) {
|
||||
_onerror = cbk;
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
after(function() {
|
||||
window.MozActivity = realMozActivity;
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(console, "error");
|
||||
_activityDetail = undefined;
|
||||
_onerror = undefined;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it("should reset failureReason", function() {
|
||||
store.setStoreState({failureReason: "Test"});
|
||||
|
||||
store.joinRoom();
|
||||
|
||||
expect(store.getStoreState().failureReason).eql(undefined);
|
||||
});
|
||||
|
||||
it("should create an activity", function() {
|
||||
store.setStoreState({
|
||||
roomToken: "fakeToken",
|
||||
token: "fakeToken"
|
||||
});
|
||||
|
||||
expect(_activityDetail).to.not.exist;
|
||||
store.joinRoom();
|
||||
expect(_activityDetail).to.exist;
|
||||
expect(_activityDetail).eql({
|
||||
name: "room-call",
|
||||
data: {
|
||||
type: "loop/rToken",
|
||||
token: "fakeToken"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should change the store state when the activity fail with a " +
|
||||
"NO_PROVIDER error", function() {
|
||||
|
||||
loop.config = {
|
||||
marketplaceUrl: "http://market/"
|
||||
};
|
||||
store._setupOutgoingRoom(true);
|
||||
fireError("NO_PROVIDER");
|
||||
expect(store.getStoreState().marketplaceSrc).eql(
|
||||
loop.config.marketplaceUrl
|
||||
);
|
||||
});
|
||||
|
||||
it("should log an error when the activity fail with a error different " +
|
||||
"from NO_PROVIDER", function() {
|
||||
loop.config = {
|
||||
marketplaceUrl: "http://market/"
|
||||
};
|
||||
store._setupOutgoingRoom(true);
|
||||
fireError("whatever");
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error, "Unexpected whatever");
|
||||
});
|
||||
|
||||
it("should log an error and exist if an activity error is received when " +
|
||||
"the parameter is false ", function() {
|
||||
loop.config = {
|
||||
marketplaceUrl: "http://market/"
|
||||
};
|
||||
store._setupOutgoingRoom(false);
|
||||
fireError("whatever");
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error,
|
||||
"Unexpected activity launch error after the app has been installed");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - _onMarketplaceMessage", function() {
|
||||
var setupOutgoingRoom;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(console, "error");
|
||||
setupOutgoingRoom = sandbox.stub(store, "_setupOutgoingRoom");
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
setupOutgoingRoom.restore();
|
||||
});
|
||||
|
||||
it("We should call trigger a FxOS outgoing call if we get " +
|
||||
"install-package message without error", function() {
|
||||
|
||||
sinon.assert.notCalled(setupOutgoingRoom);
|
||||
store._onMarketplaceMessage({
|
||||
data: {
|
||||
name: "install-package"
|
||||
}
|
||||
});
|
||||
sinon.assert.calledOnce(setupOutgoingRoom);
|
||||
});
|
||||
|
||||
it("We should log an error if we get install-package message with an " +
|
||||
"error", function() {
|
||||
|
||||
sinon.assert.notCalled(setupOutgoingRoom);
|
||||
store._onMarketplaceMessage({
|
||||
data: {
|
||||
name: "install-package",
|
||||
error: { error: "whatever error" }
|
||||
}
|
||||
});
|
||||
sinon.assert.notCalled(setupOutgoingRoom);
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error, "whatever error");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -50,6 +50,8 @@
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/otSdkDriver.js"></script>
|
||||
<script src="../../content/shared/js/store.js"></script>
|
||||
<script src="../../content/shared/js/roomStates.js"></script>
|
||||
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStore.js"></script>
|
||||
<script src="../../content/shared/js/conversationStore.js"></script>
|
||||
@ -67,6 +69,7 @@
|
||||
<script src="validate_test.js"></script>
|
||||
<script src="dispatcher_test.js"></script>
|
||||
<script src="activeRoomStore_test.js"></script>
|
||||
<script src="fxOSActiveRoomStore_test.js"></script>
|
||||
<script src="conversationStore_test.js"></script>
|
||||
<script src="feedbackStore_test.js"></script>
|
||||
<script src="otSdkDriver_test.js"></script>
|
||||
|
@ -64,7 +64,7 @@ describe("loop.store.RoomStore", function () {
|
||||
});
|
||||
|
||||
describe("constructed", function() {
|
||||
var fakeMozLoop, store;
|
||||
var fakeMozLoop, fakeNotifications, store;
|
||||
|
||||
var defaultStoreState = {
|
||||
error: undefined,
|
||||
@ -86,7 +86,14 @@ describe("loop.store.RoomStore", function () {
|
||||
on: sandbox.stub()
|
||||
}
|
||||
};
|
||||
store = new loop.store.RoomStore(dispatcher, {mozLoop: fakeMozLoop});
|
||||
fakeNotifications = {
|
||||
set: sinon.stub(),
|
||||
remove: sinon.stub()
|
||||
};
|
||||
store = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: fakeMozLoop,
|
||||
notifications: fakeNotifications
|
||||
});
|
||||
store.setStoreState(defaultStoreState);
|
||||
});
|
||||
|
||||
@ -153,7 +160,7 @@ describe("loop.store.RoomStore", function () {
|
||||
|
||||
expect(store.getStoreState().rooms).to.have.length.of(0);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe("#findNextAvailableRoomNumber", function() {
|
||||
@ -203,9 +210,20 @@ describe("loop.store.RoomStore", function () {
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
store.setStoreState({pendingCreation: false, rooms: []});
|
||||
});
|
||||
|
||||
it("should clear any existing room errors", function() {
|
||||
sandbox.stub(fakeMozLoop.rooms, "create");
|
||||
|
||||
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
|
||||
|
||||
sinon.assert.calledOnce(fakeNotifications.remove);
|
||||
sinon.assert.calledWithExactly(fakeNotifications.remove,
|
||||
"create-room-error");
|
||||
});
|
||||
|
||||
it("should request creation of a new room", function() {
|
||||
sandbox.stub(fakeMozLoop.rooms, "create");
|
||||
|
||||
@ -219,17 +237,6 @@ describe("loop.store.RoomStore", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it("should store any creation encountered error", function() {
|
||||
var err = new Error("fake");
|
||||
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
|
||||
cb(err);
|
||||
});
|
||||
|
||||
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
|
||||
|
||||
expect(store.getStoreState().error).eql(err);
|
||||
});
|
||||
|
||||
it("should switch the pendingCreation state flag to true", function() {
|
||||
sandbox.stub(fakeMozLoop.rooms, "create");
|
||||
|
||||
@ -238,33 +245,91 @@ describe("loop.store.RoomStore", function () {
|
||||
expect(store.getStoreState().pendingCreation).eql(true);
|
||||
});
|
||||
|
||||
it("should switch the pendingCreation state flag to false once the " +
|
||||
"operation is done", function() {
|
||||
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
|
||||
cb(null, {roomToken: "fakeToken"});
|
||||
});
|
||||
|
||||
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
|
||||
|
||||
expect(store.getStoreState().pendingCreation).eql(false);
|
||||
});
|
||||
|
||||
it("should dispatch an OpenRoom action once the operation is done",
|
||||
it("should dispatch a CreatedRoom action once the operation is done",
|
||||
function() {
|
||||
var dispatch = sandbox.stub(dispatcher, "dispatch");
|
||||
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
|
||||
cb(null, {roomToken: "fakeToken"});
|
||||
});
|
||||
|
||||
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch, new sharedActions.OpenRoom({
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.CreatedRoom({
|
||||
roomToken: "fakeToken"
|
||||
}));
|
||||
});
|
||||
|
||||
it("should dispatch a CreateRoomError action if the operation fails",
|
||||
function() {
|
||||
var err = new Error("fake");
|
||||
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
|
||||
cb(err);
|
||||
});
|
||||
|
||||
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.CreateRoomError({
|
||||
error: err
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createdRoom", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
});
|
||||
|
||||
it("should switch the pendingCreation state flag to false", function() {
|
||||
store.setStoreState({pendingCreation:true});
|
||||
|
||||
store.createdRoom(new sharedActions.CreatedRoom({
|
||||
roomToken: "fakeToken"
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().pendingCreation).eql(false);
|
||||
});
|
||||
|
||||
it("should dispatch an OpenRoom action once the operation is done",
|
||||
function() {
|
||||
store.createdRoom(new sharedActions.CreatedRoom({
|
||||
roomToken: "fakeToken"
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.OpenRoom({
|
||||
roomToken: "fakeToken"
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createRoomError", function() {
|
||||
it("should switch the pendingCreation state flag to false", function() {
|
||||
store.setStoreState({pendingCreation:true});
|
||||
|
||||
store.createRoomError({
|
||||
error: new Error("fake")
|
||||
});
|
||||
|
||||
expect(store.getStoreState().pendingCreation).eql(false);
|
||||
});
|
||||
|
||||
it("should set a notification", function() {
|
||||
store.createRoomError({
|
||||
error: new Error("fake")
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(fakeNotifications.set);
|
||||
sinon.assert.calledWithMatch(fakeNotifications.set, {
|
||||
id: "create-room-error",
|
||||
level: "error"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#copyRoomUrl", function() {
|
||||
it("should copy the room URL", function() {
|
||||
var copyString = sandbox.stub(fakeMozLoop, "copyString");
|
||||
|
@ -48,6 +48,8 @@
|
||||
<script src="../../content/shared/js/validate.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/store.js"></script>
|
||||
<script src="../../content/shared/js/roomStates.js"></script>
|
||||
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackViews.js"></script>
|
||||
@ -56,6 +58,7 @@
|
||||
<script src="../../standalone/content/js/standaloneAppStore.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneClient.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneMozLoop.js"></script>
|
||||
<script src="../../standalone/content/js/fxOSMarketplace.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneRoomViews.js"></script>
|
||||
<script src="../../standalone/content/js/webapp.js"></script>
|
||||
<!-- Test scripts -->
|
||||
|
@ -332,6 +332,26 @@ describe("loop.standaloneRoomViews", function() {
|
||||
.not.eql(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Marketplace hidden iframe", function() {
|
||||
|
||||
it("should set src when the store state change",
|
||||
function(done) {
|
||||
|
||||
var marketplace = view.getDOMNode().querySelector("#marketplace");
|
||||
expect(marketplace.src).to.be.equal("");
|
||||
|
||||
activeRoomStore.setStoreState({
|
||||
marketplaceSrc: "http://market/",
|
||||
onMarketplaceMessage: function () {}
|
||||
});
|
||||
|
||||
view.forceUpdate(function() {
|
||||
expect(marketplace.src).to.be.equal("http://market/");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1169,8 +1169,7 @@ describe("loop.webapp", function() {
|
||||
before(function() {
|
||||
model = new loop.webapp.FxOSConversationModel({
|
||||
loopToken: "fakeToken",
|
||||
callerId: "callerId",
|
||||
callType: "callType"
|
||||
callerId: "callerId"
|
||||
});
|
||||
|
||||
realMozActivity = window.MozActivity;
|
||||
@ -1214,13 +1213,44 @@ describe("loop.webapp", function() {
|
||||
|
||||
beforeEach(function() {
|
||||
trigger = sandbox.stub(model, "trigger");
|
||||
_activityProps = undefined;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
trigger.restore();
|
||||
});
|
||||
|
||||
it("Activity properties", function() {
|
||||
it("Activity properties with video call", function() {
|
||||
expect(_activityProps).to.not.exist;
|
||||
model.setupOutgoingCall("audio-video");
|
||||
expect(_activityProps).to.exist;
|
||||
expect(_activityProps).eql({
|
||||
name: "loop-call",
|
||||
data: {
|
||||
type: "loop/token",
|
||||
token: "fakeToken",
|
||||
callerId: "callerId",
|
||||
video: true
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("Activity properties with audio call", function() {
|
||||
expect(_activityProps).to.not.exist;
|
||||
model.setupOutgoingCall("audio");
|
||||
expect(_activityProps).to.exist;
|
||||
expect(_activityProps).eql({
|
||||
name: "loop-call",
|
||||
data: {
|
||||
type: "loop/token",
|
||||
token: "fakeToken",
|
||||
callerId: "callerId",
|
||||
video: false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("Activity properties by default", function() {
|
||||
expect(_activityProps).to.not.exist;
|
||||
model.setupOutgoingCall();
|
||||
expect(_activityProps).to.exist;
|
||||
@ -1230,7 +1260,7 @@ describe("loop.webapp", function() {
|
||||
type: "loop/token",
|
||||
token: "fakeToken",
|
||||
callerId: "callerId",
|
||||
callType: "callType"
|
||||
video: false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -44,12 +44,15 @@
|
||||
<script src="../content/shared/js/store.js"></script>
|
||||
<script src="../content/shared/js/roomStore.js"></script>
|
||||
<script src="../content/shared/js/conversationStore.js"></script>
|
||||
<script src="../content/shared/js/roomStates.js"></script>
|
||||
<script src="../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../content/shared/js/feedbackStore.js"></script>
|
||||
<script src="../content/shared/js/feedbackViews.js"></script>
|
||||
<script src="../content/js/roomViews.js"></script>
|
||||
<script src="../content/js/conversationViews.js"></script>
|
||||
<script src="../content/js/client.js"></script>
|
||||
<script src="../content/js/fxOSMarketplace.js"></script>
|
||||
<script src="../content/js/webapp.js"></script>
|
||||
<script src="../content/js/standaloneRoomViews.js"></script>
|
||||
<script type="text/javascript;version=1.8" src="../content/js/contacts.js"></script>
|
||||
|
@ -462,6 +462,17 @@ SettingsManager.prototype = {
|
||||
|
||||
cleanup: function() {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
// At this point, the window is dying, so there's nothing left
|
||||
// that we could do with our lock. Go ahead and run finalize on
|
||||
// it to make sure changes are commited.
|
||||
for (let i = 0; i < this._locks.length; ++i) {
|
||||
if (DEBUG) debug("Lock alive at destroy, finalizing: " + this._locks[i]);
|
||||
// Due to bug 1105511 we should be able to send this without
|
||||
// cached principals. However, this is scary because any iframe
|
||||
// in the process could run this?
|
||||
cpmm.sendAsyncMessage("Settings:Finalize",
|
||||
{lockID: this._locks[i]});
|
||||
}
|
||||
cpmm.removeMessageListener("Settings:Change:Return:OK", this);
|
||||
mrm.unregisterStrongReporter(this);
|
||||
this.innerWindowID = null;
|
||||
|
@ -867,6 +867,11 @@ inDOMUtils::CssPropertyIsValid(const nsAString& aPropertyName,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (propertyID == eCSSPropertyExtra_variable) {
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get a parser, parse the property.
|
||||
nsCSSParser parser;
|
||||
*_retval = parser.IsValueValidForProperty(propertyID, aPropertyValue);
|
||||
|
@ -74,6 +74,11 @@
|
||||
property: "content",
|
||||
value: "\"hello\"",
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
property: "color",
|
||||
value: "var(--some-kind-of-green)",
|
||||
expected: true
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -349,6 +349,8 @@ var BrowserApp = {
|
||||
#endif
|
||||
#ifdef NIGHTLY_BUILD
|
||||
WebcompatReporter.init();
|
||||
Telemetry.addData("TRACKING_PROTECTION_ENABLED",
|
||||
Services.prefs.getBoolPref("privacy.trackingprotection.enabled"));
|
||||
#endif
|
||||
} catch(ex) { console.log(ex); }
|
||||
}, false);
|
||||
@ -6788,15 +6790,18 @@ var IdentityHandler = {
|
||||
|
||||
getTrackingMode: function getTrackingMode(aState) {
|
||||
if (aState & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
|
||||
Telemetry.addData("TRACKING_PROTECTION_SHIELD", 2);
|
||||
return this.TRACKING_MODE_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
// Only show an indicator for loaded tracking content if the pref to block it is enabled
|
||||
if ((aState & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) &&
|
||||
Services.prefs.getBoolPref("privacy.trackingprotection.enabled")) {
|
||||
Telemetry.addData("TRACKING_PROTECTION_SHIELD", 1);
|
||||
return this.TRACKING_MODE_CONTENT_LOADED;
|
||||
}
|
||||
|
||||
Telemetry.addData("TRACKING_PROTECTION_SHIELD", 0);
|
||||
return this.TRACKING_MODE_UNKNOWN;
|
||||
},
|
||||
|
||||
|
@ -254,6 +254,11 @@ this.Download.prototype = {
|
||||
* Indicates whether, at this time, there is any partially downloaded data
|
||||
* that can be used when restarting a failed or canceled download.
|
||||
*
|
||||
* Even if the download has partial data on disk, hasPartialData will be false
|
||||
* if that data cannot be used to restart the download. In order to determine
|
||||
* if a part file is being used which contains partial data the
|
||||
* Download.target.partFilePath should be checked.
|
||||
*
|
||||
* This property is relevant while the download is in progress, and also if it
|
||||
* failed or has been canceled. If the download has been completed
|
||||
* successfully, this property is always false.
|
||||
@ -263,6 +268,13 @@ this.Download.prototype = {
|
||||
*/
|
||||
hasPartialData: false,
|
||||
|
||||
/**
|
||||
* Indicates whether, at this time, there is any data that has been blocked.
|
||||
* Since reputation blocking takes place after the download has fully
|
||||
* completed a value of true also indicates 100% of the data is present.
|
||||
*/
|
||||
hasBlockedData: false,
|
||||
|
||||
/**
|
||||
* This can be set to a function that is called after other properties change.
|
||||
*/
|
||||
@ -353,11 +365,18 @@ this.Download.prototype = {
|
||||
message: "Cannot start after finalization."}));
|
||||
}
|
||||
|
||||
if (this.error && this.error.becauseBlockedByReputationCheck) {
|
||||
return Promise.reject(new DownloadError({
|
||||
message: "Cannot start after being blocked " +
|
||||
"by a reputation check."}));
|
||||
}
|
||||
|
||||
// Initialize all the status properties for a new or restarted download.
|
||||
this.stopped = false;
|
||||
this.canceled = false;
|
||||
this.error = null;
|
||||
this.hasProgress = false;
|
||||
this.hasBlockedData = false;
|
||||
this.progress = 0;
|
||||
this.totalBytes = 0;
|
||||
this.currentBytes = 0;
|
||||
@ -448,20 +467,16 @@ this.Download.prototype = {
|
||||
yield this.saver.execute(DS_setProgressBytes.bind(this),
|
||||
DS_setProperties.bind(this));
|
||||
|
||||
// Check for application reputation, which requires the entire file to
|
||||
// be downloaded. After that, check for the last time if the download
|
||||
// has been canceled. Both cases require the target file to be deleted,
|
||||
// thus we process both in the same block of code.
|
||||
if ((yield DownloadIntegration.shouldBlockForReputationCheck(this)) ||
|
||||
this._promiseCanceled) {
|
||||
// Check for the last time if the download has been canceled.
|
||||
if (this._promiseCanceled) {
|
||||
try {
|
||||
yield OS.File.remove(this.target.path);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
// If this is actually a cancellation, this exception will be changed
|
||||
// in the catch block below.
|
||||
throw new DownloadError({ becauseBlockedByReputationCheck: true });
|
||||
|
||||
// Cancellation exceptions will be changed in the catch block below.
|
||||
throw new DownloadError();
|
||||
}
|
||||
|
||||
// Update the status properties for a successful download.
|
||||
@ -513,24 +528,7 @@ this.Download.prototype = {
|
||||
this.speed = 0;
|
||||
this._notifyChange();
|
||||
if (this.succeeded) {
|
||||
yield DownloadIntegration.downloadDone(this);
|
||||
|
||||
this._deferSucceeded.resolve();
|
||||
|
||||
if (this.launchWhenSucceeded) {
|
||||
this.launch().then(null, Cu.reportError);
|
||||
|
||||
// Always schedule files to be deleted at the end of the private browsing
|
||||
// mode, regardless of the value of the pref.
|
||||
if (this.source.isPrivate) {
|
||||
gExternalAppLauncher.deleteTemporaryPrivateFileWhenPossible(
|
||||
new FileUtils.File(this.target.path));
|
||||
} else if (Services.prefs.getBoolPref(
|
||||
"browser.helperApps.deleteTempFileOnExit")) {
|
||||
gExternalAppLauncher.deleteTemporaryFileOnExit(
|
||||
new FileUtils.File(this.target.path));
|
||||
}
|
||||
}
|
||||
yield this._succeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -541,6 +539,133 @@ this.Download.prototype = {
|
||||
return currentAttempt;
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform the actions necessary when a Download succeeds.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the steps to take after success have completed.
|
||||
* @rejects JavaScript exception if any of the operations failed.
|
||||
*/
|
||||
_succeed: Task.async(function* () {
|
||||
yield DownloadIntegration.downloadDone(this);
|
||||
|
||||
this._deferSucceeded.resolve();
|
||||
|
||||
if (this.launchWhenSucceeded) {
|
||||
this.launch().then(null, Cu.reportError);
|
||||
|
||||
// Always schedule files to be deleted at the end of the private browsing
|
||||
// mode, regardless of the value of the pref.
|
||||
if (this.source.isPrivate) {
|
||||
gExternalAppLauncher.deleteTemporaryPrivateFileWhenPossible(
|
||||
new FileUtils.File(this.target.path));
|
||||
} else if (Services.prefs.getBoolPref(
|
||||
"browser.helperApps.deleteTempFileOnExit")) {
|
||||
gExternalAppLauncher.deleteTemporaryFileOnExit(
|
||||
new FileUtils.File(this.target.path));
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* When a request to unblock the download is received, contains a promise
|
||||
* that will be resolved when the unblock request is completed. This property
|
||||
* will then continue to hold the promise indefinitely.
|
||||
*/
|
||||
_promiseUnblock: null,
|
||||
|
||||
/**
|
||||
* When a request to confirm the block of the download is received, contains
|
||||
* a promise that will be resolved when cleaning up the download has
|
||||
* completed. This property will then continue to hold the promise
|
||||
* indefinitely.
|
||||
*/
|
||||
_promiseConfirmBlock: null,
|
||||
|
||||
/**
|
||||
* Unblocks a download which had been blocked by reputation.
|
||||
*
|
||||
* The file will be moved out of quarantine and the download will be
|
||||
* marked as succeeded.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the Download has been unblocked and succeeded.
|
||||
* @rejects JavaScript exception if any of the operations failed.
|
||||
*/
|
||||
unblock: function() {
|
||||
if (this._promiseUnblock) {
|
||||
return this._promiseUnblock;
|
||||
}
|
||||
|
||||
if (this._promiseConfirmBlock) {
|
||||
return Promise.reject(new Error(
|
||||
"Download block has been confirmed, cannot unblock."));
|
||||
}
|
||||
|
||||
if (!this.hasBlockedData) {
|
||||
return Promise.reject(new Error(
|
||||
"unblock may only be called on Downloads with blocked data."));
|
||||
}
|
||||
|
||||
this._promiseUnblock = Task.spawn(function* () {
|
||||
try {
|
||||
yield OS.File.move(this.target.partFilePath, this.target.path);
|
||||
} catch (ex) {
|
||||
yield this.refresh();
|
||||
this._promiseUnblock = null;
|
||||
throw ex;
|
||||
}
|
||||
|
||||
this.succeeded = true;
|
||||
this.hasBlockedData = false;
|
||||
this._notifyChange();
|
||||
yield this._succeed();
|
||||
}.bind(this));
|
||||
|
||||
return this._promiseUnblock;
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirms that a blocked download should be cleaned up.
|
||||
*
|
||||
* If a download was blocked but retained on disk this method can be used
|
||||
* to remove the file.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the Download's data has been removed.
|
||||
* @rejects JavaScript exception if any of the operations failed.
|
||||
*/
|
||||
confirmBlock: function() {
|
||||
if (this._promiseConfirmBlock) {
|
||||
return this._promiseConfirmBlock;
|
||||
}
|
||||
|
||||
if (this._promiseUnblock) {
|
||||
return Promise.reject(new Error(
|
||||
"Download is being unblocked, cannot confirmBlock."));
|
||||
}
|
||||
|
||||
if (!this.hasBlockedData) {
|
||||
return Promise.reject(new Error(
|
||||
"confirmBlock may only be called on Downloads with blocked data."));
|
||||
}
|
||||
|
||||
this._promiseConfirmBlock = Task.spawn(function* () {
|
||||
try {
|
||||
yield OS.File.remove(this.target.partFilePath);
|
||||
} catch (ex) {
|
||||
yield this.refresh();
|
||||
this._promiseConfirmBlock = null;
|
||||
throw ex;
|
||||
}
|
||||
|
||||
this.hasBlockedData = false;
|
||||
this._notifyChange();
|
||||
}.bind(this));
|
||||
|
||||
return this._promiseConfirmBlock;
|
||||
},
|
||||
|
||||
/*
|
||||
* Launches the file after download has completed. This can open
|
||||
* the file with the default application for the target MIME type
|
||||
@ -772,21 +897,34 @@ this.Download.prototype = {
|
||||
}
|
||||
|
||||
// Update the current progress from disk if we retained partial data.
|
||||
if (this.hasPartialData && this.target.partFilePath) {
|
||||
let stat = yield OS.File.stat(this.target.partFilePath);
|
||||
if ((this.hasPartialData || this.hasBlockedData) &&
|
||||
this.target.partFilePath) {
|
||||
|
||||
// Ignore the result if the state has changed meanwhile.
|
||||
if (!this.stopped || this._finalized) {
|
||||
return;
|
||||
try {
|
||||
let stat = yield OS.File.stat(this.target.partFilePath);
|
||||
|
||||
// Ignore the result if the state has changed meanwhile.
|
||||
if (!this.stopped || this._finalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the bytes transferred and the related progress properties.
|
||||
this.currentBytes = stat.size;
|
||||
if (this.totalBytes > 0) {
|
||||
this.hasProgress = true;
|
||||
this.progress = Math.floor(this.currentBytes /
|
||||
this.totalBytes * 100);
|
||||
}
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
|
||||
// Ignore the result if the state has changed meanwhile.
|
||||
if (!this.stopped || this._finalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasBlockedData = false;
|
||||
this.hasPartialData = false;
|
||||
}
|
||||
|
||||
// Update the bytes transferred and the related progress properties.
|
||||
this.currentBytes = stat.size;
|
||||
if (this.totalBytes > 0) {
|
||||
this.hasProgress = true;
|
||||
this.progress = Math.floor(this.currentBytes /
|
||||
this.totalBytes * 100);
|
||||
}
|
||||
this._notifyChange();
|
||||
}
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
@ -984,6 +1122,7 @@ const kPlainSerializableDownloadProperties = [
|
||||
"canceled",
|
||||
"totalBytes",
|
||||
"hasPartialData",
|
||||
"hasBlockedData",
|
||||
"tryToKeepPartialData",
|
||||
"launcherPath",
|
||||
"launchWhenSucceeded",
|
||||
@ -1818,11 +1957,6 @@ this.DownloadCopySaver.prototype = {
|
||||
// background file saver that the operation can finish. If the
|
||||
// data transfer failed, the saver has been already stopped.
|
||||
if (Components.isSuccessCode(aStatusCode)) {
|
||||
if (partFilePath) {
|
||||
// Move to the final target if we were using a part file.
|
||||
backgroundFileSaver.setTarget(
|
||||
new FileUtils.File(targetPath), false);
|
||||
}
|
||||
backgroundFileSaver.finish(Cr.NS_OK);
|
||||
}
|
||||
}
|
||||
@ -1855,6 +1989,8 @@ this.DownloadCopySaver.prototype = {
|
||||
// We will wait on this promise in case no error occurred while setting
|
||||
// up the chain of objects for the download.
|
||||
yield deferSaveComplete.promise;
|
||||
|
||||
yield this._checkReputationAndMove();
|
||||
} catch (ex) {
|
||||
// Ensure we always remove the placeholder for the final target file on
|
||||
// failure, independently of which code path failed. In some cases, the
|
||||
@ -1876,6 +2012,47 @@ this.DownloadCopySaver.prototype = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform the reputation check and cleanup the downloaded data if required.
|
||||
* If the download passes the reputation check and is using a part file we
|
||||
* will move it to the target path since reputation checking is the final
|
||||
* step in the saver.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the reputation check and cleanup is complete.
|
||||
* @rejects DownloadError if the download should be blocked.
|
||||
*/
|
||||
_checkReputationAndMove: Task.async(function* () {
|
||||
let download = this.download;
|
||||
let targetPath = this.download.target.path;
|
||||
let partFilePath = this.download.target.partFilePath;
|
||||
|
||||
if (yield DownloadIntegration.shouldBlockForReputationCheck(download)) {
|
||||
download.progress = 100;
|
||||
download.hasPartialData = false;
|
||||
|
||||
// We will remove the potentially dangerous file if instructed by
|
||||
// DownloadIntegration. We will always remove the file when the
|
||||
// download did not use a partial file path, meaning it
|
||||
// currently has its final filename.
|
||||
if (!DownloadIntegration.shouldKeepBlockedData() || !partFilePath) {
|
||||
try {
|
||||
yield OS.File.remove(partFilePath || targetPath);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
} else {
|
||||
download.hasBlockedData = true;
|
||||
}
|
||||
|
||||
throw new DownloadError({ becauseBlockedByReputationCheck: true });
|
||||
}
|
||||
|
||||
if (partFilePath) {
|
||||
yield OS.File.move(partFilePath, targetPath);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Implements "DownloadSaver.cancel".
|
||||
*/
|
||||
@ -2171,13 +2348,12 @@ this.DownloadLegacySaver.prototype = {
|
||||
// to its final target path when the download succeeds. In this case,
|
||||
// an empty ".part" file is created even if no data was received from
|
||||
// the source.
|
||||
if (this.download.target.partFilePath) {
|
||||
yield OS.File.move(this.download.target.partFilePath,
|
||||
this.download.target.path);
|
||||
} else {
|
||||
// The download implementation may not have created the target file if
|
||||
// no data was received from the source. In this case, ensure that an
|
||||
// empty file is created as expected.
|
||||
//
|
||||
// When no ".part" file path is provided the download implementation may
|
||||
// not have created the target file (if no data was received from the
|
||||
// source). In this case, ensure that an empty file is created as
|
||||
// expected.
|
||||
if (!this.download.target.partFilePath) {
|
||||
try {
|
||||
// This atomic operation is more efficient than an existence check.
|
||||
let file = yield OS.File.open(this.download.target.path,
|
||||
@ -2185,6 +2361,9 @@ this.DownloadLegacySaver.prototype = {
|
||||
yield file.close();
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) { }
|
||||
}
|
||||
|
||||
yield this._checkReputationAndMove();
|
||||
|
||||
} catch (ex) {
|
||||
// Ensure we always remove the final target file on failure,
|
||||
// independently of which code path failed. In some cases, the
|
||||
@ -2217,6 +2396,10 @@ this.DownloadLegacySaver.prototype = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_checkReputationAndMove: function () {
|
||||
return DownloadCopySaver.prototype._checkReputationAndMove.call(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements "DownloadSaver.cancel".
|
||||
*/
|
||||
|
@ -152,6 +152,7 @@ this.DownloadIntegration = {
|
||||
dontCheckApplicationReputation: true,
|
||||
#endif
|
||||
shouldBlockInTestForApplicationReputation: false,
|
||||
shouldKeepBlockedDataInTest: false,
|
||||
dontOpenFileAndFolder: false,
|
||||
downloadDoneCalled: false,
|
||||
_deferTestOpenFile: null,
|
||||
@ -174,6 +175,30 @@ this.DownloadIntegration = {
|
||||
return (this._testMode = mode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether data for blocked downloads should be kept on disk.
|
||||
* Implementations which support unblocking downloads may return true to
|
||||
* keep the blocked download on disk until its fate is decided.
|
||||
*
|
||||
* If a download is blocked and the partial data is kept the Download's
|
||||
* 'hasBlockedData' property will be true. In this state Download.unblock()
|
||||
* or Download.confirmBlock() may be used to either unblock the download or
|
||||
* remove the downloaded data respectively.
|
||||
*
|
||||
* Even if shouldKeepBlockedData returns true, if the download did not use a
|
||||
* partFile the blocked data will be removed - preventing the complete
|
||||
* download from existing on disk with its final filename.
|
||||
*
|
||||
* @return boolean True if data should be kept.
|
||||
*/
|
||||
shouldKeepBlockedData: function() {
|
||||
if (this.shouldBlockInTestForApplicationReputation) {
|
||||
return this.shouldKeepBlockedDataInTest;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Performs initialization of the list of persistent downloads, before its
|
||||
* first use by the host application. This function may be called only once
|
||||
|
@ -1547,42 +1547,231 @@ add_task(function test_getSha256Hash()
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Checks that application reputation blocks the download and the target file
|
||||
* does not exist.
|
||||
* Create a download which will be reputation blocked.
|
||||
*
|
||||
* @param options
|
||||
* {
|
||||
* keepPartialData: bool,
|
||||
* keepBlockedData: bool,
|
||||
* }
|
||||
* @return {Promise}
|
||||
* @resolves The reputation blocked download.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation()
|
||||
{
|
||||
let promiseBlockedDownload = Task.async(function* (options) {
|
||||
function cleanup() {
|
||||
DownloadIntegration.shouldBlockInTestForApplicationReputation = false;
|
||||
DownloadIntegration.shouldKeepBlockedDataInTest = false;
|
||||
}
|
||||
do_register_cleanup(cleanup);
|
||||
|
||||
let {keepPartialData, keepBlockedData} = options;
|
||||
DownloadIntegration.shouldBlockInTestForApplicationReputation = true;
|
||||
DownloadIntegration.shouldKeepBlockedDataInTest = keepBlockedData;
|
||||
|
||||
let download;
|
||||
|
||||
try {
|
||||
if (!gUseLegacySaver) {
|
||||
// When testing DownloadCopySaver, we want to check that the promise
|
||||
// returned by the "start" method is rejected.
|
||||
if (keepPartialData) {
|
||||
download = yield promiseStartDownload_tryToKeepPartialData();
|
||||
continueResponses();
|
||||
} else if (gUseLegacySaver) {
|
||||
download = yield promiseStartLegacyDownload();
|
||||
} else {
|
||||
download = yield promiseNewDownload();
|
||||
yield download.start();
|
||||
} else {
|
||||
// When testing DownloadLegacySaver, we cannot be sure whether we are
|
||||
// testing the promise returned by the "start" method or we are testing
|
||||
// the "error" property checked by promiseDownloadStopped. This happens
|
||||
// because we don't have control over when the download is started.
|
||||
download = yield promiseStartLegacyDownload();
|
||||
yield promiseDownloadStopped(download);
|
||||
do_throw("The download should have blocked.");
|
||||
}
|
||||
|
||||
yield promiseDownloadStopped(download);
|
||||
do_throw("The download should have blocked.");
|
||||
} catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
|
||||
do_check_true(ex.becauseBlockedByReputationCheck);
|
||||
do_check_true(download.error.becauseBlockedByReputationCheck);
|
||||
}
|
||||
|
||||
do_check_true(download.stopped);
|
||||
do_check_false(download.succeeded);
|
||||
do_check_false(yield OS.File.exists(download.target.path));
|
||||
|
||||
cleanup();
|
||||
return download;
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that application reputation blocks the download and the target file
|
||||
* does not exist.
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation()
|
||||
{
|
||||
let download = yield promiseBlockedDownload({
|
||||
keepPartialData: false,
|
||||
keepBlockedData: false,
|
||||
});
|
||||
|
||||
// Now that the download is blocked, the target file should not exist.
|
||||
do_check_false(yield OS.File.exists(download.target.path));
|
||||
cleanup();
|
||||
|
||||
// There should also be no blocked data in this case
|
||||
do_check_false(download.hasBlockedData);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that application reputation blocks the download but maintains the
|
||||
* blocked data, which will be deleted when the block is confirmed.
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation_confirmBlock()
|
||||
{
|
||||
let download = yield promiseBlockedDownload({
|
||||
keepPartialData: true,
|
||||
keepBlockedData: true,
|
||||
});
|
||||
|
||||
do_check_true(download.hasBlockedData);
|
||||
do_check_true(yield OS.File.exists(download.target.partFilePath));
|
||||
|
||||
yield download.confirmBlock();
|
||||
|
||||
// After confirming the block the download should be in a failed state and
|
||||
// have no downloaded data left on disk.
|
||||
do_check_true(download.stopped);
|
||||
do_check_false(download.succeeded);
|
||||
do_check_false(download.hasBlockedData);
|
||||
do_check_false(yield OS.File.exists(download.target.partFilePath));
|
||||
do_check_false(yield OS.File.exists(download.target.path));
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that application reputation blocks the download but maintains the
|
||||
* blocked data, which will be used to complete the download when unblocking.
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation_unblock()
|
||||
{
|
||||
let download = yield promiseBlockedDownload({
|
||||
keepPartialData: true,
|
||||
keepBlockedData: true,
|
||||
});
|
||||
|
||||
do_check_true(download.hasBlockedData);
|
||||
do_check_true(yield OS.File.exists(download.target.partFilePath));
|
||||
|
||||
yield download.unblock();
|
||||
|
||||
// After unblocking the download should have succeeded and be
|
||||
// present at the final path.
|
||||
do_check_true(download.stopped);
|
||||
do_check_true(download.succeeded);
|
||||
do_check_false(download.hasBlockedData);
|
||||
do_check_false(yield OS.File.exists(download.target.partFilePath));
|
||||
do_check_true(yield OS.File.exists(download.target.path));
|
||||
|
||||
// The only indication the download was previously blocked is the
|
||||
// existence of the error, so we make sure it's still set.
|
||||
do_check_true(download.error instanceof Downloads.Error);
|
||||
do_check_true(download.error.becauseBlocked);
|
||||
do_check_true(download.error.becauseBlockedByReputationCheck);
|
||||
});
|
||||
|
||||
/**
|
||||
* Check that calling cancel on a blocked download will not cause errors
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation_cancel()
|
||||
{
|
||||
let download = yield promiseBlockedDownload({
|
||||
keepPartialData: true,
|
||||
keepBlockedData: true,
|
||||
});
|
||||
|
||||
// This call should succeed on a blocked download.
|
||||
yield download.cancel();
|
||||
|
||||
// Calling cancel should not have changed the current state, the download
|
||||
// should still be blocked.
|
||||
do_check_true(download.error.becauseBlockedByReputationCheck);
|
||||
do_check_true(download.stopped);
|
||||
do_check_false(download.succeeded);
|
||||
do_check_true(download.hasBlockedData);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that unblock and confirmBlock cannot race on a blocked download
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation_decisionRace()
|
||||
{
|
||||
let download = yield promiseBlockedDownload({
|
||||
keepPartialData: true,
|
||||
keepBlockedData: true,
|
||||
});
|
||||
|
||||
let unblockPromise = download.unblock();
|
||||
let confirmBlockPromise = download.confirmBlock();
|
||||
|
||||
yield confirmBlockPromise.then(() => {
|
||||
do_throw("confirmBlock should have failed.");
|
||||
}, () => {});
|
||||
|
||||
yield unblockPromise;
|
||||
|
||||
// After unblocking the download should have succeeded and be
|
||||
// present at the final path.
|
||||
do_check_true(download.stopped);
|
||||
do_check_true(download.succeeded);
|
||||
do_check_false(download.hasBlockedData);
|
||||
do_check_false(yield OS.File.exists(download.target.partFilePath));
|
||||
do_check_true(yield OS.File.exists(download.target.path));
|
||||
|
||||
download = yield promiseBlockedDownload({
|
||||
keepPartialData: true,
|
||||
keepBlockedData: true,
|
||||
});
|
||||
|
||||
confirmBlockPromise = download.confirmBlock();
|
||||
unblockPromise = download.unblock();
|
||||
|
||||
yield unblockPromise.then(() => {
|
||||
do_throw("unblock should have failed.");
|
||||
}, () => {});
|
||||
|
||||
yield confirmBlockPromise;
|
||||
|
||||
// After confirming the block the download should be in a failed state and
|
||||
// have no downloaded data left on disk.
|
||||
do_check_true(download.stopped);
|
||||
do_check_false(download.succeeded);
|
||||
do_check_false(download.hasBlockedData);
|
||||
do_check_false(yield OS.File.exists(download.target.partFilePath));
|
||||
do_check_false(yield OS.File.exists(download.target.path));
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that unblocking a blocked download fails if the blocked data has been
|
||||
* removed.
|
||||
*/
|
||||
add_task(function test_blocked_applicationReputation_unblock()
|
||||
{
|
||||
let download = yield promiseBlockedDownload({
|
||||
keepPartialData: true,
|
||||
keepBlockedData: true,
|
||||
});
|
||||
|
||||
do_check_true(download.hasBlockedData);
|
||||
do_check_true(yield OS.File.exists(download.target.partFilePath));
|
||||
|
||||
// Remove the blocked data without telling the download.
|
||||
yield OS.File.remove(download.target.partFilePath);
|
||||
|
||||
let unblockPromise = download.unblock();
|
||||
yield unblockPromise.then(() => {
|
||||
do_throw("unblock should have failed.");
|
||||
}, () => {});
|
||||
|
||||
// Even though unblocking failed the download state should have been updated
|
||||
// to reflect the lack of blocked data.
|
||||
do_check_false(download.hasBlockedData);
|
||||
do_check_true(download.stopped);
|
||||
do_check_false(download.succeeded);
|
||||
});
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user