Merge remote-tracking branch 'origin/tracking' into custom
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 95 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
|
@ -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.
|
||||
|
|
@ -4123,7 +4123,7 @@
|
|||
},
|
||||
|
||||
/*
|
||||
* Telemetry and Profiler related helpers for recording tab switch
|
||||
* Profiler related helpers for recording tab switch
|
||||
* timing.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -84,11 +84,6 @@ var gMainPane = {
|
|||
.notifyObservers(window, "main-pane-loaded", null);
|
||||
},
|
||||
|
||||
enableE10SChange: function ()
|
||||
{
|
||||
// **STUB**
|
||||
},
|
||||
|
||||
// HOME PAGE
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1832,7 +1832,6 @@
|
|||
return false;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
=======
|
||||
Firefox
|
||||
=======
|
||||
|
||||
This is the nascent documentation of the Firefox front-end code.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
DirectoryLinksProvider
|
||||
UITelemetry
|
||||
BrowserUsageTelemetry
|
||||
7
application/basilisk/extensions/pdfjs/README.basilisk
Normal 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
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.6.315
|
||||
|
|
@ -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;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
})();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}));
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 332 B |
|
After Width: | Height: | Size: 228 B |
|
After Width: | Height: | Size: 349 B |
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 490 B |
|
After Width: | Height: | Size: 461 B |
|
After Width: | Height: | Size: 1 KiB |
|
After Width: | Height: | Size: 347 B |
|
After Width: | Height: | Size: 694 B |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 344 B |
|
After Width: | Height: | Size: 621 B |
|
|
@ -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);
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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@
|
||||
|
|
|
|||
|
|
@ -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 don’t enter your passwor
|
|||
revokeOverride.label = Don’t 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 Microsoft’s Media Feature Pack.
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 468 B |
|
Before Width: | Height: | Size: 719 B |
|
Before Width: | Height: | Size: 711 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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@
|
||||
|
|
|
|||