Update On Wed Jul 17 20:48:28 CEST 2024
This commit is contained in:
parent
776d6ead9e
commit
1239d9ad40
1160 changed files with 48589 additions and 115871 deletions
90
Cargo.lock
generated
90
Cargo.lock
generated
|
@ -44,7 +44,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ce34de545ad29bcc00cb1b87a94c132256dcf83aa7eeb9674482568405a6ff0a"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"libc",
|
||||
"nix 0.26.99",
|
||||
]
|
||||
|
@ -444,7 +444,7 @@ dependencies = [
|
|||
name = "bindgen"
|
||||
version = "0.69.4"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
|
@ -460,31 +460,31 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||
checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.999.999"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
@ -1028,6 +1028,7 @@ dependencies = [
|
|||
"env_logger",
|
||||
"flate2",
|
||||
"fluent",
|
||||
"glean",
|
||||
"gtkbind",
|
||||
"intl-memoizer",
|
||||
"libloading",
|
||||
|
@ -1203,7 +1204,7 @@ source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=8bce3b333a920999
|
|||
dependencies = [
|
||||
"atomic",
|
||||
"audio-mixer",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"coreaudio-sys-utils",
|
||||
"cubeb-backend",
|
||||
"float-cmp",
|
||||
|
@ -1239,9 +1240,9 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a#82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=a0c185a28c232ee2ab63f72d6fd3a63a3f787309#a0c185a28c232ee2ab63f72d6fd3a63a3f787309"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"libloading",
|
||||
"winapi",
|
||||
]
|
||||
|
@ -1545,7 +1546,7 @@ dependencies = [
|
|||
name = "dom"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2535,7 +2536,7 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"gpu-alloc-types",
|
||||
]
|
||||
|
||||
|
@ -2545,7 +2546,7 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2566,7 +2567,7 @@ name = "gpu-descriptor"
|
|||
version = "0.3.0"
|
||||
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=7b71a4e47c81903ad75e2c53deb5ab1310f6ff4d#7b71a4e47c81903ad75e2c53deb5ab1310f6ff4d"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"gpu-descriptor-types",
|
||||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
@ -2576,7 +2577,7 @@ name = "gpu-descriptor-types"
|
|||
version = "0.2.0"
|
||||
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=7b71a4e47c81903ad75e2c53deb5ab1310f6ff4d#7b71a4e47c81903ad75e2c53deb5ab1310f6ff4d"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3663,7 +3664,7 @@ version = "0.28.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
|
@ -3728,7 +3729,7 @@ version = "0.21.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bb6eaf88cc770fa58e6ae721cf2e40c2ca6a4c942ae8c7aa324d680bd3c6717"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"debugid",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
@ -3743,7 +3744,7 @@ version = "0.8.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abcd9c8a1e6e1e9d56ce3627851f39a17ea83e17c96bc510f29d7e43d78a7d"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"crash-context",
|
||||
|
@ -3872,7 +3873,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"arrayvec",
|
||||
"bindgen 0.69.4",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"bytes",
|
||||
"cc",
|
||||
"chrono",
|
||||
|
@ -4031,11 +4032,12 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
|||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a#82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=a0c185a28c232ee2ab63f72d6fd3a63a3f787309#a0c185a28c232ee2ab63f72d6fd3a63a3f787309"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"cfg_aliases",
|
||||
"codespan-reporting",
|
||||
"hexf-parse",
|
||||
"indexmap 2.2.6",
|
||||
|
@ -4191,7 +4193,7 @@ version = "0.28.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
|
@ -4252,7 +4254,7 @@ source = "git+https://github.com/mozilla/application-services?rev=8fd08c6f2f8acd
|
|||
name = "nsstring"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"encoding_rs",
|
||||
]
|
||||
|
||||
|
@ -4702,7 +4704,7 @@ version = "0.16.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"hex",
|
||||
]
|
||||
|
||||
|
@ -4759,7 +4761,7 @@ name = "pulse"
|
|||
version = "0.3.0"
|
||||
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2#8678dcab1c287de79c4c184ccc2e065bc62b70e2"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"pulse-ffi",
|
||||
]
|
||||
|
||||
|
@ -4997,7 +4999,7 @@ checksum = "2c6d906922d99c677624d2042a93f89b2b7df0f6411032237d5d99a602c2487c"
|
|||
dependencies = [
|
||||
"arrayref",
|
||||
"bincode",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"id-arena",
|
||||
"lazy_static",
|
||||
|
@ -5019,7 +5021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -5062,7 +5064,7 @@ version = "0.31.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
|
@ -5136,7 +5138,7 @@ version = "0.38.28"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
@ -5200,7 +5202,7 @@ dependencies = [
|
|||
name = "selectors"
|
||||
version = "0.22.0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"cssparser",
|
||||
"derive_more 0.99.999",
|
||||
"fxhash",
|
||||
|
@ -5483,7 +5485,7 @@ version = "0.3.0+sdk-1.3.268.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5573,7 +5575,7 @@ dependencies = [
|
|||
"arrayvec",
|
||||
"atomic_refcell",
|
||||
"bindgen 0.69.4",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"cssparser",
|
||||
"derive_more 0.99.999",
|
||||
|
@ -5639,7 +5641,7 @@ name = "style_traits"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"cssparser",
|
||||
"euclid",
|
||||
"lazy_static",
|
||||
|
@ -6657,7 +6659,7 @@ name = "webrender"
|
|||
version = "0.62.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"build-parallel",
|
||||
"byteorder",
|
||||
"derive_more 0.99.999",
|
||||
|
@ -6694,7 +6696,7 @@ name = "webrender_api"
|
|||
version = "0.62.0"
|
||||
dependencies = [
|
||||
"app_units",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"crossbeam-channel",
|
||||
"euclid",
|
||||
|
@ -6741,7 +6743,7 @@ dependencies = [
|
|||
name = "webrender_build"
|
||||
version = "0.0.2"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
]
|
||||
|
@ -6768,11 +6770,11 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a#82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=a0c185a28c232ee2ab63f72d6fd3a63a3f787309#a0c185a28c232ee2ab63f72d6fd3a63a3f787309"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-vec",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"cfg_aliases",
|
||||
"document-features",
|
||||
"indexmap 2.2.6",
|
||||
|
@ -6793,13 +6795,13 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wgpu-hal"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a#82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=a0c185a28c232ee2ab63f72d6fd3a63a3f787309#a0c185a28c232ee2ab63f72d6fd3a63a3f787309"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"arrayvec",
|
||||
"ash",
|
||||
"bit-set",
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"cfg_aliases",
|
||||
"core-graphics-types",
|
||||
|
@ -6832,9 +6834,9 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a#82210e1cdc63cbd5e53f43788f9956bb0d4a2c6a"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=a0c185a28c232ee2ab63f72d6fd3a63a3f787309#a0c185a28c232ee2ab63f72d6fd3a63a3f787309"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"bitflags 2.6.0",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"web-sys",
|
||||
|
|
|
@ -36,6 +36,11 @@ source-repo.h: $(MDDEPDIR)/source-repo.h.stub
|
|||
buildid.h: $(MDDEPDIR)/buildid.h.stub
|
||||
# Add explicit dependencies that moz.build can't declare yet.
|
||||
build/$(MDDEPDIR)/application.ini.stub: source-repo.h buildid.h
|
||||
# The mozbuild crate includes the buildid (via `variables.py:get_buildid()`),
|
||||
# so it can only be generated after the buildid file is generated.
|
||||
ifeq ($(and $(JS_STANDALONE),$(MOZ_BUILD_APP)),)
|
||||
build/rust/mozbuild/$(MDDEPDIR)/buildconfig.rs.stub: buildid.h
|
||||
endif
|
||||
|
||||
BUILD_BACKEND_FILES := $(addprefix backend.,$(addsuffix Backend,$(BUILD_BACKENDS)))
|
||||
|
||||
|
|
|
@ -53,10 +53,11 @@ struct AtkStateMap {
|
|||
};
|
||||
|
||||
// Map array from cross platform states to ATK states
|
||||
static const AtkStateMap gAtkStateMap[] =
|
||||
{
|
||||
// Cross Platform States
|
||||
// clang-format off
|
||||
static const AtkStateMap
|
||||
gAtkStateMap[] =
|
||||
{
|
||||
// Cross Platform States
|
||||
// clang-format off
|
||||
{ kNone, kMapOpposite }, // states::UNAVAILABLE = 1 << 0
|
||||
{ ATK_STATE_SELECTED, kMapDirectly }, // states::SELECTED = 1 << 1
|
||||
{ ATK_STATE_FOCUSED, kMapDirectly }, // states::FOCUSED = 1 << 2
|
||||
|
@ -106,7 +107,7 @@ static const AtkStateMap gAtkStateMap[] =
|
|||
{ ATK_STATE_EXPANDABLE, kMapDirectly }, // states::EXPANDABLE = 1 << 46
|
||||
{ kNone, kMapDirectly }, // states::PINNED = 1 << 47
|
||||
{ ATK_STATE_ACTIVE, kMapDirectly } // states::CURRENT = 1 << 48
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static const auto gAtkStateMapLen = std::extent<decltype(gAtkStateMap)>::value;
|
||||
|
|
|
@ -231,7 +231,7 @@ void EventQueue::CoalesceEvents() {
|
|||
|
||||
default:
|
||||
break; // case eAllowDupes, eDoNotEmit
|
||||
} // switch
|
||||
} // switch
|
||||
}
|
||||
|
||||
void EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
|
||||
|
|
|
@ -211,7 +211,7 @@ class TextAttrsMgr {
|
|||
class InvalidTextAttr : public TTextAttr<uint32_t> {
|
||||
public:
|
||||
InvalidTextAttr(nsIContent* aRootElm, nsIContent* aElm);
|
||||
virtual ~InvalidTextAttr(){};
|
||||
virtual ~InvalidTextAttr() {};
|
||||
|
||||
protected:
|
||||
enum { eFalse, eGrammar, eSpelling, eTrue };
|
||||
|
|
|
@ -372,14 +372,13 @@ static int32_t sPlatformDisabledState = 0;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Markup maps array.
|
||||
|
||||
#define Attr(name, value) \
|
||||
{ nsGkAtoms::name, nsGkAtoms::value }
|
||||
#define Attr(name, value) {nsGkAtoms::name, nsGkAtoms::value}
|
||||
|
||||
#define AttrFromDOM(name, DOMAttrName) \
|
||||
{ nsGkAtoms::name, nullptr, nsGkAtoms::DOMAttrName }
|
||||
{nsGkAtoms::name, nullptr, nsGkAtoms::DOMAttrName}
|
||||
|
||||
#define AttrFromDOMIf(name, DOMAttrName, DOMAttrValue) \
|
||||
{ nsGkAtoms::name, nullptr, nsGkAtoms::DOMAttrName, nsGkAtoms::DOMAttrValue }
|
||||
{nsGkAtoms::name, nullptr, nsGkAtoms::DOMAttrName, nsGkAtoms::DOMAttrValue}
|
||||
|
||||
#define MARKUPMAP(atom, new_func, r, ...) \
|
||||
{nsGkAtoms::atom, new_func, static_cast<a11y::role>(r), {__VA_ARGS__}},
|
||||
|
|
|
@ -77,10 +77,10 @@ uint16_t RotorRule::Match(Accessible* aAcc) {
|
|||
|
||||
RotorRoleRule::RotorRoleRule(role aRole, Accessible* aDirectDescendantsFrom,
|
||||
const nsString& aSearchText)
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText), mRole(aRole){};
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText), mRole(aRole) {};
|
||||
|
||||
RotorRoleRule::RotorRoleRule(role aRole, const nsString& aSearchText)
|
||||
: RotorRule(aSearchText), mRole(aRole){};
|
||||
: RotorRule(aSearchText), mRole(aRole) {};
|
||||
|
||||
uint16_t RotorRoleRule::Match(Accessible* aAcc) {
|
||||
uint16_t result = RotorRule::Match(aAcc);
|
||||
|
@ -135,10 +135,10 @@ uint16_t RotorMacRoleRule::Match(Accessible* aAcc) {
|
|||
|
||||
RotorControlRule::RotorControlRule(Accessible* aDirectDescendantsFrom,
|
||||
const nsString& aSearchText)
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText){};
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText) {};
|
||||
|
||||
RotorControlRule::RotorControlRule(const nsString& aSearchText)
|
||||
: RotorRule(aSearchText){};
|
||||
: RotorRule(aSearchText) {};
|
||||
|
||||
uint16_t RotorControlRule::Match(Accessible* aAcc) {
|
||||
uint16_t result = RotorRule::Match(aAcc);
|
||||
|
@ -207,10 +207,10 @@ uint16_t RotorControlRule::Match(Accessible* aAcc) {
|
|||
|
||||
RotorTextEntryRule::RotorTextEntryRule(Accessible* aDirectDescendantsFrom,
|
||||
const nsString& aSearchText)
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText){};
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText) {};
|
||||
|
||||
RotorTextEntryRule::RotorTextEntryRule(const nsString& aSearchText)
|
||||
: RotorRule(aSearchText){};
|
||||
: RotorRule(aSearchText) {};
|
||||
|
||||
uint16_t RotorTextEntryRule::Match(Accessible* aAcc) {
|
||||
uint16_t result = RotorRule::Match(aAcc);
|
||||
|
@ -232,10 +232,10 @@ uint16_t RotorTextEntryRule::Match(Accessible* aAcc) {
|
|||
|
||||
RotorLinkRule::RotorLinkRule(Accessible* aDirectDescendantsFrom,
|
||||
const nsString& aSearchText)
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText){};
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText) {};
|
||||
|
||||
RotorLinkRule::RotorLinkRule(const nsString& aSearchText)
|
||||
: RotorRule(aSearchText){};
|
||||
: RotorRule(aSearchText) {};
|
||||
|
||||
uint16_t RotorLinkRule::Match(Accessible* aAcc) {
|
||||
uint16_t result = RotorRule::Match(aAcc);
|
||||
|
@ -325,10 +325,10 @@ uint16_t RotorNotMacRoleRule::Match(Accessible* aAcc) {
|
|||
|
||||
RotorStaticTextRule::RotorStaticTextRule(Accessible* aDirectDescendantsFrom,
|
||||
const nsString& aSearchText)
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText){};
|
||||
: RotorRule(aDirectDescendantsFrom, aSearchText) {};
|
||||
|
||||
RotorStaticTextRule::RotorStaticTextRule(const nsString& aSearchText)
|
||||
: RotorRule(aSearchText){};
|
||||
: RotorRule(aSearchText) {};
|
||||
|
||||
uint16_t RotorStaticTextRule::Match(Accessible* aAcc) {
|
||||
uint16_t result = RotorRule::Match(aAcc);
|
||||
|
@ -353,11 +353,11 @@ RotorHeadingLevelRule::RotorHeadingLevelRule(int32_t aLevel,
|
|||
Accessible* aDirectDescendantsFrom,
|
||||
const nsString& aSearchText)
|
||||
: RotorRoleRule(roles::HEADING, aDirectDescendantsFrom, aSearchText),
|
||||
mLevel(aLevel){};
|
||||
mLevel(aLevel) {};
|
||||
|
||||
RotorHeadingLevelRule::RotorHeadingLevelRule(int32_t aLevel,
|
||||
const nsString& aSearchText)
|
||||
: RotorRoleRule(roles::HEADING, aSearchText), mLevel(aLevel){};
|
||||
: RotorRoleRule(roles::HEADING, aSearchText), mLevel(aLevel) {};
|
||||
|
||||
uint16_t RotorHeadingLevelRule::Match(Accessible* aAcc) {
|
||||
uint16_t result = RotorRoleRule::Match(aAcc);
|
||||
|
|
|
@ -17,8 +17,8 @@ namespace a11y {
|
|||
|
||||
class sdnDocAccessible final : public ISimpleDOMDocument {
|
||||
public:
|
||||
explicit sdnDocAccessible(MsaaDocAccessible* aMsaa) : mMsaa(aMsaa){};
|
||||
~sdnDocAccessible(){};
|
||||
explicit sdnDocAccessible(MsaaDocAccessible* aMsaa) : mMsaa(aMsaa) {};
|
||||
~sdnDocAccessible() {};
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace a11y {
|
|||
|
||||
class sdnTextAccessible final : public ISimpleDOMText {
|
||||
public:
|
||||
explicit sdnTextAccessible(MsaaAccessible* aMsaa) : mMsaa(aMsaa){};
|
||||
explicit sdnTextAccessible(MsaaAccessible* aMsaa) : mMsaa(aMsaa) {};
|
||||
~sdnTextAccessible() {}
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
|
|
@ -103,8 +103,8 @@ uint64_t XULMenuitemAccessible::NativeState() const {
|
|||
(grandParentState & states::INVISIBLE) |
|
||||
(grandParentState & states::OPAQUE1);
|
||||
} // isCollapsed
|
||||
} // isSelected
|
||||
} // ROLE_COMBOBOX_OPTION
|
||||
} // isSelected
|
||||
} // ROLE_COMBOBOX_OPTION
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -889,6 +889,7 @@ class SearchAdImpression {
|
|||
opacityProperty: true,
|
||||
})
|
||||
) {
|
||||
Glean.serp.adsBlockedCount.hidden_parent.add();
|
||||
return {
|
||||
adsVisible: 0,
|
||||
adsHidden: adsLoaded,
|
||||
|
@ -901,6 +902,7 @@ class SearchAdImpression {
|
|||
elementRect.bottom < 0 &&
|
||||
innerWindowHeight + scrollY + elementRect.bottom < 0
|
||||
) {
|
||||
Glean.serp.adsBlockedCount.beyond_viewport.add();
|
||||
return {
|
||||
adsVisible: 0,
|
||||
adsHidden: adsLoaded,
|
||||
|
@ -933,6 +935,7 @@ class SearchAdImpression {
|
|||
})
|
||||
) {
|
||||
adsHidden += 1;
|
||||
Glean.serp.adsBlockedCount.hidden_child.add();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -668,10 +668,6 @@ pref("browser.urlbar.addons.minKeywordLength", 0);
|
|||
// Feature gate pref for Pocket suggestions in the urlbar.
|
||||
pref("browser.urlbar.pocket.featureGate", false);
|
||||
|
||||
// The group-relative suggestedIndex of Pocket suggestions within the Firefox
|
||||
// Suggest section.
|
||||
pref("browser.urlbar.pocket.suggestedIndex", 0);
|
||||
|
||||
// If `browser.urlbar.pocket.featureGate` is true, this controls whether Pocket
|
||||
// suggestions are turned on.
|
||||
pref("browser.urlbar.suggest.pocket", true);
|
||||
|
@ -1870,8 +1866,10 @@ pref("browser.newtabpage.activity-stream.discoverystream.recs.personalized", fal
|
|||
// System pref to allow Pocket sponsored content personalization to be turned on/off.
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.spocs.personalized", true);
|
||||
|
||||
// System pref to enable topic selection for pocket feed
|
||||
// System pref to enable topic selection for Pocket feed
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.topicSelection.enabled", false);
|
||||
// System pref to enable topic labels on Pocket cards
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.topicLabels.enabled", false);
|
||||
|
||||
// Flip this once the user has dismissed the Pocket onboarding experience,
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.onboardingExperience.dismissed", false);
|
||||
|
|
|
@ -17,8 +17,9 @@ using GlobalInitializerFn = void(__cdecl*)(void);
|
|||
|
||||
// Allocation of static initialization section for the freestanding library
|
||||
#pragma section(".freestd$a", read)
|
||||
__declspec(allocate(".freestd$a")) static const GlobalInitializerFn
|
||||
FreeStdStart = reinterpret_cast<GlobalInitializerFn>(0);
|
||||
__declspec(allocate(
|
||||
".freestd$a")) static const GlobalInitializerFn FreeStdStart =
|
||||
reinterpret_cast<GlobalInitializerFn>(0);
|
||||
|
||||
#pragma section(".freestd$z", read)
|
||||
__declspec(allocate(".freestd$z")) static const GlobalInitializerFn FreeStdEnd =
|
||||
|
|
|
@ -854,7 +854,10 @@ var gIdentityHandler = {
|
|||
|
||||
if (this._isMixedActiveContentLoaded) {
|
||||
this._identityBox.classList.add("mixedActiveContent");
|
||||
if (UrlbarPrefs.get("trimHttps") && warnTextOnInsecure) {
|
||||
if (
|
||||
UrlbarPrefs.getScotchBonnetPref("trimHttps") &&
|
||||
warnTextOnInsecure
|
||||
) {
|
||||
icon_label = gNavigatorBundle.getString("identity.notSecure.label");
|
||||
this._identityBox.classList.add("notSecureText");
|
||||
}
|
||||
|
|
|
@ -2634,24 +2634,6 @@ export class nsContextMenu {
|
|||
this.window.openTrustedLinkIn(drmInfoURL, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if Full Page Translations is currently active on this page.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
#isFullPageTranslationsActive() {
|
||||
try {
|
||||
const { requestedTranslationPair } =
|
||||
lazy.TranslationsParent.getTranslationsActor(
|
||||
this.browser
|
||||
).languageState;
|
||||
return requestedTranslationPair !== null;
|
||||
} catch {
|
||||
// Failed to retrieve the Full Page Translations actor, do nothing.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the SelectTranslationsPanel singleton instance.
|
||||
*
|
||||
|
@ -2697,6 +2679,7 @@ export class nsContextMenu {
|
|||
}
|
||||
|
||||
if (displayName) {
|
||||
translateSelectionItem.setAttribute("target-language", toLanguage);
|
||||
this.document.l10n.setAttributes(
|
||||
translateSelectionItem,
|
||||
this.isTextSelected
|
||||
|
@ -2710,6 +2693,7 @@ export class nsContextMenu {
|
|||
|
||||
// Either no to-language exists, or an error occurred,
|
||||
// so localize the menuitem without a target language.
|
||||
translateSelectionItem.removeAttribute("target-language");
|
||||
this.document.l10n.setAttributes(
|
||||
translateSelectionItem,
|
||||
this.isTextSelected
|
||||
|
@ -2769,11 +2753,10 @@ export class nsContextMenu {
|
|||
// Only show the item if Translations is supported on this hardware.
|
||||
!lazy.TranslationsParent.getIsTranslationsEngineSupported() ||
|
||||
// If there is no text to translate, we have nothing to do.
|
||||
textToTranslate.length === 0 ||
|
||||
// We do not allow translating selections on top of Full Page Translations.
|
||||
this.#isFullPageTranslationsActive();
|
||||
textToTranslate.length === 0;
|
||||
|
||||
if (translateSelectionItem.hidden) {
|
||||
translateSelectionItem.removeAttribute("target-language");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -258,14 +258,7 @@ div#feature-callout.hidden {
|
|||
#feature-callout .onboardingContainer .outer-wrapper {
|
||||
--transition: none;
|
||||
height: auto;
|
||||
}
|
||||
#feature-callout:dir(rtl) {
|
||||
transform: none;
|
||||
direction: ltr;
|
||||
}
|
||||
#feature-callout .outer-wrapper:dir(rtl) {
|
||||
transform: none;
|
||||
direction: rtl;
|
||||
}
|
||||
#feature-callout .screen:dir(rtl) {
|
||||
transform: none;
|
||||
|
@ -309,7 +302,7 @@ div#feature-callout.hidden {
|
|||
transform: rotateY(180deg);
|
||||
}
|
||||
#feature-callout .screen[pos=callout] .welcome-text {
|
||||
align-items: baseline;
|
||||
align-items: start;
|
||||
text-align: start;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -127,22 +127,14 @@
|
|||
|
||||
// auto height to allow for arrow positioning based on height
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// use a different approach to flipping to avoid the fuzzy aliasing that
|
||||
// transform causes.
|
||||
&:dir(rtl) {
|
||||
// use a different approach to flipping to avoid the fuzzy aliasing that
|
||||
// transform causes.
|
||||
transform: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
& .outer-wrapper:dir(rtl) {
|
||||
transform: none;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.screen {
|
||||
// override transform in about:welcome
|
||||
// override the RTL transform in about:welcome
|
||||
&:dir(rtl) {
|
||||
transform: none;
|
||||
}
|
||||
|
@ -198,7 +190,7 @@
|
|||
}
|
||||
|
||||
.welcome-text {
|
||||
align-items: baseline;
|
||||
align-items: start;
|
||||
text-align: start;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -14,10 +14,10 @@ class nsKeychainMigrationUtils : public nsIKeychainMigrationUtils {
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIKEYCHAINMIGRATIONUTILS
|
||||
|
||||
nsKeychainMigrationUtils(){};
|
||||
nsKeychainMigrationUtils() {};
|
||||
|
||||
protected:
|
||||
virtual ~nsKeychainMigrationUtils(){};
|
||||
virtual ~nsKeychainMigrationUtils() {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,7 @@ import { connect, useSelector } from "react-redux";
|
|||
const PREF_ONBOARDING_EXPERIENCE_DISMISSED =
|
||||
"discoverystream.onboardingExperience.dismissed";
|
||||
const PREF_THUMBS_UP_DOWN_ENABLED = "discoverystream.thumbsUpDown.enabled";
|
||||
const PREF_TOPICS_ENABLED = "discoverystream.topicLabels.enabled";
|
||||
const INTERSECTION_RATIO = 0.5;
|
||||
const VISIBLE = "visible";
|
||||
const VISIBILITY_CHANGE_EVENT = "visibilitychange";
|
||||
|
@ -335,6 +336,7 @@ export class _CardGrid extends React.PureComponent {
|
|||
const isOnboardingExperienceDismissed =
|
||||
prefs[PREF_ONBOARDING_EXPERIENCE_DISMISSED];
|
||||
const mayHaveThumbsUpDown = prefs[PREF_THUMBS_UP_DOWN_ENABLED];
|
||||
const showTopics = prefs[PREF_TOPICS_ENABLED];
|
||||
|
||||
const recs = this.props.data.recommendations.slice(0, items);
|
||||
const cards = [];
|
||||
|
@ -356,6 +358,8 @@ export class _CardGrid extends React.PureComponent {
|
|||
word_count={rec.word_count}
|
||||
time_to_read={rec.time_to_read}
|
||||
title={rec.title}
|
||||
topic={rec.topic}
|
||||
showTopics={showTopics}
|
||||
excerpt={rec.excerpt}
|
||||
url={rec.url}
|
||||
id={rec.id}
|
||||
|
|
|
@ -559,6 +559,9 @@ export class _DSCard extends React.PureComponent {
|
|||
className={`ds-card ${compactImagesClassName} ${imageGradientClassName} ${titleLinesName} ${descLinesClassName} ${ctaButtonClassName} ${ctaButtonVariantClassName}`}
|
||||
ref={this.setContextMenuButtonHostRef}
|
||||
>
|
||||
{this.props.showTopics && this.props.topic && (
|
||||
<span className="ds-card-topic">{this.props.topic}</span>
|
||||
)}
|
||||
<div className="img-wrapper">
|
||||
<DSImage
|
||||
extraClassNames="img"
|
||||
|
|
|
@ -174,6 +174,16 @@ $ds-card-image-gradient-solid: rgba(0, 0, 0, 100%);
|
|||
}
|
||||
}
|
||||
|
||||
.ds-card-topic {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background: light-dark(#F0F0F4, var(--newtab-background-color-secondary));
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--space-small);
|
||||
margin: var(--space-small);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
@ -4501,6 +4501,15 @@ main section {
|
|||
box-shadow: 0 0 0 3px var(--newtab-primary-action-background-dimmed), 0 0 0 1px var(--newtab-primary-action-background);
|
||||
transition: none;
|
||||
}
|
||||
.ds-card .ds-card-topic {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background: light-dark(#F0F0F4, var(--newtab-background-color-secondary));
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--space-small);
|
||||
margin: var(--space-small);
|
||||
font-size: 14px;
|
||||
}
|
||||
.ds-card .meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
@ -4505,6 +4505,15 @@ main section {
|
|||
box-shadow: 0 0 0 3px var(--newtab-primary-action-background-dimmed), 0 0 0 1px var(--newtab-primary-action-background);
|
||||
transition: none;
|
||||
}
|
||||
.ds-card .ds-card-topic {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background: light-dark(#F0F0F4, var(--newtab-background-color-secondary));
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--space-small);
|
||||
margin: var(--space-small);
|
||||
font-size: 14px;
|
||||
}
|
||||
.ds-card .meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
@ -4501,6 +4501,15 @@ main section {
|
|||
box-shadow: 0 0 0 3px var(--newtab-primary-action-background-dimmed), 0 0 0 1px var(--newtab-primary-action-background);
|
||||
transition: none;
|
||||
}
|
||||
.ds-card .ds-card-topic {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background: light-dark(#F0F0F4, var(--newtab-background-color-secondary));
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--space-small);
|
||||
margin: var(--space-small);
|
||||
font-size: 14px;
|
||||
}
|
||||
.ds-card .meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
@ -3213,7 +3213,9 @@ class _DSCard extends (external_React_default()).PureComponent {
|
|||
return /*#__PURE__*/external_React_default().createElement("article", {
|
||||
className: `ds-card ${compactImagesClassName} ${imageGradientClassName} ${titleLinesName} ${descLinesClassName} ${ctaButtonClassName} ${ctaButtonVariantClassName}`,
|
||||
ref: this.setContextMenuButtonHostRef
|
||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||
}, this.props.showTopics && this.props.topic && /*#__PURE__*/external_React_default().createElement("span", {
|
||||
className: "ds-card-topic"
|
||||
}, this.props.topic), /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: "img-wrapper"
|
||||
}, /*#__PURE__*/external_React_default().createElement(DSImage, {
|
||||
extraClassNames: "img",
|
||||
|
@ -3578,6 +3580,7 @@ const TopicsWidget = (0,external_ReactRedux_namespaceObject.connect)(state => ({
|
|||
|
||||
const PREF_ONBOARDING_EXPERIENCE_DISMISSED = "discoverystream.onboardingExperience.dismissed";
|
||||
const PREF_THUMBS_UP_DOWN_ENABLED = "discoverystream.thumbsUpDown.enabled";
|
||||
const PREF_TOPICS_ENABLED = "discoverystream.topicLabels.enabled";
|
||||
const CardGrid_INTERSECTION_RATIO = 0.5;
|
||||
const CardGrid_VISIBLE = "visible";
|
||||
const CardGrid_VISIBILITY_CHANGE_EVENT = "visibilitychange";
|
||||
|
@ -3851,6 +3854,7 @@ class _CardGrid extends (external_React_default()).PureComponent {
|
|||
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
|
||||
const isOnboardingExperienceDismissed = prefs[PREF_ONBOARDING_EXPERIENCE_DISMISSED];
|
||||
const mayHaveThumbsUpDown = prefs[PREF_THUMBS_UP_DOWN_ENABLED];
|
||||
const showTopics = prefs[PREF_TOPICS_ENABLED];
|
||||
const recs = this.props.data.recommendations.slice(0, items);
|
||||
const cards = [];
|
||||
let essentialReadsCards = [];
|
||||
|
@ -3868,6 +3872,8 @@ class _CardGrid extends (external_React_default()).PureComponent {
|
|||
word_count: rec.word_count,
|
||||
time_to_read: rec.time_to_read,
|
||||
title: rec.title,
|
||||
topic: rec.topic,
|
||||
showTopics: showTopics,
|
||||
excerpt: rec.excerpt,
|
||||
url: rec.url,
|
||||
id: rec.id,
|
||||
|
|
|
@ -195,7 +195,7 @@ module.exports = function (config) {
|
|||
statements: 98.25,
|
||||
lines: 98.2,
|
||||
functions: 100,
|
||||
branches: 74.81,
|
||||
branches: 74.63,
|
||||
},
|
||||
"content-src/components/DiscoveryStreamComponents/**/*.jsx": {
|
||||
statements: 90.48,
|
||||
|
|
|
@ -555,6 +555,13 @@ export const PREFS_CONFIG = new Map([
|
|||
value: "business, arts, government",
|
||||
},
|
||||
],
|
||||
[
|
||||
"discoverystream.topicLabels.enabled",
|
||||
{
|
||||
title: "Enables topic labels for discovery stream",
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
"showRecentSaves",
|
||||
{
|
||||
|
|
|
@ -1411,6 +1411,7 @@ export class DiscoveryStreamFeed {
|
|||
scheduled_corpus_item_id: item.scheduledCorpusItemId,
|
||||
url: item.url,
|
||||
title: item.title,
|
||||
topic: item.topic,
|
||||
excerpt: item.excerpt,
|
||||
publisher: item.publisher,
|
||||
raw_image_src: item.imageUrl,
|
||||
|
|
|
@ -26,13 +26,6 @@ const { DiscoveryStreamFeed } = ChromeUtils.importESModule(
|
|||
);
|
||||
|
||||
SearchTestUtils.init(this);
|
||||
AddonTestUtils.init(this);
|
||||
AddonTestUtils.createAppInfo(
|
||||
"xpcshell@tests.mozilla.org",
|
||||
"XPCShell",
|
||||
"42",
|
||||
"42"
|
||||
);
|
||||
|
||||
const { AboutNewTab } = ChromeUtils.importESModule(
|
||||
"resource:///modules/AboutNewTab.sys.mjs"
|
||||
|
@ -61,7 +54,7 @@ add_setup(async function () {
|
|||
do_get_profile();
|
||||
// The SearchService is also needed in order to construct the initial state,
|
||||
// which means that the AddonManager needs to be available.
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
await SearchTestUtils.initXPCShellAddonManager();
|
||||
|
||||
// The example.com domain will be used to host the dynamic layout JSON and
|
||||
// the top stories JSON.
|
||||
|
|
|
@ -10,20 +10,20 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneExperimental">
|
||||
<html:h1 data-l10n-id="settings-pane-labs-title"/>
|
||||
<html:h1 data-l10n-id="settings-pane-labs-title" class="section-heading"/>
|
||||
</vbox>
|
||||
|
||||
<html:div data-category="paneExperimental"
|
||||
id="pane-experimental-featureGates"
|
||||
hidden="true">
|
||||
<label class="search-header" hidden="true">
|
||||
<html:h2 data-l10n-id="settings-pane-labs-title"/>
|
||||
<html:h2 data-l10n-id="settings-pane-labs-title" class="section-heading"/>
|
||||
</label>
|
||||
<html:p data-l10n-id="pane-experimental-description3" class="description-deemphasized"/>
|
||||
<hbox pack="end">
|
||||
<button id="experimentalCategory-reset"
|
||||
class="accessory-button"
|
||||
data-l10n-id="pane-experimental-reset"/>
|
||||
<html:p data-l10n-id="pane-experimental-description3"
|
||||
class="description-deemphasized section-description"/>
|
||||
<hbox pack="start" class="section-header-last">
|
||||
<html:moz-button id="experimentalCategory-reset"
|
||||
data-l10n-id="pane-experimental-reset"/>
|
||||
</hbox>
|
||||
</html:div>
|
||||
</html:template>
|
||||
|
|
|
@ -91,7 +91,7 @@ var gExperimentalPane = {
|
|||
|
||||
setEventListener(
|
||||
"experimentalCategory-reset",
|
||||
"command",
|
||||
"click",
|
||||
gExperimentalPane.resetAllFeatures
|
||||
);
|
||||
|
||||
|
|
|
@ -459,6 +459,26 @@ serp:
|
|||
send_in_pings:
|
||||
- serp-categorization
|
||||
|
||||
ads_blocked_count:
|
||||
type: labeled_counter
|
||||
description: >
|
||||
Counts the specific type of block.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1907097
|
||||
data_reviews:
|
||||
- https://phabricator.services.mozilla.com/D216208
|
||||
notification_emails:
|
||||
- fx-search-telemetry@mozilla.com
|
||||
- rev-data@mozilla.com
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- technical
|
||||
labels:
|
||||
- beyond_viewport
|
||||
- hidden_parent
|
||||
- hidden_child
|
||||
|
||||
|
||||
search_with:
|
||||
reporting_url:
|
||||
type: url
|
||||
|
|
|
@ -35,6 +35,8 @@ support-files = ["searchTelemetryAd_searchbox_with_content.html", "serp.css"]
|
|||
["browser_search_telemetry_adImpression_component_skipCount_parent.js"]
|
||||
support-files = ["searchTelemetryAd_searchbox_with_content.html", "serp.css"]
|
||||
|
||||
["browser_search_telemetry_adblock_count.js"]
|
||||
|
||||
["browser_search_telemetry_categorization_timing.js"]
|
||||
|
||||
["browser_search_telemetry_content.js"]
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const BUILDER_URL = "https://example.com/document-builder.sjs?html=";
|
||||
|
||||
/**
|
||||
* This HTML file contains three ads:
|
||||
* - An ad that is well above the possible viewport.
|
||||
* - The numbers of ads are unique to help ensure counts are correct.
|
||||
*/
|
||||
const TEST_URI = `
|
||||
<!DOCTYPE html>
|
||||
<main>
|
||||
<style>
|
||||
.ad_parent {
|
||||
display: none;
|
||||
}
|
||||
/*
|
||||
This is if the ad blocker doesn't block the parent component but
|
||||
instead blocks the child.
|
||||
*/
|
||||
.ad_with_children div {
|
||||
display: none;
|
||||
}
|
||||
.ad_far_above {
|
||||
position: absolute;
|
||||
top: -9999px;
|
||||
}
|
||||
</style>
|
||||
<div class="ad_far_above">
|
||||
<a href="https://example.com/ad">Ad link</a>
|
||||
</div>
|
||||
<div class="ad_parent">
|
||||
<a href="https://example.com/ad">Ad link</a>
|
||||
</div>
|
||||
<div class="ad_parent">
|
||||
<a href="https://example.com/ad">Ad link</a>
|
||||
</div>
|
||||
<div class="ad_with_children">
|
||||
<span>Element</span>
|
||||
<div class="child">
|
||||
<a href="https://example.com/ad">Ad link</a>
|
||||
</div>
|
||||
<div class="child">
|
||||
<a href="https://example.com/ad">Ad link</a>
|
||||
</div>
|
||||
<div class="child">
|
||||
<a href="https://example.com/ad">Ad link</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
`;
|
||||
const URL =
|
||||
"https://example.org/document-builder.sjs?html=" +
|
||||
encodeURIComponent(TEST_URI) +
|
||||
"&s=foobar&abc=ff";
|
||||
|
||||
const TEST_PROVIDER_INFO = [
|
||||
{
|
||||
telemetryId: "example",
|
||||
searchPageRegexp: /^https:\/\/example\.org\/document-builder\.sjs/,
|
||||
queryParamNames: ["s"],
|
||||
codeParamName: "abc",
|
||||
taggedCodes: ["ff"],
|
||||
extraAdServersRegexps: [/^https:\/\/example\.com\/ad/],
|
||||
components: [
|
||||
{
|
||||
type: SearchSERPTelemetryUtils.COMPONENTS.AD_CAROUSEL,
|
||||
included: {
|
||||
parent: {
|
||||
selector: ".ad_with_children",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
selector: ".child",
|
||||
countChildren: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: SearchSERPTelemetryUtils.COMPONENTS.AD_SITELINK,
|
||||
included: {
|
||||
parent: {
|
||||
selector: ".ad_parent",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
|
||||
default: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
add_setup(async function () {
|
||||
SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
|
||||
await waitForIdle();
|
||||
// Enable local telemetry recording for the duration of the tests.
|
||||
let oldCanRecord = Services.telemetry.canRecordExtended;
|
||||
Services.telemetry.canRecordExtended = true;
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
SearchSERPTelemetry.overrideSearchTelemetryForTests();
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
resetTelemetry();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_adblock_count() {
|
||||
let { cleanup } = await openSerpInNewTab(URL);
|
||||
|
||||
assertSERPTelemetry([
|
||||
{
|
||||
impression: {
|
||||
is_signed_in: "false",
|
||||
is_private: "false",
|
||||
source: "unknown",
|
||||
is_shopping_page: "false",
|
||||
partner_code: "ff",
|
||||
provider: "example",
|
||||
shopping_tab_displayed: "false",
|
||||
tagged: "true",
|
||||
},
|
||||
adImpressions: [
|
||||
{
|
||||
component: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK,
|
||||
ads_loaded: "1",
|
||||
ads_visible: "0",
|
||||
ads_hidden: "1",
|
||||
},
|
||||
{
|
||||
component: SearchSERPTelemetryUtils.COMPONENTS.AD_SITELINK,
|
||||
ads_loaded: "2",
|
||||
ads_visible: "0",
|
||||
ads_hidden: "2",
|
||||
},
|
||||
{
|
||||
component: SearchSERPTelemetryUtils.COMPONENTS.AD_CAROUSEL,
|
||||
ads_loaded: "3",
|
||||
ads_visible: "0",
|
||||
ads_hidden: "3",
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
|
||||
Assert.equal(
|
||||
1,
|
||||
Glean.serp.adsBlockedCount.beyond_viewport.testGetValue(),
|
||||
"Number of ads blocked due to being beyond the viewport."
|
||||
);
|
||||
Assert.equal(
|
||||
2,
|
||||
Glean.serp.adsBlockedCount.hidden_parent.testGetValue(),
|
||||
"Number of parent elements blocked."
|
||||
);
|
||||
Assert.equal(
|
||||
3,
|
||||
Glean.serp.adsBlockedCount.hidden_child.testGetValue(),
|
||||
"Number of child elements blocked."
|
||||
);
|
||||
|
||||
await cleanup();
|
||||
});
|
|
@ -70,7 +70,7 @@ class AsyncFaviconDataReady final : public nsIFaviconDataCallback {
|
|||
int aIconIndex, int aTimeStamp)
|
||||
: mSearchResult(std::move(aSearchResult)),
|
||||
mIconIndex(aIconIndex),
|
||||
mTimeStamp(aTimeStamp){};
|
||||
mTimeStamp(aTimeStamp) {};
|
||||
|
||||
private:
|
||||
~AsyncFaviconDataReady() {}
|
||||
|
|
|
@ -23,7 +23,7 @@ class nsGNOMEShellSearchProvider;
|
|||
|
||||
class GnomeHistoryIcon {
|
||||
public:
|
||||
GnomeHistoryIcon() : mTimeStamp(-1), mWidth(0), mHeight(0){};
|
||||
GnomeHistoryIcon() : mTimeStamp(-1), mWidth(0), mHeight(0) {};
|
||||
|
||||
// From which search is this icon
|
||||
void Set(int aTimeStamp, mozilla::UniquePtr<uint8_t[]> aData, int aWidth,
|
||||
|
@ -58,7 +58,7 @@ class nsGNOMEShellHistorySearchResult : public nsUnixRemoteServer {
|
|||
GDBusConnection* aConnection, int aTimeStamp)
|
||||
: mSearchProvider(aSearchProvider),
|
||||
mConnection(aConnection),
|
||||
mTimeStamp(aTimeStamp){};
|
||||
mTimeStamp(aTimeStamp) {};
|
||||
|
||||
void SetReply(RefPtr<GDBusMethodInvocation> aReply) {
|
||||
mReply = std::move(aReply);
|
||||
|
|
|
@ -16,7 +16,7 @@ class nsMacShellService : public nsIMacShellService,
|
|||
public nsToolkitShellService,
|
||||
public nsIWebProgressListener {
|
||||
public:
|
||||
nsMacShellService(){};
|
||||
nsMacShellService() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISHELLSERVICE
|
||||
|
@ -24,7 +24,7 @@ class nsMacShellService : public nsIMacShellService,
|
|||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
|
||||
protected:
|
||||
virtual ~nsMacShellService(){};
|
||||
virtual ~nsMacShellService() {};
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFile> mBackgroundFile;
|
||||
|
|
|
@ -201,9 +201,21 @@ var SelectTranslationsPanel = new (class {
|
|||
* Many of these are cases where the SelectTranslationsPanel is available
|
||||
* even though the FullPageTranslationsPanel is not, so this helps inform
|
||||
* whether the translate-full-page button should be allowed in this context.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
#isFullPageTranslationsRestrictedForPage = true;
|
||||
|
||||
/**
|
||||
* The BCP-47 language tag of the active target language for Full-Page Translations,
|
||||
* if available. This may not be available if Full-Page Translations is not currently
|
||||
* active in the current tab of the current window, or if Full-Page Translations is
|
||||
* restricted on the current page.
|
||||
*
|
||||
* @type { string | undefined }
|
||||
*/
|
||||
#activeFullPageTranslationsTargetLanguage = undefined;
|
||||
|
||||
/**
|
||||
* The internal state of the SelectTranslationsPanel.
|
||||
*
|
||||
|
@ -334,6 +346,13 @@ var SelectTranslationsPanel = new (class {
|
|||
return this.#languageInfo;
|
||||
}
|
||||
|
||||
this.#isFullPageTranslationsRestrictedForPage =
|
||||
TranslationsParent.isFullPageTranslationsRestrictedForPage(gBrowser);
|
||||
this.#activeFullPageTranslationsTargetLanguage = this
|
||||
.#isFullPageTranslationsRestrictedForPage
|
||||
? undefined
|
||||
: this.#maybeGetActiveFullPageTranslationsTargetLanguage();
|
||||
|
||||
this.#languageInfo = {
|
||||
docLangTag: undefined,
|
||||
isDocLangTagSupported: undefined,
|
||||
|
@ -350,7 +369,11 @@ var SelectTranslationsPanel = new (class {
|
|||
const preferredLanguages = TranslationsParent.getPreferredLanguages();
|
||||
const topPreferredLanguage = preferredLanguages?.[0];
|
||||
this.#languageInfo = {
|
||||
docLangTag,
|
||||
docLangTag:
|
||||
// If Full-Page Translations (FPT) is active, we need to assume that the effective
|
||||
// document language tag matches the language of the FPT target language, otherwise,
|
||||
// if FPT is not active, we can take the real docLangTag value.
|
||||
this.#activeFullPageTranslationsTargetLanguage ?? docLangTag,
|
||||
isDocLangTagSupported,
|
||||
topPreferredLanguage,
|
||||
};
|
||||
|
@ -561,8 +584,6 @@ var SelectTranslationsPanel = new (class {
|
|||
|
||||
try {
|
||||
this.#sourceTextWordCount = undefined;
|
||||
this.#isFullPageTranslationsRestrictedForPage =
|
||||
TranslationsParent.isFullPageTranslationsRestrictedForPage(gBrowser);
|
||||
this.#initializeEventListeners();
|
||||
await this.#ensureLangListsBuilt();
|
||||
await Promise.all([
|
||||
|
@ -586,6 +607,26 @@ var SelectTranslationsPanel = new (class {
|
|||
this.#openPopup(event, screenX, screenY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to retrieve the language tag of the requested target language
|
||||
* for Full Page Translations, if Full Page Translations is active on the page
|
||||
* within the active tab of the active window.
|
||||
*
|
||||
* @returns {string | undefined} - The BCP-47 language tag.
|
||||
*/
|
||||
#maybeGetActiveFullPageTranslationsTargetLanguage() {
|
||||
try {
|
||||
const { requestedTranslationPair } =
|
||||
TranslationsParent.getTranslationsActor(
|
||||
gBrowser.selectedBrowser
|
||||
).languageState;
|
||||
return requestedTranslationPair?.toLanguage;
|
||||
} catch {
|
||||
this.console.warn("Failed to retrieve the TranslationsParent actor.");
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the panel to close and reopen at the same location.
|
||||
*
|
||||
|
@ -1768,6 +1809,20 @@ var SelectTranslationsPanel = new (class {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the translate-full-page button should be hidden in the current panel view.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
#shouldHideTranslateFullPageButton() {
|
||||
return (
|
||||
// Do not offer to translate the full page if it is restricted on this page.
|
||||
this.#isFullPageTranslationsRestrictedForPage ||
|
||||
// Do not offer to translate the full page if Full-Page Translations is already active.
|
||||
this.#activeFullPageTranslationsTargetLanguage
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether translation should continue based on panel state and language pair.
|
||||
*
|
||||
|
@ -1874,7 +1929,7 @@ var SelectTranslationsPanel = new (class {
|
|||
translateFullPageButton.disabled =
|
||||
invalidLangPairSelected ||
|
||||
fromLanguage === toLanguage ||
|
||||
this.#isFullPageTranslationsRestrictedForPage;
|
||||
this.#shouldHideTranslateFullPageButton();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1917,7 +1972,7 @@ var SelectTranslationsPanel = new (class {
|
|||
translationFailureMessageBar,
|
||||
tryAgainButton,
|
||||
unsupportedLanguageContent,
|
||||
...(this.#isFullPageTranslationsRestrictedForPage
|
||||
...(this.#shouldHideTranslateFullPageButton()
|
||||
? [translateFullPageButton]
|
||||
: []),
|
||||
],
|
||||
|
@ -1926,7 +1981,7 @@ var SelectTranslationsPanel = new (class {
|
|||
copyButton,
|
||||
doneButtonPrimary,
|
||||
textArea,
|
||||
...(this.#isFullPageTranslationsRestrictedForPage
|
||||
...(this.#shouldHideTranslateFullPageButton()
|
||||
? []
|
||||
: [translateFullPageButton]),
|
||||
],
|
||||
|
@ -2127,16 +2182,10 @@ var SelectTranslationsPanel = new (class {
|
|||
* @returns {Promise<MessagePort | undefined>} The message port promise.
|
||||
*/
|
||||
async #requestTranslationsPort(fromLanguage, toLanguage) {
|
||||
const innerWindowId =
|
||||
gBrowser.selectedBrowser.browsingContext.top.embedderElement
|
||||
.innerWindowID;
|
||||
if (!innerWindowId) {
|
||||
return undefined;
|
||||
}
|
||||
const port = await TranslationsParent.requestTranslationsPort(
|
||||
innerWindowId,
|
||||
fromLanguage,
|
||||
toLanguage
|
||||
toLanguage,
|
||||
/* innerWindowId */ null
|
||||
);
|
||||
return port;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,12 @@ skip-if = ["os == 'linux' && !debug"] # Bug 1863227
|
|||
|
||||
["browser_translations_select_context_menu_feature_disabled.js"]
|
||||
|
||||
["browser_translations_select_context_menu_preferred_app_locales.js"]
|
||||
|
||||
["browser_translations_select_context_menu_preferred_language_edge_cases.js"]
|
||||
|
||||
["browser_translations_select_context_menu_preferred_web_languages.js"]
|
||||
|
||||
["browser_translations_select_context_menu_with_full_page_translations_active.js"]
|
||||
|
||||
["browser_translations_select_context_menu_with_hyperlink.js"]
|
||||
|
@ -199,4 +205,8 @@ skip-if = ["os == 'linux' && !debug"] # Bug 1863227
|
|||
|
||||
["browser_translations_select_telemetry_translation_failure_ui_then_succeed.js"]
|
||||
|
||||
["browser_translations_select_telemetry_translation_failure_with_full_page_translations_active.js"]
|
||||
|
||||
["browser_translations_select_telemetry_translation_success_with_full_page_translations_active.js"]
|
||||
|
||||
["browser_translations_select_telemetry_unsupported_language_ui.js"]
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This test case tests various fallback edge cases regarding which language to
|
||||
* offer for translations based on the user's application locale settings.
|
||||
*/
|
||||
add_task(
|
||||
async function test_translate_selection_menuitem_preferred_app_locales() {
|
||||
const { cleanup, runInPage } = await loadTestPage({
|
||||
page: SELECT_TEST_PAGE_URL,
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "pl" },
|
||||
{ fromLang: "pl", toLang: "en" },
|
||||
// Only supported as a source language
|
||||
{ fromLang: "fi", toLang: "en" },
|
||||
// Only supported as a target language
|
||||
{ fromLang: "en", toLang: "sl" },
|
||||
],
|
||||
prefs: [["browser.translations.select.enable", true]],
|
||||
});
|
||||
|
||||
await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage);
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["es", "fr", "fi", "zh", "sl"],
|
||||
expectedTargetLanguage: "es",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["fr", "fi", "zh", "sl", "es"],
|
||||
expectedTargetLanguage: "fr",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["fi", "zh", "sl", "es", "fr"],
|
||||
// "fi" is not supported as a target language, so fall back
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["zh", "sl", "es", "fr", "fi"],
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["sl", "es", "fr", "fi", "zh"],
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
}
|
||||
);
|
|
@ -0,0 +1,74 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This test case tests various fallback edge cases regarding which language to
|
||||
* offer for translations based on user settings and supported translations languages.
|
||||
*/
|
||||
add_task(
|
||||
async function test_translate_selection_menuitem_preferred_language_edge_cases() {
|
||||
const { cleanup, runInPage } = await loadTestPage({
|
||||
page: SELECT_TEST_PAGE_URL,
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "pl" },
|
||||
{ fromLang: "pl", toLang: "en" },
|
||||
// Only supported as a source language
|
||||
{ fromLang: "fi", toLang: "en" },
|
||||
// Only supported as a target language
|
||||
{ fromLang: "en", toLang: "sl" },
|
||||
],
|
||||
prefs: [["browser.translations.select.enable", true]],
|
||||
});
|
||||
|
||||
await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage);
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
systemLocales: [],
|
||||
appLocales: [],
|
||||
webLanguages: [],
|
||||
// No locales are specified, so fall back to "en".
|
||||
expectedTargetLanguage: "en",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["fi", "fr", "en-US"],
|
||||
webLanguages: ["zh"],
|
||||
expectedTargetLanguage: "fr",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["zh", "uk", "fr", "en-US"],
|
||||
webLanguages: ["fi"],
|
||||
// Fall back to the first to-language compatible tag.
|
||||
expectedTargetLanguage: "fr",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
appLocales: ["zh", "fi", "sl", "fr", "en-US"],
|
||||
webLanguages: ["fi", "zh"],
|
||||
// Fall back to the first to-language compatible tag.
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
systemLocales: ["zh-TW", "zh-CN", "de"],
|
||||
appLocales: ["pt-BR", "ja"],
|
||||
webLanguages: ["cs", "hu"],
|
||||
// None of these locales are supported, so default to "en".
|
||||
expectedTargetLanguage: "en",
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
}
|
||||
);
|
|
@ -0,0 +1,64 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This test case tests various fallback edge cases regarding which language to
|
||||
* offer for translations based on the user's web content language settings.
|
||||
*/
|
||||
add_task(
|
||||
async function test_translate_selection_menuitem_preferred_web_languages() {
|
||||
const { cleanup, runInPage } = await loadTestPage({
|
||||
page: SELECT_TEST_PAGE_URL,
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "pl" },
|
||||
{ fromLang: "pl", toLang: "en" },
|
||||
// Only supported as a source language
|
||||
{ fromLang: "fi", toLang: "en" },
|
||||
// Only supported as a target language
|
||||
{ fromLang: "en", toLang: "sl" },
|
||||
],
|
||||
prefs: [["browser.translations.select.enable", true]],
|
||||
});
|
||||
|
||||
await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage);
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
webLanguages: ["es", "fr", "fi", "zh", "sl"],
|
||||
expectedTargetLanguage: "es",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
webLanguages: ["fr", "fi", "zh", "sl", "es"],
|
||||
expectedTargetLanguage: "fr",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
webLanguages: ["fi", "zh", "sl", "es", "fr"],
|
||||
// "fi" is not supported as a target language, so fall back
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
webLanguages: ["zh", "sl", "es", "fr", "fi"],
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
webLanguages: ["sl", "es", "fr", "fi", "zh"],
|
||||
expectedTargetLanguage: "sl",
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
}
|
||||
);
|
|
@ -54,9 +54,10 @@ add_task(
|
|||
{
|
||||
selectSpanishSentence: true,
|
||||
openAtSpanishSentence: true,
|
||||
expectMenuItemVisible: false,
|
||||
expectMenuItemVisible: true,
|
||||
expectedTargetLanguage: "en",
|
||||
},
|
||||
"The translate-selection context menu item should be unavailable while full-page translations is active."
|
||||
"The translate-selection context menu item should be available even while full-page translations is active."
|
||||
);
|
||||
|
||||
await FullPageTranslationsTestUtils.openPanel({
|
||||
|
@ -133,9 +134,10 @@ add_task(
|
|||
{
|
||||
selectSpanishSentence: false,
|
||||
openAtSpanishHyperlink: true,
|
||||
expectMenuItemVisible: false,
|
||||
expectMenuItemVisible: true,
|
||||
expectedTargetLanguage: "en",
|
||||
},
|
||||
"The translate-selection context menu item should be unavailable while full-page translations is active."
|
||||
"The translate-selection context menu item should be available even while full-page translations is active."
|
||||
);
|
||||
|
||||
await FullPageTranslationsTestUtils.openPanel({
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(
|
||||
async function test_select_translations_panel_translation_failure_with_full_page_translations_active() {
|
||||
const { cleanup, runInPage, resolveDownloads, rejectDownloads } =
|
||||
await loadTestPage({
|
||||
page: SELECT_TEST_PAGE_URL,
|
||||
languagePairs: LANGUAGE_PAIRS,
|
||||
prefs: [["browser.translations.select.enable", true]],
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.openPanel(runInPage, {
|
||||
openAtSpanishHyperlink: true,
|
||||
expectedFromLanguage: "es",
|
||||
expectedToLanguage: "en",
|
||||
downloadHandler: resolveDownloads,
|
||||
onOpenPanel: SelectTranslationsTestUtils.assertPanelViewTranslated,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.open,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
expectNewFlowId: true,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
text_source: "hyperlink",
|
||||
},
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 0],
|
||||
["select", 1],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
request_target: "select",
|
||||
auto_translate: false,
|
||||
source_text_code_units: 23,
|
||||
source_text_word_count: 4,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.changeSelectedToLanguage(["fr"], {
|
||||
openDropdownMenu: true,
|
||||
pivotTranslation: true,
|
||||
downloadHandler: resolveDownloads,
|
||||
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.changeToLanguage,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 0],
|
||||
["select", 2],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 2,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "fr",
|
||||
top_preferred_language: "en",
|
||||
request_target: "select",
|
||||
auto_translate: false,
|
||||
source_text_code_units: 23,
|
||||
source_text_word_count: 4,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.clickTranslateFullPageButton();
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.translateFullPageButton,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 1],
|
||||
["select", 2],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 3,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "fr",
|
||||
top_preferred_language: "en",
|
||||
request_target: "full_page",
|
||||
auto_translate: false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await FullPageTranslationsTestUtils.assertPageIsTranslated(
|
||||
"es",
|
||||
"fr",
|
||||
runInPage
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.openPanel(runInPage, {
|
||||
selectFrenchSection: true,
|
||||
openAtFrenchSection: true,
|
||||
expectedFromLanguage: "fr",
|
||||
expectedToLanguage: "en",
|
||||
downloadHandler: rejectDownloads,
|
||||
onOpenPanel:
|
||||
SelectTranslationsTestUtils.assertPanelViewTranslationFailure,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.open,
|
||||
{
|
||||
expectedEventCount: 2,
|
||||
expectNewFlowId: true,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "fr",
|
||||
from_language: "fr",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
text_source: "selection",
|
||||
},
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 1],
|
||||
["select", 3],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 4,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "fr",
|
||||
from_language: "fr",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
request_target: "select",
|
||||
auto_translate: false,
|
||||
source_text_code_units:
|
||||
AppConstants.platform === "win"
|
||||
? 1718 // With carriage returns
|
||||
: 1709, // No carriage returns
|
||||
source_text_word_count: 281,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.clickCancelButton();
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.cancelButton,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
}
|
||||
);
|
||||
|
||||
await FullPageTranslationsTestUtils.openPanel({
|
||||
onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, {
|
||||
expectedEventCount: 1,
|
||||
expectNewFlowId: true,
|
||||
assertForMostRecentEvent: {
|
||||
auto_show: false,
|
||||
view_name: "revisitView",
|
||||
opened_from: "translationsButton",
|
||||
document_language: "es",
|
||||
},
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
}
|
||||
);
|
|
@ -0,0 +1,203 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(
|
||||
async function test_select_translations_panel_translation_success_with_full_page_translations_active() {
|
||||
const { cleanup, runInPage, resolveDownloads } = await loadTestPage({
|
||||
page: SELECT_TEST_PAGE_URL,
|
||||
languagePairs: LANGUAGE_PAIRS,
|
||||
prefs: [["browser.translations.select.enable", true]],
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.openPanel(runInPage, {
|
||||
openAtSpanishHyperlink: true,
|
||||
expectedFromLanguage: "es",
|
||||
expectedToLanguage: "en",
|
||||
downloadHandler: resolveDownloads,
|
||||
onOpenPanel: SelectTranslationsTestUtils.assertPanelViewTranslated,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.open,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
expectNewFlowId: true,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
text_source: "hyperlink",
|
||||
},
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 0],
|
||||
["select", 1],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
request_target: "select",
|
||||
auto_translate: false,
|
||||
source_text_code_units: 23,
|
||||
source_text_word_count: 4,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.changeSelectedToLanguage(["fr"], {
|
||||
openDropdownMenu: true,
|
||||
pivotTranslation: true,
|
||||
downloadHandler: resolveDownloads,
|
||||
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.changeToLanguage,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 0],
|
||||
["select", 2],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 2,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "fr",
|
||||
top_preferred_language: "en",
|
||||
request_target: "select",
|
||||
auto_translate: false,
|
||||
source_text_code_units: 23,
|
||||
source_text_word_count: 4,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.clickTranslateFullPageButton();
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.translateFullPageButton,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 1],
|
||||
["select", 2],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 3,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "es",
|
||||
from_language: "es",
|
||||
to_language: "fr",
|
||||
top_preferred_language: "en",
|
||||
request_target: "full_page",
|
||||
auto_translate: false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await FullPageTranslationsTestUtils.assertPageIsTranslated(
|
||||
"es",
|
||||
"fr",
|
||||
runInPage
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.openPanel(runInPage, {
|
||||
selectFrenchSection: true,
|
||||
openAtFrenchSection: true,
|
||||
expectedFromLanguage: "fr",
|
||||
expectedToLanguage: "en",
|
||||
downloadHandler: resolveDownloads,
|
||||
onOpenPanel: SelectTranslationsTestUtils.assertPanelViewTranslated,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.open,
|
||||
{
|
||||
expectedEventCount: 2,
|
||||
expectNewFlowId: true,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "fr",
|
||||
from_language: "fr",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
text_source: "selection",
|
||||
},
|
||||
}
|
||||
);
|
||||
await TestTranslationsTelemetry.assertLabeledCounter(
|
||||
Glean.translations.requestCount,
|
||||
[
|
||||
["full_page", 1],
|
||||
["select", 3],
|
||||
]
|
||||
);
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translations.translationRequest,
|
||||
{
|
||||
expectedEventCount: 4,
|
||||
assertForMostRecentEvent: {
|
||||
document_language: "fr",
|
||||
from_language: "fr",
|
||||
to_language: "en",
|
||||
top_preferred_language: "en",
|
||||
request_target: "select",
|
||||
auto_translate: false,
|
||||
source_text_code_units:
|
||||
AppConstants.platform === "win"
|
||||
? 1718 // With carriage returns
|
||||
: 1709, // No carriage returns
|
||||
source_text_word_count: 281,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await SelectTranslationsTestUtils.clickDoneButton();
|
||||
await TestTranslationsTelemetry.assertEvent(
|
||||
Glean.translationsSelectTranslationsPanel.doneButton,
|
||||
{
|
||||
expectedEventCount: 1,
|
||||
}
|
||||
);
|
||||
|
||||
await FullPageTranslationsTestUtils.openPanel({
|
||||
onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit,
|
||||
});
|
||||
await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, {
|
||||
expectedEventCount: 1,
|
||||
expectNewFlowId: true,
|
||||
assertForMostRecentEvent: {
|
||||
auto_show: false,
|
||||
view_name: "revisitView",
|
||||
opened_from: "translationsButton",
|
||||
document_language: "es",
|
||||
},
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
}
|
||||
);
|
|
@ -199,6 +199,24 @@ function logAction(...params) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Full-Page Translations is currently active, otherwise false.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isFullPageTranslationsActive() {
|
||||
try {
|
||||
const { requestedTranslationPair } =
|
||||
TranslationsParent.getTranslationsActor(
|
||||
gBrowser.selectedBrowser
|
||||
).languageState;
|
||||
return !!requestedTranslationPair;
|
||||
} catch {
|
||||
// Translations actor unavailable, continue on.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a URL and indicate a message as to why.
|
||||
*/
|
||||
|
@ -1513,6 +1531,8 @@ class SelectTranslationsTestUtils {
|
|||
if (expectedTargetLanguage) {
|
||||
// Target language expected, check for the data-l10n-id with a `{$language}` argument.
|
||||
const expectedL10nId =
|
||||
selectH1 ||
|
||||
selectPdfSpan ||
|
||||
selectFrenchSection ||
|
||||
selectEnglishSection ||
|
||||
selectSpanishSection ||
|
||||
|
@ -1521,26 +1541,34 @@ class SelectTranslationsTestUtils {
|
|||
selectSpanishSentence
|
||||
? "main-context-menu-translate-selection-to-language"
|
||||
: "main-context-menu-translate-link-text-to-language";
|
||||
|
||||
await waitForCondition(
|
||||
() =>
|
||||
menuItem.getAttribute("target-language") === expectedTargetLanguage,
|
||||
`Waiting for translate-selection context menu item to match the expected target language ${expectedTargetLanguage}`
|
||||
);
|
||||
await waitForCondition(
|
||||
() => menuItem.getAttribute("data-l10n-id") === expectedL10nId,
|
||||
`Waiting for translate-selection context menu item to localize with target language ${expectedTargetLanguage}`
|
||||
`Waiting for translate-selection context menu item to have the correct data-l10n-id '${expectedL10nId}`
|
||||
);
|
||||
|
||||
is(
|
||||
menuItem.getAttribute("data-l10n-id"),
|
||||
expectedL10nId,
|
||||
"Expected the translate-selection context menu item to be localized with a target language."
|
||||
);
|
||||
|
||||
const l10nArgs = JSON.parse(menuItem.getAttribute("data-l10n-args"));
|
||||
is(
|
||||
l10nArgs.language,
|
||||
getIntlDisplayName(expectedTargetLanguage),
|
||||
`Expected the translate-selection context menu item to have the target language '${expectedTargetLanguage}'.`
|
||||
);
|
||||
if (Services.locale.appLocaleAsBCP47 === "en-US") {
|
||||
// We only want to test the localized name in CI if the current app locale is the default (en-US).
|
||||
const expectedLanguageDisplayName = getIntlDisplayName(
|
||||
expectedTargetLanguage
|
||||
);
|
||||
await waitForCondition(() => {
|
||||
const l10nArgs = JSON.parse(
|
||||
menuItem.getAttribute("data-l10n-args")
|
||||
);
|
||||
return l10nArgs.language === expectedLanguageDisplayName;
|
||||
}, `Waiting for translate-selection context menu item to have the correct data-l10n-args '${expectedLanguageDisplayName}`);
|
||||
}
|
||||
} else {
|
||||
// No target language expected, check for the data-l10n-id that has no `{$language}` argument.
|
||||
const expectedL10nId =
|
||||
selectH1 ||
|
||||
selectPdfSpan ||
|
||||
selectFrenchSection ||
|
||||
selectEnglishSection ||
|
||||
selectSpanishSection ||
|
||||
|
@ -1550,19 +1578,56 @@ class SelectTranslationsTestUtils {
|
|||
? "main-context-menu-translate-selection"
|
||||
: "main-context-menu-translate-link-text";
|
||||
await waitForCondition(
|
||||
() => menuItem.getAttribute("data-l10n-id") === expectedL10nId,
|
||||
"Waiting for translate-selection context menu item to localize without target language."
|
||||
() => !menuItem.getAttribute("target-language"),
|
||||
"Waiting for translate-selection context menu item to remove its target-language attribute."
|
||||
);
|
||||
|
||||
is(
|
||||
menuItem.getAttribute("data-l10n-id"),
|
||||
expectedL10nId,
|
||||
"Expected the translate-selection context menu item to be localized without a target language."
|
||||
await waitForCondition(
|
||||
() => menuItem.getAttribute("data-l10n-id") === expectedL10nId,
|
||||
`Waiting for translate-selection context menu item to have the correct data-l10n-id '${expectedL10nId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the context menu displays the expected target language for translation based on
|
||||
* the provided configurations.
|
||||
*
|
||||
* @param {object} options - Options for configuring the test environment and expected language behavior.
|
||||
* @param {Array.<string>} options.runInPage - A content-exposed function to run within the context of the page.
|
||||
* @param {Array.<string>} [options.systemLocales=[]] - Locales to mock as system locales.
|
||||
* @param {Array.<string>} [options.appLocales=[]] - Locales to mock as application locales.
|
||||
* @param {Array.<string>} [options.webLanguages=[]] - Languages to mock as web languages.
|
||||
* @param {string} options.expectedTargetLanguage - The expected target language for the translate-selection item.
|
||||
*/
|
||||
static async testContextMenuItemWithLocales({
|
||||
runInPage,
|
||||
systemLocales = [],
|
||||
appLocales = [],
|
||||
webLanguages = [],
|
||||
expectedTargetLanguage,
|
||||
}) {
|
||||
const cleanupLocales = await mockLocales({
|
||||
systemLocales,
|
||||
appLocales,
|
||||
webLanguages,
|
||||
});
|
||||
|
||||
await SelectTranslationsTestUtils.assertContextMenuTranslateSelectionItem(
|
||||
runInPage,
|
||||
{
|
||||
selectSpanishSentence: true,
|
||||
openAtSpanishSentence: true,
|
||||
expectMenuItemVisible: true,
|
||||
expectedTargetLanguage,
|
||||
},
|
||||
`The translate-selection context menu item should match the expected target language '${expectedTargetLanguage}'`
|
||||
);
|
||||
|
||||
await closeAllOpenPanelsAndMenus();
|
||||
await cleanupLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that for each provided expectation, the visible state of the corresponding
|
||||
* element in FullPageTranslationsPanel.elements both exists and matches the visibility expectation.
|
||||
|
@ -1660,14 +1725,20 @@ class SelectTranslationsTestUtils {
|
|||
textArea: true,
|
||||
toLabel: true,
|
||||
toMenuList: true,
|
||||
translateFullPageButton: !isFullPageTranslationsRestrictedForPage,
|
||||
translateFullPageButton: !(
|
||||
isFullPageTranslationsRestrictedForPage ||
|
||||
isFullPageTranslationsActive()
|
||||
),
|
||||
});
|
||||
SelectTranslationsTestUtils.#assertConditionalUIEnabled({
|
||||
copyButton: true,
|
||||
doneButtonPrimary: true,
|
||||
textArea: true,
|
||||
translateFullPageButton:
|
||||
!sameLanguageSelected && !isFullPageTranslationsRestrictedForPage,
|
||||
translateFullPageButton: !(
|
||||
sameLanguageSelected ||
|
||||
isFullPageTranslationsRestrictedForPage ||
|
||||
isFullPageTranslationsActive()
|
||||
),
|
||||
});
|
||||
|
||||
await waitForCondition(
|
||||
|
@ -1683,7 +1754,11 @@ class SelectTranslationsTestUtils {
|
|||
await SelectTranslationsTestUtils.#assertPanelTextAreaOverflow();
|
||||
|
||||
let footerButtons;
|
||||
if (sameLanguageSelected || isFullPageTranslationsRestrictedForPage) {
|
||||
if (
|
||||
sameLanguageSelected ||
|
||||
isFullPageTranslationsRestrictedForPage ||
|
||||
isFullPageTranslationsActive()
|
||||
) {
|
||||
footerButtons = [copyButton, doneButtonPrimary];
|
||||
} else {
|
||||
footerButtons =
|
||||
|
@ -1914,7 +1989,10 @@ class SelectTranslationsTestUtils {
|
|||
textArea: true,
|
||||
toLabel: true,
|
||||
toMenuList: true,
|
||||
translateFullPageButton: !isFullPageTranslationsRestrictedForPage,
|
||||
translateFullPageButton: !(
|
||||
isFullPageTranslationsRestrictedForPage ||
|
||||
isFullPageTranslationsActive()
|
||||
),
|
||||
});
|
||||
SelectTranslationsTestUtils.#assertPanelHasTranslatingPlaceholder();
|
||||
}
|
||||
|
@ -1943,7 +2021,8 @@ class SelectTranslationsTestUtils {
|
|||
doneButtonPrimary: true,
|
||||
translateFullPageButton:
|
||||
fromMenuList.value !== toMenuList.value &&
|
||||
!isFullPageTranslationsRestrictedForPage,
|
||||
!isFullPageTranslationsRestrictedForPage &&
|
||||
!isFullPageTranslationsActive(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1965,7 +2044,9 @@ class SelectTranslationsTestUtils {
|
|||
copyButton: true,
|
||||
doneButtonPrimary: true,
|
||||
translateFullPageButton:
|
||||
fromLanguage !== toLanguage && !isFullPageTranslationsRestrictedForPage,
|
||||
fromLanguage !== toLanguage &&
|
||||
!isFullPageTranslationsRestrictedForPage &&
|
||||
!isFullPageTranslationsActive(),
|
||||
});
|
||||
|
||||
if (fromLanguage === toLanguage) {
|
||||
|
|
|
@ -207,8 +207,8 @@ class _QuickSuggest {
|
|||
}
|
||||
}
|
||||
|
||||
this._updateFeatureState();
|
||||
lazy.NimbusFeatures.urlbar.onUpdate(() => this._updateFeatureState());
|
||||
this.#updateAll();
|
||||
lazy.NimbusFeatures.urlbar.onUpdate(() => this.#updateAll());
|
||||
lazy.UrlbarPrefs.addObserver(this);
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ class _QuickSuggest {
|
|||
/**
|
||||
* Updates state based on whether quick suggest and its features are enabled.
|
||||
*/
|
||||
_updateFeatureState() {
|
||||
#updateAll() {
|
||||
// IMPORTANT: This method is a `NimbusFeatures.urlbar.onUpdate()` callback,
|
||||
// which means it's called on every change to any pref that is a fallback
|
||||
// for a urlbar Nimbus variable.
|
||||
|
|
|
@ -238,6 +238,7 @@ export class UrlbarInput {
|
|||
this.window.addEventListener("draggableregionleftmousedown", this);
|
||||
}
|
||||
this.textbox.addEventListener("mousedown", this);
|
||||
this.textbox.addEventListener("mouseup", this);
|
||||
|
||||
// This listener handles clicks from our children too, included the search mode
|
||||
// indicator close button.
|
||||
|
@ -3196,7 +3197,9 @@ export class UrlbarInput {
|
|||
#maybeUntrimUrl({ moveCursorToStart = false } = {}) {
|
||||
// Check if we can untrim the current value.
|
||||
if (
|
||||
!lazy.UrlbarPrefs.get("untrimOnUserInteraction.featureGate") ||
|
||||
!lazy.UrlbarPrefs.getScotchBonnetPref(
|
||||
"untrimOnUserInteraction.featureGate"
|
||||
) ||
|
||||
!this._protocolIsTrimmed ||
|
||||
!this.focused ||
|
||||
this.#allTextSelected
|
||||
|
@ -3663,7 +3666,13 @@ export class UrlbarInput {
|
|||
// pageproxystate. In order to only show the search icon, switch to
|
||||
// an invalid pageproxystate.
|
||||
if (this.window.gBrowser.selectedBrowser.searchTerms) {
|
||||
this.setPageProxyState("invalid", true);
|
||||
// When focusing via mousedown, we don't want to cause a shift of the
|
||||
// string, thus we postpone to the mouseup event.
|
||||
if (this.focusedViaMousedown) {
|
||||
this.#setProxyStateToInvalidOnMouseUp = true;
|
||||
} else {
|
||||
this.setPageProxyState("invalid", true);
|
||||
}
|
||||
}
|
||||
|
||||
// If the value was trimmed, check whether we should untrim it.
|
||||
|
@ -3677,7 +3686,7 @@ export class UrlbarInput {
|
|||
try {
|
||||
let expectedURI = Services.io.newURI(this._untrimmedValue);
|
||||
if (
|
||||
lazy.UrlbarPrefs.get("trimHttps") &&
|
||||
lazy.UrlbarPrefs.getScotchBonnetPref("trimHttps") &&
|
||||
this._untrimmedValue.startsWith("https://")
|
||||
) {
|
||||
untrim =
|
||||
|
@ -3728,6 +3737,7 @@ export class UrlbarInput {
|
|||
_on_mousedown(event) {
|
||||
switch (event.currentTarget) {
|
||||
case this.textbox: {
|
||||
this.toggleAttribute("focusing-via-mousedown", !this.focused);
|
||||
this._mousedownOnUrlbarDescendant = true;
|
||||
|
||||
if (
|
||||
|
@ -3807,6 +3817,15 @@ export class UrlbarInput {
|
|||
}
|
||||
}
|
||||
|
||||
_on_mouseup() {
|
||||
this.toggleAttribute("focusing-via-mousedown", false);
|
||||
|
||||
if (this.#setProxyStateToInvalidOnMouseUp) {
|
||||
this.#setProxyStateToInvalidOnMouseUp = false;
|
||||
this.setPageProxyState("invalid", true);
|
||||
}
|
||||
}
|
||||
|
||||
_on_input(event) {
|
||||
if (
|
||||
this._autofillPlaceholder &&
|
||||
|
@ -4414,6 +4433,8 @@ export class UrlbarInput {
|
|||
this._isKeyDownWithMetaAndLeft)
|
||||
);
|
||||
}
|
||||
|
||||
#setProxyStateToInvalidOnMouseUp = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -189,11 +189,6 @@ const PREF_URLBAR_DEFAULTS = new Map([
|
|||
// for Pocket suggestions.
|
||||
["pocket.showLessFrequentlyCount", 0],
|
||||
|
||||
// The group-relative suggestedIndex of Pocket suggestions within the Firefox
|
||||
// Suggest section. This is a fallback pref for the `pocketSuggestIndex` Nimbus
|
||||
// variable.
|
||||
["pocket.suggestedIndex", 0],
|
||||
|
||||
// If disabled, QuickActions will not be included in either the default search
|
||||
// mode or the QuickActions search mode.
|
||||
["quickactions.enabled", true],
|
||||
|
@ -539,6 +534,7 @@ const NIMBUS_DEFAULTS = {
|
|||
experimentType: "",
|
||||
fakespotMinKeywordLength: 0,
|
||||
pocketShowLessFrequentlyCap: 0,
|
||||
pocketSuggestIndex: null,
|
||||
quickSuggestRemoteSettingsDataType: "data",
|
||||
quickSuggestScoreMap: null,
|
||||
recordNavigationalSuggestionTelemetry: false,
|
||||
|
|
|
@ -847,7 +847,7 @@ class ProviderAutofill extends UrlbarProvider {
|
|||
if (title) {
|
||||
payload.title = [title, UrlbarUtils.HIGHLIGHT.TYPED];
|
||||
} else {
|
||||
let trimHttps = lazy.UrlbarPrefs.get("trimHttps");
|
||||
let trimHttps = lazy.UrlbarPrefs.getScotchBonnetPref("trimHttps");
|
||||
let displaySpec = UrlbarUtils.prepareUrlForDisplay(finalCompleteValue, {
|
||||
trimURL: false,
|
||||
});
|
||||
|
|
|
@ -3075,10 +3075,7 @@ export class TaskQueue {
|
|||
* then a resolved promise is returned.
|
||||
*/
|
||||
get emptyPromise() {
|
||||
if (!this._queue.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise(resolve => this._emptyCallbacks.push(resolve));
|
||||
return this.#emptyPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3096,27 +3093,56 @@ export class TaskQueue {
|
|||
*/
|
||||
queue(callback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._queue.push({ callback, resolve, reject });
|
||||
if (this._queue.length == 1) {
|
||||
this._doNextTask();
|
||||
this.#queue.push({ callback, resolve, reject });
|
||||
if (this.#queue.length == 1) {
|
||||
this.#emptyDeferred = Promise.withResolvers();
|
||||
this.#emptyPromise = this.#emptyDeferred.promise;
|
||||
this.#doNextTask();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback function to the task queue that will be called on idle.
|
||||
*
|
||||
* @param {Function} callback
|
||||
* The function to queue.
|
||||
* @returns {Promise}
|
||||
* Resolved after the task queue calls and awaits `callback`. It will be
|
||||
* resolved with the value returned by `callback`. If `callback` throws an
|
||||
* error, then it will be rejected with the error.
|
||||
*/
|
||||
queueIdleCallback(callback) {
|
||||
return this.queue(async () => {
|
||||
await new Promise((resolve, reject) => {
|
||||
ChromeUtils.idleDispatch(async () => {
|
||||
try {
|
||||
let value = await callback();
|
||||
resolve(value);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the next function in the task queue and recurses until the queue is
|
||||
* empty. Once empty, all empty callback functions are called.
|
||||
*/
|
||||
async _doNextTask() {
|
||||
if (!this._queue.length) {
|
||||
while (this._emptyCallbacks.length) {
|
||||
let callback = this._emptyCallbacks.shift();
|
||||
callback();
|
||||
}
|
||||
async #doNextTask() {
|
||||
if (!this.#queue.length) {
|
||||
this.#emptyDeferred.resolve();
|
||||
this.#emptyDeferred = null;
|
||||
return;
|
||||
}
|
||||
|
||||
let { callback, resolve, reject } = this._queue[0];
|
||||
// Leave the callback in the queue while awaiting it. If we remove it now
|
||||
// the queue could become empty, and if `queue()` were called while we're
|
||||
// awaiting the callback, `#doNextTask()` would be re-entered.
|
||||
let { callback, resolve, reject } = this.#queue[0];
|
||||
try {
|
||||
let value = await callback();
|
||||
resolve(value);
|
||||
|
@ -3124,10 +3150,11 @@ export class TaskQueue {
|
|||
console.error(error);
|
||||
reject(error);
|
||||
}
|
||||
this._queue.shift();
|
||||
this._doNextTask();
|
||||
this.#queue.shift();
|
||||
this.#doNextTask();
|
||||
}
|
||||
|
||||
_queue = [];
|
||||
_emptyCallbacks = [];
|
||||
#queue = [];
|
||||
#emptyDeferred = null;
|
||||
#emptyPromise = Promise.resolve();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
|
||||
UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
|
||||
});
|
||||
|
@ -207,10 +208,24 @@ export class BaseFeature {
|
|||
|
||||
/**
|
||||
* Enables or disables the feature according to `shouldEnable` and whether
|
||||
* quick suggest is enabled. If the feature is already enabled appropriately,
|
||||
* does nothing.
|
||||
* quick suggest is enabled. If the feature's enabled status changes,
|
||||
* `enable()` is called with the new status; otherwise `enable()` is not
|
||||
* called. If the feature manages any Rust suggestion types that become
|
||||
* enabled as a result, they will be ingested.
|
||||
*/
|
||||
update() {
|
||||
// Collect the feature's Rust suggestion types that are currently enabled.
|
||||
// Features can manage multiple types. Some may be enabled while others are
|
||||
// disabled. As long as one is enabled, the feature itself will be enabled.
|
||||
let { rustBackend } = lazy.QuickSuggest;
|
||||
let oldEnabledRustSuggestionTypes =
|
||||
rustBackend.isEnabled && this.isEnabled
|
||||
? this.rustSuggestionTypes.filter(type =>
|
||||
this.isRustSuggestionTypeEnabled(type)
|
||||
)
|
||||
: [];
|
||||
|
||||
// Update the feature's enabled status.
|
||||
let enable =
|
||||
lazy.UrlbarPrefs.get("quickSuggestEnabled") && this.shouldEnable;
|
||||
if (enable != this.isEnabled) {
|
||||
|
@ -218,6 +233,20 @@ export class BaseFeature {
|
|||
this.enable(enable);
|
||||
this.#isEnabled = enable;
|
||||
}
|
||||
|
||||
// Ingest all the feature's Rust suggestion types that just became enabled.
|
||||
// This will be their initial ingests. After that, their ingests will occur
|
||||
// according to the ingest timer in the backend.
|
||||
if (rustBackend.isEnabled && enable) {
|
||||
for (let type of this.rustSuggestionTypes) {
|
||||
if (
|
||||
this.isRustSuggestionTypeEnabled(type) &&
|
||||
!oldEnabledRustSuggestionTypes.includes(type)
|
||||
) {
|
||||
rustBackend.ingestSuggestionType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#isEnabled = false;
|
||||
|
|
|
@ -192,9 +192,11 @@ export class PocketSuggestions extends BaseFeature {
|
|||
};
|
||||
|
||||
if (!suggestion.is_top_pick) {
|
||||
resultProperties.isSuggestedIndexRelativeToGroup = true;
|
||||
resultProperties.suggestedIndex =
|
||||
lazy.UrlbarPrefs.get("pocketSuggestIndex");
|
||||
let suggestedIndex = lazy.UrlbarPrefs.get("pocketSuggestIndex");
|
||||
if (suggestedIndex !== null) {
|
||||
resultProperties.isSuggestedIndexRelativeToGroup = true;
|
||||
resultProperties.suggestedIndex = suggestedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
|
|
|
@ -18,6 +18,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||
Suggestion: "resource://gre/modules/RustSuggest.sys.mjs",
|
||||
SuggestionProvider: "resource://gre/modules/RustSuggest.sys.mjs",
|
||||
SuggestionQuery: "resource://gre/modules/RustSuggest.sys.mjs",
|
||||
TaskQueue: "resource:///modules/UrlbarUtils.sys.mjs",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
|
||||
Utils: "resource://services-settings/Utils.sys.mjs",
|
||||
});
|
||||
|
@ -31,6 +32,8 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
|
||||
const SUGGEST_DATA_STORE_BASENAME = "suggest.sqlite";
|
||||
|
||||
const SPONSORED_SUGGESTION_TYPES = new Set(["Amp", "Fakespot", "Yelp"]);
|
||||
|
||||
// This ID is used to register our ingest timer with nsIUpdateTimerManager.
|
||||
const INGEST_TIMER_ID = "suggest-ingest";
|
||||
const INGEST_TIMER_LAST_UPDATE_PREF = `app.update.lastUpdateTime.${INGEST_TIMER_ID}`;
|
||||
|
@ -72,6 +75,15 @@ const gSuggestionTypesByCtor = new WeakMap();
|
|||
* [6] https://searchfox.org/mozilla-central/source/toolkit/components/uniffi-bindgen-gecko-js/config.toml
|
||||
*/
|
||||
export class SuggestBackendRust extends BaseFeature {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.#ingestQueue = new lazy.TaskQueue();
|
||||
this.#setRemoteSettingsConfig({
|
||||
serverUrl: lazy.Utils.SERVER_URL,
|
||||
bucketName: lazy.Utils.actualBucketName("main"),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {object}
|
||||
* The global Suggest config from the Rust component as returned from
|
||||
|
@ -83,11 +95,10 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
|
||||
/**
|
||||
* @returns {Promise}
|
||||
* If ingest is pending this will be resolved when it's done. Otherwise it
|
||||
* was resolved when the previous ingest finished.
|
||||
* Resolved when all pending ingests are done.
|
||||
*/
|
||||
get ingestPromise() {
|
||||
return this.#ingestPromise;
|
||||
return this.#ingestQueue.emptyPromise;
|
||||
}
|
||||
|
||||
get shouldEnable() {
|
||||
|
@ -103,14 +114,12 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
}
|
||||
|
||||
async query(searchString) {
|
||||
this.logger.info("Handling query: " + JSON.stringify(searchString));
|
||||
|
||||
if (!this.#store) {
|
||||
// There must have been an error creating `#store`.
|
||||
this.logger.info("#store is null, returning");
|
||||
return [];
|
||||
}
|
||||
|
||||
this.logger.debug("Handling query: " + JSON.stringify(searchString));
|
||||
|
||||
// Build the list of enabled Rust providers to query.
|
||||
let providers = this.#rustProviders.reduce(
|
||||
(memo, { type, feature, provider }) => {
|
||||
|
@ -137,7 +146,7 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
|
||||
suggestion.source = "rust";
|
||||
suggestion.provider = type;
|
||||
suggestion.is_sponsored = type == "Amp" || type == "Yelp";
|
||||
suggestion.is_sponsored = SPONSORED_SUGGESTION_TYPES.has(type);
|
||||
if (Array.isArray(suggestion.icon)) {
|
||||
suggestion.icon_blob = new Blob([new Uint8Array(suggestion.icon)], {
|
||||
type: suggestion.iconMimetype ?? "",
|
||||
|
@ -173,12 +182,66 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
return this.#configsBySuggestionType.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ingests the given suggestion type.
|
||||
*
|
||||
* @param {string} type
|
||||
* A Rust suggestion type name as defined in `suggest.udl`, e.g., "Amp",
|
||||
* "Wikipedia", "Mdn", etc. See also `BaseFeature.rustSuggestionTypes`.
|
||||
*/
|
||||
ingestSuggestionType(type) {
|
||||
this.#ingestQueue.queueIdleCallback(async () => {
|
||||
if (!this.#store) {
|
||||
return;
|
||||
}
|
||||
|
||||
let provider = this.#providerFromSuggestionType(type);
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
let timerId;
|
||||
this.logger.debug("Starting ingest: " + type);
|
||||
try {
|
||||
timerId = Glean.urlbar.quickSuggestIngestTime.start();
|
||||
await this.#store.ingest(
|
||||
new lazy.SuggestIngestionConstraints({
|
||||
providers: [provider],
|
||||
})
|
||||
);
|
||||
Glean.urlbar.quickSuggestIngestTime.stopAndAccumulate(timerId);
|
||||
} catch (error) {
|
||||
// Ingest can throw a `SuggestApiError` subclass called `Other` with a
|
||||
// `reason` message, which is very helpful for diagnosing problems with
|
||||
// remote settings data in tests in particular.
|
||||
this.logger.error(
|
||||
`Ingest error for ${type}: ` + (error.reason ?? error)
|
||||
);
|
||||
Glean.urlbar.quickSuggestIngestTime.cancel(timerId);
|
||||
}
|
||||
this.logger.debug("Finished ingest: " + type);
|
||||
|
||||
if (!this.#store) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the provider config.
|
||||
this.logger.debug("Fetching provider config: " + type);
|
||||
let config = await this.#store.fetchProviderConfig(provider);
|
||||
this.logger.debug(
|
||||
`Got provider config for ${type}: ` + JSON.stringify(config)
|
||||
);
|
||||
this.#configsBySuggestionType.set(type, config);
|
||||
this.logger.debug("Finished fetching provider config: " + type);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* nsITimerCallback
|
||||
*/
|
||||
notify() {
|
||||
this.logger.info("Ingest timer fired");
|
||||
this.#ingest();
|
||||
this.#ingestAll();
|
||||
}
|
||||
|
||||
get #storeDataPath() {
|
||||
|
@ -209,36 +272,19 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
let items = [];
|
||||
for (let [type, feature] of lazy.QuickSuggest
|
||||
.featuresByRustSuggestionType) {
|
||||
let key = type.toUpperCase();
|
||||
if (!lazy.SuggestionProvider.hasOwnProperty(key)) {
|
||||
this.logger.error(`SuggestionProvider["${key}"] is not defined!`);
|
||||
continue;
|
||||
let provider = this.#providerFromSuggestionType(type);
|
||||
if (provider) {
|
||||
items.push({ type, feature, provider });
|
||||
}
|
||||
items.push({ type, feature, provider: lazy.SuggestionProvider[key] });
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
async #init() {
|
||||
// Important note on schema updates:
|
||||
//
|
||||
// The first time the Suggest store is accessed after a schema version
|
||||
// update, its backing database will be deleted and a new empty database
|
||||
// will be created. The database will remain empty until we tell the store
|
||||
// to ingest. If we wait to ingest as usual until our ingest timer fires,
|
||||
// the store will remain empty for up to 24 hours, which means we won't
|
||||
// serve any suggestions at all during that time.
|
||||
//
|
||||
// Therefore we simply always ingest here in `#init()`. We'll sometimes
|
||||
// ingest unnecessarily but that's better than the alternative. (As a
|
||||
// reminder, for users who have Suggest enabled `#init()` is called whenever
|
||||
// the Rust backend is enabled, including on startup.)
|
||||
|
||||
#init() {
|
||||
// Initialize the store.
|
||||
this.logger.info(
|
||||
`Initializing SuggestStore with data path ${this.#storeDataPath}`
|
||||
);
|
||||
|
||||
let builder = lazy.SuggestStoreBuilder.init()
|
||||
.dataPath(this.#storeDataPath)
|
||||
.loadExtension(AppConstants.SQLITE_LIBRARY_FILENAME, "sqlite3_fts5_init")
|
||||
|
@ -285,8 +331,10 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
true // skipFirst
|
||||
);
|
||||
|
||||
// Ingest.
|
||||
await this.#ingest();
|
||||
// Do an initial ingest for all enabled suggestion types. When a type
|
||||
// becomes enabled after this point, its `BaseFeature` will update and call
|
||||
// `ingestSuggestionType()` for it, which will be its initial ingest.
|
||||
this.#ingestAll();
|
||||
}
|
||||
|
||||
#uninit() {
|
||||
|
@ -298,72 +346,50 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
this.#shutdownBlocker = null;
|
||||
}
|
||||
|
||||
async #ingest() {
|
||||
let instance = (this.#ingestInstance = {});
|
||||
await this.#ingestPromise;
|
||||
if (instance != this.#ingestInstance) {
|
||||
return;
|
||||
}
|
||||
this.#ingestPromise = new Promise(resolve => {
|
||||
ChromeUtils.idleDispatch(() => this.#ingestHelper().finally(resolve));
|
||||
});
|
||||
await this.#ingestPromise;
|
||||
}
|
||||
|
||||
async #ingestHelper() {
|
||||
if (!this.#store) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.info("Starting ingest and configs fetch");
|
||||
|
||||
// Do the ingest.
|
||||
let timerId;
|
||||
this.logger.debug("Starting ingest");
|
||||
try {
|
||||
timerId = Glean.urlbar.quickSuggestIngestTime.start();
|
||||
await this.#store.ingest(new lazy.SuggestIngestionConstraints());
|
||||
Glean.urlbar.quickSuggestIngestTime.stopAndAccumulate(timerId);
|
||||
} catch (error) {
|
||||
// Ingest can throw a `SuggestApiError` subclass called `Other` that has a
|
||||
// custom `reason` message, which is very helpful for diagnosing problems
|
||||
// with remote settings data in tests in particular.
|
||||
this.logger.error("Ingest error: " + (error.reason ?? error));
|
||||
Glean.urlbar.quickSuggestIngestTime.cancel(timerId);
|
||||
}
|
||||
this.logger.debug("Finished ingest");
|
||||
|
||||
if (!this.#store) {
|
||||
this.logger.info("#store became null, returning from ingest");
|
||||
return;
|
||||
#ingestAll() {
|
||||
// Ingest all enabled suggestion types.
|
||||
for (let { feature, type } of this.#rustProviders) {
|
||||
if (feature.isEnabled && feature.isRustSuggestionTypeEnabled(type)) {
|
||||
this.ingestSuggestionType(type);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the global config.
|
||||
this.logger.debug("Fetching global config");
|
||||
this.#config = await this.#store.fetchGlobalConfig();
|
||||
this.logger.debug("Got global config: " + JSON.stringify(this.#config));
|
||||
this.#ingestQueue.queueIdleCallback(async () => {
|
||||
if (!this.#store) {
|
||||
return;
|
||||
}
|
||||
this.logger.debug("Fetching global config");
|
||||
this.#config = await this.#store.fetchGlobalConfig();
|
||||
this.logger.debug("Got global config: " + JSON.stringify(this.#config));
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.#store) {
|
||||
this.logger.info("#store became null, returning from ingest");
|
||||
return;
|
||||
/**
|
||||
* Given a Rust suggestion type, gets the integer value defined on the
|
||||
* `SuggestionProvider` object in `RustSuggest.sys.mjs` that identifies the
|
||||
* corresponding provider to Rust.
|
||||
*
|
||||
* @param {string} type
|
||||
* A Rust suggestion type name as defined in `suggest.udl`, e.g., "Amp",
|
||||
* "Wikipedia", "Mdn", etc. See also `BaseFeature.rustSuggestionTypes`.
|
||||
* @returns {number}
|
||||
* An integer value defined on the `SuggestionProvider` object.
|
||||
*/
|
||||
#providerFromSuggestionType(type) {
|
||||
let key = type.toUpperCase();
|
||||
if (!lazy.SuggestionProvider.hasOwnProperty(key)) {
|
||||
this.logger.error(`SuggestionProvider["${key}"] is not defined!`);
|
||||
return null;
|
||||
}
|
||||
return lazy.SuggestionProvider[key];
|
||||
}
|
||||
|
||||
// Fetch all provider configs. We do this for all features, even ones that
|
||||
// are currently disabled, because they may become enabled before the next
|
||||
// ingest.
|
||||
this.logger.debug("Fetching provider configs");
|
||||
await Promise.all(
|
||||
this.#rustProviders.map(async ({ type, provider }) => {
|
||||
let config = await this.#store.fetchProviderConfig(provider);
|
||||
this.logger.debug(
|
||||
`Got '${type}' provider config: ` + JSON.stringify(config)
|
||||
);
|
||||
this.#configsBySuggestionType.set(type, config);
|
||||
})
|
||||
#setRemoteSettingsConfig({ serverUrl, bucketName }) {
|
||||
this.#remoteSettingsServer = new lazy.RemoteSettingsServer.Custom(
|
||||
serverUrl
|
||||
);
|
||||
this.logger.debug("Finished fetching provider configs");
|
||||
|
||||
this.logger.info("Finished ingest and configs fetch");
|
||||
this.#remoteSettingsBucketName = bucketName;
|
||||
}
|
||||
|
||||
get _test_store() {
|
||||
|
@ -371,21 +397,19 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
}
|
||||
|
||||
async _test_setRemoteSettingsConfig({ serverUrl, bucketName }) {
|
||||
this.#remoteSettingsServer = new lazy.RemoteSettingsServer.Custom(
|
||||
serverUrl
|
||||
);
|
||||
this.#remoteSettingsBucketName = bucketName;
|
||||
|
||||
this.#setRemoteSettingsConfig({ serverUrl, bucketName });
|
||||
if (this.isEnabled) {
|
||||
// Recreate the store and re-ingest.
|
||||
Services.prefs.clearUserPref(INGEST_TIMER_LAST_UPDATE_PREF);
|
||||
this.#uninit();
|
||||
await this.#init();
|
||||
this.#init();
|
||||
await this.ingestPromise;
|
||||
}
|
||||
}
|
||||
|
||||
async _test_ingest() {
|
||||
await this.#ingest();
|
||||
this.#ingestAll();
|
||||
await this.ingestPromise;
|
||||
}
|
||||
|
||||
// The `SuggestStore` instance.
|
||||
|
@ -398,13 +422,10 @@ export class SuggestBackendRust extends BaseFeature {
|
|||
// `SuggestStore.fetchProviderConfig()`.
|
||||
#configsBySuggestionType = new Map();
|
||||
|
||||
#ingestPromise;
|
||||
#ingestInstance;
|
||||
#ingestQueue;
|
||||
#shutdownBlocker;
|
||||
#remoteSettingsServer = new lazy.RemoteSettingsServer.Custom(
|
||||
lazy.Utils.SERVER_URL
|
||||
);
|
||||
#remoteSettingsBucketName = lazy.Utils.actualBucketName("main");
|
||||
#remoteSettingsServer;
|
||||
#remoteSettingsBucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -440,7 +461,7 @@ function getSuggestionType(suggestion) {
|
|||
if (type) {
|
||||
gSuggestionTypesByCtor.set(suggestion.constructor, type);
|
||||
} else {
|
||||
this.logger.error(
|
||||
console.error(
|
||||
"Unexpected error: Suggestion class not found on `Suggestion`. " +
|
||||
"Did the Rust component or its JS bindings change? " +
|
||||
"The suggestion is: " +
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
AddonTestUtils: "resource://testing-common/AddonTestUtils.sys.mjs",
|
||||
BrowserTestUtils: "resource://testing-common/BrowserTestUtils.sys.mjs",
|
||||
BrowserUIUtils: "resource:///modules/BrowserUIUtils.sys.mjs",
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
|
||||
|
@ -1069,7 +1068,7 @@ export var UrlbarTestUtils = {
|
|||
}
|
||||
|
||||
// Also remove emphasis markers if present.
|
||||
if (lazy.UrlbarPrefs.get("trimHttps")) {
|
||||
if (lazy.UrlbarPrefs.getScotchBonnetPref("trimHttps")) {
|
||||
sanitizedURL = sanitizedURL.replace(/^<?https:\/\/>?/, "");
|
||||
} else {
|
||||
sanitizedURL = sanitizedURL.replace(/^<?http:\/\/>?/, "");
|
||||
|
@ -1086,7 +1085,7 @@ export var UrlbarTestUtils = {
|
|||
*/
|
||||
getTrimmedProtocolWithSlashes() {
|
||||
if (Services.prefs.getBoolPref("browser.urlbar.trimURLs")) {
|
||||
return Services.prefs.getBoolPref("browser.urlbar.trimHttps")
|
||||
return lazy.UrlbarPrefs.getScotchBonnetPref("trimHttps")
|
||||
? "https://"
|
||||
: "http://"; // eslint-disable-this-line @microsoft/sdl/no-insecure-url
|
||||
}
|
||||
|
@ -1241,16 +1240,6 @@ export var UrlbarTestUtils = {
|
|||
Cc["@mozilla.org/satchel/form-history-startup;1"]
|
||||
.getService(Ci.nsIObserver)
|
||||
.observe(null, "profile-after-change", null);
|
||||
|
||||
// This is necessary because UrlbarMuxerUnifiedComplete.sort calls
|
||||
// Services.search.parseSubmissionURL, so we need engines.
|
||||
try {
|
||||
await lazy.AddonTestUtils.promiseStartupManager();
|
||||
} catch (error) {
|
||||
if (!error.message.includes("already started")) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -599,6 +599,8 @@ support-files = ["moz.png"]
|
|||
|
||||
["browser_tabToSearch.js"]
|
||||
|
||||
["browser_text_dont_shift_on_mousedown.js"]
|
||||
|
||||
["browser_textruns.js"]
|
||||
|
||||
["browser_tokenAlias.js"]
|
||||
|
|
|
@ -51,7 +51,10 @@ async function checkSearchString(searchString, isIpv6) {
|
|||
// decodeURI is necessary for matching square brackets in IPV6.
|
||||
let expectedUrl = isIpv6 ? decodeURI(searchUrl) : searchUrl;
|
||||
|
||||
if (UrlbarPrefs.get("trimHttps") && expectedUrl.startsWith("https://")) {
|
||||
if (
|
||||
UrlbarPrefs.getScotchBonnetPref("trimHttps") &&
|
||||
expectedUrl.startsWith("https://")
|
||||
) {
|
||||
expectedUrl = expectedUrl.slice("https://".length);
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,9 @@ const tests = [
|
|||
get selection() {
|
||||
// When untrimming is enabled, the behavior differs depending on whether
|
||||
// the selected text can generate a valid URL, so there may be an offset.
|
||||
let startOffset = UrlbarPrefs.get("untrimOnUserInteraction.featureGate")
|
||||
let startOffset = UrlbarPrefs.getScotchBonnetPref(
|
||||
"untrimOnUserInteraction.featureGate"
|
||||
)
|
||||
? gURLBar.value.indexOf(this._expectedSelectedText)
|
||||
: 0;
|
||||
return [startOffset, startOffset + this._expectedSelectedText.length];
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that focusing the urlbar with mousedown doesn't shift the text until
|
||||
* mouseup, as that may cause unexpected text selections.
|
||||
*/
|
||||
|
||||
var gDefaultEngine;
|
||||
|
||||
add_setup(async function () {
|
||||
await SearchTestUtils.installSearchExtension(
|
||||
{
|
||||
name: "MozSearch",
|
||||
search_url: "https://www.example.com/",
|
||||
search_url_get_params: "q={searchTerms}&pc=fake_code",
|
||||
},
|
||||
{ setAsDefault: true }
|
||||
);
|
||||
gDefaultEngine = Services.search.getEngineByName("MozSearch");
|
||||
|
||||
registerCleanupFunction(async function () {
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_loaded_page() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com/", async () => {
|
||||
let originalX = gURLBar.inputField.getBoundingClientRect().x;
|
||||
let finalX = getElementXBetweenMouseDownAndUp(gURLBar.inputField);
|
||||
Assert.equal(originalX, finalX, "The input field didn't move");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_invalid_proxystate() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com/", async () => {
|
||||
gURLBar.value = "modifiedText";
|
||||
let originalX = gURLBar.inputField.getBoundingClientRect().x;
|
||||
let finalX = getElementXBetweenMouseDownAndUp(gURLBar.inputField);
|
||||
Assert.equal(originalX, finalX, "The input field didn't move");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_persistedSearchTerms() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.urlbar.showSearchTerms.featureGate", true]],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab("https://example.com/", async browser => {
|
||||
const searchTerms = "pizza";
|
||||
let [expectedSearchUrl] = UrlbarUtils.getSearchQueryUrl(
|
||||
gDefaultEngine,
|
||||
searchTerms
|
||||
);
|
||||
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
|
||||
browser,
|
||||
false,
|
||||
expectedSearchUrl
|
||||
);
|
||||
gURLBar.focus();
|
||||
gURLBar.value = searchTerms;
|
||||
EventUtils.synthesizeKey("KEY_Enter");
|
||||
await browserLoadedPromise;
|
||||
Assert.equal(gURLBar.value, searchTerms, "Search was persisted");
|
||||
Assert.ok(!gURLBar.focused, "Urlbar is not focused");
|
||||
|
||||
let originalX = gURLBar.inputField.getBoundingClientRect().x;
|
||||
let finalX = getElementXBetweenMouseDownAndUp(gURLBar.inputField);
|
||||
Assert.equal(originalX, finalX, "The input field didn't move");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_dedicatedSearchButton() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.urlbar.scotchBonnet.enableOverride", true]],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab("https://example.com/", async () => {
|
||||
let originalX = gURLBar.inputField.getBoundingClientRect().x;
|
||||
let finalX = getElementXBetweenMouseDownAndUp(gURLBar.inputField);
|
||||
Assert.equal(originalX, finalX, "The input field didn't move");
|
||||
});
|
||||
});
|
||||
|
||||
function getElementXBetweenMouseDownAndUp(element) {
|
||||
EventUtils.synthesizeMouse(
|
||||
gURLBar.inputField,
|
||||
10,
|
||||
10,
|
||||
{ type: "mousedown" },
|
||||
element.getOwnerGlobal
|
||||
);
|
||||
try {
|
||||
return element.getBoundingClientRect().x;
|
||||
} finally {
|
||||
EventUtils.synthesizeMouse(
|
||||
gURLBar.inputField,
|
||||
10,
|
||||
10,
|
||||
{ type: "mouseup" },
|
||||
element.getOwnerGlobal
|
||||
);
|
||||
}
|
||||
}
|
|
@ -149,9 +149,12 @@ class _QuickSuggestTestUtils {
|
|||
* Options object
|
||||
* @param {Array} options.remoteSettingsRecords
|
||||
* Array of remote settings records. Each item in this array should be a
|
||||
* realistic remote settings record with some exceptions, e.g.,
|
||||
* `record.attachment`, if defined, should be the attachment itself and not
|
||||
* its metadata. For details see `RemoteSettingsServer.addRecords()`.
|
||||
* realistic remote settings record with some exceptions as noted below.
|
||||
* For details see `RemoteSettingsServer.addRecords()`.
|
||||
* - `record.attachment` - Optional. This should be the attachment itself
|
||||
* and not its metadata. It should be a JSONable object.
|
||||
* - `record.collection` - Optional. The name of the RS collection that
|
||||
* the record should be added to. Defaults to "quicksuggest".
|
||||
* @param {Array} options.merinoSuggestions
|
||||
* Array of Merino suggestion objects. If given, this function will start
|
||||
* the mock Merino server and set `quicksuggest.dataCollection.enabled` to
|
||||
|
@ -186,6 +189,19 @@ class _QuickSuggestTestUtils {
|
|||
} = {}) {
|
||||
prefs.push(["quicksuggest.enabled", true]);
|
||||
|
||||
// Make a Map from collection name to the array of records that should be
|
||||
// added to that collection.
|
||||
let recordsByCollection = remoteSettingsRecords.reduce((memo, record) => {
|
||||
let collection = record.collection || "quicksuggest";
|
||||
let records = memo.get(collection);
|
||||
if (!records) {
|
||||
records = [];
|
||||
memo.set(collection, records);
|
||||
}
|
||||
records.push(record);
|
||||
return memo;
|
||||
}, new Map());
|
||||
|
||||
// Set up the local remote settings server.
|
||||
this.#log(
|
||||
"ensureQuickSuggestInit",
|
||||
|
@ -194,13 +210,16 @@ class _QuickSuggestTestUtils {
|
|||
if (!this.#remoteSettingsServer) {
|
||||
this.#remoteSettingsServer = new lazy.RemoteSettingsServer();
|
||||
}
|
||||
await this.#remoteSettingsServer.setRecords({
|
||||
|
||||
this.#remoteSettingsServer.removeRecords();
|
||||
for (let [collection, records] of recordsByCollection.entries()) {
|
||||
await this.#remoteSettingsServer.addRecords({ collection, records });
|
||||
}
|
||||
await this.#remoteSettingsServer.addRecords({
|
||||
collection: "quicksuggest",
|
||||
records: [
|
||||
...remoteSettingsRecords,
|
||||
{ type: "configuration", configuration: config },
|
||||
],
|
||||
records: [{ type: "configuration", configuration: config }],
|
||||
});
|
||||
|
||||
this.#log("ensureQuickSuggestInit", "Starting remote settings server");
|
||||
await this.#remoteSettingsServer.start();
|
||||
this.#log("ensureQuickSuggestInit", "Remote settings server started");
|
||||
|
|
|
@ -23,11 +23,11 @@ export class RemoteSettingsServer {
|
|||
*
|
||||
* @param {object} options
|
||||
* @param {number} options.maxLogLevel
|
||||
* A log level value as defined by ConsoleInstance. `Info` logs basic info
|
||||
* on requests and responses like paths and status codes. Pass `Debug` to
|
||||
* log more info like headers, response bodies, added and removed records.
|
||||
* A log level value as defined by ConsoleInstance. `Info` logs server start
|
||||
* and stop. `Debug` logs requests, responses, and added and removed
|
||||
* records.
|
||||
*/
|
||||
constructor({ maxLogLevel = "Error" } = {}) {
|
||||
constructor({ maxLogLevel = "Info" } = {}) {
|
||||
this.#log = console.createInstance({
|
||||
prefix: "RemoteSettingsServer",
|
||||
maxLogLevel,
|
||||
|
@ -116,10 +116,7 @@ export class RemoteSettingsServer {
|
|||
* JSON'able objects that the server will convert to JSON in responses.
|
||||
*/
|
||||
async addRecords({ bucket = "main", collection = "test", records }) {
|
||||
this.#log.debug(
|
||||
"Adding records: " +
|
||||
JSON.stringify({ bucket, collection, records }, null, 2)
|
||||
);
|
||||
this.#log.debug("Adding records:", { bucket, collection, records });
|
||||
|
||||
this.#lastModified++;
|
||||
|
||||
|
@ -144,10 +141,9 @@ export class RemoteSettingsServer {
|
|||
allRecords.push(copy);
|
||||
}
|
||||
|
||||
this.#log.debug(
|
||||
"Done adding records. All records are now: " +
|
||||
JSON.stringify([...this.#records.entries()], null, 2)
|
||||
);
|
||||
this.#log.debug("Done adding records. All records are now:", [
|
||||
...this.#records.entries(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +166,7 @@ export class RemoteSettingsServer {
|
|||
* `{ type: "data", last_modified: 1234 }
|
||||
*/
|
||||
removeRecords(filter = null) {
|
||||
this.#log.debug("Removing records: " + JSON.stringify({ filter }));
|
||||
this.#log.debug("Removing records", { filter });
|
||||
|
||||
this.#lastModified++;
|
||||
|
||||
|
@ -194,10 +190,9 @@ export class RemoteSettingsServer {
|
|||
}
|
||||
}
|
||||
|
||||
this.#log.debug(
|
||||
"Done removing records. All records are now: " +
|
||||
JSON.stringify([...this.#records.entries()], null, 2)
|
||||
);
|
||||
this.#log.debug("Done removing records. All records are now:", [
|
||||
...this.#records.entries(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -311,8 +306,8 @@ export class RemoteSettingsServer {
|
|||
|
||||
{
|
||||
spec: "/v1/buckets/$bucket/collections/$collection/changeset",
|
||||
response: ({ bucket, collection }) => {
|
||||
let records = this.#getRecords(bucket, collection);
|
||||
response: ({ bucket, collection }, request) => {
|
||||
let records = this.#getRecords(bucket, collection, request);
|
||||
return !records
|
||||
? lazy.HTTP_404
|
||||
: {
|
||||
|
@ -327,8 +322,8 @@ export class RemoteSettingsServer {
|
|||
|
||||
{
|
||||
spec: "/v1/buckets/$bucket/collections/$collection/records",
|
||||
response: ({ bucket, collection }) => {
|
||||
let records = this.#getRecords(bucket, collection);
|
||||
response: ({ bucket, collection }, request) => {
|
||||
let records = this.#getRecords(bucket, collection, request);
|
||||
return !records
|
||||
? lazy.HTTP_404
|
||||
: {
|
||||
|
@ -444,8 +439,36 @@ export class RemoteSettingsServer {
|
|||
return match;
|
||||
}
|
||||
|
||||
#getRecords(bucket, collection) {
|
||||
return this.#records.get(this.#recordsKey(bucket, collection));
|
||||
#getRecords(bucket, collection, request) {
|
||||
let records = this.#records.get(this.#recordsKey(bucket, collection));
|
||||
let params = new URLSearchParams(request.queryString);
|
||||
|
||||
let type = params.get("type");
|
||||
if (type) {
|
||||
records = records.filter(r => r.type == type);
|
||||
}
|
||||
|
||||
let gtLastModified = params.get("gt_last_modified");
|
||||
if (gtLastModified) {
|
||||
records = records.filter(r => r.last_modified > gtLastModified);
|
||||
}
|
||||
|
||||
let since = params.get("_since");
|
||||
if (since) {
|
||||
// Example value: "%221368273600004%22"
|
||||
let match = /^"([0-9]+)"$/.exec(decodeURIComponent(since));
|
||||
if (match) {
|
||||
since = parseInt(match[1]);
|
||||
records = records.filter(r => r.last_modified > since);
|
||||
}
|
||||
}
|
||||
|
||||
let sort = params.get("_sort");
|
||||
if (sort == "last_modified") {
|
||||
records = records.toSorted((a, b) => a.last_modified - b.last_modified);
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
#recordsKey(bucket, collection) {
|
||||
|
@ -563,12 +586,9 @@ export class RemoteSettingsServer {
|
|||
if (request.queryString) {
|
||||
pathAndQuery += "?" + request.queryString;
|
||||
}
|
||||
this.#log.info(
|
||||
this.#log.debug(
|
||||
`< HTTP ${request.httpVersion} ${request.method} ${pathAndQuery}`
|
||||
);
|
||||
for (let name of request.headers) {
|
||||
this.#log.debug(`${name}: ${request.getHeader(name.toString())}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -579,18 +599,15 @@ export class RemoteSettingsServer {
|
|||
* The associated request.
|
||||
* @param {integer} options.status
|
||||
* The HTTP status code of the response.
|
||||
* @param {object} options.headers
|
||||
* @param {object} options._headers
|
||||
* An object mapping from response header names to values.
|
||||
* @param {object} options.body
|
||||
* The response body, if any.
|
||||
*/
|
||||
#logResponse({ request, status, headers, body }) {
|
||||
this.#log.info(`> ${status} ${request.path}`);
|
||||
for (let [name, value] of Object.entries(headers)) {
|
||||
this.#log.debug(`${name}: ${value}`);
|
||||
}
|
||||
#logResponse({ request, status, _headers, body }) {
|
||||
this.#log.debug(`> ${status} ${request.path}`);
|
||||
if (body) {
|
||||
this.#log.debug("Response body: " + JSON.stringify(body, null, 2));
|
||||
this.#log.debug("Response body:", body);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,59 +24,6 @@ add_setup(async function () {
|
|||
await QuickSuggestTestUtils.ensureQuickSuggestInit();
|
||||
});
|
||||
|
||||
// Makes sure `QuickSuggest._updateFeatureState()` is called when the
|
||||
// `browser.urlbar.quicksuggest.enabled` pref is changed.
|
||||
add_task(async function test_updateFeatureState_pref() {
|
||||
Assert.ok(
|
||||
UrlbarPrefs.get("quicksuggest.enabled"),
|
||||
"Sanity check: quicksuggest.enabled is true by default"
|
||||
);
|
||||
|
||||
let sandbox = sinon.createSandbox();
|
||||
let spy = sandbox.spy(QuickSuggest, "_updateFeatureState");
|
||||
|
||||
UrlbarPrefs.set("quicksuggest.enabled", false);
|
||||
Assert.equal(
|
||||
spy.callCount,
|
||||
1,
|
||||
"_updateFeatureState called once after changing pref"
|
||||
);
|
||||
|
||||
UrlbarPrefs.clear("quicksuggest.enabled");
|
||||
Assert.equal(
|
||||
spy.callCount,
|
||||
2,
|
||||
"_updateFeatureState called again after clearing pref"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
// Makes sure `QuickSuggest._updateFeatureState()` is called when a Nimbus
|
||||
// experiment is installed and uninstalled.
|
||||
add_task(async function test_updateFeatureState_experiment() {
|
||||
let sandbox = sinon.createSandbox();
|
||||
let spy = sandbox.spy(QuickSuggest, "_updateFeatureState");
|
||||
|
||||
await QuickSuggestTestUtils.withExperiment({
|
||||
callback: () => {
|
||||
Assert.equal(
|
||||
spy.callCount,
|
||||
1,
|
||||
"_updateFeatureState called once after installing experiment"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Assert.equal(
|
||||
spy.callCount,
|
||||
2,
|
||||
"_updateFeatureState called again after uninstalling experiment"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_indexes() {
|
||||
await QuickSuggestTestUtils.withExperiment({
|
||||
valueOverrides: {
|
||||
|
|
|
@ -5,74 +5,66 @@
|
|||
|
||||
// Test for Fakespot suggestions.
|
||||
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs",
|
||||
sinon: "resource://testing-common/Sinon.sys.mjs",
|
||||
});
|
||||
|
||||
// TODO: Replace with proper remote settings data once the Fakespot Rust feature
|
||||
// is vendored in to mozilla-central.
|
||||
const DUMMY_RESULT = [
|
||||
const REMOTE_SETTINGS_RECORDS = [
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/maybe-good-item",
|
||||
title: "Maybe Good Item",
|
||||
rating: 4.8,
|
||||
totalReviews: 1234567,
|
||||
fakespotGrade: "A",
|
||||
productId: "amazon-0",
|
||||
},
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/1-review-item",
|
||||
title: "1 review item",
|
||||
rating: 5,
|
||||
totalReviews: 1,
|
||||
fakespotGrade: "A",
|
||||
productId: "amazon-1",
|
||||
},
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/2-reviews-item",
|
||||
title: "2 reviews item",
|
||||
rating: 4,
|
||||
totalReviews: 2,
|
||||
fakespotGrade: "A",
|
||||
productId: "amazon-2",
|
||||
},
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/1000-reviews-item",
|
||||
title: "1000 reviews item",
|
||||
rating: 3,
|
||||
totalReviews: 1000,
|
||||
fakespotGrade: "A",
|
||||
productId: "amazon-3",
|
||||
},
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/99999-reviews-item",
|
||||
title: "99999 reviews item",
|
||||
rating: 2,
|
||||
totalReviews: 99999,
|
||||
fakespotGrade: "A",
|
||||
productId: "amazon-4",
|
||||
},
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/100000-reviews-item",
|
||||
title: "100000 reviews item",
|
||||
rating: 1,
|
||||
totalReviews: 100000,
|
||||
fakespotGrade: "A",
|
||||
productId: "amazon-5",
|
||||
collection: "fakespot-suggest-products",
|
||||
type: "fakespot-suggestions",
|
||||
attachment: [
|
||||
{
|
||||
url: "https://example.com/maybe-good-item",
|
||||
title: "Maybe Good Item",
|
||||
rating: 4.8,
|
||||
total_reviews: 1234567,
|
||||
fakespot_grade: "A",
|
||||
product_id: "amazon-0",
|
||||
score: 0.01,
|
||||
},
|
||||
{
|
||||
url: "https://example.com/1-review-item",
|
||||
title: "1 review item",
|
||||
rating: 5,
|
||||
total_reviews: 1,
|
||||
fakespot_grade: "A",
|
||||
product_id: "amazon-1",
|
||||
score: 0.1,
|
||||
},
|
||||
{
|
||||
url: "https://example.com/2-reviews-item",
|
||||
title: "2 reviews item",
|
||||
rating: 4,
|
||||
total_reviews: 2,
|
||||
fakespot_grade: "A",
|
||||
product_id: "amazon-2",
|
||||
score: 0.2,
|
||||
},
|
||||
{
|
||||
url: "https://example.com/1000-reviews-item",
|
||||
title: "1000 reviews item",
|
||||
rating: 3,
|
||||
total_reviews: 1000,
|
||||
fakespot_grade: "A",
|
||||
product_id: "amazon-3",
|
||||
score: 0.3,
|
||||
},
|
||||
{
|
||||
url: "https://example.com/99999-reviews-item",
|
||||
title: "99999 reviews item",
|
||||
rating: 2,
|
||||
total_reviews: 99999,
|
||||
fakespot_grade: "A",
|
||||
product_id: "amazon-4",
|
||||
score: 0.4,
|
||||
},
|
||||
{
|
||||
url: "https://example.com/100000-reviews-item",
|
||||
title: "100000 reviews item",
|
||||
rating: 1,
|
||||
total_reviews: 100000,
|
||||
fakespot_grade: "A",
|
||||
product_id: "amazon-5",
|
||||
score: 0.5,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -81,28 +73,21 @@ const HELP_URL =
|
|||
"awesome-bar-result-menu";
|
||||
|
||||
add_setup(async function () {
|
||||
const sandbox = lazy.sinon.createSandbox();
|
||||
sandbox
|
||||
.stub(lazy.QuickSuggest.rustBackend, "query")
|
||||
.callsFake(async searchString =>
|
||||
DUMMY_RESULT.filter(r =>
|
||||
r.title.toLowerCase().startsWith(searchString.toLowerCase())
|
||||
)
|
||||
);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.urlbar.quicksuggest.enabled", true],
|
||||
["browser.urlbar.quicksuggest.rustEnabled", true],
|
||||
["browser.urlbar.suggest.quicksuggest.sponsored", true],
|
||||
["browser.urlbar.fakespot.featureGate", true],
|
||||
["browser.urlbar.suggest.fakespot", true],
|
||||
set: [["browser.search.suggest.enabled", false]],
|
||||
});
|
||||
|
||||
await QuickSuggestTestUtils.ensureQuickSuggestInit({
|
||||
remoteSettingsRecords: REMOTE_SETTINGS_RECORDS,
|
||||
prefs: [
|
||||
["suggest.quicksuggest.sponsored", true],
|
||||
["suggest.fakespot", true],
|
||||
["fakespot.featureGate", true],
|
||||
],
|
||||
});
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
await PlacesUtils.history.clear();
|
||||
sandbox.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@ const REMOTE_SETTINGS_RECORDS = [
|
|||
},
|
||||
];
|
||||
|
||||
// This stupid test can time out in verify mode on Treeherder Mac machines.
|
||||
requestLongerTimeout(5);
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.search.suggest.enabled", false]],
|
||||
|
@ -49,9 +46,17 @@ add_task(async function successfulIngest() {
|
|||
"number",
|
||||
"newValue.count should be a number"
|
||||
);
|
||||
|
||||
let enabledCount = 0;
|
||||
for (let [type, feature] of QuickSuggest.featuresByRustSuggestionType) {
|
||||
if (feature.isEnabled && feature.isRustSuggestionTypeEnabled(type)) {
|
||||
enabledCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.equal(
|
||||
newValue.count,
|
||||
oldValue.count + 1,
|
||||
"One new value should have been recorded after ingest"
|
||||
oldValue.count + enabledCount,
|
||||
"One new value per enabled suggestion type should have been recorded after ingest"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,9 +8,18 @@
|
|||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
|
||||
AddonTestUtils: "resource://testing-common/AddonTestUtils.sys.mjs",
|
||||
ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.sys.mjs",
|
||||
});
|
||||
|
||||
AddonTestUtils.init(this, false);
|
||||
AddonTestUtils.createAppInfo(
|
||||
"xpcshell@tests.mozilla.org",
|
||||
"XPCShell",
|
||||
"42",
|
||||
"42"
|
||||
);
|
||||
|
||||
// TODO: Firefox no longer uses `rating` and `number_of_ratings` but they are
|
||||
// still present in Merino and RS suggestions, so they are included here for
|
||||
// greater accuracy. We should remove them from Merino, RS, and tests.
|
||||
|
@ -85,6 +94,8 @@ const REMOTE_SETTINGS_RESULTS = [
|
|||
];
|
||||
|
||||
add_setup(async function init() {
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
|
||||
// Disable search suggestions so we don't hit the network.
|
||||
Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
|
||||
|
||||
|
|
|
@ -6,55 +6,117 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
// TODO: Replace with proper remote settings data once the Fakespot Rust feature
|
||||
// is vendored in to mozilla-central.
|
||||
const DUMMY_SUGGESTIONS = [
|
||||
const REMOTE_SETTINGS_RECORDS = [
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/fakespot-0",
|
||||
title: "Example Fakespot suggestion",
|
||||
rating: 4.6,
|
||||
fakespotGrade: "A",
|
||||
totalReviews: 167,
|
||||
productId: "amazon-0",
|
||||
score: 0.68416834,
|
||||
is_sponsored: true,
|
||||
},
|
||||
{
|
||||
source: "rust",
|
||||
provider: "Fakespot",
|
||||
url: "https://example.com/fakespot-1",
|
||||
title: "Another Fakespot suggestion",
|
||||
rating: 3.5,
|
||||
fakespotGrade: "B",
|
||||
totalReviews: 100,
|
||||
productId: "amazon-1",
|
||||
score: 0.5,
|
||||
is_sponsored: true,
|
||||
collection: "fakespot-suggest-products",
|
||||
type: "fakespot-suggestions",
|
||||
attachment: [
|
||||
{
|
||||
url: "https://example.com/fakespot-0",
|
||||
title: "Example Fakespot suggestion",
|
||||
rating: 4.6,
|
||||
fakespot_grade: "A",
|
||||
total_reviews: 167,
|
||||
product_id: "amazon-0",
|
||||
score: 0.68416834,
|
||||
},
|
||||
{
|
||||
url: "https://example.com/fakespot-1",
|
||||
title: "Another Fakespot suggestion",
|
||||
rating: 3.5,
|
||||
fakespot_grade: "B",
|
||||
total_reviews: 100,
|
||||
product_id: "amazon-1",
|
||||
score: 0.5,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const PRIMARY_SEARCH_STRING = "example";
|
||||
const PRIMARY_TITLE = DUMMY_SUGGESTIONS[0].title;
|
||||
const PRIMARY_URL = DUMMY_SUGGESTIONS[0].url;
|
||||
const PRIMARY_TITLE = REMOTE_SETTINGS_RECORDS[0].attachment[0].title;
|
||||
const PRIMARY_URL = REMOTE_SETTINGS_RECORDS[0].attachment[0].url;
|
||||
|
||||
add_setup(async function () {
|
||||
Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
|
||||
|
||||
await QuickSuggestTestUtils.ensureQuickSuggestInit({
|
||||
remoteSettingsRecords: [],
|
||||
remoteSettingsRecords: REMOTE_SETTINGS_RECORDS,
|
||||
prefs: [
|
||||
["suggest.quicksuggest.sponsored", true],
|
||||
["suggest.fakespot", true],
|
||||
["fakespot.featureGate", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
let sandbox = sinon.createSandbox();
|
||||
sandbox
|
||||
.stub(QuickSuggest.rustBackend, "query")
|
||||
.callsFake(async () => DUMMY_SUGGESTIONS);
|
||||
add_task(async function basic() {
|
||||
const TEST_DATA = [
|
||||
{
|
||||
description: "Basic",
|
||||
query: "example fakespot suggestion",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "With upper case",
|
||||
query: "ExAmPlE fAKeSpOt SuGgEsTiOn",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Prefix match 1",
|
||||
query: "ex",
|
||||
expected: null,
|
||||
},
|
||||
{
|
||||
description: "Prefix match 2",
|
||||
query: "examp",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "First full word",
|
||||
query: "example",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "First full word + prefix",
|
||||
query: "example f",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let { description, query, expected } of TEST_DATA) {
|
||||
info(
|
||||
"Doing basic subtest: " +
|
||||
JSON.stringify({
|
||||
description,
|
||||
query,
|
||||
expected,
|
||||
})
|
||||
);
|
||||
|
||||
await check_results({
|
||||
context: createContext(query, {
|
||||
providers: [UrlbarProviderQuickSuggest.name],
|
||||
isPrivate: false,
|
||||
}),
|
||||
matches: expected ? [makeExpectedResult(expected)] : [],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function telemetryType() {
|
||||
|
@ -255,11 +317,11 @@ add_task(async function notRelevant() {
|
|||
}),
|
||||
matches: [
|
||||
makeExpectedResult({
|
||||
url: DUMMY_SUGGESTIONS[1].url,
|
||||
title: DUMMY_SUGGESTIONS[1].title,
|
||||
rating: DUMMY_SUGGESTIONS[1].rating,
|
||||
totalReviews: DUMMY_SUGGESTIONS[1].totalReviews,
|
||||
fakespotGrade: DUMMY_SUGGESTIONS[1].fakespotGrade,
|
||||
url: REMOTE_SETTINGS_RECORDS[0].attachment[1].url,
|
||||
title: REMOTE_SETTINGS_RECORDS[0].attachment[1].title,
|
||||
rating: REMOTE_SETTINGS_RECORDS[0].attachment[1].rating,
|
||||
totalReviews: REMOTE_SETTINGS_RECORDS[0].attachment[1].total_reviews,
|
||||
fakespotGrade: REMOTE_SETTINGS_RECORDS[0].attachment[1].fakespot_grade,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
@ -442,6 +504,31 @@ add_task(async function showLessFrequently() {
|
|||
UrlbarPrefs.clear("fakespot.minKeywordLength");
|
||||
});
|
||||
|
||||
// The `Fakespot` Rust provider should be passed to the Rust component when
|
||||
// querying depending on whether Fakespot suggestions are enabled.
|
||||
add_task(async function rustProviders() {
|
||||
await doRustProvidersTests({
|
||||
searchString: PRIMARY_SEARCH_STRING,
|
||||
tests: [
|
||||
{
|
||||
prefs: {
|
||||
"suggest.fakespot": true,
|
||||
},
|
||||
expectedUrls: [PRIMARY_URL],
|
||||
},
|
||||
{
|
||||
prefs: {
|
||||
"suggest.fakespot": false,
|
||||
},
|
||||
expectedUrls: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
UrlbarPrefs.clear("suggest.fakespot");
|
||||
await QuickSuggestTestUtils.forceSync();
|
||||
});
|
||||
|
||||
add_task(async function minKeywordLength_noPrefValue() {
|
||||
await doMinKeywordLengthTest({
|
||||
// expected min length: 5 (Nimbus value)
|
||||
|
@ -601,26 +688,20 @@ add_task(async function minKeywordLength_onlyPrefValue() {
|
|||
});
|
||||
|
||||
// When no min length is defined in Nimbus or the pref, we should fall back to
|
||||
// the hardcoded value of 2.
|
||||
// the natural threshold in the Rust component of 4.
|
||||
add_task(async function minKeywordLength_noNimbusOrPrefValue() {
|
||||
await doMinKeywordLengthTest({
|
||||
// expected min length: 2 (hardcoded)
|
||||
// expected min length: 4 (in Rust component)
|
||||
prefValue: null,
|
||||
nimbusValue: null,
|
||||
tests: [
|
||||
{
|
||||
query: "ex",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
expected: null,
|
||||
},
|
||||
{
|
||||
query: "exa",
|
||||
expected: {
|
||||
url: PRIMARY_URL,
|
||||
title: PRIMARY_TITLE,
|
||||
},
|
||||
expected: null,
|
||||
},
|
||||
{
|
||||
query: "exam",
|
||||
|
@ -689,9 +770,9 @@ function makeExpectedResult({
|
|||
originalUrl = undefined,
|
||||
displayUrl = undefined,
|
||||
telemetryType = "fakespot_amazon",
|
||||
rating = DUMMY_SUGGESTIONS[0].rating,
|
||||
totalReviews = DUMMY_SUGGESTIONS[0].totalReviews,
|
||||
fakespotGrade = DUMMY_SUGGESTIONS[0].fakespotGrade,
|
||||
rating = REMOTE_SETTINGS_RECORDS[0].attachment[0].rating,
|
||||
totalReviews = REMOTE_SETTINGS_RECORDS[0].attachment[0].total_reviews,
|
||||
fakespotGrade = REMOTE_SETTINGS_RECORDS[0].attachment[0].fakespot_grade,
|
||||
} = {}) {
|
||||
originalUrl ??= url;
|
||||
|
||||
|
@ -723,6 +804,7 @@ function makeExpectedResult({
|
|||
fakespotGrade,
|
||||
shouldNavigate: true,
|
||||
dynamicType: "fakespot",
|
||||
icon: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ add_setup(async () => {
|
|||
// group-relative suggestedIndex. The default Pocket suggestedIndex is 0.
|
||||
add_task(async function nimbusSuggestedIndex() {
|
||||
const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
|
||||
pocketSuggestIndex: -1,
|
||||
pocketSuggestIndex: 0,
|
||||
});
|
||||
await QuickSuggestTestUtils.forceSync();
|
||||
|
||||
|
@ -62,7 +62,7 @@ add_task(async function nimbusSuggestedIndex() {
|
|||
matches: [
|
||||
makeExpectedResult({
|
||||
searchString: LOW_KEYWORD,
|
||||
suggestedIndex: -1,
|
||||
suggestedIndex: 0,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
@ -91,7 +91,7 @@ add_task(async function nimbusSuggestedIndex() {
|
|||
matches: [
|
||||
makeExpectedResult({
|
||||
searchString: LOW_KEYWORD,
|
||||
suggestedIndex: 0,
|
||||
suggestedIndex: -1,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
@ -551,7 +551,7 @@ function makeExpectedResult({
|
|||
url.searchParams.set("utm_campaign", "pocket-collections-in-the-address-bar");
|
||||
url.searchParams.set("utm_content", "treatment");
|
||||
|
||||
let expectedSuggestedIndex = 0;
|
||||
let expectedSuggestedIndex = -1;
|
||||
if (suggestedIndex !== undefined) {
|
||||
expectedSuggestedIndex = suggestedIndex;
|
||||
} else if (isTopPick) {
|
||||
|
|
|
@ -9,6 +9,18 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
AddonTestUtils: "resource://testing-common/AddonTestUtils.sys.mjs",
|
||||
});
|
||||
|
||||
AddonTestUtils.init(this, false);
|
||||
AddonTestUtils.createAppInfo(
|
||||
"xpcshell@tests.mozilla.org",
|
||||
"XPCShell",
|
||||
"42",
|
||||
"42"
|
||||
);
|
||||
|
||||
const { DEFAULT_SUGGESTION_SCORE } = UrlbarProviderQuickSuggest;
|
||||
|
||||
const REMOTE_SETTINGS_RECORDS = [
|
||||
|
@ -131,6 +143,8 @@ const MERINO_UNKNOWN_SUGGESTION = {
|
|||
};
|
||||
|
||||
add_setup(async function init() {
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
|
||||
// Disable search suggestions so we don't hit the network.
|
||||
Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ add_task(async function interval() {
|
|||
|
||||
// Re-enable the backend with a small ingest interval. A new ingest will
|
||||
// immediately start.
|
||||
let intervalSecs = 1;
|
||||
let intervalSecs = 3;
|
||||
UrlbarPrefs.set("quicksuggest.rustIngestIntervalSeconds", intervalSecs);
|
||||
UrlbarPrefs.set("quicksuggest.rustEnabled", false);
|
||||
UrlbarPrefs.set("quicksuggest.rustEnabled", true);
|
||||
|
@ -99,7 +99,7 @@ add_task(async function interval() {
|
|||
);
|
||||
|
||||
// Wait for ingest to start and finish.
|
||||
info("Waiting for ingest to start at index " + i);
|
||||
info(`Waiting ${intervalSecs}s for ingest to start at index ${i}`);
|
||||
({ ingestPromise } = await waitForIngestStart(ingestPromise));
|
||||
info("Waiting for ingest to finish at index " + i);
|
||||
await ingestPromise;
|
||||
|
@ -118,7 +118,7 @@ add_task(async function interval() {
|
|||
// We'll simply wait for a few seconds up to two times until no new ingests
|
||||
// start.
|
||||
|
||||
let waitSecs = 3 * intervalSecs;
|
||||
let waitSecs = 2 * intervalSecs;
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
let wait = () => new Promise(r => setTimeout(r, 1000 * waitSecs));
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ var { UrlbarMuxer, UrlbarProvider, UrlbarQueryContext, UrlbarUtils } =
|
|||
ChromeUtils.importESModule("resource:///modules/UrlbarUtils.sys.mjs");
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
AddonTestUtils: "resource://testing-common/AddonTestUtils.sys.mjs",
|
||||
HttpServer: "resource://testing-common/httpd.sys.mjs",
|
||||
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
|
||||
|
@ -58,14 +57,10 @@ ChromeUtils.defineLazyGetter(this, "PlacesFrecencyRecalculator", () => {
|
|||
).wrappedJSObject;
|
||||
});
|
||||
|
||||
// Most tests need a profile to be setup, so do that here.
|
||||
do_get_profile();
|
||||
|
||||
SearchTestUtils.init(this);
|
||||
AddonTestUtils.init(this, false);
|
||||
AddonTestUtils.createAppInfo(
|
||||
"xpcshell@tests.mozilla.org",
|
||||
"XPCShell",
|
||||
"42",
|
||||
"42"
|
||||
);
|
||||
|
||||
const SUGGESTIONS_ENGINE_NAME = "Suggestions";
|
||||
const TAIL_SUGGESTIONS_ENGINE_NAME = "Tail Suggestions";
|
||||
|
|
|
@ -16,6 +16,9 @@ const fieldTemplates = {
|
|||
name: item.fieldId,
|
||||
required: item.required,
|
||||
value: item.value ?? "",
|
||||
// Conditionally add pattern attribute since pattern=""/false/undefined
|
||||
// results in weird behaviour.
|
||||
...(item.pattern && { pattern: item.pattern }),
|
||||
};
|
||||
},
|
||||
input(item) {
|
||||
|
|
|
@ -49,15 +49,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -22,14 +22,18 @@ class PictureInPictureVideoWrapper {
|
|||
};
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -17,15 +17,19 @@ class PictureInPictureVideoWrapper {
|
|||
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -42,15 +42,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -28,15 +28,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -28,8 +28,8 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback();
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
|
@ -56,15 +56,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -19,15 +19,19 @@ class PictureInPictureVideoWrapper {
|
|||
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -8,9 +8,11 @@ class PictureInPictureVideoWrapper {
|
|||
setVolume(video, volume) {
|
||||
video.volume = volume;
|
||||
}
|
||||
|
||||
isMuted(video) {
|
||||
return video.volume === 0;
|
||||
}
|
||||
|
||||
setMuted(video, shouldMute) {
|
||||
if (shouldMute) {
|
||||
this.setVolume(video, 0);
|
||||
|
@ -18,6 +20,7 @@ class PictureInPictureVideoWrapper {
|
|||
this.setVolume(video, 1);
|
||||
}
|
||||
}
|
||||
|
||||
setCaptionContainerObserver(video, updateCaptionsFunction) {
|
||||
let container = document.querySelector(
|
||||
'[data-testid="CueBoxContainer"]'
|
||||
|
@ -34,15 +37,19 @@ class PictureInPictureVideoWrapper {
|
|||
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -25,15 +25,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -8,15 +8,19 @@ class PictureInPictureVideoWrapper {
|
|||
constructor(video) {
|
||||
this.player = video.wrappedJSObject.__HuluDashPlayer__;
|
||||
}
|
||||
|
||||
play() {
|
||||
this.player.play();
|
||||
}
|
||||
|
||||
pause() {
|
||||
this.player.pause();
|
||||
}
|
||||
|
||||
isMuted(video) {
|
||||
return video.volume === 0;
|
||||
}
|
||||
|
||||
setMuted(video, shouldMute) {
|
||||
let muteButton = document.querySelector(".VolumeControl > div");
|
||||
|
||||
|
@ -24,9 +28,11 @@ class PictureInPictureVideoWrapper {
|
|||
muteButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentTime(video, position) {
|
||||
this.player.currentTime = position;
|
||||
}
|
||||
|
||||
setCaptionContainerObserver(video, updateCaptionsFunction) {
|
||||
let container = document.querySelector(".ClosedCaption");
|
||||
|
||||
|
@ -54,15 +60,20 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
|
||||
getDuration() {
|
||||
return this.player.duration;
|
||||
}
|
||||
|
|
|
@ -25,15 +25,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback();
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -18,6 +18,7 @@ class PictureInPictureVideoWrapper {
|
|||
}
|
||||
this.player = netflixPlayerAPI.getVideoPlayerBySessionId(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Netflix player returns the current time in milliseconds so we convert
|
||||
* to seconds before returning.
|
||||
|
@ -27,6 +28,7 @@ class PictureInPictureVideoWrapper {
|
|||
getCurrentTime() {
|
||||
return this.player.getCurrentTime() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Netflix player returns the duration in milliseconds so we convert to
|
||||
* seconds before returning.
|
||||
|
@ -36,9 +38,11 @@ class PictureInPictureVideoWrapper {
|
|||
getDuration() {
|
||||
return this.player.getDuration() / 1000;
|
||||
}
|
||||
|
||||
play() {
|
||||
this.player.play();
|
||||
}
|
||||
|
||||
pause() {
|
||||
this.player.pause();
|
||||
}
|
||||
|
@ -56,9 +60,9 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
|
@ -66,6 +70,10 @@ class PictureInPictureVideoWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current time of the video in milliseconds.
|
||||
*
|
||||
|
@ -75,15 +83,19 @@ class PictureInPictureVideoWrapper {
|
|||
setCurrentTime(video, position) {
|
||||
this.player.seek(position * 1000);
|
||||
}
|
||||
|
||||
setVolume(video, volume) {
|
||||
this.player.setVolume(volume);
|
||||
}
|
||||
|
||||
getVolume() {
|
||||
return this.player.getVolume();
|
||||
}
|
||||
|
||||
setMuted(video, shouldMute) {
|
||||
this.player.setMuted(shouldMute);
|
||||
}
|
||||
|
||||
isMuted() {
|
||||
return this.player.isMuted();
|
||||
}
|
||||
|
|
|
@ -23,15 +23,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -27,15 +27,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -18,6 +18,7 @@ class PictureInPictureVideoWrapper {
|
|||
video.play();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeking large amounts of time can cause the video readyState to
|
||||
* HAVE_METADATA (1) and it will throw an error when trying to play the video.
|
||||
|
@ -52,6 +53,7 @@ class PictureInPictureVideoWrapper {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
setCaptionContainerObserver(video, updateCaptionsFunction) {
|
||||
let container = document?.querySelector("#dv-web-player");
|
||||
|
||||
|
@ -85,9 +87,9 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
|
@ -95,6 +97,10 @@ class PictureInPictureVideoWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
|
||||
shouldHideToggle(video) {
|
||||
return !!video.classList.contains("tst-video-overlay-player-html5");
|
||||
}
|
||||
|
|
|
@ -25,15 +25,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -21,15 +21,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -21,15 +21,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -8,6 +8,7 @@ class PictureInPictureVideoWrapper {
|
|||
isLive() {
|
||||
return !document.querySelector(".seekbar-bar");
|
||||
}
|
||||
|
||||
getDuration(video) {
|
||||
if (this.isLive(video)) {
|
||||
return Infinity;
|
||||
|
|
|
@ -52,15 +52,18 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -24,15 +24,19 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -23,15 +23,18 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -28,15 +28,19 @@ class PictureInPictureVideoWrapper {
|
|||
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
|
||||
|
|
|
@ -14,9 +14,11 @@ class PictureInPictureVideoWrapper {
|
|||
? shortsPlayer
|
||||
: video.closest("#movie_player")?.wrappedJSObject;
|
||||
}
|
||||
|
||||
isLive() {
|
||||
return !!document.querySelector(".ytp-live");
|
||||
}
|
||||
|
||||
setMuted(video, shouldMute) {
|
||||
if (this.player) {
|
||||
if (shouldMute) {
|
||||
|
@ -28,12 +30,14 @@ class PictureInPictureVideoWrapper {
|
|||
video.muted = shouldMute;
|
||||
}
|
||||
}
|
||||
|
||||
getDuration(video) {
|
||||
if (this.isLive(video)) {
|
||||
return Infinity;
|
||||
}
|
||||
return video.duration;
|
||||
}
|
||||
|
||||
setCaptionContainerObserver(video, updateCaptionsFunction) {
|
||||
let container = document.getElementById("ytp-caption-window-container");
|
||||
|
||||
|
@ -59,18 +63,24 @@ class PictureInPictureVideoWrapper {
|
|||
// immediately invoke the callback function to add subtitles to the PiP window
|
||||
callback([1], null);
|
||||
|
||||
let captionsObserver = new MutationObserver(callback);
|
||||
this.captionsObserver = new MutationObserver(callback);
|
||||
|
||||
captionsObserver.observe(container, {
|
||||
this.captionsObserver.observe(container, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCaptionContainerObserver() {
|
||||
this.captionsObserver?.disconnect();
|
||||
}
|
||||
|
||||
shouldHideToggle(video) {
|
||||
return !!video.closest(".ytd-video-preview");
|
||||
}
|
||||
|
||||
setVolume(video, volume) {
|
||||
if (this.player) {
|
||||
this.player.setVolume(volume * 100);
|
||||
|
@ -78,6 +88,7 @@ class PictureInPictureVideoWrapper {
|
|||
video.volume = volume;
|
||||
}
|
||||
}
|
||||
|
||||
getVolume(video) {
|
||||
if (this.player) {
|
||||
return this.player.getVolume() / 100;
|
||||
|
|
|
@ -1210,6 +1210,23 @@ const AVAILABLE_UA_OVERRIDES = [
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Bug 1842767 - UA override for passport.bilibili.com
|
||||
*
|
||||
* Spoofing as Chrome makes the login page use a mobile layout.
|
||||
*/
|
||||
id: "bug1842767",
|
||||
platform: "android",
|
||||
domain: "passport.bilibili.com",
|
||||
bug: "1842767",
|
||||
config: {
|
||||
matches: ["*://*.passport.bilibili.com/*"],
|
||||
uaTransformer: () => {
|
||||
return UAHelpers.getDeviceAppropriateChromeUA();
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = AVAILABLE_UA_OVERRIDES;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "Web Compatibility Interventions",
|
||||
"description": "Urgent post-release fixes for web compatibility.",
|
||||
"version": "129.4.0",
|
||||
"version": "129.5.0",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "webcompat@mozilla.org",
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"af": {
|
||||
"pin": false,
|
||||
|
@ -35,7 +35,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"an": {
|
||||
"pin": false,
|
||||
|
@ -54,7 +54,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ar": {
|
||||
"pin": false,
|
||||
|
@ -73,7 +73,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ast": {
|
||||
"pin": false,
|
||||
|
@ -92,7 +92,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"az": {
|
||||
"pin": false,
|
||||
|
@ -111,7 +111,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"be": {
|
||||
"pin": false,
|
||||
|
@ -130,7 +130,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"bg": {
|
||||
"pin": false,
|
||||
|
@ -149,7 +149,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"bn": {
|
||||
"pin": false,
|
||||
|
@ -168,7 +168,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"bo": {
|
||||
"pin": false,
|
||||
|
@ -187,7 +187,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"br": {
|
||||
"pin": false,
|
||||
|
@ -206,7 +206,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"brx": {
|
||||
"pin": false,
|
||||
|
@ -225,7 +225,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"bs": {
|
||||
"pin": false,
|
||||
|
@ -244,7 +244,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ca": {
|
||||
"pin": false,
|
||||
|
@ -263,7 +263,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ca-valencia": {
|
||||
"pin": false,
|
||||
|
@ -282,7 +282,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"cak": {
|
||||
"pin": false,
|
||||
|
@ -301,7 +301,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ckb": {
|
||||
"pin": false,
|
||||
|
@ -320,7 +320,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"cs": {
|
||||
"pin": false,
|
||||
|
@ -339,7 +339,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"cy": {
|
||||
"pin": false,
|
||||
|
@ -358,7 +358,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"da": {
|
||||
"pin": false,
|
||||
|
@ -377,7 +377,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"de": {
|
||||
"pin": false,
|
||||
|
@ -396,7 +396,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"dsb": {
|
||||
"pin": false,
|
||||
|
@ -415,7 +415,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"el": {
|
||||
"pin": false,
|
||||
|
@ -434,7 +434,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"en-CA": {
|
||||
"pin": false,
|
||||
|
@ -453,7 +453,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"en-GB": {
|
||||
"pin": false,
|
||||
|
@ -472,7 +472,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"eo": {
|
||||
"pin": false,
|
||||
|
@ -491,7 +491,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"es-AR": {
|
||||
"pin": false,
|
||||
|
@ -510,7 +510,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"es-CL": {
|
||||
"pin": false,
|
||||
|
@ -529,7 +529,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"es-ES": {
|
||||
"pin": false,
|
||||
|
@ -548,7 +548,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"es-MX": {
|
||||
"pin": false,
|
||||
|
@ -567,7 +567,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"et": {
|
||||
"pin": false,
|
||||
|
@ -586,7 +586,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"eu": {
|
||||
"pin": false,
|
||||
|
@ -605,7 +605,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"fa": {
|
||||
"pin": false,
|
||||
|
@ -624,7 +624,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ff": {
|
||||
"pin": false,
|
||||
|
@ -643,7 +643,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"fi": {
|
||||
"pin": false,
|
||||
|
@ -662,7 +662,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"fr": {
|
||||
"pin": false,
|
||||
|
@ -681,7 +681,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"fur": {
|
||||
"pin": false,
|
||||
|
@ -700,7 +700,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"fy-NL": {
|
||||
"pin": false,
|
||||
|
@ -719,7 +719,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ga-IE": {
|
||||
"pin": false,
|
||||
|
@ -738,7 +738,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"gd": {
|
||||
"pin": false,
|
||||
|
@ -757,7 +757,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"gl": {
|
||||
"pin": false,
|
||||
|
@ -776,7 +776,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"gn": {
|
||||
"pin": false,
|
||||
|
@ -795,7 +795,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"gu-IN": {
|
||||
"pin": false,
|
||||
|
@ -814,7 +814,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"he": {
|
||||
"pin": false,
|
||||
|
@ -833,7 +833,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"hi-IN": {
|
||||
"pin": false,
|
||||
|
@ -852,7 +852,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"hr": {
|
||||
"pin": false,
|
||||
|
@ -871,7 +871,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"hsb": {
|
||||
"pin": false,
|
||||
|
@ -890,7 +890,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"hu": {
|
||||
"pin": false,
|
||||
|
@ -909,7 +909,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"hy-AM": {
|
||||
"pin": false,
|
||||
|
@ -928,7 +928,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"hye": {
|
||||
"pin": false,
|
||||
|
@ -947,7 +947,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ia": {
|
||||
"pin": false,
|
||||
|
@ -966,7 +966,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"id": {
|
||||
"pin": false,
|
||||
|
@ -985,7 +985,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"is": {
|
||||
"pin": false,
|
||||
|
@ -1004,7 +1004,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"it": {
|
||||
"pin": false,
|
||||
|
@ -1023,7 +1023,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ja": {
|
||||
"pin": false,
|
||||
|
@ -1040,7 +1040,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ja-JP-mac": {
|
||||
"pin": false,
|
||||
|
@ -1048,7 +1048,7 @@
|
|||
"macosx64",
|
||||
"macosx64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ka": {
|
||||
"pin": false,
|
||||
|
@ -1067,7 +1067,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"kab": {
|
||||
"pin": false,
|
||||
|
@ -1086,7 +1086,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"kk": {
|
||||
"pin": false,
|
||||
|
@ -1105,7 +1105,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"km": {
|
||||
"pin": false,
|
||||
|
@ -1124,7 +1124,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"kn": {
|
||||
"pin": false,
|
||||
|
@ -1143,7 +1143,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ko": {
|
||||
"pin": false,
|
||||
|
@ -1162,7 +1162,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"lij": {
|
||||
"pin": false,
|
||||
|
@ -1181,7 +1181,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"lo": {
|
||||
"pin": false,
|
||||
|
@ -1200,7 +1200,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"lt": {
|
||||
"pin": false,
|
||||
|
@ -1219,7 +1219,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ltg": {
|
||||
"pin": false,
|
||||
|
@ -1238,7 +1238,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"lv": {
|
||||
"pin": false,
|
||||
|
@ -1257,7 +1257,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"meh": {
|
||||
"pin": false,
|
||||
|
@ -1276,7 +1276,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"mk": {
|
||||
"pin": false,
|
||||
|
@ -1295,7 +1295,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"mr": {
|
||||
"pin": false,
|
||||
|
@ -1314,7 +1314,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ms": {
|
||||
"pin": false,
|
||||
|
@ -1333,7 +1333,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"my": {
|
||||
"pin": false,
|
||||
|
@ -1352,7 +1352,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"nb-NO": {
|
||||
"pin": false,
|
||||
|
@ -1371,7 +1371,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ne-NP": {
|
||||
"pin": false,
|
||||
|
@ -1390,7 +1390,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"nl": {
|
||||
"pin": false,
|
||||
|
@ -1409,7 +1409,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"nn-NO": {
|
||||
"pin": false,
|
||||
|
@ -1428,7 +1428,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"oc": {
|
||||
"pin": false,
|
||||
|
@ -1447,7 +1447,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"pa-IN": {
|
||||
"pin": false,
|
||||
|
@ -1466,7 +1466,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"pl": {
|
||||
"pin": false,
|
||||
|
@ -1485,7 +1485,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"pt-BR": {
|
||||
"pin": false,
|
||||
|
@ -1504,7 +1504,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"pt-PT": {
|
||||
"pin": false,
|
||||
|
@ -1523,7 +1523,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"rm": {
|
||||
"pin": false,
|
||||
|
@ -1542,7 +1542,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ro": {
|
||||
"pin": false,
|
||||
|
@ -1561,7 +1561,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ru": {
|
||||
"pin": false,
|
||||
|
@ -1580,7 +1580,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sat": {
|
||||
"pin": false,
|
||||
|
@ -1599,7 +1599,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sc": {
|
||||
"pin": false,
|
||||
|
@ -1618,7 +1618,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"scn": {
|
||||
"pin": false,
|
||||
|
@ -1637,7 +1637,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sco": {
|
||||
"pin": false,
|
||||
|
@ -1656,7 +1656,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"si": {
|
||||
"pin": false,
|
||||
|
@ -1675,7 +1675,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sk": {
|
||||
"pin": false,
|
||||
|
@ -1694,7 +1694,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"skr": {
|
||||
"pin": false,
|
||||
|
@ -1713,7 +1713,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sl": {
|
||||
"pin": false,
|
||||
|
@ -1732,7 +1732,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"son": {
|
||||
"pin": false,
|
||||
|
@ -1751,7 +1751,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sq": {
|
||||
"pin": false,
|
||||
|
@ -1770,7 +1770,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sr": {
|
||||
"pin": false,
|
||||
|
@ -1789,7 +1789,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"sv-SE": {
|
||||
"pin": false,
|
||||
|
@ -1808,7 +1808,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"szl": {
|
||||
"pin": false,
|
||||
|
@ -1827,7 +1827,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ta": {
|
||||
"pin": false,
|
||||
|
@ -1846,7 +1846,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"te": {
|
||||
"pin": false,
|
||||
|
@ -1865,7 +1865,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"tg": {
|
||||
"pin": false,
|
||||
|
@ -1884,7 +1884,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"th": {
|
||||
"pin": false,
|
||||
|
@ -1903,7 +1903,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"tl": {
|
||||
"pin": false,
|
||||
|
@ -1922,7 +1922,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"tr": {
|
||||
"pin": false,
|
||||
|
@ -1941,7 +1941,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"trs": {
|
||||
"pin": false,
|
||||
|
@ -1960,7 +1960,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"uk": {
|
||||
"pin": false,
|
||||
|
@ -1979,7 +1979,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"ur": {
|
||||
"pin": false,
|
||||
|
@ -1998,7 +1998,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"uz": {
|
||||
"pin": false,
|
||||
|
@ -2017,7 +2017,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"vi": {
|
||||
"pin": false,
|
||||
|
@ -2036,7 +2036,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"wo": {
|
||||
"pin": false,
|
||||
|
@ -2055,7 +2055,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"xh": {
|
||||
"pin": false,
|
||||
|
@ -2074,7 +2074,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"zh-CN": {
|
||||
"pin": false,
|
||||
|
@ -2093,7 +2093,7 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
},
|
||||
"zh-TW": {
|
||||
"pin": false,
|
||||
|
@ -2112,6 +2112,6 @@
|
|||
"win64-aarch64-devedition",
|
||||
"win64-devedition"
|
||||
],
|
||||
"revision": "84033faef5b836dbc50cf65dab575e5e0fc1f7ac"
|
||||
"revision": "ab8ebcd54e470175eb3890a5f7d560ea67b46640"
|
||||
}
|
||||
}
|
|
@ -3,15 +3,9 @@
|
|||
* 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/. */
|
||||
|
||||
import { UrlbarPrefs } from "resource:///modules/UrlbarPrefs.sys.mjs";
|
||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazy,
|
||||
"trimHttps",
|
||||
"browser.urlbar.trimHttps"
|
||||
);
|
||||
export var BrowserUIUtils = {
|
||||
/**
|
||||
* Check whether a page can be considered as 'empty', that its URI
|
||||
|
@ -149,7 +143,9 @@ export var BrowserUIUtils = {
|
|||
},
|
||||
|
||||
get trimURLProtocol() {
|
||||
return lazy.trimHttps ? "https://" : "http://";
|
||||
return UrlbarPrefs.getScotchBonnetPref("trimHttps")
|
||||
? "https://"
|
||||
: "http://";
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1508,3 +1508,16 @@ richlistitem .text-link:hover {
|
|||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
.section-heading,
|
||||
.section-description {
|
||||
margin: 0 0 var(--space-small);
|
||||
}
|
||||
|
||||
.section-header-last {
|
||||
margin: 0 0 var(--space-large);
|
||||
}
|
||||
|
||||
.search-header:has(.section-heading) {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue