Bug 1455649 - DocumentL10n, part 3 - Plug DocumentL10n life cycle into DOM hooks. r=smaug

--HG--
extra : rebase_source : d071878d22b5fd204db8367780ee22be22196773
This commit is contained in:
Zibi Braniecki 2018-09-06 18:28:40 -07:00
Родитель d105ed85e4
Коммит e78d123097
15 изменённых файлов: 292 добавлений и 1 удалений

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

@ -8911,6 +8911,10 @@ nsIDocument::SetReadyStateInternal(ReadyState rs)
mLoadingTimeStamp = mozilla::TimeStamp::Now();
}
if (READYSTATE_INTERACTIVE == rs) {
TriggerInitialDocumentTranslation();
}
RecordNavigationTiming(rs);
RefPtr<AsyncEventDispatcher> asyncDispatcher =

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

@ -144,6 +144,10 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument,
nsContentUtils::AddScriptRunner(
NewRunnableMethod("dom::HTMLLinkElement::BindToTree", this, update));
if (aDocument && this->AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, eIgnoreCase)) {
aDocument->LocalizationLinkAdded(this);
}
CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
return rv;
@ -180,6 +184,10 @@ HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsIDocument* oldDoc = GetUncomposedDoc();
ShadowRoot* oldShadowRoot = GetContainingShadow();
if (oldDoc && this->AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, eIgnoreCase)) {
oldDoc->LocalizationLinkRemoved(this);
}
CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
@ -292,6 +300,36 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
aSubjectPrincipal);
}
// If a link's `rel` attribute was changed from or to `localization`,
// update the list of localization links.
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::rel) {
nsIDocument* doc = GetComposedDoc();
if (doc) {
if ((aValue && aValue->Equals(nsGkAtoms::localization, eIgnoreCase)) &&
(!aOldValue || !aOldValue->Equals(nsGkAtoms::localization, eIgnoreCase))) {
doc->LocalizationLinkAdded(this);
} else if ((aOldValue && aOldValue->Equals(nsGkAtoms::localization, eIgnoreCase)) &&
(!aValue || !aValue->Equals(nsGkAtoms::localization, eIgnoreCase))) {
doc->LocalizationLinkRemoved(this);
}
}
}
// If the link has `rel=localization` and its `href` attribute is changed,
// update the list of localization links.
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href &&
AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, eIgnoreCase)) {
nsIDocument* doc = GetComposedDoc();
if (doc) {
if (aOldValue) {
doc->LocalizationLinkRemoved(this);
}
if (aValue) {
doc->LocalizationLinkAdded(this);
}
}
}
if (aValue) {
if (aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::href ||

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

@ -61,6 +61,11 @@ void
HTMLSharedElement::DoneAddingChildren(bool aHaveNotified)
{
if (mNodeInfo->Equals(nsGkAtoms::head)) {
nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
if (doc) {
doc->OnL10nResourceContainerParsed();
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this,
NS_LITERAL_STRING("DOMHeadElementParsed"),

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

@ -577,6 +577,7 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
nodeInfo->NameAtom() == nsGkAtoms::textarea ||
nodeInfo->NameAtom() == nsGkAtoms::video ||
nodeInfo->NameAtom() == nsGkAtoms::audio ||
nodeInfo->NameAtom() == nsGkAtoms::head ||
nodeInfo->NameAtom() == nsGkAtoms::object))
|| nodeInfo->NameAtom() == nsGkAtoms::title
) {

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

@ -76,6 +76,7 @@
#include "nsCCUncollectableMarker.h"
#include "nsURILoader.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/dom/DocumentL10n.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/NodeInfoInlines.h"
#include "mozilla/dom/ProcessingInstruction.h"
@ -1045,6 +1046,10 @@ XULDocument::AddElementToDocumentPost(Element* aElement)
if (aElement->NodeInfo()->Equals(nsGkAtoms::keyset, kNameSpaceID_XUL)) {
// Create our XUL key listener and hook it up.
nsXBLService::AttachGlobalKeyHandler(aElement);
} else if (aElement->IsXULElement(nsGkAtoms::link)) {
LocalizationLinkAdded(aElement);
} else if (aElement->IsXULElement(nsGkAtoms::linkset)) {
OnL10nResourceContainerParsed();
}
return NS_OK;
@ -1833,6 +1838,11 @@ XULDocument::DoneWalking()
NotifyPossibleTitleChange(false);
// For performance reasons, we want to trigger the DocumentL10n's `TriggerInitialDocumentTranslation` within the same
// microtask that will be created for a `MozBeforeInitialXULLayout`
// event listener.
AddEventListener(NS_LITERAL_STRING("MozBeforeInitialXULLayout"), mDocumentL10n, true, false);
nsContentUtils::DispatchTrustedEvent(
this,
static_cast<nsIDocument*>(this),
@ -1840,6 +1850,8 @@ XULDocument::DoneWalking()
CanBubble::eYes,
Cancelable::eNo);
RemoveEventListener(NS_LITERAL_STRING("MozBeforeInitialXULLayout"), mDocumentL10n, true);
// Before starting layout, check whether we're a toplevel chrome
// window. If we are, setup some state so that we don't have to restyle
// the whole tree after StartLayout.

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

@ -36,6 +36,7 @@ LOCAL_INCLUDES += [
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
JAR_MANIFESTS += ['jar.mn']

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

@ -18,3 +18,8 @@
[dom/test_mozdom_translateElements.html]
[dom/test_mozdom_translateFragment.html]
[dom/test_mozdom_translateRoots.html]
[dom/test_docl10n.xul]
[dom/test_docl10n.xhtml]
[dom/test_docl10n.html]
[dom/test_docl10n_ready_rejected.html]

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

@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test DocumentL10n in HTML environment</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<link rel="localization" href="crashreporter/aboutcrashes.ftl"/>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
document.addEventListener("DOMContentLoaded", async function() {
await document.l10n.ready;
let desc = document.getElementById("main-desc");
is(desc.textContent.length > 0, true);
// Test for manual value formatting
let msg = await document.l10n.formatValue("id-heading");
is(msg.length > 0, true);
let label = document.getElementById("label1");
document.l10n.setAttributes(
label,
"date-crashed-heading",
{
name: "John"
}
);
// Test for l10n.getAttributes
let l10nArgs = document.l10n.getAttributes(label);
is(l10nArgs.id, "date-crashed-heading");
is(l10nArgs.args.name, "John");
let verifyL10n = () => {
if (label.textContent.length > 0) {
window.removeEventListener("MozAfterPaint", verifyL10n);
SimpleTest.finish();
}
};
window.addEventListener("MozAfterPaint", verifyL10n);
}, { once: true});
</script>
</head>
<body>
<h1 id="main-desc" data-l10n-id="crash-reports-title"></h1>
<p id="label1"></p>
</body>
</html>

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

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8"></meta>
<title>Test DocumentL10n in HTML environment</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"></link>
<link rel="localization" href="crashreporter/aboutcrashes.ftl"/>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
document.addEventListener("DOMContentLoaded", async function() {
await document.l10n.ready;
let desc = document.getElementById("main-desc");
is(desc.textContent.length > 0, true);
// Test for manual value formatting
let msg = await document.l10n.formatValue("id-heading");
is(msg.length > 0, true);
let label = document.getElementById("label1");
document.l10n.setAttributes(
label,
"date-crashed-heading",
{
name: "John"
}
);
// Test for l10n.getAttributes
let l10nArgs = document.l10n.getAttributes(label);
is(l10nArgs.id, "date-crashed-heading");
is(l10nArgs.args.name, "John");
let verifyL10n = () => {
if (label.textContent.length > 0) {
window.removeEventListener("MozAfterPaint", verifyL10n);
SimpleTest.finish();
}
};
window.addEventListener("MozAfterPaint", verifyL10n);
}, { once: true});
</script>
</head>
<body>
<h1 id="main-desc" data-l10n-id="crash-reports-title"></h1>
<p id="label1" />
</body>
</html>

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

@ -0,0 +1,59 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="Testing DocumentL10n in XUL environment">
<linkset>
<link rel="localization" href="crashreporter/aboutcrashes.ftl"/>
</linkset>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
document.addEventListener("DOMContentLoaded", async function() {
await document.l10n.ready;
let desc = document.getElementById("main-desc");
is(desc.textContent.length > 0, true);
// Test for manual value formatting
let msg = await document.l10n.formatValue("id-heading");
is(msg.length > 0, true);
let label = document.getElementById("label1");
document.l10n.setAttributes(
label,
"date-crashed-heading",
{
name: "John"
}
);
// Test for l10n.getAttributes
let l10nArgs = document.l10n.getAttributes(label);
is(l10nArgs.id, "date-crashed-heading");
is(l10nArgs.args.name, "John");
let verifyL10n = () => {
if (label.textContent.length > 0) {
window.removeEventListener("MozAfterPaint", verifyL10n);
SimpleTest.finish();
}
};
window.addEventListener("MozAfterPaint", verifyL10n);
}, { once: true});
]]>
</script>
<description id="main-desc" data-l10n-id="crash-reports-title"/>
<label id="label1" />
</window>

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

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test mozIDOMLocalization.ready rejected state</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<link rel="localization" href="path/to_non_existing.ftl"/>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
document.addEventListener("DOMContentLoaded", async function() {
document.l10n.ready.then(() => {
is(1, 2, "the ready should not resolve");
SimpleTest.finish();
}, (err) => {
is(1, 1, "the ready should reject");
SimpleTest.finish();
});
});
</script>
</head>
<body>
<h1 data-l10n-id="non-existing-id"></h1>
</body>
</html>

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

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Ensure unprivilaged document cannot access document.l10n in an iframe</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
let frame = document.getElementById("frame");
let frame2 = document.getElementById("frame2");
is("l10n" in frame.contentDocument, false);
is("l10n" in frame2.contentDocument, false);
});
addLoadEvent(SimpleTest.finish);
</script>
</head>
<body>
<iframe id="frame" src="about:blank"></iframe>
<iframe id="frame2" src="about:crashes"></iframe>
</body>
</html>

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

@ -0,0 +1 @@
[dom/test_docl10n_unpriv_iframe.html]

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

@ -73,7 +73,7 @@ add_task(async function test_format_messages() {
});
add_task(async function test_format_values() {
let msgs = await domLocalization.formatValues([{"id": "key"}], 1);
let msgs = await domLocalization.formatValues([{"id": "key"}]);
equal(msgs.length, 1);
equal(msgs[0], "[en] Value");
});

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

@ -546,6 +546,7 @@ STATIC_ATOMS = [
Atom("li", "li"),
Atom("line", "line"),
Atom("link", "link"),
Atom("linkset", "linkset"),
# Atom("list", "list"), # "list" is present below
Atom("listbox", "listbox"),
Atom("listener", "listener"),
@ -556,6 +557,7 @@ STATIC_ATOMS = [
Atom("triggeringprincipal", "triggeringprincipal"),
Atom("localedir", "localedir"),
Atom("localName", "local-name"),
Atom("localization", "localization"),
Atom("longdesc", "longdesc"),
Atom("loop", "loop"),
Atom("low", "low"),