Bug 1560061 - Make DOMLocalization support ShadowDOM as roots. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D35584

--HG--
rename : dom/l10n/tests/mochitest/dom_localization/test_connectRoot.html => dom/l10n/tests/mochitest/dom_localization/test_connectRoot_webcomponent.html
extra : moz-landing-system : lando
This commit is contained in:
Zibi Braniecki 2019-06-26 17:04:43 +00:00
Родитель f792986565
Коммит ff1fca971b
6 изменённых файлов: 97 добавлений и 20 удалений

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

@ -39,13 +39,13 @@ interface DOMLocalization : Localization {
* Adds a node to nodes observed for localization
* related changes.
*/
[Throws] void connectRoot(Element aElement);
[Throws] void connectRoot(Node aElement);
/**
* Removes a node from nodes observed for localization
* related changes.
*/
[Throws] void disconnectRoot(Element aElement);
[Throws] void disconnectRoot(Node aElement);
/**
* Pauses the MutationObserver set to observe

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

@ -76,7 +76,7 @@ DOMLocalization::~DOMLocalization() { DisconnectMutations(); }
* DOMLocalization API
*/
void DOMLocalization::ConnectRoot(Element& aNode, ErrorResult& aRv) {
void DOMLocalization::ConnectRoot(nsINode& aNode, ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = aNode.GetOwnerGlobal();
if (!global) {
return;
@ -86,7 +86,7 @@ void DOMLocalization::ConnectRoot(Element& aNode, ErrorResult& aRv) {
#ifdef DEBUG
for (auto iter = mRoots.ConstIter(); !iter.Done(); iter.Next()) {
Element* root = iter.Get()->GetKey();
nsINode* root = iter.Get()->GetKey();
MOZ_ASSERT(
root != &aNode && !root->Contains(&aNode) && !aNode.Contains(root),
@ -99,7 +99,7 @@ void DOMLocalization::ConnectRoot(Element& aNode, ErrorResult& aRv) {
aNode.AddMutationObserverUnlessExists(mMutations);
}
void DOMLocalization::DisconnectRoot(Element& aNode, ErrorResult& aRv) {
void DOMLocalization::DisconnectRoot(nsINode& aNode, ErrorResult& aRv) {
if (mRoots.Contains(&aNode)) {
aNode.RemoveMutationObserver(mMutations);
mRoots.RemoveEntry(&aNode);
@ -357,12 +357,19 @@ already_AddRefed<Promise> DOMLocalization::TranslateRoots(ErrorResult& aRv) {
nsTArray<RefPtr<Promise>> promises;
for (auto iter = mRoots.ConstIter(); !iter.Done(); iter.Next()) {
Element* root = iter.Get()->GetKey();
nsINode* root = iter.Get()->GetKey();
RefPtr<Promise> promise = TranslateFragment(*root, aRv);
RefPtr<L10nRootTranslationHandler> nativeHandler =
new L10nRootTranslationHandler(root);
promise->AppendNativeHandler(nativeHandler);
// If the root is an element, we'll add a native handler
// to set root info (language, direction etc.) on it
// once the localization finishes.
if (root->IsElement()) {
RefPtr<L10nRootTranslationHandler> nativeHandler =
new L10nRootTranslationHandler(root->AsElement());
promise->AppendNativeHandler(nativeHandler);
}
promises.AppendElement(promise);
}
AutoEntryScript aes(mGlobal, "DOMLocalization TranslateRoots");
@ -470,9 +477,9 @@ void DOMLocalization::DisconnectMutations() {
void DOMLocalization::DisconnectRoots() {
for (auto iter = mRoots.ConstIter(); !iter.Done(); iter.Next()) {
Element* elem = iter.Get()->GetKey();
nsINode* node = iter.Get()->GetKey();
elem->RemoveMutationObserver(mMutations);
node->RemoveMutationObserver(mMutations);
}
mRoots.Clear();
}

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

@ -33,8 +33,8 @@ class DOMLocalization : public intl::Localization {
* Methods documentation in DOMLocalization.webidl
*/
void ConnectRoot(Element& aNode, ErrorResult& aRv);
void DisconnectRoot(Element& aNode, ErrorResult& aRv);
void ConnectRoot(nsINode& aNode, ErrorResult& aRv);
void DisconnectRoot(nsINode& aNode, ErrorResult& aRv);
void PauseObserving(ErrorResult& aRv);
void ResumeObserving(ErrorResult& aRv);
@ -87,7 +87,7 @@ class DOMLocalization : public intl::Localization {
intl::L10nArgs& aRetVal, ErrorResult& aRv);
RefPtr<L10nMutations> mMutations;
nsTHashtable<nsRefPtrHashKey<Element>> mRoots;
nsTHashtable<nsRefPtrHashKey<nsINode>> mRoots;
};
} // namespace dom

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

@ -34,8 +34,7 @@ void L10nMutations::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
if (!mObserving) {
return;
}
Document* uncomposedDoc = aElement->GetUncomposedDoc();
if (uncomposedDoc) {
if (aElement->IsInComposedDoc()) {
if (aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::datal10nid ||
aAttribute == nsGkAtoms::datal10nargs)) {
@ -56,8 +55,7 @@ void L10nMutations::ContentAppended(nsIContent* aChild) {
if (node->IsElement()) {
Element* elem = node->AsElement();
Document* uncomposedDoc = elem->GetUncomposedDoc();
if (uncomposedDoc) {
if (elem->IsInComposedDoc()) {
DOMLocalization::GetTranslatables(*node, elements, rv);
}
}
@ -82,8 +80,7 @@ void L10nMutations::ContentInserted(nsIContent* aChild) {
}
Element* elem = aChild->AsElement();
Document* uncomposedDoc = elem->GetUncomposedDoc();
if (!uncomposedDoc) {
if (!elem->IsInComposedDoc()) {
return;
}
DOMLocalization::GetTranslatables(*aChild, elements, rv);

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

@ -18,6 +18,7 @@
[dom_localization/test_translateElements.html]
[dom_localization/test_translateFragment.html]
[dom_localization/test_connectRoot.html]
[dom_localization/test_connectRoot_webcomponent.html]
[dom_localization/test_disconnectRoot.html]
[dom_localization/test_repeated_l10nid.html]
[dom_localization/test_translateRoots.html]

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

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test DOMLocalization.prototype.connectRoot with Web Components</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
class FluentWidget extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
const t = document.querySelector('#fluent-widget-template');
const instance = t.content.cloneNode(true);
shadowRoot.appendChild(instance);
}
connectedCallback() {
document.domLoc.connectRoot(this.shadowRoot);
ok(true);
let label = this.shadowRoot.getElementById("label");
// Test for mutations applied.
let verifyL10n = () => {
if (label.textContent.length > 0) {
window.removeEventListener("MozAfterPaint", verifyL10n);
// Notice: In normal tests we do not want to test against any particular
// value as per https://firefox-source-docs.mozilla.org/intl/l10n/l10n/fluent_tutorial.html#testing
// But in this particular test, since we do not rely on actual real
// localization, but instead we mock it in the test, we can test
// against the actual value safely.
is(label.textContent, "Value for Key 1", "localization content applied to element");
SimpleTest.finish();
}
};
window.addEventListener("MozAfterPaint", verifyL10n);
document.domLoc.setAttributes(label, "key1");
}
}
customElements.define('fluent-widget', FluentWidget);
</script>
<script type="application/javascript">
"use strict";
const { FluentBundle } =
ChromeUtils.import("resource://gre/modules/Fluent.jsm");
async function* mockGenerateMessages(locales, resourceIds) {
const bundle = new FluentBundle(locales);
bundle.addMessages(`
key1 = Value for Key 1
`);
yield bundle;
}
document.domLoc = new DOMLocalization(
[],
mockGenerateMessages
);
</script>
</head>
<body>
<template id="fluent-widget-template">
<div>
<p id="label"></p>
</div>
</template>
<fluent-widget id="widget1"></fluent-widget>
</body>
</html>