Merge m-c to inbound, a=merge
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -35,7 +35,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- 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"/>
|
||||
@ -120,7 +120,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -35,7 +35,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- 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"/>
|
||||
@ -126,7 +126,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
|
||||
<project name="platform/system/media" path="system/media" revision="188b3e51e0a2ce1e16dc8067edef7be3d2365ad9"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -31,7 +31,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<!-- Stock Android things -->
|
||||
@ -128,7 +128,7 @@
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -34,7 +34,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- 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"/>
|
||||
@ -124,7 +124,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="6aa61f8557a22039a30b42b7f283996381fd625d"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
|
||||
<project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -34,7 +34,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
|
||||
@ -136,7 +136,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="1d080491f26dfdfd76d5bbc3e6b40c660e8565af"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
<project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -35,7 +35,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- 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"/>
|
||||
@ -119,7 +119,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "676237f80cf72182500356fabc49365d3471c0e6",
|
||||
"git_revision": "62900f1e42d596c3faa2787a8bd18a8be034b558",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "8e1054115b6145d46f0f2a8fa1b7ef8434b19f95",
|
||||
"revision": "e51159a1a86de1eb0e0dc2a3b84dfd03e8be8b8b",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -35,7 +35,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- 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"/>
|
||||
@ -126,7 +126,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="6aa61f8557a22039a30b42b7f283996381fd625d"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
|
||||
<project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -32,7 +32,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<!-- Stock Android things -->
|
||||
@ -129,7 +129,7 @@
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--
|
||||
B2G repositories for all targets
|
||||
-->
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="676237f80cf72182500356fabc49365d3471c0e6"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="62900f1e42d596c3faa2787a8bd18a8be034b558"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
@ -35,7 +35,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="edc099cff55a6a3f9ad191acfbc8cc39f36228db"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5e96ed318db1ba8037eb402724bc052240ac9e05"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
|
||||
@ -137,7 +137,7 @@
|
||||
<project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="1d080491f26dfdfd76d5bbc3e6b40c660e8565af"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="570531db9e81a871c421b27025ae558022b1015a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="bb356d6505f914347690c8143dbd03af427dd07e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
|
||||
<project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
|
||||
|
@ -1547,8 +1547,6 @@ pref("experiments.supported", true);
|
||||
// Enable GMP support in the addon manager.
|
||||
pref("media.gmp-provider.enabled", true);
|
||||
|
||||
pref("browser.apps.URL", "https://marketplace.firefox.com/discovery/");
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.polaris.enabled", false);
|
||||
pref("privacy.trackingprotection.ui.enabled", false);
|
||||
|
@ -3121,8 +3121,7 @@ function getDetailedCertErrorInfo(location, securityInfoAsString) {
|
||||
if (!securityInfoAsString)
|
||||
return "";
|
||||
|
||||
let details = [];
|
||||
details.push(location);
|
||||
let certErrorDetails = location;
|
||||
|
||||
const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
@ -3132,7 +3131,7 @@ function getDetailedCertErrorInfo(location, securityInfoAsString) {
|
||||
let errors = Cc["@mozilla.org/nss_errors_service;1"]
|
||||
.getService(Ci.nsINSSErrorsService);
|
||||
let code = securityInfo.errorCode;
|
||||
details.push(errors.getErrorMessage(errors.getXPCOMFromNSSError(code)));
|
||||
certErrorDetails += "\r\n\r\n" + errors.getErrorMessage(errors.getXPCOMFromNSSError(code));
|
||||
|
||||
const sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
@ -3143,8 +3142,15 @@ function getDetailedCertErrorInfo(location, securityInfoAsString) {
|
||||
Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
|
||||
|
||||
let uri = Services.io.newURI(location, null, null);
|
||||
details.push(sss.isSecureHost(sss.HEADER_HSTS, uri.host, flags));
|
||||
details.push(sss.isSecureHost(sss.HEADER_HPKP, uri.host, flags));
|
||||
|
||||
let hasHSTS = sss.isSecureHost(sss.HEADER_HSTS, uri.host, flags);
|
||||
let hasHPKP = sss.isSecureHost(sss.HEADER_HPKP, uri.host, flags);
|
||||
certErrorDetails += "\r\n\r\n" +
|
||||
gNavigatorBundle.getFormattedString("certErrorDetailsHSTS.label",
|
||||
[hasHSTS]);
|
||||
certErrorDetails += "\r\n" +
|
||||
gNavigatorBundle.getFormattedString("certErrorDetailsKeyPinning.label",
|
||||
[hasHPKP]);
|
||||
|
||||
let certChain = "";
|
||||
if (securityInfo.failedCertChain) {
|
||||
@ -3155,8 +3161,12 @@ function getDetailedCertErrorInfo(location, securityInfoAsString) {
|
||||
certChain += getPEMString(cert);
|
||||
}
|
||||
}
|
||||
details.push(certChain);
|
||||
return gNavigatorBundle.getFormattedString("certErrorDetails.label", details, 5);
|
||||
|
||||
certErrorDetails += "\r\n\r\n" +
|
||||
gNavigatorBundle.getString("certErrorDetailsCertChain.label") +
|
||||
"\r\n\r\n" + certChain;
|
||||
|
||||
return certErrorDetails;
|
||||
}
|
||||
|
||||
// TODO: can we pull getDERString and getPEMString in from pippki.js instead of
|
||||
@ -6408,11 +6418,6 @@ function BrowserOpenAddonsMgr(aView) {
|
||||
}
|
||||
}
|
||||
|
||||
function BrowserOpenApps() {
|
||||
let appsURL = Services.urlFormatter.formatURLPref("browser.apps.URL");
|
||||
switchToTabHavingURI(appsURL, true)
|
||||
}
|
||||
|
||||
function AddKeywordForSearchField() {
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
|
@ -1141,18 +1141,6 @@ const CustomizableWidgets = [
|
||||
let win = aEvent.view;
|
||||
win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser)
|
||||
}
|
||||
}, {
|
||||
id: "web-apps-button",
|
||||
label: "web-apps-button.label",
|
||||
tooltiptext: "web-apps-button.tooltiptext",
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.target &&
|
||||
aEvent.target.ownerDocument &&
|
||||
aEvent.target.ownerDocument.defaultView;
|
||||
if (win && typeof win.BrowserOpenApps == "function") {
|
||||
win.BrowserOpenApps();
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
|
||||
|
@ -19,13 +19,13 @@
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-XP.png os=WINNT osversion<6
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-aero.png os=WINNT osversion=6
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-aero.png os=WINNT osversion=6.1
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-win8.png os=WINNT osversion=6.2
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-win8.png os=WINNT osversion=6.3
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-win10.png os=WINNT osversion=6.2
|
||||
% override chrome://loop/skin/toolbar.png chrome://loop/skin/toolbar-win10.png os=WINNT osversion=6.3
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-XP@2x.png os=WINNT osversion<6
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-aero@2x.png os=WINNT osversion=6
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-aero@2x.png os=WINNT osversion=6.1
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-win8@2x.png os=WINNT osversion=6.2
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-win8@2x.png os=WINNT osversion=6.3
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-win10@2x.png os=WINNT osversion=6.2
|
||||
% override chrome://loop/skin/toolbar@2x.png chrome://loop/skin/toolbar-win10@2x.png os=WINNT osversion=6.3
|
||||
skin/ (skin/*)
|
||||
content/modules/ (content/modules/*)
|
||||
* content/preferences/prefs.js (content/preferences/prefs.js)
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.7 KiB |
BIN
browser/extensions/loop/skin/windows/toolbar-win10.png
Normal file
After Width: | Height: | Size: 768 B |
BIN
browser/extensions/loop/skin/windows/toolbar-win10@2x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 751 B After Width: | Height: | Size: 752 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -799,13 +799,13 @@ unmuteTab.accesskey = M
|
||||
weakCryptoOverriding.message = %S recommends that you don't enter your password, credit card and other personal information on this website.
|
||||
revokeOverride.label = Don't Trust This Website
|
||||
revokeOverride.accesskey = D
|
||||
# LOCALIZATION NOTE (certErrorDetails.label): This is a text string that
|
||||
# appears in the about:certerror page, so that the user can copy and send it to
|
||||
# the server administrators for troubleshooting. %1$S is the visited URL, %2$S
|
||||
# is the error message, %3$S is true or false, depending on whether the server
|
||||
# supports HSTS, %4$S is true or false, depending on whether the server
|
||||
# supports HPKP, %5$S is the certificate chain in PEM format.
|
||||
certErrorDetails.label = %1$S\r\n\r\n%2$S\r\n\r\nHTTP Strict Transport Security: %3$S\r\nHTTP Public Key Pinning: %4$S\r\n\r\nCertificate chain:\r\n\r\n%5$S
|
||||
|
||||
# LOCALIZATION NOTE (certErrorDetails*.label): These are text strings that
|
||||
# appear in the about:certerror page, so that the user can copy and send them to
|
||||
# the server administrators for troubleshooting.
|
||||
certErrorDetailsHSTS.label = HTTP Strict Transport Security: %S
|
||||
certErrorDetailsKeyPinning.label = HTTP Public Key Pinning: %S
|
||||
certErrorDetailsCertChain.label = Certificate chain:
|
||||
|
||||
# LOCALIZATION NOTE (tabgroups.migration.anonGroup):
|
||||
# %S is the group number/ID
|
||||
|
@ -115,9 +115,6 @@ social-share-button.tooltiptext = Share this page
|
||||
panic-button.label = Forget
|
||||
panic-button.tooltiptext = Forget about some browsing history
|
||||
|
||||
web-apps-button.label = Apps
|
||||
web-apps-button.tooltiptext = Discover Apps
|
||||
|
||||
# LOCALIZATION NOTE(devtools-webide-button.label, devtools-webide-button.tooltiptext):
|
||||
# widget is only visible after WebIDE has been started once (Tools > Web Developers > WebIDE)
|
||||
# %S is the keyboard shortcut
|
||||
|
@ -92,7 +92,6 @@ XPCOMUtils.defineLazyGetter(this, "PALETTE_ITEMS", function() {
|
||||
"feed-button",
|
||||
"email-link-button",
|
||||
"sync-button",
|
||||
"web-apps-button",
|
||||
];
|
||||
|
||||
let panelPlacements = DEFAULT_AREA_PLACEMENTS["PanelUI-contents"];
|
||||
|
@ -890,10 +890,6 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
||||
-moz-image-region: rect(18px, 702px, 36px, 684px);
|
||||
}
|
||||
|
||||
#web-apps-button@toolbarButtonPressed@ {
|
||||
-moz-image-region: rect(18px, 720px, 36px, 702px);
|
||||
}
|
||||
|
||||
/**
|
||||
* OSX has a unique set of icons when fullscreen is in the checked state.
|
||||
*/
|
||||
@ -1061,10 +1057,6 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
||||
-moz-image-region: rect(36px, 1404px, 72px, 1368px);
|
||||
}
|
||||
|
||||
#web-apps-button@toolbarButtonPressed@ {
|
||||
-moz-image-region: rect(36px, 1440px, 72px, 1404px);
|
||||
}
|
||||
|
||||
#add-share-provider {
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
|
||||
-moz-image-region: rect(0px, 192px, 32px, 160px);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
% Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none.
|
||||
%define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button
|
||||
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #web-apps-button, #webide-button
|
||||
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #webide-button
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
% Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen
|
||||
|
@ -158,11 +158,6 @@
|
||||
-moz-image-region: rect(32px, 896px, 64px, 864px);
|
||||
}
|
||||
|
||||
#web-apps-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #web-apps-button {
|
||||
-moz-image-region: rect(0, 928px, 32px, 896px);
|
||||
}
|
||||
|
||||
#webide-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #webide-button {
|
||||
-moz-image-region: rect(0px, 960px, 32px, 928px);
|
||||
@ -368,11 +363,6 @@
|
||||
-moz-image-region: rect(64px, 1792px, 128px, 1728px);
|
||||
}
|
||||
|
||||
#web-apps-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #web-apps-button {
|
||||
-moz-image-region: rect(0, 1856px, 64px, 1792px);
|
||||
}
|
||||
|
||||
toolbaritem[sdkstylewidget="true"] > toolbarbutton {
|
||||
-moz-image-region: rect(0, 1664px, 64px, 1600px);
|
||||
}
|
||||
|
@ -167,10 +167,6 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#web-apps-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 720px, 18px, 702px);
|
||||
}
|
||||
|
||||
#webide-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 738px, 18px, 720px);
|
||||
}
|
||||
@ -338,10 +334,6 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke
|
||||
%endif
|
||||
}
|
||||
|
||||
#web-apps-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 1440px, 36px, 1404px);
|
||||
}
|
||||
|
||||
#webide-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 1476px, 36px, 1440px);
|
||||
}
|
||||
|
BIN
browser/themes/windows/loop/toolbar-win10.png
Normal file
After Width: | Height: | Size: 768 B |
BIN
browser/themes/windows/loop/toolbar-win10@2x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
@ -8,10 +8,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
AnimationsTimeline,
|
||||
RateSelector
|
||||
} = require("devtools/client/animationinspector/components");
|
||||
const {AnimationsTimeline} = require("devtools/client/animationinspector/components/animation-timeline");
|
||||
const {RateSelector} = require("devtools/client/animationinspector/components/rate-selector");
|
||||
const {formatStopwatchTime} = require("devtools/client/animationinspector/utils");
|
||||
|
||||
var $ = (selector, target = document) => target.querySelector(selector);
|
||||
|
@ -0,0 +1,160 @@
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const {
|
||||
createNode,
|
||||
TimeScale
|
||||
} = require("devtools/client/animationinspector/utils");
|
||||
const {Keyframes} = require("devtools/client/animationinspector/components/keyframes");
|
||||
/**
|
||||
* UI component responsible for displaying detailed information for a given
|
||||
* animation.
|
||||
* This includes information about timing, easing, keyframes, animated
|
||||
* properties.
|
||||
*/
|
||||
function AnimationDetails() {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.onFrameSelected = this.onFrameSelected.bind(this);
|
||||
|
||||
this.keyframeComponents = [];
|
||||
}
|
||||
|
||||
exports.AnimationDetails = AnimationDetails;
|
||||
|
||||
AnimationDetails.prototype = {
|
||||
// These are part of frame objects but are not animated properties. This
|
||||
// array is used to skip them.
|
||||
NON_PROPERTIES: ["easing", "composite", "computedOffset", "offset"],
|
||||
|
||||
init: function(containerEl) {
|
||||
this.containerEl = containerEl;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.unrender();
|
||||
this.containerEl = null;
|
||||
},
|
||||
|
||||
unrender: function() {
|
||||
for (let component of this.keyframeComponents) {
|
||||
component.off("frame-selected", this.onFrameSelected);
|
||||
component.destroy();
|
||||
}
|
||||
this.keyframeComponents = [];
|
||||
|
||||
while (this.containerEl.firstChild) {
|
||||
this.containerEl.firstChild.remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a list of frames into a list of tracks, one per animated property,
|
||||
* each with a list of frames.
|
||||
*/
|
||||
getTracksFromFrames: function(frames) {
|
||||
let tracks = {};
|
||||
|
||||
for (let frame of frames) {
|
||||
for (let name in frame) {
|
||||
if (this.NON_PROPERTIES.indexOf(name) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tracks[name]) {
|
||||
tracks[name] = [];
|
||||
}
|
||||
|
||||
tracks[name].push({
|
||||
value: frame[name],
|
||||
offset: frame.computedOffset
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return tracks;
|
||||
},
|
||||
|
||||
render: Task.async(function*(animation) {
|
||||
this.unrender();
|
||||
|
||||
if (!animation) {
|
||||
return;
|
||||
}
|
||||
this.animation = animation;
|
||||
|
||||
let frames = yield animation.getFrames();
|
||||
|
||||
// We might have been destroyed in the meantime, or the component might
|
||||
// have been re-rendered.
|
||||
if (!this.containerEl || this.animation !== animation) {
|
||||
return;
|
||||
}
|
||||
// Useful for tests to know when the keyframes have been retrieved.
|
||||
this.emit("keyframes-retrieved");
|
||||
|
||||
// Build an element for each animated property track.
|
||||
this.tracks = this.getTracksFromFrames(frames);
|
||||
for (let propertyName in this.tracks) {
|
||||
let line = createNode({
|
||||
parent: this.containerEl,
|
||||
attributes: {"class": "property"}
|
||||
});
|
||||
|
||||
createNode({
|
||||
// text-overflow doesn't work in flex items, so we need a second level
|
||||
// of container to actually have an ellipsis on the name.
|
||||
// See bug 972664.
|
||||
parent: createNode({
|
||||
parent: line,
|
||||
attributes: {"class": "name"},
|
||||
}),
|
||||
textContent: getCssPropertyName(propertyName)
|
||||
});
|
||||
|
||||
// Add the keyframes diagram for this property.
|
||||
let framesWrapperEl = createNode({
|
||||
parent: line,
|
||||
attributes: {"class": "track-container"}
|
||||
});
|
||||
|
||||
let framesEl = createNode({
|
||||
parent: framesWrapperEl,
|
||||
attributes: {"class": "frames"}
|
||||
});
|
||||
|
||||
// Scale the list of keyframes according to the current time scale.
|
||||
let {x, w} = TimeScale.getAnimationDimensions(animation);
|
||||
framesEl.style.left = `${x}%`;
|
||||
framesEl.style.width = `${w}%`;
|
||||
|
||||
let keyframesComponent = new Keyframes();
|
||||
keyframesComponent.init(framesEl);
|
||||
keyframesComponent.render({
|
||||
keyframes: this.tracks[propertyName],
|
||||
propertyName: propertyName,
|
||||
animation: animation
|
||||
});
|
||||
keyframesComponent.on("frame-selected", this.onFrameSelected);
|
||||
|
||||
this.keyframeComponents.push(keyframesComponent);
|
||||
}
|
||||
}),
|
||||
|
||||
onFrameSelected: function(e, args) {
|
||||
// Relay the event up, it's needed in parents too.
|
||||
this.emit(e, args);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Turn propertyName into property-name.
|
||||
* @param {String} jsPropertyName A camelcased CSS property name. Typically
|
||||
* something that comes out of computed styles. E.g. borderBottomColor
|
||||
* @return {String} The corresponding CSS property name: border-bottom-color
|
||||
*/
|
||||
function getCssPropertyName(jsPropertyName) {
|
||||
return jsPropertyName.replace(/[A-Z]/g, "-$&").toLowerCase();
|
||||
}
|
||||
exports.getCssPropertyName = getCssPropertyName;
|
@ -0,0 +1,320 @@
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const {
|
||||
createNode,
|
||||
TargetNodeHighlighter
|
||||
} = require("devtools/client/animationinspector/utils");
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a preview of the target dom node of
|
||||
* a given animation.
|
||||
* @param {InspectorPanel} inspector Requires a reference to the inspector-panel
|
||||
* to highlight and select the node, as well as refresh it when there are
|
||||
* mutations.
|
||||
* @param {Object} options Supported properties are:
|
||||
* - compact {Boolean} Defaults to false. If true, nodes will be previewed like
|
||||
* tag#id.class instead of <tag id="id" class="class">
|
||||
*/
|
||||
function AnimationTargetNode(inspector, options = {}) {
|
||||
this.inspector = inspector;
|
||||
this.options = options;
|
||||
|
||||
this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
|
||||
this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
|
||||
this.onSelectNodeClick = this.onSelectNodeClick.bind(this);
|
||||
this.onMarkupMutations = this.onMarkupMutations.bind(this);
|
||||
this.onHighlightNodeClick = this.onHighlightNodeClick.bind(this);
|
||||
this.onTargetHighlighterLocked = this.onTargetHighlighterLocked.bind(this);
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.AnimationTargetNode = AnimationTargetNode;
|
||||
|
||||
AnimationTargetNode.prototype = {
|
||||
init: function(containerEl) {
|
||||
let document = containerEl.ownerDocument;
|
||||
|
||||
// Init the markup for displaying the target node.
|
||||
this.el = createNode({
|
||||
parent: containerEl,
|
||||
attributes: {
|
||||
"class": "animation-target"
|
||||
}
|
||||
});
|
||||
|
||||
// Icon to select the node in the inspector.
|
||||
this.highlightNodeEl = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "node-highlighter",
|
||||
"title": L10N.getStr("node.highlightNodeLabel")
|
||||
}
|
||||
});
|
||||
|
||||
// Wrapper used for mouseover/out event handling.
|
||||
this.previewEl = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"title": L10N.getStr("node.selectNodeLabel")
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.previewEl.appendChild(document.createTextNode("<"));
|
||||
}
|
||||
|
||||
// Tag name.
|
||||
this.tagNameEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "tag-name theme-fg-color3"
|
||||
}
|
||||
});
|
||||
|
||||
// Id attribute container.
|
||||
this.idEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span"
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-name theme-fg-color2"
|
||||
},
|
||||
textContent: "id"
|
||||
});
|
||||
this.idEl.appendChild(document.createTextNode("=\""));
|
||||
} else {
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "theme-fg-color2"
|
||||
},
|
||||
textContent: "#"
|
||||
});
|
||||
}
|
||||
|
||||
createNode({
|
||||
parent: this.idEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-value theme-fg-color6"
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.idEl.appendChild(document.createTextNode("\""));
|
||||
}
|
||||
|
||||
// Class attribute container.
|
||||
this.classEl = createNode({
|
||||
parent: this.previewEl,
|
||||
nodeType: "span"
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-name theme-fg-color2"
|
||||
},
|
||||
textContent: "class"
|
||||
});
|
||||
this.classEl.appendChild(document.createTextNode("=\""));
|
||||
} else {
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "theme-fg-color6"
|
||||
},
|
||||
textContent: "."
|
||||
});
|
||||
}
|
||||
|
||||
createNode({
|
||||
parent: this.classEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "attribute-value theme-fg-color6"
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.options.compact) {
|
||||
this.classEl.appendChild(document.createTextNode("\""));
|
||||
this.previewEl.appendChild(document.createTextNode(">"));
|
||||
}
|
||||
|
||||
this.startListeners();
|
||||
},
|
||||
|
||||
startListeners: function() {
|
||||
// Init events for highlighting and selecting the node.
|
||||
this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
|
||||
this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
|
||||
this.previewEl.addEventListener("click", this.onSelectNodeClick);
|
||||
this.highlightNodeEl.addEventListener("click", this.onHighlightNodeClick);
|
||||
|
||||
// Start to listen for markupmutation events.
|
||||
this.inspector.on("markupmutation", this.onMarkupMutations);
|
||||
|
||||
// Listen to the target node highlighter.
|
||||
TargetNodeHighlighter.on("highlighted", this.onTargetHighlighterLocked);
|
||||
},
|
||||
|
||||
stopListeners: function() {
|
||||
TargetNodeHighlighter.off("highlighted", this.onTargetHighlighterLocked);
|
||||
this.inspector.off("markupmutation", this.onMarkupMutations);
|
||||
this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
|
||||
this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
|
||||
this.previewEl.removeEventListener("click", this.onSelectNodeClick);
|
||||
this.highlightNodeEl.removeEventListener("click", this.onHighlightNodeClick);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
TargetNodeHighlighter.unhighlight().catch(e => console.error(e));
|
||||
|
||||
this.stopListeners();
|
||||
|
||||
this.el.remove();
|
||||
this.el = this.tagNameEl = this.idEl = this.classEl = null;
|
||||
this.highlightNodeEl = this.previewEl = null;
|
||||
this.nodeFront = this.inspector = this.playerFront = null;
|
||||
},
|
||||
|
||||
get highlighterUtils() {
|
||||
if (this.inspector && this.inspector.toolbox) {
|
||||
return this.inspector.toolbox.highlighterUtils;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
onPreviewMouseOver: function() {
|
||||
if (!this.nodeFront || !this.highlighterUtils) {
|
||||
return;
|
||||
}
|
||||
this.highlighterUtils.highlightNodeFront(this.nodeFront)
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
onPreviewMouseOut: function() {
|
||||
if (!this.nodeFront || !this.highlighterUtils) {
|
||||
return;
|
||||
}
|
||||
this.highlighterUtils.unhighlight()
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
onSelectNodeClick: function() {
|
||||
if (!this.nodeFront) {
|
||||
return;
|
||||
}
|
||||
this.inspector.selection.setNodeFront(this.nodeFront, "animationinspector");
|
||||
},
|
||||
|
||||
onHighlightNodeClick: function(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
let classList = this.highlightNodeEl.classList;
|
||||
|
||||
let isHighlighted = classList.contains("selected");
|
||||
if (isHighlighted) {
|
||||
classList.remove("selected");
|
||||
TargetNodeHighlighter.unhighlight().then(() => {
|
||||
this.emit("target-highlighter-unlocked");
|
||||
}, e => console.error(e));
|
||||
} else {
|
||||
classList.add("selected");
|
||||
TargetNodeHighlighter.highlight(this).then(() => {
|
||||
this.emit("target-highlighter-locked");
|
||||
}, e => console.error(e));
|
||||
}
|
||||
},
|
||||
|
||||
onTargetHighlighterLocked: function(e, animationTargetNode) {
|
||||
if (animationTargetNode !== this) {
|
||||
this.highlightNodeEl.classList.remove("selected");
|
||||
}
|
||||
},
|
||||
|
||||
onMarkupMutations: function(e, mutations) {
|
||||
if (!this.nodeFront || !this.playerFront) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let {target} of mutations) {
|
||||
if (target === this.nodeFront) {
|
||||
// Re-render with the same nodeFront to update the output.
|
||||
this.render(this.playerFront);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: Task.async(function*(playerFront) {
|
||||
this.playerFront = playerFront;
|
||||
this.nodeFront = undefined;
|
||||
|
||||
try {
|
||||
this.nodeFront = yield this.inspector.walker.getNodeFromActor(
|
||||
playerFront.actorID, ["node"]);
|
||||
} catch (e) {
|
||||
if (!this.el) {
|
||||
// The panel was destroyed in the meantime. Just log a warning.
|
||||
console.warn("Cound't retrieve the animation target node, widget " +
|
||||
"destroyed");
|
||||
} else {
|
||||
// This was an unexpected error, log it.
|
||||
console.error(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.nodeFront || !this.el) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {tagName, attributes} = this.nodeFront;
|
||||
|
||||
this.tagNameEl.textContent = tagName.toLowerCase();
|
||||
|
||||
let idIndex = attributes.findIndex(({name}) => name === "id");
|
||||
if (idIndex > -1 && attributes[idIndex].value) {
|
||||
this.idEl.querySelector(".attribute-value").textContent =
|
||||
attributes[idIndex].value;
|
||||
this.idEl.style.display = "inline";
|
||||
} else {
|
||||
this.idEl.style.display = "none";
|
||||
}
|
||||
|
||||
let classIndex = attributes.findIndex(({name}) => name === "class");
|
||||
if (classIndex > -1 && attributes[classIndex].value) {
|
||||
let value = attributes[classIndex].value;
|
||||
if (this.options.compact) {
|
||||
value = value.split(" ").join(".");
|
||||
}
|
||||
|
||||
this.classEl.querySelector(".attribute-value").textContent = value;
|
||||
this.classEl.style.display = "inline";
|
||||
} else {
|
||||
this.classEl.style.display = "none";
|
||||
}
|
||||
|
||||
this.emit("target-retrieved");
|
||||
})
|
||||
};
|
@ -0,0 +1,157 @@
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {
|
||||
createNode,
|
||||
TimeScale
|
||||
} = require("devtools/client/animationinspector/utils");
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a single animation timeline, which
|
||||
* basically looks like a rectangle that shows the delay and iterations.
|
||||
*/
|
||||
function AnimationTimeBlock() {
|
||||
EventEmitter.decorate(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
exports.AnimationTimeBlock = AnimationTimeBlock;
|
||||
|
||||
AnimationTimeBlock.prototype = {
|
||||
init: function(containerEl) {
|
||||
this.containerEl = containerEl;
|
||||
this.containerEl.addEventListener("click", this.onClick);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.containerEl.removeEventListener("click", this.onClick);
|
||||
this.unrender();
|
||||
this.containerEl = null;
|
||||
this.animation = null;
|
||||
},
|
||||
|
||||
unrender: function() {
|
||||
while (this.containerEl.firstChild) {
|
||||
this.containerEl.firstChild.remove();
|
||||
}
|
||||
},
|
||||
|
||||
render: function(animation) {
|
||||
this.unrender();
|
||||
|
||||
this.animation = animation;
|
||||
let {state} = this.animation;
|
||||
|
||||
// Create a container element to hold the delay and iterations.
|
||||
// It is positioned according to its delay (divided by the playbackrate),
|
||||
// and its width is according to its duration (divided by the playbackrate).
|
||||
let {x, iterationW, delayX, delayW, negativeDelayW} =
|
||||
TimeScale.getAnimationDimensions(animation);
|
||||
|
||||
let iterations = createNode({
|
||||
parent: this.containerEl,
|
||||
attributes: {
|
||||
"class": state.type + " iterations" +
|
||||
(state.iterationCount ? "" : " infinite"),
|
||||
// Individual iterations are represented by setting the size of the
|
||||
// repeating linear-gradient.
|
||||
"style": `left:${x}%;
|
||||
width:${iterationW}%;
|
||||
background-size:${100 / (state.iterationCount || 1)}% 100%;`
|
||||
}
|
||||
});
|
||||
|
||||
// The animation name is displayed over the iterations.
|
||||
// Note that in case of negative delay, we push the name towards the right
|
||||
// so the delay can be shown.
|
||||
createNode({
|
||||
parent: iterations,
|
||||
attributes: {
|
||||
"class": "name",
|
||||
"title": this.getTooltipText(state),
|
||||
// Make space for the negative delay with a margin-left.
|
||||
"style": `margin-left:${negativeDelayW}%`
|
||||
},
|
||||
textContent: state.name
|
||||
});
|
||||
|
||||
// Delay.
|
||||
if (state.delay) {
|
||||
// Negative delays need to start at 0.
|
||||
createNode({
|
||||
parent: iterations,
|
||||
attributes: {
|
||||
"class": "delay" + (state.delay < 0 ? " negative" : ""),
|
||||
"style": `left:-${delayX}%;
|
||||
width:${delayW}%;`
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getTooltipText: function(state) {
|
||||
let getTime = time => L10N.getFormatStr("player.timeLabel",
|
||||
L10N.numberWithDecimals(time / 1000, 2));
|
||||
|
||||
let text = "";
|
||||
|
||||
// Adding the name.
|
||||
text += getFormattedAnimationTitle({state});
|
||||
text += "\n";
|
||||
|
||||
// Adding the delay.
|
||||
text += L10N.getStr("player.animationDelayLabel") + " ";
|
||||
text += getTime(state.delay);
|
||||
text += "\n";
|
||||
|
||||
// Adding the duration.
|
||||
text += L10N.getStr("player.animationDurationLabel") + " ";
|
||||
text += getTime(state.duration);
|
||||
text += "\n";
|
||||
|
||||
// Adding the iteration count (the infinite symbol, or an integer).
|
||||
if (state.iterationCount !== 1) {
|
||||
text += L10N.getStr("player.animationIterationCountLabel") + " ";
|
||||
text += state.iterationCount ||
|
||||
L10N.getStr("player.infiniteIterationCountText");
|
||||
text += "\n";
|
||||
}
|
||||
|
||||
// Adding the playback rate if it's different than 1.
|
||||
if (state.playbackRate !== 1) {
|
||||
text += L10N.getStr("player.animationRateLabel") + " ";
|
||||
text += state.playbackRate;
|
||||
text += "\n";
|
||||
}
|
||||
|
||||
// Adding a note that the animation is running on the compositor thread if
|
||||
// needed.
|
||||
if (state.isRunningOnCompositor) {
|
||||
text += L10N.getStr("player.runningOnCompositorTooltip");
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
|
||||
onClick: function(e) {
|
||||
e.stopPropagation();
|
||||
this.emit("selected", this.animation);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a formatted title for this animation. This will be either:
|
||||
* "some-name", "some-name : CSS Transition", or "some-name : CSS Animation",
|
||||
* depending if the server provides the type, and what type it is.
|
||||
* @param {AnimationPlayerFront} animation
|
||||
*/
|
||||
function getFormattedAnimationTitle({state}) {
|
||||
// Older servers don't send the type.
|
||||
return state.type
|
||||
? L10N.getFormatStr("timeline." + state.type + ".nameLabel", state.name)
|
||||
: state.name;
|
||||
}
|
@ -0,0 +1,433 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createNode,
|
||||
drawGraphElementBackground,
|
||||
findOptimalTimeInterval,
|
||||
TimeScale
|
||||
} = require("devtools/client/animationinspector/utils");
|
||||
const {AnimationDetails} = require("devtools/client/animationinspector/components/animation-details");
|
||||
const {AnimationTargetNode} = require("devtools/client/animationinspector/components/animation-target-node");
|
||||
const {AnimationTimeBlock} = require("devtools/client/animationinspector/components/animation-time-block");
|
||||
|
||||
// The minimum spacing between 2 time graduation headers in the timeline (px).
|
||||
const TIME_GRADUATION_MIN_SPACING = 40;
|
||||
// When the container window is resized, the timeline background gets refreshed,
|
||||
// but only after a timer, and the timer is reset if the window is continuously
|
||||
// resized.
|
||||
const TIMELINE_BACKGROUND_RESIZE_DEBOUNCE_TIMER = 50;
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a timeline for animations.
|
||||
* The timeline is essentially a graph with time along the x axis and animations
|
||||
* along the y axis.
|
||||
* The time is represented with a graduation header at the top and a current
|
||||
* time play head.
|
||||
* Animations are organized by lines, with a left margin containing the preview
|
||||
* of the target DOM element the animation applies to.
|
||||
* The current time play head can be moved by clicking/dragging in the header.
|
||||
* when this happens, the component emits "current-data-changed" events with the
|
||||
* new time and state of the timeline.
|
||||
*
|
||||
* @param {InspectorPanel} inspector.
|
||||
*/
|
||||
function AnimationsTimeline(inspector) {
|
||||
this.animations = [];
|
||||
this.targetNodes = [];
|
||||
this.timeBlocks = [];
|
||||
this.details = [];
|
||||
this.inspector = inspector;
|
||||
|
||||
this.onAnimationStateChanged = this.onAnimationStateChanged.bind(this);
|
||||
this.onScrubberMouseDown = this.onScrubberMouseDown.bind(this);
|
||||
this.onScrubberMouseUp = this.onScrubberMouseUp.bind(this);
|
||||
this.onScrubberMouseOut = this.onScrubberMouseOut.bind(this);
|
||||
this.onScrubberMouseMove = this.onScrubberMouseMove.bind(this);
|
||||
this.onAnimationSelected = this.onAnimationSelected.bind(this);
|
||||
this.onWindowResize = this.onWindowResize.bind(this);
|
||||
this.onFrameSelected = this.onFrameSelected.bind(this);
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.AnimationsTimeline = AnimationsTimeline;
|
||||
|
||||
AnimationsTimeline.prototype = {
|
||||
init: function(containerEl) {
|
||||
this.win = containerEl.ownerDocument.defaultView;
|
||||
|
||||
this.rootWrapperEl = createNode({
|
||||
parent: containerEl,
|
||||
attributes: {
|
||||
"class": "animation-timeline"
|
||||
}
|
||||
});
|
||||
|
||||
let scrubberContainer = createNode({
|
||||
parent: this.rootWrapperEl,
|
||||
attributes: {"class": "scrubber-wrapper track-container"}
|
||||
});
|
||||
|
||||
this.scrubberEl = createNode({
|
||||
parent: scrubberContainer,
|
||||
attributes: {
|
||||
"class": "scrubber"
|
||||
}
|
||||
});
|
||||
|
||||
this.scrubberHandleEl = createNode({
|
||||
parent: this.scrubberEl,
|
||||
attributes: {
|
||||
"class": "scrubber-handle"
|
||||
}
|
||||
});
|
||||
this.scrubberHandleEl.addEventListener("mousedown", this.onScrubberMouseDown);
|
||||
|
||||
this.timeHeaderEl = createNode({
|
||||
parent: this.rootWrapperEl,
|
||||
attributes: {
|
||||
"class": "time-header track-container"
|
||||
}
|
||||
});
|
||||
this.timeHeaderEl.addEventListener("mousedown", this.onScrubberMouseDown);
|
||||
|
||||
this.animationsEl = createNode({
|
||||
parent: this.rootWrapperEl,
|
||||
nodeType: "ul",
|
||||
attributes: {
|
||||
"class": "animations"
|
||||
}
|
||||
});
|
||||
|
||||
this.win.addEventListener("resize", this.onWindowResize);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.stopAnimatingScrubber();
|
||||
this.unrender();
|
||||
|
||||
this.win.removeEventListener("resize", this.onWindowResize);
|
||||
this.timeHeaderEl.removeEventListener("mousedown",
|
||||
this.onScrubberMouseDown);
|
||||
this.scrubberHandleEl.removeEventListener("mousedown",
|
||||
this.onScrubberMouseDown);
|
||||
|
||||
this.rootWrapperEl.remove();
|
||||
this.animations = [];
|
||||
|
||||
this.rootWrapperEl = null;
|
||||
this.timeHeaderEl = null;
|
||||
this.animationsEl = null;
|
||||
this.scrubberEl = null;
|
||||
this.scrubberHandleEl = null;
|
||||
this.win = null;
|
||||
this.inspector = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy sub-components that have been created and stored on this instance.
|
||||
* @param {String} name An array of components will be expected in this[name]
|
||||
* @param {Array} handlers An option list of event handlers information that
|
||||
* should be used to remove these handlers.
|
||||
*/
|
||||
destroySubComponents: function(name, handlers = []) {
|
||||
for (let component of this[name]) {
|
||||
for (let {event, fn} of handlers) {
|
||||
component.off(event, fn);
|
||||
}
|
||||
component.destroy();
|
||||
}
|
||||
this[name] = [];
|
||||
},
|
||||
|
||||
unrender: function() {
|
||||
for (let animation of this.animations) {
|
||||
animation.off("changed", this.onAnimationStateChanged);
|
||||
}
|
||||
TimeScale.reset();
|
||||
this.destroySubComponents("targetNodes");
|
||||
this.destroySubComponents("timeBlocks");
|
||||
this.destroySubComponents("details", [{
|
||||
event: "frame-selected",
|
||||
fn: this.onFrameSelected
|
||||
}]);
|
||||
this.animationsEl.innerHTML = "";
|
||||
},
|
||||
|
||||
onWindowResize: function() {
|
||||
if (this.windowResizeTimer) {
|
||||
this.win.clearTimeout(this.windowResizeTimer);
|
||||
}
|
||||
|
||||
this.windowResizeTimer = this.win.setTimeout(() => {
|
||||
this.drawHeaderAndBackground();
|
||||
}, TIMELINE_BACKGROUND_RESIZE_DEBOUNCE_TIMER);
|
||||
},
|
||||
|
||||
onAnimationSelected: function(e, animation) {
|
||||
let index = this.animations.indexOf(animation);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
let el = this.rootWrapperEl;
|
||||
let animationEl = el.querySelectorAll(".animation")[index];
|
||||
let propsEl = el.querySelectorAll(".animated-properties")[index];
|
||||
|
||||
// Toggle the selected state on this animation.
|
||||
animationEl.classList.toggle("selected");
|
||||
propsEl.classList.toggle("selected");
|
||||
|
||||
// Render the details component for this animation if it was shown.
|
||||
if (animationEl.classList.contains("selected")) {
|
||||
this.details[index].render(animation);
|
||||
this.emit("animation-selected", animation);
|
||||
} else {
|
||||
this.emit("animation-unselected", animation);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When a frame gets selected, move the scrubber to the corresponding position
|
||||
*/
|
||||
onFrameSelected: function(e, {x}) {
|
||||
this.moveScrubberTo(x, true);
|
||||
},
|
||||
|
||||
onScrubberMouseDown: function(e) {
|
||||
this.moveScrubberTo(e.pageX);
|
||||
this.win.addEventListener("mouseup", this.onScrubberMouseUp);
|
||||
this.win.addEventListener("mouseout", this.onScrubberMouseOut);
|
||||
this.win.addEventListener("mousemove", this.onScrubberMouseMove);
|
||||
|
||||
// Prevent text selection while dragging.
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
onScrubberMouseUp: function() {
|
||||
this.cancelTimeHeaderDragging();
|
||||
},
|
||||
|
||||
onScrubberMouseOut: function(e) {
|
||||
// Check that mouseout happened on the window itself, and if yes, cancel
|
||||
// the dragging.
|
||||
if (!this.win.document.contains(e.relatedTarget)) {
|
||||
this.cancelTimeHeaderDragging();
|
||||
}
|
||||
},
|
||||
|
||||
cancelTimeHeaderDragging: function() {
|
||||
this.win.removeEventListener("mouseup", this.onScrubberMouseUp);
|
||||
this.win.removeEventListener("mouseout", this.onScrubberMouseOut);
|
||||
this.win.removeEventListener("mousemove", this.onScrubberMouseMove);
|
||||
},
|
||||
|
||||
onScrubberMouseMove: function(e) {
|
||||
this.moveScrubberTo(e.pageX);
|
||||
},
|
||||
|
||||
moveScrubberTo: function(pageX, noOffset) {
|
||||
this.stopAnimatingScrubber();
|
||||
|
||||
// The offset needs to be in % and relative to the timeline's area (so we
|
||||
// subtract the scrubber's left offset, which is equal to the sidebar's
|
||||
// width).
|
||||
let offset = pageX;
|
||||
if (!noOffset) {
|
||||
offset -= this.timeHeaderEl.offsetLeft;
|
||||
}
|
||||
offset = offset * 100 / this.timeHeaderEl.offsetWidth;
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
this.scrubberEl.style.left = offset + "%";
|
||||
|
||||
let time = TimeScale.distanceToRelativeTime(offset);
|
||||
|
||||
this.emit("timeline-data-changed", {
|
||||
isPaused: true,
|
||||
isMoving: false,
|
||||
isUserDrag: true,
|
||||
time: time
|
||||
});
|
||||
},
|
||||
|
||||
render: function(animations, documentCurrentTime) {
|
||||
this.unrender();
|
||||
|
||||
this.animations = animations;
|
||||
if (!this.animations.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop first to set the time scale for all current animations.
|
||||
for (let {state} of animations) {
|
||||
TimeScale.addAnimation(state);
|
||||
}
|
||||
|
||||
this.drawHeaderAndBackground();
|
||||
|
||||
for (let animation of this.animations) {
|
||||
animation.on("changed", this.onAnimationStateChanged);
|
||||
|
||||
// Each line contains the target animated node and the animation time
|
||||
// block.
|
||||
let animationEl = createNode({
|
||||
parent: this.animationsEl,
|
||||
nodeType: "li",
|
||||
attributes: {
|
||||
"class": "animation" + (animation.state.isRunningOnCompositor
|
||||
? " fast-track"
|
||||
: "")
|
||||
}
|
||||
});
|
||||
|
||||
// Right below the line is a hidden-by-default line for displaying the
|
||||
// inline keyframes.
|
||||
let detailsEl = createNode({
|
||||
parent: this.animationsEl,
|
||||
nodeType: "li",
|
||||
attributes: {
|
||||
"class": "animated-properties"
|
||||
}
|
||||
});
|
||||
|
||||
let details = new AnimationDetails();
|
||||
details.init(detailsEl);
|
||||
details.on("frame-selected", this.onFrameSelected);
|
||||
this.details.push(details);
|
||||
|
||||
// Left sidebar for the animated node.
|
||||
let animatedNodeEl = createNode({
|
||||
parent: animationEl,
|
||||
attributes: {
|
||||
"class": "target"
|
||||
}
|
||||
});
|
||||
|
||||
// Draw the animated node target.
|
||||
let targetNode = new AnimationTargetNode(this.inspector, {compact: true});
|
||||
targetNode.init(animatedNodeEl);
|
||||
targetNode.render(animation);
|
||||
this.targetNodes.push(targetNode);
|
||||
|
||||
// Right-hand part contains the timeline itself (called time-block here).
|
||||
let timeBlockEl = createNode({
|
||||
parent: animationEl,
|
||||
attributes: {
|
||||
"class": "time-block track-container"
|
||||
}
|
||||
});
|
||||
|
||||
// Draw the animation time block.
|
||||
let timeBlock = new AnimationTimeBlock();
|
||||
timeBlock.init(timeBlockEl);
|
||||
timeBlock.render(animation);
|
||||
this.timeBlocks.push(timeBlock);
|
||||
|
||||
timeBlock.on("selected", this.onAnimationSelected);
|
||||
}
|
||||
|
||||
// Use the document's current time to position the scrubber (if the server
|
||||
// doesn't provide it, hide the scrubber entirely).
|
||||
// Note that because the currentTime was sent via the protocol, some time
|
||||
// may have gone by since then, and so the scrubber might be a bit late.
|
||||
if (!documentCurrentTime) {
|
||||
this.scrubberEl.style.display = "none";
|
||||
} else {
|
||||
this.scrubberEl.style.display = "block";
|
||||
this.startAnimatingScrubber(this.wasRewound()
|
||||
? TimeScale.minStartTime
|
||||
: documentCurrentTime);
|
||||
}
|
||||
},
|
||||
|
||||
isAtLeastOneAnimationPlaying: function() {
|
||||
return this.animations.some(({state}) => state.playState === "running");
|
||||
},
|
||||
|
||||
wasRewound: function() {
|
||||
return !this.isAtLeastOneAnimationPlaying() &&
|
||||
this.animations.every(({state}) => state.currentTime === 0);
|
||||
},
|
||||
|
||||
hasInfiniteAnimations: function() {
|
||||
return this.animations.some(({state}) => !state.iterationCount);
|
||||
},
|
||||
|
||||
startAnimatingScrubber: function(time) {
|
||||
let x = TimeScale.startTimeToDistance(time);
|
||||
this.scrubberEl.style.left = x + "%";
|
||||
|
||||
// Only stop the scrubber if it's out of bounds or all animations have been
|
||||
// paused, but not if at least an animation is infinite.
|
||||
let isOutOfBounds = time < TimeScale.minStartTime ||
|
||||
time > TimeScale.maxEndTime;
|
||||
let isAllPaused = !this.isAtLeastOneAnimationPlaying();
|
||||
let hasInfinite = this.hasInfiniteAnimations();
|
||||
|
||||
if (isAllPaused || (isOutOfBounds && !hasInfinite)) {
|
||||
this.stopAnimatingScrubber();
|
||||
this.emit("timeline-data-changed", {
|
||||
isPaused: !this.isAtLeastOneAnimationPlaying(),
|
||||
isMoving: false,
|
||||
isUserDrag: false,
|
||||
time: TimeScale.distanceToRelativeTime(x)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.emit("timeline-data-changed", {
|
||||
isPaused: false,
|
||||
isMoving: true,
|
||||
isUserDrag: false,
|
||||
time: TimeScale.distanceToRelativeTime(x)
|
||||
});
|
||||
|
||||
let now = this.win.performance.now();
|
||||
this.rafID = this.win.requestAnimationFrame(() => {
|
||||
if (!this.rafID) {
|
||||
// In case the scrubber was stopped in the meantime.
|
||||
return;
|
||||
}
|
||||
this.startAnimatingScrubber(time + this.win.performance.now() - now);
|
||||
});
|
||||
},
|
||||
|
||||
stopAnimatingScrubber: function() {
|
||||
if (this.rafID) {
|
||||
this.win.cancelAnimationFrame(this.rafID);
|
||||
this.rafID = null;
|
||||
}
|
||||
},
|
||||
|
||||
onAnimationStateChanged: function() {
|
||||
// For now, simply re-render the component. The animation front's state has
|
||||
// already been updated.
|
||||
this.render(this.animations);
|
||||
},
|
||||
|
||||
drawHeaderAndBackground: function() {
|
||||
let width = this.timeHeaderEl.offsetWidth;
|
||||
let scale = width / (TimeScale.maxEndTime - TimeScale.minStartTime);
|
||||
drawGraphElementBackground(this.win.document, "time-graduations",
|
||||
width, scale);
|
||||
|
||||
// And the time graduation header.
|
||||
this.timeHeaderEl.innerHTML = "";
|
||||
let interval = findOptimalTimeInterval(scale, TIME_GRADUATION_MIN_SPACING);
|
||||
for (let i = 0; i < width; i += interval) {
|
||||
let pos = 100 * i / width;
|
||||
createNode({
|
||||
parent: this.timeHeaderEl,
|
||||
nodeType: "span",
|
||||
attributes: {
|
||||
"class": "time-tick",
|
||||
"style": `left:${pos}%`
|
||||
},
|
||||
textContent: TimeScale.formatTime(TimeScale.distanceToRelativeTime(pos))
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
70
devtools/client/animationinspector/components/keyframes.js
Normal file
@ -0,0 +1,70 @@
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {createNode} = require("devtools/client/animationinspector/utils");
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a list of keyframes.
|
||||
*/
|
||||
function Keyframes() {
|
||||
EventEmitter.decorate(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
exports.Keyframes = Keyframes;
|
||||
|
||||
Keyframes.prototype = {
|
||||
init: function(containerEl) {
|
||||
this.containerEl = containerEl;
|
||||
|
||||
this.keyframesEl = createNode({
|
||||
parent: this.containerEl,
|
||||
attributes: {"class": "keyframes"}
|
||||
});
|
||||
|
||||
this.containerEl.addEventListener("click", this.onClick);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.containerEl.removeEventListener("click", this.onClick);
|
||||
this.keyframesEl.remove();
|
||||
this.containerEl = this.keyframesEl = this.animation = null;
|
||||
},
|
||||
|
||||
render: function({keyframes, propertyName, animation}) {
|
||||
this.keyframes = keyframes;
|
||||
this.propertyName = propertyName;
|
||||
this.animation = animation;
|
||||
|
||||
this.keyframesEl.classList.add(animation.state.type);
|
||||
for (let frame of this.keyframes) {
|
||||
createNode({
|
||||
parent: this.keyframesEl,
|
||||
attributes: {
|
||||
"class": "frame",
|
||||
"style": `left:${frame.offset * 100}%;`,
|
||||
"data-offset": frame.offset,
|
||||
"data-property": propertyName,
|
||||
"title": frame.value
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onClick: function(e) {
|
||||
// If the click happened on a frame, tell our parent about it.
|
||||
if (!e.target.classList.contains("frame")) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
this.emit("frame-selected", {
|
||||
animation: this.animation,
|
||||
propertyName: this.propertyName,
|
||||
offset: parseFloat(e.target.dataset.offset),
|
||||
value: e.target.getAttribute("title"),
|
||||
x: e.target.offsetLeft + e.target.closest(".frames").offsetLeft
|
||||
});
|
||||
}
|
||||
};
|
12
devtools/client/animationinspector/components/moz.build
Normal file
@ -0,0 +1,12 @@
|
||||
# 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/.
|
||||
|
||||
DevToolsModules(
|
||||
'animation-details.js',
|
||||
'animation-target-node.js',
|
||||
'animation-time-block.js',
|
||||
'animation-timeline.js',
|
||||
'keyframes.js',
|
||||
'rate-selector.js'
|
||||
)
|
@ -0,0 +1,95 @@
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {createNode} = require("devtools/client/animationinspector/utils");
|
||||
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
// List of playback rate presets displayed in the timeline toolbar.
|
||||
const PLAYBACK_RATES = [.1, .25, .5, 1, 2, 5, 10];
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying a playback rate selector UI.
|
||||
* The rendering logic is such that a predefined list of rates is generated.
|
||||
* If *all* animations passed to render share the same rate, then that rate is
|
||||
* selected in the <select> element, otherwise, the empty value is selected.
|
||||
* If the rate that all animations share isn't part of the list of predefined
|
||||
* rates, than that rate is added to the list.
|
||||
*/
|
||||
function RateSelector() {
|
||||
this.onRateChanged = this.onRateChanged.bind(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.RateSelector = RateSelector;
|
||||
|
||||
RateSelector.prototype = {
|
||||
init: function(containerEl) {
|
||||
this.selectEl = createNode({
|
||||
parent: containerEl,
|
||||
nodeType: "select",
|
||||
attributes: {"class": "devtools-button"}
|
||||
});
|
||||
|
||||
this.selectEl.addEventListener("change", this.onRateChanged);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.selectEl.removeEventListener("change", this.onRateChanged);
|
||||
this.selectEl.remove();
|
||||
this.selectEl = null;
|
||||
},
|
||||
|
||||
getAnimationsRates: function(animations) {
|
||||
return sortedUnique(animations.map(a => a.state.playbackRate));
|
||||
},
|
||||
|
||||
getAllRates: function(animations) {
|
||||
let animationsRates = this.getAnimationsRates(animations);
|
||||
if (animationsRates.length > 1) {
|
||||
return PLAYBACK_RATES;
|
||||
}
|
||||
|
||||
return sortedUnique(PLAYBACK_RATES.concat(animationsRates));
|
||||
},
|
||||
|
||||
render: function(animations) {
|
||||
let allRates = this.getAnimationsRates(animations);
|
||||
let hasOneRate = allRates.length === 1;
|
||||
|
||||
this.selectEl.innerHTML = "";
|
||||
|
||||
if (!hasOneRate) {
|
||||
// When the animations displayed have mixed playback rates, we can't
|
||||
// select any of the predefined ones, instead, insert an empty rate.
|
||||
createNode({
|
||||
parent: this.selectEl,
|
||||
nodeType: "option",
|
||||
attributes: {value: "", selector: "true"},
|
||||
textContent: "-"
|
||||
});
|
||||
}
|
||||
for (let rate of this.getAllRates(animations)) {
|
||||
let option = createNode({
|
||||
parent: this.selectEl,
|
||||
nodeType: "option",
|
||||
attributes: {value: rate},
|
||||
textContent: L10N.getFormatStr("player.playbackRateLabel", rate)
|
||||
});
|
||||
|
||||
// If there's only one rate and this is the option for it, select it.
|
||||
if (hasOneRate && rate === allRates[0]) {
|
||||
option.setAttribute("selected", "true");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onRateChanged: function() {
|
||||
let rate = parseFloat(this.selectEl.value);
|
||||
if (!isNaN(rate)) {
|
||||
this.emit("rate-changed", rate);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let sortedUnique = arr => [...new Set(arr)].sort((a, b) => a > b);
|
@ -7,7 +7,10 @@
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
||||
DIRS += [
|
||||
'components'
|
||||
]
|
||||
|
||||
DevToolsModules(
|
||||
'components.js',
|
||||
'utils.js',
|
||||
)
|
||||
|
@ -8,9 +8,11 @@ requestLongerTimeout(2);
|
||||
|
||||
// Check that the timeline shows correct time graduations in the header.
|
||||
|
||||
const {findOptimalTimeInterval} = require("devtools/client/animationinspector/utils");
|
||||
const {TimeScale} = require("devtools/client/animationinspector/components");
|
||||
// Should be kept in sync with TIME_GRADUATION_MIN_SPACING in components.js
|
||||
const {
|
||||
findOptimalTimeInterval,
|
||||
TimeScale
|
||||
} = require("devtools/client/animationinspector/utils");
|
||||
// Should be kept in sync with TIME_GRADUATION_MIN_SPACING in animation-timeline.js
|
||||
const TIME_GRADUATION_MIN_SPACING = 40;
|
||||
|
||||
add_task(function*() {
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
var Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {getCssPropertyName} = require("devtools/client/animationinspector/components");
|
||||
const {getCssPropertyName} = require("devtools/client/animationinspector/components/animation-details");
|
||||
|
||||
const TEST_DATA = [{
|
||||
jsName: "alllowercase",
|
||||
|
@ -7,8 +7,7 @@
|
||||
|
||||
var Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {TimeScale} = require("devtools/client/animationinspector/components");
|
||||
|
||||
const {TimeScale} = require("devtools/client/animationinspector/utils");
|
||||
const TEST_ANIMATIONS = [{
|
||||
desc: "Testing a few standard animations",
|
||||
animations: [{
|
||||
|
@ -7,11 +7,14 @@
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
var {loader} = Cu.import("resource://devtools/shared/Loader.jsm");
|
||||
loader.lazyRequireGetter(this, "EventEmitter",
|
||||
"devtools/shared/event-emitter");
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
// How many times, maximum, can we loop before we find the optimal time
|
||||
// interval in the timeline graph.
|
||||
const OPTIMAL_TIME_INTERVAL_MAX_ITERS = 100;
|
||||
@ -27,6 +30,8 @@ const TIME_INTERVAL_OPACITY_MIN = 32;
|
||||
// byte
|
||||
const TIME_INTERVAL_OPACITY_ADD = 32;
|
||||
|
||||
const MILLIS_TIME_FORMAT_MAX_DURATION = 4000;
|
||||
|
||||
/**
|
||||
* DOM node creation helper function.
|
||||
* @param {Object} Options to customize the node to be created.
|
||||
@ -208,3 +213,139 @@ function formatStopwatchTime(time) {
|
||||
}
|
||||
|
||||
exports.formatStopwatchTime = formatStopwatchTime;
|
||||
|
||||
/**
|
||||
* The TimeScale helper object is used to know which size should something be
|
||||
* displayed with in the animation panel, depending on the animations that are
|
||||
* currently displayed.
|
||||
* If there are 5 animations displayed, and the first one starts at 10000ms and
|
||||
* the last one ends at 20000ms, then this helper can be used to convert any
|
||||
* time in this range to a distance in pixels.
|
||||
*
|
||||
* For the helper to know how to convert, it needs to know all the animations.
|
||||
* Whenever a new animation is added to the panel, addAnimation(state) should be
|
||||
* called. reset() can be called to start over.
|
||||
*/
|
||||
var TimeScale = {
|
||||
minStartTime: Infinity,
|
||||
maxEndTime: 0,
|
||||
|
||||
/**
|
||||
* Add a new animation to time scale.
|
||||
* @param {Object} state A PlayerFront.state object.
|
||||
*/
|
||||
addAnimation: function(state) {
|
||||
let {previousStartTime, delay, duration,
|
||||
iterationCount, playbackRate} = state;
|
||||
|
||||
// Negative-delayed animations have their startTimes set such that we would
|
||||
// be displaying the delay outside the time window if we didn't take it into
|
||||
// account here.
|
||||
let relevantDelay = delay < 0 ? delay / playbackRate : 0;
|
||||
previousStartTime = previousStartTime || 0;
|
||||
|
||||
this.minStartTime = Math.min(this.minStartTime,
|
||||
previousStartTime + relevantDelay);
|
||||
let length = (delay / playbackRate) +
|
||||
((duration / playbackRate) *
|
||||
(!iterationCount ? 1 : iterationCount));
|
||||
let endTime = previousStartTime + length;
|
||||
this.maxEndTime = Math.max(this.maxEndTime, endTime);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the current time scale.
|
||||
*/
|
||||
reset: function() {
|
||||
this.minStartTime = Infinity;
|
||||
this.maxEndTime = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a startTime to a distance in %, in the current time scale.
|
||||
* @param {Number} time
|
||||
* @return {Number}
|
||||
*/
|
||||
startTimeToDistance: function(time) {
|
||||
time -= this.minStartTime;
|
||||
return this.durationToDistance(time);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a duration to a distance in %, in the current time scale.
|
||||
* @param {Number} time
|
||||
* @return {Number}
|
||||
*/
|
||||
durationToDistance: function(duration) {
|
||||
return duration * 100 / this.getDuration();
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a distance in % to a time, in the current time scale.
|
||||
* @param {Number} distance
|
||||
* @return {Number}
|
||||
*/
|
||||
distanceToTime: function(distance) {
|
||||
return this.minStartTime + (this.getDuration() * distance / 100);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a distance in % to a time, in the current time scale.
|
||||
* The time will be relative to the current minimum start time.
|
||||
* @param {Number} distance
|
||||
* @return {Number}
|
||||
*/
|
||||
distanceToRelativeTime: function(distance) {
|
||||
let time = this.distanceToTime(distance);
|
||||
return time - this.minStartTime;
|
||||
},
|
||||
|
||||
/**
|
||||
* Depending on the time scale, format the given time as milliseconds or
|
||||
* seconds.
|
||||
* @param {Number} time
|
||||
* @return {String} The formatted time string.
|
||||
*/
|
||||
formatTime: function(time) {
|
||||
// Format in milliseconds if the total duration is short enough.
|
||||
if (this.getDuration() <= MILLIS_TIME_FORMAT_MAX_DURATION) {
|
||||
return L10N.getFormatStr("timeline.timeGraduationLabel", time.toFixed(0));
|
||||
}
|
||||
|
||||
// Otherwise format in seconds.
|
||||
return L10N.getFormatStr("player.timeLabel", (time / 1000).toFixed(1));
|
||||
},
|
||||
|
||||
getDuration: function() {
|
||||
return this.maxEndTime - this.minStartTime;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given an animation, get the various dimensions (in %) useful to draw the
|
||||
* animation in the timeline.
|
||||
*/
|
||||
getAnimationDimensions: function({state}) {
|
||||
let start = state.previousStartTime || 0;
|
||||
let duration = state.duration;
|
||||
let rate = state.playbackRate;
|
||||
let count = state.iterationCount;
|
||||
let delay = state.delay || 0;
|
||||
|
||||
// The start position.
|
||||
let x = this.startTimeToDistance(start + (delay / rate));
|
||||
// The width for a single iteration.
|
||||
let w = this.durationToDistance(duration / rate);
|
||||
// The width for all iterations.
|
||||
let iterationW = w * (count || 1);
|
||||
// The start position of the delay.
|
||||
let delayX = this.durationToDistance((delay < 0 ? 0 : delay) / rate);
|
||||
// The width of the delay.
|
||||
let delayW = this.durationToDistance(Math.abs(delay) / rate);
|
||||
// The width of the delay if it is positive, 0 otherwise.
|
||||
let negativeDelayW = delay < 0 ? delayW : 0;
|
||||
|
||||
return {x, w, iterationW, delayX, delayW, negativeDelayW};
|
||||
}
|
||||
};
|
||||
|
||||
exports.TimeScale = TimeScale;
|
||||
|
@ -79,15 +79,13 @@ function testSetBreakpointBlankLine() {
|
||||
let sourceForm = getSourceForm(gSources, COFFEE_URL);
|
||||
|
||||
let source = gDebugger.gThreadClient.source(sourceForm);
|
||||
source.setBreakpoint({ line: 7 }, aResponse => {
|
||||
source.setBreakpoint({ line: 8 }, aResponse => {
|
||||
ok(!aResponse.error,
|
||||
"Should be able to set a breakpoint in a coffee source file on a blank line.");
|
||||
ok(aResponse.actualLocation,
|
||||
"Because 7 is empty, we should have an actualLocation.");
|
||||
is(aResponse.actualLocation.source.url, COFFEE_URL,
|
||||
"actualLocation.actor should be source mapped to the coffee file.");
|
||||
is(aResponse.actualLocation.line, 8,
|
||||
"actualLocation.line should be source mapped back to 8.");
|
||||
"Should be able to set a breakpoint in a coffee source file on a blank line.");
|
||||
ok(!aResponse.isPending,
|
||||
"Should not be a pending breakpoint.");
|
||||
ok(!aResponse.actualLocation,
|
||||
"Should not be a moved breakpoint.");
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
|
@ -42,6 +42,8 @@ support-files =
|
||||
[browser_rules_add-rule_04.js]
|
||||
[browser_rules_add-rule_pseudo_class.js]
|
||||
[browser_rules_authored.js]
|
||||
[browser_rules_authored_color.js]
|
||||
[browser_rules_authored_override.js]
|
||||
[browser_rules_colorpicker-and-image-tooltip_01.js]
|
||||
[browser_rules_colorpicker-and-image-tooltip_02.js]
|
||||
[browser_rules_colorpicker-appears-on-swatch-click.js]
|
||||
|
@ -6,12 +6,6 @@
|
||||
|
||||
// Test for as-authored styles.
|
||||
|
||||
add_task(function*() {
|
||||
yield basicTest();
|
||||
yield overrideTest();
|
||||
yield colorEditingTest();
|
||||
});
|
||||
|
||||
function* createTestContent(style) {
|
||||
let content = `<style type="text/css">
|
||||
${style}
|
||||
@ -24,7 +18,7 @@ function* createTestContent(style) {
|
||||
return view;
|
||||
}
|
||||
|
||||
function* basicTest() {
|
||||
add_task(function* () {
|
||||
let view = yield createTestContent("#testid {" +
|
||||
// Invalid property.
|
||||
" something: random;" +
|
||||
@ -52,79 +46,4 @@ function* basicTest() {
|
||||
is(prop.overridden, expected[i].overridden,
|
||||
"test overridden for prop " + i);
|
||||
}
|
||||
}
|
||||
|
||||
function* overrideTest() {
|
||||
let gradientText1 = "(orange, blue);";
|
||||
let gradientText2 = "(pink, teal);";
|
||||
|
||||
let view =
|
||||
yield createTestContent("#testid {" +
|
||||
" background-image: linear-gradient" +
|
||||
gradientText1 +
|
||||
" background-image: -ms-linear-gradient" +
|
||||
gradientText2 +
|
||||
" background-image: linear-gradient" +
|
||||
gradientText2 +
|
||||
"} ");
|
||||
|
||||
let elementStyle = view._elementStyle;
|
||||
let rule = elementStyle.rules[1];
|
||||
|
||||
// Initially the last property should be active.
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
let prop = rule.textProps[i];
|
||||
is(prop.name, "background-image", "check the property name");
|
||||
is(prop.overridden, i !== 2, "check overridden for " + i);
|
||||
}
|
||||
|
||||
rule.textProps[2].setEnabled(false);
|
||||
yield rule._applyingModifications;
|
||||
|
||||
// Now the first property should be active.
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
let prop = rule.textProps[i];
|
||||
is(prop.overridden || !prop.enabled, i !== 0,
|
||||
"post-change check overridden for " + i);
|
||||
}
|
||||
}
|
||||
|
||||
function* colorEditingTest() {
|
||||
let colors = [
|
||||
{name: "hex", text: "#f0c", result: "#0f0"},
|
||||
{name: "rgb", text: "rgb(0,128,250)", result: "rgb(0, 255, 0)"},
|
||||
// Test case preservation.
|
||||
{name: "hex", text: "#F0C", result: "#0F0"},
|
||||
];
|
||||
|
||||
Services.prefs.setCharPref("devtools.defaultColorUnit", "authored");
|
||||
|
||||
for (let color of colors) {
|
||||
let view = yield createTestContent("#testid {" +
|
||||
" color: " + color.text + ";" +
|
||||
"} ");
|
||||
|
||||
let cPicker = view.tooltips.colorPicker;
|
||||
let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan
|
||||
.querySelector(".ruleview-colorswatch");
|
||||
let onShown = cPicker.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShown;
|
||||
|
||||
let testNode = yield getNode("#testid");
|
||||
|
||||
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
|
||||
element: testNode,
|
||||
name: "color",
|
||||
value: "rgb(0, 255, 0)"
|
||||
});
|
||||
|
||||
let spectrum = yield cPicker.spectrum;
|
||||
let onHidden = cPicker.tooltip.once("hidden");
|
||||
EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
|
||||
is(getRuleViewPropertyValue(view, "#testid", "color"), color.result,
|
||||
"changing the color preserved the unit for " + color.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,59 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test for as-authored styles.
|
||||
|
||||
function* createTestContent(style) {
|
||||
let content = `<style type="text/css">
|
||||
${style}
|
||||
</style>
|
||||
<div id="testid" class="testclass">Styled Node</div>`;
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(content));
|
||||
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
return view;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let colors = [
|
||||
{name: "hex", text: "#f0c", result: "#0f0"},
|
||||
{name: "rgb", text: "rgb(0,128,250)", result: "rgb(0, 255, 0)"},
|
||||
// Test case preservation.
|
||||
{name: "hex", text: "#F0C", result: "#0F0"},
|
||||
];
|
||||
|
||||
Services.prefs.setCharPref("devtools.defaultColorUnit", "authored");
|
||||
|
||||
for (let color of colors) {
|
||||
let view = yield createTestContent("#testid {" +
|
||||
" color: " + color.text + ";" +
|
||||
"} ");
|
||||
|
||||
let cPicker = view.tooltips.colorPicker;
|
||||
let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan
|
||||
.querySelector(".ruleview-colorswatch");
|
||||
let onShown = cPicker.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShown;
|
||||
|
||||
let testNode = yield getNode("#testid");
|
||||
|
||||
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
|
||||
element: testNode,
|
||||
name: "color",
|
||||
value: "rgb(0, 255, 0)"
|
||||
});
|
||||
|
||||
let spectrum = yield cPicker.spectrum;
|
||||
let onHidden = cPicker.tooltip.once("hidden");
|
||||
EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
|
||||
is(getRuleViewPropertyValue(view, "#testid", "color"), color.result,
|
||||
"changing the color preserved the unit for " + color.name);
|
||||
}
|
||||
});
|
@ -0,0 +1,54 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test for as-authored styles.
|
||||
|
||||
function* createTestContent(style) {
|
||||
let content = `<style type="text/css">
|
||||
${style}
|
||||
</style>
|
||||
<div id="testid" class="testclass">Styled Node</div>`;
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(content));
|
||||
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
return view;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let gradientText1 = "(orange, blue);";
|
||||
let gradientText2 = "(pink, teal);";
|
||||
|
||||
let view =
|
||||
yield createTestContent("#testid {" +
|
||||
" background-image: linear-gradient" +
|
||||
gradientText1 +
|
||||
" background-image: -ms-linear-gradient" +
|
||||
gradientText2 +
|
||||
" background-image: linear-gradient" +
|
||||
gradientText2 +
|
||||
"} ");
|
||||
|
||||
let elementStyle = view._elementStyle;
|
||||
let rule = elementStyle.rules[1];
|
||||
|
||||
// Initially the last property should be active.
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
let prop = rule.textProps[i];
|
||||
is(prop.name, "background-image", "check the property name");
|
||||
is(prop.overridden, i !== 2, "check overridden for " + i);
|
||||
}
|
||||
|
||||
rule.textProps[2].setEnabled(false);
|
||||
yield rule._applyingModifications;
|
||||
|
||||
// Now the first property should be active.
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
let prop = rule.textProps[i];
|
||||
is(prop.overridden || !prop.enabled, i !== 0,
|
||||
"post-change check overridden for " + i);
|
||||
}
|
||||
});
|
@ -841,14 +841,13 @@ MarkupView.prototype = {
|
||||
// we're not viewing.
|
||||
continue;
|
||||
}
|
||||
if (type === "attributes" || type === "characterData") {
|
||||
if (type === "attributes" || type === "characterData"
|
||||
|| type === "events" || type === "pseudoClassLock") {
|
||||
container.update();
|
||||
} else if (type === "childList" || type === "nativeAnonymousChildList") {
|
||||
container.childrenDirty = true;
|
||||
// Update the children to take care of changes in the markup view DOM.
|
||||
this._updateChildren(container, {flash: true});
|
||||
} else if (type === "pseudoClassLock") {
|
||||
container.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2547,7 +2546,6 @@ function ElementEditor(aContainer, aNode) {
|
||||
let tagName = this.node.nodeName.toLowerCase();
|
||||
this.tag.textContent = tagName;
|
||||
this.closeTag.textContent = tagName;
|
||||
this.eventNode.style.display = this.node.hasEventListeners ? "inline-block" : "none";
|
||||
|
||||
this.update();
|
||||
this.initialized = true;
|
||||
@ -2643,6 +2641,10 @@ ElementEditor.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// Update the event bubble display
|
||||
this.eventNode.style.display = this.node.hasEventListeners ?
|
||||
"inline-block" : "none";
|
||||
|
||||
this.updateTextEditor();
|
||||
},
|
||||
|
||||
|
@ -152,6 +152,42 @@ const TEST_DATA = [
|
||||
}
|
||||
]
|
||||
},
|
||||
// #noevents tests check that dynamically added events are properly displayed
|
||||
// in the markupview
|
||||
{
|
||||
selector: "#noevents",
|
||||
expected: []
|
||||
},
|
||||
{
|
||||
selector: "#noevents",
|
||||
beforeTest: function* (inspector, testActor) {
|
||||
let nodeMutated = inspector.once("markupmutation");
|
||||
yield testActor.eval("window.wrappedJSObject.addNoeventsClickHandler();");
|
||||
yield nodeMutated;
|
||||
},
|
||||
expected: [
|
||||
{
|
||||
type: "click",
|
||||
filename: TEST_URL + ":106",
|
||||
attributes: [
|
||||
"Bubbling",
|
||||
"DOM2"
|
||||
],
|
||||
handler: 'function noeventsClickHandler(event) {\n' +
|
||||
' alert("noevents has an event listener");\n' +
|
||||
'}'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
selector: "#noevents",
|
||||
beforeTest: function* (inspector, testActor) {
|
||||
let nodeMutated = inspector.once("markupmutation");
|
||||
yield testActor.eval("window.wrappedJSObject.removeNoeventsClickHandler();");
|
||||
yield nodeMutated;
|
||||
},
|
||||
expected: []
|
||||
},
|
||||
];
|
||||
|
||||
add_task(runEventPopupTests);
|
||||
|
@ -102,6 +102,20 @@
|
||||
alert("boundHandleEvent clicked");
|
||||
}
|
||||
};
|
||||
|
||||
function noeventsClickHandler(event) {
|
||||
alert("noevents has an event listener");
|
||||
};
|
||||
|
||||
function addNoeventsClickHandler() {
|
||||
let noevents = document.getElementById("noevents");
|
||||
noevents.addEventListener("click", noeventsClickHandler);
|
||||
};
|
||||
|
||||
function removeNoeventsClickHandler() {
|
||||
let noevents = document.getElementById("noevents");
|
||||
noevents.removeEventListener("click", noeventsClickHandler);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init();">
|
||||
|
@ -7,12 +7,12 @@
|
||||
* TEST_DATA array.
|
||||
*/
|
||||
function* runEventPopupTests() {
|
||||
let {inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
let {inspector, testActor} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
yield inspector.markup.expandAll();
|
||||
|
||||
for (let {selector, expected} of TEST_DATA) {
|
||||
yield checkEventsForNode(selector, expected, inspector);
|
||||
for (let test of TEST_DATA) {
|
||||
yield checkEventsForNode(test, inspector, testActor);
|
||||
}
|
||||
|
||||
// Wait for promises to avoid leaks when running this as a single test.
|
||||
@ -25,12 +25,36 @@ function* runEventPopupTests() {
|
||||
* Generator function that takes a selector and expected results and returns
|
||||
* the event info.
|
||||
*
|
||||
* @param {String} selector
|
||||
* Selector pointing at the node to be inspected
|
||||
* @param {Object} test
|
||||
* A test object should contain the following properties:
|
||||
* - selector {String} a css selector targeting the node to edit
|
||||
* - expected {Array} array of expected event objects
|
||||
* - type {String} event type
|
||||
* - filename {String} filename:line where the evt handler is defined
|
||||
* - attributes {Array} array of event attributes ({String})
|
||||
* - handler {String} string representation of the handler
|
||||
* - beforeTest {Function} (optional) a function to execute on the page
|
||||
* before running the test
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
|
||||
* opened
|
||||
* @param {TestActorFront} testActor
|
||||
*/
|
||||
function* checkEventsForNode(selector, expected, inspector) {
|
||||
function* checkEventsForNode(test, inspector, testActor) {
|
||||
let {selector, expected, beforeTest} = test;
|
||||
let container = yield getContainerForSelector(selector, inspector);
|
||||
|
||||
if (typeof beforeTest === "function") {
|
||||
yield beforeTest(inspector, testActor);
|
||||
}
|
||||
|
||||
let evHolder = container.elt.querySelector(".markupview-events");
|
||||
|
||||
if (expected.length === 0) {
|
||||
// if no event is expected, simply check that the event bubble is hidden
|
||||
is(evHolder.style.display, "none", "event bubble should be hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
let tooltip = inspector.markup.tooltip;
|
||||
|
||||
yield selectNode(selector, inspector);
|
||||
|
@ -44,11 +44,14 @@ function* spawnTest() {
|
||||
// Expand the root and test the child items...
|
||||
|
||||
let receivedExpandEvent = treeRoot.once("expand");
|
||||
let receivedInitialFocusEvent = treeRoot.once("focus");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, treeRoot.target.querySelector(".arrow"));
|
||||
|
||||
let eventItem = yield receivedExpandEvent;
|
||||
is(eventItem, treeRoot,
|
||||
"The 'expand' event target is correct.");
|
||||
|
||||
yield receivedInitialFocusEvent;
|
||||
is(document.commandDispatcher.focusedElement, treeRoot.target,
|
||||
"The root node is now focused.");
|
||||
|
||||
|
@ -863,6 +863,8 @@ var NodeFront = protocol.FrontClass(NodeActor, {
|
||||
this._form.incompleteValue = change.incompleteValue;
|
||||
} else if (change.type === "pseudoClassLock") {
|
||||
this._form.pseudoClassLocks = change.pseudoClassLocks;
|
||||
} else if (change.type === "events") {
|
||||
this._form.hasEventListeners = change.hasEventListeners;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1348,6 +1350,32 @@ var WalkerActor = protocol.ActorClass({
|
||||
this.layoutChangeObserver.on("reflows", this._onReflows);
|
||||
this._onResize = this._onResize.bind(this);
|
||||
this.layoutChangeObserver.on("resize", this._onResize);
|
||||
|
||||
this._onEventListenerChange = this._onEventListenerChange.bind(this);
|
||||
eventListenerService.addListenerChangeListener(this._onEventListenerChange);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for eventListenerService.addListenerChangeListener
|
||||
* @param nsISimpleEnumerator changesEnum
|
||||
* enumerator of nsIEventListenerChange
|
||||
*/
|
||||
_onEventListenerChange: function(changesEnum) {
|
||||
let changes = changesEnum.enumerate();
|
||||
while (changes.hasMoreElements()) {
|
||||
let current = changes.getNext().QueryInterface(Ci.nsIEventListenerChange);
|
||||
let target = current.target;
|
||||
|
||||
if (this._refMap.has(target)) {
|
||||
let actor = this._refMap.get(target);
|
||||
let mutation = {
|
||||
type: "events",
|
||||
target: actor.actorID,
|
||||
hasEventListeners: actor._hasEventListeners
|
||||
};
|
||||
this.queueMutation(mutation);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Returns the JSON representation of this object over the wire.
|
||||
@ -1414,6 +1442,9 @@ var WalkerActor = protocol.ActorClass({
|
||||
this.layoutChangeObserver = null;
|
||||
releaseLayoutChangesObserver(this.tabActor);
|
||||
|
||||
eventListenerService.removeListenerChangeListener(
|
||||
this._onEventListenerChange);
|
||||
|
||||
this.onMutations = null;
|
||||
|
||||
this.tabActor = null;
|
||||
|
@ -2724,245 +2724,93 @@ SourceActor.prototype = {
|
||||
* @returns A Promise that resolves to the given BreakpointActor.
|
||||
*/
|
||||
_setBreakpoint: function (actor) {
|
||||
let { originalLocation } = actor;
|
||||
let { originalSourceActor, originalLine, originalColumn } = originalLocation;
|
||||
const { originalLocation } = actor;
|
||||
const { originalLine, originalSourceActor } = originalLocation;
|
||||
|
||||
return this._setBreakpointAtOriginalLocation(actor, originalLocation)
|
||||
.then((actualLocation) => {
|
||||
if (actualLocation) {
|
||||
return actualLocation;
|
||||
}
|
||||
|
||||
// There were no scripts that matched the given location, so we need to
|
||||
// perform breakpoint sliding. We try to slide the breakpoint by column
|
||||
// first, and if that fails, by line instead.
|
||||
if (!this.isSourceMapped) {
|
||||
if (originalColumn !== undefined) {
|
||||
// To perform breakpoint sliding for column breakpoints, we need to
|
||||
// build a map from column numbers to a list of entry points for each
|
||||
// column, implemented as a sparse array. An entry point is a (script,
|
||||
// offsets) pair, and represents all offsets in that script that are
|
||||
// entry points for the corresponding column.
|
||||
let columnToEntryPointsMap = [];
|
||||
|
||||
// Iterate over all scripts that correspond to this source actor and
|
||||
// line number.
|
||||
let scripts = this.scripts.getScriptsBySourceActor(this, originalLine);
|
||||
for (let script of scripts) {
|
||||
let columnToOffsetMap = script.getAllColumnOffsets()
|
||||
.filter(({ lineNumber }) => {
|
||||
return lineNumber === originalLine;
|
||||
})
|
||||
|
||||
// Iterate over each column, and add their list of offsets to the
|
||||
// map from column numbers to entry points by forming a (script,
|
||||
// offsets) pair, where script is the current script, and offsets is
|
||||
// the list of offsets for the current column.
|
||||
for (let { columnNumber: column, offset } of columnToOffsetMap) {
|
||||
let entryPoints = columnToEntryPointsMap[column];
|
||||
if (!entryPoints) {
|
||||
// We dont have a list of entry points for the current column
|
||||
// number yet, so create it and add it to the map.
|
||||
entryPoints = [];
|
||||
columnToEntryPointsMap[column] = entryPoints;
|
||||
}
|
||||
entryPoints.push({ script, offsets: [offset] });
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have a map from column numbers to a list of entry points
|
||||
// for each column, we can use it to perform breakpoint sliding. Start
|
||||
// at the original column of the breakpoint actor, and keep
|
||||
// incrementing it by one, until either we find a line that has at
|
||||
// least one entry point, or we go past the last column in the map.
|
||||
//
|
||||
// Note that by computing the entire map up front, and implementing it
|
||||
// as a sparse array, we can easily tell when we went past the last
|
||||
// column in the map.
|
||||
let actualColumn = originalColumn + 1;
|
||||
while (actualColumn < columnToEntryPointsMap.length) {
|
||||
let entryPoints = columnToEntryPointsMap[actualColumn];
|
||||
if (entryPoints) {
|
||||
setBreakpointAtEntryPoints(actor, entryPoints);
|
||||
return new OriginalLocation(
|
||||
originalSourceActor,
|
||||
originalLine,
|
||||
actualColumn
|
||||
);
|
||||
}
|
||||
++actualColumn;
|
||||
}
|
||||
|
||||
return originalLocation;
|
||||
} else {
|
||||
// To perform breakpoint sliding for line breakpoints, we need to
|
||||
// build a map from line numbers to a list of entry points for each
|
||||
// line, implemented as a sparse array. An entry point is a (script,
|
||||
// offsets) pair, and represents all offsets in that script that are
|
||||
// entry points for the corresponding line.
|
||||
let lineToEntryPointsMap = [];
|
||||
|
||||
// Iterate over all scripts that correspond to this source actor.
|
||||
let scripts = this.scripts.getScriptsBySourceActor(this);
|
||||
for (let script of scripts) {
|
||||
// Get all offsets for each line in the current script. This returns
|
||||
// a map from line numbers fo a list of offsets for each line,
|
||||
// implemented as a sparse array.
|
||||
let lineToOffsetsMap = script.getAllOffsets();
|
||||
|
||||
// Iterate over each line, and add their list of offsets to the map
|
||||
// from line numbers to entry points by forming a (script, offsets)
|
||||
// pair, where script is the current script, and offsets is the list
|
||||
// of offsets for the current line.
|
||||
for (let line = 0; line < lineToOffsetsMap.length; ++line) {
|
||||
let offsets = lineToOffsetsMap[line];
|
||||
if (offsets) {
|
||||
let entryPoints = lineToEntryPointsMap[line];
|
||||
if (!entryPoints) {
|
||||
// We dont have a list of entry points for the current line
|
||||
// number yet, so create it and add it to the map.
|
||||
entryPoints = [];
|
||||
lineToEntryPointsMap[line] = entryPoints;
|
||||
}
|
||||
entryPoints.push({ script, offsets });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have a map from line numbers to a list of entry points
|
||||
// for each line, we can use it to perform breakpoint sliding. Start
|
||||
// at the original line of the breakpoint actor, and keep incrementing
|
||||
// it by one, until either we find a line that has at least one entry
|
||||
// point, or we go past the last line in the map.
|
||||
//
|
||||
// Note that by computing the entire map up front, and implementing it
|
||||
// as a sparse array, we can easily tell when we went past the last
|
||||
// line in the map.
|
||||
let actualLine = originalLine + 1;
|
||||
while (actualLine < lineToEntryPointsMap.length) {
|
||||
let entryPoints = lineToEntryPointsMap[actualLine];
|
||||
if (entryPoints) {
|
||||
setBreakpointAtEntryPoints(actor, entryPoints);
|
||||
break;
|
||||
}
|
||||
++actualLine;
|
||||
}
|
||||
if (actualLine >= lineToEntryPointsMap.length) {
|
||||
// We went past the last line in the map, so breakpoint sliding
|
||||
// failed. Keep the BreakpointActor in the BreakpointActorMap as a
|
||||
// pending breakpoint, so we can try again whenever a new script is
|
||||
// introduced.
|
||||
return originalLocation;
|
||||
}
|
||||
|
||||
return new OriginalLocation(
|
||||
originalSourceActor,
|
||||
actualLine
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let slideByColumn = (actualColumn) => {
|
||||
return this.sources.getAllGeneratedLocations(new OriginalLocation(
|
||||
this,
|
||||
originalLine,
|
||||
actualColumn
|
||||
)).then((generatedLocations) => {
|
||||
// Because getAllGeneratedLocations will always return the list of
|
||||
// generated locations for the closest column that is greater than
|
||||
// the one we are searching for if no exact match can be found, if
|
||||
// the list of generated locations is empty, we've reached the end
|
||||
// of the original line, and sliding continues by line.
|
||||
if (generatedLocations.length === 0) {
|
||||
return slideByLine(originalLine + 1);
|
||||
}
|
||||
|
||||
// If at least one script has an offset that matches one of the
|
||||
// generated locations in the list, then breakpoint sliding
|
||||
// succeeded.
|
||||
if (this._setBreakpointAtAllGeneratedLocations(actor, generatedLocations)) {
|
||||
return this.threadActor.sources.getOriginalLocation(generatedLocations[0]);
|
||||
}
|
||||
|
||||
// Try the next column in the original source.
|
||||
return slideByColumn(actualColumn + 1);
|
||||
});
|
||||
};
|
||||
|
||||
let slideByLine = (actualLine) => {
|
||||
return this.sources.getAllGeneratedLocations(new OriginalLocation(
|
||||
this,
|
||||
actualLine
|
||||
)).then((generatedLocations) => {
|
||||
// Because getAllGeneratedLocations will always return the list of
|
||||
// generated locations for the closest line that is greater than
|
||||
// the one we are searching for if no exact match can be found, if
|
||||
// the list of generated locations is empty, we've reached the end
|
||||
// of the original source, and breakpoint sliding failed.
|
||||
if (generatedLocations.length === 0) {
|
||||
return originalLocation;
|
||||
}
|
||||
|
||||
// If at least one script has an offset that matches one of the
|
||||
// generated locations in the list, then breakpoint sliding
|
||||
// succeeded.
|
||||
if (this._setBreakpointAtAllGeneratedLocations(actor, generatedLocations)) {
|
||||
return this.threadActor.sources.getOriginalLocation(generatedLocations[0]);
|
||||
}
|
||||
|
||||
// Try the next line in the original source.
|
||||
return slideByLine(actualLine + 1);
|
||||
});
|
||||
};
|
||||
|
||||
if (originalColumn !== undefined) {
|
||||
return slideByColumn(originalColumn + 1);
|
||||
} else {
|
||||
return slideByLine(originalLine + 1);
|
||||
}
|
||||
}
|
||||
}).then((actualLocation) => {
|
||||
// If the actual location on which the BreakpointActor ended up being
|
||||
// set differs from the original line that was requested, both the
|
||||
// BreakpointActor and the BreakpointActorMap need to be updated
|
||||
// accordingly.
|
||||
if (!actualLocation.equals(originalLocation)) {
|
||||
let existingActor = this.breakpointActorMap.getActor(actualLocation);
|
||||
if (existingActor) {
|
||||
actor.onDelete();
|
||||
this.breakpointActorMap.deleteActor(originalLocation);
|
||||
actor = existingActor;
|
||||
} else {
|
||||
this.breakpointActorMap.deleteActor(originalLocation);
|
||||
actor.originalLocation = actualLocation;
|
||||
this.breakpointActorMap.setActor(actualLocation, actor);
|
||||
}
|
||||
}
|
||||
|
||||
return actor;
|
||||
});
|
||||
},
|
||||
|
||||
_setBreakpointAtOriginalLocation: function (actor, originalLocation) {
|
||||
if (!this.isSourceMapped) {
|
||||
if (!this._setBreakpointAtGeneratedLocation(
|
||||
actor,
|
||||
GeneratedLocation.fromOriginalLocation(originalLocation)
|
||||
)) {
|
||||
return promise.resolve(null);
|
||||
}
|
||||
const scripts = this.scripts.getScriptsBySourceActorAndLine(
|
||||
this,
|
||||
originalLine
|
||||
);
|
||||
|
||||
return promise.resolve(originalLocation);
|
||||
} else {
|
||||
return this.sources.getAllGeneratedLocations(originalLocation)
|
||||
.then((generatedLocations) => {
|
||||
if (!this._setBreakpointAtAllGeneratedLocations(
|
||||
actor,
|
||||
generatedLocations
|
||||
)) {
|
||||
return null;
|
||||
// Never do breakpoint sliding for column breakpoints.
|
||||
// Additionally, never do breakpoint sliding if no scripts
|
||||
// exist on this line.
|
||||
//
|
||||
// Sliding can go horribly wrong if we always try to find the
|
||||
// next line with valid entry points in the entire file.
|
||||
// Scripts may be completely GCed and we never knew they
|
||||
// existed, so we end up sliding through whole functions to
|
||||
// the user's bewilderment.
|
||||
//
|
||||
// We can slide reliably if any scripts exist, however, due
|
||||
// to how scripts are kept alive. A parent Debugger.Script
|
||||
// keeps all of its children alive, so as long as we have a
|
||||
// valid script, we can slide through it and know we won't
|
||||
// slide through any of its child scripts. Additionally, if a
|
||||
// script gets GCed, that means that all parents scripts are
|
||||
// GCed as well, and no scripts will exist on those lines
|
||||
// anymore. We will never slide through a GCed script.
|
||||
if (originalLocation.originalColumn || scripts.length === 0) {
|
||||
return promise.resolve(actor);
|
||||
}
|
||||
|
||||
return this.threadActor.sources.getOriginalLocation(generatedLocations[0]);
|
||||
// Find the script that spans the largest amount of code to
|
||||
// determine the bounds for sliding.
|
||||
const largestScript = scripts.reduce((largestScript, script) => {
|
||||
if (script.lineCount > largestScript.lineCount) {
|
||||
return script;
|
||||
}
|
||||
return largestScript;
|
||||
});
|
||||
const maxLine = largestScript.startLine + largestScript.lineCount - 1;
|
||||
|
||||
let actualLine = originalLine;
|
||||
for (; actualLine <= maxLine; actualLine++) {
|
||||
const loc = new GeneratedLocation(this, actualLine);
|
||||
if (this._setBreakpointAtGeneratedLocation(actor, loc)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The above loop should never complete. We only did breakpoint sliding
|
||||
// because we found scripts on the line we started from,
|
||||
// which means there must be valid entry points somewhere
|
||||
// within those scripts.
|
||||
assert(
|
||||
actualLine <= maxLine,
|
||||
"Could not find any entry points to set a breakpoint on, " +
|
||||
"even though I was told a script existed on the line I started " +
|
||||
"the search with."
|
||||
);
|
||||
|
||||
// Update the actor to use the new location (reusing a
|
||||
// previous breakpoint if it already exists on that line).
|
||||
const actualLocation = new OriginalLocation(originalSourceActor, actualLine);
|
||||
const existingActor = this.breakpointActorMap.getActor(actualLocation);
|
||||
this.breakpointActorMap.deleteActor(originalLocation);
|
||||
if (existingActor) {
|
||||
actor.onDelete();
|
||||
actor = existingActor;
|
||||
} else {
|
||||
actor.originalLocation = actualLocation;
|
||||
this.breakpointActorMap.setActor(actualLocation, actor);
|
||||
}
|
||||
}
|
||||
|
||||
return promise.resolve(actor);
|
||||
} else {
|
||||
return this.sources.getAllGeneratedLocations(originalLocation).then((generatedLocations) => {
|
||||
this._setBreakpointAtAllGeneratedLocations(
|
||||
actor,
|
||||
generatedLocations
|
||||
);
|
||||
|
||||
return actor;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -632,8 +632,8 @@ TabSources.prototype = {
|
||||
originalColumn
|
||||
} = originalLocation;
|
||||
|
||||
let source = originalSourceActor.source ||
|
||||
originalSourceActor.generatedSource;
|
||||
let source = (originalSourceActor.source ||
|
||||
originalSourceActor.generatedSource);
|
||||
|
||||
return this.fetchSourceMap(source).then((map) => {
|
||||
if (map) {
|
||||
|
@ -69,6 +69,7 @@ skip-if = buildapp == 'mulet'
|
||||
[test_inspector-hide.html]
|
||||
[test_inspector-insert.html]
|
||||
[test_inspector-mutations-attr.html]
|
||||
[test_inspector-mutations-events.html]
|
||||
[test_inspector-mutations-childlist.html]
|
||||
[test_inspector-mutations-frameload.html]
|
||||
[test_inspector-mutations-value.html]
|
||||
|
@ -0,0 +1,184 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1157469
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1157469</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
window.onload = function() {
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const {InspectorFront} =
|
||||
devtools.require("devtools/server/actors/inspector");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let inspectee = null;
|
||||
let inspector = null;
|
||||
let walker = null;
|
||||
let eventListener1 = function () {};
|
||||
let eventListener2 = function () {};
|
||||
let eventNode1;
|
||||
let eventNode2;
|
||||
let eventFront1;
|
||||
let eventFront2;
|
||||
|
||||
addAsyncTest(function* setup() {
|
||||
info ("Setting up inspector and walker actors.");
|
||||
let url = document.getElementById("inspectorContent").href;
|
||||
|
||||
yield new Promise(resolve => {
|
||||
attachURL(url, function(err, client, tab, doc) {
|
||||
inspectee = doc;
|
||||
inspector = InspectorFront(client, tab);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
walker = yield inspector.getWalker();
|
||||
ok(walker, "getWalker() should return an actor.");
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
addAsyncTest(function* setupEventTest() {
|
||||
eventNode1 = inspectee.querySelector("#a")
|
||||
eventNode2 = inspectee.querySelector("#b")
|
||||
|
||||
eventFront1 = yield walker.querySelector(walker.rootNode, "#a");
|
||||
eventFront2 = yield walker.querySelector(walker.rootNode, "#b");
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
addAsyncTest(function* testChangeEventListenerOnSingleNode() {
|
||||
checkNodesHaveNoEventListener();
|
||||
|
||||
info("add event listener on a single node");
|
||||
eventNode1.addEventListener("click", eventListener1);
|
||||
|
||||
let mutations = yield waitForMutations();
|
||||
is(mutations.length, 1, "one mutation expected");
|
||||
is(mutations[0].target, eventFront1, "mutation targets eventFront1");
|
||||
is(mutations[0].type, "events", "mutation type is events");
|
||||
is(mutations[0].hasEventListeners, true, "mutation target should have event listeners");
|
||||
is(eventFront1.hasEventListeners, true, "eventFront1 should have event listeners");
|
||||
|
||||
info("remove event listener on a single node");
|
||||
eventNode1.removeEventListener("click", eventListener1);
|
||||
|
||||
mutations = yield waitForMutations();
|
||||
is(mutations.length, 1, "one mutation expected");
|
||||
is(mutations[0].target, eventFront1, "mutation targets eventFront1");
|
||||
is(mutations[0].type, "events", "mutation type is events");
|
||||
is(mutations[0].hasEventListeners, false, "mutation target should have no event listeners");
|
||||
is(eventFront1.hasEventListeners, false, "eventFront1 should have no event listeners");
|
||||
|
||||
info("perform several event listener changes on a single node")
|
||||
eventNode1.addEventListener("click", eventListener1);
|
||||
eventNode1.addEventListener("click", eventListener2);
|
||||
eventNode1.removeEventListener("click", eventListener1);
|
||||
eventNode1.removeEventListener("click", eventListener2);
|
||||
|
||||
mutations = yield waitForMutations();
|
||||
is(mutations.length, 1, "one mutation expected");
|
||||
is(mutations[0].target, eventFront1, "mutation targets eventFront1");
|
||||
is(mutations[0].type, "events", "mutation type is events");
|
||||
is(mutations[0].hasEventListeners, false, "no event listener expected on mutation target");
|
||||
is(eventFront1.hasEventListeners, false, "no event listener expected on node");
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
addAsyncTest(function* testChangeEventsOnSeveralNodes() {
|
||||
checkNodesHaveNoEventListener();
|
||||
|
||||
info("add event listeners on both nodes");
|
||||
eventNode1.addEventListener("click", eventListener1);
|
||||
eventNode2.addEventListener("click", eventListener2);
|
||||
|
||||
let mutations = yield waitForMutations();
|
||||
is(mutations.length, 2, "two mutations expected, one for each modified node");
|
||||
// first mutation
|
||||
is(mutations[0].target, eventFront1, "first mutation targets eventFront1");
|
||||
is(mutations[0].type, "events", "mutation type is events");
|
||||
is(mutations[0].hasEventListeners, true, "mutation target should have event listeners");
|
||||
is(eventFront1.hasEventListeners, true, "eventFront1 should have event listeners");
|
||||
// second mutation
|
||||
is(mutations[1].target, eventFront2, "second mutation targets eventFront2");
|
||||
is(mutations[1].type, "events", "mutation type is events");
|
||||
is(mutations[1].hasEventListeners, true, "mutation target should have event listeners");
|
||||
is(eventFront2.hasEventListeners, true, "eventFront1 should have event listeners");
|
||||
|
||||
info("remove event listeners on both nodes");
|
||||
eventNode1.removeEventListener("click", eventListener1);
|
||||
eventNode2.removeEventListener("click", eventListener2);
|
||||
|
||||
mutations = yield waitForMutations();
|
||||
is(mutations.length, 2, "one mutation registered for event listener change");
|
||||
// first mutation
|
||||
is(mutations[0].target, eventFront1, "first mutation targets eventFront1");
|
||||
is(mutations[0].type, "events", "mutation type is events");
|
||||
is(mutations[0].hasEventListeners, false, "mutation target should have no event listeners");
|
||||
is(eventFront1.hasEventListeners, false, "eventFront2 should have no event listeners");
|
||||
// second mutation
|
||||
is(mutations[1].target, eventFront2, "second mutation targets eventFront2");
|
||||
is(mutations[1].type, "events", "mutation type is events");
|
||||
is(mutations[1].hasEventListeners, false, "mutation target should have no event listeners");
|
||||
is(eventFront2.hasEventListeners, false, "eventFront2 should have no event listeners");
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
addAsyncTest(function* testRemoveMissingEvent() {
|
||||
checkNodesHaveNoEventListener();
|
||||
|
||||
info("try to remove an event listener not previously added");
|
||||
eventNode1.removeEventListener("click", eventListener1);
|
||||
|
||||
info("set any attribute on the node to trigger a mutation")
|
||||
eventNode1.setAttribute("data-attr", "somevalue");
|
||||
|
||||
let mutations = yield waitForMutations();
|
||||
is(mutations.length, 1, "expect only one mutation");
|
||||
isnot(mutations.type, "events", "mutation type should not be events");
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
function checkNodesHaveNoEventListener() {
|
||||
is(eventFront1.hasEventListeners, false, "eventFront1 hasEventListeners should be false");
|
||||
is(eventFront2.hasEventListeners, false, "eventFront2 hasEventListeners should be false");
|
||||
};
|
||||
|
||||
function waitForMutations() {
|
||||
return new Promise(resolve => {
|
||||
walker.once("mutations", mutations => {
|
||||
resolve(mutations);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1157469">Mozilla Bug 1157469</a>
|
||||
<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -65,9 +65,11 @@ function test_simple_breakpoint()
|
||||
});
|
||||
});
|
||||
|
||||
Components.utils.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"var b = 2;\n", // line0 + 3
|
||||
gDebuggee);
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"var b = 2;\n", // line0 + 3
|
||||
gDebuggee
|
||||
);
|
||||
}
|
||||
|
@ -57,8 +57,11 @@ function test_breakpoint_running()
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" +
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"var b = 2;\n"); // line0 + 3
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" +
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"var b = 2;\n", // line0 + 3
|
||||
gDebuggee
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check that setting a breakpoint in a line without code will skip forward.
|
||||
* Check that setting a breakpoint on a line without code will skip
|
||||
* forward when we know the script isn't GCed (the debugger is connected,
|
||||
* so it's kept alive).
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
@ -65,14 +67,18 @@ function test_skip_breakpoint()
|
||||
});
|
||||
});
|
||||
|
||||
// Continue until the breakpoint is hit.
|
||||
gThreadClient.resume();
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"// A comment.\n" + // line0 + 3
|
||||
"var b = 2;"); // line0 + 4
|
||||
// Use `evalInSandbox` to make the debugger treat it as normal
|
||||
// globally-scoped code, where breakpoint sliding rules apply.
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"// A comment.\n" + // line0 + 3
|
||||
"var b = 2;", // line0 + 4
|
||||
gDebuggee
|
||||
);
|
||||
}
|
||||
|
@ -67,11 +67,14 @@ function test_child_breakpoint()
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" this.b = 2;\n" + // line0 + 3
|
||||
"}\n" + // line0 + 4
|
||||
"debugger;\n" + // line0 + 5
|
||||
"foo();\n"); // line0 + 6
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" this.b = 2;\n" + // line0 + 3
|
||||
"}\n" + // line0 + 4
|
||||
"debugger;\n" + // line0 + 5
|
||||
"foo();\n", // line0 + 6
|
||||
gDebuggee
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check that setting a breakpoint in a line without code in a child scrip
|
||||
* Check that setting a breakpoint in a line without code in a child script
|
||||
* will skip forward.
|
||||
*/
|
||||
|
||||
@ -68,12 +68,15 @@ function test_child_skip_breakpoint()
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" // A comment.\n" + // line0 + 3
|
||||
" this.b = 2;\n" + // line0 + 4
|
||||
"}\n" + // line0 + 5
|
||||
"debugger;\n" + // line0 + 6
|
||||
"foo();\n"); // line0 + 7
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" // A comment.\n" + // line0 + 3
|
||||
" this.b = 2;\n" + // line0 + 4
|
||||
"}\n" + // line0 + 5
|
||||
"debugger;\n" + // line0 + 6
|
||||
"foo();\n", // line0 + 7
|
||||
gDebuggee
|
||||
);
|
||||
}
|
||||
|
@ -69,18 +69,21 @@ function test_nested_breakpoint()
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" function bar() {\n" + // line0 + 2
|
||||
" function baz() {\n" + // line0 + 3
|
||||
" this.a = 1;\n" + // line0 + 4
|
||||
" // A comment.\n" + // line0 + 5
|
||||
" this.b = 2;\n" + // line0 + 6
|
||||
" }\n" + // line0 + 7
|
||||
" baz();\n" + // line0 + 8
|
||||
" }\n" + // line0 + 9
|
||||
" bar();\n" + // line0 + 10
|
||||
"}\n" + // line0 + 11
|
||||
"debugger;\n" + // line0 + 12
|
||||
"foo();\n"); // line0 + 13
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" function bar() {\n" + // line0 + 2
|
||||
" function baz() {\n" + // line0 + 3
|
||||
" this.a = 1;\n" + // line0 + 4
|
||||
" // A comment.\n" + // line0 + 5
|
||||
" this.b = 2;\n" + // line0 + 6
|
||||
" }\n" + // line0 + 7
|
||||
" baz();\n" + // line0 + 8
|
||||
" }\n" + // line0 + 9
|
||||
" bar();\n" + // line0 + 10
|
||||
"}\n" + // line0 + 11
|
||||
"debugger;\n" + // line0 + 12
|
||||
"foo();\n", // line0 + 13
|
||||
gDebuggee
|
||||
)
|
||||
}
|
||||
|
@ -68,15 +68,18 @@ function test_second_child_skip_breakpoint()
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" bar();\n" + // line0 + 2
|
||||
"}\n" + // line0 + 3
|
||||
"function bar() {\n" + // line0 + 4
|
||||
" this.a = 1;\n" + // line0 + 5
|
||||
" // A comment.\n" + // line0 + 6
|
||||
" this.b = 2;\n" + // line0 + 7
|
||||
"}\n" + // line0 + 8
|
||||
"debugger;\n" + // line0 + 9
|
||||
"foo();\n"); // line0 + 10
|
||||
Cu.evalInSandbox(
|
||||
"var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" bar();\n" + // line0 + 2
|
||||
"}\n" + // line0 + 3
|
||||
"function bar() {\n" + // line0 + 4
|
||||
" this.a = 1;\n" + // line0 + 5
|
||||
" // A comment.\n" + // line0 + 6
|
||||
" this.b = 2;\n" + // line0 + 7
|
||||
"}\n" + // line0 + 8
|
||||
"debugger;\n" + // line0 + 9
|
||||
"foo();\n", // line0 + 10
|
||||
gDebuggee
|
||||
)
|
||||
}
|
||||
|
@ -48,8 +48,7 @@ function test_child_skip_breakpoint()
|
||||
let location = { line: gDebuggee.line0 + 3 };
|
||||
|
||||
source.setBreakpoint(location, function (aResponse, bpClient) {
|
||||
// Check that the breakpoint has properly skipped forward one
|
||||
// line.
|
||||
// Check that the breakpoint has properly skipped forward one line.
|
||||
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
|
||||
do_check_eq(aResponse.actualLocation.line, location.line + 1);
|
||||
|
||||
@ -78,13 +77,20 @@ function test_child_skip_breakpoint()
|
||||
}
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" // A comment.\n" + // line0 + 3
|
||||
" this.b = 2;\n" + // line0 + 3
|
||||
"}\n"); // line0 + 4
|
||||
gDebuggee.eval("var line1 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line1 + 1
|
||||
"foo();\n"); // line1 + 2
|
||||
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" // A comment.\n" + // line0 + 3
|
||||
" this.b = 2;\n" + // line0 + 4
|
||||
"}\n", // line0 + 5
|
||||
gDebuggee,
|
||||
"1.7",
|
||||
"script1.js");
|
||||
|
||||
Cu.evalInSandbox("var line1 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line1 + 1
|
||||
"foo();\n", // line1 + 2
|
||||
gDebuggee,
|
||||
"1.7",
|
||||
"script2.js");
|
||||
}
|
||||
|
@ -71,15 +71,16 @@ function test_remove_breakpoint()
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo(stop) {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" if (stop) return;\n" + // line0 + 3
|
||||
" delete this.a;\n" + // line0 + 4
|
||||
" foo(true);\n" + // line0 + 5
|
||||
"}\n" + // line0 + 6
|
||||
"debugger;\n" + // line1 + 7
|
||||
"foo();\n"); // line1 + 8
|
||||
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"function foo(stop) {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" if (stop) return;\n" + // line0 + 3
|
||||
" delete this.a;\n" + // line0 + 4
|
||||
" foo(true);\n" + // line0 + 5
|
||||
"}\n" + // line0 + 6
|
||||
"debugger;\n" + // line1 + 7
|
||||
"foo();\n", // line1 + 8
|
||||
gDebuggee);
|
||||
if (!done) {
|
||||
do_check_true(false);
|
||||
}
|
||||
|
@ -79,10 +79,11 @@ function test_child_breakpoint()
|
||||
});
|
||||
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a, i = 0;\n" + // line0 + 2
|
||||
"for (i = 1; i <= 2; i++) {\n" + // line0 + 3
|
||||
" a = i;\n" + // line0 + 4
|
||||
"}\n"); // line0 + 5
|
||||
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a, i = 0;\n" + // line0 + 2
|
||||
"for (i = 1; i <= 2; i++) {\n" + // line0 + 3
|
||||
" a = i;\n" + // line0 + 4
|
||||
"}\n", // line0 + 5
|
||||
gDebuggee);
|
||||
}
|
||||
|
@ -80,8 +80,9 @@ function test_child_breakpoint()
|
||||
});
|
||||
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
|
||||
"var res = a.f();\n"); // line0 + 3
|
||||
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
|
||||
"var res = a.f();\n", // line0 + 3
|
||||
gDebuggee);
|
||||
}
|
||||
|
@ -55,14 +55,15 @@ function test_child_skip_breakpoint()
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" // A comment.\n" + // line0 + 3
|
||||
" this.b = 2;\n" + // line0 + 4
|
||||
"}\n" + // line0 + 5
|
||||
"debugger;\n" + // line0 + 6
|
||||
"foo();\n"); // line0 + 7
|
||||
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" // A comment.\n" + // line0 + 3
|
||||
" this.b = 2;\n" + // line0 + 4
|
||||
"}\n" + // line0 + 5
|
||||
"debugger;\n" + // line0 + 6
|
||||
"foo();\n", // line0 + 7
|
||||
gDebuggee);
|
||||
}
|
||||
|
||||
// Set many breakpoints at the same location.
|
||||
|