This commit is contained in:
Wes Kocher 2014-06-05 19:06:34 -07:00
Родитель 1972488853 ff597dd05f
Коммит 216b247057
53 изменённых файлов: 604 добавлений и 92 удалений

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

@ -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

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.3 KiB

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 143 B

После

Ширина:  |  Высота:  |  Размер: 151 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 437 B

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

До

Ширина:  |  Высота:  |  Размер: 473 B

После

Ширина:  |  Высота:  |  Размер: 473 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 781 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.5 KiB

После

Ширина:  |  Высота:  |  Размер: 945 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.5 KiB

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 143 B

После

Ширина:  |  Высота:  |  Размер: 136 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 574 B

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

До

Ширина:  |  Высота:  |  Размер: 679 B

После

Ширина:  |  Высота:  |  Размер: 679 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 21 KiB

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.7 KiB

После

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 148 B

После

Ширина:  |  Высота:  |  Размер: 156 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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 didnt work, we wouldnt 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.