Merge fx-team to m-c a=merge
|
@ -21,12 +21,16 @@ add_task(function*() {
|
|||
let panelShownPromise = promisePanelElementShown(window, widgetOverflowPanel);
|
||||
let identityBox = document.getElementById("identity-box");
|
||||
let overflowChevron = document.getElementById("nav-bar-overflow-button");
|
||||
|
||||
// Listen for hiding immediately so we don't miss the event because of the
|
||||
// async-ness of the 'shown' yield...
|
||||
let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
|
||||
|
||||
ChromeUtils.synthesizeDrop(identityBox, overflowChevron, [], null);
|
||||
yield panelShownPromise;
|
||||
|
||||
info("Overflow panel is shown.");
|
||||
|
||||
let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
|
||||
widgetOverflowPanel.hidePopup();
|
||||
yield panelHiddenPromise;
|
||||
});
|
||||
|
|
|
@ -20,6 +20,7 @@ Cu.import("resource://gre/modules/Task.jsm", this);
|
|||
|
||||
const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER};
|
||||
const DAILY_LAST_TEXT_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT};
|
||||
const DAILY_LAST_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC};
|
||||
|
||||
|
||||
this.Translation = {
|
||||
|
@ -300,6 +301,8 @@ TranslationMeasurement1.prototype = Object.freeze({
|
|||
pageTranslatedCountsByLanguage: DAILY_LAST_TEXT_FIELD,
|
||||
detectedLanguageChangedBefore: DAILY_COUNTER_FIELD,
|
||||
detectedLanguageChangedAfter: DAILY_COUNTER_FIELD,
|
||||
detectLanguageEnabled: DAILY_LAST_NUMERIC_FIELD,
|
||||
showTranslationUI: DAILY_LAST_NUMERIC_FIELD,
|
||||
},
|
||||
|
||||
shouldIncludeField: function (field) {
|
||||
|
@ -324,7 +327,7 @@ TranslationMeasurement1.prototype = Object.freeze({
|
|||
|
||||
return data;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
_wrapJSONSerializer: function (serializer) {
|
||||
let _parseInPlace = function(o, k) {
|
||||
|
@ -414,6 +417,19 @@ TranslationProvider.prototype = Object.freeze({
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
collectDailyData: function () {
|
||||
let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
|
||||
TranslationMeasurement1.prototype.version);
|
||||
|
||||
return this._enqueueTelemetryStorageTask(function* recordTask() {
|
||||
let detectLanguageEnabled = Services.prefs.getBoolPref("browser.translation.detectLanguage");
|
||||
yield m.setDailyLastNumeric("detectLanguageEnabled", detectLanguageEnabled ? 1 : 0);
|
||||
|
||||
let showTranslationUI = Services.prefs.getBoolPref("browser.translation.ui.show");
|
||||
yield m.setDailyLastNumeric("showTranslationUI", showTranslationUI ? 1 : 0);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_enqueueTelemetryStorageTask: function (task) {
|
||||
if (!Services.prefs.getBoolPref("toolkit.telemetry.enabled")) {
|
||||
// This measurement should only be included when telemetry is
|
||||
|
|
|
@ -170,6 +170,44 @@ add_task(function* test_record_translation() {
|
|||
yield storage.close();
|
||||
});
|
||||
|
||||
add_task(function* test_collect_daily() {
|
||||
let storage = yield Metrics.Storage("translation");
|
||||
let provider = new TranslationProvider();
|
||||
yield provider.init(storage);
|
||||
let now = new Date();
|
||||
|
||||
// Set the prefs we test here to `false` initially.
|
||||
const kPrefDetectLanguage = "browser.translation.detectLanguage";
|
||||
const kPrefShowUI = "browser.translation.ui.show";
|
||||
Services.prefs.setBoolPref(kPrefDetectLanguage, false);
|
||||
Services.prefs.setBoolPref(kPrefShowUI, false);
|
||||
|
||||
// Initially nothing should be configured.
|
||||
yield provider.collectDailyData();
|
||||
|
||||
let m = provider.getMeasurement("translation", 1);
|
||||
let values = yield m.getValues();
|
||||
Assert.equal(values.days.size, 1);
|
||||
Assert.ok(values.days.hasDay(now));
|
||||
let day = values.days.getDay(now);
|
||||
Assert.ok(day.has("detectLanguageEnabled"));
|
||||
Assert.ok(day.has("showTranslationUI"));
|
||||
|
||||
// Changes to the repective prefs should be picked up.
|
||||
Services.prefs.setBoolPref(kPrefDetectLanguage, true);
|
||||
Services.prefs.setBoolPref(kPrefShowUI, true);
|
||||
|
||||
yield provider.collectDailyData();
|
||||
|
||||
values = yield m.getValues();
|
||||
day = values.days.getDay(now);
|
||||
Assert.equal(day.get("detectLanguageEnabled"), 1);
|
||||
Assert.equal(day.get("showTranslationUI"), 1);
|
||||
|
||||
yield provider.shutdown();
|
||||
yield storage.close();
|
||||
});
|
||||
|
||||
// Test the payload after recording with telemetry enabled.
|
||||
add_task(function* test_healthreporter_json() {
|
||||
Services.prefs.setBoolPref("toolkit.telemetry.enabled", true);
|
||||
|
@ -227,7 +265,7 @@ add_task(function* test_healthreporter_json() {
|
|||
});
|
||||
|
||||
// Test the payload after recording with telemetry disabled.
|
||||
add_task(function* test_healthreporter_json() {
|
||||
add_task(function* test_healthreporter_json2() {
|
||||
Services.prefs.setBoolPref("toolkit.telemetry.enabled", false);
|
||||
|
||||
let reporter = yield getHealthReporter("healthreporter_json");
|
||||
|
|
|
@ -85,6 +85,9 @@ function MarkupView(aInspector, aFrame, aControllerWindow) {
|
|||
this._boundMutationObserver = this._mutationObserver.bind(this);
|
||||
this.walker.on("mutations", this._boundMutationObserver);
|
||||
|
||||
this._boundOnDisplayChange = this._onDisplayChange.bind(this);
|
||||
this.walker.on("display-change", this._boundOnDisplayChange);
|
||||
|
||||
this._boundOnNewSelection = this._onNewSelection.bind(this);
|
||||
this._inspector.selection.on("new-node-front", this._boundOnNewSelection);
|
||||
this._onNewSelection();
|
||||
|
@ -614,6 +617,19 @@ MarkupView.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* React to display-change events from the walker
|
||||
* @param {Array} nodes An array of nodeFronts
|
||||
*/
|
||||
_onDisplayChange: function(nodes) {
|
||||
for (let node of nodes) {
|
||||
let container = this._containers.get(node);
|
||||
if (container) {
|
||||
container.isDisplayed = node.isDisplayed;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a list of mutations returned by the mutation observer, flash the
|
||||
* corresponding containers to attract attention.
|
||||
|
@ -1110,6 +1126,9 @@ MarkupView.prototype = {
|
|||
this.walker.off("mutations", this._boundMutationObserver)
|
||||
this._boundMutationObserver = null;
|
||||
|
||||
this.walker.off("display-change", this._boundOnDisplayChange);
|
||||
this._boundOnDisplayChange = null;
|
||||
|
||||
this._elt.removeEventListener("mousemove", this._onMouseMove, false);
|
||||
this._elt.removeEventListener("mouseleave", this._onMouseLeave, false);
|
||||
this._elt = null;
|
||||
|
@ -1268,6 +1287,9 @@ function MarkupContainer(aMarkupView, aNode, aInspector) {
|
|||
|
||||
// Prepare the image preview tooltip data if any
|
||||
this._prepareImagePreview();
|
||||
|
||||
// Marking the node as shown or hidden
|
||||
this.isDisplayed = this.node.isDisplayed;
|
||||
}
|
||||
|
||||
MarkupContainer.prototype = {
|
||||
|
@ -1342,6 +1364,16 @@ MarkupContainer.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the element has displayed or not
|
||||
*/
|
||||
set isDisplayed(isDisplayed) {
|
||||
this.elt.classList.remove("not-displayed");
|
||||
if (!isDisplayed) {
|
||||
this.elt.classList.add("not-displayed");
|
||||
}
|
||||
},
|
||||
|
||||
copyImageDataUri: function() {
|
||||
// We need to send again a request to gettooltipData even if one was sent for
|
||||
// the tooltip, because we want the full-size image
|
||||
|
|
|
@ -6,6 +6,7 @@ support-files =
|
|||
doc_markup_flashing.html
|
||||
doc_markup_mutation.html
|
||||
doc_markup_navigation.html
|
||||
doc_markup_not_displayed.html
|
||||
doc_markup_pagesize_01.html
|
||||
doc_markup_pagesize_02.html
|
||||
doc_markup_search.html
|
||||
|
@ -26,6 +27,8 @@ support-files =
|
|||
[browser_markupview_mutation_01.js]
|
||||
[browser_markupview_mutation_02.js]
|
||||
[browser_markupview_navigation.js]
|
||||
[browser_markupview_node_not_displayed_01.js]
|
||||
[browser_markupview_node_not_displayed_02.js]
|
||||
[browser_markupview_pagesize_01.js]
|
||||
[browser_markupview_pagesize_02.js]
|
||||
[browser_markupview_search_01.js]
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that nodes that are not displayed appear differently in the markup-view
|
||||
// when these nodes are imported in the view.
|
||||
|
||||
// Note that nodes inside a display:none parent are obviously not displayed too
|
||||
// but the markup-view uses css inheritance to mark those as hidden instead of
|
||||
// having to visit each and every child of a hidden node. So there's no sense
|
||||
// testing children nodes.
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_markup_not_displayed.html";
|
||||
const TEST_DATA = [
|
||||
{selector: "#normal-div", isDisplayed: true},
|
||||
{selector: "head", isDisplayed: false},
|
||||
{selector: "#display-none", isDisplayed: false},
|
||||
{selector: "#hidden-true", isDisplayed: false},
|
||||
{selector: "#visibility-hidden", isDisplayed: true}
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let {inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
for (let {selector, isDisplayed} of TEST_DATA) {
|
||||
info("Getting node " + selector);
|
||||
let container = getContainerForRawNode(selector, inspector);
|
||||
is(!container.elt.classList.contains("not-displayed"), isDisplayed,
|
||||
"The container for " + selector + " is marked as displayed " + isDisplayed);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,132 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that nodes are marked as displayed and not-displayed dynamically, when
|
||||
// their display changes
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_markup_not_displayed.html";
|
||||
const TEST_DATA = [
|
||||
{
|
||||
desc: "Hiding a node by creating a new stylesheet",
|
||||
selector: "#normal-div",
|
||||
before: true,
|
||||
changeStyle: (doc, node) => {
|
||||
let div = doc.createElement("div");
|
||||
div.id = "new-style";
|
||||
div.innerHTML = "<style>#normal-div {display:none;}</style>";
|
||||
doc.body.appendChild(div);
|
||||
},
|
||||
after: false
|
||||
},
|
||||
{
|
||||
desc: "Showing a node by deleting an existing stylesheet",
|
||||
selector: "#normal-div",
|
||||
before: false,
|
||||
changeStyle: (doc, node) => {
|
||||
doc.getElementById("new-style").remove();
|
||||
},
|
||||
after: true
|
||||
},
|
||||
{
|
||||
desc: "Hiding a node by changing its style property",
|
||||
selector: "#display-none",
|
||||
before: false,
|
||||
changeStyle: (doc, node) => {
|
||||
node.style.display = "block";
|
||||
},
|
||||
after: true
|
||||
},
|
||||
{
|
||||
desc: "Showing a node by removing its hidden attribute",
|
||||
selector: "#hidden-true",
|
||||
before: false,
|
||||
changeStyle: (doc, node) => {
|
||||
node.removeAttribute("hidden");
|
||||
},
|
||||
after: true
|
||||
},
|
||||
{
|
||||
desc: "Hiding a node by adding a hidden attribute",
|
||||
selector: "#hidden-true",
|
||||
before: true,
|
||||
changeStyle: (doc, node) => {
|
||||
node.setAttribute("hidden", "true");
|
||||
},
|
||||
after: false
|
||||
},
|
||||
{
|
||||
desc: "Showing a node by changin a stylesheet's rule",
|
||||
selector: "#hidden-via-stylesheet",
|
||||
before: false,
|
||||
changeStyle: (doc, node) => {
|
||||
doc.styleSheets[0].cssRules[0].style.setProperty("display", "inline");
|
||||
},
|
||||
after: true
|
||||
},
|
||||
{
|
||||
desc: "Hiding a node by adding a new rule to a stylesheet",
|
||||
selector: "#hidden-via-stylesheet",
|
||||
before: true,
|
||||
changeStyle: (doc, node) => {
|
||||
doc.styleSheets[0].insertRule(
|
||||
"#hidden-via-stylesheet {display: none;}", 1);
|
||||
},
|
||||
after: false
|
||||
},
|
||||
{
|
||||
desc: "Hiding a node by adding a class that matches an existing rule",
|
||||
selector: "#normal-div",
|
||||
before: true,
|
||||
changeStyle: (doc, node) => {
|
||||
doc.styleSheets[0].insertRule(
|
||||
".a-new-class {display: none;}", 2);
|
||||
node.classList.add("a-new-class");
|
||||
},
|
||||
after: false
|
||||
}
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let {inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
for (let data of TEST_DATA) {
|
||||
info("Running test case: " + data.desc);
|
||||
yield runTestData(inspector, data);
|
||||
}
|
||||
});
|
||||
|
||||
function runTestData(inspector, {selector, before, changeStyle, after}) {
|
||||
let def = promise.defer();
|
||||
|
||||
info("Getting the " + selector + " test node");
|
||||
let container = getContainerForRawNode(selector, inspector);
|
||||
is(!container.elt.classList.contains("not-displayed"), before,
|
||||
"The container is marked as " + (before ? "shown" : "hidden"));
|
||||
|
||||
info("Listening for the display-change event");
|
||||
inspector.markup.walker.once("display-change", nodes => {
|
||||
info("Verifying that the list of changed nodes include our container");
|
||||
|
||||
ok(nodes.length, "The display-change event was received with a nodes");
|
||||
let foundContainer = false;
|
||||
for (let node of nodes) {
|
||||
if (inspector.markup.getContainer(node) === container) {
|
||||
foundContainer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(foundContainer, "Container is part of the list of changed nodes");
|
||||
|
||||
is(!container.elt.classList.contains("not-displayed"), after,
|
||||
"The container is marked as " + (after ? "shown" : "hidden"));
|
||||
def.resolve();
|
||||
});
|
||||
|
||||
info("Making style changes");
|
||||
changeStyle(content.document, getNode(selector));
|
||||
|
||||
return def.promise;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
#hidden-via-stylesheet {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="normal-div"></div>
|
||||
<div id="display-none" style="display:none;"></div>
|
||||
<div id="hidden-true" hidden="true"></div>
|
||||
<div id="visibility-hidden" style="visibility:hidden;"></div>
|
||||
<div id="hidden-via-stylesheet"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1469,24 +1469,26 @@ CssRuleView.prototype = {
|
|||
/**
|
||||
* Update the rules for the currently highlighted element.
|
||||
*/
|
||||
nodeChanged: function() {
|
||||
refreshPanel: function() {
|
||||
// Ignore refreshes during editing or when no element is selected.
|
||||
if (this.isEditing || !this._elementStyle) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._clearRules();
|
||||
|
||||
// Repopulate the element style.
|
||||
this._populate();
|
||||
this._populate(true);
|
||||
},
|
||||
|
||||
_populate: function() {
|
||||
_populate: function(clearRules = false) {
|
||||
let elementStyle = this._elementStyle;
|
||||
return this._elementStyle.populate().then(() => {
|
||||
if (this._elementStyle != elementStyle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clearRules) {
|
||||
this._clearRules();
|
||||
}
|
||||
this._createEditors();
|
||||
|
||||
// Notify anyone that cares that we refreshed.
|
||||
|
|
|
@ -109,7 +109,7 @@ RuleViewTool.prototype = {
|
|||
},
|
||||
|
||||
refresh: function RVT_refresh() {
|
||||
this.view.nodeChanged();
|
||||
this.view.refreshPanel();
|
||||
},
|
||||
|
||||
destroy: function RVT_destroy() {
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
color: #f5f7fa; /* Light foreground text */
|
||||
}
|
||||
|
||||
/* In case a node isn't displayed in the page, we fade the syntax highlighting */
|
||||
.not-displayed .open,
|
||||
.not-displayed .close {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.tag-line {
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public class TopSitesThumbnailView extends ImageView {
|
|||
private static final int COLOR_FILTER = 0x46FFFFFF;
|
||||
|
||||
// Default filter color for "Add a bookmark" views.
|
||||
private static final int DEFAULT_COLOR = 0x46ECF0F3;
|
||||
private static final int DEFAULT_COLOR = 0xFFECF0F3;
|
||||
|
||||
// Stroke width for the border.
|
||||
private final float mStrokeWidth = getResources().getDisplayMetrics().density * 2;
|
||||
|
|
После Ширина: | Высота: | Размер: 480 B |
До Ширина: | Высота: | Размер: 550 B После Ширина: | Высота: | Размер: 550 B |
После Ширина: | Высота: | Размер: 1.2 KiB |
До Ширина: | Высота: | Размер: 13 KiB После Ширина: | Высота: | Размер: 1.3 KiB |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/suggestedsites_fxsupport.png
Normal file
После Ширина: | Высота: | Размер: 1.9 KiB |
До Ширина: | Высота: | Размер: 2.3 KiB После Ширина: | Высота: | Размер: 2.0 KiB |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/top_site_add.png
До Ширина: | Высота: | Размер: 143 B После Ширина: | Высота: | Размер: 151 B |
После Ширина: | Высота: | Размер: 437 B |
До Ширина: | Высота: | Размер: 473 B После Ширина: | Высота: | Размер: 473 B |
После Ширина: | Высота: | Размер: 781 B |
До Ширина: | Высота: | Размер: 5.5 KiB После Ширина: | Высота: | Размер: 945 B |
Двоичные данные
mobile/android/base/resources/drawable-mdpi/suggestedsites_fxsupport.png
Normal file
После Ширина: | Высота: | Размер: 1.3 KiB |
До Ширина: | Высота: | Размер: 1.5 KiB После Ширина: | Высота: | Размер: 1.3 KiB |
Двоичные данные
mobile/android/base/resources/drawable-mdpi/top_site_add.png
До Ширина: | Высота: | Размер: 143 B После Ширина: | Высота: | Размер: 136 B |
После Ширина: | Высота: | Размер: 574 B |
До Ширина: | Высота: | Размер: 679 B После Ширина: | Высота: | Размер: 679 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/suggestedsites_fxaddons.png
Normal file
После Ширина: | Высота: | Размер: 1.7 KiB |
До Ширина: | Высота: | Размер: 21 KiB После Ширина: | Высота: | Размер: 1.8 KiB |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/suggestedsites_fxsupport.png
Normal file
После Ширина: | Высота: | Размер: 2.6 KiB |
До Ширина: | Высота: | Размер: 2.7 KiB После Ширина: | Высота: | Размер: 2.7 KiB |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/top_site_add.png
До Ширина: | Высота: | Размер: 148 B После Ширина: | Высота: | Размер: 156 B |
Двоичные данные
mobile/android/base/resources/drawable-xxhdpi/suggestedsites_fxaddons.png
Normal file
После Ширина: | Высота: | Размер: 2.6 KiB |
Двоичные данные
mobile/android/base/resources/drawable-xxhdpi/suggestedsites_fxmarketplace.png
Normal file
После Ширина: | Высота: | Размер: 2.8 KiB |
Двоичные данные
mobile/android/base/resources/drawable-xxhdpi/suggestedsites_fxsupport.png
Normal file
После Ширина: | Высота: | Размер: 3.9 KiB |
Двоичные данные
mobile/android/base/resources/drawable-xxhdpi/suggestedsites_mozilla.png
Normal file
После Ширина: | Высота: | Размер: 4.2 KiB |
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item gecko:state_dark="true"
|
||||
android:drawable="@drawable/close_edit_mode_dark"/>
|
||||
|
||||
<item android:drawable="@drawable/close_edit_mode_light"/>
|
||||
|
||||
</selector>
|
|
@ -109,13 +109,14 @@
|
|||
|
||||
<!-- We draw after the menu items so when they are hidden, the cancel button,
|
||||
which is thus drawn on top, may be pressed. -->
|
||||
<ImageView android:id="@+id/edit_cancel"
|
||||
style="@style/UrlBar.ImageButton.Icon"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/close_edit_mode"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:contentDescription="@string/edit_mode_cancel"
|
||||
android:visibility="gone"/>
|
||||
<org.mozilla.gecko.widget.ThemedImageView
|
||||
android:id="@+id/edit_cancel"
|
||||
style="@style/UrlBar.ImageButton.Icon"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/close_edit_mode_selector"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:contentDescription="@string/edit_mode_cancel"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</merge>
|
||||
|
|
|
@ -97,14 +97,15 @@
|
|||
|
||||
<!-- Note that the edit components are invisible so that the views
|
||||
depending on their location can properly layout. -->
|
||||
<ImageView android:id="@+id/edit_cancel"
|
||||
style="@style/UrlBar.ImageButton.Icon"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/close_edit_mode"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:contentDescription="@string/edit_mode_cancel"
|
||||
android:visibility="invisible"/>
|
||||
<org.mozilla.gecko.widget.ThemedImageView
|
||||
android:id="@+id/edit_cancel"
|
||||
style="@style/UrlBar.ImageButton.Icon"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/close_edit_mode_selector"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:contentDescription="@string/edit_mode_cancel"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<!-- The space to the left of the cancel button would be larger than the right because
|
||||
the url bar drawable contains some whitespace, so we compensate by removing
|
||||
|
|
|
@ -141,7 +141,7 @@ public class BrowserToolbar extends ThemedRelativeLayout
|
|||
private MenuPopup menuPopup;
|
||||
private List<View> focusOrder;
|
||||
|
||||
private final ImageView editCancel;
|
||||
private final ThemedImageView editCancel;
|
||||
|
||||
private final View[] tabletDisplayModeViews;
|
||||
private boolean hidForwardButtonOnStartEditing = false;
|
||||
|
@ -234,7 +234,7 @@ public class BrowserToolbar extends ThemedRelativeLayout
|
|||
actionItemBar = (LinearLayout) findViewById(R.id.menu_items);
|
||||
hasSoftMenuButton = !HardwareUtils.hasMenuButton();
|
||||
|
||||
editCancel = (ImageView) findViewById(R.id.edit_cancel);
|
||||
editCancel = (ThemedImageView) findViewById(R.id.edit_cancel);
|
||||
|
||||
// We use different layouts on phones and tablets, so adjust the focus
|
||||
// order appropriately.
|
||||
|
@ -1455,10 +1455,13 @@ public class BrowserToolbar extends ThemedRelativeLayout
|
|||
stateList.addState(EMPTY_STATE_SET, drawable);
|
||||
|
||||
setBackgroundDrawable(stateList);
|
||||
|
||||
editCancel.onLightweightThemeChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightweightThemeReset() {
|
||||
setBackgroundResource(R.drawable.url_bar_bg);
|
||||
editCancel.onLightweightThemeReset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ public class EventListener implements NativeEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
public static void installApk(final Activity context, NativeJSObject message, EventCallback callback) {
|
||||
public static void installApk(final Activity context, NativeJSObject message, final EventCallback callback) {
|
||||
final JSONObject messageData;
|
||||
|
||||
// We get the manifest url out of javascript here so we can use it as a checksum
|
||||
|
@ -237,6 +237,7 @@ public class EventListener implements NativeEventListener {
|
|||
// unregistered the receiver).
|
||||
Log.e(LOGTAG, "error unregistering install receiver: ", e);
|
||||
}
|
||||
callback.sendError("APK installation cancelled by user");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1048,7 +1048,6 @@ public class ActivityChooserModel extends DataSetObservable {
|
|||
* Command for reading the historical records from a file off the UI thread.
|
||||
*/
|
||||
private void readHistoricalDataImpl() {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
GeckoProfile profile = GeckoProfile.get(mContext);
|
||||
File f = profile.getFile(mHistoryFileName);
|
||||
|
@ -1057,26 +1056,39 @@ public class ActivityChooserModel extends DataSetObservable {
|
|||
File oldFile = new File(mHistoryFileName);
|
||||
oldFile.renameTo(f);
|
||||
}
|
||||
fis = new FileInputStream(f);
|
||||
readHistoricalDataFromStream(new FileInputStream(f));
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
try {
|
||||
Distribution dist = new Distribution(mContext);
|
||||
File distFile = dist.getDistributionFile("quickshare/" + mHistoryFileName);
|
||||
if (distFile == null) {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
fis = new FileInputStream(distFile);
|
||||
} catch(Exception ex) {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
final Distribution dist = Distribution.getInstance(mContext);
|
||||
dist.addOnDistributionReadyCallback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(LOGTAG, "Running post-distribution task: quickshare.");
|
||||
|
||||
if (!dist.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
File distFile = dist.getDistributionFile("quickshare/" + mHistoryFileName);
|
||||
if (distFile == null) {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
readHistoricalDataFromStream(new FileInputStream(distFile));
|
||||
} catch (Exception ex) {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void readHistoricalDataFromStream(FileInputStream fis) {
|
||||
try {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(fis, null);
|
||||
|
@ -1124,9 +1136,9 @@ public class ActivityChooserModel extends DataSetObservable {
|
|||
Log.i(LOG_TAG, "Read " + historicalRecords.size() + " historical records.");
|
||||
}
|
||||
} catch (XmlPullParserException xppe) {
|
||||
Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, xppe);
|
||||
Log.e(LOG_TAG, "Error reading historical record file: " + mHistoryFileName, xppe);
|
||||
} catch (IOException ioe) {
|
||||
Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, ioe);
|
||||
Log.e(LOG_TAG, "Error reading historical record file: " + mHistoryFileName, ioe);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
|
@ -1189,11 +1201,11 @@ public class ActivityChooserModel extends DataSetObservable {
|
|||
Log.i(LOG_TAG, "Wrote " + recordCount + " historical records.");
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, iae);
|
||||
Log.e(LOG_TAG, "Error writing historical record file: " + mHistoryFileName, iae);
|
||||
} catch (IllegalStateException ise) {
|
||||
Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ise);
|
||||
Log.e(LOG_TAG, "Error writing historical record file: " + mHistoryFileName, ise);
|
||||
} catch (IOException ioe) {
|
||||
Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ioe);
|
||||
Log.e(LOG_TAG, "Error writing historical record file: " + mHistoryFileName, ioe);
|
||||
} finally {
|
||||
mCanReadHistoricalData = true;
|
||||
if (fos != null) {
|
||||
|
|
|
@ -500,6 +500,12 @@ this.WebappManager = {
|
|||
type: "Webapps:InstallApk",
|
||||
filePath: apk.filePath,
|
||||
data: msg,
|
||||
}, (data, error) => {
|
||||
if (!!error) {
|
||||
// There's no page to report back to so drop the error.
|
||||
// TODO: we should notify the user about this failure.
|
||||
debug("APK install failed : " + returnError);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -41,11 +41,21 @@ browser.contentHandlers.types.0.uri=https://add.my.yahoo.com/rss?url=%s
|
|||
# browser.suggestedsites.NAME.bgcolor= Color (hex format)
|
||||
browser.suggestedsites.list.0=mozilla
|
||||
browser.suggestedsites.list.1=fxmarketplace
|
||||
browser.suggestedsites.list.2=fxaddons
|
||||
browser.suggestedsites.list.3=fxsupport
|
||||
|
||||
browser.suggestedsites.mozilla.title=Mozilla
|
||||
browser.suggestedsites.mozilla.title=The Mozilla Project
|
||||
browser.suggestedsites.mozilla.url=https://www.mozilla.org/en-US/
|
||||
browser.suggestedsites.mozilla.bgcolor=#c13832
|
||||
browser.suggestedsites.mozilla.bgcolor=#ce4e41
|
||||
|
||||
browser.suggestedsites.fxmarketplace.title=Firefox Marketplace
|
||||
browser.suggestedsites.fxmarketplace.url=https://marketplace.firefox.com/
|
||||
browser.suggestedsites.fxmarketplace.bgcolor=#0095dd
|
||||
browser.suggestedsites.fxmarketplace.bgcolor=#0096dd
|
||||
|
||||
browser.suggestedsites.fxaddons.title=Add-ons: Customize Firefox
|
||||
browser.suggestedsites.fxaddons.url=https://addons.mozilla.org/en-US/android/
|
||||
browser.suggestedsites.fxaddons.bgcolor=#62be06
|
||||
|
||||
browser.suggestedsites.fxsupport.title=Firefox Help and Support
|
||||
browser.suggestedsites.fxsupport.url=https://support.mozilla.org/en-US/products/mobile
|
||||
browser.suggestedsites.fxsupport.bgcolor=#f37c00
|
||||
|
|
|
@ -1564,6 +1564,13 @@ pageTranslatedCountsByLanguage
|
|||
language. Each language entry will be an object containing a "total" member
|
||||
along with individual counts for each language translated to.
|
||||
|
||||
Other properties:
|
||||
|
||||
detectLanguageEnabled
|
||||
Whether automatic language detection is enabled. This is an integer, 0 or 1.
|
||||
showTranslationUI
|
||||
Whether the translation feature UI will be shown. This is an integer, 0 or 1.
|
||||
|
||||
Example
|
||||
^^^^^^^
|
||||
|
||||
|
@ -1571,6 +1578,8 @@ Example
|
|||
|
||||
"org.mozilla.translation.translation": {
|
||||
"_v": 1,
|
||||
"detectLanguageEnabled": 1,
|
||||
"showTranslationUI": 1,
|
||||
"translationOpportunityCount": 134,
|
||||
"pageTranslatedCount": 6,
|
||||
"charactersTranslatedCount": "1126",
|
||||
|
|
|
@ -165,10 +165,7 @@ this.LoginImport.prototype = {
|
|||
let id = row.getResultByName("id");
|
||||
let hostname = row.getResultByName("hostname");
|
||||
|
||||
this.store.data.disabledHosts.push({
|
||||
id: this.store.data.nextId++,
|
||||
hostname: hostname,
|
||||
});
|
||||
this.store.data.disabledHosts.push(hostname);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error importing disabled host: " + ex);
|
||||
}
|
||||
|
|
|
@ -267,6 +267,31 @@ LoginStore.prototype = {
|
|||
// Indicate that the current version of the code has touched the file.
|
||||
this.data.version = kDataVersion;
|
||||
|
||||
// Due to bug 1019885, invalid data was created by the import process in
|
||||
// Nightly. This automated procedure fixes the error. This is provided as
|
||||
// a convenience to Nightly users and can be safely removed after Nightly
|
||||
// users are updated to the new version.
|
||||
let originalDisabledHosts = this.data.disabledHosts;
|
||||
if (originalDisabledHosts.some(hostItem => typeof hostItem != "string")) {
|
||||
|
||||
this.data.disabledHosts = [];
|
||||
|
||||
for (let hostItem of originalDisabledHosts) {
|
||||
// Fix each item if it is in the broken format.
|
||||
if (typeof hostItem != "string") {
|
||||
hostItem = hostItem.hostname;
|
||||
}
|
||||
|
||||
// Ensure we don't create duplicates in the process.
|
||||
if (this.data.disabledHosts.indexOf(hostItem) == -1) {
|
||||
this.data.disabledHosts.push(hostItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the updated data is saved.
|
||||
this.saveSoon();
|
||||
}
|
||||
|
||||
this.dataReady = true;
|
||||
},
|
||||
|
||||
|
|
|
@ -170,10 +170,8 @@ add_task(function test_import()
|
|||
|
||||
// Verify that disabled hosts have been imported.
|
||||
do_check_eq(store.data.disabledHosts.length, 2);
|
||||
do_check_true(store.data.disabledHosts.some(
|
||||
dataItem => dataItem.hostname == "http://www.example.com"));
|
||||
do_check_true(store.data.disabledHosts.some(
|
||||
dataItem => dataItem.hostname == "https://www.example.org"));
|
||||
do_check_true(store.data.disabledHosts.indexOf("http://www.example.com") != -1);
|
||||
do_check_true(store.data.disabledHosts.indexOf("https://www.example.org") != -1);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,7 +9,7 @@ function test()
|
|||
const expectScrollBoth = 3;
|
||||
|
||||
var allTests = [
|
||||
{dataUri: 'data:text/html,<body><style type="text/css">div { display: inline-block; }</style>\
|
||||
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body><style type="text/css">div { display: inline-block; }</style>\
|
||||
<div id="a" style="width: 100px; height: 100px; overflow: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
|
||||
<div id="b" style="width: 100px; height: 100px; overflow: auto;"><div style="width: 200px; height: 200px;"></div></div>\
|
||||
<div id="c" style="width: 100px; height: 100px; overflow-x: auto; overflow-y: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
|
||||
|
@ -23,7 +23,7 @@ function test()
|
|||
<div id="g" style="width: 99px; height: 99px; border: 10px solid black; margin: 10px; overflow: auto;"><div style="width: 100px; height: 100px;"></div></div>\
|
||||
<div id="h" style="width: 100px; height: 100px; overflow: -moz-hidden-unscrollable;"><div style="width: 200px; height: 200px;"></div></div>\
|
||||
<iframe id="iframe" style="display: none;"></iframe>\
|
||||
</body>'},
|
||||
</body></html>'},
|
||||
{elem: 'a', expected: expectScrollNone},
|
||||
{elem: 'b', expected: expectScrollBoth},
|
||||
{elem: 'c', expected: expectScrollHori},
|
||||
|
@ -32,11 +32,11 @@ function test()
|
|||
{elem: 'f', expected: expectScrollNone},
|
||||
{elem: 'g', expected: expectScrollBoth},
|
||||
{elem: 'h', expected: expectScrollNone},
|
||||
{dataUri: 'data:text/html,<html><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
|
||||
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
|
||||
<iframe id="iframe" style="display: none;"></iframe>\
|
||||
</body></html>'},
|
||||
{elem: 'i', expected: expectScrollVert}, // bug 695121
|
||||
{dataUri: 'data:text/html,<html><style>html, body { width: 100%; height: 100%; overflow-x: hidden; overflow-y: scroll; }</style>\
|
||||
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><style>html, body { width: 100%; height: 100%; overflow-x: hidden; overflow-y: scroll; }</style>\
|
||||
<body id="j"><div style="height: 2000px"></div>\
|
||||
<iframe id="iframe" style="display: none;"></iframe>\
|
||||
</body></html>'},
|
||||
|
@ -58,14 +58,35 @@ function test()
|
|||
}
|
||||
|
||||
var elem = doc.getElementById(test.elem);
|
||||
// Skip the first callback as it's the same callback that the browser
|
||||
// uses to kick off the scrolling.
|
||||
var skipFrames = 1;
|
||||
var checkScroll = function () {
|
||||
if (skipFrames--) {
|
||||
|
||||
let firstTimestamp = undefined;
|
||||
function checkScroll(timestamp) {
|
||||
if (firstTimestamp === undefined) {
|
||||
firstTimestamp = timestamp;
|
||||
}
|
||||
|
||||
// This value is calculated similarly to the value of the same name in
|
||||
// ClickEventHandler.autoscrollLoop, except here it's cumulative across
|
||||
// all frames after the first one instead of being based only on the
|
||||
// current frame.
|
||||
let timeCompensation = (timestamp - firstTimestamp) / 20;
|
||||
info("timestamp=" + timestamp + " firstTimestamp=" + firstTimestamp +
|
||||
" timeCompensation=" + timeCompensation);
|
||||
|
||||
// Try to wait until enough time has passed to allow the scroll to happen.
|
||||
// autoscrollLoop incrementally scrolls during each animation frame, but
|
||||
// due to how its calculations work, when a frame is very close to the
|
||||
// previous frame, no scrolling may actually occur during that frame.
|
||||
// After 20ms's worth of frames, timeCompensation will be 1, making it
|
||||
// more likely that the accumulated scroll in autoscrollLoop will be >= 1,
|
||||
// although it also depends on acceleration, which here in this test
|
||||
// should be > 1 due to how it synthesizes mouse events below.
|
||||
if (timeCompensation < 1) {
|
||||
window.mozRequestAnimationFrame(checkScroll);
|
||||
return;
|
||||
}
|
||||
|
||||
// Close the autoscroll popup by synthesizing Esc.
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, gBrowser.contentWindow);
|
||||
var scrollVert = test.expected & expectScrollVert;
|
||||
ok((scrollVert && elem.scrollTop > 0) ||
|
||||
|
@ -83,6 +104,8 @@ function test()
|
|||
EventUtils.synthesizeMouse(elem, 50, 50, { button: 1 },
|
||||
gBrowser.contentWindow);
|
||||
|
||||
// This ensures bug 605127 is fixed: pagehide in an unrelated document
|
||||
// should not cancel the autoscroll.
|
||||
var iframe = gBrowser.contentDocument.getElementById("iframe");
|
||||
var e = iframe.contentDocument.createEvent("pagetransition");
|
||||
e.initPageTransitionEvent("pagehide", true, true, false);
|
||||
|
@ -92,11 +115,8 @@ function test()
|
|||
EventUtils.synthesizeMouse(elem, 100, 100,
|
||||
{ type: "mousemove", clickCount: "0" },
|
||||
gBrowser.contentWindow);
|
||||
/*
|
||||
* if scrolling didn’t work, we wouldn’t do any redraws and thus time out.
|
||||
* so request and force redraws to get the chance to check for scrolling at
|
||||
* all.
|
||||
*/
|
||||
|
||||
// Start checking for the scroll.
|
||||
window.mozRequestAnimationFrame(checkScroll);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.md or:
|
||||
|
@ -324,7 +325,7 @@
|
|||
|
||||
var ltk = lastToken.type.keyword;
|
||||
if (ltk != null) {
|
||||
if (ltk == "break" || ltk == "continue") {
|
||||
if (ltk == "break" || ltk == "continue" || ltk == "return") {
|
||||
return token.type.type != ";";
|
||||
}
|
||||
if (ltk != "debugger"
|
||||
|
@ -340,7 +341,8 @@
|
|||
if (ltt == ")" && (token.type.type != ")"
|
||||
&& token.type.type != "]"
|
||||
&& token.type.type != ";"
|
||||
&& token.type.type != ",")) {
|
||||
&& token.type.type != ","
|
||||
&& token.type.type != ".")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -557,6 +559,7 @@
|
|||
|| ttt == "["
|
||||
|| ttt == "?"
|
||||
|| ttk == "do"
|
||||
|| ttk == "switch"
|
||||
|| ttk == "case"
|
||||
|| ttk == "default";
|
||||
}
|
||||
|
@ -589,7 +592,9 @@
|
|||
* level.
|
||||
*/
|
||||
function incrementsIndent(token) {
|
||||
return token.type.type == "{" || token.isArrayLiteral;
|
||||
return token.type.type == "{"
|
||||
|| token.isArrayLiteral
|
||||
|| token.type.keyword == "switch";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -724,6 +729,7 @@
|
|||
// - "[\n"
|
||||
// - "do"
|
||||
// - "?"
|
||||
// - "switch"
|
||||
// - "case"
|
||||
// - "default"
|
||||
//
|
||||
|
@ -756,7 +762,8 @@
|
|||
block: block,
|
||||
text: text,
|
||||
line: startLoc.line,
|
||||
column: startLoc.column
|
||||
column: startLoc.column,
|
||||
trailing: lastToken.endLoc.line == startLoc.line
|
||||
});
|
||||
} else {
|
||||
addComment(write, indentLevel, options, block, text, startLoc.line,
|
||||
|
@ -791,15 +798,26 @@
|
|||
|
||||
if (decrementsIndent(ttt, stack)) {
|
||||
indentLevel--;
|
||||
if (ttt == "}"
|
||||
&& stack.length > 1
|
||||
&& stack[stack.length - 2] == "switch") {
|
||||
indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
prependWhiteSpace(token, lastToken, addedNewline, write, options,
|
||||
indentLevel, stack);
|
||||
addToken(token, write, options);
|
||||
addedNewline = appendNewline(token, write, stack);
|
||||
if (commentQueue.length == 0 || !commentQueue[0].trailing) {
|
||||
addedNewline = appendNewline(token, write, stack);
|
||||
}
|
||||
|
||||
if (shouldStackPop(token, stack)) {
|
||||
stack.pop();
|
||||
if (token == "}" && stack.length
|
||||
&& stack[stack.length - 1] == "switch") {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (incrementsIndent(token)) {
|
||||
|
@ -825,13 +843,17 @@
|
|||
|
||||
// Apply all the comments that have been queued up.
|
||||
if (commentQueue.length) {
|
||||
if (!addedNewline) {
|
||||
if (!addedNewline && !commentQueue[0].trailing) {
|
||||
write("\n");
|
||||
}
|
||||
if (commentQueue[0].trailing) {
|
||||
write(" ");
|
||||
}
|
||||
for (var i = 0, n = commentQueue.length; i < n; i++) {
|
||||
var comment = commentQueue[i];
|
||||
addComment(write, indentLevel, options, comment.block, comment.text,
|
||||
comment.line, comment.column);
|
||||
var commentIndentLevel = commentQueue[i].trailing ? 0 : indentLevel;
|
||||
addComment(write, commentIndentLevel, options, comment.block,
|
||||
comment.text, comment.line, comment.column);
|
||||
}
|
||||
addedNewline = true;
|
||||
commentQueue.splice(0, commentQueue.length);
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.md or:
|
||||
|
@ -346,11 +350,11 @@ var testCases = [
|
|||
name: "Switch statements",
|
||||
input: "switch(x){case a:foo();break;default:bar()}",
|
||||
output: "switch (x) {\n" +
|
||||
"case a:\n" +
|
||||
" foo();\n" +
|
||||
" break;\n" +
|
||||
"default:\n" +
|
||||
" bar()\n" +
|
||||
" case a:\n" +
|
||||
" foo();\n" +
|
||||
" break;\n" +
|
||||
" default:\n" +
|
||||
" bar()\n" +
|
||||
"}\n"
|
||||
},
|
||||
|
||||
|
@ -481,6 +485,44 @@ var testCases = [
|
|||
output: "'\\0'\n"
|
||||
},
|
||||
|
||||
{
|
||||
name: "Bug 977082 - space between grouping operator and dot notation",
|
||||
input: "JSON.stringify(3).length;\n" +
|
||||
"([1,2,3]).length;\n" +
|
||||
"(new Date()).toLocaleString();\n",
|
||||
output: "JSON.stringify(3).length;\n" +
|
||||
"([1,\n" +
|
||||
"2,\n" +
|
||||
"3]).length;\n" +
|
||||
"(new Date()).toLocaleString();\n"
|
||||
},
|
||||
|
||||
{
|
||||
name: "Bug 975477 don't move end of line comments to next line",
|
||||
input: "switch (request.action) {\n" +
|
||||
" case 'show': //$NON-NLS-0$\n" +
|
||||
" if (localStorage.hideicon !== 'true') { //$NON-NLS-0$\n" +
|
||||
" chrome.pageAction.show(sender.tab.id);\n" +
|
||||
" }\n" +
|
||||
" break;\n" +
|
||||
" default:\n" +
|
||||
" console.warn('unknown request'); //$NON-NLS-0$\n" +
|
||||
" // don't respond if you don't understand the message.\n" +
|
||||
" return;\n" +
|
||||
"}\n",
|
||||
output: "switch (request.action) {\n" +
|
||||
" case 'show': //$NON-NLS-0$\n" +
|
||||
" if (localStorage.hideicon !== 'true') { //$NON-NLS-0$\n" +
|
||||
" chrome.pageAction.show(sender.tab.id);\n" +
|
||||
" }\n" +
|
||||
" break;\n" +
|
||||
" default:\n" +
|
||||
" console.warn('unknown request'); //$NON-NLS-0$\n" +
|
||||
" // don't respond if you don't understand the message.\n" +
|
||||
" return;\n" +
|
||||
"}\n"
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
var sourceMap = this.sourceMap || require("source-map");
|
||||
|
|
|
@ -62,6 +62,8 @@ const {Unknown} = require("sdk/platform/xpcom");
|
|||
const {Class} = require("sdk/core/heritage");
|
||||
const {PageStyleActor} = require("devtools/server/actors/styles");
|
||||
const {HighlighterActor} = require("devtools/server/actors/highlighter");
|
||||
const {getLayoutChangesObserver, releaseLayoutChangesObserver} =
|
||||
require("devtools/server/actors/layout");
|
||||
|
||||
const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
|
||||
const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
|
||||
|
@ -177,6 +179,10 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
|
|||
protocol.Actor.prototype.initialize.call(this, null);
|
||||
this.walker = walker;
|
||||
this.rawNode = node;
|
||||
|
||||
// Storing the original display of the node, to track changes when reflows
|
||||
// occur
|
||||
this.wasDisplayed = this.isDisplayed;
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
|
@ -227,6 +233,8 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
|
|||
attrs: this.writeAttrs(),
|
||||
|
||||
pseudoClassLocks: this.writePseudoClassLocks(),
|
||||
|
||||
isDisplayed: this.isDisplayed,
|
||||
};
|
||||
|
||||
if (this.isDocumentElement()) {
|
||||
|
@ -247,6 +255,29 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
|
|||
return form;
|
||||
},
|
||||
|
||||
get computedStyle() {
|
||||
if (Cu.isDeadWrapper(this.rawNode) ||
|
||||
this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE ||
|
||||
!this.rawNode.ownerDocument ||
|
||||
!this.rawNode.ownerDocument.defaultView) {
|
||||
return null;
|
||||
}
|
||||
return this.rawNode.ownerDocument.defaultView.getComputedStyle(this.rawNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Is the node's display computed style value other than "none"
|
||||
*/
|
||||
get isDisplayed() {
|
||||
let style = this.computedStyle;
|
||||
if (!style) {
|
||||
// Consider all non-element nodes as displayed
|
||||
return true;
|
||||
} else {
|
||||
return style.display !== "none";
|
||||
}
|
||||
},
|
||||
|
||||
writeAttrs: function() {
|
||||
if (!this.rawNode.attributes) {
|
||||
return undefined;
|
||||
|
@ -548,6 +579,12 @@ let NodeFront = protocol.FrontClass(NodeActor, {
|
|||
return this.pseudoClassLocks.some(locked => locked === pseudo);
|
||||
},
|
||||
|
||||
get isDisplayed() {
|
||||
// The NodeActor's form contains the isDisplayed information as a boolean
|
||||
// starting from FF32. Before that, the property is missing
|
||||
return "isDisplayed" in this._form ? this._form.isDisplayed : true;
|
||||
},
|
||||
|
||||
getNodeValue: protocol.custom(function() {
|
||||
if (!this.incompleteValue) {
|
||||
return delayedResolve(new ShortLongString(this.shortValue));
|
||||
|
@ -836,6 +873,10 @@ var WalkerActor = protocol.ActorClass({
|
|||
},
|
||||
"highlighter-hide" : {
|
||||
type: "highlighter-hide"
|
||||
},
|
||||
"display-change" : {
|
||||
type: "display-change",
|
||||
nodes: Arg(0, "array:domnode")
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -875,6 +916,10 @@ var WalkerActor = protocol.ActorClass({
|
|||
// Ensure that the root document node actor is ready and
|
||||
// managed.
|
||||
this.rootNode = this.document();
|
||||
|
||||
this.reflowObserver = getLayoutChangesObserver(this.tabActor);
|
||||
this._onReflows = this._onReflows.bind(this);
|
||||
this.reflowObserver.on("reflows", this._onReflows);
|
||||
},
|
||||
|
||||
// Returns the JSON representation of this object over the wire.
|
||||
|
@ -894,6 +939,11 @@ var WalkerActor = protocol.ActorClass({
|
|||
this.clearPseudoClassLocks();
|
||||
this._activePseudoClassLocks = null;
|
||||
this.rootDoc = null;
|
||||
|
||||
this.reflowObserver.off("reflows", this._onReflows);
|
||||
this.reflowObserver = null;
|
||||
releaseLayoutChangesObserver(this.tabActor);
|
||||
|
||||
events.emit(this, "destroyed");
|
||||
protocol.Actor.prototype.destroy.call(this);
|
||||
},
|
||||
|
@ -904,7 +954,7 @@ var WalkerActor = protocol.ActorClass({
|
|||
if (actor instanceof NodeActor) {
|
||||
if (this._activePseudoClassLocks &&
|
||||
this._activePseudoClassLocks.has(actor)) {
|
||||
this.clearPsuedoClassLocks(actor);
|
||||
this.clearPseudoClassLocks(actor);
|
||||
}
|
||||
this._refMap.delete(actor.rawNode);
|
||||
}
|
||||
|
@ -928,6 +978,24 @@ var WalkerActor = protocol.ActorClass({
|
|||
return actor;
|
||||
},
|
||||
|
||||
_onReflows: function(reflows) {
|
||||
// Going through the nodes the walker knows about, see which ones have
|
||||
// had their display changed and send a display-change event if any
|
||||
let changes = [];
|
||||
for (let [node, actor] of this._refMap) {
|
||||
let isDisplayed = actor.isDisplayed;
|
||||
if (isDisplayed !== actor.wasDisplayed) {
|
||||
changes.push(actor);
|
||||
// Updating the original value
|
||||
actor.wasDisplayed = isDisplayed;
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.length) {
|
||||
events.emit(this, "display-change", changes);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This is kept for backward-compatibility reasons with older remote targets.
|
||||
* Targets prior to bug 916443.
|
||||
|
|