|
@ -24,7 +24,7 @@
|
|||
<menupopup id="menu_ToolsPopup">
|
||||
<menuitem id="menu_preferences" label="&preferencesCmdMac.label;" key="key_preferencesCmdMac" oncommand="openPreferences();"/>
|
||||
<menuitem id="menu_mac_services" label="&servicesMenuMac.label;"/>
|
||||
<menuitem id="menu_mac_hide_app" label="&hideThisAppCmdMac.label;" key="key_hideThisAppCmdMac"/>
|
||||
<menuitem id="menu_mac_hide_app" label="&hideThisAppCmdMac2.label;" key="key_hideThisAppCmdMac"/>
|
||||
<menuitem id="menu_mac_hide_others" label="&hideOtherAppsCmdMac.label;" key="key_hideOtherAppsCmdMac"/>
|
||||
<menuitem id="menu_mac_show_all" label="&showAllAppsCmdMac.label;"/>
|
||||
</menupopup>
|
||||
|
@ -45,8 +45,8 @@
|
|||
<menuitem id="menu_openHelp"
|
||||
oncommand="openHelpLink('firefox-help')"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
label="&productHelp.label;"
|
||||
accesskey="&productHelp.accesskey;"
|
||||
label="&productHelp2.label;"
|
||||
accesskey="&productHelp2.accesskey;"
|
||||
#ifdef XP_MACOSX
|
||||
key="key_openHelpMac"/>
|
||||
#else
|
||||
|
@ -54,8 +54,8 @@
|
|||
#endif
|
||||
<menuitem id="menu_openTour"
|
||||
oncommand="openTourPage();"
|
||||
label="&helpShowTour.label;"
|
||||
accesskey="&helpShowTour.accesskey;"/>
|
||||
label="&helpShowTour2.label;"
|
||||
accesskey="&helpShowTour2.accesskey;"/>
|
||||
<menuitem id="menu_keyboardShortcuts"
|
||||
oncommand="openHelpLink('keyboard-shortcuts')"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
|
@ -63,8 +63,8 @@
|
|||
accesskey="&helpKeyboardShortcuts.accesskey;"/>
|
||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||
<menuitem id="healthReport"
|
||||
label="&healthReport.label;"
|
||||
accesskey="&healthReport.accesskey;"
|
||||
label="&healthReport2.label;"
|
||||
accesskey="&healthReport2.accesskey;"
|
||||
oncommand="openHealthReport()"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
#endif
|
||||
|
@ -84,8 +84,8 @@
|
|||
oncommand="safeModeRestart();"/>
|
||||
<menuseparator id="aboutSeparator"/>
|
||||
<menuitem id="aboutName"
|
||||
accesskey="&aboutProduct.accesskey;"
|
||||
label="&aboutProduct.label;"
|
||||
accesskey="&aboutProduct2.accesskey;"
|
||||
label="&aboutProduct2.label;"
|
||||
oncommand="openAboutDialog();"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
@ -101,7 +101,7 @@
|
|||
key="&preferencesCmdMac.commandkey;"
|
||||
modifiers="accel"/>
|
||||
<key id="key_hideThisAppCmdMac"
|
||||
key="&hideThisAppCmdMac.commandkey;"
|
||||
key="&hideThisAppCmdMac2.commandkey;"
|
||||
modifiers="accel"/>
|
||||
<key id="key_hideOtherAppsCmdMac"
|
||||
key="&hideOtherAppsCmdMac.commandkey;"
|
||||
|
|
|
@ -107,11 +107,11 @@
|
|||
oncommand="BrowserOffline.toggleOfflineStatus();"/>
|
||||
<menuitem id="menu_FileQuitItem"
|
||||
#ifdef XP_WIN
|
||||
label="&quitApplicationCmdWin.label;"
|
||||
accesskey="&quitApplicationCmdWin.accesskey;"
|
||||
label="&quitApplicationCmdWin2.label;"
|
||||
accesskey="&quitApplicationCmdWin2.accesskey;"
|
||||
#else
|
||||
#ifdef XP_MACOSX
|
||||
label="&quitApplicationCmdMac.label;"
|
||||
label="&quitApplicationCmdMac2.label;"
|
||||
#else
|
||||
label="&quitApplicationCmd.label;"
|
||||
accesskey="&quitApplicationCmd.accesskey;"
|
||||
|
|
|
@ -7128,7 +7128,7 @@ var gIdentityHandler = {
|
|||
break; }
|
||||
case this.IDENTITY_MODE_CHROMEUI:
|
||||
let brandBundle = document.getElementById("bundle_brand");
|
||||
icon_label = brandBundle.getString("brandShortName");
|
||||
icon_label = brandBundle.getString("brandShorterName");
|
||||
break;
|
||||
default:
|
||||
tooltip = gNavigatorBundle.getString("identity.unknown.tooltip");
|
||||
|
|
|
@ -816,10 +816,11 @@
|
|||
hidden="true"
|
||||
tooltiptext="&pageReportIcon.tooltip;"
|
||||
onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
|
||||
<image id="reader-mode-button"
|
||||
class="urlbar-icon"
|
||||
hidden="true"
|
||||
onclick="ReaderParent.toggleReaderMode(event);"/>
|
||||
<toolbarbutton id="reader-mode-button"
|
||||
class="tabbable"
|
||||
hidden="true"
|
||||
onclick="ReaderParent.handleReaderButtonEvent(event);"
|
||||
onkeypress="ReaderParent.handleReaderButtonEvent(event);"/>
|
||||
</hbox>
|
||||
<toolbarbutton id="urlbar-go-button"
|
||||
class="chromeclass-toolbar-additional"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- 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/. -->
|
||||
|
||||
<!ENTITY brandShorterName "Firefox">
|
||||
<!ENTITY brandShortName "Firefox Developer Edition">
|
||||
<!ENTITY brandFullName "Firefox Developer Edition">
|
||||
<!ENTITY vendorShortName "Mozilla">
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
brandShorterName=Firefox
|
||||
brandShortName=Firefox Developer Edition
|
||||
brandFullName=Firefox Developer Edition
|
||||
vendorShortName=Mozilla
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- 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/. -->
|
||||
|
||||
<!ENTITY brandShorterName "Nightly">
|
||||
<!ENTITY brandShortName "Nightly">
|
||||
<!ENTITY brandFullName "Nightly">
|
||||
<!ENTITY vendorShortName "Mozilla">
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
brandShorterName=Nightly
|
||||
brandShortName=Nightly
|
||||
brandFullName=Nightly
|
||||
vendorShortName=Mozilla
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- 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/. -->
|
||||
|
||||
<!ENTITY brandShorterName "Firefox">
|
||||
<!ENTITY brandShortName "Firefox">
|
||||
<!ENTITY brandFullName "Mozilla Firefox">
|
||||
<!ENTITY vendorShortName "Mozilla">
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
brandShorterName=Firefox
|
||||
brandShortName=Firefox
|
||||
brandFullName=Mozilla Firefox
|
||||
vendorShortName=Mozilla
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- 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/. -->
|
||||
|
||||
<!ENTITY brandShorterName "Mozilla Developer Preview">
|
||||
<!ENTITY brandShortName "Mozilla Developer Preview">
|
||||
<!ENTITY brandFullName "Mozilla Developer Preview">
|
||||
<!ENTITY vendorShortName "mozilla.org">
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
brandShorterName=Mozilla Developer Preview
|
||||
brandShortName=Mozilla Developer Preview
|
||||
brandFullName=Mozilla Developer Preview
|
||||
vendorShortName=mozilla.org
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
<toolbarseparator/>
|
||||
<toolbarbutton id="PanelUI-quit"
|
||||
#ifdef XP_WIN
|
||||
label="&quitApplicationCmdWin.label;"
|
||||
tooltiptext="&quitApplicationCmdWin.tooltip;"
|
||||
label="&quitApplicationCmdWin2.label;"
|
||||
tooltiptext="&quitApplicationCmdWin2.tooltip;"
|
||||
#else
|
||||
#ifdef XP_MACOSX
|
||||
label="&quitApplicationCmdMac.label;"
|
||||
label="&quitApplicationCmdMac2.label;"
|
||||
#else
|
||||
label="&quitApplicationCmd.label;"
|
||||
#endif
|
||||
|
|
|
@ -114,30 +114,27 @@ skip-if = os == "linux" # Intemittent failures - bug 979207
|
|||
[browser_973641_button_addon.js]
|
||||
[browser_973932_addonbar_currentset.js]
|
||||
[browser_975719_customtoolbars_behaviour.js]
|
||||
|
||||
[browser_976792_insertNodeInWindow.js]
|
||||
skip-if = os == "linux"
|
||||
|
||||
[browser_978084_dragEnd_after_move.js]
|
||||
[browser_980155_add_overflow_toolbar.js]
|
||||
[browser_981305_separator_insertion.js]
|
||||
[browser_981418-widget-onbeforecreated-handler.js]
|
||||
[browser_982656_restore_defaults_builtin_widgets.js]
|
||||
|
||||
[browser_984455_bookmarks_items_reparenting.js]
|
||||
skip-if = os == "linux"
|
||||
|
||||
[browser_985815_propagate_setToolbarVisibility.js]
|
||||
skip-if = e10s # bug 1090635
|
||||
[browser_981305_separator_insertion.js]
|
||||
[browser_988072_sidebar_events.js]
|
||||
[browser_989338_saved_placements_not_resaved.js]
|
||||
[browser_989751_subviewbutton_class.js]
|
||||
[browser_987177_destroyWidget_xul.js]
|
||||
[browser_987177_xul_wrapper_updating.js]
|
||||
[browser_987185_syncButton.js]
|
||||
[browser_987492_window_api.js]
|
||||
[browser_987640_charEncoding.js]
|
||||
skip-if = e10s # Bug 1088710
|
||||
[browser_988072_sidebar_events.js]
|
||||
[browser_989338_saved_placements_not_resaved.js]
|
||||
[browser_989751_subviewbutton_class.js]
|
||||
skip-if = os == "linux" && e10s # Bug 1102900, bug 1104745, bug 1104761
|
||||
[browser_992747_toggle_noncustomizable_toolbar.js]
|
||||
[browser_993322_widget_notoolbar.js]
|
||||
[browser_995164_registerArea_during_customize_mode.js]
|
||||
|
@ -151,7 +148,7 @@ skip-if = e10s # Bug 1088710
|
|||
[browser_1087303_button_fullscreen.js]
|
||||
skip-if = os == "mac"
|
||||
[browser_1087303_button_preferences.js]
|
||||
[browser_bootstrapped_custom_toolbar.js]
|
||||
[browser_panel_toggle.js]
|
||||
[browser_1089591_still_customizable_after_reset.js]
|
||||
[browser_1096763_seen_widgets_post_reset.js]
|
||||
[browser_bootstrapped_custom_toolbar.js]
|
||||
[browser_panel_toggle.js]
|
||||
|
|
|
@ -74,19 +74,14 @@ function createMockAllocations () {
|
|||
* @param {TabTarget} target
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function* memoryActorSupported (target) {
|
||||
function memoryActorSupported (target) {
|
||||
// This `target` property is used only in tests to test
|
||||
// instances where the memory actor is not available.
|
||||
if (target.TEST_MOCK_MEMORY_ACTOR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let method of REQUIRED_MEMORY_ACTOR_METHODS) {
|
||||
if (!(yield target.actorHasMethod("memory", method))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return !!target.getTrait("memoryActorAllocations");
|
||||
}
|
||||
exports.memoryActorSupported = Task.async(memoryActorSupported);
|
||||
|
||||
|
@ -97,13 +92,13 @@ exports.memoryActorSupported = Task.async(memoryActorSupported);
|
|||
* @param {TabTarget} target
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function* timelineActorSupported(target) {
|
||||
function timelineActorSupported(target) {
|
||||
// This `target` property is used only in tests to test
|
||||
// instances where the timeline actor is not available.
|
||||
if (target.TEST_MOCK_TIMELINE_ACTOR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return yield target.hasActor("timeline");
|
||||
return target.hasActor("timeline");
|
||||
}
|
||||
exports.timelineActorSupported = Task.async(timelineActorSupported);
|
||||
|
|
|
@ -12,6 +12,8 @@ support-files =
|
|||
[browser_perf-allocations-to-samples.js]
|
||||
[browser_perf-compatibility-01.js]
|
||||
[browser_perf-compatibility-02.js]
|
||||
[browser_perf-compatibility-03.js]
|
||||
[browser_perf-compatibility-04.js]
|
||||
[browser_perf-clear-01.js]
|
||||
[browser_perf-clear-02.js]
|
||||
[browser_perf-data-massaging-01.js]
|
||||
|
|
|
@ -12,6 +12,7 @@ function spawnTest () {
|
|||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
let { memory, timeline } = front.getMocksInUse();
|
||||
ok(memory, "memory should be mocked.");
|
||||
|
|
|
@ -13,6 +13,7 @@ let test = Task.async(function*() {
|
|||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
let { EVENTS, gFront, PerformanceController, PerformanceView } = panel.panelWin;
|
||||
|
||||
let { memory: memoryMock, timeline: timelineMock } = gFront.getMocksInUse();
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test basic functionality of PerformanceFront with only mock memory.
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 100;
|
||||
|
||||
function spawnTest () {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, {
|
||||
TEST_MOCK_MEMORY_ACTOR: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
let { memory, timeline } = front.getMocksInUse();
|
||||
ok(memory, "memory should be mocked.");
|
||||
ok(!timeline, "timeline should not be mocked.");
|
||||
|
||||
let {
|
||||
profilerStartTime,
|
||||
timelineStartTime,
|
||||
memoryStartTime
|
||||
} = yield front.startRecording({
|
||||
withTicks: true,
|
||||
withMemory: true,
|
||||
withAllocations: true
|
||||
});
|
||||
|
||||
ok(typeof profilerStartTime === "number",
|
||||
"The front.startRecording() emits a profiler start time.");
|
||||
ok(typeof timelineStartTime === "number",
|
||||
"The front.startRecording() emits a timeline start time.");
|
||||
ok(typeof memoryStartTime === "number",
|
||||
"The front.startRecording() emits a memory start time.");
|
||||
|
||||
yield busyWait(WAIT_TIME);
|
||||
|
||||
let {
|
||||
profilerEndTime,
|
||||
timelineEndTime,
|
||||
memoryEndTime
|
||||
} = yield front.stopRecording({
|
||||
withAllocations: true
|
||||
});
|
||||
|
||||
ok(typeof profilerEndTime === "number",
|
||||
"The front.stopRecording() emits a profiler end time.");
|
||||
ok(typeof timelineEndTime === "number",
|
||||
"The front.stopRecording() emits a timeline end time.");
|
||||
ok(typeof memoryEndTime === "number",
|
||||
"The front.stopRecording() emits a memory end time.");
|
||||
|
||||
ok(profilerEndTime > profilerStartTime,
|
||||
"The profilerEndTime is after profilerStartTime.");
|
||||
ok(timelineEndTime > timelineStartTime,
|
||||
"The timelineEndTime is after timelineStartTime.");
|
||||
is(memoryEndTime, memoryStartTime,
|
||||
"The memoryEndTime is the same as memoryStartTime.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the recording model is populated correctly when using timeline
|
||||
* and memory actor mocks.
|
||||
*/
|
||||
|
||||
const WAIT_TIME = 1000;
|
||||
|
||||
let test = Task.async(function*() {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
|
||||
TEST_MOCK_MEMORY_ACTOR: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
let { EVENTS, gFront, PerformanceController, PerformanceView } = panel.panelWin;
|
||||
|
||||
|
||||
let { memory: memoryMock, timeline: timelineMock } = gFront.getMocksInUse();
|
||||
ok(memoryMock, "memory should be mocked.");
|
||||
ok(!timelineMock, "timeline should not be mocked.");
|
||||
|
||||
yield startRecording(panel);
|
||||
yield busyWait(100);
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getMemory().length);
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
|
||||
yield stopRecording(panel);
|
||||
|
||||
let {
|
||||
label, duration, allocations, profile
|
||||
} = PerformanceController.getCurrentRecording().getAllData();
|
||||
|
||||
is(label, "", "Empty label for mock.");
|
||||
is(typeof duration, "number", "duration is a number");
|
||||
ok(duration > 0, "duration is not 0");
|
||||
|
||||
isEmptyArray(allocations.sites, "allocations.sites");
|
||||
isEmptyArray(allocations.timestamps, "allocations.timestamps");
|
||||
isEmptyArray(allocations.frames, "allocations.frames");
|
||||
isEmptyArray(allocations.counts, "allocations.counts");
|
||||
|
||||
let sampleCount = 0;
|
||||
|
||||
for (let thread of profile.threads) {
|
||||
info("Checking thread: " + thread.name);
|
||||
|
||||
for (let sample of thread.samples) {
|
||||
sampleCount++;
|
||||
|
||||
if (sample.frames[0].location != "(root)") {
|
||||
ok(false, "The sample " + sample.toSource() + " doesn't have a root node.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok(sampleCount > 0,
|
||||
"At least some samples have been iterated over, checking for root nodes.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
});
|
||||
|
||||
function isEmptyArray (array, name) {
|
||||
ok(Array.isArray(array), `${name} is an array`);
|
||||
is(array.length, 0, `${name} is empty`);
|
||||
}
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html?" + Date.now();
|
||||
|
||||
const TEST_XHR_ERROR_URI = `http://example.com/404.html?${Date.now()}`;
|
||||
|
||||
"use strict";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
|
@ -49,6 +51,12 @@ function consoleOpened(hud)
|
|||
xhr.open("get", TEST_URI, true);
|
||||
xhr.send();
|
||||
|
||||
// Check for xhr error.
|
||||
let xhrErr = new XMLHttpRequest();
|
||||
xhrErr.onload = () => console.log("xhr error loaded, status is: " + xhrErr.status);
|
||||
xhrErr.open("get", TEST_XHR_ERROR_URI, true);
|
||||
xhrErr.send();
|
||||
|
||||
return waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
|
@ -81,6 +89,14 @@ function consoleOpened(hud)
|
|||
text: "test-console.html",
|
||||
category: CATEGORY_NETWORK,
|
||||
severity: SEVERITY_INFO,
|
||||
isXhr: true,
|
||||
},
|
||||
{
|
||||
name: "xhr error message",
|
||||
text: "404.html",
|
||||
category: CATEGORY_NETWORK,
|
||||
severity: SEVERITY_ERROR,
|
||||
isXhr: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// Tests that network log messages bring up the network panel.
|
||||
|
||||
const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html";
|
||||
const TEST_NETWORK_REQUEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-network-request.html";
|
||||
|
||||
const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
|
||||
|
||||
|
@ -20,14 +20,20 @@ let hud, browser;
|
|||
function test()
|
||||
{
|
||||
const PREF = "devtools.webconsole.persistlog";
|
||||
let original = Services.prefs.getBoolPref("devtools.webconsole.filter.networkinfo");
|
||||
let originalXhr = Services.prefs.getBoolPref("devtools.webconsole.filter.netxhr");
|
||||
Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true);
|
||||
Services.prefs.setBoolPref("devtools.webconsole.filter.netxhr", true);
|
||||
const NET_PREF = "devtools.webconsole.filter.networkinfo";
|
||||
const NETXHR_PREF = "devtools.webconsole.filter.netxhr"
|
||||
const MIXED_AC_PREF = "security.mixed_content.block_active_content"
|
||||
let original = Services.prefs.getBoolPref(NET_PREF);
|
||||
let originalXhr = Services.prefs.getBoolPref(NETXHR_PREF);
|
||||
let originalMixedActive = Services.prefs.getBoolPref(MIXED_AC_PREF);
|
||||
Services.prefs.setBoolPref(NET_PREF, true);
|
||||
Services.prefs.setBoolPref(NETXHR_PREF, true);
|
||||
Services.prefs.setBoolPref(MIXED_AC_PREF, false);
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", original);
|
||||
Services.prefs.setBoolPref("devtools.webconsole.filter.netxhr", originalXhr);
|
||||
Services.prefs.setBoolPref(NET_PREF, original);
|
||||
Services.prefs.setBoolPref(NETXHR_PREF, originalXhr);
|
||||
Services.prefs.setBoolPref(MIXED_AC_PREF, originalMixedActive);
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
});
|
||||
|
||||
|
@ -100,13 +106,27 @@ function testXhrGet()
|
|||
is(lastRequest.request.method, "GET", "Method is correct");
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testXhrPost);
|
||||
executeSoon(testXhrWarn);
|
||||
};
|
||||
|
||||
// Start the XMLHttpRequest() GET test.
|
||||
content.wrappedJSObject.testXhrGet();
|
||||
}
|
||||
|
||||
function testXhrWarn()
|
||||
{
|
||||
requestCallback = function() {
|
||||
ok(lastRequest, "testXhrWarn() was logged");
|
||||
is(lastRequest.request.method, "GET", "Method is correct");
|
||||
lastRequest = null;
|
||||
requestCallback = null;
|
||||
executeSoon(testXhrPost);
|
||||
};
|
||||
|
||||
// Start the XMLHttpRequest() warn test.
|
||||
content.wrappedJSObject.testXhrWarn();
|
||||
}
|
||||
|
||||
function testXhrPost()
|
||||
{
|
||||
requestCallback = function() {
|
||||
|
@ -143,8 +163,16 @@ function testFormSubmission()
|
|||
text: "test-data.json",
|
||||
category: CATEGORY_NETWORK,
|
||||
severity: SEVERITY_INFO,
|
||||
isXhr: true,
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
text: "http://example.com/",
|
||||
category: CATEGORY_NETWORK,
|
||||
severity: SEVERITY_WARNING,
|
||||
isXhr: true,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
}).then(testLiveFilteringOnSearchStrings);
|
||||
};
|
||||
|
|
|
@ -1117,6 +1117,14 @@ function waitForMessages(aOptions)
|
|||
return true;
|
||||
}
|
||||
|
||||
function hasXhrLabel(aElement) {
|
||||
let xhr = aElement.querySelector('.xhr');
|
||||
if (!xhr) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkMessage(aRule, aElement)
|
||||
{
|
||||
let elemText = aElement.textContent;
|
||||
|
@ -1161,6 +1169,14 @@ function waitForMessages(aOptions)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (aRule.isXhr && !hasXhrLabel(aElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aRule.isXhr && hasXhrLabel(aElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let partialMatch = !!(aRule.consoleTrace || aRule.consoleTime ||
|
||||
aRule.consoleTimeEnd);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
var str = "Dolske Digs Bacon, Now and Forevermore."
|
||||
for (var i=0; i < 5; i++) {
|
||||
console.log(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.info("INLINE SCRIPT:");
|
||||
test();
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
makeXhr('get', 'test-data.json', null, aCallback);
|
||||
}
|
||||
|
||||
function testXhrWarn(aCallback) {
|
||||
makeXhr('get', 'http://example.com', null, aCallback);
|
||||
}
|
||||
|
||||
function testXhrPost(aCallback) {
|
||||
makeXhr('post', 'test-data.json', "Hello world!", aCallback);
|
||||
}
|
||||
|
@ -28,7 +32,7 @@
|
|||
<h1>Heads Up Display HTTP Logging Testpage</h1>
|
||||
<h2>This page is used to test the HTTP logging.</h2>
|
||||
|
||||
<form action="http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html" method="post">
|
||||
<form action="https://example.com/browser/browser/devtools/webconsole/test/test-network-request.html" method="post">
|
||||
<input name="name" type="text" value="foo bar"><br>
|
||||
<input name="age" type="text" value="144"><br>
|
||||
</form>
|
||||
|
|
|
@ -1499,6 +1499,7 @@ WebConsoleFrame.prototype = {
|
|||
let clipboardText = request.method + " " + request.url;
|
||||
let severity = SEVERITY_LOG;
|
||||
if (networkInfo.isXHR) {
|
||||
clipboardText = request.method + " XHR " + request.url;
|
||||
severity = SEVERITY_INFO;
|
||||
}
|
||||
let mixedRequest =
|
||||
|
@ -1523,6 +1524,14 @@ WebConsoleFrame.prototype = {
|
|||
let body = methodNode.parentNode;
|
||||
body.setAttribute("aria-haspopup", true);
|
||||
|
||||
if (networkInfo.isXHR) {
|
||||
let xhrNode = this.document.createElementNS(XHTML_NS, "span");
|
||||
xhrNode.className = "xhr";
|
||||
xhrNode.textContent = l10n.getStr("webConsoleXhrIndicator");
|
||||
body.appendChild(xhrNode);
|
||||
body.appendChild(this.document.createTextNode(" "));
|
||||
}
|
||||
|
||||
let displayUrl = request.url;
|
||||
let pos = displayUrl.indexOf("?");
|
||||
if (pos > -1) {
|
||||
|
@ -1855,6 +1864,7 @@ WebConsoleFrame.prototype = {
|
|||
let hasEventTimings = updates.indexOf("eventTimings") > -1;
|
||||
let hasResponseStart = updates.indexOf("responseStart") > -1;
|
||||
let request = networkInfo.request;
|
||||
let methodText = (networkInfo.isXHR)? request.method + ' XHR' : request.method;
|
||||
let response = networkInfo.response;
|
||||
let updated = false;
|
||||
|
||||
|
@ -1872,7 +1882,7 @@ WebConsoleFrame.prototype = {
|
|||
let statusNode = messageNode.getElementsByClassName("status")[0];
|
||||
statusNode.textContent = statusText;
|
||||
|
||||
messageNode.clipboardText = [request.method, request.url, statusText]
|
||||
messageNode.clipboardText = [methodText, request.url, statusText]
|
||||
.join(" ");
|
||||
|
||||
if (hasResponseStart && response.status >= MIN_HTTP_ERROR_CODE &&
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
for the help button in the menubar but Gnome does not. -->
|
||||
<!ENTITY helpMenuWin.label "Help">
|
||||
<!ENTITY helpMenuWin.accesskey "H">
|
||||
<!ENTITY aboutProduct.label "About &brandShortName;">
|
||||
<!ENTITY aboutProduct.accesskey "A">
|
||||
<!ENTITY productHelp.label "&brandShortName; Help">
|
||||
<!ENTITY productHelp.accesskey "H">
|
||||
<!ENTITY aboutProduct2.label "About &brandShorterName;">
|
||||
<!ENTITY aboutProduct2.accesskey "A">
|
||||
<!ENTITY productHelp2.label "&brandShorterName; Help">
|
||||
<!ENTITY productHelp2.accesskey "H">
|
||||
<!ENTITY helpMac.commandkey "?">
|
||||
|
||||
<!ENTITY helpKeyboardShortcuts.label "Keyboard Shortcuts">
|
||||
|
@ -26,8 +26,8 @@
|
|||
<!ENTITY helpSafeMode.label "Restart with Add-ons Disabled…">
|
||||
<!ENTITY helpSafeMode.accesskey "R">
|
||||
|
||||
<!ENTITY healthReport.label "&brandShortName; Health Report">
|
||||
<!ENTITY healthReport.accesskey "e">
|
||||
<!ENTITY healthReport2.label "&brandShorterName; Health Report">
|
||||
<!ENTITY healthReport2.accesskey "e">
|
||||
|
||||
<!ENTITY helpTroubleshootingInfo.label "Troubleshooting Information">
|
||||
<!ENTITY helpTroubleshootingInfo.accesskey "T">
|
||||
|
@ -35,16 +35,16 @@
|
|||
<!ENTITY helpFeedbackPage.label "Submit Feedback…">
|
||||
<!ENTITY helpFeedbackPage.accesskey "S">
|
||||
|
||||
<!ENTITY helpShowTour.label "&brandShortName; Tour">
|
||||
<!ENTITY helpShowTour.accesskey "o">
|
||||
<!ENTITY helpShowTour2.label "&brandShorterName; Tour">
|
||||
<!ENTITY helpShowTour2.accesskey "o">
|
||||
|
||||
<!ENTITY preferencesCmdMac.label "Preferences…">
|
||||
<!ENTITY preferencesCmdMac.commandkey ",">
|
||||
|
||||
<!ENTITY servicesMenuMac.label "Services">
|
||||
|
||||
<!ENTITY hideThisAppCmdMac.label "Hide &brandShortName;">
|
||||
<!ENTITY hideThisAppCmdMac.commandkey "H">
|
||||
<!ENTITY hideThisAppCmdMac2.label "Hide &brandShorterName;">
|
||||
<!ENTITY hideThisAppCmdMac2.commandkey "H">
|
||||
|
||||
<!ENTITY hideOtherAppsCmdMac.label "Hide Others">
|
||||
<!ENTITY hideOtherAppsCmdMac.commandkey "H">
|
||||
|
|
|
@ -605,14 +605,14 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
|
||||
<!ENTITY sidebarCloseButton.tooltip "Close sidebar">
|
||||
|
||||
<!ENTITY quitApplicationCmdWin.label "Exit">
|
||||
<!ENTITY quitApplicationCmdWin.accesskey "x">
|
||||
<!ENTITY quitApplicationCmdWin.tooltip "Exit &brandShortName;">
|
||||
<!ENTITY quitApplicationCmdWin2.label "Exit">
|
||||
<!ENTITY quitApplicationCmdWin2.accesskey "x">
|
||||
<!ENTITY quitApplicationCmdWin2.tooltip "Exit &brandShorterName;">
|
||||
<!ENTITY goBackCmd.commandKey "[">
|
||||
<!ENTITY goForwardCmd.commandKey "]">
|
||||
<!ENTITY quitApplicationCmd.label "Quit">
|
||||
<!ENTITY quitApplicationCmd.accesskey "Q">
|
||||
<!ENTITY quitApplicationCmdMac.label "Quit &brandShortName;">
|
||||
<!ENTITY quitApplicationCmdMac2.label "Quit &brandShorterName;">
|
||||
<!-- LOCALIZATION NOTE(quitApplicationCmdUnix.key): This keyboard shortcut is used by both Linux and OSX builds. -->
|
||||
<!ENTITY quitApplicationCmdUnix.key "Q">
|
||||
|
||||
|
|
|
@ -70,6 +70,11 @@ ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, conso
|
|||
# the URL the correct direction. Parameters: %S is the web page URL.
|
||||
webConsoleWindowTitleAndURL=Web Console - %S
|
||||
|
||||
# LOCALIZATION NOTE (webConsoleXhrIndicator): the indicator displayed before
|
||||
# a URL in the Web Console that was requested using an XMLHttpRequest.
|
||||
# Should probably be the same as &btnConsoleXhr; in webConsole.dtd
|
||||
webConsoleXhrIndicator=XHR
|
||||
|
||||
# LOCALIZATION NOTE (webConsoleMixedContentWarning): the message displayed
|
||||
# after a URL in the Web Console that has been flagged for Mixed Content (i.e.
|
||||
# http content in an https page).
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# 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/.
|
||||
|
||||
readerMode.enter=Enter Reader Mode
|
||||
readerMode.exit=Exit Reader Mode
|
|
@ -138,6 +138,7 @@
|
|||
locale/browser/preferences/tabs.dtd (%chrome/browser/preferences/tabs.dtd)
|
||||
locale/browser/preferences/search.dtd (%chrome/browser/preferences/search.dtd)
|
||||
locale/browser/preferences/translation.dtd (%chrome/browser/preferences/translation.dtd)
|
||||
locale/browser/readerMode.properties (%chrome/browser/readerMode.properties)
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
locale/browser/syncBrand.dtd (%chrome/browser/syncBrand.dtd)
|
||||
locale/browser/syncSetup.dtd (%chrome/browser/syncSetup.dtd)
|
||||
|
|
|
@ -15,6 +15,8 @@ Cu.import("resource://gre/modules/Task.jsm");
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm");
|
||||
|
||||
const gStringBundle = Services.strings.createBundle("chrome://browser/locale/readerMode.properties");
|
||||
|
||||
let ReaderParent = {
|
||||
|
||||
MESSAGES: [
|
||||
|
@ -101,13 +103,23 @@ let ReaderParent = {
|
|||
if (browser.currentURI.spec.startsWith("about:reader")) {
|
||||
button.setAttribute("readeractive", true);
|
||||
button.hidden = false;
|
||||
button.setAttribute("tooltiptext", gStringBundle.GetStringFromName("readerMode.exit"));
|
||||
} else {
|
||||
button.removeAttribute("readeractive");
|
||||
button.setAttribute("tooltiptext", gStringBundle.GetStringFromName("readerMode.enter"));
|
||||
button.hidden = !browser.isArticle;
|
||||
}
|
||||
},
|
||||
|
||||
toggleReaderMode: function(event) {
|
||||
handleReaderButtonEvent: function(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if ((event.type == "click" && event.button != 0) ||
|
||||
(event.type == "keypress" && event.charCode != Ci.nsIDOMKeyEvent.DOM_VK_SPACE &&
|
||||
event.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN)) {
|
||||
return; // Left click, space or enter only
|
||||
}
|
||||
|
||||
let win = event.target.ownerDocument.defaultView;
|
||||
let url = win.gBrowser.selectedBrowser.currentURI.spec;
|
||||
if (url.startsWith("about:reader")) {
|
||||
|
|
|
@ -30,6 +30,7 @@ EXTRA_JS_MODULES += [
|
|||
'offlineAppCache.jsm',
|
||||
'PanelFrame.jsm',
|
||||
'ProcessHangMonitor.jsm',
|
||||
'ReaderParent.jsm',
|
||||
'RemotePrompt.jsm',
|
||||
'SitePermissions.jsm',
|
||||
'Social.jsm',
|
||||
|
@ -52,7 +53,6 @@ if CONFIG['NIGHTLY_BUILD']:
|
|||
EXTRA_PP_JS_MODULES += [
|
||||
'AboutHome.jsm',
|
||||
'PluginContent.jsm',
|
||||
'ReaderParent.jsm',
|
||||
'RecentWindow.jsm',
|
||||
'webrtcUI.jsm',
|
||||
]
|
||||
|
|
|
@ -1617,10 +1617,20 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
/* Reader mode button */
|
||||
|
||||
#reader-mode-button {
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
list-style-image: url("chrome://browser/skin/reader-mode-16.png");
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#reader-mode-button > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#reader-mode-button:focus {
|
||||
outline: 1px dotted;
|
||||
}
|
||||
|
||||
#reader-mode-button:hover:active,
|
||||
#reader-mode-button[readeractive] {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
|
|
|
@ -2521,20 +2521,29 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
|||
/* Reader mode button */
|
||||
|
||||
#reader-mode-button {
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
list-style-image: url("chrome://browser/skin/reader-mode-16.png");
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#reader-mode-button > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#reader-mode-button:focus {
|
||||
@hudButtonFocused@
|
||||
}
|
||||
|
||||
#reader-mode-button:hover:active,
|
||||
#reader-mode-button[readeractive] {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#reader-mode-button{
|
||||
#reader-mode-button {
|
||||
list-style-image: url("chrome://browser/skin/reader-mode-16@2x.png");
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
#reader-mode-button:hover:active,
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
|
||||
.call-tree-header[type="samples"],
|
||||
.call-tree-cell[type="samples"] {
|
||||
width: 4vw;
|
||||
width: 4.5vw;
|
||||
}
|
||||
|
||||
.call-tree-header[type="allocations"],
|
||||
|
|
|
@ -262,6 +262,17 @@ a {
|
|||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.message[category=network] .xhr {
|
||||
background-color: var(--theme-body-color-alt);
|
||||
color: var(--theme-body-background);
|
||||
border-radius: 3px;
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
padding: 2px;
|
||||
line-height: 10px;
|
||||
-moz-margin-end: 1ex;
|
||||
}
|
||||
|
||||
/* CSS styles */
|
||||
.webconsole-filter-button[category="css"] > .toolbarbutton-menubutton-button:before {
|
||||
background-image: linear-gradient(#2DC3F3, #00B6F0);
|
||||
|
|
|
@ -1579,10 +1579,20 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
/* Reader mode button */
|
||||
|
||||
#reader-mode-button {
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
list-style-image: url("chrome://browser/skin/reader-mode-16.png");
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#reader-mode-button > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#reader-mode-button:focus {
|
||||
outline: 1px dotted;
|
||||
}
|
||||
|
||||
#reader-mode-button:hover:active,
|
||||
#reader-mode-button[readeractive] {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
|
|
|
@ -850,7 +850,19 @@ pref("dom.meta-viewport.enabled", true);
|
|||
// Enable the OpenH264 plugin support in the addon manager.
|
||||
pref("media.gmp-gmpopenh264.provider.enabled", true);
|
||||
|
||||
// The default color scheme in reader mode (light, dark, print, auto)
|
||||
// The default color scheme in reader mode (light, dark, auto)
|
||||
// auto = color automatically adjusts according to ambient light level
|
||||
// (auto only works on platforms where the 'devicelight' event is enabled)
|
||||
pref("reader.color_scheme", "auto");
|
||||
|
||||
// Color scheme values available in reader mode UI.
|
||||
pref("reader.color_scheme.values", "[\"light\",\"dark\",\"auto\"]");
|
||||
|
||||
// The font type in reader (charis-sil, clear-sans)
|
||||
pref("reader.font_type", "clear-sans");
|
||||
|
||||
// Font type values available in reader mode UI.
|
||||
pref("reader.font_type.values", "[\"charis-sil\",\"clear-sans\"]");
|
||||
|
||||
// Whether to use a vertical or horizontal toolbar.
|
||||
pref("reader.toolbar.vertical", false);
|
||||
|
|
|
@ -839,9 +839,7 @@ public abstract class GeckoApp
|
|||
|
||||
@Override
|
||||
public void onToastHidden(ButtonToast.ReasonHidden reason) {
|
||||
if (reason == ButtonToast.ReasonHidden.TIMEOUT) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Hidden", buttonId));
|
||||
}
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Hidden", buttonId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -329,18 +329,17 @@ public class AccountPickler {
|
|||
NonObjectJSONException, NoSuchAlgorithmException {
|
||||
// TODO: Should copy-pasta BUNDLE_KEY_STATE & LABEL to this file to ensure we maintain
|
||||
// old versions?
|
||||
final StateLabel stateLabel = StateLabel.valueOf(
|
||||
final StateLabel stateLabelString = StateLabel.valueOf(
|
||||
bundle.getString(AndroidFxAccount.BUNDLE_KEY_STATE_LABEL));
|
||||
final String stateString = bundle.getString(AndroidFxAccount.BUNDLE_KEY_STATE);
|
||||
if (stateLabel == null) {
|
||||
throw new IllegalStateException("stateLabel must not be null");
|
||||
}
|
||||
if (stateString == null) {
|
||||
throw new IllegalStateException("stateString must not be null");
|
||||
if (stateLabelString == null || stateString == null) {
|
||||
throw new IllegalStateException("stateLabel and stateString must not be null, but: " +
|
||||
"(stateLabel == null) = " + (stateLabelString == null) +
|
||||
" and (stateString == null) = " + (stateString == null));
|
||||
}
|
||||
|
||||
try {
|
||||
return StateFactory.fromJSONObject(stateLabel, new ExtendedJSONObject(stateString));
|
||||
return StateFactory.fromJSONObject(stateLabelString, new ExtendedJSONObject(stateString));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("could not get state", e);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Collections;
|
|||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.background.common.GlobalConstants;
|
||||
|
@ -83,6 +84,21 @@ public class AndroidFxAccount {
|
|||
protected final AccountManager accountManager;
|
||||
protected final Account account;
|
||||
|
||||
/**
|
||||
* A cache associating Account name (email address) to a representation of the
|
||||
* account's internal bundle.
|
||||
* <p>
|
||||
* The cache is invalidated entirely when <it>any</it> new Account is added,
|
||||
* because there is no reliable way to know that an Account has been removed
|
||||
* and then re-added.
|
||||
*/
|
||||
protected static final ConcurrentHashMap<String, ExtendedJSONObject> perAccountBundleCache =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public static void invalidateCaches() {
|
||||
perAccountBundleCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Android Firefox Account instance backed by an Android Account
|
||||
* instance.
|
||||
|
@ -138,15 +154,28 @@ public class AndroidFxAccount {
|
|||
* Saves the given data as the internal bundle associated with this account.
|
||||
* @param bundle to write to account.
|
||||
*/
|
||||
protected void persistBundle(ExtendedJSONObject bundle) {
|
||||
protected synchronized void persistBundle(ExtendedJSONObject bundle) {
|
||||
perAccountBundleCache.put(account.name, bundle);
|
||||
accountManager.setUserData(account, ACCOUNT_KEY_DESCRIPTOR, bundle.toJSONString());
|
||||
}
|
||||
|
||||
protected ExtendedJSONObject unbundle() {
|
||||
return unbundle(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the internal bundle associated with this account.
|
||||
* @return bundle associated with account.
|
||||
*/
|
||||
protected ExtendedJSONObject unbundle() {
|
||||
protected synchronized ExtendedJSONObject unbundle(boolean allowCachedBundle) {
|
||||
if (allowCachedBundle) {
|
||||
final ExtendedJSONObject cachedBundle = perAccountBundleCache.get(account.name);
|
||||
if (cachedBundle != null) {
|
||||
Logger.debug(LOG_TAG, "Returning cached account bundle.");
|
||||
return cachedBundle;
|
||||
}
|
||||
}
|
||||
|
||||
final int version = getAccountVersion();
|
||||
if (version < CURRENT_ACCOUNT_VERSION) {
|
||||
// Needs upgrade. For now, do nothing. We'd like to just put your account
|
||||
|
@ -159,11 +188,14 @@ public class AndroidFxAccount {
|
|||
return null;
|
||||
}
|
||||
|
||||
String bundle = accountManager.getUserData(account, ACCOUNT_KEY_DESCRIPTOR);
|
||||
if (bundle == null) {
|
||||
String bundleString = accountManager.getUserData(account, ACCOUNT_KEY_DESCRIPTOR);
|
||||
if (bundleString == null) {
|
||||
return null;
|
||||
}
|
||||
return unbundleAccountV2(bundle);
|
||||
final ExtendedJSONObject bundle = unbundleAccountV2(bundleString);
|
||||
perAccountBundleCache.put(account.name, bundle);
|
||||
Logger.info(LOG_TAG, "Account bundle persisted to cache.");
|
||||
return bundle;
|
||||
}
|
||||
|
||||
protected String getBundleData(String key) {
|
||||
|
@ -194,25 +226,18 @@ public class AndroidFxAccount {
|
|||
return o.getByteArrayHex(key);
|
||||
}
|
||||
|
||||
protected void updateBundleDataBytes(String key, byte[] value) {
|
||||
updateBundleValue(key, value == null ? null : Utils.byte2Hex(value));
|
||||
}
|
||||
|
||||
protected void updateBundleValue(String key, boolean value) {
|
||||
protected void updateBundleValues(String key, String value, String... more) {
|
||||
if (more.length % 2 != 0) {
|
||||
throw new IllegalArgumentException("more must be a list of key, value pairs");
|
||||
}
|
||||
ExtendedJSONObject descriptor = unbundle();
|
||||
if (descriptor == null) {
|
||||
return;
|
||||
}
|
||||
descriptor.put(key, value);
|
||||
persistBundle(descriptor);
|
||||
}
|
||||
|
||||
protected void updateBundleValue(String key, String value) {
|
||||
ExtendedJSONObject descriptor = unbundle();
|
||||
if (descriptor == null) {
|
||||
return;
|
||||
for (int i = 0; i + 1 < more.length; i += 2) {
|
||||
descriptor.put(more[i], more[i+1]);
|
||||
}
|
||||
descriptor.put(key, value);
|
||||
persistBundle(descriptor);
|
||||
}
|
||||
|
||||
|
@ -497,8 +522,9 @@ public class AndroidFxAccount {
|
|||
}
|
||||
Logger.info(LOG_TAG, "Moving account named like " + getObfuscatedEmail() +
|
||||
" to state " + state.getStateLabel().toString());
|
||||
updateBundleValue(BUNDLE_KEY_STATE_LABEL, state.getStateLabel().name());
|
||||
updateBundleValue(BUNDLE_KEY_STATE, state.toJSONObject().toJSONString());
|
||||
updateBundleValues(
|
||||
BUNDLE_KEY_STATE_LABEL, state.getStateLabel().name(),
|
||||
BUNDLE_KEY_STATE, state.toJSONObject().toJSONString());
|
||||
broadcastAccountStateChangedIntent();
|
||||
}
|
||||
|
||||
|
@ -511,11 +537,10 @@ public class AndroidFxAccount {
|
|||
public synchronized State getState() {
|
||||
String stateLabelString = getBundleData(BUNDLE_KEY_STATE_LABEL);
|
||||
String stateString = getBundleData(BUNDLE_KEY_STATE);
|
||||
if (stateLabelString == null) {
|
||||
throw new IllegalStateException("stateLabelString must not be null");
|
||||
}
|
||||
if (stateString == null) {
|
||||
throw new IllegalStateException("stateString must not be null");
|
||||
if (stateLabelString == null || stateString == null) {
|
||||
throw new IllegalStateException("stateLabelString and stateString must not be null, but: " +
|
||||
"(stateLabelString == null) = " + (stateLabelString == null) +
|
||||
" and (stateString == null) = " + (stateString == null));
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -36,6 +36,10 @@ public class FxAccountAuthenticator extends AbstractAccountAuthenticator {
|
|||
throws NetworkErrorException {
|
||||
Logger.debug(LOG_TAG, "addAccount");
|
||||
|
||||
// The data associated to each Account should be invalidated when we change
|
||||
// the set of Firefox Accounts on the system.
|
||||
AndroidFxAccount.invalidateCaches();
|
||||
|
||||
final Bundle res = new Bundle();
|
||||
|
||||
if (!FxAccountConstants.ACCOUNT_TYPE.equals(accountType)) {
|
||||
|
|
|
@ -175,6 +175,13 @@ public class RemoteTabsExpandableListFragment extends RemoteTabsBaseFragment {
|
|||
|
||||
@Override
|
||||
protected void updateUiFromClients(List<RemoteClient> clients, List<RemoteClient> hiddenClients) {
|
||||
if (getView() == null) {
|
||||
// Early abort. It is possible to get UI updates after the view is
|
||||
// destroyed; this can happen due to asynchronous loaders or
|
||||
// animations complete.
|
||||
return;
|
||||
}
|
||||
|
||||
// We have three states: no clients (including hidden clients) at all;
|
||||
// all clients hidden; some clients hidden. We want to show the empty
|
||||
// list view only when we have no clients at all. This flag
|
||||
|
|
|
@ -204,6 +204,13 @@ public class RemoteTabsSplitPlaneFragment extends RemoteTabsBaseFragment {
|
|||
|
||||
@Override
|
||||
protected void updateUiFromClients(List<RemoteClient> clients, List<RemoteClient> hiddenClients) {
|
||||
if (getView() == null) {
|
||||
// Early abort. It is possible to get UI updates after the view is
|
||||
// destroyed; this can happen due to asynchronous loaders or
|
||||
// animations complete.
|
||||
return;
|
||||
}
|
||||
|
||||
// We have three states: no clients (including hidden clients) at all;
|
||||
// all clients hidden; some clients hidden. We want to show the empty
|
||||
// list view only when we have no clients at all. This flag
|
||||
|
|
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ab_mic.png
До Ширина: | Высота: | Размер: 874 B После Ширина: | Высота: | Размер: 514 B |
Двоичные данные
mobile/android/base/resources/drawable-mdpi/ab_mic.png
До Ширина: | Высота: | Размер: 524 B После Ширина: | Высота: | Размер: 337 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/ab_mic.png
До Ширина: | Высота: | Размер: 1.1 KiB После Ширина: | Высота: | Размер: 578 B |
Двоичные данные
mobile/android/base/resources/drawable-xxhdpi/ab_mic.png
До Ширина: | Высота: | Размер: 1.8 KiB После Ширина: | Высота: | Размер: 856 B |
|
@ -13,32 +13,31 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="1.0">
|
||||
<org.mozilla.gecko.widget.GeckoSwipeRefreshLayout
|
||||
android:id="@id/remote_tabs_refresh_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.mozilla.gecko.home.HomeListView
|
||||
android:id="@+id/clients_list"
|
||||
style="@style/Widget.RemoteTabsListView"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<org.mozilla.gecko.widget.GeckoSwipeRefreshLayout
|
||||
android:id="@id/remote_tabs_refresh_layout"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<org.mozilla.gecko.home.HomeListView
|
||||
android:id="@+id/tabs_list"
|
||||
style="@style/Widget.RemoteTabsListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
android:id="@+id/clients_list"
|
||||
style="@style/Widget.RemoteTabsListView"
|
||||
android:layout_weight="0.32"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</org.mozilla.gecko.widget.GeckoSwipeRefreshLayout>
|
||||
<org.mozilla.gecko.home.HomeListView
|
||||
android:id="@+id/tabs_list"
|
||||
style="@style/Widget.RemoteTabsListView"
|
||||
android:layout_weight="0.68"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</org.mozilla.gecko.widget.GeckoSwipeRefreshLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<!-- Overall, we want 12dp of padding from mic to the right edge of the toolbar.
|
||||
However, setting a value of 12dp (using the padding from the parent container)
|
||||
does not match drawablePadding=12dp. Part of this is the url_bar_entry drawable
|
||||
overlaps the EditText, but I can't figure out the rest. Thus eyeballing for
|
||||
paddingRight. -->
|
||||
<org.mozilla.gecko.toolbar.ToolbarEditText
|
||||
android:id="@+id/url_edit_text"
|
||||
style="@style/UrlBar.Title"
|
||||
|
@ -17,6 +22,8 @@
|
|||
android:selectAllOnFocus="true"
|
||||
android:contentDescription="@string/url_bar_default_text"
|
||||
android:drawableRight="@drawable/ab_mic"
|
||||
android:drawablePadding="12dp"
|
||||
android:paddingRight="8dp"
|
||||
gecko:autoUpdateTheme="false"/>
|
||||
|
||||
</merge>
|
||||
|
|
|
@ -11,11 +11,12 @@ import org.mozilla.gecko.Element;
|
|||
import org.mozilla.gecko.R;
|
||||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
|
||||
public class testFindInPage extends JavascriptTest implements GeckoEventListener {
|
||||
public class testFindInPage extends JavascriptTest implements NativeEventListener {
|
||||
private static final int WAIT_FOR_TEST = 3000;
|
||||
protected Element next, close;
|
||||
|
||||
|
@ -24,14 +25,15 @@ public class testFindInPage extends JavascriptTest implements GeckoEventListener
|
|||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(String event, final JSONObject message) {
|
||||
public void handleMessage(final String event, final NativeJSObject message,
|
||||
final EventCallback callback) {
|
||||
if (event.equals("Test:FindInPage")) {
|
||||
try {
|
||||
final String text = message.getString("text");
|
||||
final int nrOfMatches = Integer.parseInt(message.getString("nrOfMatches"));
|
||||
final int nrOfMatches = message.getInt("nrOfMatches");
|
||||
findText(text, nrOfMatches);
|
||||
} catch (Exception e) {
|
||||
fFail("Can't extract find query from JSON");
|
||||
callback.sendError("Can't extract find query from JSON :" + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,9 +41,11 @@ public class testFindInPage extends JavascriptTest implements GeckoEventListener
|
|||
try {
|
||||
close.click();
|
||||
} catch (Exception e) {
|
||||
fFail("FindInPage prompt not opened");
|
||||
callback.sendError("FindInPage prompt not opened");
|
||||
}
|
||||
}
|
||||
|
||||
callback.sendSuccess("done");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,17 +35,21 @@ function openTabWithUrl(url) {
|
|||
}
|
||||
|
||||
function findInPage(browser, text, nrOfMatches) {
|
||||
let repaintPromise = promiseBrowserEvent(browser, "MozAfterPaint");
|
||||
do_print("Send findInPageMessage: " + text + " nth: " + nrOfMatches);
|
||||
Messaging.sendRequest({ type: "Test:FindInPage", text: text, nrOfMatches: nrOfMatches });
|
||||
return repaintPromise;
|
||||
let messagePromise = Messaging.sendRequestForResult({
|
||||
type: "Test:FindInPage",
|
||||
text: text,
|
||||
nrOfMatches: nrOfMatches
|
||||
});
|
||||
let repaintPromise = promiseBrowserEvent(browser, "MozAfterPaint");
|
||||
return Promise.all([messagePromise, repaintPromise]);
|
||||
}
|
||||
|
||||
function closeFindInPage(browser) {
|
||||
let repaintPromise = promiseBrowserEvent(browser, "MozAfterPaint");
|
||||
do_print("Send closeFindInPageMessage");
|
||||
Messaging.sendRequest({ type: "Test:CloseFindInPage" });
|
||||
return repaintPromise;
|
||||
let messagePromise = Messaging.sendRequestForResult({ type: "Test:CloseFindInPage" });
|
||||
let repaintPromise = promiseBrowserEvent(browser, "MozAfterPaint");
|
||||
return Promise.all([messagePromise, repaintPromise]);
|
||||
}
|
||||
|
||||
function assertSelection(document, expectedSelection = false, expectedAnchorText = false) {
|
||||
|
|
|
@ -150,8 +150,21 @@ var FindHelper = {
|
|||
this._targetTab.sendViewportUpdate();
|
||||
}
|
||||
} else {
|
||||
// Disabled until bug 1014113 is fixed
|
||||
// ZoomHelper.zoomToRect(aData.rect);
|
||||
// Defines the space around the highlighted element as a factor of the element's size.
|
||||
const spacingFactor = 6;
|
||||
|
||||
// We replace the start of the zoom rect to keep the highlighted word in the middle.
|
||||
// We divide this offset by two to consider a spacing on each side of the rect.
|
||||
let x = aData.rect.x + (aData.rect.width * (1 - spacingFactor)) / 2;
|
||||
let y = aData.rect.y + (aData.rect.height * (1 - spacingFactor)) / 2;
|
||||
|
||||
let rect = new Rect(Math.max(x, 0),
|
||||
Math.max(y, 0),
|
||||
// we use a bigger viewport than just the highlighted word
|
||||
aData.rect.width * spacingFactor,
|
||||
aData.rect.height * spacingFactor);
|
||||
|
||||
ZoomHelper.zoomToRect(rect);
|
||||
this._viewportChanged = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,11 @@ var ZoomHelper = {
|
|||
* if it is really tall.
|
||||
*/
|
||||
zoomToRect: function(aRect, aClickY = -1) {
|
||||
if(aRect.isEmpty()) {
|
||||
// Protect from empty or negative-sized rects & potentials NaN in following calculations
|
||||
return;
|
||||
}
|
||||
|
||||
let viewport = BrowserApp.selectedTab.getViewport();
|
||||
|
||||
let rect = {
|
||||
|
|
|
@ -7656,8 +7656,9 @@ var Distribution = {
|
|||
}
|
||||
|
||||
// Apply a lightweight theme if necessary
|
||||
if (prefs["lightweightThemes.isThemeSelected"])
|
||||
if (prefs && prefs["lightweightThemes.isThemeSelected"]) {
|
||||
Services.obs.notifyObservers(null, "lightweight-theme-apply", "");
|
||||
}
|
||||
|
||||
let localizedString = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(Ci.nsIPrefLocalizedString);
|
||||
let localizeablePrefs = aData["LocalizablePreferences"];
|
||||
|
|
|
@ -25,11 +25,11 @@ body {
|
|||
color: #eeeeee;
|
||||
}
|
||||
|
||||
.sans-serif {
|
||||
.clear-sans {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.serif {
|
||||
.charis-sil {
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
|
@ -107,61 +107,61 @@ body {
|
|||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.font-size1 > .header > h1 {
|
||||
.font-size1 > body > .header > h1 {
|
||||
font-size: 27px;
|
||||
}
|
||||
|
||||
.font-size2 > .header > h1 {
|
||||
.font-size2 > body > .header > h1 {
|
||||
font-size: 29px;
|
||||
}
|
||||
|
||||
.font-size3 > .header > h1 {
|
||||
.font-size3 > body > .header > h1 {
|
||||
font-size: 31px;
|
||||
}
|
||||
|
||||
.font-size4 > .header > h1 {
|
||||
.font-size4 > body > .header > h1 {
|
||||
font-size: 33px;
|
||||
}
|
||||
|
||||
.font-size5 > .header > h1 {
|
||||
.font-size5 > body > .header > h1 {
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
/* This covers caption, domain, and credits
|
||||
texts in the reader UI */
|
||||
|
||||
.font-size1 > .content .wp-caption-text,
|
||||
.font-size1 > .content figcaption,
|
||||
.font-size1 > .header > .domain,
|
||||
.font-size1 > .header > .credits {
|
||||
.font-size1 > body > .content .wp-caption-text,
|
||||
.font-size1 > body > .content figcaption,
|
||||
.font-size1 > body > .header > .domain,
|
||||
.font-size1 > body > .header > .credits {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.font-size2 > .content .wp-caption-text,
|
||||
.font-size2 > .content figcaption,
|
||||
.font-size2 > .header > .domain,
|
||||
.font-size2 > .header > .credits {
|
||||
.font-size2 > body > .content .wp-caption-text,
|
||||
.font-size2 > body > .content figcaption,
|
||||
.font-size2 > body > .header > .domain,
|
||||
.font-size2 > body > .header > .credits {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.font-size3 > .content .wp-caption-text,
|
||||
.font-size3 > .content figcaption,
|
||||
.font-size3 > .header > .domain,
|
||||
.font-size3 > .header > .credits {
|
||||
.font-size3 > body > .content .wp-caption-text,
|
||||
.font-size3 > body > .content figcaption,
|
||||
.font-size3 > body > .header > .domain,
|
||||
.font-size3 > body > .header > .credits {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.font-size4 > .content .wp-caption-text,
|
||||
.font-size4 > .content figcaption,
|
||||
.font-size4 > .header > .domain,
|
||||
.font-size4 > .header > .credits {
|
||||
.font-size4 > body > .content .wp-caption-text,
|
||||
.font-size4 > body > .content figcaption,
|
||||
.font-size4 > body > .header > .domain,
|
||||
.font-size4 > body > .header > .credits {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.font-size5 > .content .wp-caption-text,
|
||||
.font-size5 > .content figcaption,
|
||||
.font-size5 > .header > .domain,
|
||||
.font-size5 > .header > .credits {
|
||||
.font-size5 > body > .content .wp-caption-text,
|
||||
.font-size5 > body > .content figcaption,
|
||||
.font-size5 > body > .header > .domain,
|
||||
.font-size5 > body > .header > .credits {
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
|
@ -296,27 +296,27 @@ body {
|
|||
}
|
||||
|
||||
.font-size1-sample,
|
||||
.font-size1 > .content {
|
||||
.font-size1 > body > .content {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.font-size2-sample,
|
||||
.font-size2 > .content {
|
||||
.font-size2 > body > .content {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.font-size3-sample,
|
||||
.font-size3 > .content {
|
||||
.font-size3 > body > .content {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
.font-size4-sample,
|
||||
.font-size4 > .content {
|
||||
.font-size4 > body > .content {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
|
||||
.font-size5-sample,
|
||||
.font-size5 > .content {
|
||||
.font-size5 > body > .content {
|
||||
font-size: 22px !important;
|
||||
}
|
||||
|
||||
|
@ -488,6 +488,12 @@ body {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* desktop-only controls */
|
||||
.close-button,
|
||||
.list-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-button.on {
|
||||
background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-mdpi.png');
|
||||
}
|
||||
|
|
|
@ -4538,18 +4538,27 @@ pref("reader.parse-on-load.force-enabled", false);
|
|||
// The default relative font size in reader mode (1-5)
|
||||
pref("reader.font_size", 3);
|
||||
|
||||
// The default color scheme in reader mode (light, dark, print, auto)
|
||||
// The default color scheme in reader mode (light, dark, sepia, auto)
|
||||
// auto = color automatically adjusts according to ambient light level
|
||||
// (auto only works on platforms where the 'devicelight' event is enabled)
|
||||
pref("reader.color_scheme", "light");
|
||||
|
||||
// Color scheme values available in reader mode UI.
|
||||
pref("reader.color_scheme.values", "[\"light\",\"dark\",\"sepia\"]");
|
||||
|
||||
// The font type in reader (sans-serif, serif)
|
||||
pref("reader.font_type", "sans-serif");
|
||||
|
||||
// Font type values available in reader mode UI.
|
||||
pref("reader.font_type.values", "[\"serif\",\"sans-serif\"]");
|
||||
|
||||
// Whether or not the user has interacted with the reader mode toolbar.
|
||||
// This is used to show a first-launch tip in reader mode.
|
||||
pref("reader.has_used_toolbar", false);
|
||||
|
||||
// Whether to use a vertical or horizontal toolbar.
|
||||
pref("reader.toolbar.vertical", true);
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
// Whether to allow, on a Linux system that doesn't support the necessary sandboxing
|
||||
// features, loading Gecko Media Plugins unsandboxed. However, EME CDMs will not be
|
||||
|
|
|
@ -150,6 +150,16 @@ nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel,
|
|||
// the security state. If any channels are subsequently cancelled
|
||||
// (page elements blocked) the state will be then updated.
|
||||
if (*result) {
|
||||
#ifdef DEBUG
|
||||
nsCString topspec;
|
||||
nsCString spec;
|
||||
uri->GetSpec(topspec);
|
||||
aChannel->GetURI(getter_AddRefs(uri));
|
||||
uri->GetSpec(spec);
|
||||
LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on channel[%p] "
|
||||
"with uri %s for toplevel window %s", this, aChannel, spec.get(),
|
||||
topspec.get()));
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -289,14 +299,25 @@ nsChannelClassifier::StartInternal()
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = securityManager->GetChannelResultPrincipal(mChannel,
|
||||
getter_AddRefs(principal));
|
||||
rv = securityManager->GetChannelURIPrincipal(mChannel, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool expectCallback;
|
||||
bool trackingProtectionEnabled = false;
|
||||
(void)ShouldEnableTrackingProtection(mChannel, &trackingProtectionEnabled);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCString uriSpec;
|
||||
uri->GetSpec(uriSpec);
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
principal->GetURI(getter_AddRefs(principalURI));
|
||||
nsCString principalSpec;
|
||||
principalURI->GetSpec(principalSpec);
|
||||
LOG(("nsChannelClassifier: Classifying principal %s on channel with uri %s "
|
||||
"[this=%p]", principalSpec.get(), uriSpec.get(), this));
|
||||
}
|
||||
#endif
|
||||
rv = uriClassifier->Classify(principal, trackingProtectionEnabled, this,
|
||||
&expectCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -4853,14 +4853,20 @@ nsHttpChannel::BeginConnect()
|
|||
nsCOMPtr<nsIPrincipal> principal = GetPrincipal(false);
|
||||
bool tp = false;
|
||||
channelClassifier->ShouldEnableTrackingProtection(this, &tp);
|
||||
// See bug 1122691
|
||||
// We skip speculative connections by setting mLocalBlocklist only
|
||||
// when tracking protection is enabled. Though we could do this for
|
||||
// both phishing and malware, it is not necessary for correctness,
|
||||
// since no network events will be received while the
|
||||
// nsChannelClassifier is in progress. See bug 1122691.
|
||||
if (tp) {
|
||||
nsresult response = NS_OK;
|
||||
classifier->ClassifyLocal(principal, tp, &response);
|
||||
if (NS_FAILED(response)) {
|
||||
LOG(("nsHttpChannel::Found principal on local blocklist "
|
||||
"[this=%p]", this));
|
||||
LOG(("nsHttpChannel::ClassifyLocal found principal on local "
|
||||
"blocklist [this=%p]", this));
|
||||
mLocalBlocklist = true;
|
||||
} else {
|
||||
LOG(("nsHttpChannel::ClassifyLocal no result found [this=%p]", this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4928,25 +4934,29 @@ nsHttpChannel::BeginConnect()
|
|||
}
|
||||
mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
|
||||
}
|
||||
// mLocalBlocklist is true only if the URI is not a tracking domain, it
|
||||
// makes not guarantees about phishing or malware, so we must call
|
||||
if (!(mLoadFlags & LOAD_CLASSIFY_URI)) {
|
||||
return ContinueBeginConnect();
|
||||
}
|
||||
// mLocalBlocklist is true only if tracking protection is enabled and the
|
||||
// URI is a tracking domain, it makes no guarantees about phishing or
|
||||
// malware, so if LOAD_CLASSIFY_URI is true we must call
|
||||
// nsChannelClassifier to catch phishing and malware URIs.
|
||||
bool callContinueBeginConnect = true;
|
||||
if (mCanceled || !mLocalBlocklist) {
|
||||
rv = ContinueBeginConnect();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
callContinueBeginConnect = false;
|
||||
rv = ContinueBeginConnect();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
callContinueBeginConnect = false;
|
||||
}
|
||||
// nsChannelClassifier calls ContinueBeginConnect if it has not already
|
||||
// been called, after optionally cancelling the channel once we have a
|
||||
// remote verdict. We call a concrete class instead of an nsI* that might
|
||||
// be overridden.
|
||||
if (!mCanceled) {
|
||||
LOG(("nsHttpChannel::Starting nsChannelClassifier %p [this=%p]",
|
||||
LOG(("nsHttpChannel::Starting nsChannelClassifier %p [this=%p]",
|
||||
channelClassifier.get(), this));
|
||||
channelClassifier->Start(this, callContinueBeginConnect);
|
||||
channelClassifier->Start(this, callContinueBeginConnect);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -56,34 +56,29 @@ let AboutReader = function(mm, win) {
|
|||
doc.addEventListener("visibilitychange", this, false);
|
||||
|
||||
this._setupStyleDropdown();
|
||||
this._setupButton("close-button", this._onReaderClose.bind(this));
|
||||
this._setupButton("toggle-button", this._onReaderToggle.bind(this));
|
||||
this._setupButton("share-button", this._onShare.bind(this));
|
||||
|
||||
let colorSchemeOptions = [
|
||||
{ name: gStrings.GetStringFromName("aboutReader.colorSchemeDark"),
|
||||
value: "dark"},
|
||||
{ name: gStrings.GetStringFromName("aboutReader.colorSchemeLight"),
|
||||
value: "light"},
|
||||
{ name: gStrings.GetStringFromName("aboutReader.colorSchemeAuto"),
|
||||
value: "auto"}
|
||||
];
|
||||
let colorSchemeValues = JSON.parse(Services.prefs.getCharPref("reader.color_scheme.values"));
|
||||
let colorSchemeOptions = colorSchemeValues.map((value) => {
|
||||
return { name: gStrings.GetStringFromName("aboutReader.colorScheme." + value),
|
||||
value: value,
|
||||
itemClass: value + "-button" };
|
||||
});
|
||||
|
||||
let colorScheme = Services.prefs.getCharPref("reader.color_scheme");
|
||||
this._setupSegmentedButton("color-scheme-buttons", colorSchemeOptions, colorScheme, this._setColorSchemePref.bind(this));
|
||||
this._setColorSchemePref(colorScheme);
|
||||
|
||||
let fontTypeSample = gStrings.GetStringFromName("aboutReader.fontTypeSample");
|
||||
let fontTypeOptions = [
|
||||
{ name: fontTypeSample,
|
||||
description: gStrings.GetStringFromName("aboutReader.fontTypeSerif"),
|
||||
value: "serif",
|
||||
linkClass: "serif" },
|
||||
{ name: fontTypeSample,
|
||||
description: gStrings.GetStringFromName("aboutReader.fontTypeSansSerif"),
|
||||
value: "sans-serif",
|
||||
linkClass: "sans-serif"
|
||||
},
|
||||
];
|
||||
let fontTypeValues = JSON.parse(Services.prefs.getCharPref("reader.font_type.values"));
|
||||
let fontTypeOptions = fontTypeValues.map((value) => {
|
||||
return { name: fontTypeSample,
|
||||
description: gStrings.GetStringFromName("aboutReader.fontType." + value),
|
||||
value: value,
|
||||
linkClass: value };
|
||||
});
|
||||
|
||||
let fontType = Services.prefs.getCharPref("reader.font_type");
|
||||
this._setupSegmentedButton("font-type-buttons", fontTypeOptions, fontType, this._setFontType.bind(this));
|
||||
|
@ -112,13 +107,11 @@ let AboutReader = function(mm, win) {
|
|||
this._setupSegmentedButton("font-size-buttons", fontSizeOptions, fontSize, this._setFontSize.bind(this));
|
||||
this._setFontSize(fontSize);
|
||||
|
||||
let queryArgs = this._decodeQueryString(win.location.href);
|
||||
|
||||
// Track status of reader toolbar add/remove toggle button
|
||||
this._isReadingListItem = -1;
|
||||
this._updateToggleButton();
|
||||
|
||||
this._loadArticle(queryArgs.url);
|
||||
this._loadArticle();
|
||||
}
|
||||
|
||||
AboutReader.prototype = {
|
||||
|
@ -163,6 +156,13 @@ AboutReader.prototype = {
|
|||
return this._messageElementRef.get();
|
||||
},
|
||||
|
||||
get _isToolbarVertical() {
|
||||
if (this._toolbarVertical !== undefined) {
|
||||
return this._toolbarVertical;
|
||||
}
|
||||
return this._toolbarVertical = Services.prefs.getBoolPref("reader.toolbar.vertical");
|
||||
},
|
||||
|
||||
receiveMessage: function (message) {
|
||||
switch (message.name) {
|
||||
case "Reader:Added": {
|
||||
|
@ -253,6 +253,10 @@ AboutReader.prototype = {
|
|||
this._mm.sendAsyncMessage("Reader:ListStatusRequest", { url: this._article.url });
|
||||
},
|
||||
|
||||
_onReaderClose: function Reader_onToggle() {
|
||||
this._win.location.href = this._getOriginalUrl();
|
||||
},
|
||||
|
||||
_onReaderToggle: function Reader_onToggle() {
|
||||
if (!this._article)
|
||||
return;
|
||||
|
@ -278,13 +282,13 @@ AboutReader.prototype = {
|
|||
},
|
||||
|
||||
_setFontSize: function Reader_setFontSize(newFontSize) {
|
||||
let bodyClasses = this._doc.body.classList;
|
||||
let htmlClasses = this._doc.documentElement.classList;
|
||||
|
||||
if (this._fontSize > 0)
|
||||
bodyClasses.remove("font-size" + this._fontSize);
|
||||
htmlClasses.remove("font-size" + this._fontSize);
|
||||
|
||||
this._fontSize = newFontSize;
|
||||
bodyClasses.add("font-size" + this._fontSize);
|
||||
htmlClasses.add("font-size" + this._fontSize);
|
||||
|
||||
Services.prefs.setIntPref("reader.font_size", this._fontSize);
|
||||
},
|
||||
|
@ -438,7 +442,8 @@ AboutReader.prototype = {
|
|||
this._mm.sendAsyncMessage("Reader:SystemUIVisibility", { visible: visible });
|
||||
},
|
||||
|
||||
_loadArticle: Task.async(function* (url) {
|
||||
_loadArticle: Task.async(function* () {
|
||||
let url = this._getOriginalUrl();
|
||||
this._showProgressDelayed();
|
||||
|
||||
let article = yield this._getArticle(url);
|
||||
|
@ -617,18 +622,17 @@ AboutReader.prototype = {
|
|||
}.bind(this), 300);
|
||||
},
|
||||
|
||||
_decodeQueryString: function Reader_decodeQueryString(url) {
|
||||
let result = {};
|
||||
let query = url.split("?")[1];
|
||||
if (query) {
|
||||
let pairs = query.split("&");
|
||||
for (let i = 0; i < pairs.length; i++) {
|
||||
let [name, value] = pairs[i].split("=");
|
||||
result[name] = decodeURIComponent(value);
|
||||
}
|
||||
/**
|
||||
* Returns the original article URL for this about:reader view.
|
||||
*/
|
||||
_getOriginalUrl: function() {
|
||||
let url = this._win.location.href;
|
||||
let searchParams = new URLSearchParams(url.split("?")[1]);
|
||||
if (!searchParams.has("url")) {
|
||||
Cu.reportError("Error finding original URL for about:reader URL: " + url);
|
||||
return url;
|
||||
}
|
||||
|
||||
return result;
|
||||
return decodeURIComponent(searchParams.get("url"));
|
||||
},
|
||||
|
||||
_setupSegmentedButton: function Reader_setupSegmentedButton(id, options, initialValue, callback) {
|
||||
|
@ -643,6 +647,9 @@ AboutReader.prototype = {
|
|||
link.textContent = option.name;
|
||||
item.appendChild(link);
|
||||
|
||||
if (option.itemClass !== undefined)
|
||||
item.classList.add(option.itemClass);
|
||||
|
||||
if (option.linkClass !== undefined)
|
||||
link.classList.add(option.linkClass);
|
||||
|
||||
|
@ -655,7 +662,7 @@ AboutReader.prototype = {
|
|||
link.style.MozUserSelect = 'none';
|
||||
segmentedButton.appendChild(item);
|
||||
|
||||
link.addEventListener("click", function(aEvent) {
|
||||
item.addEventListener("click", function(aEvent) {
|
||||
if (!aEvent.isTrusted)
|
||||
return;
|
||||
|
||||
|
@ -696,24 +703,30 @@ AboutReader.prototype = {
|
|||
let win = this._win;
|
||||
|
||||
let dropdown = doc.getElementById("style-dropdown");
|
||||
|
||||
let dropdownToggle = dropdown.querySelector(".dropdown-toggle");
|
||||
let dropdownPopup = dropdown.querySelector(".dropdown-popup");
|
||||
let dropdownArrow = dropdown.querySelector(".dropdown-arrow");
|
||||
|
||||
let updatePopupPosition = function() {
|
||||
let popupWidth = dropdownPopup.offsetWidth + 30;
|
||||
let arrowWidth = dropdownArrow.offsetWidth;
|
||||
let toggleWidth = dropdownToggle.offsetWidth;
|
||||
let toggleLeft = dropdownToggle.offsetLeft;
|
||||
let updatePopupPosition = () => {
|
||||
if (this._isToolbarVertical) {
|
||||
let toggleHeight = dropdownToggle.offsetHeight;
|
||||
let toggleTop = dropdownToggle.offsetTop;
|
||||
let popupTop = toggleTop - toggleHeight / 2;
|
||||
dropdownPopup.style.top = popupTop + "px";
|
||||
} else {
|
||||
let popupWidth = dropdownPopup.offsetWidth + 30;
|
||||
let arrowWidth = dropdownArrow.offsetWidth;
|
||||
let toggleWidth = dropdownToggle.offsetWidth;
|
||||
let toggleLeft = dropdownToggle.offsetLeft;
|
||||
|
||||
let popupShift = (toggleWidth - popupWidth) / 2;
|
||||
let popupLeft = Math.max(0, Math.min(win.innerWidth - popupWidth, toggleLeft + popupShift));
|
||||
dropdownPopup.style.left = popupLeft + "px";
|
||||
let popupShift = (toggleWidth - popupWidth) / 2;
|
||||
let popupLeft = Math.max(0, Math.min(win.innerWidth - popupWidth, toggleLeft + popupShift));
|
||||
dropdownPopup.style.left = popupLeft + "px";
|
||||
|
||||
let arrowShift = (toggleWidth - arrowWidth) / 2;
|
||||
let arrowLeft = toggleLeft - popupLeft + arrowShift;
|
||||
dropdownArrow.style.left = arrowLeft + "px";
|
||||
let arrowShift = (toggleWidth - arrowWidth) / 2;
|
||||
let arrowLeft = toggleLeft - popupLeft + arrowShift;
|
||||
dropdownArrow.style.left = arrowLeft + "px";
|
||||
}
|
||||
};
|
||||
|
||||
win.addEventListener("resize", event => {
|
||||
|
@ -730,14 +743,12 @@ AboutReader.prototype = {
|
|||
|
||||
event.stopPropagation();
|
||||
|
||||
if (!this._getToolbarVisibility())
|
||||
return;
|
||||
|
||||
if (dropdown.classList.contains("open")) {
|
||||
dropdown.classList.remove("open");
|
||||
} else {
|
||||
dropdown.classList.add("open");
|
||||
updatePopupPosition();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
</div>
|
||||
|
||||
<ul id="reader-toolbar" class="toolbar toolbar-hidden">
|
||||
<li><a id="close-button" class="button close-button" href="#"></a></li>
|
||||
<li><a id="share-button" class="button share-button" href="#"></a></li>
|
||||
<ul id="style-dropdown" class="dropdown">
|
||||
<li><a class="dropdown-toggle button style-button" href="#"></a></li>
|
||||
|
@ -38,6 +39,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
<li><a id="toggle-button" class="button toggle-button" href="#"></a></li>
|
||||
<li><a id="list-button" class="button list-button" href="#"></a></li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -3574,7 +3574,7 @@ SearchService.prototype = {
|
|||
this._defaultEngine = null;
|
||||
|
||||
// Clear the metadata service.
|
||||
engineMetadataService._initState = engineMetadataService._InitStates.NOT_STARTED;
|
||||
engineMetadataService._initialized = false;
|
||||
engineMetadataService._initializer = null;
|
||||
|
||||
Task.spawn(function* () {
|
||||
|
@ -4867,29 +4867,8 @@ SearchService.prototype = {
|
|||
var engineMetadataService = {
|
||||
_jsonFile: OS.Path.join(OS.Constants.Path.profileDir, "search-metadata.json"),
|
||||
|
||||
/**
|
||||
* Possible values for |_initState|.
|
||||
*
|
||||
* We have two paths to perform initialization: a default asynchronous
|
||||
* path and a fallback synchronous path that can interrupt the async
|
||||
* path. For this reason, initialization is actually something of a
|
||||
* finite state machine, represented with the following states:
|
||||
*
|
||||
* @enum
|
||||
*/
|
||||
_InitStates: {
|
||||
NOT_STARTED: "NOT_STARTED"
|
||||
/**Initialization has not started*/,
|
||||
FINISHED_SUCCESS: "FINISHED_SUCCESS"
|
||||
/**Setup complete, with a success*/
|
||||
},
|
||||
|
||||
/**
|
||||
* The latest step completed by initialization. One of |InitStates|
|
||||
*
|
||||
* @type {engineMetadataService._InitStates}
|
||||
*/
|
||||
_initState: null,
|
||||
// Boolean flag that is true if initialization was successful.
|
||||
_initialized: false,
|
||||
|
||||
// A promise fulfilled once initialization is complete
|
||||
_initializer: null,
|
||||
|
@ -4905,34 +4884,32 @@ var engineMetadataService = {
|
|||
let initializer = this._initializer = Promise.defer();
|
||||
Task.spawn((function task_init() {
|
||||
LOG("metadata init: starting");
|
||||
switch (this._initState) {
|
||||
case engineMetadataService._InitStates.NOT_STARTED:
|
||||
// 1. Load json file if it exists
|
||||
try {
|
||||
let contents = yield OS.File.read(this._jsonFile);
|
||||
if (this._initState == engineMetadataService._InitStates.FINISHED_SUCCESS) {
|
||||
// No need to pursue asynchronous initialization,
|
||||
// synchronous fallback was called and has finished.
|
||||
return;
|
||||
}
|
||||
this._store = JSON.parse(new TextDecoder().decode(contents));
|
||||
} catch (ex) {
|
||||
if (this._initState == engineMetadataService._InitStates.FINISHED_SUCCESS) {
|
||||
// No need to pursue asynchronous initialization,
|
||||
// synchronous fallback was called and has finished.
|
||||
return;
|
||||
}
|
||||
// Couldn't load json, use an empty store
|
||||
LOG("metadata init: could not load JSON file " + ex);
|
||||
this._store = {};
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("metadata init: invalid state " + this._initState);
|
||||
if (this._initialized) {
|
||||
throw new Error("metadata init: invalid state, _initialized is " +
|
||||
"true but initialization promise has not been " +
|
||||
"resolved");
|
||||
}
|
||||
// 1. Load json file if it exists
|
||||
try {
|
||||
let contents = yield OS.File.read(this._jsonFile);
|
||||
if (this._initialized) {
|
||||
// No need to pursue asynchronous initialization,
|
||||
// synchronous fallback was called and has finished.
|
||||
return;
|
||||
}
|
||||
this._store = JSON.parse(new TextDecoder().decode(contents));
|
||||
} catch (ex) {
|
||||
if (this._initialized) {
|
||||
// No need to pursue asynchronous initialization,
|
||||
// synchronous fallback was called and has finished.
|
||||
return;
|
||||
}
|
||||
// Couldn't load json, use an empty store
|
||||
LOG("metadata init: could not load JSON file " + ex);
|
||||
this._store = {};
|
||||
}
|
||||
|
||||
this._initState = this._InitStates.FINISHED_SUCCESS;
|
||||
this._initialized = true;
|
||||
LOG("metadata init: complete");
|
||||
}).bind(this)).then(
|
||||
// 3. Inform any observers
|
||||
|
@ -4957,39 +4934,32 @@ var engineMetadataService = {
|
|||
*/
|
||||
syncInit: function epsSyncInit() {
|
||||
LOG("metadata syncInit start");
|
||||
if (this._initState == engineMetadataService._InitStates.FINISHED_SUCCESS) {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
switch (this._initState) {
|
||||
case engineMetadataService._InitStates.NOT_STARTED:
|
||||
let jsonFile = new FileUtils.File(this._jsonFile);
|
||||
// 1. Load json file if it exists
|
||||
if (jsonFile.exists()) {
|
||||
try {
|
||||
let uri = Services.io.newFileURI(jsonFile);
|
||||
let stream = Services.io.newChannelFromURI2(uri,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER).open();
|
||||
this._store = parseJsonFromStream(stream);
|
||||
} catch (x) {
|
||||
LOG("metadata syncInit: could not load JSON file " + x);
|
||||
this._store = {};
|
||||
}
|
||||
} else {
|
||||
LOG("metadata syncInit: using an empty store");
|
||||
this._store = {};
|
||||
}
|
||||
|
||||
this._initState = this._InitStates.FINISHED_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("metadata syncInit: invalid state " + this._initState);
|
||||
let jsonFile = new FileUtils.File(this._jsonFile);
|
||||
// 1. Load json file if it exists
|
||||
if (jsonFile.exists()) {
|
||||
try {
|
||||
let uri = Services.io.newFileURI(jsonFile);
|
||||
let stream = Services.io.newChannelFromURI2(uri,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER).open();
|
||||
this._store = parseJsonFromStream(stream);
|
||||
} catch (x) {
|
||||
LOG("metadata syncInit: could not load JSON file " + x);
|
||||
this._store = {};
|
||||
}
|
||||
} else {
|
||||
LOG("metadata syncInit: using an empty store");
|
||||
this._store = {};
|
||||
}
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
// 3. Inform any observers
|
||||
if (this._initializer) {
|
||||
this._initializer.resolve();
|
||||
|
@ -5123,7 +5093,7 @@ var engineMetadataService = {
|
|||
_lazyWriter: null
|
||||
};
|
||||
|
||||
engineMetadataService._initState = engineMetadataService._InitStates.NOT_STARTED;
|
||||
engineMetadataService._initialized = false;
|
||||
|
||||
const SEARCH_UPDATE_LOG_PREFIX = "*** Search update: ";
|
||||
|
||||
|
|
|
@ -88,6 +88,41 @@ let AnimationPlayerActor = ActorClass({
|
|||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Some of the player's properties are retrieved from the node's
|
||||
* computed-styles because the Web Animations API does not provide them yet.
|
||||
* But the computed-styles may contain multiple animations for a node and so
|
||||
* we need to know which is the index of the current animation in the style.
|
||||
* @return {Number}
|
||||
*/
|
||||
getPlayerIndex: function() {
|
||||
let names = this.styles.animationName;
|
||||
|
||||
// If no names are found, then it's probably a transition, in which case we
|
||||
// can't find the actual index, so just trust the playerIndex passed by
|
||||
// the AnimationsActor at initialization time.
|
||||
// Note that this may be incorrect if by the time the AnimationPlayerActor
|
||||
// is initialized, one of the transitions has ended, but it's the best we
|
||||
// can do for now.
|
||||
if (!names) {
|
||||
return this.playerIndex;
|
||||
}
|
||||
|
||||
// If there's only one name.
|
||||
if (names.contains(",") === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there are several names, retrieve the index of the animation name in
|
||||
// the list.
|
||||
names = names.split(",").map(n => n.trim());
|
||||
for (let i = 0; i < names.length; i ++) {
|
||||
if (names[i] === this.player.source.effect.name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the animation duration from this player, in milliseconds.
|
||||
* Note that the Web Animations API doesn't yet offer a way to retrieve this
|
||||
|
@ -105,8 +140,10 @@ let AnimationPlayerActor = ActorClass({
|
|||
return null;
|
||||
}
|
||||
|
||||
// If the computed duration has multiple entries, we need to find the right
|
||||
// one.
|
||||
if (durationText.indexOf(",") !== -1) {
|
||||
durationText = durationText.split(",")[this.playerIndex];
|
||||
durationText = durationText.split(",")[this.getPlayerIndex()];
|
||||
}
|
||||
|
||||
return parseFloat(durationText) * 1000;
|
||||
|
@ -130,7 +167,7 @@ let AnimationPlayerActor = ActorClass({
|
|||
}
|
||||
|
||||
if (delayText.indexOf(",") !== -1) {
|
||||
delayText = delayText.split(",")[this.playerIndex];
|
||||
delayText = delayText.split(",")[this.getPlayerIndex()];
|
||||
}
|
||||
|
||||
return parseFloat(delayText) * 1000;
|
||||
|
@ -148,7 +185,7 @@ let AnimationPlayerActor = ActorClass({
|
|||
getIterationCount: function() {
|
||||
let iterationText = this.styles.animationIterationCount;
|
||||
if (iterationText.indexOf(",") !== -1) {
|
||||
iterationText = iterationText.split(",")[this.playerIndex];
|
||||
iterationText = iterationText.split(",")[this.getPlayerIndex()];
|
||||
}
|
||||
|
||||
return iterationText === "infinite"
|
||||
|
|
|
@ -172,7 +172,8 @@ let MemoryActor = protocol.ActorClass({
|
|||
options: Arg(0, "nullable:AllocationsRecordingOptions")
|
||||
},
|
||||
response: {
|
||||
value: RetVal(0, "number")
|
||||
// Accept `nullable` in the case of server Gecko <= 37, handled on the front
|
||||
value: RetVal(0, "nullable:number")
|
||||
}
|
||||
}),
|
||||
|
||||
|
@ -187,7 +188,8 @@ let MemoryActor = protocol.ActorClass({
|
|||
}), {
|
||||
request: {},
|
||||
response: {
|
||||
value: RetVal(0, "number")
|
||||
// Accept `nullable` in the case of server Gecko <= 37, handled on the front
|
||||
value: RetVal(0, "nullable:number")
|
||||
}
|
||||
}),
|
||||
|
||||
|
|
|
@ -157,7 +157,10 @@ RootActor.prototype = {
|
|||
noPrettyPrinting: false,
|
||||
// Whether the page style actor implements the getUsedFontFaces method
|
||||
// that returns the font faces used on a node
|
||||
getUsedFontFaces: true
|
||||
getUsedFontFaces: true,
|
||||
// Trait added in Gecko 38, indicating that all features necessary for
|
||||
// grabbing allocations from the MemoryActor are available for the performance tool
|
||||
memoryActorAllocations: true
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,8 @@ const DEFAULT_TIMELINE_DATA_PULL_TIMEOUT = 200; // ms
|
|||
*/
|
||||
protocol.types.addType("array-of-numbers-as-strings", {
|
||||
write: (v) => v.join(","),
|
||||
read: (v) => v.split(",")
|
||||
// In Gecko <= 37, `v` is an array; do not transform in this case.
|
||||
read: (v) => typeof v === "string" ? v.split(",") : v
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
.not-animated {
|
||||
display: inline-block;
|
||||
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.simple-animation {
|
||||
display: inline-block;
|
||||
|
||||
|
@ -83,6 +92,17 @@
|
|||
animation: move .5s 1s 10, glow 1s .75s 30;
|
||||
}
|
||||
|
||||
.multiple-animations-2 {
|
||||
display: inline-block;
|
||||
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: blue;
|
||||
|
||||
animation: move 2s, glow 1s 2s infinite, grow 3s 1s 100;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
100% {
|
||||
transform: translateY(100px);
|
||||
|
@ -94,6 +114,12 @@
|
|||
background: yellow;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes grow {
|
||||
100% {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="not-animated"></div>
|
||||
<div class="simple-animation"></div>
|
||||
|
@ -103,6 +129,7 @@
|
|||
<div class="delayed-animation"></div>
|
||||
<div class="delayed-transition"></div>
|
||||
<div class="delayed-multiple-animations"></div>
|
||||
<div class="multiple-animations-2"></div>
|
||||
<script type="text/javascript">
|
||||
// Get the transitions started when the page loads
|
||||
var players;
|
||||
|
|
|
@ -24,6 +24,7 @@ support-files =
|
|||
[browser_animation_actors_07.js]
|
||||
[browser_animation_actors_08.js]
|
||||
[browser_animation_actors_09.js]
|
||||
[browser_animation_actors_10.js]
|
||||
[browser_navigateEvents.js]
|
||||
[browser_storage_dynamic_windows.js]
|
||||
[browser_storage_listings.js]
|
||||
|
|
|
@ -47,7 +47,7 @@ function* theRightNumberOfPlayersIsReturned(walker, front) {
|
|||
function* playersCanBePausedAndResumed(walker, front) {
|
||||
let node = yield walker.querySelector(walker.rootNode, ".simple-animation");
|
||||
let [player] = yield front.getAnimationPlayersForNode(node);
|
||||
yield player.ready;
|
||||
yield player.ready();
|
||||
|
||||
ok(player.initialState, "The player has an initialState");
|
||||
ok(player.getCurrentState, "The player has the getCurrentState method");
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Check that the right duration/iterationCount/delay are retrieved even when
|
||||
// the node has multiple animations and one of them already ended before getting
|
||||
// the player objects.
|
||||
// See toolkit/devtools/server/actors/animation.js |getPlayerIndex| for more
|
||||
// information.
|
||||
|
||||
const {AnimationsFront} = require("devtools/server/actors/animation");
|
||||
const {InspectorFront} = require("devtools/server/actors/inspector");
|
||||
|
||||
add_task(function*() {
|
||||
let doc = yield addTab(MAIN_DOMAIN + "animation.html");
|
||||
|
||||
initDebuggerServer();
|
||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
let form = yield connectDebuggerClient(client);
|
||||
let inspector = InspectorFront(client, form);
|
||||
let walker = yield inspector.getWalker();
|
||||
let front = AnimationsFront(client, form);
|
||||
|
||||
info("Retrieve a non animated node");
|
||||
let node = yield walker.querySelector(walker.rootNode, ".not-animated");
|
||||
|
||||
info("Apply the multiple-animations-2 class to start the animations");
|
||||
yield node.modifyAttributes([
|
||||
{attributeName: "class", newValue: "multiple-animations-2"}
|
||||
]);
|
||||
|
||||
info("Retrieve the list of animation players for the node");
|
||||
let players = yield front.getAnimationPlayersForNode(node);
|
||||
is(players.length, 3, "3 animations are currently applied to the node");
|
||||
|
||||
info("Waiting for the first animation to end");
|
||||
let player = players[0];
|
||||
player.startAutoRefresh();
|
||||
|
||||
let onFinished = new Promise(resolve => {
|
||||
let onNewState = (e, state) => {
|
||||
if (state.playState === "finished") {
|
||||
info("Received the 'finished' playState event");
|
||||
player.off(player.AUTO_REFRESH_EVENT, onNewState);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
info("Listening for auto-refresh events");
|
||||
player.on(player.AUTO_REFRESH_EVENT, onNewState);
|
||||
});
|
||||
yield onFinished;
|
||||
|
||||
info("Get the list of players again");
|
||||
players = yield front.getAnimationPlayersForNode(node);
|
||||
is(players.length, 2, "2 animations remain on the node");
|
||||
|
||||
is(players[0].state.duration, 1000, "The duration of the first animation is correct");
|
||||
is(players[0].state.delay, 2000, "The delay of the first animation is correct");
|
||||
is(players[0].state.iterationCount, null, "The iterationCount of the first animation is correct");
|
||||
|
||||
is(players[1].state.duration, 3000, "The duration of the second animation is correct");
|
||||
is(players[1].state.delay, 1000, "The delay of the second animation is correct");
|
||||
is(players[1].state.iterationCount, 100, "The iterationCount of the second animation is correct");
|
||||
|
||||
yield closeDebuggerClient(client);
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
|
@ -5,15 +5,20 @@
|
|||
aboutReader.loading=Loading...
|
||||
aboutReader.loadError=Failed to load article from page
|
||||
|
||||
aboutReader.colorSchemeLight=Light
|
||||
aboutReader.colorSchemeDark=Dark
|
||||
aboutReader.colorSchemeSepia=Sepia
|
||||
aboutReader.colorSchemeAuto=Auto
|
||||
aboutReader.colorScheme.light=Light
|
||||
aboutReader.colorScheme.dark=Dark
|
||||
aboutReader.colorScheme.sepia=Sepia
|
||||
aboutReader.colorScheme.auto=Auto
|
||||
|
||||
# LOCALIZATION NOTE (aboutReader.fontTypeSerif, aboutReader.fontTypeSansSerif):
|
||||
# These are the names of the fonts that are used.
|
||||
aboutReader.fontTypeSerif=Charis SIL Compact
|
||||
aboutReader.fontTypeSansSerif=Clear Sans
|
||||
# LOCALIZATION NOTE (aboutReader.fontType.serif, aboutReader.fontType.sans-serif):
|
||||
# These are the styles of typeface that are used on desktop.
|
||||
aboutReader.fontType.serif=Serif
|
||||
aboutReader.fontType.sans-serif=Sans-serif
|
||||
|
||||
# LOCALIZATION NOTE (aboutReader.fontType.charis-sil, aboutReader.fontType.clear-sans):
|
||||
# These are the names of the fonts that are used on Android
|
||||
aboutReader.fontType.charis-sil=Charis SIL Compact
|
||||
aboutReader.fontType.clear-sans=Clear Sans
|
||||
|
||||
# LOCALIZATION NOTE (aboutReader.fontTypeSample): String used to sample font types.
|
||||
aboutReader.fontTypeSample=Aa
|
||||
|
|
|
@ -9,50 +9,6 @@ this.EXPORTED_SYMBOLS = ["PromiseUtils"];
|
|||
Components.utils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
this.PromiseUtils = {
|
||||
/*
|
||||
* A simple timeout mechanism.
|
||||
*
|
||||
* Example:
|
||||
* resolveOrTimeout(myModule.shutdown(), 1000,
|
||||
* () => new Error("The module took too long to shutdown"));
|
||||
*
|
||||
* @param {Promise} promise The Promise that should resolve/reject quickly.
|
||||
* @param {number} delay A delay after which to stop waiting for `promise`, in milliseconds.
|
||||
* @param {function} rejection If `promise` hasn't resolved/rejected after `delay`,
|
||||
* a value used to construct the rejection.
|
||||
*
|
||||
* @return {Promise} A promise that behaves as `promise`, if `promise` is
|
||||
* resolved/rejected within `delay` ms, or rejects with `rejection()` otherwise.
|
||||
*/
|
||||
resolveOrTimeout : function(promise, delay, rejection) {
|
||||
// throw a TypeError if <promise> is not a Promise object
|
||||
if (!(promise instanceof Promise)) {
|
||||
throw new TypeError("first argument <promise> must be a Promise object");
|
||||
}
|
||||
|
||||
// throw a TypeError if <delay> is not a number
|
||||
if (typeof delay != "number" || delay < 0) {
|
||||
throw new TypeError("second argument <delay> must be a positive number");
|
||||
}
|
||||
|
||||
// throws a TypeError if <rejection> is not a function
|
||||
if (rejection && typeof rejection != "function") {
|
||||
throw new TypeError("third optional argument <rejection> must be a function");
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
promise.then(resolve, reject);
|
||||
let id = setTimeout(() => {
|
||||
try {
|
||||
rejection ? reject(rejection()) : reject(new Error("Promise Timeout"));
|
||||
} catch(ex) {
|
||||
reject(ex);
|
||||
}
|
||||
clearTimeout(id);
|
||||
}, delay);
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Creates a new pending Promise and provide methods to resolve and reject this Promise.
|
||||
*
|
||||
|
|
|
@ -11,76 +11,6 @@ function run_test() {
|
|||
run_next_test();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tests for PromiseUtils.resolveOrTimeout()
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Tests for the case when arguments to resolveOrTimeout
|
||||
* are not of correct type */
|
||||
add_task(function* test_wrong_arguments() {
|
||||
let p = new Promise((resolve, reject) => {});
|
||||
// for the first argument
|
||||
Assert.throws(() => PromiseUtils.resolveOrTimeout("string", 200), /first argument <promise> must be a Promise object/,
|
||||
"TypeError thrown because first argument is not a Promsie object");
|
||||
// for second argument
|
||||
Assert.throws(() => PromiseUtils.resolveOrTimeout(p, "string"), /second argument <delay> must be a positive number/,
|
||||
"TypeError thrown because second argument is not a positive number");
|
||||
// for the third argument
|
||||
Assert.throws(() => PromiseUtils.resolveOrTimeout(p, 200, "string"), /third optional argument <rejection> must be a function/,
|
||||
"TypeError thrown because thrird argument is not a function");
|
||||
});
|
||||
|
||||
/* Tests for the case when the optional third argument is not provided
|
||||
* In that case the returned promise rejects with a default Error */
|
||||
add_task(function* test_optional_third_argument() {
|
||||
let p = new Promise((resolve, reject) => {});
|
||||
yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200), /Promise Timeout/, "Promise rejects with a default Error");
|
||||
});
|
||||
|
||||
/* Test for the case when the passed promise resolves quickly
|
||||
* In that case the returned promise also resolves with the same value */
|
||||
add_task(function* test_resolve_quickly() {
|
||||
let p = new Promise((resolve, reject) => setTimeout(() => resolve("Promise is resolved"), 20));
|
||||
let result = yield PromiseUtils.resolveOrTimeout(p, 200);
|
||||
Assert.equal(result, "Promise is resolved", "Promise resolves quickly");
|
||||
});
|
||||
|
||||
/* Test for the case when the passed promise rejects quickly
|
||||
* In that case the returned promise also rejects with the same value */
|
||||
add_task(function* test_reject_quickly() {
|
||||
let p = new Promise((resolve, reject) => setTimeout(() => reject("Promise is rejected"), 20));
|
||||
yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200), /Promise is rejected/, "Promise rejects quickly");
|
||||
});
|
||||
|
||||
/* Tests for the case when the passed promise doesn't settle
|
||||
* and rejection returns string/object/undefined */
|
||||
add_task(function* test_rejection_function() {
|
||||
let p = new Promise((resolve, reject) => {});
|
||||
// for rejection returning string
|
||||
yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200, () => {
|
||||
return "Rejection returned a string";
|
||||
}), /Rejection returned a string/, "Rejection returned a string");
|
||||
|
||||
// for rejection returning object
|
||||
yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200, () => {
|
||||
return {Name:"Promise"};
|
||||
}), Object, "Rejection returned an object");
|
||||
|
||||
// for rejection returning undefined
|
||||
yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200, () => {
|
||||
return;
|
||||
}), undefined, "Rejection returned undefined");
|
||||
});
|
||||
|
||||
/* Tests for the case when the passed promise doesn't settles
|
||||
* and rejection throws an error */
|
||||
add_task(function* test_rejection_throw_error() {
|
||||
let p = new Promise((resolve, reject) => {});
|
||||
yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200, () => {
|
||||
throw new Error("Rejection threw an Error");
|
||||
}), /Rejection threw an Error/, "Rejection threw an error");
|
||||
});
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tests for PromiseUtils.defer()
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -5,8 +5,5 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
skip-if = toolkit == 'android'
|
||||
|
||||
[consumerNotifications.js]
|
||||
# Bug 676992: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
|
|
|
@ -196,6 +196,13 @@ toolkit.jar:
|
|||
skin/classic/global/in-content/radio.svg (../../shared/in-content/radio.svg)
|
||||
skin/classic/global/in-content/sorter.png (../../shared/in-content/sorter.png)
|
||||
skin/classic/global/in-content/sorter@2x.png (../../shared/in-content/sorter@2x.png)
|
||||
skin/classic/global/reader/RM-Add-24x24.svg (../../shared/reader/RM-Add-24x24.svg)
|
||||
skin/classic/global/reader/RM-Close-24x24.svg (../../shared/reader/RM-Close-24x24.svg)
|
||||
skin/classic/global/reader/RM-Close-hover-24x24.svg (../../shared/reader/RM-Close-hover-24x24.svg)
|
||||
skin/classic/global/reader/RM-Delete-24x24.svg (../../shared/reader/RM-Delete-24x24.svg)
|
||||
skin/classic/global/reader/RM-Reading-List-24x24.svg (../../shared/reader/RM-Reading-List-24x24.svg)
|
||||
skin/classic/global/reader/RM-Type-Controls-24x24.svg (../../shared/reader/RM-Type-Controls-24x24.svg)
|
||||
skin/classic/global/reader/RM-Type-Controls-Arrow.svg (../../shared/reader/RM-Type-Controls-Arrow.svg)
|
||||
skin/classic/global/scale/scale-tray-horiz.gif (scale/scale-tray-horiz.gif)
|
||||
skin/classic/global/scale/scale-tray-vert.gif (scale/scale-tray-vert.gif)
|
||||
skin/classic/global/splitter/dimple.png (splitter/dimple.png)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#808080" d="M12,2C6.477,2,2,6.477,2,12c0,5.523,4.477,10,10,10s10-4.477,10-10
|
||||
C22,6.477,17.523,2,12,2z M17.714,12.714h-5v5h-1.429v-5h-5v-1.429h5v-5h1.429v5h5V12.714z"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 481 B |
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<g>
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#808080" points="20,6.748 17.338,4.079 12.038,9.391 6.661,4 4,6.669
|
||||
9.377,12.059 4.157,17.292 6.819,19.961 12.039,14.728 17.298,20 19.959,17.331 14.701,12.06 "/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 499 B |
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<g>
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" points="20,6.748 17.338,4.079 12.038,9.391 6.661,4 4,6.669
|
||||
9.377,12.059 4.157,17.292 6.819,19.961 12.039,14.728 17.298,20 19.959,17.331 14.701,12.06 "/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 498 B |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#808080" d="M12,2C6.477,2,2,6.477,2,12c0,5.523,4.477,10,10,10s10-4.477,10-10
|
||||
C22,6.477,17.523,2,12,2z M11.286,6.286 M6.286,12.714v-1.429h11.429v1.429H6.286z"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 473 B |
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<g>
|
||||
<rect x="8" y="10" fill-rule="evenodd" clip-rule="evenodd" fill="#808080" width="14" height="4"/>
|
||||
<rect x="8" y="16" fill-rule="evenodd" clip-rule="evenodd" fill="#808080" width="14" height="4"/>
|
||||
<rect x="8" y="4" fill-rule="evenodd" clip-rule="evenodd" fill="#808080" width="14" height="4"/>
|
||||
<circle fill-rule="evenodd" clip-rule="evenodd" fill="#808080" cx="4" cy="6" r="2"/>
|
||||
<circle fill-rule="evenodd" clip-rule="evenodd" fill="#808080" cx="4" cy="12" r="2"/>
|
||||
<circle fill-rule="evenodd" clip-rule="evenodd" fill="#808080" cx="4" cy="18" r="2"/>
|
||||
</g>
|
||||
<g enable-background="new ">
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_2_" x="-197" y="-1054" width="22" height="34"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_1_">
|
||||
<use xlink:href="#SVGID_2_" overflow="visible"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#SVGID_1_)">
|
||||
<defs>
|
||||
<rect id="SVGID_6_" x="-293" y="-1459" width="1080" height="2896"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_3_">
|
||||
<use xlink:href="#SVGID_6_" overflow="visible"/>
|
||||
</clipPath>
|
||||
</g>
|
||||
<g clip-path="url(#SVGID_1_)">
|
||||
<defs>
|
||||
<rect id="SVGID_10_" x="-293" y="-1459" width="1080" height="2896"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_5_">
|
||||
<use xlink:href="#SVGID_10_" overflow="visible"/>
|
||||
</clipPath>
|
||||
</g>
|
||||
<g clip-path="url(#SVGID_1_)">
|
||||
<defs>
|
||||
<rect id="SVGID_16_" x="-293" y="-1459" width="1080" height="2896"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_7_">
|
||||
<use xlink:href="#SVGID_16_" overflow="visible"/>
|
||||
</clipPath>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 2.0 KiB |
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#808080" d="M8.23,18.748v-1.016l1.182-0.146c0.065-0.013,0.12-0.055,0.166-0.127s0.052-0.143,0.02-0.215L8.513,14.07
|
||||
H4.236l-1.104,3.096c-0.039,0.104-0.02,0.199,0.059,0.283s0.153,0.13,0.225,0.137l1.123,0.146v1.016H0.232v-1.016l1.123-0.166
|
||||
L5.837,5.008h2.275l4.443,12.197c0.052,0.124,0.103,0.21,0.151,0.259s0.145,0.089,0.288,0.122l0.762,0.146v1.016H8.23z
|
||||
M6.296,8.084l-1.68,4.805h3.398L6.296,8.084z"/>
|
||||
<path fill="#808080" d="M20.05,18.748l-0.264-0.996c-0.345,0.234-0.706,0.443-1.083,0.625c-0.331,0.156-0.702,0.298-1.112,0.425
|
||||
c-0.409,0.127-0.835,0.19-1.277,0.19c-0.364,0-0.704-0.06-1.02-0.181s-0.592-0.293-0.829-0.518s-0.424-0.497-0.561-0.815
|
||||
S13.7,16.801,13.7,16.404c0-0.299,0.024-0.576,0.073-0.83s0.146-0.49,0.293-0.708s0.356-0.426,0.63-0.625s0.637-0.392,1.089-0.581
|
||||
s1.008-0.377,1.665-0.566s1.445-0.384,2.363-0.586v-0.244c0-0.098,0.003-0.186,0.01-0.264c0-0.091,0.003-0.182,0.01-0.273
|
||||
c0.007-0.189-0.013-0.392-0.059-0.61s-0.137-0.42-0.273-0.605s-0.329-0.338-0.576-0.459s-0.569-0.181-0.967-0.181
|
||||
c-0.137,0-0.259,0.003-0.366,0.01s-0.197,0.016-0.269,0.029c-0.085,0.013-0.159,0.026-0.225,0.039v1.895h-2.061
|
||||
c-0.169,0.013-0.319-0.003-0.449-0.049c-0.11-0.039-0.213-0.107-0.308-0.205s-0.142-0.25-0.142-0.459
|
||||
c0-0.371,0.132-0.703,0.396-0.996c0.263-0.293,0.607-0.542,1.033-0.747s0.904-0.363,1.435-0.474
|
||||
c0.529-0.111,1.058-0.166,1.585-0.166c0.572,0,1.096,0.042,1.57,0.127s0.883,0.249,1.224,0.493c0.342,0.244,0.604,0.587,0.79,1.03
|
||||
s0.278,1.025,0.278,1.748v5.137c0,0.124,0.042,0.229,0.127,0.317s0.188,0.138,0.312,0.151l0.879,0.059v0.938H20.05z M19.793,13.592
|
||||
c-0.645,0.13-1.177,0.264-1.597,0.4s-0.754,0.293-1.001,0.469s-0.42,0.376-0.518,0.601s-0.146,0.487-0.146,0.786
|
||||
c0,0.208,0.034,0.402,0.103,0.581s0.166,0.335,0.293,0.469s0.278,0.239,0.454,0.317s0.368,0.117,0.576,0.117
|
||||
c0.215,0,0.432-0.023,0.649-0.068s0.415-0.094,0.591-0.146c0.208-0.065,0.407-0.14,0.596-0.225V13.592z"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 2.2 KiB |
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<polygon opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" points="16.583,0.015 16.569,0 4.583,12 16.569,24 16.583,23.985
|
||||
"/>
|
||||
<g enable-background="new ">
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_2_" x="-125" y="-1086.667" width="22" height="34"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_1_">
|
||||
<use xlink:href="#SVGID_2_" overflow="visible"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#SVGID_1_)">
|
||||
<defs>
|
||||
<rect id="SVGID_6_" x="-221" y="-1491.667" width="1080" height="2896"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_3_">
|
||||
<use xlink:href="#SVGID_6_" overflow="visible"/>
|
||||
</clipPath>
|
||||
</g>
|
||||
<g clip-path="url(#SVGID_1_)">
|
||||
<defs>
|
||||
<rect id="SVGID_10_" x="-221" y="-1491.667" width="1080" height="2896"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_5_">
|
||||
<use xlink:href="#SVGID_10_" overflow="visible"/>
|
||||
</clipPath>
|
||||
</g>
|
||||
<g clip-path="url(#SVGID_1_)">
|
||||
<defs>
|
||||
<rect id="SVGID_16_" x="-221" y="-1491.667" width="1080" height="2896"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_7_">
|
||||
<use xlink:href="#SVGID_16_" overflow="visible"/>
|
||||
</clipPath>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#FBFBFB" points="16.575,1.021 16.561,1.008 5.583,12 16.577,23.008
|
||||
16.591,22.994 "/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.7 KiB |
|
@ -9,19 +9,22 @@ body {
|
|||
margin-right: auto;
|
||||
}
|
||||
|
||||
.light {
|
||||
.light,
|
||||
.light-button {
|
||||
color: #333333;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.dark {
|
||||
.dark,
|
||||
.dark-button {
|
||||
color: #eeeeee;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.print {
|
||||
.sepia,
|
||||
.sepia-button {
|
||||
color: #333333;
|
||||
background-color: #fff1df;
|
||||
background-color: #f0ece7;
|
||||
}
|
||||
|
||||
.sans-serif {
|
||||
|
@ -32,6 +35,32 @@ body {
|
|||
font-family: serif;
|
||||
}
|
||||
|
||||
.font-size1,
|
||||
.font-size1-sample {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.font-size2,
|
||||
.font-size2-sample {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.font-size3,
|
||||
.font-size3-sample {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.font-size4,
|
||||
.font-size4-sample {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.font-size5,
|
||||
.font-size5-sample {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* Loading/error message */
|
||||
|
||||
.message {
|
||||
|
@ -39,7 +68,7 @@ body {
|
|||
display: none;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
@ -50,8 +79,8 @@ body {
|
|||
}
|
||||
|
||||
.domain {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.33rem;
|
||||
padding-bottom: 4px;
|
||||
font-family: sans-serif;
|
||||
text-decoration: none;
|
||||
|
@ -60,7 +89,7 @@ body {
|
|||
}
|
||||
|
||||
.light > .header > .domain,
|
||||
.print > .header > .domain {
|
||||
.sepia > .header > .domain {
|
||||
border-bottom-color: #333333;
|
||||
}
|
||||
|
||||
|
@ -69,16 +98,16 @@ body {
|
|||
}
|
||||
|
||||
.header > h1 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-size: 1.33rem;
|
||||
line-height: 1.66rem;
|
||||
width: 100%;
|
||||
margin: 30px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header > .credits {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.33rem;
|
||||
margin: 0 0 30px 0;
|
||||
padding: 0;
|
||||
font-style: italic;
|
||||
|
@ -88,8 +117,8 @@ body {
|
|||
|
||||
.content {
|
||||
display: none;
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.44rem;
|
||||
}
|
||||
|
||||
.content h1,
|
||||
|
@ -99,18 +128,18 @@ body {
|
|||
}
|
||||
|
||||
.content h1 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-size: 1.33rem;
|
||||
line-height: 1.66rem;
|
||||
}
|
||||
|
||||
.content h2 {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.66rem;
|
||||
}
|
||||
|
||||
.content h3 {
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.66rem;
|
||||
}
|
||||
|
||||
.content a {
|
||||
|
@ -149,8 +178,8 @@ body {
|
|||
.content .caption,
|
||||
.content .wp-caption-text,
|
||||
.content figcaption {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.33rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
@ -165,7 +194,7 @@ body {
|
|||
}
|
||||
|
||||
.light > .content blockquote,
|
||||
.print > .content blockquote {
|
||||
.sepia > .content blockquote {
|
||||
-moz-border-start: 2px solid #333333;
|
||||
}
|
||||
|
||||
|
@ -191,5 +220,184 @@ body {
|
|||
/* Toolbar */
|
||||
|
||||
.toolbar {
|
||||
font-family: sans-serif;
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
background-color: #FBFBFB;
|
||||
-moz-user-select: none;
|
||||
border-right: 1px solid #B5B5B5;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: white;
|
||||
display: block;
|
||||
background-position: center;
|
||||
background-size: 24px 24px;
|
||||
background-repeat: no-repeat;
|
||||
padding: 4px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-bottom: 1px solid #c1c1c1;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
text-align: center;
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.dropdown li {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.dropdown-popup {
|
||||
text-align: start;
|
||||
position: absolute;
|
||||
left: 48px; /* offset to account for toolbar width */
|
||||
z-index: 1000;
|
||||
background-color: #FBFBFB;
|
||||
font-size: 14px;
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #B5B5B5;
|
||||
box-shadow: 0px 1px 12px #666;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.dropdown-popup > hr {
|
||||
width: 100%;
|
||||
height: 0px;
|
||||
border: 0px;
|
||||
border-top: 1px solid #B5B5B5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.open > .dropdown-popup {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
position: absolute;
|
||||
top: 30px; /* offset arrow from top of popup */
|
||||
left: -16px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-image: url("chrome://global/skin/reader/RM-Type-Controls-Arrow.svg");
|
||||
display: block;
|
||||
}
|
||||
|
||||
#font-type-buttons,
|
||||
.segmented-button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
list-style: none;
|
||||
white-space: nowrap;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#font-type-buttons > li,
|
||||
.segmented-button > li {
|
||||
flex: 1 0 auto;
|
||||
text-align: center;
|
||||
border-left: 1px solid #B5B5B5;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#font-type-buttons > li {
|
||||
width: 50px; /* combined with flex, this acts as a minimum width */
|
||||
}
|
||||
|
||||
.segmented-button > li {
|
||||
width: 30px; /* combined with flex, this acts as a minimum width */
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#font-type-buttons > li:first-child,
|
||||
.segmented-button > li:first-child {
|
||||
border-left: 0px;
|
||||
}
|
||||
|
||||
#font-type-buttons > li > a,
|
||||
.segmented-button > li > a {
|
||||
vertical-align: middle;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#font-type-buttons > li > a {
|
||||
display: inline-block;
|
||||
font-size: 48px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.segmented-button > li > a {
|
||||
display: block;
|
||||
font-family: sans-serif;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
#font-type-buttons > li:active:hover,
|
||||
#font-type-buttons > li.selected {
|
||||
border-bottom: 3px solid #FC6420;
|
||||
}
|
||||
|
||||
.button:hover,
|
||||
#font-size-buttons > li:hover {
|
||||
background-color: #EBEBEB;
|
||||
}
|
||||
|
||||
.dropdown.open,
|
||||
.button:active,
|
||||
#font-size-buttons > li:active,
|
||||
#font-size-buttons > li.selected {
|
||||
background-color: #DADADA;
|
||||
}
|
||||
|
||||
#font-type-buttons > li > .sans-serif {
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
#font-type-buttons > li > div {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Android-only controls */
|
||||
.share-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background-image: url("chrome://global/skin/reader/RM-Close-24x24.svg");
|
||||
height: 60px;
|
||||
background-position: center 8px;
|
||||
}
|
||||
|
||||
.close-button:active,
|
||||
.close-button:hover {
|
||||
background-image: url("chrome://global/skin/reader/RM-Close-hover-24x24.svg");
|
||||
background-color: #d94141;
|
||||
}
|
||||
|
||||
.style-button {
|
||||
background-image: url("chrome://global/skin/reader/RM-Type-Controls-24x24.svg");
|
||||
}
|
||||
|
||||
.toggle-button.on {
|
||||
background-image: url("chrome://global/skin/reader/RM-Delete-24x24.svg");
|
||||
}
|
||||
|
||||
.toggle-button {
|
||||
background-image: url("chrome://global/skin/reader/RM-Add-24x24.svg");
|
||||
}
|
||||
|
||||
.list-button {
|
||||
background-image: url("chrome://global/skin/reader/RM-Reading-List-24x24.svg");
|
||||
}
|
||||
|
|
|
@ -187,6 +187,14 @@ toolkit.jar:
|
|||
skin/classic/global/printpreview/arrow-right-end.png (printpreview/arrow-right-end.png)
|
||||
skin/classic/global/radio/radio-check.gif (radio/radio-check.gif)
|
||||
skin/classic/global/radio/radio-check-dis.gif (radio/radio-check-dis.gif)
|
||||
skin/classic/global/reader/RM-Add-24x24.svg (../../shared/reader/RM-Add-24x24.svg)
|
||||
skin/classic/global/reader/RM-Close-24x24.svg (../../shared/reader/RM-Close-24x24.svg)
|
||||
skin/classic/global/reader/RM-Close-hover-24x24.svg (../../shared/reader/RM-Close-hover-24x24.svg)
|
||||
skin/classic/global/reader/RM-Delete-24x24.svg (../../shared/reader/RM-Delete-24x24.svg)
|
||||
skin/classic/global/reader/RM-Reading-List-24x24.svg (../../shared/reader/RM-Reading-List-24x24.svg)
|
||||
skin/classic/global/reader/RM-Type-Controls-24x24.svg (../../shared/reader/RM-Type-Controls-24x24.svg)
|
||||
skin/classic/global/reader/RM-Type-Controls-Arrow.svg (../../shared/reader/RM-Type-Controls-Arrow.svg)
|
||||
|
||||
skin/classic/global/scrollbar/slider.gif (scrollbar/slider.gif)
|
||||
skin/classic/global/splitter/grip-bottom.gif (splitter/grip-bottom.gif)
|
||||
skin/classic/global/splitter/grip-top.gif (splitter/grip-top.gif)
|
||||
|
@ -383,6 +391,13 @@ toolkit.jar:
|
|||
skin/classic/aero/global/printpreview/arrow-right-end.png (printpreview/arrow-right-end-aero.png)
|
||||
skin/classic/aero/global/radio/radio-check.gif (radio/radio-check.gif)
|
||||
skin/classic/aero/global/radio/radio-check-dis.gif (radio/radio-check-dis.gif)
|
||||
skin/classic/aero/global/reader/RM-Add-24x24.svg (../../shared/reader/RM-Add-24x24.svg)
|
||||
skin/classic/aero/global/reader/RM-Close-24x24.svg (../../shared/reader/RM-Close-24x24.svg)
|
||||
skin/classic/aero/global/reader/RM-Close-hover-24x24.svg (../../shared/reader/RM-Close-hover-24x24.svg)
|
||||
skin/classic/aero/global/reader/RM-Delete-24x24.svg (../../shared/reader/RM-Delete-24x24.svg)
|
||||
skin/classic/aero/global/reader/RM-Reading-List-24x24.svg (../../shared/reader/RM-Reading-List-24x24.svg)
|
||||
skin/classic/aero/global/reader/RM-Type-Controls-24x24.svg (../../shared/reader/RM-Type-Controls-24x24.svg)
|
||||
skin/classic/aero/global/reader/RM-Type-Controls-Arrow.svg (../../shared/reader/RM-Type-Controls-Arrow.svg)
|
||||
skin/classic/aero/global/scrollbar/slider.gif (scrollbar/slider.gif)
|
||||
skin/classic/aero/global/splitter/grip-bottom.gif (splitter/grip-bottom.gif)
|
||||
skin/classic/aero/global/splitter/grip-top.gif (splitter/grip-top.gif)
|
||||
|
|