Update On Tue Mar 25 19:23:03 CET 2025
This commit is contained in:
parent
240d9e05c1
commit
61427ba9a4
3058 changed files with 59039 additions and 22181 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2781,9 +2781,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.22"
|
version = "0.3.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
|
|
@ -219,6 +219,11 @@ bool SelectionManager::SelectionRangeChanged(SelectionType aType,
|
||||||
dom::Document* doc = start->OwnerDoc();
|
dom::Document* doc = start->OwnerDoc();
|
||||||
MOZ_ASSERT(doc);
|
MOZ_ASSERT(doc);
|
||||||
nsINode* node = aRange.GetClosestCommonInclusiveAncestor();
|
nsINode* node = aRange.GetClosestCommonInclusiveAncestor();
|
||||||
|
if (!node) {
|
||||||
|
// Bug 1954751: This can happen when a Selection is being garbage collected,
|
||||||
|
// but it's unclear exactly what other circumstances are involved.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
HyperTextAccessible* acc = nsAccUtils::GetTextContainer(node);
|
HyperTextAccessible* acc = nsAccUtils::GetTextContainer(node);
|
||||||
if (!acc) {
|
if (!acc) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -116,10 +116,8 @@ void nsCoreUtils::DispatchClickEvent(XULTreeElement* aTree, int32_t aRowIndex,
|
||||||
int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + int32_t(rect.y) + 1) +
|
int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + int32_t(rect.y) + 1) +
|
||||||
presContext->AppUnitsToDevPixels(offset.y);
|
presContext->AppUnitsToDevPixels(offset.y);
|
||||||
|
|
||||||
if (StaticPrefs::dom_popup_experimental()) {
|
// This isn't needed once bug 1924790 is fixed.
|
||||||
// This isn't needed once bug 1924790 is fixed.
|
tcElm->OwnerDoc()->NotifyUserGestureActivation();
|
||||||
tcElm->OwnerDoc()->NotifyUserGestureActivation();
|
|
||||||
}
|
|
||||||
|
|
||||||
// XUL is just desktop, so there is no real reason for senfing touch events.
|
// XUL is just desktop, so there is no real reason for senfing touch events.
|
||||||
DispatchMouseEvent(eMouseDown, cnvdX, cnvdY, tcElm, tcFrame, presShell,
|
DispatchMouseEvent(eMouseDown, cnvdX, cnvdY, tcElm, tcFrame, presShell,
|
||||||
|
|
|
@ -2573,10 +2573,9 @@ void LocalAccessible::DispatchClickEvent(uint32_t aActionIndex) const {
|
||||||
nsCoreUtils::DispatchTouchEvent(eTouchStart, x, y, mContent, frame, presShell,
|
nsCoreUtils::DispatchTouchEvent(eTouchStart, x, y, mContent, frame, presShell,
|
||||||
widget);
|
widget);
|
||||||
|
|
||||||
if (StaticPrefs::dom_popup_experimental()) {
|
// This isn't needed once bug 1924790 is fixed.
|
||||||
// This isn't needed once bug 1924790 is fixed.
|
mContent->OwnerDoc()->NotifyUserGestureActivation();
|
||||||
mContent->OwnerDoc()->NotifyUserGestureActivation();
|
|
||||||
}
|
|
||||||
nsCoreUtils::DispatchMouseEvent(eMouseDown, x, y, mContent, frame, presShell,
|
nsCoreUtils::DispatchMouseEvent(eMouseDown, x, y, mContent, frame, presShell,
|
||||||
widget);
|
widget);
|
||||||
nsCoreUtils::DispatchTouchEvent(eTouchEnd, x, y, mContent, frame, presShell,
|
nsCoreUtils::DispatchTouchEvent(eTouchEnd, x, y, mContent, frame, presShell,
|
||||||
|
|
|
@ -381,19 +381,6 @@ between
|
||||||
<div id="popover2" popover>popover2</div>
|
<div id="popover2" popover>popover2</div>
|
||||||
<button id="toggle5">toggle5</button>
|
<button id="toggle5">toggle5</button>
|
||||||
</template></div>
|
</template></div>
|
||||||
<script>
|
|
||||||
const toggle1 = document.getElementById("toggle1");
|
|
||||||
const popover1 = document.getElementById("popover1");
|
|
||||||
toggle1.popoverTargetElement = popover1;
|
|
||||||
const toggle3 = document.getElementById("toggle3");
|
|
||||||
const shadow = document.getElementById("shadowHost").shadowRoot;
|
|
||||||
const toggle4 = shadow.getElementById("toggle4");
|
|
||||||
const popover2 = shadow.getElementById("popover2");
|
|
||||||
toggle3.popoverTargetElement = popover2;
|
|
||||||
toggle4.popoverTargetElement = popover2;
|
|
||||||
const toggle5 = shadow.getElementById("toggle5");
|
|
||||||
toggle5.popoverTargetElement = popover1;
|
|
||||||
</script>
|
|
||||||
`,
|
`,
|
||||||
async function testPopoverIdl(browser, docAcc) {
|
async function testPopoverIdl(browser, docAcc) {
|
||||||
// No popover is showing, so there shouldn't be any details relations.
|
// No popover is showing, so there shouldn't be any details relations.
|
||||||
|
@ -465,7 +452,23 @@ between
|
||||||
await hidden;
|
await hidden;
|
||||||
await testCachedRelation(toggle4, RELATION_DETAILS, []);
|
await testCachedRelation(toggle4, RELATION_DETAILS, []);
|
||||||
},
|
},
|
||||||
{ chrome: true, topLevel: true }
|
{
|
||||||
|
chrome: true,
|
||||||
|
topLevel: true,
|
||||||
|
contentSetup: async function contentSetup() {
|
||||||
|
const toggle1 = content.document.getElementById("toggle1");
|
||||||
|
const popover1 = content.document.getElementById("popover1");
|
||||||
|
toggle1.popoverTargetElement = popover1;
|
||||||
|
const toggle3 = content.document.getElementById("toggle3");
|
||||||
|
const shadow = content.document.getElementById("shadowHost").shadowRoot;
|
||||||
|
const toggle4 = shadow.getElementById("toggle4");
|
||||||
|
const popover2 = shadow.getElementById("popover2");
|
||||||
|
toggle3.popoverTargetElement = popover2;
|
||||||
|
toggle4.popoverTargetElement = popover2;
|
||||||
|
const toggle5 = shadow.getElementById("toggle5");
|
||||||
|
toggle5.popoverTargetElement = popover1;
|
||||||
|
},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -348,6 +348,12 @@ function wrapWithIFrame(doc, options = {}) {
|
||||||
id: DEFAULT_IFRAME_DOC_BODY_ID,
|
id: DEFAULT_IFRAME_DOC_BODY_ID,
|
||||||
...iframeDocBodyAttrs,
|
...iframeDocBodyAttrs,
|
||||||
};
|
};
|
||||||
|
if (options.contentSetup) {
|
||||||
|
// Hide the body initially so we can ensure that any changes made by
|
||||||
|
// contentSetup are included when the body's content is initially added to
|
||||||
|
// the accessibility tree.
|
||||||
|
iframeDocBodyAttrs["aria-hidden"] = "true";
|
||||||
|
}
|
||||||
if (options.remoteIframe) {
|
if (options.remoteIframe) {
|
||||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||||
const srcURL = new URL(`http://example.net/document-builder.sjs`);
|
const srcURL = new URL(`http://example.net/document-builder.sjs`);
|
||||||
|
@ -418,6 +424,11 @@ function snippetToURL(doc, options = {}) {
|
||||||
|
|
||||||
if (gIsIframe) {
|
if (gIsIframe) {
|
||||||
doc = wrapWithIFrame(doc, options);
|
doc = wrapWithIFrame(doc, options);
|
||||||
|
} else if (options.contentSetup) {
|
||||||
|
// Hide the body initially so we can ensure that any changes made by
|
||||||
|
// contentSetup are included when the body's content is initially added to
|
||||||
|
// the accessibility tree.
|
||||||
|
attrs["aria-hidden"] = "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
const encodedDoc = encodeURIComponent(
|
const encodedDoc = encodeURIComponent(
|
||||||
|
@ -595,6 +606,21 @@ function accessibleTask(doc, task, options = {}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.contentSetup) {
|
||||||
|
info("Executing contentSetup");
|
||||||
|
const ready = waitForEvent(EVENT_REORDER, currentContentDoc());
|
||||||
|
await invokeContentTask(browser, [], options.contentSetup);
|
||||||
|
// snippetToURL set aria-hidden on the body. We now Remove aria-hidden
|
||||||
|
// and wait for a reorder on the body. This guarantees that any
|
||||||
|
// changes made by contentSetup are included when the body's content
|
||||||
|
// is initially added to the accessibility tree and that the
|
||||||
|
// accessibility tree is up to date.
|
||||||
|
await invokeContentTask(browser, [], () => {
|
||||||
|
content.document.body.removeAttribute("aria-hidden");
|
||||||
|
});
|
||||||
|
await ready;
|
||||||
|
info("contentSetup done");
|
||||||
|
}
|
||||||
await loadContentScripts(browser, {
|
await loadContentScripts(browser, {
|
||||||
script: "Common.sys.mjs",
|
script: "Common.sys.mjs",
|
||||||
symbol: "CommonUtils",
|
symbol: "CommonUtils",
|
||||||
|
@ -670,6 +696,22 @@ function accessibleTask(doc, task, options = {}) {
|
||||||
* - {CacheDomain} cacheDomains
|
* - {CacheDomain} cacheDomains
|
||||||
* The set of cache domains that should be present at the start of the
|
* The set of cache domains that should be present at the start of the
|
||||||
* test. If not set, all cache domains will be present.
|
* test. If not set, all cache domains will be present.
|
||||||
|
* - {Function|AsyncFunction} contentSetup
|
||||||
|
* An optional task to run to set up the content document before the
|
||||||
|
* test starts. If this test is to be run as a chrome document in the
|
||||||
|
* parent process (chrome: true), This should be used instead of an
|
||||||
|
* inline <script> element in the test snippet, since inline script is
|
||||||
|
* not allowed in such documents. This task is ultimately executed
|
||||||
|
* using SpecialPowers.spawn. Any updates to the content within the
|
||||||
|
* body will be included when the content is initially added to the
|
||||||
|
* accessibility tree. The accessibility tree is guaranteed to be up
|
||||||
|
* to date when the test starts. This will not work correctly for
|
||||||
|
* changes to the html or body elements themselves. Note that you will
|
||||||
|
* need to define this exactly as follows:
|
||||||
|
* contentSetup: async function contentSetup() { ... }
|
||||||
|
* async contentSetup() will fail when the task is serialized.
|
||||||
|
* contentSetup: async function() will be changed to
|
||||||
|
* async contentSetup() by the linter and likewise fail.
|
||||||
*/
|
*/
|
||||||
function addAccessibleTask(doc, task, options = {}) {
|
function addAccessibleTask(doc, task, options = {}) {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -170,18 +170,7 @@ add_task(async function testTextFragmentSamePage() {
|
||||||
* Test custom highlight mutations.
|
* Test custom highlight mutations.
|
||||||
*/
|
*/
|
||||||
addAccessibleTask(
|
addAccessibleTask(
|
||||||
`
|
snippet,
|
||||||
${snippet}
|
|
||||||
<script>
|
|
||||||
const firstText = document.getElementById("first").firstChild;
|
|
||||||
// Highlight the word "first".
|
|
||||||
const range1 = new Range();
|
|
||||||
range1.setStart(firstText, 4);
|
|
||||||
range1.setEnd(firstText, 9);
|
|
||||||
const highlight1 = new Highlight(range1);
|
|
||||||
CSS.highlights.set("highlight1", highlight1);
|
|
||||||
</script>
|
|
||||||
`,
|
|
||||||
async function testCustomHighlightMutations(browser, docAcc) {
|
async function testCustomHighlightMutations(browser, docAcc) {
|
||||||
info("Checking initial highlight");
|
info("Checking initial highlight");
|
||||||
const first = findAccessibleChildByID(docAcc, "first");
|
const first = findAccessibleChildByID(docAcc, "first");
|
||||||
|
@ -272,41 +261,26 @@ ${snippet}
|
||||||
});
|
});
|
||||||
await rangeCheck;
|
await rangeCheck;
|
||||||
},
|
},
|
||||||
{ chrome: true, topLevel: true }
|
{
|
||||||
|
chrome: true,
|
||||||
|
topLevel: true,
|
||||||
|
contentSetup: async function contentSetup() {
|
||||||
|
const firstText = content.document.getElementById("first").firstChild;
|
||||||
|
// Highlight the word "first".
|
||||||
|
const range1 = new content.Range();
|
||||||
|
range1.setStart(firstText, 4);
|
||||||
|
range1.setEnd(firstText, 9);
|
||||||
|
const highlight1 = new content.Highlight(range1);
|
||||||
|
content.CSS.highlights.set("highlight1", highlight1);
|
||||||
|
},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test custom highlight types.
|
* Test custom highlight types.
|
||||||
*/
|
*/
|
||||||
addAccessibleTask(
|
addAccessibleTask(
|
||||||
`
|
snippet,
|
||||||
${snippet}
|
|
||||||
<script>
|
|
||||||
const firstText = document.getElementById("first").firstChild;
|
|
||||||
// Highlight the word "The".
|
|
||||||
const range1 = new Range();
|
|
||||||
range1.setStart(firstText, 0);
|
|
||||||
range1.setEnd(firstText, 3);
|
|
||||||
const highlight = new Highlight(range1);
|
|
||||||
CSS.highlights.set("highlight", highlight);
|
|
||||||
|
|
||||||
// Make the word "first" a spelling error.
|
|
||||||
const range2 = new Range();
|
|
||||||
range2.setStart(firstText, 4);
|
|
||||||
range2.setEnd(firstText, 9);
|
|
||||||
const spelling = new Highlight(range2);
|
|
||||||
spelling.type = "spelling-error";
|
|
||||||
CSS.highlights.set("spelling", spelling);
|
|
||||||
|
|
||||||
// Make the word "phrase" a grammar error.
|
|
||||||
const range3 = new Range();
|
|
||||||
range3.setStart(firstText, 10);
|
|
||||||
range3.setEnd(firstText, 16);
|
|
||||||
const grammar = new Highlight(range3);
|
|
||||||
grammar.type = "grammar-error";
|
|
||||||
CSS.highlights.set("grammar", grammar);
|
|
||||||
</script>
|
|
||||||
`,
|
|
||||||
async function testCustomHighlightTypes(browser, docAcc) {
|
async function testCustomHighlightTypes(browser, docAcc) {
|
||||||
const first = findAccessibleChildByID(docAcc, "first");
|
const first = findAccessibleChildByID(docAcc, "first");
|
||||||
ok(
|
ok(
|
||||||
|
@ -345,85 +319,42 @@ ${snippet}
|
||||||
"second highlight ranges correct"
|
"second highlight ranges correct"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{ chrome: true, topLevel: true }
|
{
|
||||||
|
chrome: true,
|
||||||
|
topLevel: true,
|
||||||
|
contentSetup: async function contentSetup() {
|
||||||
|
const firstText = content.document.getElementById("first").firstChild;
|
||||||
|
// Highlight the word "The".
|
||||||
|
const range1 = new content.Range();
|
||||||
|
range1.setStart(firstText, 0);
|
||||||
|
range1.setEnd(firstText, 3);
|
||||||
|
const highlight = new content.Highlight(range1);
|
||||||
|
content.CSS.highlights.set("highlight", highlight);
|
||||||
|
|
||||||
|
// Make the word "first" a spelling error.
|
||||||
|
const range2 = new content.Range();
|
||||||
|
range2.setStart(firstText, 4);
|
||||||
|
range2.setEnd(firstText, 9);
|
||||||
|
const spelling = new content.Highlight(range2);
|
||||||
|
spelling.type = "spelling-error";
|
||||||
|
content.CSS.highlights.set("spelling", spelling);
|
||||||
|
|
||||||
|
// Make the word "phrase" a grammar error.
|
||||||
|
const range3 = new content.Range();
|
||||||
|
range3.setStart(firstText, 10);
|
||||||
|
range3.setEnd(firstText, 16);
|
||||||
|
const grammar = new content.Highlight(range3);
|
||||||
|
grammar.type = "grammar-error";
|
||||||
|
content.CSS.highlights.set("grammar", grammar);
|
||||||
|
},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test overlapping custom highlights.
|
* Test overlapping custom highlights.
|
||||||
*/
|
*/
|
||||||
addAccessibleTask(
|
addAccessibleTask(
|
||||||
`
|
snippet,
|
||||||
${snippet}
|
|
||||||
<script>
|
|
||||||
const firstText = document.getElementById("first").firstChild;
|
|
||||||
// Make the word "The" both a highlight and a spelling error.
|
|
||||||
const range1 = new Range();
|
|
||||||
range1.setStart(firstText, 0);
|
|
||||||
range1.setEnd(firstText, 3);
|
|
||||||
const highlight1 = new Highlight(range1);
|
|
||||||
CSS.highlights.set("highlight1", highlight1);
|
|
||||||
const spelling = new Highlight(range1);
|
|
||||||
spelling.type = "spelling-error";
|
|
||||||
CSS.highlights.set("spelling", spelling);
|
|
||||||
|
|
||||||
// Highlight the word "first".
|
|
||||||
const range2 = new Range();
|
|
||||||
range2.setStart(firstText, 4);
|
|
||||||
range2.setEnd(firstText, 9);
|
|
||||||
highlight1.add(range2);
|
|
||||||
// Make "fir" a spelling error.
|
|
||||||
const range3 = new Range();
|
|
||||||
range3.setStart(firstText, 4);
|
|
||||||
range3.setEnd(firstText, 7);
|
|
||||||
spelling.add(range3);
|
|
||||||
// Make "rst" a spelling error.
|
|
||||||
const range4 = new Range();
|
|
||||||
range4.setStart(firstText, 6);
|
|
||||||
range4.setEnd(firstText, 9);
|
|
||||||
spelling.add(range4);
|
|
||||||
|
|
||||||
// Highlight the word "phrase".
|
|
||||||
const range5 = new Range();
|
|
||||||
range5.setStart(firstText, 10);
|
|
||||||
range5.setEnd(firstText, 16);
|
|
||||||
highlight1.add(range5);
|
|
||||||
// Make "ras" a spelling error.
|
|
||||||
const range6 = new Range();
|
|
||||||
range6.setStart(firstText, 12);
|
|
||||||
range6.setEnd(firstText, 15);
|
|
||||||
spelling.add(range6);
|
|
||||||
|
|
||||||
const secondText = document.querySelector("#second i").firstChild;
|
|
||||||
// Highlight the word "second".
|
|
||||||
const range7 = new Range();
|
|
||||||
range7.setStart(secondText, 0);
|
|
||||||
range7.setEnd(secondText, 6);
|
|
||||||
highlight1.add(range7);
|
|
||||||
// Make "sec" a spelling error.
|
|
||||||
const range8 = new Range();
|
|
||||||
range8.setStart(secondText, 0);
|
|
||||||
range8.setEnd(secondText, 3);
|
|
||||||
spelling.add(range8);
|
|
||||||
// Make "nd" a spelling error.
|
|
||||||
const range9 = new Range();
|
|
||||||
range9.setStart(secondText, 4);
|
|
||||||
range9.setEnd(secondText, 6);
|
|
||||||
spelling.add(range9);
|
|
||||||
|
|
||||||
const phrase2Text = document.querySelector("#second b").firstChild;
|
|
||||||
// Highlight the word "phrase".
|
|
||||||
const range10 = new Range();
|
|
||||||
range10.setStart(phrase2Text, 0);
|
|
||||||
range10.setEnd(phrase2Text, 6);
|
|
||||||
highlight1.add(range10);
|
|
||||||
// Highlight "ras" using a different Highlight.
|
|
||||||
const range11 = new Range();
|
|
||||||
range11.setStart(phrase2Text, 2);
|
|
||||||
range11.setEnd(phrase2Text, 5);
|
|
||||||
const highlight2 = new Highlight(range11);
|
|
||||||
CSS.highlights.set("highlight2", highlight2);
|
|
||||||
</script>
|
|
||||||
`,
|
|
||||||
async function testCustomHighlightOverlapping(browser, docAcc) {
|
async function testCustomHighlightOverlapping(browser, docAcc) {
|
||||||
const first = findAccessibleChildByID(docAcc, "first");
|
const first = findAccessibleChildByID(docAcc, "first");
|
||||||
ok(
|
ok(
|
||||||
|
@ -484,5 +415,78 @@ ${snippet}
|
||||||
"second spelling ranges correct"
|
"second spelling ranges correct"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{ chrome: true, topLevel: true }
|
{
|
||||||
|
chrome: true,
|
||||||
|
topLevel: true,
|
||||||
|
contentSetup: async function contentSetup() {
|
||||||
|
const firstText = content.document.getElementById("first").firstChild;
|
||||||
|
// Make the word "The" both a highlight and a spelling error.
|
||||||
|
const range1 = new content.Range();
|
||||||
|
range1.setStart(firstText, 0);
|
||||||
|
range1.setEnd(firstText, 3);
|
||||||
|
const highlight1 = new content.Highlight(range1);
|
||||||
|
content.CSS.highlights.set("highlight1", highlight1);
|
||||||
|
const spelling = new content.Highlight(range1);
|
||||||
|
spelling.type = "spelling-error";
|
||||||
|
content.CSS.highlights.set("spelling", spelling);
|
||||||
|
|
||||||
|
// Highlight the word "first".
|
||||||
|
const range2 = new content.Range();
|
||||||
|
range2.setStart(firstText, 4);
|
||||||
|
range2.setEnd(firstText, 9);
|
||||||
|
highlight1.add(range2);
|
||||||
|
// Make "fir" a spelling error.
|
||||||
|
const range3 = new content.Range();
|
||||||
|
range3.setStart(firstText, 4);
|
||||||
|
range3.setEnd(firstText, 7);
|
||||||
|
spelling.add(range3);
|
||||||
|
// Make "rst" a spelling error.
|
||||||
|
const range4 = new content.Range();
|
||||||
|
range4.setStart(firstText, 6);
|
||||||
|
range4.setEnd(firstText, 9);
|
||||||
|
spelling.add(range4);
|
||||||
|
|
||||||
|
// Highlight the word "phrase".
|
||||||
|
const range5 = new content.Range();
|
||||||
|
range5.setStart(firstText, 10);
|
||||||
|
range5.setEnd(firstText, 16);
|
||||||
|
highlight1.add(range5);
|
||||||
|
// Make "ras" a spelling error.
|
||||||
|
const range6 = new content.Range();
|
||||||
|
range6.setStart(firstText, 12);
|
||||||
|
range6.setEnd(firstText, 15);
|
||||||
|
spelling.add(range6);
|
||||||
|
|
||||||
|
const secondText = content.document.querySelector("#second i").firstChild;
|
||||||
|
// Highlight the word "second".
|
||||||
|
const range7 = new content.Range();
|
||||||
|
range7.setStart(secondText, 0);
|
||||||
|
range7.setEnd(secondText, 6);
|
||||||
|
highlight1.add(range7);
|
||||||
|
// Make "sec" a spelling error.
|
||||||
|
const range8 = new content.Range();
|
||||||
|
range8.setStart(secondText, 0);
|
||||||
|
range8.setEnd(secondText, 3);
|
||||||
|
spelling.add(range8);
|
||||||
|
// Make "nd" a spelling error.
|
||||||
|
const range9 = new content.Range();
|
||||||
|
range9.setStart(secondText, 4);
|
||||||
|
range9.setEnd(secondText, 6);
|
||||||
|
spelling.add(range9);
|
||||||
|
|
||||||
|
const phrase2Text =
|
||||||
|
content.document.querySelector("#second b").firstChild;
|
||||||
|
// Highlight the word "phrase".
|
||||||
|
const range10 = new content.Range();
|
||||||
|
range10.setStart(phrase2Text, 0);
|
||||||
|
range10.setEnd(phrase2Text, 6);
|
||||||
|
highlight1.add(range10);
|
||||||
|
// Highlight "ras" using a different Highlight.
|
||||||
|
const range11 = new content.Range();
|
||||||
|
range11.setStart(phrase2Text, 2);
|
||||||
|
range11.setEnd(phrase2Text, 5);
|
||||||
|
const highlight2 = new content.Highlight(range11);
|
||||||
|
content.CSS.highlights.set("highlight2", highlight2);
|
||||||
|
},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1841,6 +1841,7 @@ pref("browser.newtabpage.activity-stream.newtabWallpapers.customWallpaper.enable
|
||||||
// Utility preferences for custom wallpaper upload
|
// Utility preferences for custom wallpaper upload
|
||||||
pref("browser.newtabpage.activity-stream.newtabWallpapers.customWallpaper.uuid", "");
|
pref("browser.newtabpage.activity-stream.newtabWallpapers.customWallpaper.uuid", "");
|
||||||
pref("browser.newtabpage.activity-stream.newtabWallpapers.customWallpaper.fileSize", 0);
|
pref("browser.newtabpage.activity-stream.newtabWallpapers.customWallpaper.fileSize", 0);
|
||||||
|
pref("browser.newtabpage.activity-stream.newtabWallpapers.customWallpaper.fileSize.enabled", false);
|
||||||
|
|
||||||
// Current new tab page background images.
|
// Current new tab page background images.
|
||||||
pref("browser.newtabpage.activity-stream.newtabWallpapers.wallpaper", "");
|
pref("browser.newtabpage.activity-stream.newtabWallpapers.wallpaper", "");
|
||||||
|
@ -2099,10 +2100,10 @@ pref("sidebar.revamp.round-content-area", false);
|
||||||
pref("sidebar.animation.enabled", true);
|
pref("sidebar.animation.enabled", true);
|
||||||
pref("sidebar.animation.duration-ms", 200);
|
pref("sidebar.animation.duration-ms", 200);
|
||||||
pref("sidebar.animation.expand-on-hover.duration-ms", 400);
|
pref("sidebar.animation.expand-on-hover.duration-ms", 400);
|
||||||
// The sidebar.main.tools pref cannot be changed.
|
// This pref is used to store user customized tools in the sidebar launcher and shouldn't be changed.
|
||||||
// Use the sidebar.newTool.migration. pref branch to introduce a new "tool" to the sidebar launcher;
|
// See https://firefox-source-docs.mozilla.org/browser/components/sidebar/docs/index.html for ways
|
||||||
// see https://firefox-source-docs.mozilla.org/browser/components/sidebar/docs/index.html for instructions.
|
// you can introduce a new tool to the sidebar launcher.
|
||||||
pref("sidebar.main.tools", "aichat,syncedtabs,history");
|
pref("sidebar.main.tools", "");
|
||||||
pref("sidebar.verticalTabs", false);
|
pref("sidebar.verticalTabs", false);
|
||||||
pref("sidebar.visibility", "always-show");
|
pref("sidebar.visibility", "always-show");
|
||||||
// Sidebar UI state is stored per-window via session restore. Use this pref
|
// Sidebar UI state is stored per-window via session restore. Use this pref
|
||||||
|
|
|
@ -24,7 +24,7 @@ add_task(async function findbar_test() {
|
||||||
await gFindBarPromise;
|
await gFindBarPromise;
|
||||||
gFindBar.open();
|
gFindBar.open();
|
||||||
|
|
||||||
await new ContentTask.spawn(newTab.linkedBrowser, null, async function () {
|
await ContentTask.spawn(newTab.linkedBrowser, null, async function () {
|
||||||
let iframe = content.document.getElementById("iframe");
|
let iframe = content.document.getElementById("iframe");
|
||||||
let awaitLoad = ContentTaskUtils.waitForEvent(iframe, "load", false);
|
let awaitLoad = ContentTaskUtils.waitForEvent(iframe, "load", false);
|
||||||
iframe.src = "https://example.org/";
|
iframe.src = "https://example.org/";
|
||||||
|
|
|
@ -19,7 +19,7 @@ const TEST_CASES = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "chrome page",
|
type: "chrome page",
|
||||||
testURL: "chrome://global/skin/in-content/info-pages.css",
|
testURL: "chrome://global/content/mozilla.html",
|
||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -75,8 +75,8 @@ var tests = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "chrome:",
|
name: "chrome:",
|
||||||
location: "chrome://global/skin/in-content/info-pages.css",
|
location: "chrome://global/content/mozilla.html",
|
||||||
hostForDisplay: "chrome://global/skin/in-content/info-pages.css",
|
hostForDisplay: "chrome://global/content/mozilla.html",
|
||||||
hasSubview: false,
|
hasSubview: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -3698,7 +3698,7 @@ BrowserGlue.prototype = {
|
||||||
_migrateUI() {
|
_migrateUI() {
|
||||||
// Use an increasing number to keep track of the current migration state.
|
// Use an increasing number to keep track of the current migration state.
|
||||||
// Completely unrelated to the current Firefox release number.
|
// Completely unrelated to the current Firefox release number.
|
||||||
const UI_VERSION = 152;
|
const UI_VERSION = 153;
|
||||||
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
|
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
|
||||||
|
|
||||||
if (!Services.prefs.prefHasUserValue("browser.migration.version")) {
|
if (!Services.prefs.prefHasUserValue("browser.migration.version")) {
|
||||||
|
@ -4501,6 +4501,19 @@ BrowserGlue.prototype = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentUIVersion < 153 &&
|
||||||
|
Services.prefs.getBoolPref("sidebar.revamp") &&
|
||||||
|
!Services.prefs.prefHasUserValue("sidebar.main.tools")
|
||||||
|
) {
|
||||||
|
// This pref will now be a user set branch but we want to preserve the previous
|
||||||
|
// default value for existing sidebar.revamp users who hadn't changed it.
|
||||||
|
Services.prefs.setCharPref(
|
||||||
|
"sidebar.main.tools",
|
||||||
|
"aichat,syncedtabs,history"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the migration version.
|
// Update the migration version.
|
||||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1894,10 +1894,8 @@ const MESSAGES = () => {
|
||||||
{
|
{
|
||||||
type: "action",
|
type: "action",
|
||||||
label: {
|
label: {
|
||||||
raw: {
|
string_id:
|
||||||
string_id:
|
"shopping-callout-not-opted-in-integrated-reminder-do-not-show",
|
||||||
"shopping-callout-not-opted-in-integrated-reminder-do-not-show",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: "SET_PREF",
|
type: "SET_PREF",
|
||||||
|
@ -1914,10 +1912,8 @@ const MESSAGES = () => {
|
||||||
{
|
{
|
||||||
type: "action",
|
type: "action",
|
||||||
label: {
|
label: {
|
||||||
raw: {
|
string_id:
|
||||||
string_id:
|
"shopping-callout-not-opted-in-integrated-reminder-show-fewer",
|
||||||
"shopping-callout-not-opted-in-integrated-reminder-show-fewer",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: "MULTI_ACTION",
|
type: "MULTI_ACTION",
|
||||||
|
@ -1954,10 +1950,8 @@ const MESSAGES = () => {
|
||||||
{
|
{
|
||||||
type: "action",
|
type: "action",
|
||||||
label: {
|
label: {
|
||||||
raw: {
|
string_id:
|
||||||
string_id:
|
"shopping-callout-not-opted-in-integrated-reminder-manage-settings",
|
||||||
"shopping-callout-not-opted-in-integrated-reminder-manage-settings",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: "OPEN_ABOUT_PAGE",
|
type: "OPEN_ABOUT_PAGE",
|
||||||
|
@ -2150,10 +2144,8 @@ const MESSAGES = () => {
|
||||||
{
|
{
|
||||||
type: "action",
|
type: "action",
|
||||||
label: {
|
label: {
|
||||||
raw: {
|
string_id:
|
||||||
string_id:
|
"shopping-callout-not-opted-in-integrated-reminder-do-not-show",
|
||||||
"shopping-callout-not-opted-in-integrated-reminder-do-not-show",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: "SET_PREF",
|
type: "SET_PREF",
|
||||||
|
@ -2170,10 +2162,8 @@ const MESSAGES = () => {
|
||||||
{
|
{
|
||||||
type: "action",
|
type: "action",
|
||||||
label: {
|
label: {
|
||||||
raw: {
|
string_id:
|
||||||
string_id:
|
"shopping-callout-not-opted-in-integrated-reminder-show-fewer",
|
||||||
"shopping-callout-not-opted-in-integrated-reminder-show-fewer",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: "MULTI_ACTION",
|
type: "MULTI_ACTION",
|
||||||
|
@ -2210,10 +2200,8 @@ const MESSAGES = () => {
|
||||||
{
|
{
|
||||||
type: "action",
|
type: "action",
|
||||||
label: {
|
label: {
|
||||||
raw: {
|
string_id:
|
||||||
string_id:
|
"shopping-callout-not-opted-in-integrated-reminder-manage-settings",
|
||||||
"shopping-callout-not-opted-in-integrated-reminder-manage-settings",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: "OPEN_ABOUT_PAGE",
|
type: "OPEN_ABOUT_PAGE",
|
||||||
|
|
|
@ -29,9 +29,13 @@ add_task(async function test_show_chat() {
|
||||||
|
|
||||||
Assert.ok(GenAI.canShowChatEntrypoint, "Can show with provider");
|
Assert.ok(GenAI.canShowChatEntrypoint, "Can show with provider");
|
||||||
|
|
||||||
|
Services.prefs.setStringPref("sidebar.main.tools", "aichat");
|
||||||
Services.prefs.setBoolPref("sidebar.revamp", true);
|
Services.prefs.setBoolPref("sidebar.revamp", true);
|
||||||
|
|
||||||
Assert.ok(GenAI.canShowChatEntrypoint, "Can show with revamp");
|
Assert.ok(
|
||||||
|
GenAI.canShowChatEntrypoint,
|
||||||
|
"Can show with revamp and aichat tool"
|
||||||
|
);
|
||||||
|
|
||||||
Services.prefs.setStringPref("sidebar.main.tools", "history");
|
Services.prefs.setStringPref("sidebar.main.tools", "history");
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,7 @@ newtab:
|
||||||
- interaction
|
- interaction
|
||||||
notification_emails:
|
notification_emails:
|
||||||
- nbarrett@mozilla.com
|
- nbarrett@mozilla.com
|
||||||
|
- mcrawford@mozilla.com
|
||||||
expires: never
|
expires: never
|
||||||
extra_keys:
|
extra_keys:
|
||||||
selected_wallpaper:
|
selected_wallpaper:
|
||||||
|
@ -353,28 +354,6 @@ newtab:
|
||||||
description: >
|
description: >
|
||||||
Whether or not user had a previously set wallpaper
|
Whether or not user had a previously set wallpaper
|
||||||
type: boolean
|
type: boolean
|
||||||
newtab_visit_id: *newtab_visit_id
|
|
||||||
send_in_pings:
|
|
||||||
- newtab
|
|
||||||
|
|
||||||
wallpaper_upload:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
Recorded when a user uploads a custom wallpaper
|
|
||||||
bugs:
|
|
||||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1943663
|
|
||||||
data_reviews:
|
|
||||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1943663
|
|
||||||
data_sensitivity:
|
|
||||||
- interaction
|
|
||||||
notification_emails:
|
|
||||||
- mcrawford@mozilla.com
|
|
||||||
expires: never
|
|
||||||
extra_keys:
|
|
||||||
had_previous_wallpaper:
|
|
||||||
description: >
|
|
||||||
Whether or not user had a previously set wallpaper
|
|
||||||
type: boolean
|
|
||||||
had_uploaded_previously:
|
had_uploaded_previously:
|
||||||
description: >
|
description: >
|
||||||
Whether or not user had a previously uploaded a custom wallpaper
|
Whether or not user had a previously uploaded a custom wallpaper
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!-- 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/. -->
|
||||||
|
<svg width="120" height="40" viewBox="0 0 120 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect y="16" width="120" height="24" fill="white"/>
|
||||||
|
<rect y="12" width="120" height="4" fill="#F9F9FB"/>
|
||||||
|
<rect width="120" height="12" fill="#F0F0F4"/>
|
||||||
|
<mask id="mask0" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="42" y="0" width="86" height="41">
|
||||||
|
<path d="M76 0.0661167C76 0.0661167 60.5 -1.9339 60.5 16.0661C60.5 37.0662 48.3333 40.0661 42 40.5661L128 40.5662V0.0661167H76Z" fill="#D9D9D9"/>
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0)">
|
||||||
|
<path d="M45 16H120V40H45V16Z" fill="#42414D"/>
|
||||||
|
<path d="M45 0H120V12H45V0Z" fill="#1C1B22"/>
|
||||||
|
<path d="M45 12H120V16H45V12Z" fill="#2B2A33"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 897 B |
|
@ -10,18 +10,28 @@
|
||||||
gap: var(--space-xlarge);
|
gap: var(--space-xlarge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#profile-content h2[data-l10n-id="edit-profile-page-header"] {
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#header-avatar {
|
#header-avatar {
|
||||||
-moz-context-properties: fill, stroke;
|
-moz-context-properties: fill, stroke;
|
||||||
|
|
||||||
width: var(--header-avatar-size);
|
width: var(--header-avatar-size);
|
||||||
height: var(--header-avatar-size);
|
height: var(--header-avatar-size);
|
||||||
border-radius: var(--border-radius-circle);
|
border-radius: var(--border-radius-circle);
|
||||||
|
margin-inline-end: var(--space-xxlarge);
|
||||||
}
|
}
|
||||||
|
|
||||||
#profile-name-area {
|
#profile-name-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-xsmall);
|
gap: var(--space-xsmall);
|
||||||
|
margin-block: 0 var(--space-large);
|
||||||
|
}
|
||||||
|
|
||||||
|
#profile-name-area label {
|
||||||
|
margin-bottom: var(--space-xsmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
#profile-name {
|
#profile-name {
|
||||||
|
@ -68,8 +78,18 @@
|
||||||
color: var(--icon-color-success);
|
color: var(--icon-color-success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#themes::part(inputs) {
|
||||||
|
margin-top: var(--space-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
#avatars::part(inputs) {
|
||||||
|
margin-top: var(--space-medium);
|
||||||
|
}
|
||||||
|
|
||||||
#avatars::part(inputs),
|
#avatars::part(inputs),
|
||||||
#themes::part(inputs) {
|
#themes::part(inputs) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
row-gap: var(--space-small);
|
||||||
|
column-gap: var(--space-medium);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ export class NewProfileCard extends EditProfileCard {
|
||||||
<span data-l10n-id="new-profile-page-header-description"></span>
|
<span data-l10n-id="new-profile-page-header-description"></span>
|
||||||
<a
|
<a
|
||||||
is="moz-support-link"
|
is="moz-support-link"
|
||||||
support-page="profiles"
|
support-page="profile-management"
|
||||||
data-l10n-id="new-profile-page-learn-more"
|
data-l10n-id="new-profile-page-learn-more"
|
||||||
></a>
|
></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
outline-offset: var(--focus-outline-offset);
|
outline-offset: var(--focus-outline-offset);
|
||||||
border: 1px solid var(--border-color-interactive);
|
border: 1px solid var(--border-color-interactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper[checked] ::slotted(*:first-of-type) {
|
.wrapper[checked] ::slotted(*:first-of-type) {
|
||||||
border: var(--focus-outline);
|
border-width: var(--border-width);
|
||||||
border-width: 1px;
|
border-style: solid;
|
||||||
|
border-color: var(--border-color-interactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper:focus-within ::slotted(*:first-of-type) {
|
.wrapper:focus-within ::slotted(*:first-of-type) {
|
||||||
|
|
|
@ -52,7 +52,8 @@ new-profile-card {
|
||||||
#delete-profile-card {
|
#delete-profile-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--space-xxlarge);
|
gap: var(--space-xxlarge);
|
||||||
padding: var(--space-xxlarge);
|
padding-block: 50px var(--space-xxlarge);
|
||||||
|
padding-inline: var(--space-xxlarge);
|
||||||
|
|
||||||
@media only screen and (width <= 830px) {
|
@media only screen and (width <= 830px) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -20,12 +20,37 @@ export class ProfilesThemeCard extends MozLitElement {
|
||||||
imgHolder: ".img-holder",
|
imgHolder: ".img-holder",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
super.firstUpdated();
|
||||||
|
this.updateThemeImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateThemeImage() {
|
||||||
|
if (!this.theme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.theme.id === "default-theme@mozilla.org") {
|
||||||
|
// For system theme, we use a special SVG that shows the light/dark wave design
|
||||||
|
this.backgroundImg.src =
|
||||||
|
"chrome://browser/content/profiles/assets/system-theme-background.svg";
|
||||||
|
// Reset any inline styles since the SVG has its own colors
|
||||||
|
this.backgroundImg.style.fill = "";
|
||||||
|
this.backgroundImg.style.stroke = "";
|
||||||
|
this.imgHolder.style.backgroundColor = "";
|
||||||
|
} else {
|
||||||
|
// For other themes, use the standard SVG with dynamic colors
|
||||||
|
this.backgroundImg.src =
|
||||||
|
"chrome://browser/content/profiles/assets/theme-selector-background.svg";
|
||||||
|
this.backgroundImg.style.fill = this.theme.chromeColor;
|
||||||
|
this.backgroundImg.style.stroke = this.theme.toolbarColor;
|
||||||
|
this.imgHolder.style.backgroundColor = this.theme.contentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
super.updated();
|
super.updated();
|
||||||
|
this.updateThemeImage();
|
||||||
this.backgroundImg.style.fill = this.theme.chromeColor;
|
|
||||||
this.backgroundImg.style.stroke = this.theme.toolbarColor;
|
|
||||||
this.imgHolder.style.backgroundColor = this.theme.contentColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -42,9 +67,7 @@ export class ProfilesThemeCard extends MozLitElement {
|
||||||
<moz-card class="theme-card">
|
<moz-card class="theme-card">
|
||||||
<div class="theme-content">
|
<div class="theme-content">
|
||||||
<div class="img-holder">
|
<div class="img-holder">
|
||||||
<img
|
<img />
|
||||||
src="chrome://browser/content/profiles/assets/theme-selector-background.svg"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="theme-name"
|
class="theme-name"
|
||||||
|
|
|
@ -36,6 +36,7 @@ head = "../unit/head.js head.js"
|
||||||
run-if = ["os != 'linux'"] # Linux clients cannot remote themselves.
|
run-if = ["os != 'linux'"] # Linux clients cannot remote themselves.
|
||||||
|
|
||||||
["browser_preferences.js"]
|
["browser_preferences.js"]
|
||||||
|
fail-if = ["a11y_checks"] # Bug 1955503
|
||||||
|
|
||||||
["browser_test_db_lazily_created.js"]
|
["browser_test_db_lazily_created.js"]
|
||||||
|
|
||||||
|
|
|
@ -640,8 +640,7 @@ export class ShoppingContainer extends MozLitElement {
|
||||||
!RPMGetBoolPref(HAS_SEEN_POSITION_NOTIFICATION_CARD_PREF, true) &&
|
!RPMGetBoolPref(HAS_SEEN_POSITION_NOTIFICATION_CARD_PREF, true) &&
|
||||||
this.isProductPage;
|
this.isProductPage;
|
||||||
let canShowKeepClosedMessage =
|
let canShowKeepClosedMessage =
|
||||||
this.showingKeepClosedMessage &&
|
this.showingKeepClosedMessage && this.isProductPage;
|
||||||
RPMGetBoolPref(SHOW_KEEP_SIDEBAR_CLOSED_MESSAGE_PREF, true);
|
|
||||||
|
|
||||||
if (canShowNotificationCard) {
|
if (canShowNotificationCard) {
|
||||||
return this.newPositionNotificationCardTemplate();
|
return this.newPositionNotificationCardTemplate();
|
||||||
|
@ -730,7 +729,9 @@ export class ShoppingContainer extends MozLitElement {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
yetToSeeNotificationCard ||
|
yetToSeeNotificationCard ||
|
||||||
!RPMGetBoolPref(SHOW_KEEP_SIDEBAR_CLOSED_MESSAGE_PREF, false)
|
!RPMGetBoolPref(SHOW_KEEP_SIDEBAR_CLOSED_MESSAGE_PREF, false) ||
|
||||||
|
this.showOnboarding ||
|
||||||
|
!this.isProductPage
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
/* import-globals-from head.js */
|
/* import-globals-from head.js */
|
||||||
|
|
||||||
|
// withReviewCheckerSidebar calls SpecialPowers.spawn, which injects
|
||||||
|
// ContentTaskUtils in the scope of the callback. Eslint doesn't know about
|
||||||
|
// that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
const CONTENT_PAGE = "https://example.com";
|
const CONTENT_PAGE = "https://example.com";
|
||||||
|
|
||||||
add_setup(async function setup() {
|
add_setup(async function setup() {
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* import-globals-from head.js */
|
/* import-globals-from head.js */
|
||||||
|
// withReviewCheckerSidebar calls SpecialPowers.spawn, which injects
|
||||||
|
// ContentTaskUtils in the scope of the callback. Eslint doesn't know about
|
||||||
|
// that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
const CONTENT_PAGE = "https://example.com";
|
const CONTENT_PAGE = "https://example.com";
|
||||||
const NON_PDP_PAGE = "about:about";
|
const NON_PDP_PAGE = "about:about";
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* import-globals-from head.js */
|
/* import-globals-from head.js */
|
||||||
|
// withReviewCheckerSidebar calls SpecialPowers.spawn, which injects
|
||||||
|
// ContentTaskUtils in the scope of the callback. Eslint doesn't know about
|
||||||
|
// that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
|
const NON_PDP_PAGE = "about:about";
|
||||||
|
|
||||||
async function testNotificationCardThenCloseRC() {
|
async function testNotificationCardThenCloseRC() {
|
||||||
await withReviewCheckerSidebar(async _args => {
|
await withReviewCheckerSidebar(async _args => {
|
||||||
|
@ -228,3 +234,93 @@ add_task(
|
||||||
await SpecialPowers.popPrefEnv();
|
await SpecialPowers.popPrefEnv();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_task(async function test_keep_closed_message_not_visible_non_pdp() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["browser.shopping.experience2023.newPositionCard.hasSeen", true],
|
||||||
|
["browser.shopping.experience2023.showKeepSidebarClosedMessage", true],
|
||||||
|
// Set to minimum closed counts met, to speed up testing
|
||||||
|
["browser.shopping.experience2023.sidebarClosedCount", 4],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await BrowserTestUtils.withNewTab(PRODUCT_TEST_URL, async _browser => {
|
||||||
|
await SidebarController.show("viewReviewCheckerSidebar");
|
||||||
|
info("Waiting for sidebar to update.");
|
||||||
|
await reviewCheckerSidebarUpdated(PRODUCT_TEST_URL);
|
||||||
|
|
||||||
|
await TestUtils.waitForTick();
|
||||||
|
|
||||||
|
Assert.ok(SidebarController.isOpen, "Sidebar is open now");
|
||||||
|
|
||||||
|
await withReviewCheckerSidebar(async _args => {
|
||||||
|
let shoppingContainer = await ContentTaskUtils.waitForCondition(
|
||||||
|
() =>
|
||||||
|
content.document.querySelector("shopping-container")?.wrappedJSObject,
|
||||||
|
"Review Checker is loaded."
|
||||||
|
);
|
||||||
|
|
||||||
|
await shoppingContainer.updateComplete;
|
||||||
|
info("Shopping container update complete");
|
||||||
|
|
||||||
|
let keepClosedPromise = ContentTaskUtils.waitForCondition(
|
||||||
|
() => shoppingContainer.keepClosedMessageBarEl,
|
||||||
|
"Keep closed message is visible."
|
||||||
|
);
|
||||||
|
|
||||||
|
shoppingContainer.closeButtonEl.click();
|
||||||
|
|
||||||
|
await keepClosedPromise;
|
||||||
|
});
|
||||||
|
|
||||||
|
let nonPDPTab = BrowserTestUtils.addTab(gBrowser, NON_PDP_PAGE);
|
||||||
|
let nonPDPBrowser = nonPDPTab.linkedBrowser;
|
||||||
|
let browserLoadedPromise = BrowserTestUtils.browserLoaded(
|
||||||
|
nonPDPBrowser,
|
||||||
|
false,
|
||||||
|
NON_PDP_PAGE
|
||||||
|
);
|
||||||
|
await browserLoadedPromise;
|
||||||
|
|
||||||
|
info("Switching tabs now");
|
||||||
|
await BrowserTestUtils.switchTab(gBrowser, nonPDPTab);
|
||||||
|
|
||||||
|
Assert.ok(true, "Browser is loaded");
|
||||||
|
await SidebarController.show("viewReviewCheckerSidebar");
|
||||||
|
|
||||||
|
await withReviewCheckerSidebar(async _args => {
|
||||||
|
let shoppingContainer = await ContentTaskUtils.waitForCondition(
|
||||||
|
() =>
|
||||||
|
content.document.querySelector("shopping-container")?.wrappedJSObject,
|
||||||
|
"Review Checker is loaded."
|
||||||
|
);
|
||||||
|
|
||||||
|
await shoppingContainer.updateComplete;
|
||||||
|
|
||||||
|
Assert.ok(
|
||||||
|
!shoppingContainer.keepClosedMessageBarEl,
|
||||||
|
"'Keep closed' message is not visible before close button click"
|
||||||
|
);
|
||||||
|
|
||||||
|
shoppingContainer.closeButtonEl.click();
|
||||||
|
|
||||||
|
let showKeepSidebarClosedMessage = Services.prefs.getBoolPref(
|
||||||
|
"browser.shopping.experience2023.showKeepSidebarClosedMessage"
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.ok(
|
||||||
|
showKeepSidebarClosedMessage,
|
||||||
|
"browser.shopping.experience2023.showKeepSidebarClosedMessage is true"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.ok(
|
||||||
|
!SidebarController.isOpen,
|
||||||
|
"'Keep closed' message did not prevent sidebar from closing"
|
||||||
|
);
|
||||||
|
|
||||||
|
await BrowserTestUtils.removeTab(nonPDPTab);
|
||||||
|
});
|
||||||
|
SidebarController.hide();
|
||||||
|
await SpecialPowers.popPrefEnv();
|
||||||
|
});
|
||||||
|
|
|
@ -9,6 +9,10 @@ const BACKUP_STATE_PREF = "sidebar.backupState";
|
||||||
const VISIBILITY_SETTING_PREF = "sidebar.visibility";
|
const VISIBILITY_SETTING_PREF = "sidebar.visibility";
|
||||||
const SIDEBAR_TOOLS = "sidebar.main.tools";
|
const SIDEBAR_TOOLS = "sidebar.main.tools";
|
||||||
|
|
||||||
|
// New panels that are ready to be introduced to new sidebar users should be added to this list;
|
||||||
|
// ensure your feature flag is enabled at the same time you do this and that its the same value as
|
||||||
|
// what you added to .
|
||||||
|
const DEFAULT_LAUNCHER_TOOLS = "aichat,syncedtabs,history,bookmarks";
|
||||||
const lazy = {};
|
const lazy = {};
|
||||||
ChromeUtils.defineESModuleGetters(lazy, {
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs",
|
ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs",
|
||||||
|
@ -40,7 +44,15 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
() => SidebarManager.updateDefaultTools()
|
() => SidebarManager.updateDefaultTools()
|
||||||
);
|
);
|
||||||
|
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(lazy, "sidebarTools", SIDEBAR_TOOLS);
|
XPCOMUtils.defineLazyPreferenceGetter(lazy, "sidebarTools", SIDEBAR_TOOLS, "");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
lazy,
|
||||||
|
"newSidebarHasBeenUsed",
|
||||||
|
"sidebar.new-sidebar.has-used",
|
||||||
|
false,
|
||||||
|
() => SidebarManager.updateDefaultTools()
|
||||||
|
);
|
||||||
|
|
||||||
export const SidebarManager = {
|
export const SidebarManager = {
|
||||||
/**
|
/**
|
||||||
|
@ -84,7 +96,7 @@ export const SidebarManager = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
setPref("nimbus", slug);
|
setPref("nimbus", slug);
|
||||||
["main.tools", "revamp", "verticalTabs", "visibility"].forEach(pref =>
|
["revamp", "verticalTabs", "visibility"].forEach(pref =>
|
||||||
setPref(pref, lazy.NimbusFeatures[featureId].getVariable(pref))
|
setPref(pref, lazy.NimbusFeatures[featureId].getVariable(pref))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -119,16 +131,20 @@ export const SidebarManager = {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends any new tools defined on the sidebar.newTool.migration pref branch
|
* Prepopulates default tools for new sidebar users and appends any new tools defined
|
||||||
* to the sidebar.main.tools pref one time as a way of introducing a new tool
|
* on the sidebar.newTool.migration pref branch to the sidebar.main.tools pref.
|
||||||
* to the launcher without overwriting what a user had previously customized.
|
|
||||||
*/
|
*/
|
||||||
updateDefaultTools() {
|
updateDefaultTools() {
|
||||||
if (!lazy.sidebarRevampEnabled) {
|
if (!lazy.sidebarRevampEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tools = lazy.sidebarTools;
|
let tools = lazy.sidebarTools;
|
||||||
|
|
||||||
|
// For new sidebar.revamp users, we pre-populate a set of default tools to show in the launcher.
|
||||||
|
if (!tools && !lazy.newSidebarHasBeenUsed) {
|
||||||
|
tools = DEFAULT_LAUNCHER_TOOLS;
|
||||||
|
}
|
||||||
|
|
||||||
for (const pref of Services.prefs.getChildList(
|
for (const pref of Services.prefs.getChildList(
|
||||||
"sidebar.newTool.migration."
|
"sidebar.newTool.migration."
|
||||||
)) {
|
)) {
|
||||||
|
@ -136,8 +152,7 @@ export const SidebarManager = {
|
||||||
let options = JSON.parse(Services.prefs.getStringPref(pref));
|
let options = JSON.parse(Services.prefs.getStringPref(pref));
|
||||||
let newTool = pref.split(".")[3];
|
let newTool = pref.split(".")[3];
|
||||||
|
|
||||||
// ensure we only add this tool once
|
if (options?.alreadyShown) {
|
||||||
if (options?.alreadyShown || lazy.sidebarTools.includes(newTool)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +170,10 @@ export const SidebarManager = {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tools = tools + "," + newTool;
|
// avoid adding a tool from the pref branch where it's already been added to the DEFAULT_LAUNCHER_TOOLS (for new users)
|
||||||
|
if (!tools.includes(newTool)) {
|
||||||
|
tools += "," + newTool;
|
||||||
|
}
|
||||||
options.alreadyShown = true;
|
options.alreadyShown = true;
|
||||||
Services.prefs.setStringPref(pref, JSON.stringify(options));
|
Services.prefs.setStringPref(pref, JSON.stringify(options));
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
|
|
@ -15,12 +15,12 @@ const { DeferredTask } = ChromeUtils.importESModule(
|
||||||
"resource://gre/modules/DeferredTask.sys.mjs"
|
"resource://gre/modules/DeferredTask.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultTools = {
|
const toolsNameMap = {
|
||||||
viewGenaiChatSidebar: "aichat",
|
viewGenaiChatSidebar: "aichat",
|
||||||
viewReviewCheckerSidebar: "reviewchecker",
|
|
||||||
viewTabsSidebar: "syncedtabs",
|
viewTabsSidebar: "syncedtabs",
|
||||||
viewHistorySidebar: "history",
|
viewHistorySidebar: "history",
|
||||||
viewBookmarksSidebar: "bookmarks",
|
viewBookmarksSidebar: "bookmarks",
|
||||||
|
viewReviewCheckerSidebar: "reviewchecker",
|
||||||
viewCPMSidebar: "passwords",
|
viewCPMSidebar: "passwords",
|
||||||
};
|
};
|
||||||
const EXPAND_ON_HOVER_DEBOUNCE_RATE_MS = 200;
|
const EXPAND_ON_HOVER_DEBOUNCE_RATE_MS = 200;
|
||||||
|
@ -203,6 +203,7 @@ var SidebarController = {
|
||||||
revampL10nId: "sidebar-menu-customize-label",
|
revampL10nId: "sidebar-menu-customize-label",
|
||||||
iconUrl: "chrome://global/skin/icons/settings.svg",
|
iconUrl: "chrome://global/skin/icons/settings.svg",
|
||||||
gleanEvent: Glean.sidebarCustomize.panelToggle,
|
gleanEvent: Glean.sidebarCustomize.panelToggle,
|
||||||
|
visible: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this._sidebars;
|
return this._sidebars;
|
||||||
|
@ -1316,7 +1317,7 @@ var SidebarController = {
|
||||||
let changed = false;
|
let changed = false;
|
||||||
const tools = new Set(this.sidebarRevampTools.split(","));
|
const tools = new Set(this.sidebarRevampTools.split(","));
|
||||||
this.toolsAndExtensions.forEach((tool, commandID) => {
|
this.toolsAndExtensions.forEach((tool, commandID) => {
|
||||||
const toolID = defaultTools[commandID];
|
const toolID = toolsNameMap[commandID];
|
||||||
if (toolID) {
|
if (toolID) {
|
||||||
const expected = !tools.has(toolID);
|
const expected = !tools.has(toolID);
|
||||||
if (tool.disabled != expected) {
|
if (tool.disabled != expected) {
|
||||||
|
@ -1346,13 +1347,13 @@ var SidebarController = {
|
||||||
// Tools are persisted via a pref.
|
// Tools are persisted via a pref.
|
||||||
if (!Object.hasOwn(toggledTool, "extensionId")) {
|
if (!Object.hasOwn(toggledTool, "extensionId")) {
|
||||||
const tools = new Set(this.sidebarRevampTools.split(","));
|
const tools = new Set(this.sidebarRevampTools.split(","));
|
||||||
const updatedTools = tools.has(defaultTools[commandID])
|
const updatedTools = tools.has(toolsNameMap[commandID])
|
||||||
? Array.from(tools).filter(
|
? Array.from(tools).filter(
|
||||||
tool => !!tool && tool != defaultTools[commandID]
|
tool => !!tool && tool != toolsNameMap[commandID]
|
||||||
)
|
)
|
||||||
: [
|
: [
|
||||||
...Array.from(tools).filter(tool => !!tool),
|
...Array.from(tools).filter(tool => !!tool),
|
||||||
defaultTools[commandID],
|
toolsNameMap[commandID],
|
||||||
];
|
];
|
||||||
Services.prefs.setStringPref(this.TOOLS_PREF, updatedTools.join());
|
Services.prefs.setStringPref(this.TOOLS_PREF, updatedTools.join());
|
||||||
}
|
}
|
||||||
|
@ -1532,13 +1533,13 @@ var SidebarController = {
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
getTools() {
|
getTools() {
|
||||||
return Object.keys(defaultTools)
|
return Object.keys(toolsNameMap)
|
||||||
.filter(commandID => this.sidebars.get(commandID))
|
.filter(commandID => this.sidebars.get(commandID))
|
||||||
.map(commandID => {
|
.map(commandID => {
|
||||||
const sidebar = this.sidebars.get(commandID);
|
const sidebar = this.sidebars.get(commandID);
|
||||||
const disabled = !this.sidebarRevampTools
|
const disabled = !this.sidebarRevampTools
|
||||||
.split(",")
|
.split(",")
|
||||||
.includes(defaultTools[commandID]);
|
.includes(toolsNameMap[commandID]);
|
||||||
return {
|
return {
|
||||||
commandID,
|
commandID,
|
||||||
view: commandID,
|
view: commandID,
|
||||||
|
@ -2117,7 +2118,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
SidebarController,
|
SidebarController,
|
||||||
"sidebarRevampTools",
|
"sidebarRevampTools",
|
||||||
"sidebar.main.tools",
|
"sidebar.main.tools",
|
||||||
"aichat,syncedtabs,history",
|
"",
|
||||||
() => {
|
() => {
|
||||||
if (
|
if (
|
||||||
!SidebarController.inSingleTabWindow &&
|
!SidebarController.inSingleTabWindow &&
|
||||||
|
|
|
@ -9,12 +9,14 @@ The new sidebar builds on existing legacy sidebar code treating ``browser-sideba
|
||||||
Introducing a new panel
|
Introducing a new panel
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Every panel that is registered and enabled in ``browser-sidebar.js``` and the ```defaultTools``` map will show as an option in the Customize Sidebar menu (which is a sidebar panel that contains settings).
|
Every panel that is registered and enabled in ``browser-sidebar.js``` and the ```toolsNameMap``` map will show as an option in the Customize Sidebar menu (which is a sidebar panel that contains settings).
|
||||||
|
|
||||||
The launcher is a container for tools (ie, icons that when clicked open or close the associated panel). Registering a panel - which should be behind a pref until it is ready to be introduced - does not automatically add a new icon to the launcher.
|
The launcher is a container for tools (ie, icons that when clicked open or close the associated panel). Registering a panel - which should be behind a pref until it is ready to be introduced - does not automatically add a new icon to the launcher.
|
||||||
|
|
||||||
A tool can be added once for all users by adding it to the designated pref branch ``sidebar.newTool.migration.`` in ``profile/firefox.js``. So an example would be ``pref("sidebar.newTool.migration.bookmarks", '{}')``. The pref suffix (``bookmarks`` in this example) is the ``toolID`` that should match what you added as the value portion of the relevant entry in the ``defaultTools`` map in ``browser-sidebar.js``. It's important to note that if you have a pref governing the visibility of your sidebar panel, it will need to be enabled at the same time in order to be shown in a user's launcher - either via a nimbus rollout or in-tree.
|
A tool can be added once for all users by adding it to the designated pref branch ``sidebar.newTool.migration.`` in ``profile/firefox.js``. So an example would be ``pref("sidebar.newTool.migration.bookmarks", '{}')``. The pref suffix (``bookmarks`` in this example) is the ``toolID`` that should match what you added as the value portion of the relevant entry in the ``toolsNameMap`` map in ``browser-sidebar.js``. It's important to note that if you have a pref governing the visibility of your sidebar panel, it will need to be enabled at the same time in order to be shown in a user's launcher - either via a nimbus rollout or in-tree.
|
||||||
|
|
||||||
If you only want to add this item if the pref governing visibility is true, you can pass the pref you want to observe, e.g. ``pref("sidebar.newTool.migration.reviewchecker", '{ "visibilityPref": "browser.shopping.experience2023.integratedSidebar"}')`` where ``browser.shopping.experience2023.integratedSidebar`` is the pref controlling the visibility of the review checker panel.
|
If you only want to add this item if the pref governing visibility is true, you can pass the pref you want to observe, e.g. ``pref("sidebar.newTool.migration.reviewchecker", '{ "visibilityPref": "browser.shopping.experience2023.integratedSidebar"}')`` where ``browser.shopping.experience2023.integratedSidebar`` is the pref controlling the visibility of the review checker panel.
|
||||||
|
|
||||||
In both cases, the tool will be introduced to the launcher one time (appended to a user's customized list of tools) and any customization after that (ie, removing it) takes precedence. If it's not removed, it will persist after that session.
|
In both cases, the tool will be introduced to the launcher one time (appended to a user's customized list of tools) and any customization after that (ie, removing it) takes precedence. If it's not removed, it will persist after that session.
|
||||||
|
|
||||||
|
If you only want to introduce a tool to new users, you can do so by adding it to the ``DEFAULT_LAUNCHER_TOOLS`` list in ``SidebarManager`` and the ``toolsNameMap``. You can do this even if you have previously introduced a tool via a pref branch migration as there is logic that will prevent a tool from being added twice, however the expectation is that when adding it to ``defaultTools`` the pref governing panel visibility is also enabled in-tree.
|
||||||
|
|
|
@ -23,12 +23,6 @@ skip-if = [
|
||||||
["browser_extensions_sidebar.js"]
|
["browser_extensions_sidebar.js"]
|
||||||
|
|
||||||
["browser_glean_sidebar.js"]
|
["browser_glean_sidebar.js"]
|
||||||
skip-if = [
|
|
||||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64'", # Bug 1919183
|
|
||||||
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # Bug 1919183
|
|
||||||
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && opt", # Bug 1919183
|
|
||||||
"os == 'win' && os_version == '11.26100'", # Bug 1919183
|
|
||||||
]
|
|
||||||
|
|
||||||
["browser_hide_sidebar_on_popup.js"]
|
["browser_hide_sidebar_on_popup.js"]
|
||||||
|
|
||||||
|
@ -66,15 +60,6 @@ run-if = ["os == 'mac'"] # Mac only feature
|
||||||
["browser_syncedtabs_sidebar.js"]
|
["browser_syncedtabs_sidebar.js"]
|
||||||
|
|
||||||
["browser_toolbar_sidebar_button.js"]
|
["browser_toolbar_sidebar_button.js"]
|
||||||
skip-if = [
|
|
||||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && asan && swgl", # Bug 1898739
|
|
||||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && opt", # Bug 1898739
|
|
||||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && debug && swgl", # Bug 1898739
|
|
||||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && debug && socketprocess_networking", # Bug 1898739
|
|
||||||
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && opt", # Bug 1898739
|
|
||||||
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && opt", # Bug 1898739
|
|
||||||
"os == 'win' && os_version == '11.26100' && opt", # Bug 1898739
|
|
||||||
]
|
|
||||||
|
|
||||||
["browser_tools_migration.js"]
|
["browser_tools_migration.js"]
|
||||||
|
|
||||||
|
|
|
@ -66,13 +66,7 @@ add_task(async function test_customize_sidebar_actions() {
|
||||||
4,
|
4,
|
||||||
"Four default tools are shown in the customize menu"
|
"Four default tools are shown in the customize menu"
|
||||||
);
|
);
|
||||||
let bookmarksInput = Array.from(customizeComponent.toolInputs).find(
|
|
||||||
input => input.name === "viewBookmarksSidebar"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!bookmarksInput.checked,
|
|
||||||
"The bookmarks input is unchecked initally as Bookmarks are disabled initially."
|
|
||||||
);
|
|
||||||
for (const toolInput of customizeComponent.toolInputs) {
|
for (const toolInput of customizeComponent.toolInputs) {
|
||||||
let toolDisabledInitialState = !toolInput.checked;
|
let toolDisabledInitialState = !toolInput.checked;
|
||||||
toolInput.click();
|
toolInput.click();
|
||||||
|
|
|
@ -361,8 +361,7 @@ add_task(async function test_customize_history_enabled() {
|
||||||
add_task(async function test_customize_bookmarks_enabled() {
|
add_task(async function test_customize_bookmarks_enabled() {
|
||||||
await testCustomizeToggle(
|
await testCustomizeToggle(
|
||||||
"viewBookmarksSidebar",
|
"viewBookmarksSidebar",
|
||||||
Glean.sidebarCustomize.bookmarksEnabled,
|
Glean.sidebarCustomize.bookmarksEnabled
|
||||||
false
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -589,7 +588,6 @@ async function testIconClick(expanded) {
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["browser.ml.chat.enabled", true],
|
["browser.ml.chat.enabled", true],
|
||||||
["sidebar.main.tools", "aichat,syncedtabs,history,bookmarks"],
|
|
||||||
[TAB_DIRECTION_PREF, true],
|
[TAB_DIRECTION_PREF, true],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,11 +9,9 @@ const { ExperimentFakes } = ChromeUtils.importESModule(
|
||||||
* Check that enrolling into sidebar experiments sets user prefs
|
* Check that enrolling into sidebar experiments sets user prefs
|
||||||
*/
|
*/
|
||||||
add_task(async function test_nimbus_user_prefs() {
|
add_task(async function test_nimbus_user_prefs() {
|
||||||
const main = "sidebar.main.tools";
|
|
||||||
const nimbus = "sidebar.nimbus";
|
const nimbus = "sidebar.nimbus";
|
||||||
const vertical = "sidebar.verticalTabs";
|
const vertical = "sidebar.verticalTabs";
|
||||||
|
|
||||||
Assert.ok(!Services.prefs.prefHasUserValue(main), "No user main pref yet");
|
|
||||||
Assert.ok(
|
Assert.ok(
|
||||||
!Services.prefs.prefHasUserValue(nimbus),
|
!Services.prefs.prefHasUserValue(nimbus),
|
||||||
"No user nimbus pref yet"
|
"No user nimbus pref yet"
|
||||||
|
@ -22,55 +20,13 @@ add_task(async function test_nimbus_user_prefs() {
|
||||||
let cleanup = await ExperimentFakes.enrollWithFeatureConfig({
|
let cleanup = await ExperimentFakes.enrollWithFeatureConfig({
|
||||||
featureId: "sidebar",
|
featureId: "sidebar",
|
||||||
value: {
|
value: {
|
||||||
"main.tools": "bar",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
Services.prefs.getStringPref(main),
|
|
||||||
"bar",
|
|
||||||
"Set user pref with experiment"
|
|
||||||
);
|
|
||||||
Assert.ok(Services.prefs.prefHasUserValue(main), "main pref has user value");
|
|
||||||
const nimbusValue = Services.prefs.getStringPref(nimbus);
|
|
||||||
Assert.ok(nimbusValue, "Set some nimbus slug");
|
|
||||||
Assert.ok(
|
|
||||||
Services.prefs.prefHasUserValue(nimbus),
|
|
||||||
"nimbus pref has user value"
|
|
||||||
);
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
Services.prefs.getStringPref(main),
|
|
||||||
"bar",
|
|
||||||
"main pref still set"
|
|
||||||
);
|
|
||||||
Assert.equal(
|
|
||||||
Services.prefs.getStringPref(nimbus),
|
|
||||||
nimbusValue,
|
|
||||||
"nimbus pref still set"
|
|
||||||
);
|
|
||||||
Assert.ok(!Services.prefs.getBoolPref(vertical), "vertical is default value");
|
|
||||||
Assert.ok(
|
|
||||||
!Services.prefs.prefHasUserValue(vertical),
|
|
||||||
"vertical used default value"
|
|
||||||
);
|
|
||||||
|
|
||||||
cleanup = await ExperimentFakes.enrollWithFeatureConfig({
|
|
||||||
featureId: "sidebar",
|
|
||||||
value: {
|
|
||||||
"main.tools": "aichat,syncedtabs,history",
|
|
||||||
verticalTabs: true,
|
verticalTabs: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.ok(!Services.prefs.prefHasUserValue(main), "main pref no longer set");
|
const nimbusValue = Services.prefs.getStringPref(nimbus);
|
||||||
Assert.notEqual(
|
|
||||||
Services.prefs.getStringPref(nimbus),
|
Assert.ok(nimbusValue, "Set some nimbus slug");
|
||||||
nimbusValue,
|
|
||||||
"nimbus pref changed"
|
|
||||||
);
|
|
||||||
Assert.ok(Services.prefs.getBoolPref(vertical), "vertical set to true");
|
Assert.ok(Services.prefs.getBoolPref(vertical), "vertical set to true");
|
||||||
Assert.ok(
|
Assert.ok(
|
||||||
Services.prefs.prefHasUserValue(vertical),
|
Services.prefs.prefHasUserValue(vertical),
|
||||||
|
@ -123,13 +79,11 @@ add_task(async function test_nimbus_rollout_experiment() {
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that multi-feature sidebar and chatbot sets prefs
|
* Check that multi-feature chatbot sets prefs
|
||||||
*/
|
*/
|
||||||
add_task(async function test_nimbus_multi_feature() {
|
add_task(async function test_nimbus_multi_feature() {
|
||||||
const chatbot = "browser.ml.chat.test";
|
const chatbot = "browser.ml.chat.test";
|
||||||
const sidebar = "sidebar.main.tools";
|
|
||||||
Assert.ok(!Services.prefs.prefHasUserValue(chatbot), "chatbot is default");
|
Assert.ok(!Services.prefs.prefHasUserValue(chatbot), "chatbot is default");
|
||||||
Assert.ok(!Services.prefs.prefHasUserValue(sidebar), "sidebar is default");
|
|
||||||
|
|
||||||
const cleanup = await ExperimentFakes.enrollmentHelper(
|
const cleanup = await ExperimentFakes.enrollmentHelper(
|
||||||
ExperimentFakes.recipe("foo", {
|
ExperimentFakes.recipe("foo", {
|
||||||
|
@ -137,10 +91,6 @@ add_task(async function test_nimbus_multi_feature() {
|
||||||
{
|
{
|
||||||
slug: "variant",
|
slug: "variant",
|
||||||
features: [
|
features: [
|
||||||
{
|
|
||||||
featureId: "sidebar",
|
|
||||||
value: { "main.tools": "syncedtabs,history" },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
featureId: "chatbot",
|
featureId: "chatbot",
|
||||||
value: { prefs: { test: { value: true } } },
|
value: { prefs: { test: { value: true } } },
|
||||||
|
@ -152,15 +102,12 @@ add_task(async function test_nimbus_multi_feature() {
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert.ok(Services.prefs.prefHasUserValue(chatbot), "chatbot user pref set");
|
Assert.ok(Services.prefs.prefHasUserValue(chatbot), "chatbot user pref set");
|
||||||
Assert.ok(Services.prefs.prefHasUserValue(sidebar), "sidebar user pref set");
|
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
Assert.ok(Services.prefs.prefHasUserValue(chatbot), "chatbot pref still set");
|
Assert.ok(Services.prefs.prefHasUserValue(chatbot), "chatbot pref still set");
|
||||||
Assert.ok(Services.prefs.prefHasUserValue(sidebar), "sidebar pref still set");
|
|
||||||
|
|
||||||
Services.prefs.clearUserPref(chatbot);
|
Services.prefs.clearUserPref(chatbot);
|
||||||
Services.prefs.clearUserPref(sidebar);
|
|
||||||
Services.prefs.clearUserPref("browser.ml.chat.nimbus");
|
Services.prefs.clearUserPref("browser.ml.chat.nimbus");
|
||||||
Services.prefs.clearUserPref("sidebar.nimbus");
|
Services.prefs.clearUserPref("sidebar.nimbus");
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,12 +7,11 @@ add_task(async function test_tools_prefs() {
|
||||||
const win = await BrowserTestUtils.openNewBrowserWindow();
|
const win = await BrowserTestUtils.openNewBrowserWindow();
|
||||||
const { document } = win;
|
const { document } = win;
|
||||||
const sidebar = document.querySelector("sidebar-main");
|
const sidebar = document.querySelector("sidebar-main");
|
||||||
ok(sidebar, "Sidebar is shown.");
|
|
||||||
await sidebar.updateComplete;
|
await sidebar.updateComplete;
|
||||||
|
|
||||||
is(
|
is(
|
||||||
Services.prefs.getStringPref("sidebar.main.tools"),
|
Services.prefs.getStringPref("sidebar.main.tools"),
|
||||||
"aichat,syncedtabs,history",
|
"aichat,syncedtabs,history,bookmarks",
|
||||||
"Default tools pref unchanged"
|
"Default tools pref unchanged"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -35,11 +34,14 @@ add_task(async function test_tools_prefs() {
|
||||||
input => input.name === "viewBookmarksSidebar"
|
input => input.name === "viewBookmarksSidebar"
|
||||||
);
|
);
|
||||||
ok(
|
ok(
|
||||||
!bookmarksInput.checked,
|
bookmarksInput.checked,
|
||||||
"The bookmarks input is unchecked initially as Bookmarks are disabled initially."
|
"The bookmarks input is checked initially as Bookmarks is a default tool."
|
||||||
);
|
);
|
||||||
for (const toolInput of customizeComponent.toolInputs) {
|
for (const toolInput of customizeComponent.toolInputs) {
|
||||||
let toolDisabledInitialState = !toolInput.checked;
|
let toolDisabledInitialState = !toolInput.checked;
|
||||||
|
if (toolInput.name == "viewBookmarksSidebar") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
toolInput.click();
|
toolInput.click();
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() => {
|
() => {
|
||||||
|
@ -67,7 +69,7 @@ add_task(async function test_tools_prefs() {
|
||||||
is(
|
is(
|
||||||
updatedTools,
|
updatedTools,
|
||||||
"bookmarks",
|
"bookmarks",
|
||||||
"History, aichat and syncedtabs have been removed from the pref, and bookmarks added"
|
"All tools have been removed from the launcher except bookmarks"
|
||||||
);
|
);
|
||||||
|
|
||||||
await BrowserTestUtils.closeWindow(win);
|
await BrowserTestUtils.closeWindow(win);
|
||||||
|
@ -143,11 +145,13 @@ add_task(async function test_tool_pref_change() {
|
||||||
});
|
});
|
||||||
is(sidebar.toolButtons.length, origCount - 1, "Removed tool");
|
is(sidebar.toolButtons.length, origCount - 1, "Removed tool");
|
||||||
|
|
||||||
await SpecialPowers.pushPrefEnv({ set: [["sidebar.main.tools", origTools]] });
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["sidebar.main.tools", origTools]],
|
||||||
|
});
|
||||||
is(sidebar.toolButtons.length, origCount, "Restored tool");
|
is(sidebar.toolButtons.length, origCount, "Restored tool");
|
||||||
|
|
||||||
await SpecialPowers.pushPrefEnv({ clear: [["sidebar.main.tools"]] });
|
await SpecialPowers.pushPrefEnv({ clear: [["sidebar.main.tools"]] });
|
||||||
is(sidebar.toolButtons.length, 3, "Restored default tools");
|
is(sidebar.toolButtons.length, 0, "Cleared default tools");
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
add_setup(async () => {
|
add_setup(async () => {
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["sidebar.main.tools", "syncedtabs,history"],
|
["sidebar.main.tools", "syncedtabs,bookmarks,history"],
|
||||||
["sidebar.newTool.migration.bookmarks", "{}"],
|
["sidebar.newTool.migration.bookmarks", "{}"],
|
||||||
["browser.ml.chat.enabled", false],
|
["browser.ml.chat.enabled", false],
|
||||||
[
|
[
|
||||||
|
@ -19,7 +19,29 @@ add_setup(async () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_task(async function test_duplicate_tool() {
|
||||||
|
const sidebar = document.querySelector("sidebar-main");
|
||||||
|
let tools = Services.prefs.getStringPref("sidebar.main.tools").split(",");
|
||||||
|
is(tools.length, 3, "Three tools are in the sidebar.main.tools pref");
|
||||||
|
is(
|
||||||
|
tools.filter(tool => tool == "bookmarks").length,
|
||||||
|
1,
|
||||||
|
"Bookmarks has only been added once"
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
sidebar.toolButtons.length,
|
||||||
|
3,
|
||||||
|
"Three default tools are visible in the launcher"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
add_task(async function test_one_time_tool_migration() {
|
add_task(async function test_one_time_tool_migration() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["sidebar.main.tools", "syncedtabs,history"],
|
||||||
|
["sidebar.newTool.migration.bookmarks", "{}"],
|
||||||
|
],
|
||||||
|
});
|
||||||
const sidebar = document.querySelector("sidebar-main");
|
const sidebar = document.querySelector("sidebar-main");
|
||||||
let tools = Services.prefs.getStringPref("sidebar.main.tools");
|
let tools = Services.prefs.getStringPref("sidebar.main.tools");
|
||||||
is(
|
is(
|
||||||
|
|
|
@ -19,13 +19,11 @@ const kPrefCustomizationHorizontalTabstrip =
|
||||||
"browser.uiCustomization.horizontalTabstrip";
|
"browser.uiCustomization.horizontalTabstrip";
|
||||||
const kPrefCustomizationNavBarWhenVerticalTabs =
|
const kPrefCustomizationNavBarWhenVerticalTabs =
|
||||||
"browser.uiCustomization.navBarWhenVerticalTabs";
|
"browser.uiCustomization.navBarWhenVerticalTabs";
|
||||||
const kPrefSidebarTools = "sidebar.main.tools";
|
|
||||||
|
|
||||||
const MODIFIED_PREFS = Object.freeze([
|
const MODIFIED_PREFS = Object.freeze([
|
||||||
kPrefCustomizationState,
|
kPrefCustomizationState,
|
||||||
kPrefCustomizationHorizontalTabstrip,
|
kPrefCustomizationHorizontalTabstrip,
|
||||||
kPrefCustomizationNavBarWhenVerticalTabs,
|
kPrefCustomizationNavBarWhenVerticalTabs,
|
||||||
kPrefSidebarTools,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Ensure we clear any previous pref values
|
// Ensure we clear any previous pref values
|
||||||
|
|
|
@ -678,7 +678,7 @@ export class SmartTabGroupingManager {
|
||||||
|
|
||||||
const UPDATE_THRESHOLD_PERCENTAGE = 0.5;
|
const UPDATE_THRESHOLD_PERCENTAGE = 0.5;
|
||||||
const ONE_MB = 1024 * 1024;
|
const ONE_MB = 1024 * 1024;
|
||||||
const START_THRESHOLD_BYTES = ONE_MB;
|
const START_THRESHOLD_BYTES = ONE_MB * 0.2;
|
||||||
|
|
||||||
const mutliProgressAggregator = new lazy.MultiProgressAggregator({
|
const mutliProgressAggregator = new lazy.MultiProgressAggregator({
|
||||||
progressCallback: ({ progress, totalLoaded, metadata }) => {
|
progressCallback: ({ progress, totalLoaded, metadata }) => {
|
||||||
|
|
|
@ -5967,6 +5967,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bug 1955388 - prevent pinned tabs from commingling with non-pinned tabs
|
||||||
|
* when there are hidden tabs present
|
||||||
|
*/
|
||||||
|
if (tab.pinned && !targetElement?.pinned) {
|
||||||
|
// prevent pinned tab from being dragged past a non-pinned tab
|
||||||
|
targetElement = this.tabs[this.pinnedTabCount - 1];
|
||||||
|
moveBefore = false;
|
||||||
|
}
|
||||||
|
|
||||||
let getContainer = () => {
|
let getContainer = () => {
|
||||||
if (tab.pinned && this.tabContainer.verticalMode) {
|
if (tab.pinned && this.tabContainer.verticalMode) {
|
||||||
return this.tabContainer.verticalPinnedTabsContainer;
|
return this.tabContainer.verticalPinnedTabsContainer;
|
||||||
|
|
|
@ -1017,8 +1017,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#setMovingTabMode(movingTab) {
|
#setMovingTabMode(movingTab) {
|
||||||
|
if (movingTab == this.#isMovingTab()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.toggleAttribute("movingtab", movingTab);
|
this.toggleAttribute("movingtab", movingTab);
|
||||||
gNavToolbox.toggleAttribute("movingtab", movingTab);
|
gNavToolbox.toggleAttribute("movingtab", movingTab);
|
||||||
|
|
||||||
|
if (movingTab) {
|
||||||
|
// This is a bit of an escape hatch in case a tab drag & drop session
|
||||||
|
// wasn't ended properly, leaving behind the movingtab attribute, which
|
||||||
|
// may break the UI (bug 1954163). We don't get mousemove events while
|
||||||
|
// dragging tabs, so at that point it should be safe to assume that we
|
||||||
|
// should not be in drag and drop mode, and clean things up if needed.
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.addEventListener(
|
||||||
|
"mousemove",
|
||||||
|
() => {
|
||||||
|
this.finishAnimateTabMove();
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#isMovingTab() {
|
#isMovingTab() {
|
||||||
|
@ -1137,7 +1158,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let shouldTranslate = !gReduceMotion && !shouldCreateGroupOnDrop;
|
let shouldTranslate =
|
||||||
|
!gReduceMotion &&
|
||||||
|
!shouldCreateGroupOnDrop &&
|
||||||
|
!isTabGroupLabel(draggedTab);
|
||||||
if (this.#isContainerVerticalPinnedExpanded(draggedTab)) {
|
if (this.#isContainerVerticalPinnedExpanded(draggedTab)) {
|
||||||
shouldTranslate &&=
|
shouldTranslate &&=
|
||||||
(oldTranslateX && oldTranslateX != newTranslateX) ||
|
(oldTranslateX && oldTranslateX != newTranslateX) ||
|
||||||
|
@ -1161,6 +1185,7 @@
|
||||||
} else {
|
} else {
|
||||||
gBrowser.moveTabsAfter(movingTabs, dropElement);
|
gBrowser.moveTabsAfter(movingTabs, dropElement);
|
||||||
}
|
}
|
||||||
|
this.#expandGroupOnDrop(draggedTab);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shouldTranslate) {
|
if (shouldTranslate) {
|
||||||
|
@ -1313,7 +1338,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draggedTab) {
|
if (draggedTab) {
|
||||||
this.#expandGroupOnDrop(draggedTab);
|
|
||||||
delete draggedTab._dragData;
|
delete draggedTab._dragData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1336,17 +1360,13 @@
|
||||||
if (
|
if (
|
||||||
dt.mozUserCancelled ||
|
dt.mozUserCancelled ||
|
||||||
dt.dropEffect != "none" ||
|
dt.dropEffect != "none" ||
|
||||||
|
!Services.prefs.getBoolPref("browser.tabs.allowTabDetach") ||
|
||||||
this._isCustomizing
|
this._isCustomizing
|
||||||
) {
|
) {
|
||||||
delete draggedTab._dragData;
|
delete draggedTab._dragData;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if tab detaching is enabled
|
|
||||||
if (!Services.prefs.getBoolPref("browser.tabs.allowTabDetach")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable detach within the browser toolbox
|
// Disable detach within the browser toolbox
|
||||||
let [tabAxisPos, tabAxisStart, tabAxisEnd] = this.verticalMode
|
let [tabAxisPos, tabAxisStart, tabAxisEnd] = this.verticalMode
|
||||||
? [event.screenY, window.screenY, window.screenY + window.outerHeight]
|
? [event.screenY, window.screenY, window.screenY + window.outerHeight]
|
||||||
|
|
|
@ -61,7 +61,14 @@ let currentTab = () =>
|
||||||
lazy.BrowserWindowTracker.getTopWindow()?.gBrowser.selectedTab;
|
lazy.BrowserWindowTracker.getTopWindow()?.gBrowser.selectedTab;
|
||||||
|
|
||||||
ChromeUtils.defineLazyGetter(lazy, "gFluentStrings", function () {
|
ChromeUtils.defineLazyGetter(lazy, "gFluentStrings", function () {
|
||||||
return new Localization(["branding/brand.ftl", "browser/browser.ftl"], true);
|
return new Localization(
|
||||||
|
[
|
||||||
|
"branding/brand.ftl",
|
||||||
|
"browser/browser.ftl",
|
||||||
|
"toolkit/branding/brandings.ftl",
|
||||||
|
],
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const DEFAULT_ACTIONS = {
|
const DEFAULT_ACTIONS = {
|
||||||
|
@ -83,10 +90,10 @@ const DEFAULT_ACTIONS = {
|
||||||
},
|
},
|
||||||
clear: {
|
clear: {
|
||||||
l10nCommands: [
|
l10nCommands: [
|
||||||
"quickactions-cmd-clearhistory",
|
"quickactions-cmd-clearrecenthistory",
|
||||||
"quickactions-clearhistory",
|
"quickactions-clearrecenthistory",
|
||||||
],
|
],
|
||||||
label: "quickactions-clearhistory",
|
label: "quickactions-clearrecenthistory",
|
||||||
onPick: () => {
|
onPick: () => {
|
||||||
lazy.BrowserWindowTracker.getTopWindow()
|
lazy.BrowserWindowTracker.getTopWindow()
|
||||||
.document.getElementById("Tools:Sanitize")
|
.document.getElementById("Tools:Sanitize")
|
||||||
|
@ -105,6 +112,22 @@ const DEFAULT_ACTIONS = {
|
||||||
label: "quickactions-extensions",
|
label: "quickactions-extensions",
|
||||||
onPick: openAddonsUrl("addons://list/extension"),
|
onPick: openAddonsUrl("addons://list/extension"),
|
||||||
},
|
},
|
||||||
|
help: {
|
||||||
|
l10nCommands: ["quickactions-cmd-help"],
|
||||||
|
icon: "chrome://global/skin/icons/help.svg",
|
||||||
|
label: "quickactions-help",
|
||||||
|
onPick: openUrlFun(
|
||||||
|
"https://support.mozilla.org/products/firefox?as=u&utm_source=inproduct"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
firefoxview: {
|
||||||
|
l10nCommands: ["quickactions-cmd-firefoxview"],
|
||||||
|
icon: "chrome://browser/skin/firefox-view.svg",
|
||||||
|
label: "quickactions-firefoxview",
|
||||||
|
onPick: () => {
|
||||||
|
lazy.BrowserWindowTracker.getTopWindow().FirefoxViewHandler.openTab();
|
||||||
|
},
|
||||||
|
},
|
||||||
inspect: {
|
inspect: {
|
||||||
l10nCommands: ["quickactions-cmd-inspector"],
|
l10nCommands: ["quickactions-cmd-inspector"],
|
||||||
icon: "chrome://devtools/skin/images/open-inspector.svg",
|
icon: "chrome://devtools/skin/images/open-inspector.svg",
|
||||||
|
|
|
@ -125,6 +125,7 @@ add_task(async function test_viewsource() {
|
||||||
"view-source:https://example.com/"
|
"view-source:https://example.com/"
|
||||||
);
|
);
|
||||||
EventUtils.synthesizeKey("KEY_Tab", {}, window);
|
EventUtils.synthesizeKey("KEY_Tab", {}, window);
|
||||||
|
EventUtils.synthesizeKey("KEY_Tab", {}, window);
|
||||||
assertAccessibilityWhenSelected("viewsource");
|
assertAccessibilityWhenSelected("viewsource");
|
||||||
EventUtils.synthesizeKey("KEY_Enter", {}, window);
|
EventUtils.synthesizeKey("KEY_Enter", {}, window);
|
||||||
const viewSourceTab = await onLoad;
|
const viewSourceTab = await onLoad;
|
||||||
|
@ -136,8 +137,10 @@ add_task(async function test_viewsource() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.equal(
|
Assert.equal(
|
||||||
hasQuickActions(window),
|
window.document.querySelector(
|
||||||
false,
|
`.urlbarView-action-btn[data-action=viewsource]`
|
||||||
|
),
|
||||||
|
null,
|
||||||
"Result for quick actions is hidden"
|
"Result for quick actions is hidden"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,26 @@ add_setup(async function setup() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const LOAD_TYPE = {
|
||||||
|
CURRENT_TAB: 1,
|
||||||
|
NEW_TAB: 2,
|
||||||
|
PRE_LOADED: 3,
|
||||||
|
};
|
||||||
|
|
||||||
let COMMANDS_TESTS = [
|
let COMMANDS_TESTS = [
|
||||||
|
{
|
||||||
|
cmd: "open view",
|
||||||
|
uri: "about:firefoxview",
|
||||||
|
loadType: LOAD_TYPE.PRE_LOADED,
|
||||||
|
testFun: async () => {
|
||||||
|
await BrowserTestUtils.waitForCondition(() => {
|
||||||
|
return (
|
||||||
|
window.gBrowser.selectedBrowser.currentURI.spec == "about:firefoxview"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
cmd: "add-ons",
|
cmd: "add-ons",
|
||||||
uri: "about:addons",
|
uri: "about:addons",
|
||||||
|
@ -52,7 +71,7 @@ let COMMANDS_TESTS = [
|
||||||
await onLoad;
|
await onLoad;
|
||||||
},
|
},
|
||||||
uri: "about:addons",
|
uri: "about:addons",
|
||||||
isNewTab: true,
|
loadType: LOAD_TYPE.NEW_TAB,
|
||||||
testFun: async () => isSelected("button[name=discover]"),
|
testFun: async () => isSelected("button[name=discover]"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -70,7 +89,7 @@ let COMMANDS_TESTS = [
|
||||||
await onLoad;
|
await onLoad;
|
||||||
},
|
},
|
||||||
uri: "about:addons",
|
uri: "about:addons",
|
||||||
isNewTab: true,
|
loadType: LOAD_TYPE.NEW_TAB,
|
||||||
testFun: async () => isSelected("button[name=plugin]"),
|
testFun: async () => isSelected("button[name=plugin]"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -88,7 +107,7 @@ let COMMANDS_TESTS = [
|
||||||
await onLoad;
|
await onLoad;
|
||||||
},
|
},
|
||||||
uri: "about:addons",
|
uri: "about:addons",
|
||||||
isNewTab: true,
|
loadType: LOAD_TYPE.NEW_TAB,
|
||||||
testFun: async () => isSelected("button[name=extension]"),
|
testFun: async () => isSelected("button[name=extension]"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -106,7 +125,7 @@ let COMMANDS_TESTS = [
|
||||||
await onLoad;
|
await onLoad;
|
||||||
},
|
},
|
||||||
uri: "about:addons",
|
uri: "about:addons",
|
||||||
isNewTab: true,
|
loadType: LOAD_TYPE.NEW_TAB,
|
||||||
testFun: async () => isSelected("button[name=theme]"),
|
testFun: async () => isSelected("button[name=theme]"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -119,7 +138,7 @@ let isSelected = async selector =>
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_pages() {
|
add_task(async function test_pages() {
|
||||||
for (const { cmd, uri, setup, isNewTab, testFun } of COMMANDS_TESTS) {
|
for (const { cmd, uri, setup, loadType, testFun } of COMMANDS_TESTS) {
|
||||||
info(`Testing ${cmd} command is triggered`);
|
info(`Testing ${cmd} command is triggered`);
|
||||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||||
|
|
||||||
|
@ -128,9 +147,10 @@ add_task(async function test_pages() {
|
||||||
await setup();
|
await setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
let onLoad = isNewTab
|
let onLoad =
|
||||||
? BrowserTestUtils.waitForNewTab(gBrowser, uri, true)
|
loadType == LOAD_TYPE.NEW_TAB
|
||||||
: BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, uri);
|
? BrowserTestUtils.waitForNewTab(gBrowser, uri, true)
|
||||||
|
: BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, uri);
|
||||||
|
|
||||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||||
window,
|
window,
|
||||||
|
@ -139,14 +159,15 @@ add_task(async function test_pages() {
|
||||||
EventUtils.synthesizeKey("KEY_Tab", {}, window);
|
EventUtils.synthesizeKey("KEY_Tab", {}, window);
|
||||||
EventUtils.synthesizeKey("KEY_Enter", {}, window);
|
EventUtils.synthesizeKey("KEY_Enter", {}, window);
|
||||||
|
|
||||||
const newTab = await onLoad;
|
const newTab =
|
||||||
|
loadType == LOAD_TYPE.PRE_LOADED ? gBrowser.selectedTab : await onLoad;
|
||||||
|
|
||||||
Assert.ok(
|
Assert.ok(
|
||||||
await testFun(),
|
await testFun(),
|
||||||
`The command "${cmd}" passed completed its test`
|
`The command "${cmd}" passed completed its test`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isNewTab) {
|
if ([LOAD_TYPE.NEW_TAB, LOAD_TYPE.PRE_LOADED].includes(loadType)) {
|
||||||
await BrowserTestUtils.removeTab(newTab);
|
await BrowserTestUtils.removeTab(newTab);
|
||||||
}
|
}
|
||||||
await BrowserTestUtils.removeTab(tab);
|
await BrowserTestUtils.removeTab(tab);
|
||||||
|
|
|
@ -131,7 +131,10 @@ const HELP_URL =
|
||||||
|
|
||||||
add_setup(async function () {
|
add_setup(async function () {
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [["browser.search.suggest.enabled", false]],
|
set: [
|
||||||
|
["browser.search.suggest.enabled", false],
|
||||||
|
["browser.urlbar.suggest.quickactions", false],
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
await QuickSuggestTestUtils.ensureQuickSuggestInit({
|
await QuickSuggestTestUtils.ensureQuickSuggestInit({
|
||||||
|
|
|
@ -30,6 +30,8 @@ skip-if = [
|
||||||
|
|
||||||
["browser_autofill_address_housenumber.js"]
|
["browser_autofill_address_housenumber.js"]
|
||||||
|
|
||||||
|
["browser_autofill_address_level.js"]
|
||||||
|
|
||||||
["browser_autofill_address_select.js"]
|
["browser_autofill_address_select.js"]
|
||||||
|
|
||||||
["browser_autofill_address_select_inexact.js"]
|
["browser_autofill_address_select_inexact.js"]
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const TEST_PROFILE_BR = {
|
||||||
|
"given-name": "Carlos",
|
||||||
|
"family-name": "Alves",
|
||||||
|
"street-address": "160 Rua Acores\nApartment 300",
|
||||||
|
"address-level1": "São Paulo",
|
||||||
|
"address-level2": "Sampletown",
|
||||||
|
"address-level3": "Somewhere",
|
||||||
|
"postal-code": "04829-310",
|
||||||
|
};
|
||||||
|
|
||||||
|
add_autofill_heuristic_tests([
|
||||||
|
{
|
||||||
|
description: "Test autofill with address-level3 autocomplete",
|
||||||
|
fixtureData: `<form>
|
||||||
|
<input id="name"/>
|
||||||
|
<input id="address-line1"/>
|
||||||
|
<input id="address-line2">
|
||||||
|
<input id="address-level1">
|
||||||
|
<input id="address-level2">
|
||||||
|
<input id="postcode">
|
||||||
|
<input id="extrainfo" autocomplete="address-level3">
|
||||||
|
</form>`,
|
||||||
|
profile: TEST_PROFILE_BR,
|
||||||
|
expectedResult: [
|
||||||
|
{
|
||||||
|
default: {
|
||||||
|
reason: "regex-heuristic",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldName: "name",
|
||||||
|
autofill:
|
||||||
|
TEST_PROFILE_BR["given-name"] +
|
||||||
|
" " +
|
||||||
|
TEST_PROFILE_BR["family-name"],
|
||||||
|
},
|
||||||
|
{ fieldName: "address-line1", autofill: "160 Rua Acores" },
|
||||||
|
{
|
||||||
|
fieldName: "address-line2",
|
||||||
|
autofill: "Apartment 300",
|
||||||
|
reason: "update-heuristic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level1",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level1"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level2",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level2"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "postal-code",
|
||||||
|
autofill: TEST_PROFILE_BR["postal-code"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level3",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level3"],
|
||||||
|
reason: "autocomplete",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Test autofill with address-level3",
|
||||||
|
fixtureData: `<form>
|
||||||
|
<input id="name"/>
|
||||||
|
<input id="address-line1"/>
|
||||||
|
<input id="address-line2">
|
||||||
|
<input id="address-level1">
|
||||||
|
<input id="address-level2">
|
||||||
|
<input id="address-level3">
|
||||||
|
<input id="postcode">
|
||||||
|
</form>`,
|
||||||
|
profile: TEST_PROFILE_BR,
|
||||||
|
expectedResult: [
|
||||||
|
{
|
||||||
|
default: {
|
||||||
|
reason: "regex-heuristic",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldName: "name",
|
||||||
|
autofill:
|
||||||
|
TEST_PROFILE_BR["given-name"] +
|
||||||
|
" " +
|
||||||
|
TEST_PROFILE_BR["family-name"],
|
||||||
|
},
|
||||||
|
{ fieldName: "address-line1", autofill: "160 Rua Acores" },
|
||||||
|
{
|
||||||
|
fieldName: "address-line2",
|
||||||
|
autofill: "Apartment 300",
|
||||||
|
reason: "update-heuristic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level1",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level1"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level2",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level2"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level3",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level3"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "postal-code",
|
||||||
|
autofill: TEST_PROFILE_BR["postal-code"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Test autofill with label for neighbourhood",
|
||||||
|
fixtureData: `<form>
|
||||||
|
<label>Nome <input id="field1"/></label>
|
||||||
|
<label>Endereço <input id="field2"/></label>
|
||||||
|
<label>Apartamento<input id="field3" autocomplete="address-line2"></label>
|
||||||
|
<label>CEP <input id="field4"></label>
|
||||||
|
<label>Bairro <input id="field5"></label>
|
||||||
|
<label>Cidade <input id="field6"></label>
|
||||||
|
<label>Estado <input id="field7"></label>
|
||||||
|
</form>`,
|
||||||
|
profile: TEST_PROFILE_BR,
|
||||||
|
expectedResult: [
|
||||||
|
{
|
||||||
|
default: {
|
||||||
|
reason: "regex-heuristic",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldName: "name",
|
||||||
|
autofill:
|
||||||
|
TEST_PROFILE_BR["given-name"] +
|
||||||
|
" " +
|
||||||
|
TEST_PROFILE_BR["family-name"],
|
||||||
|
},
|
||||||
|
{ fieldName: "address-line1", autofill: "160 Rua Acores" },
|
||||||
|
{
|
||||||
|
fieldName: "address-line2",
|
||||||
|
autofill: "Apartment 300",
|
||||||
|
reason: "autocomplete",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "postal-code",
|
||||||
|
autofill: TEST_PROFILE_BR["postal-code"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level3",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level3"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level2",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level2"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: "address-level1",
|
||||||
|
autofill: TEST_PROFILE_BR["address-level1"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -46,6 +46,8 @@ skip-if = ["os == 'mac' && os_version == '11.20' && arch == 'aarch64' && !debug"
|
||||||
|
|
||||||
["browser_parse_street_address_fields.js"]
|
["browser_parse_street_address_fields.js"]
|
||||||
|
|
||||||
|
["browser_parse_tel_fields.js"]
|
||||||
|
|
||||||
["browser_section_validation_address.js"]
|
["browser_section_validation_address.js"]
|
||||||
|
|
||||||
["browser_sections_by_name.js"]
|
["browser_sections_by_name.js"]
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/* global add_heuristic_tests */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
add_heuristic_tests([
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
"Address form with tel-country-code select element (Bug 1951890).",
|
||||||
|
fixtureData: `
|
||||||
|
<form>
|
||||||
|
<input type="text" id="name" autocomplete="name"/>
|
||||||
|
<input type="text" id="country" autocomplete="country"/>
|
||||||
|
<input type="text" id="street-address" autocomplete="street-address"/>
|
||||||
|
<input type="text" id="address-line1" autocomplete="address-line1"/>
|
||||||
|
<input type="tel" id="tel" autocomplete="tel"/>
|
||||||
|
<select name="phone_country_select">
|
||||||
|
</form>`,
|
||||||
|
expectedResult: [
|
||||||
|
{
|
||||||
|
default: {
|
||||||
|
reason: "autocomplete",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{ fieldName: "name" },
|
||||||
|
{ fieldName: "country" },
|
||||||
|
{ fieldName: "street-address" },
|
||||||
|
{ fieldName: "address-line1" },
|
||||||
|
{ fieldName: "tel" },
|
||||||
|
{ fieldName: "tel-country-code", reason: "regex-heuristic" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -61,7 +61,7 @@ add_heuristic_tests(
|
||||||
{
|
{
|
||||||
invalid: true,
|
invalid: true,
|
||||||
fields: [
|
fields: [
|
||||||
{ fieldName: "address-level2", reason: "regex-heuristic" },
|
{ fieldName: "postal-code", reason: "regex-heuristic" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -147,7 +147,7 @@ add_heuristic_tests(
|
||||||
{
|
{
|
||||||
invalid: true,
|
invalid: true,
|
||||||
fields: [
|
fields: [
|
||||||
{ fieldName: "address-level2", reason: "regex-heuristic" },
|
{ fieldName: "postal-code", reason: "regex-heuristic" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -616,9 +616,6 @@ export class BaseContent extends React.PureComponent {
|
||||||
const enabledSections = {
|
const enabledSections = {
|
||||||
topSitesEnabled: prefs["feeds.topsites"],
|
topSitesEnabled: prefs["feeds.topsites"],
|
||||||
pocketEnabled: prefs["feeds.section.topstories"],
|
pocketEnabled: prefs["feeds.section.topstories"],
|
||||||
highlightsEnabled: prefs["feeds.section.highlights"],
|
|
||||||
showSponsoredTopSitesEnabled: prefs.showSponsoredTopSites,
|
|
||||||
showSponsoredPocketEnabled: prefs.showSponsored,
|
|
||||||
showInferredPersonalizationEnabled:
|
showInferredPersonalizationEnabled:
|
||||||
prefs[PREF_INFERRED_PERSONALIZATION_USER],
|
prefs[PREF_INFERRED_PERSONALIZATION_USER],
|
||||||
showRecentSavesEnabled: prefs.showRecentSaves,
|
showRecentSavesEnabled: prefs.showRecentSaves,
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { actionCreators as ac } from "common/Actions.mjs";
|
import { actionCreators as ac } from "common/Actions.mjs";
|
||||||
import { SectionsMgmtPanel } from "../SectionsMgmtPanel/SectionsMgmtPanel";
|
import { SectionsMgmtPanel } from "../SectionsMgmtPanel/SectionsMgmtPanel";
|
||||||
import { SafeAnchor } from "../../DiscoveryStreamComponents/SafeAnchor/SafeAnchor";
|
|
||||||
import { WallpapersSection } from "../../WallpapersSection/WallpapersSection";
|
import { WallpapersSection } from "../../WallpapersSection/WallpapersSection";
|
||||||
import { WallpaperCategories } from "../../WallpapersSection/WallpaperCategories";
|
import { WallpaperCategories } from "../../WallpapersSection/WallpaperCategories";
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ export class ContentSection extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPreferenceSelect(e) {
|
onPreferenceSelect(e) {
|
||||||
// eventSource: TOP_SITES | TOP_STORIES | HIGHLIGHTS | WEATHER
|
// eventSource: WEATHER | TOP_SITES | TOP_STORIES
|
||||||
const { preference, eventSource } = e.target.dataset;
|
const { preference, eventSource } = e.target.dataset;
|
||||||
let value;
|
let value;
|
||||||
if (e.target.nodeName === "SELECT") {
|
if (e.target.nodeName === "SELECT") {
|
||||||
|
@ -86,7 +85,7 @@ export class ContentSection extends React.PureComponent {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
drawerRef.style.marginTop = "var(--space-large)";
|
drawerRef.style.marginTop = "var(--space-large)";
|
||||||
} else {
|
} else {
|
||||||
drawerRef.style.marginTop = `-${drawerHeight}px`;
|
drawerRef.style.marginTop = `-${drawerHeight + 3}px`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,14 +93,11 @@ export class ContentSection extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
enabledSections,
|
enabledSections,
|
||||||
mayHaveSponsoredTopSites,
|
|
||||||
pocketRegion,
|
pocketRegion,
|
||||||
mayHaveSponsoredStories,
|
|
||||||
mayHaveInferredPersonalization,
|
mayHaveInferredPersonalization,
|
||||||
mayHaveRecentSaves,
|
mayHaveRecentSaves,
|
||||||
mayHaveWeather,
|
mayHaveWeather,
|
||||||
openPreferences,
|
openPreferences,
|
||||||
spocMessageVariant,
|
|
||||||
wallpapersEnabled,
|
wallpapersEnabled,
|
||||||
wallpapersV2Enabled,
|
wallpapersV2Enabled,
|
||||||
activeWallpaper,
|
activeWallpaper,
|
||||||
|
@ -112,10 +108,7 @@ export class ContentSection extends React.PureComponent {
|
||||||
const {
|
const {
|
||||||
topSitesEnabled,
|
topSitesEnabled,
|
||||||
pocketEnabled,
|
pocketEnabled,
|
||||||
highlightsEnabled,
|
|
||||||
weatherEnabled,
|
weatherEnabled,
|
||||||
showSponsoredTopSitesEnabled,
|
|
||||||
showSponsoredPocketEnabled,
|
|
||||||
showInferredPersonalizationEnabled,
|
showInferredPersonalizationEnabled,
|
||||||
showRecentSavesEnabled,
|
showRecentSavesEnabled,
|
||||||
topSitesRowsCount,
|
topSitesRowsCount,
|
||||||
|
@ -144,6 +137,19 @@ export class ContentSection extends React.PureComponent {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="settings-toggles">
|
<div className="settings-toggles">
|
||||||
|
{mayHaveWeather && (
|
||||||
|
<div id="weather-section" className="section">
|
||||||
|
<moz-toggle
|
||||||
|
id="weather-toggle"
|
||||||
|
pressed={weatherEnabled || null}
|
||||||
|
onToggle={this.onPreferenceSelect}
|
||||||
|
data-preference="showWeather"
|
||||||
|
data-eventSource="WEATHER"
|
||||||
|
data-l10n-id="newtab-custom-weather-toggle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div id="shortcuts-section" className="section">
|
<div id="shortcuts-section" className="section">
|
||||||
<moz-toggle
|
<moz-toggle
|
||||||
id="shortcuts-toggle"
|
id="shortcuts-toggle"
|
||||||
|
@ -190,25 +196,6 @@ export class ContentSection extends React.PureComponent {
|
||||||
data-l10n-args='{"num": 4}'
|
data-l10n-args='{"num": 4}'
|
||||||
/>
|
/>
|
||||||
</select>
|
</select>
|
||||||
{mayHaveSponsoredTopSites && (
|
|
||||||
<div className="check-wrapper" role="presentation">
|
|
||||||
<input
|
|
||||||
id="sponsored-shortcuts"
|
|
||||||
className="customize-menu-checkbox"
|
|
||||||
disabled={!topSitesEnabled}
|
|
||||||
checked={showSponsoredTopSitesEnabled}
|
|
||||||
type="checkbox"
|
|
||||||
onChange={this.onPreferenceSelect}
|
|
||||||
data-preference="showSponsoredTopSites"
|
|
||||||
data-eventSource="SPONSORED_TOP_SITES"
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
className="customize-menu-checkbox-label"
|
|
||||||
htmlFor="sponsored-shortcuts"
|
|
||||||
data-l10n-id="newtab-custom-sponsored-sites"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -227,31 +214,14 @@ export class ContentSection extends React.PureComponent {
|
||||||
data-l10n-id="newtab-custom-stories-toggle"
|
data-l10n-id="newtab-custom-stories-toggle"
|
||||||
>
|
>
|
||||||
<div slot="nested">
|
<div slot="nested">
|
||||||
{(mayHaveSponsoredStories || mayHaveRecentSaves) && (
|
{(mayHaveRecentSaves ||
|
||||||
|
mayHaveInferredPersonalization ||
|
||||||
|
mayHaveTopicSections) && (
|
||||||
<div className="more-info-pocket-wrapper">
|
<div className="more-info-pocket-wrapper">
|
||||||
<div
|
<div
|
||||||
className="more-information"
|
className="more-information"
|
||||||
ref={this.pocketDrawerRef}
|
ref={this.pocketDrawerRef}
|
||||||
>
|
>
|
||||||
{mayHaveSponsoredStories && (
|
|
||||||
<div className="check-wrapper" role="presentation">
|
|
||||||
<input
|
|
||||||
id="sponsored-pocket"
|
|
||||||
className="customize-menu-checkbox"
|
|
||||||
disabled={!pocketEnabled}
|
|
||||||
checked={showSponsoredPocketEnabled}
|
|
||||||
type="checkbox"
|
|
||||||
onChange={this.onPreferenceSelect}
|
|
||||||
data-preference="showSponsored"
|
|
||||||
data-eventSource="POCKET_SPOCS"
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
className="customize-menu-checkbox-label"
|
|
||||||
htmlFor="sponsored-pocket"
|
|
||||||
data-l10n-id="newtab-custom-pocket-sponsored"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{mayHaveInferredPersonalization && (
|
{mayHaveInferredPersonalization && (
|
||||||
<div className="check-wrapper" role="presentation">
|
<div className="check-wrapper" role="presentation">
|
||||||
<input
|
<input
|
||||||
|
@ -302,47 +272,6 @@ export class ContentSection extends React.PureComponent {
|
||||||
</moz-toggle>
|
</moz-toggle>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div id="recent-section" className="section">
|
|
||||||
<moz-toggle
|
|
||||||
id="highlights-toggle"
|
|
||||||
pressed={highlightsEnabled || null}
|
|
||||||
onToggle={this.onPreferenceSelect}
|
|
||||||
data-preference="feeds.section.highlights"
|
|
||||||
data-eventSource="HIGHLIGHTS"
|
|
||||||
data-l10n-id="newtab-custom-recent-toggle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{mayHaveWeather && (
|
|
||||||
<div id="weather-section" className="section">
|
|
||||||
<moz-toggle
|
|
||||||
id="weather-toggle"
|
|
||||||
pressed={weatherEnabled || null}
|
|
||||||
onToggle={this.onPreferenceSelect}
|
|
||||||
data-preference="showWeather"
|
|
||||||
data-eventSource="WEATHER"
|
|
||||||
data-l10n-id="newtab-custom-weather-toggle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{pocketRegion &&
|
|
||||||
mayHaveSponsoredStories &&
|
|
||||||
spocMessageVariant === "variant-c" && (
|
|
||||||
<div className="sponsored-content-info">
|
|
||||||
<div className="icon icon-help"></div>
|
|
||||||
<div>
|
|
||||||
Sponsored content supports our mission to build a better web.{" "}
|
|
||||||
<SafeAnchor
|
|
||||||
dispatch={this.props.dispatch}
|
|
||||||
url="https://support.mozilla.org/kb/pocket-sponsored-stories-new-tabs"
|
|
||||||
>
|
|
||||||
Find out how
|
|
||||||
</SafeAnchor>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="divider" role="separator"></span>
|
<span className="divider" role="separator"></span>
|
||||||
|
|
|
@ -83,14 +83,11 @@ export class _CustomizeMenu extends React.PureComponent {
|
||||||
activeWallpaper={this.props.activeWallpaper}
|
activeWallpaper={this.props.activeWallpaper}
|
||||||
pocketRegion={this.props.pocketRegion}
|
pocketRegion={this.props.pocketRegion}
|
||||||
mayHaveTopicSections={this.props.mayHaveTopicSections}
|
mayHaveTopicSections={this.props.mayHaveTopicSections}
|
||||||
mayHaveSponsoredTopSites={this.props.mayHaveSponsoredTopSites}
|
|
||||||
mayHaveSponsoredStories={this.props.mayHaveSponsoredStories}
|
|
||||||
mayHaveInferredPersonalization={
|
mayHaveInferredPersonalization={
|
||||||
this.props.mayHaveInferredPersonalization
|
this.props.mayHaveInferredPersonalization
|
||||||
}
|
}
|
||||||
mayHaveRecentSaves={this.props.DiscoveryStream.recentSavesEnabled}
|
mayHaveRecentSaves={this.props.DiscoveryStream.recentSavesEnabled}
|
||||||
mayHaveWeather={this.props.mayHaveWeather}
|
mayHaveWeather={this.props.mayHaveWeather}
|
||||||
spocMessageVariant={this.props.spocMessageVariant}
|
|
||||||
dispatch={this.props.dispatch}
|
dispatch={this.props.dispatch}
|
||||||
exitEventFired={this.state.exitEventFired}
|
exitEventFired={this.state.exitEventFired}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -5,8 +5,21 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { SafeAnchor } from "../SafeAnchor/SafeAnchor";
|
import { SafeAnchor } from "../SafeAnchor/SafeAnchor";
|
||||||
import { ImpressionStats } from "../../DiscoveryStreamImpressionStats/ImpressionStats";
|
import { ImpressionStats } from "../../DiscoveryStreamImpressionStats/ImpressionStats";
|
||||||
import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
|
import { actionCreators as ac } from "common/Actions.mjs";
|
||||||
|
import { AdBannerContextMenu } from "../AdBannerContextMenu/AdBannerContextMenu";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A new banner ad that appears between rows of stories: leaderboard or billboard size.
|
||||||
|
*
|
||||||
|
* @param spoc
|
||||||
|
* @param dispatch
|
||||||
|
* @param firstVisibleTimestamp
|
||||||
|
* @param row
|
||||||
|
* @param type
|
||||||
|
* @param prefs
|
||||||
|
* @returns {Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
export const AdBanner = ({
|
export const AdBanner = ({
|
||||||
spoc,
|
spoc,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
@ -39,39 +52,12 @@ export const AdBanner = ({
|
||||||
|
|
||||||
const { width: imgWidth, height: imgHeight } = getDimensions(spoc.format);
|
const { width: imgWidth, height: imgHeight } = getDimensions(spoc.format);
|
||||||
|
|
||||||
const handleDismissClick = () => {
|
|
||||||
dispatch(
|
|
||||||
ac.AlsoToMain({
|
|
||||||
type: at.BLOCK_URL,
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
block_key: spoc.block_key,
|
|
||||||
fetchTimestamp: spoc.fetchTimestamp,
|
|
||||||
flight_id: spoc.flight_id,
|
|
||||||
format: spoc.format,
|
|
||||||
id: spoc.id,
|
|
||||||
card_type: "spoc",
|
|
||||||
is_pocket_card: true,
|
|
||||||
position: row,
|
|
||||||
sponsor: spoc.sponsor,
|
|
||||||
title: spoc.title,
|
|
||||||
url: spoc.url || spoc.shim.url,
|
|
||||||
personalization_models: spoc.personalization_models,
|
|
||||||
priority: spoc.priority,
|
|
||||||
score: spoc.score,
|
|
||||||
alt_text: spoc.alt_text,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLinkClick = () => {
|
const onLinkClick = () => {
|
||||||
dispatch(
|
dispatch(
|
||||||
ac.DiscoveryStreamUserEvent({
|
ac.DiscoveryStreamUserEvent({
|
||||||
event: "CLICK",
|
event: "CLICK",
|
||||||
source: type.toUpperCase(),
|
source: type.toUpperCase(),
|
||||||
// Banner ads dont have a position, but a row number
|
// Banner ads don't have a position, but a row number
|
||||||
action_position: row,
|
action_position: row,
|
||||||
value: {
|
value: {
|
||||||
card_type: "spoc",
|
card_type: "spoc",
|
||||||
|
@ -98,13 +84,12 @@ export const AdBanner = ({
|
||||||
return (
|
return (
|
||||||
<aside className="ad-banner-wrapper" style={{ gridRow: clampedRow }}>
|
<aside className="ad-banner-wrapper" style={{ gridRow: clampedRow }}>
|
||||||
<div className={`ad-banner-inner ${spoc.format}`}>
|
<div className={`ad-banner-inner ${spoc.format}`}>
|
||||||
<div className="ad-banner-dismiss">
|
<AdBannerContextMenu
|
||||||
<button
|
dispatch={dispatch}
|
||||||
className="icon icon-dismiss"
|
spoc={spoc}
|
||||||
onClick={handleDismissClick}
|
position={row}
|
||||||
data-l10n-id="newtab-toast-dismiss-button"
|
type={type}
|
||||||
></button>
|
/>
|
||||||
</div>
|
|
||||||
<SafeAnchor
|
<SafeAnchor
|
||||||
className="ad-banner-link"
|
className="ad-banner-link"
|
||||||
url={spoc.url}
|
url={spoc.url}
|
||||||
|
|
|
@ -33,24 +33,6 @@
|
||||||
.ad-banner-inner {
|
.ad-banner-inner {
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
|
|
||||||
.ad-banner-dismiss {
|
|
||||||
// Contrast fix for users who have wallpapers set
|
|
||||||
@include wallpaper-contrast-fix;
|
|
||||||
|
|
||||||
margin-block: 0 var(--space-small);
|
|
||||||
margin-inline: 0 var(--space-xxsmall);
|
|
||||||
text-align: end;
|
|
||||||
|
|
||||||
.icon-dismiss {
|
|
||||||
background-size: var(--size-item-small);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-dismiss:hover {
|
|
||||||
background-color: var(--newtab-button-hover-background);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.leaderboard {
|
&.leaderboard {
|
||||||
max-width: var(--leaderboard-width);
|
max-width: var(--leaderboard-width);
|
||||||
|
|
||||||
|
@ -74,7 +56,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.billboard {
|
&.billboard {
|
||||||
min-width: var(--billboard-width);
|
width: var(--billboard-width);
|
||||||
|
|
||||||
.ad-banner-content {
|
.ad-banner-content {
|
||||||
height: var(--billboard-height);
|
height: var(--billboard-height);
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { actionCreators as ac } from "common/Actions.mjs";
|
||||||
|
import { LinkMenu } from "../../LinkMenu/LinkMenu";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A context menu for IAB banners (e.g. billboard, leaderboard).
|
||||||
|
*
|
||||||
|
* Note: MREC ad formats and sponsored stories share the context menu with
|
||||||
|
* other cards: make sure you also look at DSLinkMenu component
|
||||||
|
* to keep any updates to ad-related context menu items in sync.
|
||||||
|
*
|
||||||
|
* @param dispatch
|
||||||
|
* @param spoc
|
||||||
|
* @param position
|
||||||
|
* @param type
|
||||||
|
* @returns {Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function AdBannerContextMenu({ dispatch, spoc, position, type }) {
|
||||||
|
const ADBANNER_CONTEXT_MENU_OPTIONS = [
|
||||||
|
"BlockAdUrl",
|
||||||
|
"ManageSponsoredContent",
|
||||||
|
"OurSponsorsAndYourPrivacy",
|
||||||
|
];
|
||||||
|
|
||||||
|
const [showContextMenu, setShowContextMenu] = useState(false);
|
||||||
|
|
||||||
|
const onClick = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
setShowContextMenu(!showContextMenu);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUpdate = () => {
|
||||||
|
setShowContextMenu(!showContextMenu);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ads-context-menu-wrapper">
|
||||||
|
<div className="ads-context-menu">
|
||||||
|
<moz-button
|
||||||
|
type="icon"
|
||||||
|
size="default"
|
||||||
|
iconsrc="chrome://global/skin/icons/more.svg"
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
{showContextMenu && (
|
||||||
|
<LinkMenu
|
||||||
|
onUpdate={onUpdate}
|
||||||
|
dispatch={dispatch}
|
||||||
|
options={ADBANNER_CONTEXT_MENU_OPTIONS}
|
||||||
|
shouldSendImpressionStats={true}
|
||||||
|
userEvent={ac.DiscoveryStreamUserEvent}
|
||||||
|
site={{
|
||||||
|
// Props we want to pass on for new ad types that come from Unified Ads API
|
||||||
|
block_key: spoc.block_key,
|
||||||
|
fetchTimestamp: spoc.fetchTimestamp,
|
||||||
|
flight_id: spoc.flight_id,
|
||||||
|
format: spoc.format,
|
||||||
|
id: spoc.id,
|
||||||
|
guid: spoc.guid,
|
||||||
|
card_type: "spoc",
|
||||||
|
// required to record telemetry for an action, see handleBlockUrl in TelemetryFeed.sys.mjs
|
||||||
|
is_pocket_card: true,
|
||||||
|
position,
|
||||||
|
sponsor: spoc.sponsor,
|
||||||
|
title: spoc.title,
|
||||||
|
url: spoc.url || spoc.shim.url,
|
||||||
|
personalization_models: spoc.personalization_models,
|
||||||
|
priority: spoc.priority,
|
||||||
|
score: spoc.score,
|
||||||
|
alt_text: spoc.alt_text,
|
||||||
|
shim: spoc.shim,
|
||||||
|
}}
|
||||||
|
index={position}
|
||||||
|
source={type.toUpperCase()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
.ads-context-menu-wrapper {
|
||||||
|
// Contrast fix for users who have wallpapers set
|
||||||
|
@include wallpaper-contrast-fix;
|
||||||
|
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ads-context-menu {
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
> moz-button {
|
||||||
|
padding-block-end: var(--space-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transparent on light backgrounds as specified in Figma designs
|
||||||
|
// and default moz-button colours on dark backgrounds.
|
||||||
|
> moz-button::part(button) {
|
||||||
|
background-color: light-dark(transparent, var(--button-background-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu {
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
/* Position the menu just under and to the right of the context menu button */
|
||||||
|
top: calc(2.25 * var(--size-item-small));
|
||||||
|
inset-inline-start: calc(-12.25 * var(--size-item-small));
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,12 @@ import { CSSTransition } from "react-transition-group";
|
||||||
const PREF_WALLPAPER_UPLOADED_PREVIOUSLY =
|
const PREF_WALLPAPER_UPLOADED_PREVIOUSLY =
|
||||||
"newtabWallpapers.customWallpaper.uploadedPreviously";
|
"newtabWallpapers.customWallpaper.uploadedPreviously";
|
||||||
|
|
||||||
|
const PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE =
|
||||||
|
"newtabWallpapers.customWallpaper.fileSize";
|
||||||
|
|
||||||
|
const PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE_ENABLED =
|
||||||
|
"newtabWallpapers.customWallpaper.fileSize.enabled";
|
||||||
|
|
||||||
// Returns a function will not be continuously triggered when called. The
|
// Returns a function will not be continuously triggered when called. The
|
||||||
// function will be triggered if called again after `wait` milliseconds.
|
// function will be triggered if called again after `wait` milliseconds.
|
||||||
function debounce(func, wait) {
|
function debounce(func, wait) {
|
||||||
|
@ -52,6 +58,7 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
showColorPicker: false,
|
showColorPicker: false,
|
||||||
inputType: "radio",
|
inputType: "radio",
|
||||||
activeId: null,
|
activeId: null,
|
||||||
|
isCustomWallpaperError: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +128,13 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
|
|
||||||
this.props.setPref("newtabWallpapers.wallpaper", id);
|
this.props.setPref("newtabWallpapers.wallpaper", id);
|
||||||
|
|
||||||
|
const uploadedPreviously =
|
||||||
|
this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
||||||
|
|
||||||
this.handleUserEvent(at.WALLPAPER_CLICK, {
|
this.handleUserEvent(at.WALLPAPER_CLICK, {
|
||||||
selected_wallpaper: id,
|
selected_wallpaper: id,
|
||||||
had_previous_wallpaper: !!this.props.activeWallpaper,
|
had_previous_wallpaper: !!this.props.activeWallpaper,
|
||||||
|
had_uploaded_previously: !!uploadedPreviously,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,13 +221,14 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReset() {
|
handleReset() {
|
||||||
this.props.setPref("newtabWallpapers.wallpaper", "");
|
|
||||||
|
|
||||||
const uploadedPreviously =
|
const uploadedPreviously =
|
||||||
this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
||||||
|
|
||||||
if (uploadedPreviously) {
|
const selectedWallpaper =
|
||||||
this.props.setPref(PREF_WALLPAPER_UPLOADED_PREVIOUSLY, false);
|
this.props.Prefs.values["newtabWallpapers.wallpaper"];
|
||||||
|
|
||||||
|
// If a custom wallpaper is set, remove it
|
||||||
|
if (selectedWallpaper === "custom") {
|
||||||
this.props.dispatch(
|
this.props.dispatch(
|
||||||
ac.OnlyToMain({
|
ac.OnlyToMain({
|
||||||
type: at.WALLPAPER_REMOVE_UPLOAD,
|
type: at.WALLPAPER_REMOVE_UPLOAD,
|
||||||
|
@ -224,9 +236,14 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset active wallpaper
|
||||||
|
this.props.setPref("newtabWallpapers.wallpaper", "");
|
||||||
|
|
||||||
|
// Fire WALLPAPER_CLICK telemetry event
|
||||||
this.handleUserEvent(at.WALLPAPER_CLICK, {
|
this.handleUserEvent(at.WALLPAPER_CLICK, {
|
||||||
selected_wallpaper: "none",
|
selected_wallpaper: "none",
|
||||||
had_previous_wallpaper: !!this.props.activeWallpaper,
|
had_previous_wallpaper: !!this.props.activeWallpaper,
|
||||||
|
had_uploaded_previously: !!uploadedPreviously,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,31 +272,42 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
|
|
||||||
// Custom wallpaper image upload
|
// Custom wallpaper image upload
|
||||||
async handleUpload() {
|
async handleUpload() {
|
||||||
// TODO: Bug 1943663: Add telemetry
|
const wallpaperUploadMaxFileSizeEnabled =
|
||||||
|
this.props.Prefs.values[PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE_ENABLED];
|
||||||
|
|
||||||
// TODO: Bug 1947813: Add image upload error states/UI
|
const wallpaperUploadMaxFileSize =
|
||||||
|
this.props.Prefs.values[PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE];
|
||||||
|
|
||||||
// TODO: Once Bug 1947813 has landed, we may need a separate event
|
|
||||||
// for selecting previously uploaded wallpaper, rather than uploading a new one.
|
|
||||||
// The plan would be to reuse at.WALLPAPER_CLICK for this use case
|
|
||||||
const uploadedPreviously =
|
const uploadedPreviously =
|
||||||
this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
||||||
|
|
||||||
this.handleUserEvent(at.WALLPAPER_UPLOAD, {
|
|
||||||
had_uploaded_previously: !!uploadedPreviously,
|
|
||||||
had_previous_wallpaper: !!this.props.activeWallpaper,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.setPref(PREF_WALLPAPER_UPLOADED_PREVIOUSLY, true);
|
|
||||||
|
|
||||||
// Create a file input since category buttons are radio inputs
|
// Create a file input since category buttons are radio inputs
|
||||||
const fileInput = document.createElement("input");
|
const fileInput = document.createElement("input");
|
||||||
fileInput.type = "file";
|
fileInput.type = "file";
|
||||||
fileInput.accept = "image/*"; // only allow image files
|
fileInput.accept = "image/*"; // only allow image files
|
||||||
|
|
||||||
|
// Catch cancel events
|
||||||
|
fileInput.oncancel = async () => {
|
||||||
|
this.setState({ isCustomWallpaperError: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset error state when user begins file selection
|
||||||
|
this.setState({ isCustomWallpaperError: false });
|
||||||
|
|
||||||
|
// Fire when user selects a file
|
||||||
fileInput.onchange = async event => {
|
fileInput.onchange = async event => {
|
||||||
const [file] = event.target.files;
|
const [file] = event.target.files;
|
||||||
|
|
||||||
|
// Limit image uploaded to a maximum file size if enabled
|
||||||
|
// Note: The max file size pref (customWallpaper.fileSize) is converted to megabytes (MB)
|
||||||
|
// Example: if pref value is 5, max file size is 5 MB
|
||||||
|
const maxSize = wallpaperUploadMaxFileSize * 1024 * 1024;
|
||||||
|
if (wallpaperUploadMaxFileSizeEnabled && file && file.size > maxSize) {
|
||||||
|
console.error("File size exceeds limit");
|
||||||
|
this.setState({ isCustomWallpaperError: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
this.props.dispatch(
|
this.props.dispatch(
|
||||||
ac.OnlyToMain({
|
ac.OnlyToMain({
|
||||||
|
@ -287,6 +315,19 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
data: file,
|
data: file,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Set active wallpaper ID to "custom"
|
||||||
|
this.props.setPref("newtabWallpapers.wallpaper", "custom");
|
||||||
|
|
||||||
|
// Update the uploadedPreviously pref to TRUE
|
||||||
|
// Note: this pref used for telemetry. Do not reset to false.
|
||||||
|
this.props.setPref(PREF_WALLPAPER_UPLOADED_PREVIOUSLY, true);
|
||||||
|
|
||||||
|
this.handleUserEvent(at.WALLPAPER_CLICK, {
|
||||||
|
selected_wallpaper: "custom",
|
||||||
|
had_previous_wallpaper: !!this.props.activeWallpaper,
|
||||||
|
had_uploaded_previously: !!uploadedPreviously,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -332,6 +373,8 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
let filteredWallpapers = wallpaperList.filter(
|
let filteredWallpapers = wallpaperList.filter(
|
||||||
wallpaper => wallpaper.category === activeCategory
|
wallpaper => wallpaper.category === activeCategory
|
||||||
);
|
);
|
||||||
|
const wallpaperUploadMaxFileSize =
|
||||||
|
this.props.Prefs.values[PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE];
|
||||||
|
|
||||||
function reduceColorsToFitCustomColorInput(arr) {
|
function reduceColorsToFitCustomColorInput(arr) {
|
||||||
// Reduce the amount of custom colors to make space for the custom color picker
|
// Reduce the amount of custom colors to make space for the custom color picker
|
||||||
|
@ -491,6 +534,9 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
: `wallpaper-input theme-custom-wallpaper`
|
: `wallpaper-input theme-custom-wallpaper`
|
||||||
}
|
}
|
||||||
tabIndex={index === 0 ? 0 : -1}
|
tabIndex={index === 0 ? 0 : -1}
|
||||||
|
{...(category === "custom-wallpaper"
|
||||||
|
? { "aria-errormessage": "customWallpaperError" }
|
||||||
|
: {})}
|
||||||
/>
|
/>
|
||||||
<label htmlFor={category} data-l10n-id={fluent_id}>
|
<label htmlFor={category} data-l10n-id={fluent_id}>
|
||||||
{fluent_id}
|
{fluent_id}
|
||||||
|
@ -499,6 +545,15 @@ export class _WallpaperCategories extends React.PureComponent {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
{this.state.isCustomWallpaperError && (
|
||||||
|
<div className="custom-wallpaper-error" id="customWallpaperError">
|
||||||
|
<span className="icon icon-info"></span>
|
||||||
|
<span
|
||||||
|
data-l10n-id="newtab-wallpaper-error-max-file-size"
|
||||||
|
data-l10n-args={`{"file_size": ${wallpaperUploadMaxFileSize}}`}
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
|
|
|
@ -287,3 +287,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bug 1947813 - Custom Upload Error Message
|
||||||
|
.custom-wallpaper-error {
|
||||||
|
padding-block-start: var(--space-xlarge);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-small);
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: var(--button-size-icon-small);
|
||||||
|
height: var(--button-size-icon-small);
|
||||||
|
fill: var(--icon-color-critical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -151,6 +151,28 @@ export const LinkMenuOptions = {
|
||||||
userEvent: "BLOCK",
|
userEvent: "BLOCK",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// This is the "Dismiss" action for leaderboard/billboard ads.
|
||||||
|
BlockAdUrl: (site, pos, eventSource) => ({
|
||||||
|
id: "newtab-menu-dismiss",
|
||||||
|
icon: "dismiss",
|
||||||
|
action: ac.AlsoToMain({
|
||||||
|
type: at.BLOCK_URL,
|
||||||
|
data: [site],
|
||||||
|
}),
|
||||||
|
impression: ac.ImpressionStats({
|
||||||
|
source: eventSource,
|
||||||
|
block: 0,
|
||||||
|
tiles: [
|
||||||
|
{
|
||||||
|
id: site.guid,
|
||||||
|
pos,
|
||||||
|
...(site.shim && site.shim.save ? { shim: site.shim.save } : {}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
userEvent: "BLOCK",
|
||||||
|
}),
|
||||||
|
|
||||||
// This is an option for web extentions which will result in remove items from
|
// This is an option for web extentions which will result in remove items from
|
||||||
// memory and notify the web extenion, rather than using the built-in block list.
|
// memory and notify the web extenion, rather than using the built-in block list.
|
||||||
WebExtDismiss: (site, index, eventSource) => ({
|
WebExtDismiss: (site, index, eventSource) => ({
|
||||||
|
|
|
@ -194,6 +194,7 @@ input {
|
||||||
@import '../components/DiscoveryStreamComponents/TopicSelection/TopicSelection';
|
@import '../components/DiscoveryStreamComponents/TopicSelection/TopicSelection';
|
||||||
@import '../components/DiscoveryStreamComponents/ListFeed/ListFeed';
|
@import '../components/DiscoveryStreamComponents/ListFeed/ListFeed';
|
||||||
@import '../components/DiscoveryStreamComponents/AdBanner/AdBanner';
|
@import '../components/DiscoveryStreamComponents/AdBanner/AdBanner';
|
||||||
|
@import '../components/DiscoveryStreamComponents/AdBannerContextMenu/AdBannerContextMenu';
|
||||||
@import '../components/DiscoveryStreamComponents/SectionContextMenu/SectionContextMenu';
|
@import '../components/DiscoveryStreamComponents/SectionContextMenu/SectionContextMenu';
|
||||||
@import '../components/DiscoveryStreamComponents/InterestPicker/InterestPicker';
|
@import '../components/DiscoveryStreamComponents/InterestPicker/InterestPicker';
|
||||||
|
|
||||||
|
|
|
@ -2791,6 +2791,19 @@ main section {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-wallpaper-error {
|
||||||
|
padding-block-start: var(--space-xlarge);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-small);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.custom-wallpaper-error .icon {
|
||||||
|
width: var(--button-size-icon-small);
|
||||||
|
height: var(--button-size-icon-small);
|
||||||
|
fill: var(--icon-color-critical);
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--newtab-weather-content-font-size: 11px;
|
--newtab-weather-content-font-size: 11px;
|
||||||
--newtab-weather-sponsor-font-size: 8px;
|
--newtab-weather-sponsor-font-size: 8px;
|
||||||
|
@ -8024,24 +8037,6 @@ main section {
|
||||||
.ad-banner-wrapper .ad-banner-inner {
|
.ad-banner-wrapper .ad-banner-inner {
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
.ad-banner-wrapper .ad-banner-inner .ad-banner-dismiss {
|
|
||||||
margin-block: 0 var(--space-small);
|
|
||||||
margin-inline: 0 var(--space-xxsmall);
|
|
||||||
text-align: end;
|
|
||||||
}
|
|
||||||
.lightWallpaper .ad-banner-wrapper .ad-banner-inner .ad-banner-dismiss {
|
|
||||||
color-scheme: light;
|
|
||||||
}
|
|
||||||
.darkWallpaper .ad-banner-wrapper .ad-banner-inner .ad-banner-dismiss {
|
|
||||||
color-scheme: dark;
|
|
||||||
}
|
|
||||||
.ad-banner-wrapper .ad-banner-inner .ad-banner-dismiss .icon-dismiss {
|
|
||||||
background-size: var(--size-item-small);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
.ad-banner-wrapper .ad-banner-inner .ad-banner-dismiss .icon-dismiss:hover {
|
|
||||||
background-color: var(--newtab-button-hover-background);
|
|
||||||
}
|
|
||||||
.ad-banner-wrapper .ad-banner-inner.leaderboard {
|
.ad-banner-wrapper .ad-banner-inner.leaderboard {
|
||||||
max-width: var(--leaderboard-width);
|
max-width: var(--leaderboard-width);
|
||||||
}
|
}
|
||||||
|
@ -8062,7 +8057,7 @@ main section {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ad-banner-wrapper .ad-banner-inner.billboard {
|
.ad-banner-wrapper .ad-banner-inner.billboard {
|
||||||
min-width: var(--billboard-width);
|
width: var(--billboard-width);
|
||||||
}
|
}
|
||||||
.ad-banner-wrapper .ad-banner-inner.billboard .ad-banner-content {
|
.ad-banner-wrapper .ad-banner-inner.billboard .ad-banner-content {
|
||||||
height: var(--billboard-height);
|
height: var(--billboard-height);
|
||||||
|
@ -8092,6 +8087,33 @@ main section {
|
||||||
color: var(--newtab-contextual-text-secondary-color);
|
color: var(--newtab-contextual-text-secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ads-context-menu-wrapper {
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
.lightWallpaper .ads-context-menu-wrapper {
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
.darkWallpaper .ads-context-menu-wrapper {
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ads-context-menu {
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ads-context-menu > moz-button {
|
||||||
|
padding-block-end: var(--space-small);
|
||||||
|
}
|
||||||
|
.ads-context-menu > moz-button::part(button) {
|
||||||
|
background-color: light-dark(transparent, var(--button-background-color));
|
||||||
|
}
|
||||||
|
.ads-context-menu .context-menu {
|
||||||
|
width: auto;
|
||||||
|
/* Position the menu just under and to the right of the context menu button */
|
||||||
|
top: calc(2.25 * var(--size-item-small));
|
||||||
|
inset-inline-start: calc(-12.25 * var(--size-item-small));
|
||||||
|
}
|
||||||
|
|
||||||
.section-context-menu {
|
.section-context-menu {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1828,6 +1828,28 @@ const LinkMenuOptions = {
|
||||||
userEvent: "BLOCK",
|
userEvent: "BLOCK",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// This is the "Dismiss" action for leaderboard/billboard ads.
|
||||||
|
BlockAdUrl: (site, pos, eventSource) => ({
|
||||||
|
id: "newtab-menu-dismiss",
|
||||||
|
icon: "dismiss",
|
||||||
|
action: actionCreators.AlsoToMain({
|
||||||
|
type: actionTypes.BLOCK_URL,
|
||||||
|
data: [site],
|
||||||
|
}),
|
||||||
|
impression: actionCreators.ImpressionStats({
|
||||||
|
source: eventSource,
|
||||||
|
block: 0,
|
||||||
|
tiles: [
|
||||||
|
{
|
||||||
|
id: site.guid,
|
||||||
|
pos,
|
||||||
|
...(site.shim && site.shim.save ? { shim: site.shim.save } : {}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
userEvent: "BLOCK",
|
||||||
|
}),
|
||||||
|
|
||||||
// This is an option for web extentions which will result in remove items from
|
// This is an option for web extentions which will result in remove items from
|
||||||
// memory and notify the web extenion, rather than using the built-in block list.
|
// memory and notify the web extenion, rather than using the built-in block list.
|
||||||
WebExtDismiss: (site, index, eventSource) => ({
|
WebExtDismiss: (site, index, eventSource) => ({
|
||||||
|
@ -4284,6 +4306,84 @@ function ListFeed({
|
||||||
}, ctaCopy)))));
|
}, ctaCopy)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/AdBannerContextMenu/AdBannerContextMenu.jsx
|
||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A context menu for IAB banners (e.g. billboard, leaderboard).
|
||||||
|
*
|
||||||
|
* Note: MREC ad formats and sponsored stories share the context menu with
|
||||||
|
* other cards: make sure you also look at DSLinkMenu component
|
||||||
|
* to keep any updates to ad-related context menu items in sync.
|
||||||
|
*
|
||||||
|
* @param dispatch
|
||||||
|
* @param spoc
|
||||||
|
* @param position
|
||||||
|
* @param type
|
||||||
|
* @returns {Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdBannerContextMenu({
|
||||||
|
dispatch,
|
||||||
|
spoc,
|
||||||
|
position,
|
||||||
|
type
|
||||||
|
}) {
|
||||||
|
const ADBANNER_CONTEXT_MENU_OPTIONS = ["BlockAdUrl", "ManageSponsoredContent", "OurSponsorsAndYourPrivacy"];
|
||||||
|
const [showContextMenu, setShowContextMenu] = (0,external_React_namespaceObject.useState)(false);
|
||||||
|
const onClick = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
setShowContextMenu(!showContextMenu);
|
||||||
|
};
|
||||||
|
const onUpdate = () => {
|
||||||
|
setShowContextMenu(!showContextMenu);
|
||||||
|
};
|
||||||
|
return /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
|
className: "ads-context-menu-wrapper"
|
||||||
|
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
|
className: "ads-context-menu"
|
||||||
|
}, /*#__PURE__*/external_React_default().createElement("moz-button", {
|
||||||
|
type: "icon",
|
||||||
|
size: "default",
|
||||||
|
iconsrc: "chrome://global/skin/icons/more.svg",
|
||||||
|
onClick: onClick
|
||||||
|
}), showContextMenu && /*#__PURE__*/external_React_default().createElement(LinkMenu, {
|
||||||
|
onUpdate: onUpdate,
|
||||||
|
dispatch: dispatch,
|
||||||
|
options: ADBANNER_CONTEXT_MENU_OPTIONS,
|
||||||
|
shouldSendImpressionStats: true,
|
||||||
|
userEvent: actionCreators.DiscoveryStreamUserEvent,
|
||||||
|
site: {
|
||||||
|
// Props we want to pass on for new ad types that come from Unified Ads API
|
||||||
|
block_key: spoc.block_key,
|
||||||
|
fetchTimestamp: spoc.fetchTimestamp,
|
||||||
|
flight_id: spoc.flight_id,
|
||||||
|
format: spoc.format,
|
||||||
|
id: spoc.id,
|
||||||
|
guid: spoc.guid,
|
||||||
|
card_type: "spoc",
|
||||||
|
// required to record telemetry for an action, see handleBlockUrl in TelemetryFeed.sys.mjs
|
||||||
|
is_pocket_card: true,
|
||||||
|
position,
|
||||||
|
sponsor: spoc.sponsor,
|
||||||
|
title: spoc.title,
|
||||||
|
url: spoc.url || spoc.shim.url,
|
||||||
|
personalization_models: spoc.personalization_models,
|
||||||
|
priority: spoc.priority,
|
||||||
|
score: spoc.score,
|
||||||
|
alt_text: spoc.alt_text,
|
||||||
|
shim: spoc.shim
|
||||||
|
},
|
||||||
|
index: position,
|
||||||
|
source: type.toUpperCase()
|
||||||
|
})));
|
||||||
|
}
|
||||||
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/AdBanner/AdBanner.jsx
|
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/AdBanner/AdBanner.jsx
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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,
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
@ -4293,6 +4393,20 @@ function ListFeed({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A new banner ad that appears between rows of stories: leaderboard or billboard size.
|
||||||
|
*
|
||||||
|
* @param spoc
|
||||||
|
* @param dispatch
|
||||||
|
* @param firstVisibleTimestamp
|
||||||
|
* @param row
|
||||||
|
* @param type
|
||||||
|
* @param prefs
|
||||||
|
* @returns {Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
const AdBanner = ({
|
const AdBanner = ({
|
||||||
spoc,
|
spoc,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
@ -4325,33 +4439,11 @@ const AdBanner = ({
|
||||||
width: imgWidth,
|
width: imgWidth,
|
||||||
height: imgHeight
|
height: imgHeight
|
||||||
} = getDimensions(spoc.format);
|
} = getDimensions(spoc.format);
|
||||||
const handleDismissClick = () => {
|
|
||||||
dispatch(actionCreators.AlsoToMain({
|
|
||||||
type: actionTypes.BLOCK_URL,
|
|
||||||
data: [{
|
|
||||||
block_key: spoc.block_key,
|
|
||||||
fetchTimestamp: spoc.fetchTimestamp,
|
|
||||||
flight_id: spoc.flight_id,
|
|
||||||
format: spoc.format,
|
|
||||||
id: spoc.id,
|
|
||||||
card_type: "spoc",
|
|
||||||
is_pocket_card: true,
|
|
||||||
position: row,
|
|
||||||
sponsor: spoc.sponsor,
|
|
||||||
title: spoc.title,
|
|
||||||
url: spoc.url || spoc.shim.url,
|
|
||||||
personalization_models: spoc.personalization_models,
|
|
||||||
priority: spoc.priority,
|
|
||||||
score: spoc.score,
|
|
||||||
alt_text: spoc.alt_text
|
|
||||||
}]
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
const onLinkClick = () => {
|
const onLinkClick = () => {
|
||||||
dispatch(actionCreators.DiscoveryStreamUserEvent({
|
dispatch(actionCreators.DiscoveryStreamUserEvent({
|
||||||
event: "CLICK",
|
event: "CLICK",
|
||||||
source: type.toUpperCase(),
|
source: type.toUpperCase(),
|
||||||
// Banner ads dont have a position, but a row number
|
// Banner ads don't have a position, but a row number
|
||||||
action_position: row,
|
action_position: row,
|
||||||
value: {
|
value: {
|
||||||
card_type: "spoc",
|
card_type: "spoc",
|
||||||
|
@ -4380,13 +4472,12 @@ const AdBanner = ({
|
||||||
}
|
}
|
||||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
className: `ad-banner-inner ${spoc.format}`
|
className: `ad-banner-inner ${spoc.format}`
|
||||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
}, /*#__PURE__*/external_React_default().createElement(AdBannerContextMenu, {
|
||||||
className: "ad-banner-dismiss"
|
dispatch: dispatch,
|
||||||
}, /*#__PURE__*/external_React_default().createElement("button", {
|
spoc: spoc,
|
||||||
className: "icon icon-dismiss",
|
position: row,
|
||||||
onClick: handleDismissClick,
|
type: type
|
||||||
"data-l10n-id": "newtab-toast-dismiss-button"
|
}), /*#__PURE__*/external_React_default().createElement(SafeAnchor, {
|
||||||
})), /*#__PURE__*/external_React_default().createElement(SafeAnchor, {
|
|
||||||
className: "ad-banner-link",
|
className: "ad-banner-link",
|
||||||
url: spoc.url,
|
url: spoc.url,
|
||||||
title: spoc.title,
|
title: spoc.title,
|
||||||
|
@ -11351,6 +11442,7 @@ const WallpapersSection = (0,external_ReactRedux_namespaceObject.connect)(state
|
||||||
};
|
};
|
||||||
})(_WallpapersSection);
|
})(_WallpapersSection);
|
||||||
;// CONCATENATED MODULE: ./content-src/components/WallpapersSection/WallpaperCategories.jsx
|
;// CONCATENATED MODULE: ./content-src/components/WallpapersSection/WallpaperCategories.jsx
|
||||||
|
function WallpaperCategories_extends() { WallpaperCategories_extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return WallpaperCategories_extends.apply(this, arguments); }
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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,
|
* 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
@ -11361,6 +11453,8 @@ const WallpapersSection = (0,external_ReactRedux_namespaceObject.connect)(state
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
|
|
||||||
const PREF_WALLPAPER_UPLOADED_PREVIOUSLY = "newtabWallpapers.customWallpaper.uploadedPreviously";
|
const PREF_WALLPAPER_UPLOADED_PREVIOUSLY = "newtabWallpapers.customWallpaper.uploadedPreviously";
|
||||||
|
const PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE = "newtabWallpapers.customWallpaper.fileSize";
|
||||||
|
const PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE_ENABLED = "newtabWallpapers.customWallpaper.fileSize.enabled";
|
||||||
|
|
||||||
// Returns a function will not be continuously triggered when called. The
|
// Returns a function will not be continuously triggered when called. The
|
||||||
// function will be triggered if called again after `wait` milliseconds.
|
// function will be triggered if called again after `wait` milliseconds.
|
||||||
|
@ -11399,7 +11493,8 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
activeCategoryFluentID: null,
|
activeCategoryFluentID: null,
|
||||||
showColorPicker: false,
|
showColorPicker: false,
|
||||||
inputType: "radio",
|
inputType: "radio",
|
||||||
activeId: null
|
activeId: null,
|
||||||
|
isCustomWallpaperError: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -11456,9 +11551,11 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
id = `solid-color-picker-${event.target.value}`;
|
id = `solid-color-picker-${event.target.value}`;
|
||||||
}
|
}
|
||||||
this.props.setPref("newtabWallpapers.wallpaper", id);
|
this.props.setPref("newtabWallpapers.wallpaper", id);
|
||||||
|
const uploadedPreviously = this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
||||||
this.handleUserEvent(actionTypes.WALLPAPER_CLICK, {
|
this.handleUserEvent(actionTypes.WALLPAPER_CLICK, {
|
||||||
selected_wallpaper: id,
|
selected_wallpaper: id,
|
||||||
had_previous_wallpaper: !!this.props.activeWallpaper
|
had_previous_wallpaper: !!this.props.activeWallpaper,
|
||||||
|
had_uploaded_previously: !!uploadedPreviously
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11525,17 +11622,24 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
this.wallpaperRef[nextIndex].click();
|
this.wallpaperRef[nextIndex].click();
|
||||||
}
|
}
|
||||||
handleReset() {
|
handleReset() {
|
||||||
this.props.setPref("newtabWallpapers.wallpaper", "");
|
|
||||||
const uploadedPreviously = this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
const uploadedPreviously = this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
||||||
if (uploadedPreviously) {
|
const selectedWallpaper = this.props.Prefs.values["newtabWallpapers.wallpaper"];
|
||||||
this.props.setPref(PREF_WALLPAPER_UPLOADED_PREVIOUSLY, false);
|
|
||||||
|
// If a custom wallpaper is set, remove it
|
||||||
|
if (selectedWallpaper === "custom") {
|
||||||
this.props.dispatch(actionCreators.OnlyToMain({
|
this.props.dispatch(actionCreators.OnlyToMain({
|
||||||
type: actionTypes.WALLPAPER_REMOVE_UPLOAD
|
type: actionTypes.WALLPAPER_REMOVE_UPLOAD
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset active wallpaper
|
||||||
|
this.props.setPref("newtabWallpapers.wallpaper", "");
|
||||||
|
|
||||||
|
// Fire WALLPAPER_CLICK telemetry event
|
||||||
this.handleUserEvent(actionTypes.WALLPAPER_CLICK, {
|
this.handleUserEvent(actionTypes.WALLPAPER_CLICK, {
|
||||||
selected_wallpaper: "none",
|
selected_wallpaper: "none",
|
||||||
had_previous_wallpaper: !!this.props.activeWallpaper
|
had_previous_wallpaper: !!this.props.activeWallpaper,
|
||||||
|
had_uploaded_previously: !!uploadedPreviously
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleCategory = event => {
|
handleCategory = event => {
|
||||||
|
@ -11564,32 +11668,59 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
|
|
||||||
// Custom wallpaper image upload
|
// Custom wallpaper image upload
|
||||||
async handleUpload() {
|
async handleUpload() {
|
||||||
// TODO: Bug 1943663: Add telemetry
|
const wallpaperUploadMaxFileSizeEnabled = this.props.Prefs.values[PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE_ENABLED];
|
||||||
|
const wallpaperUploadMaxFileSize = this.props.Prefs.values[PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE];
|
||||||
// TODO: Bug 1947813: Add image upload error states/UI
|
|
||||||
|
|
||||||
// TODO: Once Bug 1947813 has landed, we may need a separate event
|
|
||||||
// for selecting previously uploaded wallpaper, rather than uploading a new one.
|
|
||||||
// The plan would be to reuse at.WALLPAPER_CLICK for this use case
|
|
||||||
const uploadedPreviously = this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
const uploadedPreviously = this.props.Prefs.values[PREF_WALLPAPER_UPLOADED_PREVIOUSLY];
|
||||||
this.handleUserEvent(actionTypes.WALLPAPER_UPLOAD, {
|
|
||||||
had_uploaded_previously: !!uploadedPreviously,
|
|
||||||
had_previous_wallpaper: !!this.props.activeWallpaper
|
|
||||||
});
|
|
||||||
this.props.setPref(PREF_WALLPAPER_UPLOADED_PREVIOUSLY, true);
|
|
||||||
|
|
||||||
// Create a file input since category buttons are radio inputs
|
// Create a file input since category buttons are radio inputs
|
||||||
const fileInput = document.createElement("input");
|
const fileInput = document.createElement("input");
|
||||||
fileInput.type = "file";
|
fileInput.type = "file";
|
||||||
fileInput.accept = "image/*"; // only allow image files
|
fileInput.accept = "image/*"; // only allow image files
|
||||||
|
|
||||||
|
// Catch cancel events
|
||||||
|
fileInput.oncancel = async () => {
|
||||||
|
this.setState({
|
||||||
|
isCustomWallpaperError: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset error state when user begins file selection
|
||||||
|
this.setState({
|
||||||
|
isCustomWallpaperError: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fire when user selects a file
|
||||||
fileInput.onchange = async event => {
|
fileInput.onchange = async event => {
|
||||||
const [file] = event.target.files;
|
const [file] = event.target.files;
|
||||||
|
|
||||||
|
// Limit image uploaded to a maximum file size if enabled
|
||||||
|
// Note: The max file size pref (customWallpaper.fileSize) is converted to megabytes (MB)
|
||||||
|
// Example: if pref value is 5, max file size is 5 MB
|
||||||
|
const maxSize = wallpaperUploadMaxFileSize * 1024 * 1024;
|
||||||
|
if (wallpaperUploadMaxFileSizeEnabled && file && file.size > maxSize) {
|
||||||
|
console.error("File size exceeds limit");
|
||||||
|
this.setState({
|
||||||
|
isCustomWallpaperError: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (file) {
|
if (file) {
|
||||||
this.props.dispatch(actionCreators.OnlyToMain({
|
this.props.dispatch(actionCreators.OnlyToMain({
|
||||||
type: actionTypes.WALLPAPER_UPLOAD,
|
type: actionTypes.WALLPAPER_UPLOAD,
|
||||||
data: file
|
data: file
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Set active wallpaper ID to "custom"
|
||||||
|
this.props.setPref("newtabWallpapers.wallpaper", "custom");
|
||||||
|
|
||||||
|
// Update the uploadedPreviously pref to TRUE
|
||||||
|
// Note: this pref used for telemetry. Do not reset to false.
|
||||||
|
this.props.setPref(PREF_WALLPAPER_UPLOADED_PREVIOUSLY, true);
|
||||||
|
this.handleUserEvent(actionTypes.WALLPAPER_CLICK, {
|
||||||
|
selected_wallpaper: "custom",
|
||||||
|
had_previous_wallpaper: !!this.props.activeWallpaper,
|
||||||
|
had_uploaded_previously: !!uploadedPreviously
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fileInput.click();
|
fileInput.click();
|
||||||
|
@ -11642,6 +11773,7 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
activeCategoryFluentID
|
activeCategoryFluentID
|
||||||
} = this.state;
|
} = this.state;
|
||||||
let filteredWallpapers = wallpaperList.filter(wallpaper => wallpaper.category === activeCategory);
|
let filteredWallpapers = wallpaperList.filter(wallpaper => wallpaper.category === activeCategory);
|
||||||
|
const wallpaperUploadMaxFileSize = this.props.Prefs.values[PREF_WALLPAPER_UPLOAD_MAX_FILE_SIZE];
|
||||||
function reduceColorsToFitCustomColorInput(arr) {
|
function reduceColorsToFitCustomColorInput(arr) {
|
||||||
// Reduce the amount of custom colors to make space for the custom color picker
|
// Reduce the amount of custom colors to make space for the custom color picker
|
||||||
while (arr.length % 3 !== 2) {
|
while (arr.length % 3 !== 2) {
|
||||||
|
@ -11755,7 +11887,7 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
}
|
}
|
||||||
return /*#__PURE__*/external_React_default().createElement("div", {
|
return /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
key: category
|
key: category
|
||||||
}, /*#__PURE__*/external_React_default().createElement("input", {
|
}, /*#__PURE__*/external_React_default().createElement("input", WallpaperCategories_extends({
|
||||||
ref: el => {
|
ref: el => {
|
||||||
if (el) {
|
if (el) {
|
||||||
this.categoryRef[index] = el;
|
this.categoryRef[index] = el;
|
||||||
|
@ -11770,10 +11902,20 @@ class _WallpaperCategories extends (external_React_default()).PureComponent {
|
||||||
onClick: category !== "custom-wallpaper" ? this.handleCategory : this.handleUpload,
|
onClick: category !== "custom-wallpaper" ? this.handleCategory : this.handleUpload,
|
||||||
className: category !== "custom-wallpaper" ? `wallpaper-input` : `wallpaper-input theme-custom-wallpaper`,
|
className: category !== "custom-wallpaper" ? `wallpaper-input` : `wallpaper-input theme-custom-wallpaper`,
|
||||||
tabIndex: index === 0 ? 0 : -1
|
tabIndex: index === 0 ? 0 : -1
|
||||||
}), /*#__PURE__*/external_React_default().createElement("label", {
|
}, category === "custom-wallpaper" ? {
|
||||||
|
"aria-errormessage": "customWallpaperError"
|
||||||
|
} : {})), /*#__PURE__*/external_React_default().createElement("label", {
|
||||||
htmlFor: category,
|
htmlFor: category,
|
||||||
"data-l10n-id": fluent_id
|
"data-l10n-id": fluent_id
|
||||||
}, fluent_id));
|
}, fluent_id));
|
||||||
|
})), this.state.isCustomWallpaperError && /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
|
className: "custom-wallpaper-error",
|
||||||
|
id: "customWallpaperError"
|
||||||
|
}, /*#__PURE__*/external_React_default().createElement("span", {
|
||||||
|
className: "icon icon-info"
|
||||||
|
}), /*#__PURE__*/external_React_default().createElement("span", {
|
||||||
|
"data-l10n-id": "newtab-wallpaper-error-max-file-size",
|
||||||
|
"data-l10n-args": `{"file_size": ${wallpaperUploadMaxFileSize}}`
|
||||||
}))), /*#__PURE__*/external_React_default().createElement(external_ReactTransitionGroup_namespaceObject.CSSTransition, {
|
}))), /*#__PURE__*/external_React_default().createElement(external_ReactTransitionGroup_namespaceObject.CSSTransition, {
|
||||||
in: !!activeCategory,
|
in: !!activeCategory,
|
||||||
timeout: 300,
|
timeout: 300,
|
||||||
|
@ -11847,7 +11989,6 @@ const WallpaperCategories = (0,external_ReactRedux_namespaceObject.connect)(stat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ContentSection extends (external_React_default()).PureComponent {
|
class ContentSection extends (external_React_default()).PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -11868,7 +12009,7 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
onPreferenceSelect(e) {
|
onPreferenceSelect(e) {
|
||||||
// eventSource: TOP_SITES | TOP_STORIES | HIGHLIGHTS | WEATHER
|
// eventSource: WEATHER | TOP_SITES | TOP_STORIES
|
||||||
const {
|
const {
|
||||||
preference,
|
preference,
|
||||||
eventSource
|
eventSource
|
||||||
|
@ -11913,21 +12054,18 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
drawerRef.style.marginTop = "var(--space-large)";
|
drawerRef.style.marginTop = "var(--space-large)";
|
||||||
} else {
|
} else {
|
||||||
drawerRef.style.marginTop = `-${drawerHeight}px`;
|
drawerRef.style.marginTop = `-${drawerHeight + 3}px`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
enabledSections,
|
enabledSections,
|
||||||
mayHaveSponsoredTopSites,
|
|
||||||
pocketRegion,
|
pocketRegion,
|
||||||
mayHaveSponsoredStories,
|
|
||||||
mayHaveInferredPersonalization,
|
mayHaveInferredPersonalization,
|
||||||
mayHaveRecentSaves,
|
mayHaveRecentSaves,
|
||||||
mayHaveWeather,
|
mayHaveWeather,
|
||||||
openPreferences,
|
openPreferences,
|
||||||
spocMessageVariant,
|
|
||||||
wallpapersEnabled,
|
wallpapersEnabled,
|
||||||
wallpapersV2Enabled,
|
wallpapersV2Enabled,
|
||||||
activeWallpaper,
|
activeWallpaper,
|
||||||
|
@ -11938,10 +12076,7 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
const {
|
const {
|
||||||
topSitesEnabled,
|
topSitesEnabled,
|
||||||
pocketEnabled,
|
pocketEnabled,
|
||||||
highlightsEnabled,
|
|
||||||
weatherEnabled,
|
weatherEnabled,
|
||||||
showSponsoredTopSitesEnabled,
|
|
||||||
showSponsoredPocketEnabled,
|
|
||||||
showInferredPersonalizationEnabled,
|
showInferredPersonalizationEnabled,
|
||||||
showRecentSavesEnabled,
|
showRecentSavesEnabled,
|
||||||
topSitesRowsCount
|
topSitesRowsCount
|
||||||
|
@ -11964,7 +12099,17 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
role: "separator"
|
role: "separator"
|
||||||
})), /*#__PURE__*/external_React_default().createElement("div", {
|
})), /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
className: "settings-toggles"
|
className: "settings-toggles"
|
||||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
}, mayHaveWeather && /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
|
id: "weather-section",
|
||||||
|
className: "section"
|
||||||
|
}, /*#__PURE__*/external_React_default().createElement("moz-toggle", {
|
||||||
|
id: "weather-toggle",
|
||||||
|
pressed: weatherEnabled || null,
|
||||||
|
onToggle: this.onPreferenceSelect,
|
||||||
|
"data-preference": "showWeather",
|
||||||
|
"data-eventSource": "WEATHER",
|
||||||
|
"data-l10n-id": "newtab-custom-weather-toggle"
|
||||||
|
})), /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
id: "shortcuts-section",
|
id: "shortcuts-section",
|
||||||
className: "section"
|
className: "section"
|
||||||
}, /*#__PURE__*/external_React_default().createElement("moz-toggle", {
|
}, /*#__PURE__*/external_React_default().createElement("moz-toggle", {
|
||||||
|
@ -12006,22 +12151,6 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
value: "4",
|
value: "4",
|
||||||
"data-l10n-id": "newtab-custom-row-selector",
|
"data-l10n-id": "newtab-custom-row-selector",
|
||||||
"data-l10n-args": "{\"num\": 4}"
|
"data-l10n-args": "{\"num\": 4}"
|
||||||
})), mayHaveSponsoredTopSites && /*#__PURE__*/external_React_default().createElement("div", {
|
|
||||||
className: "check-wrapper",
|
|
||||||
role: "presentation"
|
|
||||||
}, /*#__PURE__*/external_React_default().createElement("input", {
|
|
||||||
id: "sponsored-shortcuts",
|
|
||||||
className: "customize-menu-checkbox",
|
|
||||||
disabled: !topSitesEnabled,
|
|
||||||
checked: showSponsoredTopSitesEnabled,
|
|
||||||
type: "checkbox",
|
|
||||||
onChange: this.onPreferenceSelect,
|
|
||||||
"data-preference": "showSponsoredTopSites",
|
|
||||||
"data-eventSource": "SPONSORED_TOP_SITES"
|
|
||||||
}), /*#__PURE__*/external_React_default().createElement("label", {
|
|
||||||
className: "customize-menu-checkbox-label",
|
|
||||||
htmlFor: "sponsored-shortcuts",
|
|
||||||
"data-l10n-id": "newtab-custom-sponsored-sites"
|
|
||||||
}))))))), pocketRegion && /*#__PURE__*/external_React_default().createElement("div", {
|
}))))))), pocketRegion && /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
id: "pocket-section",
|
id: "pocket-section",
|
||||||
className: "section"
|
className: "section"
|
||||||
|
@ -12035,28 +12164,12 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
"data-l10n-id": "newtab-custom-stories-toggle"
|
"data-l10n-id": "newtab-custom-stories-toggle"
|
||||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
slot: "nested"
|
slot: "nested"
|
||||||
}, (mayHaveSponsoredStories || mayHaveRecentSaves) && /*#__PURE__*/external_React_default().createElement("div", {
|
}, (mayHaveRecentSaves || mayHaveInferredPersonalization || mayHaveTopicSections) && /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
className: "more-info-pocket-wrapper"
|
className: "more-info-pocket-wrapper"
|
||||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
className: "more-information",
|
className: "more-information",
|
||||||
ref: this.pocketDrawerRef
|
ref: this.pocketDrawerRef
|
||||||
}, mayHaveSponsoredStories && /*#__PURE__*/external_React_default().createElement("div", {
|
}, mayHaveInferredPersonalization && /*#__PURE__*/external_React_default().createElement("div", {
|
||||||
className: "check-wrapper",
|
|
||||||
role: "presentation"
|
|
||||||
}, /*#__PURE__*/external_React_default().createElement("input", {
|
|
||||||
id: "sponsored-pocket",
|
|
||||||
className: "customize-menu-checkbox",
|
|
||||||
disabled: !pocketEnabled,
|
|
||||||
checked: showSponsoredPocketEnabled,
|
|
||||||
type: "checkbox",
|
|
||||||
onChange: this.onPreferenceSelect,
|
|
||||||
"data-preference": "showSponsored",
|
|
||||||
"data-eventSource": "POCKET_SPOCS"
|
|
||||||
}), /*#__PURE__*/external_React_default().createElement("label", {
|
|
||||||
className: "customize-menu-checkbox-label",
|
|
||||||
htmlFor: "sponsored-pocket",
|
|
||||||
"data-l10n-id": "newtab-custom-pocket-sponsored"
|
|
||||||
})), mayHaveInferredPersonalization && /*#__PURE__*/external_React_default().createElement("div", {
|
|
||||||
className: "check-wrapper",
|
className: "check-wrapper",
|
||||||
role: "presentation"
|
role: "presentation"
|
||||||
}, /*#__PURE__*/external_React_default().createElement("input", {
|
}, /*#__PURE__*/external_React_default().createElement("input", {
|
||||||
|
@ -12089,34 +12202,7 @@ class ContentSection extends (external_React_default()).PureComponent {
|
||||||
className: "customize-menu-checkbox-label",
|
className: "customize-menu-checkbox-label",
|
||||||
htmlFor: "recent-saves-pocket",
|
htmlFor: "recent-saves-pocket",
|
||||||
"data-l10n-id": "newtab-custom-pocket-show-recent-saves"
|
"data-l10n-id": "newtab-custom-pocket-show-recent-saves"
|
||||||
}))))))), /*#__PURE__*/external_React_default().createElement("div", {
|
})))))))), /*#__PURE__*/external_React_default().createElement("span", {
|
||||||
id: "recent-section",
|
|
||||||
className: "section"
|
|
||||||
}, /*#__PURE__*/external_React_default().createElement("moz-toggle", {
|
|
||||||
id: "highlights-toggle",
|
|
||||||
pressed: highlightsEnabled || null,
|
|
||||||
onToggle: this.onPreferenceSelect,
|
|
||||||
"data-preference": "feeds.section.highlights",
|
|
||||||
"data-eventSource": "HIGHLIGHTS",
|
|
||||||
"data-l10n-id": "newtab-custom-recent-toggle"
|
|
||||||
})), mayHaveWeather && /*#__PURE__*/external_React_default().createElement("div", {
|
|
||||||
id: "weather-section",
|
|
||||||
className: "section"
|
|
||||||
}, /*#__PURE__*/external_React_default().createElement("moz-toggle", {
|
|
||||||
id: "weather-toggle",
|
|
||||||
pressed: weatherEnabled || null,
|
|
||||||
onToggle: this.onPreferenceSelect,
|
|
||||||
"data-preference": "showWeather",
|
|
||||||
"data-eventSource": "WEATHER",
|
|
||||||
"data-l10n-id": "newtab-custom-weather-toggle"
|
|
||||||
})), pocketRegion && mayHaveSponsoredStories && spocMessageVariant === "variant-c" && /*#__PURE__*/external_React_default().createElement("div", {
|
|
||||||
className: "sponsored-content-info"
|
|
||||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
|
||||||
className: "icon icon-help"
|
|
||||||
}), /*#__PURE__*/external_React_default().createElement("div", null, "Sponsored content supports our mission to build a better web.", " ", /*#__PURE__*/external_React_default().createElement(SafeAnchor, {
|
|
||||||
dispatch: this.props.dispatch,
|
|
||||||
url: "https://support.mozilla.org/kb/pocket-sponsored-stories-new-tabs"
|
|
||||||
}, "Find out how")))), /*#__PURE__*/external_React_default().createElement("span", {
|
|
||||||
className: "divider",
|
className: "divider",
|
||||||
role: "separator"
|
role: "separator"
|
||||||
}), /*#__PURE__*/external_React_default().createElement("div", null, /*#__PURE__*/external_React_default().createElement("button", {
|
}), /*#__PURE__*/external_React_default().createElement("div", null, /*#__PURE__*/external_React_default().createElement("button", {
|
||||||
|
@ -12205,12 +12291,9 @@ class _CustomizeMenu extends (external_React_default()).PureComponent {
|
||||||
activeWallpaper: this.props.activeWallpaper,
|
activeWallpaper: this.props.activeWallpaper,
|
||||||
pocketRegion: this.props.pocketRegion,
|
pocketRegion: this.props.pocketRegion,
|
||||||
mayHaveTopicSections: this.props.mayHaveTopicSections,
|
mayHaveTopicSections: this.props.mayHaveTopicSections,
|
||||||
mayHaveSponsoredTopSites: this.props.mayHaveSponsoredTopSites,
|
|
||||||
mayHaveSponsoredStories: this.props.mayHaveSponsoredStories,
|
|
||||||
mayHaveInferredPersonalization: this.props.mayHaveInferredPersonalization,
|
mayHaveInferredPersonalization: this.props.mayHaveInferredPersonalization,
|
||||||
mayHaveRecentSaves: this.props.DiscoveryStream.recentSavesEnabled,
|
mayHaveRecentSaves: this.props.DiscoveryStream.recentSavesEnabled,
|
||||||
mayHaveWeather: this.props.mayHaveWeather,
|
mayHaveWeather: this.props.mayHaveWeather,
|
||||||
spocMessageVariant: this.props.spocMessageVariant,
|
|
||||||
dispatch: this.props.dispatch,
|
dispatch: this.props.dispatch,
|
||||||
exitEventFired: this.state.exitEventFired
|
exitEventFired: this.state.exitEventFired
|
||||||
}))));
|
}))));
|
||||||
|
@ -13825,9 +13908,6 @@ class BaseContent extends (external_React_default()).PureComponent {
|
||||||
const enabledSections = {
|
const enabledSections = {
|
||||||
topSitesEnabled: prefs["feeds.topsites"],
|
topSitesEnabled: prefs["feeds.topsites"],
|
||||||
pocketEnabled: prefs["feeds.section.topstories"],
|
pocketEnabled: prefs["feeds.section.topstories"],
|
||||||
highlightsEnabled: prefs["feeds.section.highlights"],
|
|
||||||
showSponsoredTopSitesEnabled: prefs.showSponsoredTopSites,
|
|
||||||
showSponsoredPocketEnabled: prefs.showSponsored,
|
|
||||||
showInferredPersonalizationEnabled: prefs[PREF_INFERRED_PERSONALIZATION_USER],
|
showInferredPersonalizationEnabled: prefs[PREF_INFERRED_PERSONALIZATION_USER],
|
||||||
showRecentSavesEnabled: prefs.showRecentSaves,
|
showRecentSavesEnabled: prefs.showRecentSaves,
|
||||||
topSitesRowsCount: prefs.topSitesRows,
|
topSitesRowsCount: prefs.topSitesRows,
|
||||||
|
|
|
@ -219,6 +219,13 @@ module.exports = function (config) {
|
||||||
{
|
{
|
||||||
branches: 60,
|
branches: 60,
|
||||||
},
|
},
|
||||||
|
"content-src/components/DiscoveryStreamComponents/AdBannerContextMenu/AdBannerContextMenu.jsx":
|
||||||
|
{
|
||||||
|
statements: 87.5,
|
||||||
|
lines: 87.5,
|
||||||
|
functions: 66.67,
|
||||||
|
branches: 0,
|
||||||
|
},
|
||||||
"content-src/components/DiscoveryStreamComponents/**/*.jsx": {
|
"content-src/components/DiscoveryStreamComponents/**/*.jsx": {
|
||||||
statements: 90.48,
|
statements: 90.48,
|
||||||
lines: 90.48,
|
lines: 90.48,
|
||||||
|
|
|
@ -25,7 +25,25 @@ const PREFS_BEFORE_SECTIONS = () => [
|
||||||
feed: "showSearch",
|
feed: "showSearch",
|
||||||
titleString: "home-prefs-search-header",
|
titleString: "home-prefs-search-header",
|
||||||
},
|
},
|
||||||
icon: "chrome://global/skin/icons/search-glass.svg",
|
},
|
||||||
|
{
|
||||||
|
id: "weather",
|
||||||
|
pref: {
|
||||||
|
feed: "showWeather",
|
||||||
|
titleString: "home-prefs-weather-header",
|
||||||
|
descString: "home-prefs-weather-description",
|
||||||
|
learnMore: {
|
||||||
|
link: {
|
||||||
|
href: "https://support.mozilla.org/kb/customize-items-on-firefox-new-tab-page",
|
||||||
|
id: "home-prefs-weather-learn-more-link",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
eventSource: "WEATHER",
|
||||||
|
shouldHidePref: !Services.prefs.getBoolPref(
|
||||||
|
"browser.newtabpage.activity-stream.system.showWeather",
|
||||||
|
false
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "topsites",
|
id: "topsites",
|
||||||
|
@ -45,31 +63,10 @@ const PREFS_BEFORE_SECTIONS = () => [
|
||||||
: [];
|
: [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
icon: "chrome://browser/skin/topsites.svg",
|
|
||||||
maxRows: 4,
|
maxRows: 4,
|
||||||
rowsPref: "topSitesRows",
|
rowsPref: "topSitesRows",
|
||||||
eventSource: "TOP_SITES",
|
eventSource: "TOP_SITES",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "weather",
|
|
||||||
icon: "chrome://browser/skin/weather/sunny.svg",
|
|
||||||
pref: {
|
|
||||||
feed: "showWeather",
|
|
||||||
titleString: "home-prefs-weather-header",
|
|
||||||
descString: "home-prefs-weather-description",
|
|
||||||
learnMore: {
|
|
||||||
link: {
|
|
||||||
href: "https://support.mozilla.org/kb/customize-items-on-firefox-new-tab-page",
|
|
||||||
id: "home-prefs-weather-learn-more-link",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eventSource: "WEATHER",
|
|
||||||
shouldHidePref: !Services.prefs.getBoolPref(
|
|
||||||
"browser.newtabpage.activity-stream.system.showWeather",
|
|
||||||
false
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export class AboutPreferences {
|
export class AboutPreferences {
|
||||||
|
@ -192,7 +189,6 @@ export class AboutPreferences {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
pref: prefData,
|
pref: prefData,
|
||||||
icon = "webextension",
|
|
||||||
maxRows,
|
maxRows,
|
||||||
rowsPref,
|
rowsPref,
|
||||||
shouldHidePref,
|
shouldHidePref,
|
||||||
|
@ -210,17 +206,11 @@ export class AboutPreferences {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use full icon spec for certain protocols or fall back to packaged icon
|
|
||||||
const iconUrl = !icon.search(/^(chrome|moz-extension|resource):/)
|
|
||||||
? icon
|
|
||||||
: `chrome://newtab/content/data/content/assets/glyph-${icon}-16.svg`;
|
|
||||||
|
|
||||||
// Add the main preference for turning on/off a section
|
// Add the main preference for turning on/off a section
|
||||||
const sectionVbox = createAppend("vbox", contentsGroup);
|
const sectionVbox = createAppend("vbox", contentsGroup);
|
||||||
sectionVbox.setAttribute("data-subcategory", id);
|
sectionVbox.setAttribute("data-subcategory", id);
|
||||||
const checkbox = createAppend("checkbox", sectionVbox);
|
const checkbox = createAppend("checkbox", sectionVbox);
|
||||||
checkbox.classList.add("section-checkbox");
|
checkbox.classList.add("section-checkbox");
|
||||||
checkbox.setAttribute("src", iconUrl);
|
|
||||||
// Setup a user event if we have an event source for this pref.
|
// Setup a user event if we have an event source for this pref.
|
||||||
if (eventSource) {
|
if (eventSource) {
|
||||||
this.setupUserEvent(checkbox, eventSource);
|
this.setupUserEvent(checkbox, eventSource);
|
||||||
|
|
|
@ -465,10 +465,24 @@ export const PREFS_CONFIG = new Map([
|
||||||
"newtabWallpapers.customWallpaper.uploadedPreviously",
|
"newtabWallpapers.customWallpaper.uploadedPreviously",
|
||||||
{
|
{
|
||||||
title:
|
title:
|
||||||
"Boolean flag to track if a user has previously uploaded a custom wallpaper",
|
"Boolean flag used for telemetry to track if a user has previously uploaded a custom wallpaper",
|
||||||
value: false,
|
value: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"newtabWallpapers.customWallpaper.fileSize.enabled",
|
||||||
|
{
|
||||||
|
title: "Boolean flag to enforce a maximum file size for uploaded images",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"newtabWallpapers.customWallpaper.fileSize",
|
||||||
|
{
|
||||||
|
title: "Number pref of maximum file size (in MB) a user can upload",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"newtabAdSize.variant-a",
|
"newtabAdSize.variant-a",
|
||||||
{
|
{
|
||||||
|
|
|
@ -1151,13 +1151,18 @@ export class TelemetryFeed {
|
||||||
break;
|
break;
|
||||||
case "WALLPAPER_CLICK":
|
case "WALLPAPER_CLICK":
|
||||||
{
|
{
|
||||||
const { selected_wallpaper, had_previous_wallpaper } = data;
|
const {
|
||||||
|
selected_wallpaper,
|
||||||
|
had_previous_wallpaper,
|
||||||
|
had_uploaded_previously,
|
||||||
|
} = data;
|
||||||
|
|
||||||
// if either of the wallpaper prefs are truthy, they had a previous wallpaper
|
// if either of the wallpaper prefs are truthy, they had a previous wallpaper
|
||||||
Glean.newtab.wallpaperClick.record({
|
Glean.newtab.wallpaperClick.record({
|
||||||
newtab_visit_id: session.session_id,
|
newtab_visit_id: session.session_id,
|
||||||
selected_wallpaper,
|
selected_wallpaper,
|
||||||
had_previous_wallpaper,
|
had_previous_wallpaper,
|
||||||
|
had_uploaded_previously,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1171,18 +1176,6 @@ export class TelemetryFeed {
|
||||||
newtab_visit_id: session.session_id,
|
newtab_visit_id: session.session_id,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "WALLPAPER_UPLOAD":
|
|
||||||
{
|
|
||||||
const { had_uploaded_previously, had_previous_wallpaper } = data;
|
|
||||||
|
|
||||||
Glean.newtab.wallpaperUpload.record({
|
|
||||||
newtab_visit_id: session.session_id,
|
|
||||||
had_previous_wallpaper,
|
|
||||||
had_uploaded_previously,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_tab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
// Test that we do not set icons in individual tile and card context menus on
|
// Test that we do not set icons in individual tile and card context menus on
|
||||||
// newtab page.
|
// newtab page.
|
||||||
test_newtab({
|
test_newtab({
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
const { WeatherFeed } = ChromeUtils.importESModule(
|
const { WeatherFeed } = ChromeUtils.importESModule(
|
||||||
"resource://newtab/lib/WeatherFeed.sys.mjs"
|
"resource://newtab/lib/WeatherFeed.sys.mjs"
|
||||||
);
|
);
|
||||||
|
@ -14,8 +18,7 @@ test_newtab({
|
||||||
async before({ pushPrefs }) {
|
async before({ pushPrefs }) {
|
||||||
await pushPrefs(
|
await pushPrefs(
|
||||||
["browser.newtabpage.activity-stream.feeds.topsites", false],
|
["browser.newtabpage.activity-stream.feeds.topsites", false],
|
||||||
["browser.newtabpage.activity-stream.feeds.section.topstories", false],
|
["browser.newtabpage.activity-stream.feeds.section.topstories", false]
|
||||||
["browser.newtabpage.activity-stream.feeds.section.highlights", false]
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
test: async function test_render_customizeMenu() {
|
test: async function test_render_customizeMenu() {
|
||||||
|
@ -32,8 +35,6 @@ test_newtab({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const TOPSITES_PREF = "browser.newtabpage.activity-stream.feeds.topsites";
|
const TOPSITES_PREF = "browser.newtabpage.activity-stream.feeds.topsites";
|
||||||
const HIGHLIGHTS_PREF =
|
|
||||||
"browser.newtabpage.activity-stream.feeds.section.highlights";
|
|
||||||
const TOPSTORIES_PREF =
|
const TOPSTORIES_PREF =
|
||||||
"browser.newtabpage.activity-stream.feeds.section.topstories";
|
"browser.newtabpage.activity-stream.feeds.section.topstories";
|
||||||
|
|
||||||
|
@ -93,26 +94,6 @@ test_newtab({
|
||||||
await sectionShownPromise;
|
await sectionShownPromise;
|
||||||
|
|
||||||
Assert.ok(getSection("topstories"), "Pocket section is rendered");
|
Assert.ok(getSection("topstories"), "Pocket section is rendered");
|
||||||
|
|
||||||
// Test that clicking the recent activity toggle will make the
|
|
||||||
// recent activity section appear on the newtab page.
|
|
||||||
//
|
|
||||||
// We waive XRay wrappers because we want to call the click()
|
|
||||||
// method defined on the toggle from this context.
|
|
||||||
let highlightsSwitch = Cu.waiveXrays(
|
|
||||||
content.document.querySelector("#recent-section moz-toggle")
|
|
||||||
);
|
|
||||||
Assert.ok(
|
|
||||||
!Services.prefs.getBoolPref(HIGHLIGHTS_PREF),
|
|
||||||
"Highlights pref is turned off"
|
|
||||||
);
|
|
||||||
Assert.ok(!getSection("highlights"), "Highlights section is not rendered");
|
|
||||||
|
|
||||||
sectionShownPromise = promiseSectionShown("highlights");
|
|
||||||
highlightsSwitch.click();
|
|
||||||
await sectionShownPromise;
|
|
||||||
|
|
||||||
Assert.ok(getSection("highlights"), "Highlights section is rendered");
|
|
||||||
},
|
},
|
||||||
async after() {
|
async after() {
|
||||||
Services.prefs.clearUserPref(
|
Services.prefs.clearUserPref(
|
||||||
|
@ -121,9 +102,6 @@ test_newtab({
|
||||||
Services.prefs.clearUserPref(
|
Services.prefs.clearUserPref(
|
||||||
"browser.newtabpage.activity-stream.feeds.section.topstories"
|
"browser.newtabpage.activity-stream.feeds.section.topstories"
|
||||||
);
|
);
|
||||||
Services.prefs.clearUserPref(
|
|
||||||
"browser.newtabpage.activity-stream.feeds.section.highlights"
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
// Test that the customization menu is rendered.
|
// Test that the customization menu is rendered.
|
||||||
test_newtab({
|
test_newtab({
|
||||||
async before() {
|
async before() {
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
// Test that the customization menu is rendered.
|
// Test that the customization menu is rendered.
|
||||||
test_newtab({
|
test_newtab({
|
||||||
test: async function test_render_customizeMenu() {
|
test: async function test_render_customizeMenu() {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
// If this fails it could be because of schema changes.
|
// If this fails it could be because of schema changes.
|
||||||
// `topstories.json` defines the stories shown
|
// `topstories.json` defines the stories shown
|
||||||
test_newtab({
|
test_newtab({
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
async function before({ pushPrefs }) {
|
async function before({ pushPrefs }) {
|
||||||
await pushPrefs([
|
await pushPrefs([
|
||||||
"browser.newtabpage.activity-stream.discoverystream.config",
|
"browser.newtabpage.activity-stream.discoverystream.config",
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
// Tests that:
|
// Tests that:
|
||||||
// 1. Top sites header is hidden and the topsites section is not collapsed on load.
|
// 1. Top sites header is hidden and the topsites section is not collapsed on load.
|
||||||
// 2. Pocket header and section are visible and not collapsed on load.
|
// 2. Pocket header and section are visible and not collapsed on load.
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// test_newtab calls SpecialPowers.spawn, which injects ContentTaskUtils in the
|
||||||
|
// scope of the callback. Eslint doesn't know about that.
|
||||||
|
/* global ContentTaskUtils */
|
||||||
|
|
||||||
test_newtab({
|
test_newtab({
|
||||||
async before() {
|
async before() {
|
||||||
// Some reason test-linux1804-64-qr/debug can end up with example.com, so
|
// Some reason test-linux1804-64-qr/debug can end up with example.com, so
|
||||||
|
|
|
@ -47,31 +47,19 @@ describe("ContentSection", () => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have data-eventSource attributes on relevent pref changing inputs", () => {
|
it("should have data-eventSource attributes on relevant pref changing inputs", () => {
|
||||||
wrapper = mount(<ContentSection {...DEFAULT_PROPS} />);
|
wrapper = mount(<ContentSection {...DEFAULT_PROPS} />);
|
||||||
|
assert.equal(
|
||||||
|
wrapper.find("#weather-toggle").prop("data-eventSource"),
|
||||||
|
"WEATHER"
|
||||||
|
);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
wrapper.find("#shortcuts-toggle").prop("data-eventSource"),
|
wrapper.find("#shortcuts-toggle").prop("data-eventSource"),
|
||||||
"TOP_SITES"
|
"TOP_SITES"
|
||||||
);
|
);
|
||||||
assert.equal(
|
|
||||||
wrapper.find("#sponsored-shortcuts").prop("data-eventSource"),
|
|
||||||
"SPONSORED_TOP_SITES"
|
|
||||||
);
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
wrapper.find("#pocket-toggle").prop("data-eventSource"),
|
wrapper.find("#pocket-toggle").prop("data-eventSource"),
|
||||||
"TOP_STORIES"
|
"TOP_STORIES"
|
||||||
);
|
);
|
||||||
assert.equal(
|
|
||||||
wrapper.find("#sponsored-pocket").prop("data-eventSource"),
|
|
||||||
"POCKET_SPOCS"
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find("#highlights-toggle").prop("data-eventSource"),
|
|
||||||
"HIGHLIGHTS"
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find("#weather-toggle").prop("data-eventSource"),
|
|
||||||
"WEATHER"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -121,15 +121,12 @@ describe("Discovery Stream <AdBanner>", () => {
|
||||||
assert.deepEqual(aside.prop("style"), { gridRow: clampedRow });
|
assert.deepEqual(aside.prop("style"), { gridRow: clampedRow });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have the dismiss button be visible", () => {
|
it("should have the context menu button be visible", () => {
|
||||||
const dismiss = wrapper.find(".ad-banner-dismiss .icon-dismiss");
|
const dismiss = wrapper.find("moz-button");
|
||||||
assert.ok(dismiss.exists());
|
assert.ok(dismiss.exists());
|
||||||
|
|
||||||
dismiss.simulate("click");
|
// The rest of the context menu functionality is now tested in
|
||||||
|
// AdBannerContextMenu.test.jsx
|
||||||
let [action] = dispatch.secondCall.args;
|
|
||||||
assert.equal(action.type, "BLOCK_URL");
|
|
||||||
assert.equal(action.data[0].id, DEFAULT_PROPS.spoc.id);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call onLinkClick when banner is clicked", () => {
|
it("should call onLinkClick when banner is clicked", () => {
|
||||||
|
@ -142,7 +139,7 @@ describe("Discovery Stream <AdBanner>", () => {
|
||||||
ac.DiscoveryStreamUserEvent({
|
ac.DiscoveryStreamUserEvent({
|
||||||
event: "CLICK",
|
event: "CLICK",
|
||||||
source: "FOO",
|
source: "FOO",
|
||||||
// Banner ads dont have a position, but a row number
|
// Banner ads don't have a position, but a row number
|
||||||
action_position: DEFAULT_PROPS.row,
|
action_position: DEFAULT_PROPS.row,
|
||||||
value: {
|
value: {
|
||||||
card_type: "spoc",
|
card_type: "spoc",
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { shallow } from "enzyme";
|
||||||
|
import { AdBannerContextMenu } from "content-src/components/DiscoveryStreamComponents/AdBannerContextMenu/AdBannerContextMenu";
|
||||||
|
import { LinkMenu } from "content-src/components/LinkMenu/LinkMenu";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
describe("<AdBannerContextMenu>", () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
describe("Ad banner context menu options", () => {
|
||||||
|
const props = {
|
||||||
|
spoc: { url: "https://www.test.com/", shim: "aaabbbcccddd" },
|
||||||
|
position: 1,
|
||||||
|
type: "billboard",
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = shallow(<AdBannerContextMenu {...props} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render a context menu button", () => {
|
||||||
|
assert.ok(wrapper.exists());
|
||||||
|
assert.ok(
|
||||||
|
wrapper.find("moz-button").exists(),
|
||||||
|
"context menu button exists"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render LinkMenu when context menu button is clicked", () => {
|
||||||
|
let button = wrapper.find("moz-button");
|
||||||
|
button.simulate("click", {
|
||||||
|
preventDefault: () => {},
|
||||||
|
});
|
||||||
|
assert.equal(wrapper.find(LinkMenu).length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should pass props to LinkMenu", () => {
|
||||||
|
wrapper.find("moz-button").simulate("click", {
|
||||||
|
preventDefault: () => {},
|
||||||
|
});
|
||||||
|
const linkMenuProps = wrapper.find(LinkMenu).props();
|
||||||
|
[
|
||||||
|
"onUpdate",
|
||||||
|
"dispatch",
|
||||||
|
"options",
|
||||||
|
"shouldSendImpressionStats",
|
||||||
|
"userEvent",
|
||||||
|
"site",
|
||||||
|
"index",
|
||||||
|
"source",
|
||||||
|
].forEach(prop => assert.property(linkMenuProps, prop));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should pass through the correct menu options to LinkMenu for ad banners", () => {
|
||||||
|
wrapper.find("moz-button").simulate("click", {
|
||||||
|
preventDefault: () => {},
|
||||||
|
});
|
||||||
|
const linkMenuProps = wrapper.find(LinkMenu).props();
|
||||||
|
assert.deepEqual(linkMenuProps.options, [
|
||||||
|
"BlockAdUrl",
|
||||||
|
"ManageSponsoredContent",
|
||||||
|
"OurSponsorsAndYourPrivacy",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -125,8 +125,8 @@ describe("AboutPreferences Feed", () => {
|
||||||
assert.calledOnce(stub);
|
assert.calledOnce(stub);
|
||||||
const [, structure] = stub.firstCall.args;
|
const [, structure] = stub.firstCall.args;
|
||||||
assert.equal(structure[0].id, "search");
|
assert.equal(structure[0].id, "search");
|
||||||
assert.equal(structure[1].id, "topsites");
|
assert.equal(structure[1].id, "weather");
|
||||||
assert.equal(structure[2].id, "weather");
|
assert.equal(structure[2].id, "topsites");
|
||||||
assert.equal(structure[3].id, "topstories");
|
assert.equal(structure[3].id, "topstories");
|
||||||
assert.isEmpty(structure[3].rowsPref);
|
assert.isEmpty(structure[3].rowsPref);
|
||||||
});
|
});
|
||||||
|
@ -228,38 +228,6 @@ describe("AboutPreferences Feed", () => {
|
||||||
assert.notCalled(Preferences.add);
|
assert.notCalled(Preferences.add);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("pref icon", () => {
|
|
||||||
it("should default to webextension icon", () => {
|
|
||||||
prefStructure = [{ pref: { feed: "feed" } }];
|
|
||||||
|
|
||||||
testRender();
|
|
||||||
|
|
||||||
assert.calledWith(
|
|
||||||
node.setAttribute,
|
|
||||||
"src",
|
|
||||||
"chrome://newtab/content/data/content/assets/glyph-webextension-16.svg"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should use desired glyph icon", () => {
|
|
||||||
prefStructure = [{ icon: "mail", pref: { feed: "feed" } }];
|
|
||||||
|
|
||||||
testRender();
|
|
||||||
|
|
||||||
assert.calledWith(
|
|
||||||
node.setAttribute,
|
|
||||||
"src",
|
|
||||||
"chrome://newtab/content/data/content/assets/glyph-mail-16.svg"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should use specified chrome icon", () => {
|
|
||||||
const icon = "chrome://the/icon.svg";
|
|
||||||
prefStructure = [{ icon, pref: { feed: "feed" } }];
|
|
||||||
|
|
||||||
testRender();
|
|
||||||
|
|
||||||
assert.calledWith(node.setAttribute, "src", icon);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe("title line", () => {
|
describe("title line", () => {
|
||||||
it("should render a title", () => {
|
it("should render a title", () => {
|
||||||
const titleString = "the_title";
|
const titleString = "the_title";
|
||||||
|
|
|
@ -290,8 +290,8 @@ quickactions-bookmarks2 = Manage bookmarks
|
||||||
quickactions-cmd-bookmarks = bookmarks
|
quickactions-cmd-bookmarks = bookmarks
|
||||||
|
|
||||||
# Opens a SUMO article explaining how to clear history
|
# Opens a SUMO article explaining how to clear history
|
||||||
quickactions-clearhistory = Clear History
|
quickactions-clearrecenthistory = Clear recent history
|
||||||
quickactions-cmd-clearhistory = clear history
|
quickactions-cmd-clearrecenthistory = clear recent history, history
|
||||||
|
|
||||||
# Opens about:downloads page
|
# Opens about:downloads page
|
||||||
quickactions-downloads2 = View downloads
|
quickactions-downloads2 = View downloads
|
||||||
|
@ -301,6 +301,17 @@ quickactions-cmd-downloads = downloads
|
||||||
quickactions-extensions = Manage extensions
|
quickactions-extensions = Manage extensions
|
||||||
quickactions-cmd-extensions = extensions
|
quickactions-cmd-extensions = extensions
|
||||||
|
|
||||||
|
# Opens Firefox View
|
||||||
|
quickactions-firefoxview = Open { -firefoxview-brand-name }
|
||||||
|
# English is using "view" and "open view", since the feature name is
|
||||||
|
# "Firefox View". If you have translated the name in your language, you
|
||||||
|
# should use a word related to the existing translation.
|
||||||
|
quickactions-cmd-firefoxview = open { -firefoxview-brand-name }, { -firefoxview-brand-name }, open view, view
|
||||||
|
|
||||||
|
# Opens SUMO home page
|
||||||
|
quickactions-help = { -brand-product-name } help
|
||||||
|
quickactions-cmd-help = help, support
|
||||||
|
|
||||||
# Opens the devtools web inspector
|
# Opens the devtools web inspector
|
||||||
quickactions-inspector2 = Open Developer Tools
|
quickactions-inspector2 = Open Developer Tools
|
||||||
quickactions-cmd-inspector = inspector, devtools
|
quickactions-cmd-inspector = inspector, devtools
|
||||||
|
|
|
@ -142,7 +142,7 @@ actions-callout-title = Complete common tasks or access basic settings
|
||||||
# These example text inputs correlate to the the following strings
|
# These example text inputs correlate to the the following strings
|
||||||
# (either matching the whole string, or the first word of the string).
|
# (either matching the whole string, or the first word of the string).
|
||||||
# "print" - quickactions-cmd-print
|
# "print" - quickactions-cmd-print
|
||||||
# "clear" - quickactions-cmd-clearhistory
|
# "clear" - quickactions-cmd-clearrecenthistory
|
||||||
# When localizing, ensure the translations match to ensure the action button appears as expected.
|
# When localizing, ensure the translations match to ensure the action button appears as expected.
|
||||||
actions-callout-subtitle = Try typing an action like “print” to print a page, or “clear” to clear your history.
|
actions-callout-subtitle = Try typing an action like “print” to print a page, or “clear” to clear your history.
|
||||||
|
|
||||||
|
|
|
@ -285,15 +285,10 @@ newtab-custom-row-selector =
|
||||||
[one] { $num } row
|
[one] { $num } row
|
||||||
*[other] { $num } rows
|
*[other] { $num } rows
|
||||||
}
|
}
|
||||||
newtab-custom-sponsored-sites = Sponsored shortcuts
|
|
||||||
newtab-custom-stories-toggle =
|
newtab-custom-stories-toggle =
|
||||||
.label = Recommended stories
|
.label = Recommended stories
|
||||||
.description = Exceptional content curated by the { -brand-product-name } family
|
.description = Exceptional content curated by the { -brand-product-name } family
|
||||||
newtab-custom-pocket-sponsored = Sponsored stories
|
|
||||||
newtab-custom-pocket-show-recent-saves = Show recent saves
|
newtab-custom-pocket-show-recent-saves = Show recent saves
|
||||||
newtab-custom-recent-toggle =
|
|
||||||
.label = Recent activity
|
|
||||||
.description = A selection of recent sites and content
|
|
||||||
newtab-custom-weather-toggle =
|
newtab-custom-weather-toggle =
|
||||||
.label = Weather
|
.label = Weather
|
||||||
.description = Today’s forecast at a glance
|
.description = Today’s forecast at a glance
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"af": {
|
"af": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"an": {
|
"an": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ar": {
|
"ar": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ast": {
|
"ast": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"az": {
|
"az": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"be": {
|
"be": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -137,7 +137,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"bg": {
|
"bg": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -157,7 +157,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"bn": {
|
"bn": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -177,7 +177,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"bo": {
|
"bo": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"br": {
|
"br": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -217,7 +217,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"brx": {
|
"brx": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -237,7 +237,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"bs": {
|
"bs": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -257,7 +257,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ca": {
|
"ca": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -277,7 +277,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ca-valencia": {
|
"ca-valencia": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -297,7 +297,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"cak": {
|
"cak": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -317,7 +317,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ckb": {
|
"ckb": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -337,7 +337,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"cs": {
|
"cs": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"cy": {
|
"cy": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -377,7 +377,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"da": {
|
"da": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -397,7 +397,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"de": {
|
"de": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -417,7 +417,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"dsb": {
|
"dsb": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -437,7 +437,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"el": {
|
"el": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -457,7 +457,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"en-CA": {
|
"en-CA": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -477,7 +477,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"en-GB": {
|
"en-GB": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -497,7 +497,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"eo": {
|
"eo": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -517,7 +517,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"es-AR": {
|
"es-AR": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -537,7 +537,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"es-CL": {
|
"es-CL": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -557,7 +557,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"es-ES": {
|
"es-ES": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -577,7 +577,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"es-MX": {
|
"es-MX": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -597,7 +597,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"et": {
|
"et": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -617,7 +617,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"eu": {
|
"eu": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -637,7 +637,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"fa": {
|
"fa": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -657,7 +657,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ff": {
|
"ff": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -677,7 +677,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"fi": {
|
"fi": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -697,7 +697,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"fr": {
|
"fr": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -717,7 +717,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"fur": {
|
"fur": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -737,7 +737,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"fy-NL": {
|
"fy-NL": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -757,7 +757,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ga-IE": {
|
"ga-IE": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -777,7 +777,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"gd": {
|
"gd": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -797,7 +797,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"gl": {
|
"gl": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -817,7 +817,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"gn": {
|
"gn": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -837,7 +837,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"gu-IN": {
|
"gu-IN": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -857,7 +857,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"he": {
|
"he": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -877,7 +877,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"hi-IN": {
|
"hi-IN": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -897,7 +897,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"hr": {
|
"hr": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -917,7 +917,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"hsb": {
|
"hsb": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -937,7 +937,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"hu": {
|
"hu": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -957,7 +957,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"hy-AM": {
|
"hy-AM": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -977,7 +977,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"hye": {
|
"hye": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -997,7 +997,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ia": {
|
"ia": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1017,7 +1017,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1037,7 +1037,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"is": {
|
"is": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1057,7 +1057,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"it": {
|
"it": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1077,7 +1077,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ja": {
|
"ja": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1095,7 +1095,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ja-JP-mac": {
|
"ja-JP-mac": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1103,7 +1103,7 @@
|
||||||
"macosx64",
|
"macosx64",
|
||||||
"macosx64-devedition"
|
"macosx64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ka": {
|
"ka": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1123,7 +1123,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"kab": {
|
"kab": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1143,7 +1143,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"kk": {
|
"kk": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1163,7 +1163,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"km": {
|
"km": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1183,7 +1183,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"kn": {
|
"kn": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1203,7 +1203,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ko": {
|
"ko": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1223,7 +1223,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"lij": {
|
"lij": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1243,7 +1243,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"lo": {
|
"lo": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1263,7 +1263,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"lt": {
|
"lt": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1283,7 +1283,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ltg": {
|
"ltg": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1303,7 +1303,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"lv": {
|
"lv": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1323,7 +1323,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"meh": {
|
"meh": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1343,7 +1343,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"mk": {
|
"mk": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1363,7 +1363,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ml": {
|
"ml": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1383,7 +1383,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"mr": {
|
"mr": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1403,7 +1403,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1423,7 +1423,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"my": {
|
"my": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1443,7 +1443,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"nb-NO": {
|
"nb-NO": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1463,7 +1463,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ne-NP": {
|
"ne-NP": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1483,7 +1483,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"nl": {
|
"nl": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1503,7 +1503,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"nn-NO": {
|
"nn-NO": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1523,7 +1523,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"oc": {
|
"oc": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1543,7 +1543,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"pa-IN": {
|
"pa-IN": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1563,7 +1563,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"pl": {
|
"pl": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1583,7 +1583,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"pt-BR": {
|
"pt-BR": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1603,7 +1603,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"pt-PT": {
|
"pt-PT": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1623,7 +1623,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"rm": {
|
"rm": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1643,7 +1643,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ro": {
|
"ro": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1663,7 +1663,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ru": {
|
"ru": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1683,7 +1683,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sat": {
|
"sat": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1703,7 +1703,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sc": {
|
"sc": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1723,7 +1723,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"scn": {
|
"scn": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1743,7 +1743,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sco": {
|
"sco": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1763,7 +1763,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"si": {
|
"si": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1783,7 +1783,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sk": {
|
"sk": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1803,7 +1803,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"skr": {
|
"skr": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1823,7 +1823,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sl": {
|
"sl": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1843,7 +1843,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"son": {
|
"son": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1863,7 +1863,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sq": {
|
"sq": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1883,7 +1883,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sr": {
|
"sr": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1903,7 +1903,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"sv-SE": {
|
"sv-SE": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1923,7 +1923,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"szl": {
|
"szl": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1943,7 +1943,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ta": {
|
"ta": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1963,7 +1963,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"te": {
|
"te": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -1983,7 +1983,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"tg": {
|
"tg": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2003,7 +2003,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"th": {
|
"th": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2023,7 +2023,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"tl": {
|
"tl": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2043,7 +2043,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"tr": {
|
"tr": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2063,7 +2063,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"trs": {
|
"trs": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2083,7 +2083,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"uk": {
|
"uk": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2103,7 +2103,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"ur": {
|
"ur": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2123,7 +2123,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"uz": {
|
"uz": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2143,7 +2143,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"vi": {
|
"vi": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2163,7 +2163,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"wo": {
|
"wo": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2183,7 +2183,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"xh": {
|
"xh": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2203,7 +2203,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"zh-CN": {
|
"zh-CN": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2223,7 +2223,7 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
},
|
},
|
||||||
"zh-TW": {
|
"zh-TW": {
|
||||||
"pin": false,
|
"pin": false,
|
||||||
|
@ -2243,6 +2243,6 @@
|
||||||
"win64-aarch64-devedition",
|
"win64-aarch64-devedition",
|
||||||
"win64-devedition"
|
"win64-devedition"
|
||||||
],
|
],
|
||||||
"revision": "dd8d34b0244b4db61494c64d78c4b96bf367f2df"
|
"revision": "e234130176d2813fec2397bbf3a313909565006e"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -221,7 +221,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
#tabbrowser-tabs[movingtab] &[fadein]:not([selected]):not([multiselected]),
|
#tabbrowser-tabs[movingtab] :not(tab-group:active) > &[fadein]:not(:active, [multiselected]),
|
||||||
&[multiselected-move-together],
|
&[multiselected-move-together],
|
||||||
&[tabdrop-samewindow] {
|
&[tabdrop-samewindow] {
|
||||||
transition: var(--tab-dragover-transition);
|
transition: var(--tab-dragover-transition);
|
||||||
|
@ -1028,9 +1028,7 @@
|
||||||
pointer-events: none; /* avoid blocking dragover events on scroll buttons */
|
pointer-events: none; /* avoid blocking dragover events on scroll buttons */
|
||||||
}
|
}
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
#tabbrowser-tabs[movingtab] &,
|
#tabbrowser-tabs[movingtab] &:not(:active) {
|
||||||
&[multiselected-move-together],
|
|
||||||
&[tabdrop-samewindow] {
|
|
||||||
transition: var(--tab-dragover-transition);
|
transition: var(--tab-dragover-transition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,12 @@
|
||||||
@media (-moz-windows-mica) {
|
@media (-moz-windows-mica) {
|
||||||
&:not([lwtheme]) {
|
&:not([lwtheme]) {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
||||||
|
/* stylelint-disable-next-line media-query-no-invalid */
|
||||||
|
@media -moz-pref("widget.windows.mica.toplevel-backdrop", 2) {
|
||||||
|
/* For acrylic, do the same we do for popups to guarantee some contrast */
|
||||||
|
background-color: light-dark(rgba(255, 255, 255, .6), rgba(0, 0, 0, .6));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository ->
|
gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository ->
|
||||||
maven {
|
maven {
|
||||||
url repository
|
url = repository
|
||||||
if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) {
|
if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) {
|
||||||
allowInsecureProtocol = true
|
allowInsecureProtocol = true
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository ->
|
gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository ->
|
||||||
maven {
|
maven {
|
||||||
url repository
|
url = repository
|
||||||
if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) {
|
if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) {
|
||||||
allowInsecureProtocol = true
|
allowInsecureProtocol = true
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ allprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadDependencies() {
|
task downloadDependencies() {
|
||||||
description 'Download all dependencies to the Gradle cache'
|
description = 'Download all dependencies to the Gradle cache'
|
||||||
doLast {
|
doLast {
|
||||||
configurations.each { configuration ->
|
configurations.each { configuration ->
|
||||||
if (configuration.canBeResolved) {
|
if (configuration.canBeResolved) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ def android_sdk_version():
|
||||||
# If you think you can't handle the whole set of changes, please reach out to the Release
|
# If you think you can't handle the whole set of changes, please reach out to the Release
|
||||||
# Engineering team.
|
# Engineering team.
|
||||||
return namespace(
|
return namespace(
|
||||||
build_tools_version="35.0.0",
|
build_tools_version="35.0.1",
|
||||||
compile_sdk_version="35",
|
compile_sdk_version="35",
|
||||||
target_sdk_version="35",
|
target_sdk_version="35",
|
||||||
min_sdk_version="21",
|
min_sdk_version="21",
|
||||||
|
|
|
@ -577,6 +577,10 @@ netmonitor.toolbar.priority=Priority
|
||||||
# in the network table toolbar, above the "file" column.
|
# in the network table toolbar, above the "file" column.
|
||||||
netmonitor.toolbar.file=File
|
netmonitor.toolbar.file=File
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (netmonitor.toolbar.path): This is the label displayed
|
||||||
|
# in the network table toolbar, above the "Path" column.
|
||||||
|
netmonitor.toolbar.path=Path
|
||||||
|
|
||||||
# LOCALIZATION NOTE (netmonitor.toolbar.url): This is the label displayed
|
# LOCALIZATION NOTE (netmonitor.toolbar.url): This is the label displayed
|
||||||
# in the network table toolbar, above the "url" column.
|
# in the network table toolbar, above the "url" column.
|
||||||
netmonitor.toolbar.url=URL
|
netmonitor.toolbar.url=URL
|
||||||
|
|
|
@ -70,6 +70,14 @@ perftools-button-add-directory = Add a directory
|
||||||
perftools-button-remove-directory = Remove selected
|
perftools-button-remove-directory = Remove selected
|
||||||
perftools-button-edit-settings = Edit Settings…
|
perftools-button-edit-settings = Edit Settings…
|
||||||
|
|
||||||
|
## More actions menu
|
||||||
|
|
||||||
|
perftools-menu-more-actions-button =
|
||||||
|
.title = More actions
|
||||||
|
perftools-menu-more-actions-restart-with-profiling = Restart { -brand-shorter-name } with startup profiling enabled
|
||||||
|
perftools-menu-more-actions-copy-for-startup = Copy environment variables for startup profiling
|
||||||
|
perftools-menu-more-actions-copy-for-perf-tests = Copy parameters for performance tests
|
||||||
|
|
||||||
## These messages are descriptions of the threads that can be enabled for the profiler.
|
## These messages are descriptions of the threads that can be enabled for the profiler.
|
||||||
|
|
||||||
perftools-thread-gecko-main =
|
perftools-thread-gecko-main =
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component,
|
||||||
|
} = require("resource://devtools/client/shared/vendor/react.js");
|
||||||
|
const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
|
||||||
|
const {
|
||||||
|
L10N,
|
||||||
|
} = require("resource://devtools/client/netmonitor/src/utils/l10n.js");
|
||||||
|
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
|
||||||
|
const {
|
||||||
|
connect,
|
||||||
|
} = require("resource://devtools/client/shared/vendor/react-redux.js");
|
||||||
|
const {
|
||||||
|
propertiesEqual,
|
||||||
|
} = require("resource://devtools/client/netmonitor/src/utils/request-utils.js");
|
||||||
|
const { truncateString } = require("resource://devtools/shared/string.js");
|
||||||
|
const {
|
||||||
|
MAX_UI_STRING_LENGTH,
|
||||||
|
} = require("resource://devtools/client/netmonitor/src/constants.js");
|
||||||
|
const {
|
||||||
|
getOverriddenUrl,
|
||||||
|
} = require("resource://devtools/client/netmonitor/src/selectors/index.js");
|
||||||
|
|
||||||
|
const UPDATED_FILE_PROPS = ["urlDetails", "waitingTime"];
|
||||||
|
|
||||||
|
class RequestListColumnPath extends Component {
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
item: PropTypes.object.isRequired,
|
||||||
|
onWaterfallMouseDown: PropTypes.func,
|
||||||
|
isOverridden: PropTypes.bool.isRequired,
|
||||||
|
overriddenUrl: PropTypes.string,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
return (
|
||||||
|
!propertiesEqual(UPDATED_FILE_PROPS, this.props.item, nextProps.item) ||
|
||||||
|
nextProps.overriddenUrl !== this.props.overriddenUrl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
item: { urlDetails },
|
||||||
|
isOverridden,
|
||||||
|
overriddenUrl,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const originalFileURL = urlDetails.url;
|
||||||
|
const decodedFileURL = urlDetails.unicodeUrl;
|
||||||
|
const ORIGINAL_FILE_URL = L10N.getFormatStr(
|
||||||
|
"netRequest.originalFileURL.tooltip",
|
||||||
|
originalFileURL
|
||||||
|
);
|
||||||
|
const DECODED_FILE_URL = L10N.getFormatStr(
|
||||||
|
"netRequest.decodedFileURL.tooltip",
|
||||||
|
decodedFileURL
|
||||||
|
);
|
||||||
|
const requestedPath = urlDetails.path;
|
||||||
|
const fileToolTip =
|
||||||
|
originalFileURL === decodedFileURL
|
||||||
|
? originalFileURL
|
||||||
|
: ORIGINAL_FILE_URL + "\n\n" + DECODED_FILE_URL;
|
||||||
|
|
||||||
|
// Build extra content for the title if the request is overridden.
|
||||||
|
const overrideTitle = isOverridden ? ` → ${overriddenUrl}` : "";
|
||||||
|
|
||||||
|
return dom.td(
|
||||||
|
{
|
||||||
|
className: "requests-list-column requests-list-path",
|
||||||
|
title:
|
||||||
|
truncateString(fileToolTip, MAX_UI_STRING_LENGTH) + overrideTitle,
|
||||||
|
},
|
||||||
|
dom.div({}, truncateString(requestedPath, MAX_UI_STRING_LENGTH))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(
|
||||||
|
(state, props) => {
|
||||||
|
const overriddenUrl = getOverriddenUrl(state, props.item.urlDetails?.url);
|
||||||
|
return {
|
||||||
|
isOverridden: !!overriddenUrl,
|
||||||
|
overriddenUrl,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
undefined,
|
||||||
|
{ storeKey: "toolbox-store" }
|
||||||
|
)(RequestListColumnPath);
|
|
@ -26,6 +26,7 @@ const {
|
||||||
RequestListColumnCookies,
|
RequestListColumnCookies,
|
||||||
RequestListColumnDomain,
|
RequestListColumnDomain,
|
||||||
RequestListColumnFile,
|
RequestListColumnFile,
|
||||||
|
RequestListColumnPath,
|
||||||
RequestListColumnMethod,
|
RequestListColumnMethod,
|
||||||
RequestListColumnProtocol,
|
RequestListColumnProtocol,
|
||||||
RequestListColumnRemoteIP,
|
RequestListColumnRemoteIP,
|
||||||
|
@ -65,6 +66,11 @@ loader.lazyGetter(this, "RequestListColumnFile", function () {
|
||||||
require("resource://devtools/client/netmonitor/src/components/request-list/RequestListColumnFile.js")
|
require("resource://devtools/client/netmonitor/src/components/request-list/RequestListColumnFile.js")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
loader.lazyGetter(this, "RequestListColumnPath", function () {
|
||||||
|
return createFactory(
|
||||||
|
require("resource://devtools/client/netmonitor/src/components/request-list/RequestListColumnPath.js")
|
||||||
|
);
|
||||||
|
});
|
||||||
loader.lazyGetter(this, "RequestListColumnUrl", function () {
|
loader.lazyGetter(this, "RequestListColumnUrl", function () {
|
||||||
return createFactory(
|
return createFactory(
|
||||||
require("resource://devtools/client/netmonitor/src/components/request-list/RequestListColumnUrl.js")
|
require("resource://devtools/client/netmonitor/src/components/request-list/RequestListColumnUrl.js")
|
||||||
|
@ -199,6 +205,11 @@ const COLUMN_COMPONENTS = [
|
||||||
ColumnComponent: RequestListColumnFile,
|
ColumnComponent: RequestListColumnFile,
|
||||||
props: ["onWaterfallMouseDown", "slowLimit"],
|
props: ["onWaterfallMouseDown", "slowLimit"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
column: "path",
|
||||||
|
ColumnComponent: RequestListColumnPath,
|
||||||
|
props: ["onWaterfallMouseDown"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
column: "url",
|
column: "url",
|
||||||
ColumnComponent: RequestListColumnUrl,
|
ColumnComponent: RequestListColumnUrl,
|
||||||
|
|
|
@ -11,6 +11,7 @@ DevToolsModules(
|
||||||
"RequestListColumnInitiator.js",
|
"RequestListColumnInitiator.js",
|
||||||
"RequestListColumnMethod.js",
|
"RequestListColumnMethod.js",
|
||||||
"RequestListColumnOverride.js",
|
"RequestListColumnOverride.js",
|
||||||
|
"RequestListColumnPath.js",
|
||||||
"RequestListColumnPriority.js",
|
"RequestListColumnPriority.js",
|
||||||
"RequestListColumnProtocol.js",
|
"RequestListColumnProtocol.js",
|
||||||
"RequestListColumnRemoteIP.js",
|
"RequestListColumnRemoteIP.js",
|
||||||
|
|
|
@ -299,6 +299,10 @@ const HEADERS = [
|
||||||
name: "file",
|
name: "file",
|
||||||
canFilter: false,
|
canFilter: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "path",
|
||||||
|
canFilter: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "url",
|
name: "url",
|
||||||
canFilter: true,
|
canFilter: true,
|
||||||
|
|
|
@ -33,6 +33,7 @@ const cols = {
|
||||||
method: true,
|
method: true,
|
||||||
domain: true,
|
domain: true,
|
||||||
file: true,
|
file: true,
|
||||||
|
path: false,
|
||||||
url: false,
|
url: false,
|
||||||
protocol: false,
|
protocol: false,
|
||||||
scheme: false,
|
scheme: false,
|
||||||
|
|
|
@ -292,6 +292,18 @@ function getUrlScheme(url) {
|
||||||
return protocol.replace(":", "").toLowerCase();
|
return protocol.replace(":", "").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for getting the full path portion of a url.
|
||||||
|
*
|
||||||
|
* @param {string|URL} url - unvalidated url string or URL instance
|
||||||
|
* @return {string} string path of a url
|
||||||
|
*/
|
||||||
|
function getUrlPath(url) {
|
||||||
|
const href = getUrlProperty(url, "href");
|
||||||
|
const origin = getUrlProperty(url, "origin");
|
||||||
|
return href.replace(origin, "");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract several details fields from a URL at once.
|
* Extract several details fields from a URL at once.
|
||||||
*/
|
*/
|
||||||
|
@ -302,6 +314,7 @@ function getUrlDetails(url) {
|
||||||
const hostname = getUrlHostName(urlObject);
|
const hostname = getUrlHostName(urlObject);
|
||||||
const unicodeUrl = getUnicodeUrl(urlObject);
|
const unicodeUrl = getUnicodeUrl(urlObject);
|
||||||
const scheme = getUrlScheme(urlObject);
|
const scheme = getUrlScheme(urlObject);
|
||||||
|
const path = getUrlPath(urlObject);
|
||||||
|
|
||||||
// If the hostname contains unreadable ASCII characters, we need to do the
|
// If the hostname contains unreadable ASCII characters, we need to do the
|
||||||
// following two steps:
|
// following two steps:
|
||||||
|
@ -338,6 +351,7 @@ function getUrlDetails(url) {
|
||||||
unicodeUrl,
|
unicodeUrl,
|
||||||
isLocal,
|
isLocal,
|
||||||
url,
|
url,
|
||||||
|
path,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,8 @@ skip-if = [
|
||||||
|
|
||||||
["browser_net_column_headers_tooltips.js"]
|
["browser_net_column_headers_tooltips.js"]
|
||||||
|
|
||||||
|
["browser_net_column_path.js"]
|
||||||
|
|
||||||
["browser_net_column_slow-request-indicator.js"]
|
["browser_net_column_slow-request-indicator.js"]
|
||||||
|
|
||||||
["browser_net_columns_last_column.js"]
|
["browser_net_columns_last_column.js"]
|
||||||
|
|
46
devtools/client/netmonitor/test/browser_net_column_path.js
Normal file
46
devtools/client/netmonitor/test/browser_net_column_path.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for path column. Note that the column
|
||||||
|
* header is visible only if there are requests in the list.
|
||||||
|
*/
|
||||||
|
add_task(async function () {
|
||||||
|
const { monitor, tab } = await initNetMonitor(SIMPLE_URL, {
|
||||||
|
requestCount: 1,
|
||||||
|
});
|
||||||
|
const { document } = monitor.panelWin;
|
||||||
|
info("Starting test... ");
|
||||||
|
|
||||||
|
const onNetworkEvents = waitForNetworkEvents(monitor, 2);
|
||||||
|
await reloadBrowser();
|
||||||
|
await ContentTask.spawn(tab.linkedBrowser, null, () => {
|
||||||
|
content.wrappedJSObject.fetch("data:text/plain,some_text");
|
||||||
|
});
|
||||||
|
await onNetworkEvents;
|
||||||
|
|
||||||
|
await showColumn(monitor, "path");
|
||||||
|
|
||||||
|
const pathColumn = document.querySelector(`.requests-list-path`);
|
||||||
|
const requestList = document.querySelectorAll(
|
||||||
|
".network-monitor .request-list-item"
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(pathColumn, "Path column should be visible");
|
||||||
|
is(
|
||||||
|
requestList[0].querySelector(".requests-list-path div:first-child")
|
||||||
|
.textContent,
|
||||||
|
"/browser/devtools/client/netmonitor/test/html_simple-test-page.html",
|
||||||
|
"Path content should contain the request url without origin"
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
requestList[1].querySelector(".requests-list-path div:first-child")
|
||||||
|
.textContent,
|
||||||
|
"data:text/plain,some_text",
|
||||||
|
"Path content should contain the data url"
|
||||||
|
);
|
||||||
|
|
||||||
|
await teardown(monitor);
|
||||||
|
});
|
15
devtools/client/performance-new/@types/perf.d.ts
vendored
15
devtools/client/performance-new/@types/perf.d.ts
vendored
|
@ -186,15 +186,6 @@ export type ReceiveProfile = (
|
||||||
getSymbolTableCallback: GetSymbolTableCallback
|
getSymbolTableCallback: GetSymbolTableCallback
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the type signature for a function to restart the browser with a given
|
|
||||||
* environment variable. Currently only implemented for the popup.
|
|
||||||
*/
|
|
||||||
export type RestartBrowserWithEnvironmentVariable = (
|
|
||||||
envName: string,
|
|
||||||
value: string
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the type signature for the event listener that's called once the
|
* This is the type signature for the event listener that's called once the
|
||||||
* profile has been obtained.
|
* profile has been obtained.
|
||||||
|
@ -397,6 +388,12 @@ export interface PerformancePref {
|
||||||
* button in the customization palette.
|
* button in the customization palette.
|
||||||
*/
|
*/
|
||||||
PopupFeatureFlag: "devtools.performance.popup.feature-flag";
|
PopupFeatureFlag: "devtools.performance.popup.feature-flag";
|
||||||
|
/**
|
||||||
|
* This preference controls whether about:profiling contains some Firefox
|
||||||
|
* developer-specific options. For example when true the "more actions" menu
|
||||||
|
* contains items to copy parameters to use with mach try perf.
|
||||||
|
*/
|
||||||
|
AboutProfilingHasDeveloperOptions: "devtools.performance.aboutprofiling.has-developer-options";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The next 2 types bring some duplication from gecko.d.ts, but this is simpler
|
/* The next 2 types bring some duplication from gecko.d.ts, but this is simpler
|
||||||
|
|
|
@ -4,22 +4,8 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template P
|
|
||||||
* @typedef {import("react-redux").ResolveThunks<P>} ResolveThunks<P>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} StateProps
|
|
||||||
* @property {boolean?} isSupportedPlatform
|
|
||||||
* @property {PageContext} pageContext
|
|
||||||
* @property {string | null} promptEnvRestart
|
|
||||||
* @property {(() => void) | undefined} openRemoteDevTools
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {StateProps} Props
|
|
||||||
* @typedef {import("../../@types/perf").State} StoreState
|
* @typedef {import("../../@types/perf").State} StoreState
|
||||||
* @typedef {import("../../@types/perf").PageContext} PageContext
|
* @typedef {import("../../@types/perf").PerformancePref} PerformancePref
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -27,6 +13,9 @@
|
||||||
const {
|
const {
|
||||||
PureComponent,
|
PureComponent,
|
||||||
createFactory,
|
createFactory,
|
||||||
|
createElement: h,
|
||||||
|
Fragment,
|
||||||
|
createRef,
|
||||||
} = require("resource://devtools/client/shared/vendor/react.mjs");
|
} = require("resource://devtools/client/shared/vendor/react.mjs");
|
||||||
const {
|
const {
|
||||||
connect,
|
connect,
|
||||||
|
@ -51,6 +40,209 @@ const {
|
||||||
restartBrowserWithEnvironmentVariable,
|
restartBrowserWithEnvironmentVariable,
|
||||||
} = require("resource://devtools/client/performance-new/shared/browser.js");
|
} = require("resource://devtools/client/performance-new/shared/browser.js");
|
||||||
|
|
||||||
|
/** @type {PerformancePref["AboutProfilingHasDeveloperOptions"]} */
|
||||||
|
const ABOUTPROFILING_HAS_DEVELOPER_OPTIONS_PREF =
|
||||||
|
"devtools.performance.aboutprofiling.has-developer-options";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function encodes the parameter so that it can be used as an environment
|
||||||
|
* variable value.
|
||||||
|
* Basically it uses single quotes, but replacing any single quote by '"'"':
|
||||||
|
* 1. close the previous single-quoted string,
|
||||||
|
* 2. add a double-quoted string containing only a single quote
|
||||||
|
* 3. start a single-quoted string again.
|
||||||
|
* so that it's properly retained.
|
||||||
|
*
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function encodeShellValue(value) {
|
||||||
|
return "'" + value.replaceAll("'", `'"'"'`) + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../../@types/perf").RecordingSettings} RecordingSettings
|
||||||
|
*
|
||||||
|
* @typedef {Object} ButtonStateProps
|
||||||
|
* @property {RecordingSettings} recordingSettings
|
||||||
|
*
|
||||||
|
* @typedef {ButtonStateProps} ButtonProps
|
||||||
|
*
|
||||||
|
* @typedef {Object} ButtonState
|
||||||
|
* @property {boolean} hasDeveloperOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component implements the button that triggers the menu that makes it
|
||||||
|
* possible to show more actions.
|
||||||
|
* @extends {React.PureComponent<ButtonProps, ButtonState>}
|
||||||
|
*/
|
||||||
|
class MoreActionsButtonImpl extends PureComponent {
|
||||||
|
state = {
|
||||||
|
hasDeveloperOptions: Services.prefs.getBoolPref(
|
||||||
|
ABOUTPROFILING_HAS_DEVELOPER_OPTIONS_PREF,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
Services.prefs.addObserver(
|
||||||
|
ABOUTPROFILING_HAS_DEVELOPER_OPTIONS_PREF,
|
||||||
|
this.onHasDeveloperOptionsPrefChanges
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
Services.prefs.removeObserver(
|
||||||
|
ABOUTPROFILING_HAS_DEVELOPER_OPTIONS_PREF,
|
||||||
|
this.onHasDeveloperOptionsPrefChanges
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_menuRef = createRef();
|
||||||
|
|
||||||
|
onHasDeveloperOptionsPrefChanges = () => {
|
||||||
|
this.setState({
|
||||||
|
hasDeveloperOptions: Services.prefs.getBoolPref(
|
||||||
|
ABOUTPROFILING_HAS_DEVELOPER_OPTIONS_PREF,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See the part "Showing the menu" in
|
||||||
|
* https://searchfox.org/mozilla-central/rev/4bacdbc8ac088f2ee516daf42c535fab2bc24a04/toolkit/content/widgets/panel-list/README.stories.md
|
||||||
|
* Strangely our React's type doesn't have the `detail` property for
|
||||||
|
* MouseEvent, so we're defining it manually.
|
||||||
|
* @param {React.MouseEvent & { detail: number }} e
|
||||||
|
*/
|
||||||
|
handleClickOrMousedown = e => {
|
||||||
|
// The menu is toggled either for a "mousedown", or for a keyboard enter
|
||||||
|
// (which triggers a "click" event with 0 clicks (detail == 0)).
|
||||||
|
if (this._menuRef.current && (e.type == "mousedown" || e.detail === 0)) {
|
||||||
|
this._menuRef.current.toggle(e.nativeEvent, e.currentTarget);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
getEnvironmentVariablesForStartupFromRecordingSettings = () => {
|
||||||
|
const { interval, entries, threads, features } =
|
||||||
|
this.props.recordingSettings;
|
||||||
|
return {
|
||||||
|
MOZ_PROFILER_STARTUP: "1",
|
||||||
|
MOZ_PROFILER_STARTUP_INTERVAL: String(interval),
|
||||||
|
MOZ_PROFILER_STARTUP_ENTRIES: String(entries),
|
||||||
|
MOZ_PROFILER_STARTUP_FEATURES: features.join(","),
|
||||||
|
MOZ_PROFILER_STARTUP_FILTERS: threads.join(","),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
onRestartWithProfiling = () => {
|
||||||
|
const envVariables =
|
||||||
|
this.getEnvironmentVariablesForStartupFromRecordingSettings();
|
||||||
|
restartBrowserWithEnvironmentVariable(envVariables);
|
||||||
|
};
|
||||||
|
|
||||||
|
onCopyEnvVariables = async () => {
|
||||||
|
const envVariables =
|
||||||
|
this.getEnvironmentVariablesForStartupFromRecordingSettings();
|
||||||
|
const envString = Object.entries(envVariables)
|
||||||
|
.map(([key, value]) => `${key}=${encodeShellValue(value)}`)
|
||||||
|
.join(" ");
|
||||||
|
await navigator.clipboard.writeText(envString);
|
||||||
|
};
|
||||||
|
|
||||||
|
onCopyTestVariables = async () => {
|
||||||
|
const { interval, entries, threads, features } =
|
||||||
|
this.props.recordingSettings;
|
||||||
|
|
||||||
|
const envString =
|
||||||
|
"--gecko-profile" +
|
||||||
|
` --gecko-profile-interval ${interval}` +
|
||||||
|
` --gecko-profile-entries ${entries}` +
|
||||||
|
` --gecko-profile-features ${encodeShellValue(features.join(","))}` +
|
||||||
|
` --gecko-profile-threads ${encodeShellValue(threads.join(","))}`;
|
||||||
|
await navigator.clipboard.writeText(envString);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return h(
|
||||||
|
Fragment,
|
||||||
|
null,
|
||||||
|
Localized(
|
||||||
|
{
|
||||||
|
id: "perftools-menu-more-actions-button",
|
||||||
|
attrs: { title: true },
|
||||||
|
},
|
||||||
|
h("moz-button", {
|
||||||
|
iconsrc: "chrome://global/skin/icons/more.svg",
|
||||||
|
"aria-expanded": "false",
|
||||||
|
"aria-haspopup": "menu",
|
||||||
|
onClick: this.handleClickOrMousedown,
|
||||||
|
onMouseDown: this.handleClickOrMousedown,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
"panel-list",
|
||||||
|
{ ref: this._menuRef },
|
||||||
|
Localized(
|
||||||
|
{ id: "perftools-menu-more-actions-restart-with-profiling" },
|
||||||
|
h(
|
||||||
|
"panel-item",
|
||||||
|
{ onClick: this.onRestartWithProfiling },
|
||||||
|
"Restart Firefox with startup profiling enabled"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
this.state.hasDeveloperOptions
|
||||||
|
? Localized(
|
||||||
|
{ id: "perftools-menu-more-actions-copy-for-startup" },
|
||||||
|
h(
|
||||||
|
"panel-item",
|
||||||
|
{ onClick: this.onCopyEnvVariables },
|
||||||
|
"Copy environment variables for startup profiling"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
this.state.hasDeveloperOptions
|
||||||
|
? Localized(
|
||||||
|
{ id: "perftools-menu-more-actions-copy-for-perf-tests" },
|
||||||
|
h(
|
||||||
|
"panel-item",
|
||||||
|
{ onClick: this.onCopyTestVariables },
|
||||||
|
"Copy parameters for mach try perf"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StoreState} state
|
||||||
|
* @returns {ButtonStateProps}
|
||||||
|
*/
|
||||||
|
function mapStateToButtonProps(state) {
|
||||||
|
return {
|
||||||
|
recordingSettings: selectors.getRecordingSettings(state),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const MoreActionsButton = connect(mapStateToButtonProps)(MoreActionsButtonImpl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../../@types/perf").PageContext} PageContext
|
||||||
|
*
|
||||||
|
* @typedef {Object} StateProps
|
||||||
|
* @property {boolean?} isSupportedPlatform
|
||||||
|
* @property {PageContext} pageContext
|
||||||
|
* @property {string | null} promptEnvRestart
|
||||||
|
* @property {(() => void) | undefined} openRemoteDevTools
|
||||||
|
*
|
||||||
|
* @typedef {StateProps} Props
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the top level component for the about:profiling page. It shares components
|
* This is the top level component for the about:profiling page. It shares components
|
||||||
* with the popup and DevTools page.
|
* with the popup and DevTools page.
|
||||||
|
@ -58,16 +250,6 @@ const {
|
||||||
* @extends {React.PureComponent<Props>}
|
* @extends {React.PureComponent<Props>}
|
||||||
*/
|
*/
|
||||||
class AboutProfiling extends PureComponent {
|
class AboutProfiling extends PureComponent {
|
||||||
handleRestart = () => {
|
|
||||||
const { promptEnvRestart } = this.props;
|
|
||||||
if (!promptEnvRestart) {
|
|
||||||
throw new Error(
|
|
||||||
"handleRestart() should only be called when promptEnvRestart exists."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
restartBrowserWithEnvironmentVariable(promptEnvRestart, "1");
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
isSupportedPlatform,
|
isSupportedPlatform,
|
||||||
|
@ -97,7 +279,11 @@ class AboutProfiling extends PureComponent {
|
||||||
{
|
{
|
||||||
className: "perf-photon-button perf-photon-button-micro",
|
className: "perf-photon-button perf-photon-button-micro",
|
||||||
type: "button",
|
type: "button",
|
||||||
onClick: this.handleRestart,
|
onClick: () => {
|
||||||
|
restartBrowserWithEnvironmentVariable({
|
||||||
|
[promptEnvRestart]: "1",
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Localized({ id: "perftools-button-restart" })
|
Localized({ id: "perftools-button-restart" })
|
||||||
)
|
)
|
||||||
|
@ -121,9 +307,13 @@ class AboutProfiling extends PureComponent {
|
||||||
|
|
||||||
div(
|
div(
|
||||||
{ className: "perf-intro" },
|
{ className: "perf-intro" },
|
||||||
h1(
|
div(
|
||||||
{ className: "perf-intro-title" },
|
{ className: "perf-intro-title-bar" },
|
||||||
Localized({ id: "perftools-intro-title" })
|
h1(
|
||||||
|
{ className: "perf-intro-title" },
|
||||||
|
Localized({ id: "perftools-intro-title" })
|
||||||
|
),
|
||||||
|
h(MoreActionsButton)
|
||||||
),
|
),
|
||||||
div(
|
div(
|
||||||
{ className: "perf-intro-row" },
|
{ className: "perf-intro-row" },
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
* @typedef {import("../@types/perf").PreferenceFront} PreferenceFront
|
* @typedef {import("../@types/perf").PreferenceFront} PreferenceFront
|
||||||
* @typedef {import("../@types/perf").PerformancePref} PerformancePref
|
* @typedef {import("../@types/perf").PerformancePref} PerformancePref
|
||||||
* @typedef {import("../@types/perf").RecordingSettings} RecordingSettings
|
* @typedef {import("../@types/perf").RecordingSettings} RecordingSettings
|
||||||
* @typedef {import("../@types/perf").RestartBrowserWithEnvironmentVariable} RestartBrowserWithEnvironmentVariable
|
|
||||||
* @typedef {import("../@types/perf").GetActiveBrowserID} GetActiveBrowserID
|
* @typedef {import("../@types/perf").GetActiveBrowserID} GetActiveBrowserID
|
||||||
* @typedef {import("../@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
|
* @typedef {import("../@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
|
||||||
* @typedef {import("../@types/perf").ProfilerViewMode} ProfilerViewMode
|
* @typedef {import("../@types/perf").ProfilerViewMode} ProfilerViewMode
|
||||||
|
@ -145,10 +144,12 @@ function sharedLibrariesFromProfile(profile) {
|
||||||
/**
|
/**
|
||||||
* Restarts the browser with a given environment variable set to a value.
|
* Restarts the browser with a given environment variable set to a value.
|
||||||
*
|
*
|
||||||
* @type {RestartBrowserWithEnvironmentVariable}
|
* @param {Record<string, string>} env
|
||||||
*/
|
*/
|
||||||
function restartBrowserWithEnvironmentVariable(envName, value) {
|
function restartBrowserWithEnvironmentVariable(env) {
|
||||||
Services.env.set(envName, value);
|
for (const [envName, envValue] of Object.entries(env)) {
|
||||||
|
Services.env.set(envName, envValue);
|
||||||
|
}
|
||||||
|
|
||||||
Services.startup.quit(
|
Services.startup.quit(
|
||||||
Services.startup.eForceQuit | Services.startup.eRestart
|
Services.startup.eForceQuit | Services.startup.eRestart
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
* @typedef {import("../@types/perf").InitializedValues} InitializedValues
|
* @typedef {import("../@types/perf").InitializedValues} InitializedValues
|
||||||
* @typedef {import("../@types/perf").PerfFront} PerfFront
|
* @typedef {import("../@types/perf").PerfFront} PerfFront
|
||||||
* @typedef {import("../@types/perf").ReceiveProfile} ReceiveProfile
|
* @typedef {import("../@types/perf").ReceiveProfile} ReceiveProfile
|
||||||
* @typedef {import("../@types/perf").RestartBrowserWithEnvironmentVariable} RestartBrowserWithEnvironmentVariable
|
|
||||||
* @typedef {import("../@types/perf").PageContext} PageContext
|
* @typedef {import("../@types/perf").PageContext} PageContext
|
||||||
* @typedef {import("../@types/perf").Presets} Presets
|
* @typedef {import("../@types/perf").Presets} Presets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,6 +26,8 @@ support-files = [
|
||||||
|
|
||||||
["browser_aboutprofiling-interval.js"]
|
["browser_aboutprofiling-interval.js"]
|
||||||
|
|
||||||
|
["browser_aboutprofiling-more-actions-menu.js"]
|
||||||
|
|
||||||
["browser_aboutprofiling-presets-custom.js"]
|
["browser_aboutprofiling-presets-custom.js"]
|
||||||
|
|
||||||
["browser_aboutprofiling-presets.js"]
|
["browser_aboutprofiling-presets.js"]
|
||||||
|
|
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