Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-10-06 10:48:24 +08:00
commit 879ab0d7dc
72 changed files with 81921 additions and 71421 deletions

View file

@ -866,11 +866,7 @@ pref("browser.zoom.siteSpecific", true);
pref("browser.zoom.updateBackgroundTabs", true);
// The breakpad report server to link to in about:crashes
pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
// URL for "Learn More" for Crash Reporter
pref("toolkit.crashreporter.infoURL",
"https://www.mozilla.org/legal/privacy/firefox.html#crash-reporter");
pref("breakpad.reportURL", "");
// base URL for web-based support pages
pref("app.support.baseURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/");
@ -1045,12 +1041,6 @@ pref("browser.newtabpage.rows", 3);
// number of columns of newtab grid
pref("browser.newtabpage.columns", 5);
// directory tiles download URL
pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
// endpoint to send newtab click and view pings
pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3/links/");
// activates the remote-hosted newtab page
pref("browser.newtabpage.remote", false);
@ -1146,11 +1136,6 @@ pref("browser.uiCustomization.debug", false);
// CustomizableUI state of the browser's user interface
pref("browser.uiCustomization.state", "");
// URLs for promo links to mobile browsers. Note that consumers are expected to
// append a value for utm_campaign.
pref("identity.mobilepromo.android", "https://www.mozilla.org/firefox/android/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=");
pref("identity.mobilepromo.ios", "https://www.mozilla.org/firefox/ios/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=");
// On GTK, we now default to showing the menubar only when alt is pressed:
#ifdef MOZ_WIDGET_GTK
pref("ui.key.menuAccessKeyFocuses", true);
@ -1241,13 +1226,6 @@ pref("browser.tabs.remote.autostart.1", false);
pref("browser.tabs.remote.autostart.2", true);
#endif
// For the about:tabcrashed page
pref("browser.tabs.crashReporting.sendReport", true);
pref("browser.tabs.crashReporting.includeURL", false);
pref("browser.tabs.crashReporting.requestEmail", false);
pref("browser.tabs.crashReporting.emailMe", false);
pref("browser.tabs.crashReporting.email", "");
// Enable e10s add-on interposition by default.
pref("extensions.interposition.enabled", true);
pref("extensions.interposition.prefetching", true);
@ -1340,25 +1318,7 @@ pref("print.use_simplify_page", true);
// Space separated list of URLS that are allowed to send objects (instead of
// only strings) through webchannels. This list is duplicated in mobile/android/app/mobile.js
pref("webchannel.allowObject.urlWhitelist", "https://accounts.firefox.com https://content.cdn.mozilla.net https://input.mozilla.org https://support.mozilla.org https://install.mozilla.org");
// Whether or not the browser should scan for unsubmitted
// crash reports, and then show a notification for submitting
// those reports.
pref("browser.crashReports.unsubmittedCheck.enabled", false);
// chancesUntilSuppress is how many times we'll show the unsubmitted
// crash report notification across different days and shutdown
// without a user choice before we suppress the notification for
// some number of days.
pref("browser.crashReports.unsubmittedCheck.chancesUntilSuppress", 4);
pref("browser.crashReports.unsubmittedCheck.autoSubmit2", false);
#ifdef NIGHTLY_BUILD
// Enable the (fairly costly) client/server validation on nightly only. The other prefs
// controlling validation are located in /services/sync/services-sync.js
pref("services.sync.validation.enabled", true);
#endif
pref("webchannel.allowObject.urlWhitelist", "");
// When a user cancels this number of authentication dialogs coming from
// a single web page (eTLD+1) in a row, all following authentication dialogs

View file

@ -6,7 +6,6 @@
// Services = object with smart getters for common XPCOM services
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AppConstants.jsm");
function init(aEvent)
{
@ -69,23 +68,29 @@ function init(aEvent)
let arch = bundle.GetStringFromName(archResource);
versionField.textContent += ` (${arch})`;
#ifdef MOZ_WIDGET_GTK
// If Linux append the toolkit "(GTK2)" or "(GTK3)"
let toolkit = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime).widgetToolkit.toUpperCase();
versionField.textContent += ` (${toolkit})`;
#endif
// Get Release Notes URL from Preferences
let releaseNotesURL = Services.prefs.getCharPref("app.releaseNotesURL");
document.getElementById("releasenotes").setAttribute("href", releaseNotesURL);
if (AppConstants.MOZ_UPDATER) {
gAppUpdater = new appUpdater();
#ifdef MOZ_UPDATER
gAppUpdater = new appUpdater();
let channelLabel = document.getElementById("currentChannel");
let currentChannelText = document.getElementById("currentChannelText");
channelLabel.value = UpdateUtils.UpdateChannel;
if (/^release($|\-)/.test(channelLabel.value))
currentChannelText.hidden = true;
}
let channelLabel = document.getElementById("currentChannel");
let currentChannelText = document.getElementById("currentChannelText");
channelLabel.value = UpdateUtils.UpdateChannel;
if (/^release($|\-)/.test(channelLabel.value))
currentChannelText.hidden = true;
#endif
if (AppConstants.platform == "macosx") {
// it may not be sized at this point, and we need its width to calculate its position
window.sizeToContent();
window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
}
#ifdef XP_MACOSX
// it may not be sized at this point, and we need its width to calculate its position
window.sizeToContent();
window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
#endif
}

View file

@ -13,7 +13,6 @@ var gPluginHandler = {
"PluginContent:HideNotificationBar",
"PluginContent:InstallSinglePlugin",
"PluginContent:ShowPluginCrashedNotification",
"PluginContent:SubmitReport",
"PluginContent:LinkClickCallback",
],
@ -62,9 +61,6 @@ var gPluginHandler = {
this.showPluginCrashedNotification(msg.target, msg.data.messageString,
msg.data.pluginID);
break;
case "PluginContent:SubmitReport":
// Nothing to do here
break;
case "PluginContent:LinkClickCallback":
switch (msg.data.name) {
case "managePlugins":
@ -95,11 +91,6 @@ var gPluginHandler = {
openUILinkIn(url, "tab");
},
submitReport: function(runID, keyVals, submitURLOptIn) {
/*** STUB ***/
return;
},
// Callback for user clicking a "reload page" link
reloadPage: function (browser) {
browser.reload();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -1,23 +0,0 @@
.. _healthreport_preferences:
===========
Preferences
===========
The following preferences are used by SSL Error reporting:
"security.ssl.errorReporting.enabled"
Should the SSL Error Reporting UI be shown on pin violations? Default
value: ``true``
"security.ssl.errorReporting.url"
Where should SSL error reports be sent? Default value:
``https://incoming.telemetry.mozilla.org/submit/sslreports/``
"security.ssl.errorReporting.automatic"
Should error reports be sent without user interaction. Default value:
``false``. Note: this pref is overridden by the value of
``security.ssl.errorReporting.enabled``
This is only set when specifically requested by the user. The user can set
this value (or unset it) by checking the "Automatically report errors in the
future" checkbox when about:neterror is displayed for SSL Errors.

View file

@ -4123,7 +4123,7 @@
},
/*
* Telemetry and Profiler related helpers for recording tab switch
* Profiler related helpers for recording tab switch
* timing.
*/

View file

@ -16,7 +16,7 @@ browser.jar:
content/browser/aboutDialog-appUpdater.js (content/aboutDialog-appUpdater.js)
* content/browser/aboutDialog.xul (content/aboutDialog.xul)
content/browser/aboutDialog.js (content/aboutDialog.js)
* content/browser/aboutDialog.js (content/aboutDialog.js)
content/browser/aboutDialog.css (content/aboutDialog.css)
* content/browser/abouthome/aboutHome.xhtml (content/abouthome/aboutHome.xhtml)
content/browser/abouthome/aboutHome.js (content/abouthome/aboutHome.js)
@ -108,8 +108,6 @@ browser.jar:
content/browser/defaultthemes/5.header.png (content/defaultthemes/5.header.png)
content/browser/defaultthemes/5.icon.jpg (content/defaultthemes/5.icon.jpg)
content/browser/defaultthemes/5.preview.jpg (content/defaultthemes/5.preview.jpg)
content/browser/defaultthemes/devedition.header.png (content/defaultthemes/devedition.header.png)
content/browser/defaultthemes/devedition.icon.png (content/defaultthemes/devedition.icon.png)
content/browser/gcli_sec_bad.svg (content/gcli_sec_bad.svg)
content/browser/gcli_sec_good.svg (content/gcli_sec_good.svg)
content/browser/gcli_sec_moderate.svg (content/gcli_sec_moderate.svg)

View file

@ -3,6 +3,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/.
DEFINES['MOZ_APP_NAME'] = CONFIG['MOZ_APP_NAME']
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']

View file

@ -8,13 +8,10 @@ DIRS += [
]
EXTRA_JS_MODULES += [
'CustomizableUI.jsm',
'CustomizableWidgets.jsm',
'CustomizeMode.jsm',
'DragPositionManager.jsm',
'PanelWideWidgetTracker.jsm',
'ScrollbarSampler.jsm',
]
EXTRA_PP_JS_MODULES += [
'CustomizableUI.jsm',
]

View file

@ -208,30 +208,6 @@ var gAdvancedPane = {
// DATA CHOICES TAB
/**
* Set up or hide the Learn More links for various data collection options
*/
_setupLearnMoreLink: function (pref, element) {
// set up the Learn More link with the correct URL
let url = Services.prefs.getCharPref(pref);
let el = document.getElementById(element);
if (url) {
el.setAttribute("href", url);
} else {
el.setAttribute("hidden", "true");
}
},
/**
*
*/
initSubmitCrashes: function ()
{
this._setupLearnMoreLink("toolkit.crashreporter.infoURL",
"crashReporterLearnMore");
},
/**
* Initialize the health report service reference and checkbox.
*/

View file

@ -8,7 +8,7 @@ browser.jar:
content/browser/preferences/in-content/subdialogs.js
content/browser/preferences/in-content/main.js
* content/browser/preferences/in-content/privacy.js
content/browser/preferences/in-content/privacy.js
content/browser/preferences/in-content/containers.js
content/browser/preferences/in-content/advanced.js
content/browser/preferences/in-content/applications.js
@ -16,5 +16,5 @@ browser.jar:
#ifdef MOZ_SERVICES_SYNC
content/browser/preferences/in-content/sync.js
#endif
* content/browser/preferences/in-content/security.js
content/browser/preferences/in-content/security.js
content/browser/preferences/in-content/search.js

View file

@ -84,11 +84,6 @@ var gMainPane = {
.notifyObservers(window, "main-pane-loaded", null);
},
enableE10SChange: function ()
{
// **STUB**
},
// HOME PAGE
/*

View file

@ -4,5 +4,5 @@
browser.jar:
content/browser/aboutPrivateBrowsing.css (content/aboutPrivateBrowsing.css)
* content/browser/aboutPrivateBrowsing.xhtml (content/aboutPrivateBrowsing.xhtml)
* content/browser/aboutPrivateBrowsing.js (content/aboutPrivateBrowsing.js)
content/browser/aboutPrivateBrowsing.xhtml (content/aboutPrivateBrowsing.xhtml)
content/browser/aboutPrivateBrowsing.js (content/aboutPrivateBrowsing.js)

View file

@ -1832,7 +1832,6 @@
return false;
]]></body>
</method>
</implementation>
<handlers>

View file

@ -8,12 +8,12 @@ DIST_SUBDIR = ''
DEFINES['HAVE_SIDEBAR'] = True
EXTRA_COMPONENTS += [
'nsSearchService.js',
'nsSearchSuggestions.js',
'nsSidebar.js',
]
EXTRA_PP_COMPONENTS += [
'nsSearchService.js',
'toolkitsearch.manifest',
]

View file

@ -908,7 +908,6 @@ var SessionStoreInternal = {
this._crashedBrowsers.delete(browser.permanentKey);
break;
case "SessionStore:error":
this.reportInternalError(data);
TabStateFlusher.resolveAll(browser, false, "Received error from the content process");
break;
default:
@ -4439,13 +4438,6 @@ var SessionStoreInternal = {
this._browserEpochs.delete(browser.permanentKey);
},
/**
* Handle an error report from a content process.
*/
reportInternalError(data) {
// STUB, was only reported through Telemetry.
},
/**
* Countdown for a given duration, skipping beats if the computer is too busy,
* sleeping or otherwise unavailable.

View file

@ -8,8 +8,6 @@ var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
var gStateObject;
var gTreeData;
@ -195,9 +193,11 @@ function onListClick(aEvent) {
if (cell.col) {
// Restore this specific tab in the same window for middle/double/accel clicking
// on a tab's title.
let accelKey = AppConstants.platform == "macosx" ?
aEvent.metaKey :
aEvent.ctrlKey;
#ifdef XP_MACOSX
let accelKey = aEvent.metaKey;
#else
let accelKey = aEvent.ctrlKey;
#endif
if ((aEvent.button == 1 || aEvent.button == 0 && aEvent.detail == 2 || accelKey) &&
cell.col.id == "title" &&
!treeView.isContainer(cell.row)) {

View file

@ -4,5 +4,5 @@
browser.jar:
* content/browser/aboutSessionRestore.xhtml (content/aboutSessionRestore.xhtml)
content/browser/aboutSessionRestore.js (content/aboutSessionRestore.js)
* content/browser/aboutSessionRestore.js (content/aboutSessionRestore.js)
content/browser/content-sessionStore.js (content/content-sessionStore.js)

View file

@ -1,28 +0,0 @@
.. _browserusagetelemetry:
=======================
Browser Usage Telemetry
=======================
The `BrowserUsageTelemetry.jsm <https://dxr.mozilla.org/mozilla-central/source/browser/modules/BrowserUsageTelemetry.jsm>`_ module is the main module for measurements regarding the browser usage (e.g. tab and window counts, search counts, ...).
The measurements recording begins right after the ``SessionStore`` has finished restoring the session (i.e. restoring tabs/windows after Firefox starts).
Search telemetry
================
This module exposes the ``recordSearch`` method, which serves as the main entry point for recording search related Telemetry. It records only the search *counts* per engine and the origin of the search, but nothing pertaining the search contents themselves.
As the transition to the ``BrowserUsageTelemetry`` happens, the ``recordSearch`` calls are dispatched through `BrowserSearch.recordSearchInTelemetry <https://dxr.mozilla.org/mozilla-central/rev/3e73fd638e687a4d7f46613586e5156b8e2af846/browser/base/content/browser.js#3752>`_, that is called by all the search related UI components (urlbar, searchbar, context menu and about\:\* pages).
A list of the components recording search Telemetry can be found using the following `DXR search <https://dxr.mozilla.org/mozilla-central/search?q=recordSearchInTelemetry>`_.
Measured interactions
=====================
The usage telemetry module currently measures these interactions with the browser:
- *tab and window engagement*: counts the number of non-private tabs and windows opened in a subsession, after the session is restored (see e.g. ``browser.engagement.max_concurrent_tab_count``);
- *URI loads*: counts the number of page loads (doesn't track and send the addresses, just the counts) directly triggered by the users (see ``browser.engagement.total_uri_count``);
- *navigation events*: at this time, this only counts the number of time a page load is triggered by a particular UI interaction (e.g. by searching through the URL bar, see ``browser.engagement.navigation.urlbar``).
Please see `Scalars.yaml <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ for the full list of tracked interactions.

View file

@ -1,278 +0,0 @@
=============================================
Directory Links Architecture and Data Formats
=============================================
Directory links are enhancements to the new tab experience that combine content
Firefox already knows about from user browsing with external content. There are
3 kinds of links:
- directory links fill in additional tiles on the new tab page if there would
have been empty tiles because the user has a clean profile or cleared history
- suggested links are shown if certain triggering criteria matches the user's
browsing behavior, i.e., if the user has a top site that matches one of
several possible sites. E.g., only show a sports suggestion if the user has a
sport site as a top site
- enhanced links replace a matching user's visible history tile from the same
site but only the visual aspects: title, image, and rollover image
To power the above features, DirectoryLinksProvider module downloads, at most
once per 24 hours, the directory source links as JSON with enough data for
Firefox to determine what should be shown or not. This module also handles
reporting back data about the tiles via asynchronous pings that don't return
data from the server.
For the directory source and ping endpoints, the default preference values point
to Mozilla key-pinned servers with encryption. No cookies are set by the servers
and Firefox enforces this by making anonymous requests.
- default directory source endpoint:
https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%
- default directory ping endpoint: https://tiles.services.mozilla.com/v3/links/
Preferences
===========
There are two main preferences that control downloading links and reporting
metrics.
``browser.newtabpage.directory.source``
---------------------------------------
This endpoint tells Firefox where to download directory source file as a GET
request. It should return JSON of the appropriate format containing the relevant
links data. The value can be a data URI, e.g., an empty JSON object effectively
turns off remote downloading: ``data:text/plain,{}``
The preference value will have %LOCALE% and %CHANNEL% replaced by the
appropriate values for the build of Firefox, e.g.,
- directory source endpoint:
https://tiles.services.mozilla.com/v3/links/fetch/en-US/release
``browser.newtabpage.directory.ping``
-------------------------------------
This endpoint tells Firefox where to report Tiles metrics as a POST request. The
data is sent as a JSON blob. Setting it to empty effectively turns off reporting
of Tiles data.
A path segment will be appended to the endpoint of "view" or "click" depending
on the type of ping, e.g.,
- ``view`` ping endpoint: https://tiles.services.mozilla.com/v3/links/view
- ``click`` ping endpoint: https://tiles.services.mozilla.com/v3/links/click
Data Flow
=========
When Firefox starts, it checks for a cached directory source file. If one
exists, it checks for its timestamp to determine if a new file should be
downloaded.
If a directory source file needs to be downloaded, a GET request is made then
cacheed and unpacked the JSON into the different types of links. Various checks
filter out invalid links, e.g., those with http-hosted images or those that
don't fit the allowed suggestions.
When a new tab page is built, DirectoryLinksProvider module provides additional
link data that is combined with history link data to determine which links can
be displayed or not.
When a new tab page is shown, a ``view`` ping is sent with relevant tiles data.
Similarly, when the user clicks on various parts of tiles (to load the page,
pin, block, etc.), a ``click`` ping is sent with similar data. Both of these can
trigger downloading of fresh directory source links if 24 hours have elapsed
since last download.
Users can turn off the ping with in-new-tab-page controls.
As the new tab page is rendered, any images for tiles are downloaded if not
already cached. The default servers hosting the images are Mozilla CDN that
don't use cookies: https://tiles.cdn.mozilla.net/ and Firefox enforces that the
images come from mozilla.net or data URIs when using the default directory
source.
Source JSON Format
==================
Firefox expects links data in a JSON object with top level keys each providing
an array of tile objects. The keys correspond to the different types of links:
``directory``, ``suggested``, and ``enhanced``.
Example
-------
Below is an example directory source file::
{
"directory": [
{
"bgColor": "",
"directoryId": 498,
"enhancedImageURI": "https://tiles.cdn.mozilla.net/images/d11ba0b3095bb19d8092cd29be9cbb9e197671ea.28088.png",
"imageURI": "https://tiles.cdn.mozilla.net/images/1332a68badf11e3f7f69bf7364e79c0a7e2753bc.5316.png",
"title": "Mozilla Community",
"type": "affiliate",
"url": "http://contribute.mozilla.org/"
}
],
"enhanced": [
{
"bgColor": "",
"directoryId": 776,
"enhancedImageURI": "https://tiles.cdn.mozilla.net/images/44a14fc405cebc299ead86514dff0e3735c8cf65.10814.png",
"imageURI": "https://tiles.cdn.mozilla.net/images/20e24aa2219ec7542cc8cf0fd79f0c81e16ebeac.11859.png",
"title": "TurboTax",
"type": "sponsored",
"url": "https://turbotax.intuit.com/"
}
],
"suggested": [
{
"adgroup_name": "open-source browser",
"bgColor": "#cae1f4",
"check_inadjacency": true,
"directoryId": 702,
"explanation": "Suggested for %1$S enthusiasts who visit sites like %2$S",
"frecent_sites": [
"addons.mozilla.org",
"air.mozilla.org",
"blog.mozilla.org",
"bugzilla.mozilla.org",
"developer.mozilla.org",
"etherpad.mozilla.org",
"hacks.mozilla.org",
"hg.mozilla.org",
"mozilla.org",
"planet.mozilla.org",
"quality.mozilla.org",
"support.mozilla.org",
"treeherder.mozilla.org",
"wiki.mozilla.org"
],
"frequency_caps": {"daily": 3, "total": 10},
"imageURI": "https://tiles.cdn.mozilla.net/images/9ee2b265678f2775de2e4bf680df600b502e6038.3875.png",
"time_limits": {"start": "2014-01-01T00:00:00.000Z", "end": "2014-02-01T00:00:00.000Z"},
"title": "Thanks for testing!",
"type": "affiliate",
"url": "https://www.mozilla.com/firefox/tiles"
}
]
}
Link Object
-----------
Each link object has various values that Firefox uses to display a tile:
- ``url`` - string url for the page to be loaded when the tile is clicked. Only
https and http URLs are allowed.
- ``title`` - string that appears below the tile.
- ``type`` - string relationship of the link to Mozilla. Expected values:
affiliate, organic, sponsored.
- ``imageURI`` - string url for the tile image to show. Only https and data URIs
are allowed.
- ``enhancedImageURI`` - string url for the image to be shown before the user
hovers. Only https and data URIs are allowed.
- ``bgColor`` - string css color for additional fill background color.
- ``directoryId`` - id of the tile to be used during ping reporting
Suggested Link Object Extras
----------------------------
A suggested link has additional values:
- ``adgroup_name`` - string to override the hardcoded display name of the
triggering set of sites in Firefox.
- ``check_inadjacency`` - boolean if true prevents the suggested link from being
shown if the new tab page is showing a site from an inadjacency list.
- ``explanation`` - string to override the default explanation that appears
below a Suggested Tile. %1$S is replaced by the triggering adgroup name and
%2$S is replaced by the triggering site.
- ``frecent_sites`` - array of strings of the sites that can trigger showing a
Suggested Tile if the user has the site in one of the top 100 most-frecent
pages.
- ``frequency_caps`` - an object consisting of daily and total frequency caps
that limit the number of times a Suggested Tile can be shown in the new tab
per day and overall.
- ``time_limits`` - an object consisting of start and end timestamps specifying
when a Suggested Tile may start and has to stop showing in the newtab.
The timestamp is expected in ISO_8601 format: '2014-01-10T20:00:00.000Z'
The inadjacency list is packaged with Firefox as base64-encoded 1-way-hashed
sites that tend to have adult, gambling, alcohol, drug, and similar content.
Its location: chrome://browser/content/newtab/newTab.inadjacent.json
The preapproved arrays follow a policy for determining what topic grouping is
allowed as well as the composition of a grouping. The topics are broad
uncontroversial categories, e.g., Mobile Phone, News, Technology, Video Game,
Web Development. There are at least 5 sites within a grouping, and as many
popular sites relevant to the topic are included to avoid having one site be
clearly dominant. These requirements provide some deniability of which site
actually triggered a suggestion during ping reporting, so it's more difficult to
determine if a user has gone to a specific site.
Ping JSON Format
================
Firefox reports back an action and the state of tiles on the new tab page based
on the user opening a new tab or clicking a tile. The top level keys of the
ping:
- ``locale`` - string locale of the Firefox build
- ``tiles`` - array of tiles ping objects
An additional key at the top level indicates which action triggered the ping.
The value associated to the action key is the 0-based index into the tiles array
of which tile triggered the action. Valid actions: block, click, pin, sponsored,
sponsored_link, unpin, view. E.g., if the second tile is being clicked, the ping
will have ``"click": 1``
Example
-------
Below is an example ``click`` ping with 3 tiles: a pinned suggested tile
followed by a history tile and a directory tile. The first tile is being
blocked::
{
"locale": "en-US",
"tiles": [
{
"id": 702,
"pin": 1,
"past_impressions": {"total": 5, "daily": 1},
},
{},
{
"id": 498,
}
],
"block": 0
}
Tiles Ping Object
-----------------
Each tile of the new tab page is reported back as part of the ping with some or
none of the following optional values:
- ``id`` - id that was provided as part of the downloaded link object (for all
types of links: directory, suggested, enhanced); not present if the tile was
created from user behavior, e.g., visiting pages
- ``past_impressions`` - number of impressions (new tab "views") a suggested
tile was shown before it was clicked, pinned or blocked. Where the "total"
counter is the overall number of impressions accumulated prior to a click action,
and "daily" counter is the number impressions occurred on same calendar day of
a click. This infomration is submitted once per a suggested tile upon click,
pin or block
- ``pinned`` - 1 if the tile is pinned; not present otherwise
- ``pos`` - integer position if the tile is not in the natural order, e.g., a
pinned tile after an empty slot; not present otherwise
- ``score`` - integer truncated score based on the tile's frecency; not present
if 0
- ``url`` - empty string if it's an enhanced tile; not present otherwise

View file

@ -1,142 +0,0 @@
.. _uitelemetry:
=======================
UITelemetry data format
=======================
UI Telemetry sends its data as a JSON blob. This document describes the different parts
of the JSON blob.
``toolbars``
============
This tracks the state of the user's UI customizations. It has the following properties:
- ``sizemode`` - string indicating whether the window is in maximized, normal (restored) or
fullscreen mode;
- ``bookmarksBarEnabled`` - boolean indicating whether the bookmarks bar is visible;
- ``menuBarEnabled`` - boolean indicating whether the menu bar is visible (always false on OS X);
- ``titleBarEnabled`` - boolean indicating whether the (real) titlebar is visible (rather than
having tabs in the titlebar);
- ``defaultKept`` - list of strings identifying toolbar buttons and items that are still in their
default position. Only the IDs of builtin widgets are sent (ie not add-on widgets);
- ``defaultMoved`` - list of strings identifying toolbar buttons and items that are no longer in
their default position, but have not been removed to the palette. Only the IDs of builtin widgets
are sent (ie not add-on widgets);
- ``nondefaultAdded`` - list of strings identifying toolbar buttons and items that have been added
from the palette. Only the IDs of builtin widgets are sent (ie not add-on widgets);
- ``defaultRemoved`` - list of strings identifying toolbar buttons and items that are in the
palette that are elsewhere by default. Only the IDs of builtin widgets are sent
(ie not add-on widgets);
- ``addonToolbars`` - the number of non-default toolbars that are customizable. 1 by default
because it counts the add-on bar shim;
- ``visibleTabs`` - array of the number of visible tabs per window;
- ``hiddenTabs`` - array of the number of hidden tabs per window (ie tabs in panorama groups which
are not the current group);
- ``countableEvents`` - please refer to the next section.
- ``durations`` - an object mapping descriptions to duration records, which records the amount of
time a user spent doing something. Currently only has one property:
- ``customization`` - how long a user spent customizing the browser. This is an array of
objects, where each object has a ``duration`` property indicating the time in milliseconds,
and a ``bucket`` property indicating a bucket in which the duration info falls.
.. _UITelemetry_countableEvents:
``countableEvents``
===================
Countable events are stored under the ``toolbars`` section. They count the number of times certain
events happen. No timing or other correlating information is stored - purely the number of times
things happen.
``countableEvents`` contains a list of buckets as its properties. A bucket represents the state the browser was in when these events occurred, such as currently running an interactive tour. There are 3 types of buckets:
- ``__DEFAULT__`` - No bucket, for times when the browser is not in any special state.
- ``bucket_<NAME>`` - Normal buckets, for when the browser is in a special state. The ``<NAME>`` in the bucket ID is the name associated with the bucket and may be further broken down into parts by the ``|`` character.
- ``bucket_<NAME>|<INTERVAL>`` - Expiring buckets, which are similar to a countdown timer. The ``<INTERVAL>`` in the bucket ID describes the time interval the recorded event happened in. The intervals are ``1m`` (one minute), ``3m`` (three minutes), ``10m`` (ten minutes), and ``1h`` (one hour). After one hour, the ``__DEFAULT__`` bucket is automatically used again.
Each bucket is an object with the following properties:
- ``click-builtin-item`` is an object tracking clicks on builtin customizable toolbar items, keyed
off the item IDs, with an object for each item with keys ``left``, ``middle`` and ``right`` each
storing a number indicating how often the respective type of click has happened.
- ``click-menu-button`` is the same, except the item ID is always 'button'.
- ``click-bookmarks-bar`` is the same, with the item IDs being replaced by either ``container`` for
clicks on bookmark or livemark folders, and ``item`` for individual bookmarks.
- ``click-menubar`` is similar, with the item IDs being replaced by one of ``menu``, ``menuitem``
or ``other``, depending on the kind of item clicked. Note that this is not tracked on OS X, where
we can't listen for these events because of the global menubar.
- ``click-bookmarks-menu-button`` is also similar, with the item IDs being replaced by:
- ``menu`` for clicks on the 'menu' part of the item;
- ``add`` for clicks that add a bookmark;
- ``edit`` for clicks that open the panel to edit an existing bookmark;
- ``in-panel`` for clicks when the button is in the menu panel, and clicking it does none of the
above;
- ``customize`` tracks different types of customization events without the ``left``, ``middle`` and
``right`` distinctions. The different events are the following, with each storing a count of the
number of times they occurred:
- ``start`` counts the number of times the user starts customizing;
- ``add`` counts the number of times an item is added somewhere from the palette;
- ``move`` counts the number of times an item is moved somewhere else (but not to the palette);
- ``remove`` counts the number of times an item is removed to the palette;
- ``reset`` counts the number of times the 'restore defaults' button is used;
- ``search`` is an object tracking searches of various types, keyed off the search
location, storing a number indicating how often the respective type of search
has happened.
- There are also two special keys that mean slightly different things.
- ``urlbar-keyword`` records searches that would have been an invalid-protocol
error, but are now keyword searches. They are also counted in the ``urlbar``
keyword (along with all the other urlbar searches).
- ``selection`` searches records selections of search suggestions. They include
the source, the index of the selection, and the kind of selection (mouse or
enter key). Selection searches are also counted in their sources.
``UITour``
==========
The UITour API provides ways for pages on trusted domains to safely interact with the browser UI and request it to perform actions such as opening menus and showing highlights over the browser chrome - for the purposes of interactive tours. We track some usage of this API via the ``UITour`` object in the UI Telemetry output.
Each page is able to register itself with an identifier, a ``Page ID``. A list of Page IDs that have been seen over the last 8 weeks is available via ``seenPageIDs``.
Page IDs are also used to identify buckets for :ref:`UITelemetry_countableEvents`, in the following circumstances:
- The current tab is a tour page. This will be a normal bucket with the name ``UITour|<PAGEID>``, where ``<PAGEID>`` is the page's registered ID. This will result in bucket IDs such as ``bucket_UITour|australis-tour``.
- A tour tab is open but another tab is active. This will be an expiring bucket with the name ``UITour|<PAGEID>|inactive``. This will result in bucket IDs such as ``bucket_UITour|australis-tour|inactive|1m``.
- A tour tab has recently been open but has been closed. This will be an expiring bucket with the name ``UITour|<PAGEID>|closed``. This will result in bucket IDs such as ``bucket_UITour|australis-tour|closed|10m``.
``contextmenu``
===============
We track context menu interactions to figure out which ones are most often used and/or how
effective they are. In the ``contextmenu`` object, we first store things per-bucket. Next, we
divide the following different context menu situations:
- ``selection`` if there is content on the page that's selected on which the user clicks;
- ``link`` if the user opened the context menu for a link
- ``image-link`` if the user opened the context menu on an image or canvas that's a link;
- ``image`` if the user opened the context menu on an image (that isn't a link);
- ``canvas`` if the user opened the context menu on a canvas (that isn't a link);
- ``media`` if the user opened the context menu on an HTML video or audio element;
- ``input`` if the user opened the context menu on a text input element;
- ``other`` for all other openings of the content menu;
Each of these objects (if they exist) then gets a "withcustom" and/or a "withoutcustom" property
for context menus opened with custom page-created items and without them, and each of those
properties holds an object with IDs corresponding to a count of how often an item with that ID was
activated in the context menu. Only builtin context menu items are tracked, and besides those items
there are four special items which get counts:
- ``close-without-interaction`` is incremented when the user closes the context menu without interacting with it;
- ``custom-page-item`` is incremented when the user clicks an item that was created by the page;
- ``unknown`` is incremented when an item without an ID was clicked;
- ``other-item`` is incremented when an add-on-provided menuitem is clicked.

View file

@ -1,12 +0,0 @@
=======
Firefox
=======
This is the nascent documentation of the Firefox front-end code.
.. toctree::
:maxdepth: 1
DirectoryLinksProvider
UITelemetry
BrowserUsageTelemetry

View file

@ -0,0 +1,7 @@
This is a port of IsaacSchemm's PDF.JS for SeaMonkey addon, https://github.com/IsaacSchemm/pdf.js-seamonkey
Current extension version is: 2.3.235
Taken from https://github.com/IsaacSchemm/pdf.js-seamonkey/releases/tag/v2.3.235
PdfJs.jsm ported from Firefox 60.9.0's version of PDF.js

View file

@ -1,3 +0,0 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.6.315

View file

@ -12,87 +12,109 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, PdfjsChromeUtils,
PdfjsContentUtils, PdfStreamConverter */
'use strict';
"use strict";
var EXPORTED_SYMBOLS = ['PdfJs'];
var EXPORTED_SYMBOLS = ["PdfJs"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cm = Components.manager;
const Cu = Components.utils;
const PREF_PREFIX = 'pdfjs';
const PREF_DISABLED = PREF_PREFIX + '.disabled';
const PREF_MIGRATION_VERSION = PREF_PREFIX + '.migrationVersion';
const PREF_PREVIOUS_ACTION = PREF_PREFIX + '.previousHandler.preferredAction';
const PREF_PREFIX = "pdfjs";
const PREF_DISABLED = PREF_PREFIX + ".disabled";
const PREF_MIGRATION_VERSION = PREF_PREFIX + ".migrationVersion";
const PREF_PREVIOUS_ACTION = PREF_PREFIX + ".previousHandler.preferredAction";
const PREF_PREVIOUS_ASK = PREF_PREFIX +
'.previousHandler.alwaysAskBeforeHandling';
const PREF_DISABLED_PLUGIN_TYPES = 'plugin.disable_full_page_plugin_for_types';
const TOPIC_PDFJS_HANDLER_CHANGED = 'pdfjs:handlerChanged';
const TOPIC_PLUGINS_LIST_UPDATED = 'plugins-list-updated';
const TOPIC_PLUGIN_INFO_UPDATED = 'plugin-info-updated';
const PDF_CONTENT_TYPE = 'application/pdf';
".previousHandler.alwaysAskBeforeHandling";
const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
const PREF_ENABLED_CACHE_STATE = PREF_PREFIX + ".enabledCache.state";
const PREF_ENABLED_CACHE_INITIALIZED = PREF_PREFIX +
".enabledCache.initialized";
const PREF_APP_UPDATE_POSTUPDATE = "app.update.postupdate";
const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
const TOPIC_PLUGINS_LIST_UPDATED = "plugins-list-updated";
const TOPIC_PLUGIN_INFO_UPDATED = "plugin-info-updated";
const PDF_CONTENT_TYPE = "application/pdf";
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1',
'nsIMIMEService');
XPCOMUtils.defineLazyServiceGetter(Svc, 'pluginHost',
'@mozilla.org/plugin/host;1',
'nsIPluginHost');
XPCOMUtils.defineLazyModuleGetter(this, 'PdfjsChromeUtils',
'resource://pdf.js/PdfjsChromeUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'PdfjsContentUtils',
'resource://pdf.js/PdfjsContentUtils.jsm');
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
XPCOMUtils.defineLazyServiceGetter(Svc, "pluginHost",
"@mozilla.org/plugin/host;1",
"nsIPluginHost");
XPCOMUtils.defineLazyModuleGetter(this, "PdfjsChromeUtils",
"resource://pdf.js/PdfjsChromeUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PdfjsContentUtils",
"resource://pdf.js/PdfjsContentUtils.jsm");
function getBoolPref(aPref, aDefaultValue) {
try {
return Services.prefs.getBoolPref(aPref);
} catch (ex) {
return aDefaultValue;
}
}
function getIntPref(aPref, aDefaultValue) {
try {
return Services.prefs.getIntPref(aPref);
} catch (ex) {
return aDefaultValue;
}
}
function isDefaultHandler() {
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
return PdfjsContentUtils.isDefaultHandlerApp();
}
return PdfjsChromeUtils.isDefaultHandlerApp();
if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
throw new Error("isDefaultHandler should only get called in the parent " +
"process.");
}
return PdfjsChromeUtils.isDefaultHandlerApp();
}
function initializeDefaultPreferences() {
/* eslint-disable semi */
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"enableHandToolOnLoad": false,
"cursorToolOnLoad": 0,
"enableWebGL": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"disableAutoFetch": false,
"disableFontFace": false,
"disableTextLayer": false,
"textLayerMode": 1,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"enhanceTextSelection": false,
"renderer": "canvas",
"renderInteractiveForms": false,
"enablePrintAutoRotate": false,
"disablePageMode": false,
"disablePageLabels": false
}
/* eslint-enable semi */
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
var defaultValue;
for (var key in DEFAULT_PREFERENCES) {
defaultValue = DEFAULT_PREFERENCES[key];
switch (typeof defaultValue) {
case 'boolean':
case "boolean":
defaultBranch.setBoolPref(key, defaultValue);
break;
case 'number':
case "number":
defaultBranch.setIntPref(key, defaultValue);
break;
case 'string':
case "string":
defaultBranch.setCharPref(key, defaultValue);
break;
}
@ -127,7 +149,7 @@ Factory.prototype = {
registrar.unregisterFactory(this._classID2, this._factory);
}
this._factory = null;
}
},
};
var PdfJs = {
@ -138,8 +160,8 @@ var PdfJs = {
init: function init(remote) {
if (Services.appinfo.processType !==
Services.appinfo.PROCESS_TYPE_DEFAULT) {
throw new Error('PdfJs.init should only get called ' +
'in the parent process.');
throw new Error("PdfJs.init should only get called " +
"in the parent process.");
}
PdfjsChromeUtils.init();
if (!remote) {
@ -155,7 +177,7 @@ var PdfJs = {
}
this._initialized = true;
if (!Services.prefs.getBoolPref(PREF_DISABLED, true)) {
if (!getBoolPref(PREF_DISABLED, true)) {
this._migrate();
}
@ -171,28 +193,28 @@ var PdfJs = {
},
updateRegistration: function updateRegistration() {
if (this.enabled) {
this._ensureRegistered();
if (this.checkEnabled()) {
this.ensureRegistered();
} else {
this._ensureUnregistered();
this.ensureUnregistered();
}
},
uninit: function uninit() {
if (this._initialized) {
Services.prefs.removeObserver(PREF_DISABLED, this, false);
Services.prefs.removeObserver(PREF_DISABLED_PLUGIN_TYPES, this, false);
Services.obs.removeObserver(this, TOPIC_PDFJS_HANDLER_CHANGED, false);
Services.obs.removeObserver(this, TOPIC_PLUGINS_LIST_UPDATED, false);
Services.obs.removeObserver(this, TOPIC_PLUGIN_INFO_UPDATED, false);
Services.prefs.removeObserver(PREF_DISABLED, this);
Services.prefs.removeObserver(PREF_DISABLED_PLUGIN_TYPES, this);
Services.obs.removeObserver(this, TOPIC_PDFJS_HANDLER_CHANGED);
Services.obs.removeObserver(this, TOPIC_PLUGINS_LIST_UPDATED);
Services.obs.removeObserver(this, TOPIC_PLUGIN_INFO_UPDATED);
this._initialized = false;
}
this._ensureUnregistered();
this.ensureUnregistered();
},
_migrate: function migrate() {
const VERSION = 2;
var currentVersion = Services.prefs.getIntPref(PREF_MIGRATION_VERSION, 0);
var currentVersion = getIntPref(PREF_MIGRATION_VERSION, 0);
if (currentVersion >= VERSION) {
return;
}
@ -202,13 +224,13 @@ var PdfJs = {
}
if (currentVersion < 2) {
// cleaning up of unused database preference (see #3994)
Services.prefs.clearUserPref(PREF_PREFIX + '.database');
Services.prefs.clearUserPref(PREF_PREFIX + ".database");
}
Services.prefs.setIntPref(PREF_MIGRATION_VERSION, VERSION);
},
_becomeHandler: function _becomeHandler() {
let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, 'pdf');
let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
let prefs = Services.prefs;
if (handlerInfo.preferredAction !== Ci.nsIHandlerInfo.handleInternally &&
handlerInfo.preferredAction !== false) {
@ -219,7 +241,7 @@ var PdfJs = {
prefs.setBoolPref(PREF_PREVIOUS_ASK, handlerInfo.alwaysAskBeforeHandling);
}
let handlerService = Cc['@mozilla.org/uriloader/handler-service;1'].
let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].
getService(Ci.nsIHandlerService);
// Change and save mime handler settings.
@ -228,46 +250,30 @@ var PdfJs = {
handlerService.store(handlerInfo);
// Also disable any plugins for pdfs.
var stringTypes = '';
var stringTypes = "";
var types = [];
if (prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
stringTypes = prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES);
}
if (stringTypes !== '') {
types = stringTypes.split(',');
if (stringTypes !== "") {
types = stringTypes.split(",");
}
if (types.indexOf(PDF_CONTENT_TYPE) === -1) {
if (!types.includes(PDF_CONTENT_TYPE)) {
types.push(PDF_CONTENT_TYPE);
}
prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(','));
prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(","));
// Update the category manager in case the plugins are already loaded.
let categoryManager = Cc['@mozilla.org/categorymanager;1'];
let categoryManager = Cc["@mozilla.org/categorymanager;1"];
categoryManager.getService(Ci.nsICategoryManager).
deleteCategoryEntry('Gecko-Content-Viewers',
deleteCategoryEntry("Gecko-Content-Viewers",
PDF_CONTENT_TYPE,
false);
},
// nsIObserver
observe: function observe(aSubject, aTopic, aData) {
this.updateRegistration();
if (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_DEFAULT) {
let jsm = 'resource://pdf.js/PdfjsChromeUtils.jsm';
let PdfjsChromeUtils = Components.utils.import(jsm, {}).PdfjsChromeUtils;
PdfjsChromeUtils.notifyChildOfSettingsChange();
}
},
/**
* pdf.js is only enabled if it is both selected as the pdf viewer and if the
* global switch enabling it is true.
* @return {boolean} Whether or not it's enabled.
*/
get enabled() {
var disabled = Services.prefs.getBoolPref(PREF_DISABLED, true);
_isEnabled: function _isEnabled() {
var disabled = getBoolPref(PREF_DISABLED, true);
if (disabled) {
return false;
}
@ -280,8 +286,8 @@ var PdfJs = {
// Check if we have disabled plugin handling of 'application/pdf' in prefs
if (Services.prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
let disabledPluginTypes =
Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES).split(',');
if (disabledPluginTypes.indexOf(PDF_CONTENT_TYPE) >= 0) {
Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES).split(",");
if (disabledPluginTypes.includes(PDF_CONTENT_TYPE)) {
return true;
}
}
@ -289,7 +295,7 @@ var PdfJs = {
// Check if there is an enabled pdf plugin.
// Note: this check is performed last because getPluginTags() triggers
// costly plugin list initialization (bug 881575)
let tags = Cc['@mozilla.org/plugin/host;1'].
let tags = Cc["@mozilla.org/plugin/host;1"].
getService(Ci.nsIPluginHost).
getPluginTags();
let enabledPluginFound = tags.some(function(tag) {
@ -306,26 +312,70 @@ var PdfJs = {
return !enabledPluginFound;
},
_ensureRegistered: function _ensureRegistered() {
checkEnabled: function checkEnabled() {
let isEnabled = this._isEnabled();
// This will be updated any time we observe a dependency changing, since
// updateRegistration internally calls enabled.
Services.prefs.setBoolPref(PREF_ENABLED_CACHE_STATE, isEnabled);
return isEnabled;
},
// nsIObserver
observe: function observe(aSubject, aTopic, aData) {
if (Services.appinfo.processType !==
Services.appinfo.PROCESS_TYPE_DEFAULT) {
throw new Error("Only the parent process should be observing PDF " +
"handler changes.");
}
this.updateRegistration();
let jsm = "resource://pdf.js/PdfjsChromeUtils.jsm";
let PdfjsChromeUtils = Cu.import(jsm, {}).PdfjsChromeUtils;
PdfjsChromeUtils.notifyChildOfSettingsChange(this.enabled);
},
/**
* pdf.js is only enabled if it is both selected as the pdf viewer and if the
* global switch enabling it is true.
* @return {boolean} Whether or not it's enabled.
*/
get enabled() {
if (!Services.policies.isAllowed("PDF.js")) {
return false;
}
if (!Services.prefs.getBoolPref(PREF_ENABLED_CACHE_INITIALIZED, false)) {
// If we just updated, and the cache hasn't been initialized, then we
// can't assume a default state, and need to synchronously initialize
// PdfJs
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_POSTUPDATE)) {
this.checkEnabled();
}
Services.prefs.setBoolPref(PREF_ENABLED_CACHE_INITIALIZED, true);
}
return Services.prefs.getBoolPref(PREF_ENABLED_CACHE_STATE, true);
},
ensureRegistered: function ensureRegistered() {
if (this._registered) {
return;
}
this._pdfStreamConverterFactory = new Factory();
Cu.import('resource://pdf.js/PdfStreamConverter.jsm');
Cu.import("resource://pdf.js/PdfStreamConverter.jsm");
this._pdfStreamConverterFactory.register(PdfStreamConverter);
this._registered = true;
},
_ensureUnregistered: function _ensureUnregistered() {
ensureUnregistered: function ensureUnregistered() {
if (!this._registered) {
return;
}
this._pdfStreamConverterFactory.unregister();
Cu.unload('resource://pdf.js/PdfStreamConverter.jsm');
Cu.unload("resource://pdf.js/PdfStreamConverter.jsm");
delete this._pdfStreamConverterFactory;
this._registered = false;
}
},
};

View file

@ -12,43 +12,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Components, Services */
'use strict';
"use strict";
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ['NetworkManager'];
function log(aMsg) {
var msg = 'network.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
Services.console.logStringMessage(msg);
}
var EXPORTED_SYMBOLS = ["NetworkManager"];
var NetworkManager = (function NetworkManagerClosure() {
var OK_RESPONSE = 200;
var PARTIAL_CONTENT_RESPONSE = 206;
function NetworkManager(url, args) {
this.url = url;
args = args || {};
this.isHttp = /^https?:/i.test(url);
this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
this.withCredentials = args.withCredentials || false;
this.getXhr = args.getXhr ||
function NetworkManager_getXhr() {
return new XMLHttpRequest();
};
this.currXhrId = 0;
this.pendingRequests = Object.create(null);
this.loadedRequests = Object.create(null);
}
const OK_RESPONSE = 200;
const PARTIAL_CONTENT_RESPONSE = 206;
function getArrayBuffer(xhr) {
var data = xhr.response;
if (typeof data !== 'string') {
if (typeof data !== "string") {
return data;
}
var length = data.length;
@ -59,54 +37,69 @@ var NetworkManager = (function NetworkManagerClosure() {
return array.buffer;
}
NetworkManager.prototype = {
requestRange: function NetworkManager_requestRange(begin, end, listeners) {
class NetworkManagerClass {
constructor(url, args) {
this.url = url;
args = args || {};
this.isHttp = /^https?:/i.test(url);
this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
this.withCredentials = args.withCredentials || false;
this.getXhr = args.getXhr ||
function NetworkManager_getXhr() {
return new XMLHttpRequest();
};
this.currXhrId = 0;
this.pendingRequests = Object.create(null);
this.loadedRequests = Object.create(null);
}
requestRange(begin, end, listeners) {
var args = {
begin: begin,
end: end
begin,
end,
};
for (var prop in listeners) {
args[prop] = listeners[prop];
}
return this.request(args);
},
}
requestFull: function NetworkManager_requestFull(listeners) {
requestFull(listeners) {
return this.request(listeners);
},
}
request: function NetworkManager_request(args) {
request(args) {
var xhr = this.getXhr();
var xhrId = this.currXhrId++;
var pendingRequest = this.pendingRequests[xhrId] = {
xhr: xhr
xhr,
};
xhr.open('GET', this.url);
xhr.open("GET", this.url);
xhr.withCredentials = this.withCredentials;
for (var property in this.httpHeaders) {
var value = this.httpHeaders[property];
if (typeof value === 'undefined') {
if (typeof value === "undefined") {
continue;
}
xhr.setRequestHeader(property, value);
}
if (this.isHttp && 'begin' in args && 'end' in args) {
var rangeStr = args.begin + '-' + (args.end - 1);
xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
if (this.isHttp && "begin" in args && "end" in args) {
var rangeStr = args.begin + "-" + (args.end - 1);
xhr.setRequestHeader("Range", "bytes=" + rangeStr);
pendingRequest.expectedStatus = 206;
xhr.channel.QueryInterface(Ci.nsIHttpChannel).redirectionLimit = 0;
} else {
pendingRequest.expectedStatus = 200;
}
var useMozChunkedLoading = !!args.onProgressiveData;
if (useMozChunkedLoading) {
xhr.responseType = 'moz-chunked-arraybuffer';
xhr.responseType = "moz-chunked-arraybuffer";
pendingRequest.onProgressiveData = args.onProgressiveData;
pendingRequest.mozChunked = true;
} else {
xhr.responseType = 'arraybuffer';
xhr.responseType = "arraybuffer";
}
if (args.onError) {
@ -125,9 +118,9 @@ var NetworkManager = (function NetworkManagerClosure() {
xhr.send(null);
return xhrId;
},
}
onProgress: function NetworkManager_onProgress(xhrId, evt) {
onProgress(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
// Maybe abortRequest was called...
@ -143,9 +136,9 @@ var NetworkManager = (function NetworkManagerClosure() {
if (onProgress) {
onProgress(evt);
}
},
}
onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
onStateChange(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
// Maybe abortRequest was called...
@ -198,61 +191,61 @@ var NetworkManager = (function NetworkManagerClosure() {
var chunk = getArrayBuffer(xhr);
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
var rangeHeader = xhr.getResponseHeader('Content-Range');
var rangeHeader = xhr.getResponseHeader("Content-Range");
var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
var begin = parseInt(matches[1], 10);
pendingRequest.onDone({
begin: begin,
chunk: chunk
begin,
chunk,
});
} else if (pendingRequest.onProgressiveData) {
pendingRequest.onDone(null);
} else if (chunk) {
pendingRequest.onDone({
begin: 0,
chunk: chunk
chunk,
});
} else if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
},
}
hasPendingRequests: function NetworkManager_hasPendingRequests() {
hasPendingRequests() {
for (var xhrId in this.pendingRequests) {
return true;
}
return false;
},
}
getRequestXhr: function NetworkManager_getXhr(xhrId) {
getRequestXhr(xhrId) {
return this.pendingRequests[xhrId].xhr;
},
}
isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
isStreamingRequest(xhrId) {
return !!(this.pendingRequests[xhrId].onProgressiveData);
},
}
isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
isPendingRequest(xhrId) {
return xhrId in this.pendingRequests;
},
}
isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
isLoadedRequest(xhrId) {
return xhrId in this.loadedRequests;
},
}
abortAllRequests: function NetworkManager_abortAllRequests() {
abortAllRequests() {
for (var xhrId in this.pendingRequests) {
this.abortRequest(xhrId | 0);
}
},
}
abortRequest: function NetworkManager_abortRequest(xhrId) {
abortRequest(xhrId) {
var xhr = this.pendingRequests[xhrId].xhr;
delete this.pendingRequests[xhrId];
xhr.abort();
}
};
}
return NetworkManager;
return NetworkManagerClass;
})();

View file

@ -12,49 +12,52 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils */
'use strict';
"use strict";
var EXPORTED_SYMBOLS = ['PdfjsChromeUtils'];
var EXPORTED_SYMBOLS = ["PdfjsChromeUtils"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PREF_PREFIX = 'pdfjs';
const PDF_CONTENT_TYPE = 'application/pdf';
const PREF_PREFIX = "extensions.uriloader@pdf.js";
const PDF_CONTENT_TYPE = "application/pdf";
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1',
'nsIMIMEService');
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
/* eslint-disable semi */
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
"cursorToolOnLoad": 0,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"enableHandToolOnLoad": false,
"disablePageLabels": false,
"enablePrintAutoRotate": false,
"enableWebGL": false,
"eventBusDispatchToDOM": false,
"externalLinkTarget": 0,
"historyUpdateUrl": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"renderer": "canvas",
"renderInteractiveForms": false,
"sidebarViewOnLoad": -1,
"scrollModeOnLoad": -1,
"spreadModeOnLoad": -1,
"textLayerMode": 1,
"useOnlyCssZoom": false,
"viewOnLoad": 0,
"disableAutoFetch": false,
"disableFontFace": false,
"disableTextLayer": false,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"enhanceTextSelection": false,
"renderInteractiveForms": false,
"disablePageLabels": false
"disableRange": false,
"disableStream": false
}
/* eslint-enable semi */
var PdfjsChromeUtils = {
// For security purposes when running remote, we restrict preferences
@ -67,50 +70,60 @@ var PdfjsChromeUtils = {
* Public API
*/
init: function () {
init() {
this._browsers = new WeakSet();
if (!this._ppmm) {
// global parent process message manager (PPMM)
this._ppmm = Cc['@mozilla.org/parentprocessmessagemanager;1'].
this._ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].
getService(Ci.nsIMessageBroadcaster);
this._ppmm.addMessageListener('PDFJS:Parent:clearUserPref', this);
this._ppmm.addMessageListener('PDFJS:Parent:setIntPref', this);
this._ppmm.addMessageListener('PDFJS:Parent:setBoolPref', this);
this._ppmm.addMessageListener('PDFJS:Parent:setCharPref', this);
this._ppmm.addMessageListener('PDFJS:Parent:setStringPref', this);
this._ppmm.addMessageListener('PDFJS:Parent:isDefaultHandlerApp', this);
this._ppmm.addMessageListener("PDFJS:Parent:clearUserPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setIntPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setBoolPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setCharPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:setStringPref", this);
this._ppmm.addMessageListener("PDFJS:Parent:isDefaultHandlerApp", this);
// global dom message manager (MMg)
this._mmg = Cc['@mozilla.org/globalmessagemanager;1'].
this._mmg = Cc["@mozilla.org/globalmessagemanager;1"].
getService(Ci.nsIMessageListenerManager);
this._mmg.addMessageListener('PDFJS:Parent:displayWarning', this);
this._mmg.addMessageListener("PDFJS:Parent:displayWarning", this);
this._mmg.addMessageListener('PDFJS:Parent:addEventListener', this);
this._mmg.addMessageListener('PDFJS:Parent:removeEventListener', this);
this._mmg.addMessageListener('PDFJS:Parent:updateControlState', this);
this._mmg.addMessageListener("PDFJS:Parent:addEventListener", this);
this._mmg.addMessageListener("PDFJS:Parent:removeEventListener", this);
this._mmg.addMessageListener("PDFJS:Parent:updateControlState", this);
// observer to handle shutdown
Services.obs.addObserver(this, 'quit-application', false);
// The signature of `Services.obs.addObserver` changed in Firefox 55,
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1355216.
// PLEASE NOTE: While the third parameter is now optional,
// omitting it in prior Firefox versions breaks the addon.
var ffVersion = parseInt(Services.appinfo.platformVersion);
if (ffVersion <= 55) {
// eslint-disable-next-line mozilla/no-useless-parameters
Services.obs.addObserver(this, "quit-application", false);
return;
}
// Observer to handle shutdown.
Services.obs.addObserver(this, "quit-application");
}
},
uninit: function () {
uninit() {
if (this._ppmm) {
this._ppmm.removeMessageListener('PDFJS:Parent:clearUserPref', this);
this._ppmm.removeMessageListener('PDFJS:Parent:setIntPref', this);
this._ppmm.removeMessageListener('PDFJS:Parent:setBoolPref', this);
this._ppmm.removeMessageListener('PDFJS:Parent:setCharPref', this);
this._ppmm.removeMessageListener('PDFJS:Parent:setStringPref', this);
this._ppmm.removeMessageListener('PDFJS:Parent:isDefaultHandlerApp',
this._ppmm.removeMessageListener("PDFJS:Parent:clearUserPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setIntPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setBoolPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setCharPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:setStringPref", this);
this._ppmm.removeMessageListener("PDFJS:Parent:isDefaultHandlerApp",
this);
this._mmg.removeMessageListener('PDFJS:Parent:displayWarning', this);
this._mmg.removeMessageListener("PDFJS:Parent:displayWarning", this);
this._mmg.removeMessageListener('PDFJS:Parent:addEventListener', this);
this._mmg.removeMessageListener('PDFJS:Parent:removeEventListener', this);
this._mmg.removeMessageListener('PDFJS:Parent:updateControlState', this);
this._mmg.removeMessageListener("PDFJS:Parent:addEventListener", this);
this._mmg.removeMessageListener("PDFJS:Parent:removeEventListener", this);
this._mmg.removeMessageListener("PDFJS:Parent:updateControlState", this);
Services.obs.removeObserver(this, 'quit-application', false);
Services.obs.removeObserver(this, "quit-application");
this._mmg = null;
this._ppmm = null;
@ -123,7 +136,7 @@ var PdfjsChromeUtils = {
* instruct the child to refresh its configuration and (possibly)
* the module's registration.
*/
notifyChildOfSettingsChange: function () {
notifyChildOfSettingsChange(enabled) {
if (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_DEFAULT && this._ppmm) {
// XXX kinda bad, we want to get the parent process mm associated
@ -131,7 +144,8 @@ var PdfjsChromeUtils = {
// manager, which means this is going to fire to every child process
// we have open. Unfortunately I can't find a way to get at that
// process specific mm from js.
this._ppmm.broadcastAsyncMessage('PDFJS:Child:refreshSettings', {});
this._ppmm.broadcastAsyncMessage("PDFJS:Child:updateSettings",
{ enabled, });
}
},
@ -139,63 +153,63 @@ var PdfjsChromeUtils = {
* Events
*/
observe: function(aSubject, aTopic, aData) {
if (aTopic === 'quit-application') {
observe(aSubject, aTopic, aData) {
if (aTopic === "quit-application") {
this.uninit();
}
},
receiveMessage: function (aMsg) {
receiveMessage(aMsg) {
switch (aMsg.name) {
case 'PDFJS:Parent:clearUserPref':
case "PDFJS:Parent:clearUserPref":
this._clearUserPref(aMsg.data.name);
break;
case 'PDFJS:Parent:setIntPref':
case "PDFJS:Parent:setIntPref":
this._setIntPref(aMsg.data.name, aMsg.data.value);
break;
case 'PDFJS:Parent:setBoolPref':
case "PDFJS:Parent:setBoolPref":
this._setBoolPref(aMsg.data.name, aMsg.data.value);
break;
case 'PDFJS:Parent:setCharPref':
case "PDFJS:Parent:setCharPref":
this._setCharPref(aMsg.data.name, aMsg.data.value);
break;
case 'PDFJS:Parent:setStringPref':
case "PDFJS:Parent:setStringPref":
this._setStringPref(aMsg.data.name, aMsg.data.value);
break;
case 'PDFJS:Parent:isDefaultHandlerApp':
case "PDFJS:Parent:isDefaultHandlerApp":
return this.isDefaultHandlerApp();
case 'PDFJS:Parent:displayWarning':
case "PDFJS:Parent:displayWarning":
this._displayWarning(aMsg);
break;
case 'PDFJS:Parent:updateControlState':
case "PDFJS:Parent:updateControlState":
return this._updateControlState(aMsg);
case 'PDFJS:Parent:addEventListener':
case "PDFJS:Parent:addEventListener":
return this._addEventListener(aMsg);
case 'PDFJS:Parent:removeEventListener':
case "PDFJS:Parent:removeEventListener":
return this._removeEventListener(aMsg);
}
return undefined;
},
/*
* Internal
*/
_findbarFromMessage: function(aMsg) {
_findbarFromMessage(aMsg) {
let browser = aMsg.target;
let tabbrowser = browser.getTabBrowser();
let tab = tabbrowser.getTabForBrowser(browser);
return tabbrowser.getFindBar(tab);
},
_updateControlState: function (aMsg) {
_updateControlState(aMsg) {
let data = aMsg.data;
this._findbarFromMessage(aMsg)
.updateControlState(data.result, data.findPrevious);
},
handleEvent: function(aEvent) {
handleEvent(aEvent) {
// To avoid forwarding the message as a CPOW, create a structured cloneable
// version of the event for both performance, and ease of usage, reasons.
let type = aEvent.type;
@ -203,31 +217,30 @@ var PdfjsChromeUtils = {
query: aEvent.detail.query,
caseSensitive: aEvent.detail.caseSensitive,
highlightAll: aEvent.detail.highlightAll,
findPrevious: aEvent.detail.findPrevious
findPrevious: aEvent.detail.findPrevious,
};
let browser = aEvent.currentTarget.browser;
if (!this._browsers.has(browser)) {
throw new Error('FindEventManager was not bound ' +
'for the current browser.');
throw new Error("FindEventManager was not bound " +
"for the current browser.");
}
// Only forward the events if the current browser is a registered browser.
let mm = browser.messageManager;
mm.sendAsyncMessage('PDFJS:Child:handleEvent',
{ type: type, detail: detail });
mm.sendAsyncMessage("PDFJS:Child:handleEvent", { type, detail, });
aEvent.preventDefault();
},
_types: ['find',
'findagain',
'findhighlightallchange',
'findcasesensitivitychange'],
_types: ["find",
"findagain",
"findhighlightallchange",
"findcasesensitivitychange"],
_addEventListener: function (aMsg) {
_addEventListener(aMsg) {
let browser = aMsg.target;
if (this._browsers.has(browser)) {
throw new Error('FindEventManager was bound 2nd time ' +
'without unbinding it first.');
throw new Error("FindEventManager was bound 2nd time " +
"without unbinding it first.");
}
// Since this jsm is global, we need to store all the browsers
@ -242,10 +255,10 @@ var PdfjsChromeUtils = {
}
},
_removeEventListener: function (aMsg) {
_removeEventListener(aMsg) {
let browser = aMsg.target;
if (!this._browsers.has(browser)) {
throw new Error('FindEventManager was unbound without binding it first.');
throw new Error("FindEventManager was unbound without binding it first.");
}
this._browsers.delete(browser);
@ -258,42 +271,46 @@ var PdfjsChromeUtils = {
}
},
_ensurePreferenceAllowed: function (aPrefName) {
let unPrefixedName = aPrefName.split(PREF_PREFIX + '.');
if (unPrefixedName[0] !== '' ||
this._allowedPrefNames.indexOf(unPrefixedName[1]) === -1) {
let msg = '"' + aPrefName + '" ' +
'can\'t be accessed from content. See PdfjsChromeUtils.';
_ensurePreferenceAllowed(aPrefName) {
let unPrefixedName = aPrefName.split(PREF_PREFIX + ".");
if (unPrefixedName[0] !== "" ||
!this._allowedPrefNames.includes(unPrefixedName[1])) {
let msg = "\"" + aPrefName + "\" " +
"can't be accessed from content. See PdfjsChromeUtils.";
throw new Error(msg);
}
},
_clearUserPref: function (aPrefName) {
_clearUserPref(aPrefName) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.clearUserPref(aPrefName);
},
_setIntPref: function (aPrefName, aPrefValue) {
_setIntPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.setIntPref(aPrefName, aPrefValue);
},
_setBoolPref: function (aPrefName, aPrefValue) {
_setBoolPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.setBoolPref(aPrefName, aPrefValue);
},
_setCharPref: function (aPrefName, aPrefValue) {
_setCharPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
Services.prefs.setCharPref(aPrefName, aPrefValue);
},
_setStringPref: function (aPrefName, aPrefValue) {
_setStringPref(aPrefName, aPrefValue) {
this._ensurePreferenceAllowed(aPrefName);
let str = Cc['@mozilla.org/supports-string;1']
.createInstance(Ci.nsISupportsString);
str.data = aPrefValue;
Services.prefs.setComplexValue(aPrefName, Ci.nsISupportsString, str);
if (!Services.prefs.setStringPref) {
let str = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
str.data = aPrefValue;
Services.prefs.setComplexValue(aPrefName, Ci.nsISupportsString, str);
return;
}
Services.prefs.setStringPref(aPrefName, aPrefValue);
},
/*
@ -301,8 +318,8 @@ var PdfjsChromeUtils = {
* we bounce this pdfjs enabled configuration check over to the
* parent.
*/
isDefaultHandlerApp: function () {
var handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, 'pdf');
isDefaultHandlerApp() {
var handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
return (!handlerInfo.alwaysAskBeforeHandling &&
handlerInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally);
},
@ -311,7 +328,7 @@ var PdfjsChromeUtils = {
* Display a notification warning when the renderer isn't sure
* a pdf displayed correctly.
*/
_displayWarning: function (aMsg) {
_displayWarning(aMsg) {
let data = aMsg.data;
let browser = aMsg.target;
@ -324,24 +341,23 @@ var PdfjsChromeUtils = {
let messageSent = false;
function sendMessage(download) {
let mm = browser.messageManager;
mm.sendAsyncMessage('PDFJS:Child:fallbackDownload',
{ download: download });
mm.sendAsyncMessage("PDFJS:Child:fallbackDownload", { download, });
}
let buttons = [{
label: data.label,
accessKey: data.accessKey,
callback: function() {
callback() {
messageSent = true;
sendMessage(true);
}
},
}];
notificationBox.appendNotification(data.message, 'pdfjs-fallback', null,
notificationBox.appendNotification(data.message, "pdfjs-fallback", null,
notificationBox.PRIORITY_INFO_LOW,
buttons,
function eventsCallback(eventType) {
// Currently there is only one event "removed" but if there are any other
// added in the future we still only care about removed at the moment.
if (eventType !== 'removed') {
if (eventType !== "removed") {
return;
}
// Don't send a response again if we already responded when the button was
@ -351,7 +367,6 @@ var PdfjsChromeUtils = {
}
sendMessage(false);
});
}
},
};

View file

@ -12,20 +12,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils */
'use strict';
"use strict";
var EXPORTED_SYMBOLS = ['PdfjsContentUtils'];
var EXPORTED_SYMBOLS = ["PdfjsContentUtils"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var PdfjsContentUtils = {
_mm: null,
@ -39,21 +36,32 @@ var PdfjsContentUtils = {
Services.appinfo.PROCESS_TYPE_CONTENT);
},
init: function () {
init() {
// child *process* mm, or when loaded into the parent for in-content
// support the psuedo child process mm 'child PPMM'.
if (!this._mm) {
this._mm = Cc['@mozilla.org/childprocessmessagemanager;1'].
this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].
getService(Ci.nsISyncMessageSender);
this._mm.addMessageListener('PDFJS:Child:refreshSettings', this);
Services.obs.addObserver(this, 'quit-application', false);
this._mm.addMessageListener("PDFJS:Child:updateSettings", this);
// The signature of `Services.obs.addObserver` changed in Firefox 55,
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1355216.
// PLEASE NOTE: While the third parameter is now optional,
// omitting it in prior Firefox versions breaks the addon.
var ffVersion = parseInt(Services.appinfo.platformVersion);
if (ffVersion <= 55) {
// eslint-disable-next-line mozilla/no-useless-parameters
Services.obs.addObserver(this, "quit-application", false);
return;
}
Services.obs.addObserver(this, "quit-application");
}
},
uninit: function () {
uninit() {
if (this._mm) {
this._mm.removeMessageListener('PDFJS:Child:refreshSettings', this);
Services.obs.removeObserver(this, 'quit-application');
this._mm.removeMessageListener("PDFJS:Child:updateSettings", this);
Services.obs.removeObserver(this, "quit-application");
}
this._mm = null;
},
@ -64,62 +72,54 @@ var PdfjsContentUtils = {
* approved pdfjs prefs in chrome utils.
*/
clearUserPref: function (aPrefName) {
this._mm.sendSyncMessage('PDFJS:Parent:clearUserPref', {
name: aPrefName
});
},
setIntPref: function (aPrefName, aPrefValue) {
this._mm.sendSyncMessage('PDFJS:Parent:setIntPref', {
clearUserPref(aPrefName) {
this._mm.sendSyncMessage("PDFJS:Parent:clearUserPref", {
name: aPrefName,
value: aPrefValue
});
},
setBoolPref: function (aPrefName, aPrefValue) {
this._mm.sendSyncMessage('PDFJS:Parent:setBoolPref', {
setIntPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setIntPref", {
name: aPrefName,
value: aPrefValue
value: aPrefValue,
});
},
setCharPref: function (aPrefName, aPrefValue) {
this._mm.sendSyncMessage('PDFJS:Parent:setCharPref', {
setBoolPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setBoolPref", {
name: aPrefName,
value: aPrefValue
value: aPrefValue,
});
},
setStringPref: function (aPrefName, aPrefValue) {
this._mm.sendSyncMessage('PDFJS:Parent:setStringPref', {
setCharPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setCharPref", {
name: aPrefName,
value: aPrefValue
value: aPrefValue,
});
},
/*
* Forwards default app query to the parent where we check various
* handler app settings only available in the parent process.
*/
isDefaultHandlerApp: function () {
return this._mm.sendSyncMessage('PDFJS:Parent:isDefaultHandlerApp')[0];
setStringPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setStringPref", {
name: aPrefName,
value: aPrefValue,
});
},
/*
* Request the display of a notification warning in the associated window
* when the renderer isn't sure a pdf displayed correctly.
*/
displayWarning: function (aWindow, aMessage, aLabel, accessKey) {
displayWarning(aWindow, aMessage, aLabel, aAccessKey) {
// the child's dom frame mm associated with the window.
let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
winmm.sendAsyncMessage('PDFJS:Parent:displayWarning', {
winmm.sendAsyncMessage("PDFJS:Parent:displayWarning", {
message: aMessage,
label: aLabel,
accessKey: accessKey
accessKey: aAccessKey,
});
},
@ -127,24 +127,28 @@ var PdfjsContentUtils = {
* Events
*/
observe: function(aSubject, aTopic, aData) {
if (aTopic === 'quit-application') {
observe(aSubject, aTopic, aData) {
if (aTopic === "quit-application") {
this.uninit();
}
},
receiveMessage: function (aMsg) {
receiveMessage(aMsg) {
switch (aMsg.name) {
case 'PDFJS:Child:refreshSettings':
case "PDFJS:Child:updateSettings":
// Only react to this if we are remote.
if (Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_CONTENT) {
let jsm = 'resource://pdf.js/PdfJs.jsm';
let jsm = "resource://pdf.js/PdfJs.jsm";
let pdfjs = Components.utils.import(jsm, {}).PdfJs;
pdfjs.updateRegistration();
if (aMsg.data.enabled) {
pdfjs.ensureRegistered();
} else {
pdfjs.ensureUnregistered();
}
}
break;
}
}
},
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,614 +0,0 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// NOTE: Be careful what goes in this file, as it is also used from the context
// of the addon. So using warn/error in here will break the addon.
'use strict';
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define('pdfjs/core/network', ['exports', 'pdfjs/shared/util',
'pdfjs/core/worker'], factory);
} else if (typeof exports !== 'undefined') {
factory(exports, require('../shared/util.js'), require('./worker.js'));
} else {
factory((root.pdfjsCoreNetwork = {}), root.pdfjsSharedUtil,
root.pdfjsCoreWorker);
}
}(this, function (exports, sharedUtil, coreWorker) {
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
throw new Error('Module "pdfjs/core/network" shall not ' +
'be used with FIREFOX or MOZCENTRAL build.');
}
var OK_RESPONSE = 200;
var PARTIAL_CONTENT_RESPONSE = 206;
function NetworkManager(url, args) {
this.url = url;
args = args || {};
this.isHttp = /^https?:/i.test(url);
this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
this.withCredentials = args.withCredentials || false;
this.getXhr = args.getXhr ||
function NetworkManager_getXhr() {
return new XMLHttpRequest();
};
this.currXhrId = 0;
this.pendingRequests = Object.create(null);
this.loadedRequests = Object.create(null);
}
function getArrayBuffer(xhr) {
var data = xhr.response;
if (typeof data !== 'string') {
return data;
}
var length = data.length;
var array = new Uint8Array(length);
for (var i = 0; i < length; i++) {
array[i] = data.charCodeAt(i) & 0xFF;
}
return array.buffer;
}
var supportsMozChunked =
typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME') ? false :
(function supportsMozChunkedClosure() {
try {
var x = new XMLHttpRequest();
// Firefox 37- required .open() to be called before setting responseType.
// https://bugzilla.mozilla.org/show_bug.cgi?id=707484
// Even though the URL is not visited, .open() could fail if the URL is
// blocked, e.g. via the connect-src CSP directive or the NoScript addon.
// When this error occurs, this feature detection method will mistakenly
// report that moz-chunked-arraybuffer is not supported in Firefox 37-.
x.open('GET', 'https://example.com');
x.responseType = 'moz-chunked-arraybuffer';
return x.responseType === 'moz-chunked-arraybuffer';
} catch (e) {
return false;
}
})();
NetworkManager.prototype = {
requestRange: function NetworkManager_requestRange(begin, end, listeners) {
var args = {
begin: begin,
end: end
};
for (var prop in listeners) {
args[prop] = listeners[prop];
}
return this.request(args);
},
requestFull: function NetworkManager_requestFull(listeners) {
return this.request(listeners);
},
request: function NetworkManager_request(args) {
var xhr = this.getXhr();
var xhrId = this.currXhrId++;
var pendingRequest = this.pendingRequests[xhrId] = {
xhr: xhr
};
xhr.open('GET', this.url);
xhr.withCredentials = this.withCredentials;
for (var property in this.httpHeaders) {
var value = this.httpHeaders[property];
if (typeof value === 'undefined') {
continue;
}
xhr.setRequestHeader(property, value);
}
if (this.isHttp && 'begin' in args && 'end' in args) {
var rangeStr = args.begin + '-' + (args.end - 1);
xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
pendingRequest.expectedStatus = 206;
} else {
pendingRequest.expectedStatus = 200;
}
var useMozChunkedLoading = supportsMozChunked && !!args.onProgressiveData;
if (useMozChunkedLoading) {
xhr.responseType = 'moz-chunked-arraybuffer';
pendingRequest.onProgressiveData = args.onProgressiveData;
pendingRequest.mozChunked = true;
} else {
xhr.responseType = 'arraybuffer';
}
if (args.onError) {
xhr.onerror = function(evt) {
args.onError(xhr.status);
};
}
xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
xhr.onprogress = this.onProgress.bind(this, xhrId);
pendingRequest.onHeadersReceived = args.onHeadersReceived;
pendingRequest.onDone = args.onDone;
pendingRequest.onError = args.onError;
pendingRequest.onProgress = args.onProgress;
xhr.send(null);
return xhrId;
},
onProgress: function NetworkManager_onProgress(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
// Maybe abortRequest was called...
return;
}
if (pendingRequest.mozChunked) {
var chunk = getArrayBuffer(pendingRequest.xhr);
pendingRequest.onProgressiveData(chunk);
}
var onProgress = pendingRequest.onProgress;
if (onProgress) {
onProgress(evt);
}
},
onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
// Maybe abortRequest was called...
return;
}
var xhr = pendingRequest.xhr;
if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
pendingRequest.onHeadersReceived();
delete pendingRequest.onHeadersReceived;
}
if (xhr.readyState !== 4) {
return;
}
if (!(xhrId in this.pendingRequests)) {
// The XHR request might have been aborted in onHeadersReceived()
// callback, in which case we should abort request
return;
}
delete this.pendingRequests[xhrId];
// success status == 0 can be on ftp, file and other protocols
if (xhr.status === 0 && this.isHttp) {
if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
return;
}
var xhrStatus = xhr.status || OK_RESPONSE;
// From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
// "A server MAY ignore the Range header". This means it's possible to
// get a 200 rather than a 206 response from a range request.
var ok_response_on_range_request =
xhrStatus === OK_RESPONSE &&
pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
if (!ok_response_on_range_request &&
xhrStatus !== pendingRequest.expectedStatus) {
if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
return;
}
this.loadedRequests[xhrId] = true;
var chunk = getArrayBuffer(xhr);
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
var rangeHeader = xhr.getResponseHeader('Content-Range');
var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
var begin = parseInt(matches[1], 10);
pendingRequest.onDone({
begin: begin,
chunk: chunk
});
} else if (pendingRequest.onProgressiveData) {
pendingRequest.onDone(null);
} else if (chunk) {
pendingRequest.onDone({
begin: 0,
chunk: chunk
});
} else if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
},
hasPendingRequests: function NetworkManager_hasPendingRequests() {
for (var xhrId in this.pendingRequests) {
return true;
}
return false;
},
getRequestXhr: function NetworkManager_getXhr(xhrId) {
return this.pendingRequests[xhrId].xhr;
},
isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
return !!(this.pendingRequests[xhrId].onProgressiveData);
},
isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
return xhrId in this.pendingRequests;
},
isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
return xhrId in this.loadedRequests;
},
abortAllRequests: function NetworkManager_abortAllRequests() {
for (var xhrId in this.pendingRequests) {
this.abortRequest(xhrId | 0);
}
},
abortRequest: function NetworkManager_abortRequest(xhrId) {
var xhr = this.pendingRequests[xhrId].xhr;
delete this.pendingRequests[xhrId];
xhr.abort();
}
};
var assert = sharedUtil.assert;
var createPromiseCapability = sharedUtil.createPromiseCapability;
var isInt = sharedUtil.isInt;
var MissingPDFException = sharedUtil.MissingPDFException;
var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
/** @implements {IPDFStream} */
function PDFNetworkStream(options) {
this._options = options;
var source = options.source;
this._manager = new NetworkManager(source.url, {
httpHeaders: source.httpHeaders,
withCredentials: source.withCredentials
});
this._rangeChunkSize = source.rangeChunkSize;
this._fullRequestReader = null;
this._rangeRequestReaders = [];
}
PDFNetworkStream.prototype = {
_onRangeRequestReaderClosed:
function PDFNetworkStream_onRangeRequestReaderClosed(reader) {
var i = this._rangeRequestReaders.indexOf(reader);
if (i >= 0) {
this._rangeRequestReaders.splice(i, 1);
}
},
getFullReader: function PDFNetworkStream_getFullReader() {
assert(!this._fullRequestReader);
this._fullRequestReader =
new PDFNetworkStreamFullRequestReader(this._manager, this._options);
return this._fullRequestReader;
},
getRangeReader: function PDFNetworkStream_getRangeReader(begin, end) {
var reader = new PDFNetworkStreamRangeRequestReader(this._manager,
begin, end);
reader.onClosed = this._onRangeRequestReaderClosed.bind(this);
this._rangeRequestReaders.push(reader);
return reader;
},
cancelAllRequests: function PDFNetworkStream_cancelAllRequests(reason) {
if (this._fullRequestReader) {
this._fullRequestReader.cancel(reason);
}
var readers = this._rangeRequestReaders.slice(0);
readers.forEach(function (reader) {
reader.cancel(reason);
});
}
};
/** @implements {IPDFStreamReader} */
function PDFNetworkStreamFullRequestReader(manager, options) {
this._manager = manager;
var source = options.source;
var args = {
onHeadersReceived: this._onHeadersReceived.bind(this),
onProgressiveData: source.disableStream ? null :
this._onProgressiveData.bind(this),
onDone: this._onDone.bind(this),
onError: this._onError.bind(this),
onProgress: this._onProgress.bind(this)
};
this._url = source.url;
this._fullRequestId = manager.requestFull(args);
this._headersReceivedCapability = createPromiseCapability();
this._disableRange = options.disableRange || false;
this._contentLength = source.length; // optional
this._rangeChunkSize = source.rangeChunkSize;
if (!this._rangeChunkSize && !this._disableRange) {
this._disableRange = true;
}
this._isStreamingSupported = false;
this._isRangeSupported = false;
this._cachedChunks = [];
this._requests = [];
this._done = false;
this._storedError = undefined;
this.onProgress = null;
}
PDFNetworkStreamFullRequestReader.prototype = {
_validateRangeRequestCapabilities: function
PDFNetworkStreamFullRequestReader_validateRangeRequestCapabilities() {
if (this._disableRange) {
return false;
}
var networkManager = this._manager;
var fullRequestXhrId = this._fullRequestId;
var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
return false;
}
var contentEncoding =
fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
if (contentEncoding !== 'identity') {
return false;
}
var length = fullRequestXhr.getResponseHeader('Content-Length');
length = parseInt(length, 10);
if (!isInt(length)) {
return false;
}
this._contentLength = length; // setting right content length
if (length <= 2 * this._rangeChunkSize) {
// The file size is smaller than the size of two chunks, so it does
// not make any sense to abort the request and retry with a range
// request.
return false;
}
return true;
},
_onHeadersReceived:
function PDFNetworkStreamFullRequestReader_onHeadersReceived() {
if (this._validateRangeRequestCapabilities()) {
this._isRangeSupported = true;
}
var networkManager = this._manager;
var fullRequestXhrId = this._fullRequestId;
if (networkManager.isStreamingRequest(fullRequestXhrId)) {
// We can continue fetching when progressive loading is enabled,
// and we don't need the autoFetch feature.
this._isStreamingSupported = true;
} else if (this._isRangeSupported) {
// NOTE: by cancelling the full request, and then issuing range
// requests, there will be an issue for sites where you can only
// request the pdf once. However, if this is the case, then the
// server should not be returning that it can support range
// requests.
networkManager.abortRequest(fullRequestXhrId);
}
this._headersReceivedCapability.resolve();
},
_onProgressiveData:
function PDFNetworkStreamFullRequestReader_onProgressiveData(chunk) {
if (this._requests.length > 0) {
var requestCapability = this._requests.shift();
requestCapability.resolve({value: chunk, done: false});
} else {
this._cachedChunks.push(chunk);
}
},
_onDone: function PDFNetworkStreamFullRequestReader_onDone(args) {
if (args) {
this._onProgressiveData(args.chunk);
}
this._done = true;
if (this._cachedChunks.length > 0) {
return;
}
this._requests.forEach(function (requestCapability) {
requestCapability.resolve({value: undefined, done: true});
});
this._requests = [];
},
_onError: function PDFNetworkStreamFullRequestReader_onError(status) {
var url = this._url;
var exception;
if (status === 404 || status === 0 && /^file:/.test(url)) {
exception = new MissingPDFException('Missing PDF "' + url + '".');
} else {
exception = new UnexpectedResponseException(
'Unexpected server response (' + status +
') while retrieving PDF "' + url + '".', status);
}
this._storedError = exception;
this._headersReceivedCapability.reject(exception);
this._requests.forEach(function (requestCapability) {
requestCapability.reject(exception);
});
this._requests = [];
this._cachedChunks = [];
},
_onProgress: function PDFNetworkStreamFullRequestReader_onProgress(data) {
if (this.onProgress) {
this.onProgress({
loaded: data.loaded,
total: data.lengthComputable ? data.total : this._contentLength
});
}
},
get isRangeSupported() {
return this._isRangeSupported;
},
get isStreamingSupported() {
return this._isStreamingSupported;
},
get contentLength() {
return this._contentLength;
},
get headersReady() {
return this._headersReceivedCapability.promise;
},
read: function PDFNetworkStreamFullRequestReader_read() {
if (this._storedError) {
return Promise.reject(this._storedError);
}
if (this._cachedChunks.length > 0) {
var chunk = this._cachedChunks.shift();
return Promise.resolve(chunk);
}
if (this._done) {
return Promise.resolve({value: undefined, done: true});
}
var requestCapability = createPromiseCapability();
this._requests.push(requestCapability);
return requestCapability.promise;
},
cancel: function PDFNetworkStreamFullRequestReader_cancel(reason) {
this._done = true;
this._headersReceivedCapability.reject(reason);
this._requests.forEach(function (requestCapability) {
requestCapability.resolve({value: undefined, done: true});
});
this._requests = [];
if (this._manager.isPendingRequest(this._fullRequestId)) {
this._manager.abortRequest(this._fullRequestId);
}
this._fullRequestReader = null;
}
};
/** @implements {IPDFStreamRangeReader} */
function PDFNetworkStreamRangeRequestReader(manager, begin, end) {
this._manager = manager;
var args = {
onDone: this._onDone.bind(this),
onProgress: this._onProgress.bind(this)
};
this._requestId = manager.requestRange(begin, end, args);
this._requests = [];
this._queuedChunk = null;
this._done = false;
this.onProgress = null;
this.onClosed = null;
}
PDFNetworkStreamRangeRequestReader.prototype = {
_close: function PDFNetworkStreamRangeRequestReader_close() {
if (this.onClosed) {
this.onClosed(this);
}
},
_onDone: function PDFNetworkStreamRangeRequestReader_onDone(data) {
var chunk = data.chunk;
if (this._requests.length > 0) {
var requestCapability = this._requests.shift();
requestCapability.resolve({value: chunk, done: false});
} else {
this._queuedChunk = chunk;
}
this._done = true;
this._requests.forEach(function (requestCapability) {
requestCapability.resolve({value: undefined, done: true});
});
this._requests = [];
this._close();
},
_onProgress: function PDFNetworkStreamRangeRequestReader_onProgress(evt) {
if (!this.isStreamingSupported && this.onProgress) {
this.onProgress({
loaded: evt.loaded
});
}
},
get isStreamingSupported() {
return false; // TODO allow progressive range bytes loading
},
read: function PDFNetworkStreamRangeRequestReader_read() {
if (this._queuedChunk !== null) {
var chunk = this._queuedChunk;
this._queuedChunk = null;
return Promise.resolve({value: chunk, done: false});
}
if (this._done) {
return Promise.resolve({value: undefined, done: true});
}
var requestCapability = createPromiseCapability();
this._requests.push(requestCapability);
return requestCapability.promise;
},
cancel: function PDFNetworkStreamRangeRequestReader_cancel(reason) {
this._done = true;
this._requests.forEach(function (requestCapability) {
requestCapability.resolve({value: undefined, done: true});
});
this._requests = [];
if (this._manager.isPendingRequest(this._requestId)) {
this._manager.abortRequest(this._requestId);
}
this._close();
}
};
coreWorker.setPDFNetworkStreamClass(PDFNetworkStream);
exports.PDFNetworkStream = PDFNetworkStream;
exports.NetworkManager = NetworkManager;
}));

View file

@ -1,36 +0,0 @@
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, PdfjsContentUtils, PdfJs, Services */
'use strict';
/*
* pdfjschildbootstrap.js loads into the content process to take care of
* initializing our built-in version of pdfjs when running remote.
*/
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import('resource://pdf.js/PdfJs.jsm');
Components.utils.import('resource://pdf.js/PdfjsContentUtils.jsm');
// init content utils shim pdfjs will use to access privileged apis.
PdfjsContentUtils.init();
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
// register various pdfjs factories that hook us into content loading.
PdfJs.updateRegistration();
}

View file

@ -12,38 +12,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-var */
'use strict';
var FontInspector = (function FontInspectorClosure() {
var fonts;
var fonts, createObjectURL;
var active = false;
var fontAttribute = 'data-font-name';
function removeSelection() {
var divs = document.querySelectorAll('div[' + fontAttribute + ']');
for (var i = 0, ii = divs.length; i < ii; ++i) {
var div = divs[i];
let divs = document.querySelectorAll(`span[${fontAttribute}]`);
for (let div of divs) {
div.className = '';
}
}
function resetSelection() {
var divs = document.querySelectorAll('div[' + fontAttribute + ']');
for (var i = 0, ii = divs.length; i < ii; ++i) {
var div = divs[i];
let divs = document.querySelectorAll(`span[${fontAttribute}]`);
for (let div of divs) {
div.className = 'debuggerHideText';
}
}
function selectFont(fontName, show) {
var divs = document.querySelectorAll('div[' + fontAttribute + '=' +
fontName + ']');
for (var i = 0, ii = divs.length; i < ii; ++i) {
var div = divs[i];
let divs = document.querySelectorAll(`span[${fontAttribute}=${fontName}]`);
for (let div of divs) {
div.className = show ? 'debuggerShowText' : 'debuggerHideText';
}
}
function textLayerClick(e) {
if (!e.target.dataset.fontName ||
e.target.tagName.toUpperCase() !== 'DIV') {
e.target.tagName.toUpperCase() !== 'SPAN') {
return;
}
var fontName = e.target.dataset.fontName;
@ -74,6 +71,8 @@ var FontInspector = (function FontInspectorClosure() {
fonts = document.createElement('div');
panel.appendChild(fonts);
createObjectURL = pdfjsLib.createObjectURL;
},
cleanup: function cleanup() {
fonts.textContent = '';
@ -118,10 +117,7 @@ var FontInspector = (function FontInspectorClosure() {
url = /url\(['"]?([^\)"']+)/.exec(url);
download.href = url[1];
} else if (fontObj.data) {
url = URL.createObjectURL(new Blob([fontObj.data], {
type: fontObj.mimeType
}));
download.href = url;
download.href = createObjectURL(fontObj.data, fontObj.mimeType);
}
download.textContent = 'Download';
var logIt = document.createElement('a');
@ -149,12 +145,12 @@ var FontInspector = (function FontInspectorClosure() {
fonts.appendChild(font);
// Somewhat of a hack, should probably add a hook for when the text layer
// is done rendering.
setTimeout(function() {
setTimeout(() => {
if (this.active) {
resetSelection();
}
}.bind(this), 2000);
}
}, 2000);
},
};
})();
@ -243,7 +239,7 @@ var StepperManager = (function StepperManagerClosure() {
saveBreakPoints: function saveBreakPoints(pageIndex, bps) {
breakPoints[pageIndex] = bps;
sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints));
}
},
};
})();
@ -262,7 +258,7 @@ var Stepper = (function StepperClosure() {
if (typeof args === 'string') {
var MAX_STRING_LENGTH = 75;
return args.length <= MAX_STRING_LENGTH ? args :
args.substr(0, MAX_STRING_LENGTH) + '...';
args.substring(0, MAX_STRING_LENGTH) + '...';
}
if (typeof args !== 'object' || args === null) {
return args;
@ -337,7 +333,7 @@ var Stepper = (function StepperClosure() {
line.className = 'line';
line.dataset.idx = i;
chunk.appendChild(line);
var checked = this.breakPoints.indexOf(i) !== -1;
var checked = this.breakPoints.includes(i);
var args = operatorList.argsArray[i] || [];
var breakCell = c('td');
@ -387,7 +383,9 @@ var Stepper = (function StepperClosure() {
this.table.appendChild(chunk);
},
getNextBreakPoint: function getNextBreakPoint() {
this.breakPoints.sort(function(a, b) { return a - b; });
this.breakPoints.sort(function(a, b) {
return a - b;
});
for (var i = 0; i < this.breakPoints.length; i++) {
if (this.breakPoints[i] > this.currentIdx) {
return this.breakPoints[i];
@ -403,13 +401,13 @@ var Stepper = (function StepperClosure() {
var listener = function(e) {
switch (e.keyCode) {
case 83: // step
dom.removeEventListener('keydown', listener, false);
dom.removeEventListener('keydown', listener);
self.nextBreakPoint = self.currentIdx + 1;
self.goTo(-1);
callback();
break;
case 67: // continue
dom.removeEventListener('keydown', listener, false);
dom.removeEventListener('keydown', listener);
var breakPoint = self.getNextBreakPoint();
self.nextBreakPoint = breakPoint;
self.goTo(-1);
@ -417,7 +415,7 @@ var Stepper = (function StepperClosure() {
break;
}
};
dom.addEventListener('keydown', listener, false);
dom.addEventListener('keydown', listener);
self.goTo(idx);
},
goTo: function goTo(idx) {
@ -431,7 +429,7 @@ var Stepper = (function StepperClosure() {
row.style.backgroundColor = null;
}
}
}
},
};
return Stepper;
})();
@ -457,14 +455,13 @@ var Stats = (function Stats() {
name: 'Stats',
panel: null,
manager: null,
init: function init(pdfjsLib) {
init(pdfjsLib) {
this.panel.setAttribute('style', 'padding: 5px;');
pdfjsLib.PDFJS.enableStats = true;
},
enabled: false,
active: false,
// Stats specific functions.
add: function(pageNumber, stat) {
add(pageNumber, stat) {
if (!stat) {
return;
}
@ -483,22 +480,24 @@ var Stats = (function Stats() {
statsDiv.textContent = stat.toString();
wrapper.appendChild(title);
wrapper.appendChild(statsDiv);
stats.push({ pageNumber: pageNumber, div: wrapper });
stats.sort(function(a, b) { return a.pageNumber - b.pageNumber; });
stats.push({ pageNumber, div: wrapper, });
stats.sort(function(a, b) {
return a.pageNumber - b.pageNumber;
});
clear(this.panel);
for (var i = 0, ii = stats.length; i < ii; ++i) {
this.panel.appendChild(stats[i].div);
}
},
cleanup: function () {
cleanup() {
stats = [];
clear(this.panel);
}
},
};
})();
// Manages all the debugging tools.
var PDFBug = (function PDFBugClosure() {
window.PDFBug = (function PDFBugClosure() {
var panelWidth = 300;
var buttons = [];
var activePanel = null;
@ -509,14 +508,14 @@ var PDFBug = (function PDFBugClosure() {
StepperManager,
Stats
],
enable: function(ids) {
enable(ids) {
var all = false, tools = this.tools;
if (ids.length === 1 && ids[0] === 'all') {
all = true;
}
for (var i = 0; i < tools.length; ++i) {
var tool = tools[i];
if (all || ids.indexOf(tool.id) !== -1) {
if (all || ids.includes(tool.id)) {
tool.enabled = true;
}
}
@ -531,7 +530,7 @@ var PDFBug = (function PDFBugClosure() {
});
}
},
init: function init(pdfjsLib, container) {
init(pdfjsLib, container) {
/*
* Basic Layout:
* PDFBug
@ -584,14 +583,14 @@ var PDFBug = (function PDFBugClosure() {
}
this.selectPanel(0);
},
cleanup: function cleanup() {
cleanup() {
for (var i = 0, ii = this.tools.length; i < ii; i++) {
if (this.tools[i].enabled) {
this.tools[i].cleanup();
}
}
},
selectPanel: function selectPanel(index) {
selectPanel(index) {
if (typeof index !== 'number') {
index = this.tools.indexOf(index);
}
@ -611,6 +610,6 @@ var PDFBug = (function PDFBugClosure() {
tools[j].panel.setAttribute('hidden', 'true');
}
}
}
},
};
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

View file

@ -1,151 +0,0 @@
'use strict';
// Small subset of the webL10n API by Fabien Cazenave for pdf.js extension.
(function(window) {
var gLanguage = '';
var gExternalLocalizerServices = null;
// fetch an l10n objects
function getL10nData(key) {
var response = gExternalLocalizerServices.getStrings(key);
var data = JSON.parse(response);
if (!data) {
console.warn('[l10n] #' + key + ' missing for [' + gLanguage + ']');
}
return data;
}
// replace {{arguments}} with their values
function substArguments(text, args) {
if (!args) {
return text;
}
return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function(all, name) {
return (name in args ? args[name] : '{{' + name + '}}');
});
}
// translate a string
function translateString(key, args, fallback) {
var i = key.lastIndexOf('.');
var name, property;
if (i >= 0) {
name = key.substring(0, i);
property = key.substring(i + 1);
} else {
name = key;
property = 'textContent';
}
var data = getL10nData(name);
var value = (data && data[property]) || fallback;
if (!value) {
return '{{' + key + '}}';
}
return substArguments(value, args);
}
// translate an HTML element
function translateElement(element) {
if (!element || !element.dataset) {
return;
}
// get the related l10n object
var key = element.dataset.l10nId;
var data = getL10nData(key);
if (!data) {
return;
}
// get arguments (if any)
// TODO: more flexible parser?
var args;
if (element.dataset.l10nArgs) {
try {
args = JSON.parse(element.dataset.l10nArgs);
} catch (e) {
console.warn('[l10n] could not parse arguments for #' + key + '');
}
}
// translate element
// TODO: security check?
for (var k in data) {
element[k] = substArguments(data[k], args);
}
}
// translate an HTML subtree
function translateFragment(element) {
element = element || document.querySelector('html');
// check all translatable children (= w/ a `data-l10n-id' attribute)
var children = element.querySelectorAll('*[data-l10n-id]');
var elementCount = children.length;
for (var i = 0; i < elementCount; i++) {
translateElement(children[i]);
}
// translate element itself if necessary
if (element.dataset.l10nId) {
translateElement(element);
}
}
function translateDocument() {
gLanguage = gExternalLocalizerServices.getLocale();
translateFragment();
// fire a 'localized' DOM event
var evtObject = document.createEvent('Event');
evtObject.initEvent('localized', false, false);
evtObject.language = gLanguage;
window.dispatchEvent(evtObject);
}
window.addEventListener('DOMContentLoaded', function() {
if (gExternalLocalizerServices) {
translateDocument();
}
// ... else see setExternalLocalizerServices below
});
// Public API
document.mozL10n = {
// get a localized string
get: translateString,
// get the document language
getLanguage: function() {
return gLanguage;
},
// get the direction (ltr|rtl) of the current language
getDirection: function() {
// http://www.w3.org/International/questions/qa-scripts
// Arabic, Hebrew, Farsi, Pashto, Urdu
var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
// use the short language code for "full" codes like 'ar-sa' (issue 5440)
var shortCode = gLanguage.split('-')[0];
return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr';
},
setExternalLocalizerServices: function (externalLocalizerServices) {
gExternalLocalizerServices = externalLocalizerServices;
// ... in case if we missed DOMContentLoaded above.
if (window.document.readyState === 'interactive' ||
window.document.readyState === 'complete') {
translateDocument();
}
},
// translate an element or document fragment
translate: translateFragment
};
})(this);

View file

@ -24,12 +24,11 @@
line-height: 1.0;
}
.textLayer > div {
.textLayer > span {
color: transparent;
position: absolute;
white-space: pre;
cursor: text;
-moz-transform-origin: 0% 0%;
transform-origin: 0% 0%;
}
@ -58,7 +57,6 @@
}
.textLayer ::selection { background: rgb(0,0,255); }
.textLayer ::-moz-selection { background: rgb(0,0,255); }
.textLayer .endOfContent {
display: block;
@ -69,7 +67,7 @@
bottom: 0px;
z-index: -1;
cursor: default;
-moz-user-select: none;
user-select: none;
}
.textLayer .endOfContent.active {
@ -81,7 +79,8 @@
position: absolute;
}
.annotationLayer .linkAnnotation > a {
.annotationLayer .linkAnnotation > a,
.annotationLayer .buttonWidgetAnnotation.pushButton > a {
position: absolute;
font-size: 1em;
top: 0;
@ -90,7 +89,8 @@
height: 100%;
}
.annotationLayer .linkAnnotation > a:hover {
.annotationLayer .linkAnnotation > a:hover,
.annotationLayer .buttonWidgetAnnotation.pushButton > a:hover {
opacity: 0.2;
background: #ff0;
box-shadow: 0px 2px 10px #ff0;
@ -103,17 +103,28 @@
.annotationLayer .textWidgetAnnotation input,
.annotationLayer .textWidgetAnnotation textarea,
.annotationLayer .choiceWidgetAnnotation select {
.annotationLayer .choiceWidgetAnnotation select,
.annotationLayer .buttonWidgetAnnotation.checkBox input,
.annotationLayer .buttonWidgetAnnotation.radioButton input {
background-color: rgba(0, 54, 255, 0.13);
border: 1px solid transparent;
box-sizing: border-box;
font-size: 9px;
height: 100%;
margin: 0;
padding: 0 3px;
vertical-align: top;
width: 100%;
}
.annotationLayer .choiceWidgetAnnotation select option {
padding: 0;
}
.annotationLayer .buttonWidgetAnnotation.radioButton input {
border-radius: 50%;
}
.annotationLayer .textWidgetAnnotation textarea {
font: message-box;
font-size: 9px;
@ -122,7 +133,9 @@
.annotationLayer .textWidgetAnnotation input[disabled],
.annotationLayer .textWidgetAnnotation textarea[disabled],
.annotationLayer .choiceWidgetAnnotation select[disabled] {
.annotationLayer .choiceWidgetAnnotation select[disabled],
.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled],
.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] {
background: none;
border: 1px solid transparent;
cursor: not-allowed;
@ -130,7 +143,9 @@
.annotationLayer .textWidgetAnnotation input:hover,
.annotationLayer .textWidgetAnnotation textarea:hover,
.annotationLayer .choiceWidgetAnnotation select:hover {
.annotationLayer .choiceWidgetAnnotation select:hover,
.annotationLayer .buttonWidgetAnnotation.checkBox input:hover,
.annotationLayer .buttonWidgetAnnotation.radioButton input:hover {
border: 1px solid #000;
}
@ -141,6 +156,38 @@
border: 1px solid transparent;
}
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before,
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after,
.annotationLayer .buttonWidgetAnnotation.radioButton input:checked:before {
background-color: #000;
content: '';
display: block;
position: absolute;
}
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before,
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after {
height: 80%;
left: 45%;
width: 1px;
}
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before {
transform: rotate(45deg);
}
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after {
transform: rotate(-45deg);
}
.annotationLayer .buttonWidgetAnnotation.radioButton input:checked:before {
border-radius: 50%;
height: 50%;
left: 30%;
top: 20%;
width: 50%;
}
.annotationLayer .textWidgetAnnotation input.comb {
font-family: monospace;
padding-left: 2px;
@ -157,6 +204,12 @@
width: 115%;
}
.annotationLayer .buttonWidgetAnnotation.checkBox input,
.annotationLayer .buttonWidgetAnnotation.radioButton input {
appearance: none;
padding: 0;
}
.annotationLayer .popupWrapper {
position: absolute;
width: 20em;
@ -167,28 +220,48 @@
z-index: 200;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 5px #333;
box-shadow: 0px 2px 5px #888;
border-radius: 2px;
padding: 0.6em;
padding: 6px;
margin-left: 5px;
cursor: pointer;
font: message-box;
font-size: 9px;
word-wrap: break-word;
}
.annotationLayer .popup > * {
font-size: 9px;
}
.annotationLayer .popup h1 {
font-size: 1em;
border-bottom: 1px solid #000000;
padding-bottom: 0.2em;
display: inline-block;
}
.annotationLayer .popup span {
display: inline-block;
margin-left: 5px;
}
.annotationLayer .popup p {
padding-top: 0.2em;
border-top: 1px solid #333;
margin-top: 2px;
padding-top: 2px;
}
.annotationLayer .highlightAnnotation,
.annotationLayer .underlineAnnotation,
.annotationLayer .squigglyAnnotation,
.annotationLayer .strikeoutAnnotation,
.annotationLayer .freeTextAnnotation,
.annotationLayer .lineAnnotation svg line,
.annotationLayer .squareAnnotation svg rect,
.annotationLayer .circleAnnotation svg ellipse,
.annotationLayer .polylineAnnotation svg polyline,
.annotationLayer .polygonAnnotation svg polygon,
.annotationLayer .caretAnnotation,
.annotationLayer .inkAnnotation svg polyline,
.annotationLayer .stampAnnotation,
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
}
@ -224,11 +297,55 @@
border: none;
}
.pdfViewer.scrollHorizontal, .pdfViewer.scrollWrapped, .spread {
margin-left: 3.5px;
margin-right: 3.5px;
text-align: center;
}
.pdfViewer.scrollHorizontal, .spread {
white-space: nowrap;
}
.pdfViewer.removePageBorders,
.pdfViewer.scrollHorizontal .spread,
.pdfViewer.scrollWrapped .spread {
margin-left: 0;
margin-right: 0;
}
.spread .page,
.pdfViewer.scrollHorizontal .page,
.pdfViewer.scrollWrapped .page,
.pdfViewer.scrollHorizontal .spread,
.pdfViewer.scrollWrapped .spread {
display: inline-block;
vertical-align: middle;
}
.spread .page,
.pdfViewer.scrollHorizontal .page,
.pdfViewer.scrollWrapped .page {
margin-left: -3.5px;
margin-right: -3.5px;
}
.pdfViewer.removePageBorders .spread .page,
.pdfViewer.removePageBorders.scrollHorizontal .page,
.pdfViewer.removePageBorders.scrollWrapped .page {
margin-left: 5px;
margin-right: 5px;
}
.pdfViewer .page canvas {
margin: 0;
display: block;
}
.pdfViewer .page canvas[hidden] {
display: none;
}
.pdfViewer .page .loadingIcon {
position: absolute;
display: block;
@ -239,9 +356,24 @@
background: url('images/loading-icon.gif') center no-repeat;
}
.pdfPresentationMode:-moz-full-screen .pdfViewer .page {
margin-bottom: 100%;
border: 0;
.pdfPresentationMode .pdfViewer {
margin-left: 0;
margin-right: 0;
}
.pdfPresentationMode .pdfViewer .page,
.pdfPresentationMode .pdfViewer .spread {
display: block;
}
.pdfPresentationMode .pdfViewer .page,
.pdfPresentationMode .pdfViewer.removePageBorders .page {
margin-left: auto;
margin-right: auto;
}
.pdfPresentationMode:-ms-fullscreen .pdfViewer .page {
margin-bottom: 100% !important;
}
.pdfPresentationMode:fullscreen .pdfViewer .page {
@ -249,6 +381,10 @@
border: 0;
}
:root {
--sidebar-width: 200px;
}
* {
padding: 0;
margin: 0;
@ -283,15 +419,13 @@ select {
display: none !important;
}
#viewerContainer.pdfPresentationMode:-moz-full-screen {
top: 0px;
border-top: 2px solid transparent;
#viewerContainer.pdfPresentationMode:-ms-fullscreen {
top: 0px !important;
overflow: hidden !important;
}
#viewerContainer.pdfPresentationMode:-ms-fullscreen::-ms-backdrop {
background-color: #000;
width: 100%;
height: 100%;
overflow: hidden;
cursor: none;
-moz-user-select: none;
}
#viewerContainer.pdfPresentationMode:fullscreen {
@ -302,27 +436,19 @@ select {
height: 100%;
overflow: hidden;
cursor: none;
-moz-user-select: none;
}
.pdfPresentationMode:-moz-full-screen a:not(.internalLink) {
display: none;
user-select: none;
}
.pdfPresentationMode:fullscreen a:not(.internalLink) {
display: none;
}
.pdfPresentationMode:-moz-full-screen .textLayer > div {
cursor: none;
}
.pdfPresentationMode:fullscreen .textLayer > div {
.pdfPresentationMode:fullscreen .textLayer > span {
cursor: none;
}
.pdfPresentationMode.pdfPresentationModeControls > *,
.pdfPresentationMode.pdfPresentationModeControls .textLayer > div {
.pdfPresentationMode.pdfPresentationModeControls .textLayer > span {
cursor: default;
}
@ -334,31 +460,48 @@ select {
#sidebarContainer {
position: absolute;
top: 0;
top: 32px;
bottom: 0;
width: 200px;
width: 200px; /* Here, and elsewhere below, keep the constant value for compatibility
with older browsers that lack support for CSS variables. */
width: var(--sidebar-width);
visibility: hidden;
z-index: 100;
border-top: 1px solid #333;
transition-duration: 200ms;
transition-timing-function: ease;
}
html[dir='ltr'] #sidebarContainer {
transition-property: left;
left: -200px;
left: calc(-1 * var(--sidebar-width));
}
html[dir='rtl'] #sidebarContainer {
transition-property: right;
right: -200px;
right: calc(-1 * var(--sidebar-width));
}
#outerContainer.sidebarMoving > #sidebarContainer,
#outerContainer.sidebarOpen > #sidebarContainer {
.loadingInProgress #sidebarContainer {
top: 36px;
}
#outerContainer.sidebarResizing #sidebarContainer {
/* Improve responsiveness and avoid visual glitches when the sidebar is resized. */
transition-duration: 0s;
/* Prevent e.g. the thumbnails being selected when the sidebar is resized. */
user-select: none;
}
#outerContainer.sidebarMoving #sidebarContainer,
#outerContainer.sidebarOpen #sidebarContainer {
visibility: visible;
}
html[dir='ltr'] #outerContainer.sidebarOpen > #sidebarContainer {
html[dir='ltr'] #outerContainer.sidebarOpen #sidebarContainer {
left: 0px;
}
html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer {
html[dir='rtl'] #outerContainer.sidebarOpen #sidebarContainer {
right: 0px;
}
@ -369,24 +512,15 @@ html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer {
bottom: 0;
left: 0;
min-width: 320px;
transition-duration: 200ms;
transition-timing-function: ease;
}
html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
transition-property: left;
left: 200px;
}
html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
transition-property: right;
right: 200px;
}
#sidebarContent {
top: 32px;
bottom: 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
width: 200px;
width: 100%;
background-color: hsla(0,0%,0%,.1);
}
html[dir='ltr'] #sidebarContent {
@ -400,6 +534,7 @@ html[dir='rtl'] #sidebarContent {
#viewerContainer {
overflow: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
top: 32px;
right: 0;
@ -407,6 +542,10 @@ html[dir='rtl'] #sidebarContent {
left: 0;
outline: none;
}
#viewerContainer:not(.pdfPresentationMode) {
transition-duration: 200ms;
transition-timing-function: ease;
}
html[dir='ltr'] #viewerContainer {
box-shadow: inset 1px 0 0 hsla(0,0%,100%,.05);
}
@ -414,6 +553,22 @@ html[dir='rtl'] #viewerContainer {
box-shadow: inset -1px 0 0 hsla(0,0%,100%,.05);
}
#outerContainer.sidebarResizing #viewerContainer {
/* Improve responsiveness and avoid visual glitches when the sidebar is resized. */
transition-duration: 0s;
}
html[dir='ltr'] #outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) {
transition-property: left;
left: 200px;
left: var(--sidebar-width);
}
html[dir='rtl'] #outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) {
transition-property: right;
right: 200px;
right: var(--sidebar-width);
}
.toolbar {
position: relative;
left: 0;
@ -427,7 +582,7 @@ html[dir='rtl'] #viewerContainer {
}
#toolbarSidebar {
width: 200px;
width: 100%;
height: 32px;
background-color: #424242; /* fallback */
background-image: url(images/texture.png),
@ -446,6 +601,21 @@ html[dir='rtl'] #toolbarSidebar {
0 0 1px hsla(0,0%,0%,.1);
}
#sidebarResizer {
position: absolute;
top: 0;
bottom: 0;
width: 6px;
z-index: 200;
cursor: ew-resize;
}
html[dir='ltr'] #sidebarResizer {
right: -6px;
}
html[dir='rtl'] #sidebarResizer {
left: -6px;
}
#toolbarContainer, .findbar, .secondaryToolbar {
position: relative;
height: 32px;
@ -454,15 +624,13 @@ html[dir='rtl'] #toolbarSidebar {
linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
}
html[dir='ltr'] #toolbarContainer, .findbar, .secondaryToolbar {
box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08),
inset 0 1px 1px hsla(0,0%,0%,.15),
box-shadow: inset 0 1px 1px hsla(0,0%,0%,.15),
inset 0 -1px 0 hsla(0,0%,100%,.05),
0 1px 0 hsla(0,0%,0%,.15),
0 1px 1px hsla(0,0%,0%,.1);
}
html[dir='rtl'] #toolbarContainer, .findbar, .secondaryToolbar {
box-shadow: inset -1px 0 0 hsla(0,0%,100%,.08),
inset 0 1px 1px hsla(0,0%,0%,.15),
box-shadow: inset 0 1px 1px hsla(0,0%,0%,.15),
inset 0 -1px 0 hsla(0,0%,100%,.05),
0 1px 0 hsla(0,0%,0%,.15),
0 1px 1px hsla(0,0%,0%,.1);
@ -520,8 +688,7 @@ html[dir='rtl'] #toolbarContainer, .findbar, .secondaryToolbar {
top: 32px;
position: absolute;
z-index: 10000;
height: 32px;
height: auto;
min-width: 16px;
padding: 0px 6px 0px 6px;
margin: 4px 2px 4px 2px;
@ -532,18 +699,38 @@ html[dir='rtl'] #toolbarContainer, .findbar, .secondaryToolbar {
cursor: default;
}
.findbar {
min-width: 300px;
}
.findbar > div {
height: 32px;
}
.findbar.wrapContainers > div {
clear: both;
}
.findbar.wrapContainers > div#findbarMessageContainer {
height: auto;
}
html[dir='ltr'] .findbar {
left: 68px;
}
html[dir='rtl'] .findbar {
right: 68px;
}
.findbar label {
-moz-user-select: none;
user-select: none;
}
#findInput {
width: 200px;
}
#findInput::-webkit-input-placeholder {
color: hsl(0, 0%, 75%);
}
#findInput::placeholder {
font-style: italic;
}
#findInput[data-status="pending"] {
background-image: url(images/loading-small.png);
background-repeat: no-repeat;
@ -569,9 +756,15 @@ html[dir='rtl'] .secondaryToolbar {
max-width: 200px;
max-height: 400px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
margin-bottom: -4px;
}
#secondaryToolbarButtonContainer.hiddenScrollModeButtons > .scrollModeButtons,
#secondaryToolbarButtonContainer.hiddenSpreadModeButtons > .spreadModeButtons {
display: none !important;
}
.doorHanger,
.doorHangerRight {
border: 1px solid hsla(0,0%,0%,.5);
@ -634,6 +827,9 @@ html[dir='ltr'] .doorHangerRight:before {
font-style: italic;
color: #A6B7D0;
}
#findMsg:empty {
display: none;
}
#findInput.notFound {
background-color: rgb(255, 102, 102);
@ -656,14 +852,14 @@ html[dir='rtl'] #toolbarViewerLeft {
html[dir='ltr'] #toolbarViewerLeft > *,
html[dir='ltr'] #toolbarViewerMiddle > *,
html[dir='ltr'] #toolbarViewerRight > *,
html[dir='ltr'] .findbar > * {
html[dir='ltr'] .findbar * {
position: relative;
float: left;
}
html[dir='rtl'] #toolbarViewerLeft > *,
html[dir='rtl'] #toolbarViewerMiddle > *,
html[dir='rtl'] #toolbarViewerRight > *,
html[dir='rtl'] .findbar > * {
html[dir='rtl'] .findbar * {
position: relative;
float: right;
}
@ -707,10 +903,6 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
opacity: .5;
}
.toolbarButton.group {
margin-right: 0;
}
.splitToolbarButton.toggled .toolbarButton {
margin: 0;
}
@ -802,7 +994,7 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
color: hsla(0,0%,100%,.8);
font-size: 12px;
line-height: 14px;
-moz-user-select: none;
user-select: none;
/* Opera does not support user-select, use <... unselectable="on"> instead */
cursor: default;
transition-property: background-color, border-color, box-shadow;
@ -931,11 +1123,6 @@ html[dir='rtl'] .toolbarButton:first-child {
height: 1px;
}
.toolbarButtonFlexibleSpacer {
-moz-box-flex: 1;
min-width: 30px;
}
html[dir='ltr'] #findPrevious {
margin-left: 3px;
}
@ -1077,6 +1264,24 @@ html[dir="rtl"] #viewOutline.toolbarButton::before {
content: url(images/toolbarButton-search.png);
}
.toolbarButton.pdfSidebarNotification::after {
position: absolute;
display: inline-block;
top: 1px;
/* Create a filled circle, with a diameter of 9 pixels, using only CSS: */
content: '';
background-color: #70DB55;
height: 9px;
width: 9px;
border-radius: 50%;
}
html[dir='ltr'] .toolbarButton.pdfSidebarNotification::after {
left: 17px;
}
html[dir='rtl'] .toolbarButton.pdfSidebarNotification::after {
right: 17px;
}
.secondaryToolbarButton {
position: relative;
margin: 0 0 4px 0;
@ -1125,10 +1330,38 @@ html[dir="rtl"] .secondaryToolbarButton > span {
content: url(images/secondaryToolbarButton-rotateCw.png);
}
.secondaryToolbarButton.selectTool::before {
content: url(images/secondaryToolbarButton-selectTool.png);
}
.secondaryToolbarButton.handTool::before {
content: url(images/secondaryToolbarButton-handTool.png);
}
.secondaryToolbarButton.scrollVertical::before {
content: url(images/secondaryToolbarButton-scrollVertical.png);
}
.secondaryToolbarButton.scrollHorizontal::before {
content: url(images/secondaryToolbarButton-scrollHorizontal.png);
}
.secondaryToolbarButton.scrollWrapped::before {
content: url(images/secondaryToolbarButton-scrollWrapped.png);
}
.secondaryToolbarButton.spreadNone::before {
content: url(images/secondaryToolbarButton-spreadNone.png);
}
.secondaryToolbarButton.spreadOdd::before {
content: url(images/secondaryToolbarButton-spreadOdd.png);
}
.secondaryToolbarButton.spreadEven::before {
content: url(images/secondaryToolbarButton-spreadEven.png);
}
.secondaryToolbarButton.documentProperties::before {
content: url(images/secondaryToolbarButton-documentProperties.png);
}
@ -1196,6 +1429,12 @@ html[dir='rtl'] .verticalToolbarSeparator {
background-position: 1px;
}
.toolbarField.pageNumber::-webkit-inner-spin-button,
.toolbarField.pageNumber::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.toolbarField:hover {
background-color: hsla(0,0%,100%,.11);
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45);
@ -1216,22 +1455,33 @@ html[dir='rtl'] .verticalToolbarSeparator {
font-size: 12px;
line-height: 14px;
text-align: left;
-moz-user-select: none;
user-select: none;
cursor: default;
}
#thumbnailView {
position: absolute;
width: 120px;
width: calc(100% - 60px);
top: 0;
bottom: 0;
padding: 10px 40px 0;
padding: 10px 30px 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#thumbnailView > a:active,
#thumbnailView > a:focus {
outline: 0;
}
.thumbnail {
margin: 0 10px 5px 10px;
}
html[dir='ltr'] .thumbnail {
float: left;
margin-bottom: 5px;
}
html[dir='rtl'] .thumbnail {
float: right;
}
#thumbnailView > a:last-of-type > .thumbnail {
@ -1244,7 +1494,7 @@ html[dir='rtl'] .verticalToolbarSeparator {
.thumbnail:not([data-loaded]) {
border: 1px dashed rgba(255, 255, 255, 0.5);
margin: -1px -1px 4px -1px;
margin: -1px 9px 4px 9px;
}
.thumbnailImage {
@ -1295,11 +1545,12 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
#outlineView,
#attachmentsView {
position: absolute;
width: 192px;
width: calc(100% - 8px);
top: 0;
bottom: 0;
overflow: auto;
-moz-user-select: none;
-webkit-overflow-scrolling: touch;
user-select: none;
}
#outlineView {
@ -1332,7 +1583,7 @@ html[dir='rtl'] .outlineItem > .outlineItems {
color: hsla(0,0%,100%,.8);
font-size: 13px;
line-height: 15px;
-moz-user-select: none;
user-select: none;
white-space: normal;
}
@ -1428,7 +1679,6 @@ html[dir='rtl'] .outlineItemToggler::before {
so we can override the opaque grey background when the window is inactive;
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
::selection { background: rgba(0,0,255,0.3); }
::-moz-selection { background: rgba(0,0,255,0.3); }
#errorWrapper {
background: none repeat scroll 0 0 #FF5555;
@ -1476,6 +1726,7 @@ html[dir='rtl'] .outlineItemToggler::before {
}
#overlayContainer > * {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#overlayContainer > .container {
@ -1599,6 +1850,7 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
bottom: 0;
left: 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
right: 0;
top: 27px;
@ -1637,19 +1889,19 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
mix-blend-mode: screen;
}
#viewer.textLayer-visible .textLayer > div {
#viewer.textLayer-visible .textLayer > span {
background-color: rgba(255, 255, 0, 0.1);
color: black;
border: solid 1px rgba(255, 0, 0, 0.5);
box-sizing: border-box;
}
#viewer.textLayer-hover .textLayer > div:hover {
#viewer.textLayer-hover .textLayer > span:hover {
background-color: white;
color: black;
}
#viewer.textLayer-shadow .textLayer > div {
#viewer.textLayer-shadow .textLayer > span {
background-color: rgba(255,255,255, .6);
color: black;
}
@ -1685,7 +1937,7 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
display: none;
}
@media screen and (min-resolution: 2dppx) {
@media screen and (min-resolution: 1.1dppx) {
/* Rules for Retina screens */
.toolbarButton::before {
transform: scale(0.5);
@ -1830,10 +2082,38 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
content: url(images/secondaryToolbarButton-rotateCw@2x.png);
}
.secondaryToolbarButton.selectTool::before {
content: url(images/secondaryToolbarButton-selectTool@2x.png);
}
.secondaryToolbarButton.handTool::before {
content: url(images/secondaryToolbarButton-handTool@2x.png);
}
.secondaryToolbarButton.scrollVertical::before {
content: url(images/secondaryToolbarButton-scrollVertical@2x.png);
}
.secondaryToolbarButton.scrollHorizontal::before {
content: url(images/secondaryToolbarButton-scrollHorizontal@2x.png);
}
.secondaryToolbarButton.scrollWrapped::before {
content: url(images/secondaryToolbarButton-scrollWrapped@2x.png);
}
.secondaryToolbarButton.spreadNone::before {
content: url(images/secondaryToolbarButton-spreadNone@2x.png);
}
.secondaryToolbarButton.spreadOdd::before {
content: url(images/secondaryToolbarButton-spreadOdd@2x.png);
}
.secondaryToolbarButton.spreadEven::before {
content: url(images/secondaryToolbarButton-spreadEven@2x.png);
}
.secondaryToolbarButton.documentProperties::before {
content: url(images/secondaryToolbarButton-documentProperties@2x.png);
}
@ -1927,28 +2207,6 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
display: none;
}
@media all and (max-width: 1040px) {
#outerContainer.sidebarMoving #toolbarViewerMiddle,
#outerContainer.sidebarOpen #toolbarViewerMiddle {
display: table;
margin: auto;
left: auto;
position: inherit;
transform: none;
}
}
@media all and (max-width: 980px) {
.sidebarMoving .hiddenLargeView,
.sidebarOpen .hiddenLargeView {
display: none;
}
.sidebarMoving .visibleLargeView,
.sidebarOpen .visibleLargeView {
display: inherit;
}
}
@media all and (max-width: 900px) {
#toolbarViewerMiddle {
display: table;
@ -1957,34 +2215,18 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
position: inherit;
transform: none;
}
.sidebarMoving .hiddenMediumView,
.sidebarOpen .hiddenMediumView {
display: none;
}
.sidebarMoving .visibleMediumView,
.sidebarOpen .visibleMediumView {
display: inherit;
}
}
@media all and (max-width: 840px) {
#sidebarContainer {
top: 32px;
z-index: 100;
}
.loadingInProgress #sidebarContainer {
top: 37px;
}
#sidebarContent {
top: 32px;
background-color: hsla(0,0%,0%,.7);
}
html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
left: 0px;
html[dir='ltr'] #outerContainer.sidebarOpen #viewerContainer {
left: 0px !important;
}
html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
right: 0px;
html[dir='rtl'] #outerContainer.sidebarOpen #viewerContainer {
right: 0px !important;
}
#outerContainer .hiddenLargeView,
@ -2016,7 +2258,7 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
}
@media all and (max-width: 640px) {
.hiddenSmallView {
.hiddenSmallView, .hiddenSmallView * {
display: none;
}
.visibleSmallView {
@ -2025,6 +2267,12 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
.toolbarButtonSpacer {
width: 0;
}
html[dir='ltr'] .findbar {
left: 38px;
}
html[dir='rtl'] .findbar {
right: 38px;
}
}
@media all and (max-width: 535px) {

View file

@ -20,7 +20,7 @@ Adobe CMap resources are covered by their own copyright but the same license:
See https://github.com/adobe-type-tools/cmap-resources
-->
<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
<html dir="ltr" mozdisallowselectionprint>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
@ -28,7 +28,6 @@ See https://github.com/adobe-type-tools/cmap-resources
<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
<base href="resource://pdf.js/web/">
<script src="l10n.js"></script>
<script src="../build/pdf.js"></script>
@ -36,9 +35,6 @@ See https://github.com/adobe-type-tools/cmap-resources
<script src="viewer.js"></script>
</head>
@ -49,13 +45,13 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="sidebarContainer">
<div id="toolbarSidebar">
<div class="splitToolbarButton toggled">
<button id="viewThumbnail" class="toolbarButton group toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
<button id="viewThumbnail" class="toolbarButton toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
<span data-l10n-id="thumbs_label">Thumbnails</span>
</button>
<button id="viewOutline" class="toolbarButton group" title="Show Document Outline (double-click to expand/collapse all items)" tabindex="3" data-l10n-id="document_outline">
<button id="viewOutline" class="toolbarButton" title="Show Document Outline (double-click to expand/collapse all items)" tabindex="3" data-l10n-id="document_outline">
<span data-l10n-id="document_outline_label">Document Outline</span>
</button>
<button id="viewAttachments" class="toolbarButton group" title="Show Attachments" tabindex="4" data-l10n-id="attachments">
<button id="viewAttachments" class="toolbarButton" title="Show Attachments" tabindex="4" data-l10n-id="attachments">
<span data-l10n-id="attachments_label">Attachments</span>
</button>
</div>
@ -68,27 +64,39 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="attachmentsView" class="hidden">
</div>
</div>
<div id="sidebarResizer" class="hidden"></div>
</div> <!-- sidebarContainer -->
<div id="mainContainer">
<div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
<label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:</label>
<input id="findInput" class="toolbarField" tabindex="91">
<div class="splitToolbarButton">
<button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="92" data-l10n-id="find_previous">
<span data-l10n-id="find_previous_label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button class="toolbarButton findNext" title="" id="findNext" tabindex="93" data-l10n-id="find_next">
<span data-l10n-id="find_next_label">Next</span>
</button>
<div class="findbar hidden doorHanger" id="findbar">
<div id="findbarInputContainer">
<input id="findInput" class="toolbarField" title="Find" placeholder="Find in document…" tabindex="91" data-l10n-id="find_input">
<div class="splitToolbarButton">
<button id="findPrevious" class="toolbarButton findPrevious" title="Find the previous occurrence of the phrase" tabindex="92" data-l10n-id="find_previous">
<span data-l10n-id="find_previous_label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button id="findNext" class="toolbarButton findNext" title="Find the next occurrence of the phrase" tabindex="93" data-l10n-id="find_next">
<span data-l10n-id="find_next_label">Next</span>
</button>
</div>
</div>
<div id="findbarOptionsOneContainer">
<input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
<label for="findHighlightAll" class="toolbarLabel" data-l10n-id="find_highlight">Highlight all</label>
<input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
<label for="findMatchCase" class="toolbarLabel" data-l10n-id="find_match_case_label">Match case</label>
</div>
<div id="findbarOptionsTwoContainer">
<input type="checkbox" id="findEntireWord" class="toolbarField" tabindex="96">
<label for="findEntireWord" class="toolbarLabel" data-l10n-id="find_entire_word_label">Whole words</label>
<span id="findResultsCount" class="toolbarLabel hidden"></span>
</div>
<div id="findbarMessageContainer">
<span id="findMsg" class="toolbarLabel"></span>
</div>
<input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
<label for="findHighlightAll" class="toolbarLabel" data-l10n-id="find_highlight">Highlight all</label>
<input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
<label for="findMatchCase" class="toolbarLabel" data-l10n-id="find_match_case_label">Match case</label>
<span id="findResultsCount" class="toolbarLabel hidden"></span>
<span id="findMsg" class="toolbarLabel"></span>
</div> <!-- findbar -->
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
@ -133,13 +141,40 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="horizontalToolbarSeparator"></div>
<button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="60" data-l10n-id="hand_tool_enable">
<span data-l10n-id="hand_tool_enable_label">Enable hand tool</span>
<button id="cursorSelectTool" class="secondaryToolbarButton selectTool toggled" title="Enable Text Selection Tool" tabindex="60" data-l10n-id="cursor_text_select_tool">
<span data-l10n-id="cursor_text_select_tool_label">Text Selection Tool</span>
</button>
<button id="cursorHandTool" class="secondaryToolbarButton handTool" title="Enable Hand Tool" tabindex="61" data-l10n-id="cursor_hand_tool">
<span data-l10n-id="cursor_hand_tool_label">Hand Tool</span>
</button>
<div class="horizontalToolbarSeparator"></div>
<button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="61" data-l10n-id="document_properties">
<button id="scrollVertical" class="secondaryToolbarButton scrollModeButtons scrollVertical toggled" title="Use Vertical Scrolling" tabindex="62" data-l10n-id="scroll_vertical">
<span data-l10n-id="scroll_vertical_label">Vertical Scrolling</span>
</button>
<button id="scrollHorizontal" class="secondaryToolbarButton scrollModeButtons scrollHorizontal" title="Use Horizontal Scrolling" tabindex="63" data-l10n-id="scroll_horizontal">
<span data-l10n-id="scroll_horizontal_label">Horizontal Scrolling</span>
</button>
<button id="scrollWrapped" class="secondaryToolbarButton scrollModeButtons scrollWrapped" title="Use Wrapped Scrolling" tabindex="64" data-l10n-id="scroll_wrapped">
<span data-l10n-id="scroll_wrapped_label">Wrapped Scrolling</span>
</button>
<div class="horizontalToolbarSeparator scrollModeButtons"></div>
<button id="spreadNone" class="secondaryToolbarButton spreadModeButtons spreadNone toggled" title="Do not join page spreads" tabindex="65" data-l10n-id="spread_none">
<span data-l10n-id="spread_none_label">No Spreads</span>
</button>
<button id="spreadOdd" class="secondaryToolbarButton spreadModeButtons spreadOdd" title="Join page spreads starting with odd-numbered pages" tabindex="66" data-l10n-id="spread_odd">
<span data-l10n-id="spread_odd_label">Odd Spreads</span>
</button>
<button id="spreadEven" class="secondaryToolbarButton spreadModeButtons spreadEven" title="Join page spreads starting with even-numbered pages" tabindex="67" data-l10n-id="spread_even">
<span data-l10n-id="spread_even_label">Even Spreads</span>
</button>
<div class="horizontalToolbarSeparator spreadModeButtons"></div>
<button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="68" data-l10n-id="document_properties">
<span data-l10n-id="document_properties_label">Document Properties…</span>
</button>
</div>
@ -153,10 +188,10 @@ See https://github.com/adobe-type-tools/cmap-resources
<span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
</button>
<div class="toolbarButtonSpacer"></div>
<button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="12" data-l10n-id="findbar">
<span data-l10n-id="findbar_label">Find</span>
<button id="viewFind" class="toolbarButton" title="Find in Document" tabindex="12" data-l10n-id="findbar">
<span data-l10n-id="findbar_label">Find</span>
</button>
<div class="splitToolbarButton">
<div class="splitToolbarButton hiddenSmallView">
<button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="13" data-l10n-id="previous">
<span data-l10n-id="previous_label">Previous</span>
</button>
@ -208,8 +243,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
<option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
<option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
<option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Page Fit</option>
<option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Page Width</option>
<option id="customScaleOption" title="" value="custom" disabled="disabled" hidden="true"></option>
<option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option>
<option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option>
@ -274,8 +309,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<p id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</p>
</div>
<div class="row">
<!-- The type="password" attribute is set via script, to prevent warnings in Firefox for all http:// documents. -->
<input id="password" class="toolbarField">
<input type="password" id="password" class="toolbarField">
</div>
<div class="buttonRow">
<button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>
@ -323,6 +357,13 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="row">
<span data-l10n-id="document_properties_page_count">Page Count:</span> <p id="pageCountField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_page_size">Page Size:</span> <p id="pageSizeField">-</p>
</div>
<div class="separator"></div>
<div class="row">
<span data-l10n-id="document_properties_linearized">Fast Web View:</span> <p id="linearizedField">-</p>
</div>
<div class="buttonRow">
<button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Close</span></button>
</div>

File diff suppressed because it is too large Load diff

View file

@ -224,7 +224,4 @@ res/table-remove-column.gif
res/table-remove-row-active.gif
res/table-remove-row-hover.gif
res/table-remove-row.gif
# Aurora branding
browser/chrome/browser/content/browser/defaultthemes/devedition.icon.png
browser/chrome/browser/content/branding/icon64.png
browser/chrome/devtools/content/framework/dev-edition-promo/dev-edition-logo.png

View file

@ -74,8 +74,10 @@
@BINPATH@/@DLL_PREFIX@gkmedias@DLL_SUFFIX@
#endif
#ifndef MOZ_SYSTEM_HUNSPELL
#ifndef XP_SOLARIS
@BINPATH@/@DLL_PREFIX@hunspell@DLL_SUFFIX@
#endif
#endif
#ifndef MOZ_SYSTEM_NSPR
#ifndef MOZ_FOLD_LIBS
@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@

View file

@ -106,10 +106,6 @@ unsignedAddonsDisabled.message=One or more installed add-ons cannot be verified
unsignedAddonsDisabled.learnMore.label=Learn More
unsignedAddonsDisabled.learnMore.accesskey=L
# LOCALIZATION NOTE (deveditionTheme.name): This should be nearly the brand name for aurora.
# See browser/branding/aurora/locales/*/brand.properties
deveditionTheme.name=Developer Edition
# LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
# the host name of the site.
lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
@ -608,17 +604,6 @@ appmenu.downloadUpdateButton.label = Download Update
readingList.promo.firstUse.readerView.title = Reader View
readingList.promo.firstUse.readerView.body = Remove clutter so you can focus exactly on what you want to read.
# LOCALIZATION NOTE (appMenuRemoteTabs.mobilePromo.text2):
# %1$S will be replaced with a link, the text of which is
# appMenuRemoteTabs.mobilePromo.android and the link will be to
# https://www.mozilla.org/firefox/android/.
# %2$S will be replaced with a link, the text of which is
# appMenuRemoteTabs.mobilePromo.ios
# and the link will be to https://www.mozilla.org/firefox/ios/.
appMenuRemoteTabs.mobilePromo.text2 = Download %1$S or %2$S and connect them to your Firefox Account.
appMenuRemoteTabs.mobilePromo.android = Firefox for Android
appMenuRemoteTabs.mobilePromo.ios = Firefox for iOS
# LOCALIZATION NOTE (e10s.accessibilityNotice.mainMessage,
# e10s.accessibilityNotice.enableAndRestart.label,
# e10s.accessibilityNotice.enableAndRestart.accesskey):
@ -673,14 +658,6 @@ weakCryptoOverriding.message = %S recommends that you dont enter your passwor
revokeOverride.label = Dont Trust This Website
revokeOverride.accesskey = D
# LOCALIZATION NOTE (pendingCrashReports2.label): Semi-colon list of plural forms
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 is the number of pending crash reports
pendingCrashReports2.label = You have an unsent crash report;You have #1 unsent crash reports
pendingCrashReports.viewAll = View
pendingCrashReports.send = Send
pendingCrashReports.alwaysSend = Always Send
decoder.noCodecs.button = Learn how
decoder.noCodecs.accesskey = L
decoder.noCodecs.message = To play video, you may need to install Microsofts Media Feature Pack.

View file

@ -38,7 +38,6 @@
<!ENTITY crashReporterDesc2.label "Crash reports help &vendorShortName; fix problems and make your browser more stable and secure">
<!ENTITY alwaysSubmitCrashReports.label "Allow &brandShortName; to send backlogged crash reports on your behalf">
<!ENTITY alwaysSubmitCrashReports.accesskey "c">
<!ENTITY crashReporterLearnMore.label "Learn More">
<!ENTITY networkTab.label "Network">

View file

@ -77,7 +77,7 @@
locale/browser/preferences/preferences.dtd (%chrome/browser/preferences/preferences.dtd)
locale/browser/preferences/preferences.properties (%chrome/browser/preferences/preferences.properties)
locale/browser/preferences/containers.properties (%chrome/browser/preferences/containers.properties)
* locale/browser/preferences/privacy.dtd (%chrome/browser/preferences/privacy.dtd)
locale/browser/preferences/privacy.dtd (%chrome/browser/preferences/privacy.dtd)
locale/browser/preferences/security.dtd (%chrome/browser/preferences/security.dtd)
locale/browser/preferences/containers.dtd (%chrome/browser/preferences/containers.dtd)
#ifdef MOZ_SERVICES_SYNC

View file

@ -10,8 +10,7 @@ var Cu = Components.utils;
var Cr = Components.results;
this.EXPORTED_SYMBOLS = [ "TabCrashHandler",
"PluginCrashReporter",
"UnsubmittedCrashHandler" ];
"PluginCrashReporter" ];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -50,11 +49,6 @@ this.TabCrashHandler = {
unseenCrashedChildIDs: [],
crashedBrowserQueues: new Map(),
get prefs() {
delete this.prefs;
return this.prefs = Services.prefs.getBranch("browser.tabs.crashReporting.");
},
init: function () {
if (this.initialized)
return;
@ -140,19 +134,16 @@ this.TabCrashHandler = {
}
case "closeTab": {
this.maybeSendCrashReport(message);
gBrowser.removeTab(tab, { animate: true });
break;
}
case "restoreTab": {
this.maybeSendCrashReport(message);
SessionStore.reviveCrashedTab(tab);
break;
}
case "restoreAll": {
this.maybeSendCrashReport(message);
SessionStore.reviveAllCrashedTabs();
break;
}
@ -245,20 +236,9 @@ this.TabCrashHandler = {
// 1) We are aware that this browser crashed
// 2) We know we've never shown the tab crash page for the
// crash yet
// 3) The user is not configured to automatically submit backlogged
// crash reports. If they are, we'll send the crash report
// immediately.
if (childID &&
this.unseenCrashedChildIDs.indexOf(childID) != -1) {
if (UnsubmittedCrashHandler.autoSubmit) {
let dumpID = this.childMap.get(childID);
if (dumpID) {
UnsubmittedCrashHandler.submitReports([dumpID]);
}
} else {
this.sendToTabCrashedPage(browser);
return true;
}
if (childID && this.unseenCrashedChildIDs.indexOf(childID) != -1) {
this.sendToTabCrashedPage(browser);
return true;
}
return false;
@ -286,15 +266,6 @@ this.TabCrashHandler = {
tab.setAttribute("crashed", true);
},
/**
* Submits a crash report from about:tabcrashed, if the crash
* reporter is enabled and a crash report can be found.
*/
maybeSendCrashReport(message) {
/*** STUB ***/
return;
},
removeSubmitCheckboxesForSameCrash: function(childID) {
let enumerator = Services.wm.getEnumerator("navigator:browser");
while (enumerator.hasMoreElements()) {
@ -342,34 +313,10 @@ this.TabCrashHandler = {
this.unseenCrashedChildIDs.splice(index, 1);
}
let dumpID = this.getDumpID(browser);
if (!dumpID) {
message.target.sendAsyncMessage("SetCrashReportAvailable", {
hasReport: false,
});
return;
}
let requestAutoSubmit = !UnsubmittedCrashHandler.autoSubmit;
let requestEmail = this.prefs.getBoolPref("requestEmail");
let sendReport = this.prefs.getBoolPref("sendReport");
let includeURL = this.prefs.getBoolPref("includeURL");
let emailMe = this.prefs.getBoolPref("emailMe");
let data = {
hasReport: true,
sendReport,
includeURL,
emailMe,
requestAutoSubmit,
requestEmail,
};
if (emailMe) {
data.email = this.prefs.getCharPref("email", "");
}
message.target.sendAsyncMessage("SetCrashReportAvailable", data);
message.target.sendAsyncMessage("SetCrashReportAvailable", {
hasReport: false,
});
return;
},
onAboutTabCrashedUnload(message) {
@ -391,382 +338,8 @@ this.TabCrashHandler = {
let childID = this.browserMap.get(browser.permanentKey);
},
/**
* For some <xul:browser>, return a crash report dump ID for that browser
* if we have been informed of one. Otherwise, return null.
*/
getDumpID(browser) {
/*** STUB ***/
return null;
},
}
/**
* This component is responsible for scanning the pending
* crash report directory for reports, and (if enabled), to
* prompt the user to submit those reports. It might also
* submit those reports automatically without prompting if
* the user has opted in.
*/
this.UnsubmittedCrashHandler = {
get prefs() {
delete this.prefs;
return this.prefs =
Services.prefs.getBranch("browser.crashReports.unsubmittedCheck.");
},
get enabled() {
return this.prefs.getBoolPref("enabled");
},
// showingNotification is set to true once a notification
// is successfully shown, and then set back to false if
// the notification is dismissed by an action by the user.
showingNotification: false,
// suppressed is true if we've determined that we've shown
// the notification too many times across too many days without
// user interaction, so we're suppressing the notification for
// some number of days. See the documentation for
// shouldShowPendingSubmissionsNotification().
suppressed: false,
init() {
if (this.initialized) {
return;
}
this.initialized = true;
// UnsubmittedCrashHandler can be initialized but still be disabled.
// This is intentional, as this makes simulating UnsubmittedCrashHandler's
// reactions to browser startup and shutdown easier in test automation.
//
// UnsubmittedCrashHandler, when initialized but not enabled, is inert.
if (this.enabled) {
if (this.prefs.prefHasUserValue("suppressUntilDate")) {
if (this.prefs.getCharPref("suppressUntilDate") > this.dateString()) {
// We'll be suppressing any notifications until after suppressedDate,
// so there's no need to do anything more.
this.suppressed = true;
return;
}
// We're done suppressing, so we don't need this pref anymore.
this.prefs.clearUserPref("suppressUntilDate");
}
Services.obs.addObserver(this, "browser-delayed-startup-finished",
false);
Services.obs.addObserver(this, "profile-before-change",
false);
}
},
uninit() {
if (!this.initialized) {
return;
}
this.initialized = false;
if (!this.enabled) {
return;
}
if (this.suppressed) {
this.suppressed = false;
// No need to do any more clean-up, since we were suppressed.
return;
}
if (this.showingNotification) {
this.prefs.setBoolPref("shutdownWhileShowing", true);
this.showingNotification = false;
}
try {
Services.obs.removeObserver(this, "browser-delayed-startup-finished");
} catch (e) {
// The browser-delayed-startup-finished observer might have already
// fired and removed itself, so if this fails, it's okay.
if (e.result != Cr.NS_ERROR_FAILURE) {
throw e;
}
}
Services.obs.removeObserver(this, "profile-before-change");
},
observe(subject, topic, data) {
switch (topic) {
case "browser-delayed-startup-finished": {
Services.obs.removeObserver(this, topic);
this.checkForUnsubmittedCrashReports();
break;
}
case "profile-before-change": {
this.uninit();
break;
}
}
},
/**
* Scans the profile directory for unsubmitted crash reports
* within the past PENDING_CRASH_REPORT_DAYS days. If it
* finds any, it will, if necessary, attempt to open a notification
* bar to prompt the user to submit them.
*
* @returns Promise
* Resolves with the <xul:notification> after it tries to
* show a notification on the most recent browser window.
* If a notification cannot be shown, will resolve with null.
*/
checkForUnsubmittedCrashReports: Task.async(function*() {
let dateLimit = new Date();
dateLimit.setDate(dateLimit.getDate() - PENDING_CRASH_REPORT_DAYS);
let reportIDs = [];
try {
reportIDs = yield CrashSubmit.pendingIDsAsync(dateLimit);
} catch (e) {
Cu.reportError(e);
return null;
}
if (reportIDs.length) {
if (this.autoSubmit) {
this.submitReports(reportIDs);
} else if (this.shouldShowPendingSubmissionsNotification()) {
return this.showPendingSubmissionsNotification(reportIDs);
}
}
return null;
}),
/**
* Returns true if the notification should be shown.
* shouldShowPendingSubmissionsNotification makes this decision
* by looking at whether or not the user has seen the notification
* over several days without ever interacting with it. If this occurs
* too many times, we suppress the notification for DAYS_TO_SUPPRESS
* days.
*
* @returns bool
*/
shouldShowPendingSubmissionsNotification() {
if (!this.prefs.prefHasUserValue("shutdownWhileShowing")) {
return true;
}
let shutdownWhileShowing = this.prefs.getBoolPref("shutdownWhileShowing");
this.prefs.clearUserPref("shutdownWhileShowing");
if (!this.prefs.prefHasUserValue("lastShownDate")) {
// This isn't expected, but we're being defensive here. We'll
// opt for showing the notification in this case.
return true;
}
let lastShownDate = this.prefs.getCharPref("lastShownDate");
if (this.dateString() > lastShownDate && shutdownWhileShowing) {
// We're on a newer day then when we last showed the
// notification without closing it. We don't want to do
// this too many times, so we'll decrement a counter for
// this situation. Too many of these, and we'll assume the
// user doesn't know or care about unsubmitted notifications,
// and we'll suppress the notification for a while.
let chances = this.prefs.getIntPref("chancesUntilSuppress");
if (--chances < 0) {
// We're out of chances!
this.prefs.clearUserPref("chancesUntilSuppress");
// We'll suppress for DAYS_TO_SUPPRESS days.
let suppressUntil =
this.dateString(new Date(Date.now() + (DAY * DAYS_TO_SUPPRESS)));
this.prefs.setCharPref("suppressUntilDate", suppressUntil);
return false;
}
this.prefs.setIntPref("chancesUntilSuppress", chances);
}
return true;
},
/**
* Given an array of unsubmitted crash report IDs, try to open
* up a notification asking the user to submit them.
*
* @param reportIDs (Array<string>)
* The Array of report IDs to offer the user to send.
* @returns The <xul:notification> if one is shown. null otherwise.
*/
showPendingSubmissionsNotification(reportIDs) {
let count = reportIDs.length;
if (!count) {
return null;
}
let messageTemplate =
gNavigatorBundle.GetStringFromName("pendingCrashReports2.label");
let message = PluralForm.get(count, messageTemplate).replace("#1", count);
let notification = this.show({
notificationID: "pending-crash-reports",
message,
reportIDs,
onAction: () => {
this.showingNotification = false;
},
});
if (notification) {
this.showingNotification = true;
this.prefs.setCharPref("lastShownDate", this.dateString());
}
return notification;
},
/**
* Returns a string representation of a Date in the format
* YYYYMMDD.
*
* @param someDate (Date, optional)
* The Date to convert to the string. If not provided,
* defaults to today's date.
* @returns String
*/
dateString(someDate = new Date()) {
let year = String(someDate.getFullYear()).padStart(4, "0");
let month = String(someDate.getMonth() + 1).padStart(2, "0");
let day = String(someDate.getDate()).padStart(2, "0");
return year + month + day;
},
/**
* Attempts to show a notification bar to the user in the most
* recent browser window asking them to submit some crash report
* IDs. If a notification cannot be shown (for example, there
* is no browser window), this method exits silently.
*
* The notification will allow the user to submit their crash
* reports. If the user dismissed the notification, the crash
* reports will be marked to be ignored (though they can
* still be manually submitted via about:crashes).
*
* @param JS Object
* An Object with the following properties:
*
* notificationID (string)
* The ID for the notification to be opened.
*
* message (string)
* The message to be displayed in the notification.
*
* reportIDs (Array<string>)
* The array of report IDs to offer to the user.
*
* onAction (function, optional)
* A callback to fire once the user performs an
* action on the notification bar (this includes
* dismissing the notification).
*
* @returns The <xul:notification> if one is shown. null otherwise.
*/
show({ notificationID, message, reportIDs, onAction }) {
let chromeWin = RecentWindow.getMostRecentBrowserWindow();
if (!chromeWin) {
// Can't show a notification in this case. We'll hopefully
// get another opportunity to have the user submit their
// crash reports later.
return null;
}
let nb = chromeWin.document.getElementById("global-notificationbox");
let notification = nb.getNotificationWithValue(notificationID);
if (notification) {
return null;
}
let buttons = [{
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.send"),
callback: () => {
this.submitReports(reportIDs);
if (onAction) {
onAction();
}
},
},
{
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.alwaysSend"),
callback: () => {
this.autoSubmit = true;
this.submitReports(reportIDs);
if (onAction) {
onAction();
}
},
},
{
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.viewAll"),
callback: function() {
chromeWin.openUILinkIn("about:crashes", "tab");
return true;
},
}];
let eventCallback = (eventType) => {
if (eventType == "dismissed") {
// The user intentionally dismissed the notification,
// which we interpret as meaning that they don't care
// to submit the reports. We'll ignore these particular
// reports going forward.
reportIDs.forEach(function(reportID) {
CrashSubmit.ignore(reportID);
});
if (onAction) {
onAction();
}
}
};
return nb.appendNotification(message, notificationID,
"chrome://browser/skin/tab-crashed.svg",
nb.PRIORITY_INFO_HIGH, buttons,
eventCallback);
},
get autoSubmit() {
return Services.prefs
.getBoolPref("browser.crashReports.unsubmittedCheck.autoSubmit2");
},
set autoSubmit(val) {
Services.prefs.setBoolPref("browser.crashReports.unsubmittedCheck.autoSubmit2",
val);
},
/**
* Attempt to submit reports to the crash report server. Each
* report will have the "SubmittedFromInfobar" extra key set
* to true.
*
* @param reportIDs (Array<string>)
* The array of reportIDs to submit.
*/
submitReports(reportIDs) {
for (let reportID of reportIDs) {
CrashSubmit.submit(reportID, {
extraExtraKeyVals: {
"SubmittedFromInfobar": true,
},
});
}
},
};
this.PluginCrashReporter = {
/**
* Makes the PluginCrashReporter ready to hear about and

View file

@ -608,11 +608,6 @@ PluginContent.prototype = {
{ name, pluginTag });
},
submitReport: function submitReport(plugin) {
/*** STUB ***/
return;
},
reloadPage: function () {
this.global.content.location.reload();
},
@ -982,7 +977,6 @@ PluginContent.prototype = {
.addEventListener("click", (event) => {
if (event.button != 0 || !event.isTrusted)
return;
this.submitReport(plugin);
});
let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -289,9 +289,7 @@ description > html|a {
margin-inline-end: 4px; /* add the 4px end-margin of other elements */
}
#telemetryLearnMore,
#FHRLearnMore,
#crashReporterLearnMore {
#FHRLearnMore {
/* provide some margin between the links and the label text */
/* !important is needed to override the rules defined in common.css */
margin-inline-start: 20px !important;
@ -542,11 +540,6 @@ description > html|a {
margin-inline-end: 14px;
}
.fxaMobilePromo {
margin-bottom: 20px;
margin-top: 25px;
}
#fxaLoginRejectedWarning {
list-style-image: url(chrome://browser/skin/warning.svg);
filter: drop-shadow(0 1px 0 hsla(206, 50%, 10%, .15));
@ -557,36 +550,12 @@ description > html|a {
margin-bottom: 27.5px;
}
.androidLink {
background-image: url("chrome://browser/skin/fxa/android.png");
}
.iOSLink {
background-image: url("chrome://browser/skin/fxa/ios.png");
}
.androidLink,
.iOSLink {
margin: 0 0 0 2px;
padding-left: 28px;
padding-top: 6px;
height: 28px;
background-repeat: no-repeat;
background-size: 24px 28px;
}
#tosPP-small {
margin-top: 20px;
margin-bottom: 20px;
}
@media (min-resolution: 1.1dppx) {
.androidLink {
background-image: url("chrome://browser/skin/fxa/android@2x.png");
}
.iOSLink {
background-image: url("chrome://browser/skin/fxa/ios@2x.png");
}
.fxaSyncIllustration {
list-style-image: url(chrome://browser/skin/fxa/sync-illustration@2x.png)
}

View file

@ -81,10 +81,6 @@
skin/classic/browser/fxa/sync-illustration.png (../shared/fxa/sync-illustration.png)
skin/classic/browser/fxa/sync-illustration@2x.png (../shared/fxa/sync-illustration@2x.png)
skin/classic/browser/fxa/sync-illustration.svg (../shared/fxa/sync-illustration.svg)
skin/classic/browser/fxa/android.png (../shared/fxa/android.png)
skin/classic/browser/fxa/android@2x.png (../shared/fxa/android@2x.png)
skin/classic/browser/fxa/ios.png (../shared/fxa/ios.png)
skin/classic/browser/fxa/ios@2x.png (../shared/fxa/ios@2x.png)
skin/classic/browser/search-indicator.png (../shared/search/search-indicator.png)
skin/classic/browser/search-indicator@2x.png (../shared/search/search-indicator@2x.png)
skin/classic/browser/search-engine-placeholder.png (../shared/search/search-engine-placeholder.png)

View file

@ -500,6 +500,9 @@ pref("browser.bookmarks.autoExportHTML", false);
// 0: no backups created (and deletes all existing backups)
pref("browser.bookmarks.max_backups", 10);
// Whether menu should close after Ctrl-click, middle-click, etc.
pref("browser.bookmarks.openInTabClosesMenu", true);
// Scripts & Windows prefs
pref("dom.disable_open_during_load", true);
pref("javascript.options.showInConsole", true);

View file

@ -371,6 +371,7 @@
placespopup="true"
context="placesContext"
openInTabs="children"
onmouseup="BookmarksEventHandler.onMouseUp(event);"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="PlacesCommandHook.updateBookmarkAllTabsCommand();

View file

@ -767,17 +767,46 @@ HistoryMenu.prototype = {
* Functions for handling events in the Bookmarks Toolbar and menu.
*/
var BookmarksEventHandler = {
/**
* Handler for mouseUp event for an item in the bookmarks toolbar or menu.
* When items are middle-clicked (or clicked with modifier), check if the
* menu should remain open.
* @param aEvent
* DOMEvent for the click
*/
onMouseUp(aEvent) {
// Handles left-click with modifier if not browser.bookmarks.openInTabClosesMenu.
if (aEvent.button != 0 ||
Services.prefs.getBoolPref("browser.bookmarks.openInTabClosesMenu", true))
return;
let target = aEvent.originalTarget;
if (target.tagName != "menuitem")
return;
#ifdef XP_MACOSX
var modifKey = aEvent.metaKey;
#else
var modifKey = aEvent.ctrlKey;
#endif
// Don't keep menu open for 'Open all in Tabs'.
if (modifKey && !target.classList.contains("openintabs-menuitem")) {
target.setAttribute("closemenu", "none");
}
},
/**
* Handler for click event for an item in the bookmarks toolbar or menu.
* Menus and submenus from the folder buttons bubble up to this handler.
* Left-click is handled in the onCommand function.
* When items are middle-clicked (or clicked with modifier), open in tabs.
* If the click came through a menu, close the menu.
* If the click came through a menu, close the menu unless preffed otherwise.
* @param aEvent
* DOMEvent for the click
* @param aView
* The places view which aEvent should be associated with.
*/
onClick: function(aEvent, aView) {
// Only handle middle-click or left-click with modifiers.
var modifKey = aEvent.ctrlKey || aEvent.shiftKey;
@ -786,19 +815,23 @@ var BookmarksEventHandler = {
}
var target = aEvent.originalTarget;
// If this event bubbled up from a menu or menuitem, close the menus.
// Do this before opening tabs, to avoid hiding the open tabs confirm-dialog.
if (target.localName == "menu" || target.localName == "menuitem") {
for (node = target.parentNode; node; node = node.parentNode) {
if (node.localName == "menupopup") {
node.hidePopup();
} else if (node.localName != "menu" &&
node.localName != "splitmenu" &&
node.localName != "hbox" &&
node.localName != "vbox" ) {
break;
}
}
// If this event bubbled up from a menu or menuitem,
// close the menus if browser.bookmarks.openInTabClosesMenu.
if ((Services.prefs.getBoolPref("browser.bookmarks.openInTabClosesMenu", true) &&
target.tagName == "menuitem") ||
target.tagName == "menu" ||
target.classList.contains("openintabs-menuitem")) {
closeMenus(aEvent.target);
}
// Command already precesssed so remove any closemenu attr set in onMouseUp.
if (aEvent.button == 0 &&
target.tagName == "menuitem" &&
target.getAttribute("closemenu") == "none") {
// On Mac we need to extend when we remove the flag, to avoid any pre-close
// animations.
setTimeout(() => {
target.removeAttribute("closemenu");
}, 500);
}
if (target._placesNode && PlacesUtils.nodeIsContainer(target._placesNode)) {

View file

@ -548,6 +548,7 @@
placespopup="true"
context="placesContext"
openInTabs="children"
onmouseup="BookmarksEventHandler.onMouseUp(event);"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
onclick="event.stopPropagation();
BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
@ -704,6 +705,7 @@
<hbox flex="1"
id="PlacesToolbar"
context="placesContext"
onmouseup="BookmarksEventHandler.onMouseUp(event);"
onclick="BookmarksEventHandler.onClick(event, this._placesView);"
oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
tooltip="bhTooltip"

View file

@ -100,6 +100,10 @@
<menupopup id="placesContext"
onpopupshowing="this._view = PlacesUIUtils.getViewForNode(document.popupNode);
if (!PlacesUIUtils.openInTabClosesMenu) {
document.getElementById ('placesContext_open:newtab')
.setAttribute('closemenu', 'single');
}
return this._view.buildContextMenu(this);"
onpopuphiding="this._view.destroyContextMenu();">
<menuitem id="placesContext_open"

View file

@ -67,8 +67,10 @@
@BINPATH@/@DLL_PREFIX@gkmedias@DLL_SUFFIX@
#endif
#ifndef MOZ_SYSTEM_HUNSPELL
#ifndef XP_SOLARIS
@BINPATH@/@DLL_PREFIX@hunspell@DLL_SUFFIX@
#endif
#endif
#ifndef MOZ_SYSTEM_NSPR
#ifndef MOZ_FOLD_LIBS
@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@