Merge fx-team to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-03-17 13:12:50 -04:00
commit b1ea0b0fab
25 changed files with 1896 additions and 1291 deletions

View File

@ -44,9 +44,10 @@ let developerHUD = {
/**
* This method registers a metric watcher that will watch one or more metrics
* of apps that are being tracked. A watcher must implement the trackApp(app)
* and untrackApp(app) methods, add entries to the app.metrics map, keep them
* up-to-date, and call app.display() when values were changed.
* on app frames that are being tracked. A watcher must implement the
* `trackTarget(target)` and `untrackTarget(target)` methods, register
* observed metrics with `target.register(metric)`, and keep them up-to-date
* with `target.update(metric, value, message)` when necessary.
*/
registerWatcher: function dwp_registerWatcher(watcher) {
this._watchers.unshift(watcher);
@ -87,7 +88,7 @@ let developerHUD = {
});
});
SettingsListener.observe('hud.logging', enabled => {
SettingsListener.observe('hud.logging', this._logging, enabled => {
this._logging = enabled;
});
},
@ -194,9 +195,9 @@ let developerHUD = {
/**
* An App object represents all there is to know about a Firefox OS app that is
* being tracked, e.g. its manifest information, current values of watched
* metrics, and how to update these values on the front-end.
* A Target object represents all there is to know about a Firefox OS app frame
* that is being tracked, e.g. a pointer to the frame, current values of watched
* metrics, and how to notify the front-end when metrics have changed.
*/
function Target(frame, actor) {
this.frame = frame;
@ -276,17 +277,27 @@ Target.prototype = {
/**
* The Console Watcher tracks the following metrics in apps: reflows, warnings,
* and errors.
* and errors, with security errors reported separately.
*/
let consoleWatcher = {
_client: null,
_targets: new Map(),
_watching: {
reflows: false,
warnings: false,
errors: false
errors: false,
security: false
},
_client: null,
_security: [
'Mixed Content Blocker',
'Mixed Content Message',
'CSP',
'Invalid HSTS Headers',
'Insecure Password Field',
'SSL',
'CORS'
],
init: function cw_init(client) {
this._client = client;
@ -296,7 +307,7 @@ let consoleWatcher = {
for (let key in watching) {
let metric = key;
SettingsListener.observe('hud.' + metric, false, watch => {
SettingsListener.observe('hud.' + metric, watching[metric], watch => {
// Watch or unwatch the metric.
if (watching[metric] = watch) {
return;
@ -319,6 +330,7 @@ let consoleWatcher = {
target.register('reflows');
target.register('warnings');
target.register('errors');
target.register('security');
this._client.request({
to: target.actor.consoleActor,
@ -357,13 +369,17 @@ let consoleWatcher = {
output += 'error (';
}
if (this._security.indexOf(pageError.category) > -1) {
metric = 'security';
}
let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError;
output += category + '): "' + (errorMessage.initial || errorMessage) +
'" in ' + sourceName + ':' + lineNumber + ':' + columnNumber;
break;
case 'consoleAPICall':
switch (packet.output.level) {
switch (packet.message.level) {
case 'error':
metric = 'errors';

View File

@ -7,8 +7,9 @@
"use strict";
// Used to detect minification for automatic pretty printing
const SAMPLE_SIZE = 30; // no of lines
const INDENT_COUNT_THRESHOLD = 20; // percentage
const SAMPLE_SIZE = 50; // no of lines
const INDENT_COUNT_THRESHOLD = 5; // percentage
const CHARACTER_LIMIT = 250; // line character limit
/**
* Functions handling the sources UI.
@ -1500,6 +1501,7 @@ let SourceUtils = {
let lineStartIndex = 0;
let lines = 0;
let indentCount = 0;
let overCharLimit = false;
// Strip comments.
aText = aText.replace(/\/\*[\S\s]*?\*\/|\/\/(.+|\n)/g, "");
@ -1512,9 +1514,15 @@ let SourceUtils = {
if (/^\s+/.test(aText.slice(lineStartIndex, lineEndIndex))) {
indentCount++;
}
// For files with no indents but are not minified.
if ((lineEndIndex - lineStartIndex) > CHARACTER_LIMIT) {
overCharLimit = true;
break;
}
lineStartIndex = lineEndIndex + 1;
}
isMinified = ((indentCount / lines ) * 100) < INDENT_COUNT_THRESHOLD;
isMinified = ((indentCount / lines ) * 100) < INDENT_COUNT_THRESHOLD ||
overCharLimit;
this._minifiedCache.set(sourceClient, isMinified);
return isMinified;

View File

@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 0.8.1114
Current extension version is: 0.8.1181

View File

@ -61,6 +61,27 @@ function getIntPref(aPref, aDefaultValue) {
}
}
function initializeDefaultPreferences() {
Cu.import('resource://pdf.js/default_preferences.js');
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
var defaultValue;
for (var key in DEFAULT_PREFERENCES) {
defaultValue = DEFAULT_PREFERENCES[key];
switch (typeof defaultValue) {
case 'boolean':
defaultBranch.setBoolPref(key, defaultValue);
break;
case 'number':
defaultBranch.setIntPref(key, defaultValue);
break;
case 'string':
defaultBranch.setCharPref(key, defaultValue);
break;
}
}
}
// Register/unregister a constructor as a factory.
function Factory() {}
Factory.prototype = {
@ -104,6 +125,8 @@ let PdfJs = {
Services.obs.addObserver(this, TOPIC_PDFJS_HANDLER_CHANGED, false);
Services.obs.addObserver(this, TOPIC_PLUGINS_LIST_UPDATED, false);
Services.obs.addObserver(this, TOPIC_PLUGIN_INFO_UPDATED, false);
initializeDefaultPreferences();
},
_migrate: function migrate() {

View File

@ -16,7 +16,7 @@
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils,
dump, NetworkManager, PdfJsTelemetry, DEFAULT_PREFERENCES */
dump, NetworkManager, PdfJsTelemetry */
'use strict';
@ -33,16 +33,14 @@ const PDF_CONTENT_TYPE = 'application/pdf';
const PREF_PREFIX = 'pdfjs';
const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
const MAX_DATABASE_LENGTH = 4096;
const MAX_STRING_PREF_LENGTH = 4096;
const MAX_NUMBER_OF_PREFS = 50;
const MAX_STRING_PREF_LENGTH = 128;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/NetUtil.jsm');
Cu.import('resource://pdf.js/network.js');
// Load the default preferences.
Cu.import('resource://pdf.js/default_preferences.js');
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
'resource://gre/modules/PrivateBrowsingUtils.jsm');
@ -453,56 +451,60 @@ ChromeActions.prototype = {
.updateControlState(result, findPrevious);
},
setPreferences: function(prefs) {
var prefValue, defaultValue, prefName, prefType, defaultType;
for (var key in DEFAULT_PREFERENCES) {
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
var numberOfPrefs = 0;
var prefValue, prefName;
for (var key in prefs) {
if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) {
log('setPreferences - Exceeded the maximum number of preferences ' +
'that is allowed to be set at once.');
break;
} else if (!defaultBranch.getPrefType(key)) {
continue;
}
prefValue = prefs[key];
defaultValue = DEFAULT_PREFERENCES[key];
prefName = (PREF_PREFIX + '.' + key);
if (prefValue === undefined || prefValue === defaultValue) {
Services.prefs.clearUserPref(prefName);
} else {
prefType = typeof prefValue;
defaultType = typeof defaultValue;
if (prefType !== defaultType) {
continue;
}
switch (defaultType) {
case 'boolean':
setBoolPref(prefName, prefValue);
break;
case 'number':
setIntPref(prefName, prefValue);
break;
case 'string':
// Protect against adding arbitrarily long strings in about:config.
if (prefValue.length <= MAX_STRING_PREF_LENGTH) {
setStringPref(prefName, prefValue);
}
break;
}
switch (typeof prefValue) {
case 'boolean':
setBoolPref(prefName, prefValue);
break;
case 'number':
setIntPref(prefName, prefValue);
break;
case 'string':
if (prefValue.length > MAX_STRING_PREF_LENGTH) {
log('setPreferences - Exceeded the maximum allowed length ' +
'for a string preference.');
} else {
setStringPref(prefName, prefValue);
}
break;
}
}
},
getPreferences: function() {
var currentPrefs = {};
var defaultValue, prefName;
for (var key in DEFAULT_PREFERENCES) {
defaultValue = DEFAULT_PREFERENCES[key];
getPreferences: function(prefs) {
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
var currentPrefs = {}, numberOfPrefs = 0;
var prefValue, prefName;
for (var key in prefs) {
if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) {
log('getPreferences - Exceeded the maximum number of preferences ' +
'that is allowed to be fetched at once.');
break;
} else if (!defaultBranch.getPrefType(key)) {
continue;
}
prefValue = prefs[key];
prefName = (PREF_PREFIX + '.' + key);
switch (typeof defaultValue) {
switch (typeof prefValue) {
case 'boolean':
currentPrefs[key] = getBoolPref(prefName, defaultValue);
currentPrefs[key] = getBoolPref(prefName, prefValue);
break;
case 'number':
currentPrefs[key] = getIntPref(prefName, defaultValue);
currentPrefs[key] = getIntPref(prefName, prefValue);
break;
case 'string':
currentPrefs[key] = getStringPref(prefName, defaultValue);
currentPrefs[key] = getStringPref(prefName, prefValue);
break;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -46,13 +46,17 @@ var FontInspector = (function FontInspectorClosure() {
}
}
function textLayerClick(e) {
if (!e.target.dataset.fontName || e.target.tagName.toUpperCase() !== 'DIV')
if (!e.target.dataset.fontName ||
e.target.tagName.toUpperCase() !== 'DIV') {
return;
}
var fontName = e.target.dataset.fontName;
var selects = document.getElementsByTagName('input');
for (var i = 0; i < selects.length; ++i) {
var select = selects[i];
if (select.dataset.fontName != fontName) continue;
if (select.dataset.fontName != fontName) {
continue;
}
select.checked = !select.checked;
selectFont(fontName, select.checked);
select.scrollIntoView();
@ -140,8 +144,9 @@ var FontInspector = (function FontInspectorClosure() {
// Somewhat of a hack, should probably add a hook for when the text layer
// is done rendering.
setTimeout(function() {
if (this.active)
if (this.active) {
resetSelection();
}
}.bind(this), 2000);
}
};
@ -172,8 +177,9 @@ var StepperManager = (function StepperManagerClosure() {
stepperDiv = document.createElement('div');
this.panel.appendChild(stepperControls);
this.panel.appendChild(stepperDiv);
if (sessionStorage.getItem('pdfjsBreakPoints'))
if (sessionStorage.getItem('pdfjsBreakPoints')) {
breakPoints = JSON.parse(sessionStorage.getItem('pdfjsBreakPoints'));
}
},
enabled: false,
active: false,
@ -191,19 +197,22 @@ var StepperManager = (function StepperManagerClosure() {
var initBreakPoints = breakPoints[pageIndex] || [];
var stepper = new Stepper(debug, pageIndex, initBreakPoints);
steppers.push(stepper);
if (steppers.length === 1)
if (steppers.length === 1) {
this.selectStepper(pageIndex, false);
}
return stepper;
},
selectStepper: function selectStepper(pageIndex, selectPanel) {
if (selectPanel)
if (selectPanel) {
this.manager.selectPanel(1);
}
for (var i = 0; i < steppers.length; ++i) {
var stepper = steppers[i];
if (stepper.pageIndex == pageIndex)
if (stepper.pageIndex == pageIndex) {
stepper.panel.removeAttribute('hidden');
else
} else {
stepper.panel.setAttribute('hidden', true);
}
}
var options = stepperChooser.options;
for (var i = 0; i < options.length; ++i) {
@ -223,8 +232,9 @@ var Stepper = (function StepperClosure() {
// Shorter way to create element and optionally set textContent.
function c(tag, textContent) {
var d = document.createElement(tag);
if (textContent)
if (textContent) {
d.textContent = textContent;
}
return d;
}
@ -297,10 +307,11 @@ var Stepper = (function StepperClosure() {
cbox.checked = checked;
cbox.onclick = (function(x) {
return function() {
if (this.checked)
if (this.checked) {
self.breakPoints.push(x);
else
} else {
self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
}
StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
};
})(i);
@ -336,8 +347,9 @@ var Stepper = (function StepperClosure() {
getNextBreakPoint: function getNextBreakPoint() {
this.breakPoints.sort(function(a, b) { return a - b; });
for (var i = 0; i < this.breakPoints.length; i++) {
if (this.breakPoints[i] > this.currentIdx)
if (this.breakPoints[i] > this.currentIdx) {
return this.breakPoints[i];
}
}
return null;
},
@ -385,13 +397,16 @@ var Stepper = (function StepperClosure() {
var Stats = (function Stats() {
var stats = [];
function clear(node) {
while (node.hasChildNodes())
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
}
function getStatIndex(pageNumber) {
for (var i = 0, ii = stats.length; i < ii; ++i)
if (stats[i].pageNumber === pageNumber)
for (var i = 0, ii = stats.length; i < ii; ++i) {
if (stats[i].pageNumber === pageNumber) {
return i;
}
}
return false;
}
return {
@ -408,8 +423,9 @@ var Stats = (function Stats() {
active: false,
// Stats specific functions.
add: function(pageNumber, stat) {
if (!stat)
if (!stat) {
return;
}
var statsIndex = getStatIndex(pageNumber);
if (statsIndex !== false) {
var b = stats[statsIndex];
@ -428,8 +444,9 @@ var Stats = (function Stats() {
stats.push({ pageNumber: 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)
for (var i = 0, ii = stats.length; i < ii; ++i) {
this.panel.appendChild(stats[i].div);
}
}
};
})();
@ -448,12 +465,14 @@ var PDFBug = (function PDFBugClosure() {
],
enable: function(ids) {
var all = false, tools = this.tools;
if (ids.length === 1 && ids[0] === 'all')
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.indexOf(tool.id) !== -1) {
tool.enabled = true;
}
}
if (!all) {
// Sort the tools by the order they are enabled.
@ -509,19 +528,21 @@ var PDFBug = (function PDFBugClosure() {
panels.appendChild(panel);
tool.panel = panel;
tool.manager = this;
if (tool.enabled)
if (tool.enabled) {
tool.init();
else
} else {
panel.textContent = tool.name + ' is disabled. To enable add ' +
' "' + tool.id + '" to the pdfBug parameter ' +
'and refresh (seperate multiple by commas).';
}
buttons.push(panelButton);
}
this.selectPanel(0);
},
selectPanel: function selectPanel(index) {
if (index === activePanel)
if (index === activePanel) {
return;
}
activePanel = index;
var tools = this.tools;
for (var j = 0; j < tools.length; ++j) {

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
</svg>

After

Width:  |  Height:  |  Size: 158 B

View File

@ -1157,14 +1157,7 @@ canvas {
background-color: white;
}
.page > a,
.annotationLayer > a {
display: block;
position: absolute;
}
.page > a:hover,
.annotationLayer > a:hover {
.annotLink > a:hover {
opacity: 0.2;
background: #ff0;
box-shadow: 0px 2px 10px #ff0;
@ -1229,29 +1222,49 @@ canvas {
::selection { background:rgba(0,0,255,0.3); }
::-moz-selection { background:rgba(0,0,255,0.3); }
.annotText > div {
z-index: 200;
.annotationHighlight {
position: absolute;
padding: 0.6em;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 10px #333;
border-radius: 7px;
border: 2px #FFFF99 solid;
}
.annotText > img {
position: absolute;
opacity: 0.6;
cursor: pointer;
}
.annotText > img:hover {
opacity: 1;
.annotTextContentWrapper {
position: absolute;
width: 20em;
}
.annotText > div > h1 {
font-size: 1.2em;
.annotTextContent {
z-index: 200;
float: left;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 5px #333;
border-radius: 2px;
padding: 0.6em;
cursor: pointer;
}
.annotTextContent > h1 {
font-size: 1em;
border-bottom: 1px solid #000000;
margin: 0px;
padding-bottom: 0.2em;
}
.annotTextContent > p {
padding-top: 0.2em;
}
.annotLink > a {
position: absolute;
font-size: 1em;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#errorWrapper {

View File

@ -68,10 +68,9 @@ var CustomStyle = (function CustomStyleClosure() {
// in some versions of IE9 it is critical that ms appear in this list
// before Moz
var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
var _cache = { };
var _cache = {};
function CustomStyle() {
}
function CustomStyle() {}
CustomStyle.getProp = function get(propName, element) {
// check cache only when no element is given
@ -104,8 +103,9 @@ var CustomStyle = (function CustomStyleClosure() {
CustomStyle.setProp = function set(propName, element, str) {
var prop = this.getProp(propName);
if (prop != 'undefined')
if (prop != 'undefined') {
element.style[prop] = str;
}
};
return CustomStyle;
@ -291,11 +291,13 @@ var Cache = function cacheCache(size) {
var data = [];
this.push = function cachePush(view) {
var i = data.indexOf(view);
if (i >= 0)
if (i >= 0) {
data.splice(i);
}
data.push(view);
if (data.length > size)
if (data.length > size) {
data.shift().destroy();
}
};
};
@ -315,12 +317,13 @@ var Preferences = (function PreferencesClosure() {
function Preferences() {
this.prefs = {};
this.isInitializedPromiseResolved = false;
this.initializedPromise = this.readFromStorage().then(function(prefObj) {
this.isInitializedPromiseResolved = true;
if (prefObj) {
this.prefs = prefObj;
}
}.bind(this));
this.initializedPromise = this.readFromStorage(DEFAULT_PREFERENCES).then(
function(prefObj) {
this.isInitializedPromiseResolved = true;
if (prefObj) {
this.prefs = prefObj;
}
}.bind(this));
}
Preferences.prototype = {
@ -328,7 +331,7 @@ var Preferences = (function PreferencesClosure() {
return;
},
readFromStorage: function Preferences_readFromStorage() {
readFromStorage: function Preferences_readFromStorage(prefObj) {
var readFromStoragePromise = Promise.resolve();
return readFromStoragePromise;
},
@ -336,7 +339,7 @@ var Preferences = (function PreferencesClosure() {
reset: function Preferences_reset() {
if (this.isInitializedPromiseResolved) {
this.prefs = {};
this.writeToStorage(this.prefs);
this.writeToStorage(DEFAULT_PREFERENCES);
}
},
@ -361,6 +364,12 @@ var Preferences = (function PreferencesClosure() {
valueType + '\", expected a \"' + defaultType + '\".');
return;
}
} else {
if (valueType === 'number' && (value | 0) !== value) {
console.error('Preferences_set: \'' + value +
'\' must be an \"integer\".');
return;
}
}
this.prefs[name] = value;
this.writeToStorage(this.prefs);
@ -427,8 +436,8 @@ var FirefoxCom = (function FirefoxComClosure() {
var request = document.createTextNode('');
if (callback) {
document.addEventListener('pdf.js.response', function listener(event) {
var node = event.target,
response = event.detail.response;
var node = event.target;
var response = event.detail.response;
document.documentElement.removeChild(node);
@ -483,9 +492,10 @@ Preferences.prototype.writeToStorage = function(prefObj) {
FirefoxCom.requestSync('setPreferences', prefObj);
};
Preferences.prototype.readFromStorage = function() {
Preferences.prototype.readFromStorage = function(prefObj) {
var readFromStoragePromise = new Promise(function (resolve) {
var readPrefs = JSON.parse(FirefoxCom.requestSync('getPreferences'));
var readPrefs = JSON.parse(FirefoxCom.requestSync('getPreferences',
prefObj));
resolve(readPrefs);
});
return readFromStoragePromise;
@ -576,8 +586,6 @@ var ViewHistory = (function ViewHistoryClosure() {
})();
/* globals PDFFindController, FindStates, mozL10n */
/**
* Creates a "search bar" given set of DOM elements
* that act as controls for searching, or for setting
@ -586,7 +594,6 @@ var ViewHistory = (function ViewHistoryClosure() {
* searching is done by PDFFindController
*/
var PDFFindBar = {
opened: false,
bar: null,
toggleButton: null,
@ -600,7 +607,7 @@ var PDFFindBar = {
initialize: function(options) {
if(typeof PDFFindController === 'undefined' || PDFFindController === null) {
throw 'PDFFindBar cannot be initialized ' +
throw 'PDFFindBar cannot be initialized ' +
'without a PDFFindController instance.';
}
@ -715,8 +722,9 @@ var PDFFindBar = {
},
close: function() {
if (!this.opened) return;
if (!this.opened) {
return;
}
this.opened = false;
this.toggleButton.classList.remove('toggled');
this.bar.classList.add('hidden');
@ -735,8 +743,6 @@ var PDFFindBar = {
/* globals PDFFindBar, PDFJS, FindStates, FirefoxCom, Promise */
/**
* Provides a "search" or "find" functionality for the PDF.
* This object actually performs the search for a given string.
@ -876,8 +882,9 @@ var PDFFindController = {
self.pageContents.push(str);
extractTextPromisesResolves[pageIndex](pageIndex);
if ((pageIndex + 1) < self.pdfPageSource.pages.length)
if ((pageIndex + 1) < self.pdfPageSource.pages.length) {
extractPageText(pageIndex + 1);
}
}
);
}
@ -2432,10 +2439,11 @@ var PDFView = {
viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) {
var currentY = viewAreaElement.scrollTop;
var lastY = state.lastY;
if (currentY > lastY)
if (currentY > lastY) {
state.down = true;
else if (currentY < lastY)
} else if (currentY < lastY) {
state.down = false;
}
// else do nothing and use previous value
state.lastY = currentY;
callback();
@ -2688,8 +2696,9 @@ var PDFView = {
}
var args = e.data;
if (typeof args !== 'object' || !('pdfjsLoadAction' in args))
if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) {
return;
}
switch (args.pdfjsLoadAction) {
case 'supportsRangedLoading':
PDFView.open(args.pdfUrl, 0, undefined, pdfDataRangeTransport, {
@ -2884,8 +2893,9 @@ var PDFView = {
},
getDestinationHash: function pdfViewGetDestinationHash(dest) {
if (typeof dest === 'string')
if (typeof dest === 'string') {
return PDFView.getAnchorUrl('#' + escape(dest));
}
if (dest instanceof Array) {
var destRef = dest[0]; // see navigateTo method for dest format
var pageNumber = destRef instanceof Object ?
@ -3003,15 +3013,18 @@ var PDFView = {
var thumbsView = document.getElementById('thumbnailView');
thumbsView.parentNode.scrollTop = 0;
while (thumbsView.hasChildNodes())
while (thumbsView.hasChildNodes()) {
thumbsView.removeChild(thumbsView.lastChild);
}
if ('_loadingInterval' in thumbsView)
if ('_loadingInterval' in thumbsView) {
clearInterval(thumbsView._loadingInterval);
}
var container = document.getElementById('viewer');
while (container.hasChildNodes())
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
var pagesCount = pdfDocument.numPages;
@ -3178,16 +3191,17 @@ var PDFView = {
(PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : ''));
var pdfTitle;
if (metadata) {
if (metadata.has('dc:title'))
pdfTitle = metadata.get('dc:title');
if (metadata && metadata.has('dc:title')) {
pdfTitle = metadata.get('dc:title');
}
if (!pdfTitle && info && info['Title'])
if (!pdfTitle && info && info['Title']) {
pdfTitle = info['Title'];
}
if (pdfTitle)
if (pdfTitle) {
self.setTitle(pdfTitle + ' - ' + document.title);
}
if (info.IsAcroFormPresent) {
console.warn('Warning: AcroForm/XFA is not supported');
@ -3313,21 +3327,24 @@ var PDFView = {
}
for (var i = 0; i < numVisible; ++i) {
var view = visibleViews[i].view;
if (!this.isViewFinished(view))
if (!this.isViewFinished(view)) {
return view;
}
}
// All the visible views have rendered, try to render next/previous pages.
if (scrolledDown) {
var nextPageIndex = visible.last.id;
// ID's start at 1 so no need to add 1.
if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex]))
if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) {
return views[nextPageIndex];
}
} else {
var previousPageIndex = visible.first.id - 2;
if (views[previousPageIndex] &&
!this.isViewFinished(views[previousPageIndex]))
!this.isViewFinished(views[previousPageIndex])) {
return views[previousPageIndex];
}
}
// Everything that needs to be rendered has been.
return false;
@ -3360,8 +3377,9 @@ var PDFView = {
},
setHash: function pdfViewSetHash(hash) {
if (!hash)
if (!hash) {
return;
}
if (hash.indexOf('=') >= 0) {
var params = PDFView.parseQueryString(hash);
@ -3449,8 +3467,9 @@ var PDFView = {
thumbsView.classList.add('hidden');
outlineView.classList.remove('hidden');
if (outlineButton.getAttribute('disabled'))
if (outlineButton.getAttribute('disabled')) {
return;
}
break;
}
},
@ -3567,8 +3586,9 @@ var PDFView = {
afterPrint: function pdfViewSetupAfterPrint() {
var div = document.getElementById('printContainer');
while (div.hasChildNodes())
while (div.hasChildNodes()) {
div.removeChild(div.lastChild);
}
},
rotatePages: function pdfViewRotatePages(delta) {
@ -3610,14 +3630,16 @@ var PDFView = {
// In case one page has already been flipped there is a cooldown time
// which has to expire before next page can be scrolled on to.
if (currentTime > storedTime &&
currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME)
currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
return;
}
// In case the user decides to scroll to the opposite direction than before
// clear the accumulated delta.
if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) ||
(this.mouseScrollDelta < 0 && mouseScrollDelta > 0))
(this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) {
this.clearMouseScrollState();
}
this.mouseScrollDelta += mouseScrollDelta;
@ -3640,8 +3662,9 @@ var PDFView = {
// to do anything.
if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) ||
(currentPage == this.pages.length &&
pageFlipDirection == PageFlipDirection.DOWN))
pageFlipDirection == PageFlipDirection.DOWN)) {
return;
}
this.page += pageFlipDirection;
this.mouseScrollTimeStamp = currentTime;
@ -3946,10 +3969,13 @@ var PageView = function pageView(container, id, scale,
CustomStyle.setProp('transformOrigin', element, transformOriginStr);
if (data.subtype === 'Link' && !data.url) {
if (data.action) {
bindNamedAction(element, data.action);
} else {
bindLink(element, ('dest' in data) ? data.dest : null);
var link = element.getElementsByTagName('a')[0];
if (link) {
if (data.action) {
bindNamedAction(link, data.action);
} else {
bindLink(link, ('dest' in data) ? data.dest : null);
}
}
}
@ -4215,6 +4241,7 @@ var PageView = function pageView(container, id, scale,
canvasContext: ctx,
viewport: this.viewport,
textLayer: textLayer,
// intent: 'default', // === 'display'
continueCallback: function pdfViewcContinueCallback(cont) {
if (PDFView.highestPriorityPage !== 'page' + self.id) {
self.renderingState = RenderingStates.PAUSED;
@ -4286,13 +4313,13 @@ var PageView = function pageView(container, id, scale,
var renderContext = {
canvasContext: ctx,
viewport: viewport
viewport: viewport,
intent: 'print'
};
pdfPage.render(renderContext).promise.then(function() {
// Tell the printEngine that rendering this canvas/page has finished.
obj.done();
self.pdfPage.destroy();
}, function(error) {
console.error(error);
// Tell the printEngine that rendering this canvas/page has failed.
@ -4302,7 +4329,6 @@ var PageView = function pageView(container, id, scale,
} else {
obj.done();
}
self.pdfPage.destroy();
});
};
};
@ -4522,12 +4548,12 @@ var TextLayerBuilder = function textLayerBuilder(options) {
this.viewport = options.viewport;
this.isViewerInPresentationMode = options.isViewerInPresentationMode;
if(typeof PDFFindController === 'undefined') {
window.PDFFindController = null;
if (typeof PDFFindController === 'undefined') {
window.PDFFindController = null;
}
if(typeof this.lastScrollSource === 'undefined') {
this.lastScrollSource = null;
if (typeof this.lastScrollSource === 'undefined') {
this.lastScrollSource = null;
}
this.beginLayout = function textLayerBuilderBeginLayout() {
@ -4548,8 +4574,9 @@ var TextLayerBuilder = function textLayerBuilder(options) {
// No point in rendering so many divs as it'd make the browser unusable
// even after the divs are rendered
var MAX_TEXT_DIVS_TO_RENDER = 100000;
if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER)
if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) {
return;
}
for (var i = 0, ii = textDivs.length; i < ii; i++) {
var textDiv = textDivs[i];
@ -4581,16 +4608,17 @@ var TextLayerBuilder = function textLayerBuilder(options) {
// run it right away
var RENDER_DELAY = 200; // in ms
var self = this;
var lastScroll = this.lastScrollSource === null ?
0 : this.lastScrollSource.lastScroll;
var lastScroll = (this.lastScrollSource === null ?
0 : this.lastScrollSource.lastScroll);
if (Date.now() - lastScroll > RENDER_DELAY) {
// Render right away
this.renderLayer();
} else {
// Schedule
if (this.renderTimer)
if (this.renderTimer) {
clearTimeout(this.renderTimer);
}
this.renderTimer = setTimeout(function() {
self.setupRenderLayoutTimer();
}, RENDER_DELAY);
@ -4608,8 +4636,8 @@ var TextLayerBuilder = function textLayerBuilder(options) {
textDiv.style.fontSize = fontHeight + 'px';
textDiv.style.fontFamily = geom.fontFamily;
var fontAscent = geom.ascent ? geom.ascent * fontHeight :
geom.descent ? (1 + geom.descent) * fontHeight : fontHeight;
var fontAscent = (geom.ascent ? geom.ascent * fontHeight :
(geom.descent ? (1 + geom.descent) * fontHeight : fontHeight));
textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px';
textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px';
@ -4621,8 +4649,9 @@ var TextLayerBuilder = function textLayerBuilder(options) {
this.insertDivContent = function textLayerUpdateTextContent() {
// Only set the content of the divs once layout has finished, the content
// for the divs is available and content is not yet set on the divs.
if (!this.layoutDone || this.divContentDone || !this.textContent)
if (!this.layoutDone || this.divContentDone || !this.textContent) {
return;
}
this.divContentDone = true;
@ -4661,8 +4690,8 @@ var TextLayerBuilder = function textLayerBuilder(options) {
var iIndex = 0;
var bidiTexts = this.textContent;
var end = bidiTexts.length - 1;
var queryLen = PDFFindController === null ?
0 : PDFFindController.state.query.length;
var queryLen = (PDFFindController === null ?
0 : PDFFindController.state.query.length);
var lastDivIdx = -1;
var pos;
@ -4721,14 +4750,14 @@ var TextLayerBuilder = function textLayerBuilder(options) {
var bidiTexts = this.textContent;
var textDivs = this.textDivs;
var prevEnd = null;
var isSelectedPage = PDFFindController === null ?
false : (this.pageIdx === PDFFindController.selected.pageIdx);
var isSelectedPage = (PDFFindController === null ?
false : (this.pageIdx === PDFFindController.selected.pageIdx));
var selectedMatchIdx = PDFFindController === null ?
-1 : PDFFindController.selected.matchIdx;
var selectedMatchIdx = (PDFFindController === null ?
-1 : PDFFindController.selected.matchIdx);
var highlightAll = PDFFindController === null ?
false : PDFFindController.state.highlightAll;
var highlightAll = (PDFFindController === null ?
false : PDFFindController.state.highlightAll);
var infty = {
divIdx: -1,
@ -4827,8 +4856,9 @@ var TextLayerBuilder = function textLayerBuilder(options) {
this.updateMatches = function textLayerUpdateMatches() {
// Only show matches, once all rendering is done.
if (!this.renderingDone)
if (!this.renderingDone) {
return;
}
// Clear out all matches.
var matches = this.matches;
@ -4848,14 +4878,14 @@ var TextLayerBuilder = function textLayerBuilder(options) {
clearedUntilDivIdx = match.end.divIdx + 1;
}
if (PDFFindController === null || !PDFFindController.active)
if (PDFFindController === null || !PDFFindController.active) {
return;
}
// Convert the matches on the page controller into the match format used
// for the textLayer.
this.matches = matches =
this.convertMatches(PDFFindController === null ?
[] : (PDFFindController.pageMatches[this.pageIdx] || []));
this.matches = matches = (this.convertMatches(PDFFindController === null ?
[] : (PDFFindController.pageMatches[this.pageIdx] || [])));
this.renderMatches(this.matches);
};
@ -4866,13 +4896,14 @@ var TextLayerBuilder = function textLayerBuilder(options) {
var DocumentOutlineView = function documentOutlineView(outline) {
var outlineView = document.getElementById('outlineView');
var outlineButton = document.getElementById('viewOutline');
while (outlineView.firstChild)
while (outlineView.firstChild) {
outlineView.removeChild(outlineView.firstChild);
}
if (!outline) {
if (!outlineView.classList.contains('hidden'))
if (!outlineView.classList.contains('hidden')) {
PDFView.switchSidebarView('thumbs');
}
return;
}
@ -5101,8 +5132,9 @@ document.addEventListener('DOMContentLoaded', webViewerLoad, true);
function updateViewarea() {
if (!PDFView.initialized)
if (!PDFView.initialized) {
return;
}
var visible = PDFView.getVisiblePages();
var visiblePages = visible.views;
if (visiblePages.length === 0) {
@ -5118,9 +5150,9 @@ function updateViewarea() {
i < ii; ++i) {
var page = visiblePages[i];
if (page.percent < 100)
if (page.percent < 100) {
break;
}
if (page.id === PDFView.page) {
stillFullyVisible = true;
break;
@ -5473,23 +5505,6 @@ window.addEventListener('keydown', function keydown(evt) {
PDFView.rotatePages(90);
break;
}
if (!handled && !PresentationMode.active) {
// 33=Page Up 34=Page Down 35=End 36=Home
// 37=Left 38=Up 39=Right 40=Down
if (evt.keyCode >= 33 && evt.keyCode <= 40 &&
!PDFView.container.contains(curElement)) {
// The page container is not focused, but a page navigation key has been
// pressed. Change the focus to the viewer container to make sure that
// navigation by keyboard works as expected.
PDFView.container.focus();
}
// 32=Spacebar
if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') {
// Workaround for issue in Firefox, that prevents scroll keys from working
// when elements with 'tabindex' are focused. (#3499)
PDFView.container.blur();
}
}
}
if (cmd === 4) { // shift-key
@ -5509,6 +5524,24 @@ window.addEventListener('keydown', function keydown(evt) {
}
}
if (!handled && !PresentationMode.active) {
// 33=Page Up 34=Page Down 35=End 36=Home
// 37=Left 38=Up 39=Right 40=Down
if (evt.keyCode >= 33 && evt.keyCode <= 40 &&
!PDFView.container.contains(curElement)) {
// The page container is not focused, but a page navigation key has been
// pressed. Change the focus to the viewer container to make sure that
// navigation by keyboard works as expected.
PDFView.container.focus();
}
// 32=Spacebar
if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') {
// Workaround for issue in Firefox, that prevents scroll keys from
// working when elements with 'tabindex' are focused. (#3498)
PDFView.container.blur();
}
}
if (cmd === 2) { // alt-key
switch (evt.keyCode) {
case 37: // left arrow

View File

@ -503,6 +503,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
break;
case SELECTED:
flags.add(UpdateFlags.PRIVATE_MODE);
setPrivateMode(tab.isPrivate());
// Fall through.
case LOAD_ERROR:
flags.add(UpdateFlags.TITLE);
// Fall through.
@ -511,12 +514,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
// us of a title change, so we don't update the title here.
flags.add(UpdateFlags.FAVICON);
flags.add(UpdateFlags.SITE_IDENTITY);
flags.add(UpdateFlags.PRIVATE_MODE);
updateBackButton(tab);
updateForwardButton(tab);
setPrivateMode(tab.isPrivate());
break;
case TITLE:

View File

@ -63,7 +63,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm")
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@ -411,27 +411,48 @@ this.Download.prototype = {
}
}
// In case the download was restarted while cancellation was in progress,
// but the previous attempt actually succeeded before cancellation could
// be processed, it is possible that the download has already finished.
if (this.succeeded) {
return;
}
try {
// Disallow download if parental controls service restricts it.
if (yield DownloadIntegration.shouldBlockForParentalControls(this)) {
throw new DownloadError({ becauseBlockedByParentalControls: true });
}
// We should check if we have been canceled in the meantime, after all
// the previous asynchronous operations have been executed and just
// before we call the "execute" method of the saver.
if (this._promiseCanceled) {
// The exception will become a cancellation in the "catch" block.
throw undefined;
}
// Execute the actual download through the saver object.
this._saverExecuting = true;
yield this.saver.execute(DS_setProgressBytes.bind(this),
DS_setProperties.bind(this));
// Check for application reputation, which requires the entire file to
// be downloaded.
if (yield DownloadIntegration.shouldBlockForReputationCheck(this)) {
// Delete the target file that BackgroundFileSaver already moved
// into place.
// be downloaded. After that, check for the last time if the download
// has been canceled. Both cases require the target file to be deleted,
// thus we process both in the same block of code.
if ((yield DownloadIntegration.shouldBlockForReputationCheck(this)) ||
this._promiseCanceled) {
try {
yield OS.File.remove(this.target.path);
} catch (ex) {
Cu.reportError(ex);
}
// If this is actually a cancellation, this exception will be changed
// in the catch block below.
throw new DownloadError({ becauseBlockedByReputationCheck: true });
}
// Update the status properties for a successful download.
this.progress = 100;
this.succeeded = true;
@ -461,6 +482,7 @@ this.Download.prototype = {
throw ex;
} finally {
// Any cancellation request has now been processed.
this._saverExecuting = false;
this._promiseCanceled = null;
// Update the status properties, unless a new attempt already started.
@ -546,6 +568,12 @@ this.Download.prototype = {
*/
_promiseCanceled: null,
/**
* True between the call to the "execute" method of the saver and the
* completion of the current download attempt.
*/
_saverExecuting: false,
/**
* Cancels the download.
*
@ -589,8 +617,12 @@ this.Download.prototype = {
this.canceled = true;
this._notifyChange();
// Execute the actual cancellation through the saver object.
this.saver.cancel();
// Execute the actual cancellation through the saver object, in case it
// has already started. Otherwise, the cancellation will be handled just
// before the saver is started.
if (this._saverExecuting) {
this.saver.cancel();
}
}
return this._promiseCanceled;
@ -1363,31 +1395,6 @@ this.DownloadSaver.prototype = {
targetUri);
},
/**
* Return true if the request's response has been blocked by Windows parental
* controls with an HTTP 450 error code.
*
* @param aRequest
* nsIRequest object
* @return True if the response is blocked.
*/
isResponseParentalBlocked: function(aRequest)
{
// If the HTTP status is 450, then Windows Parental Controls have
// blocked this download.
if (aRequest instanceof Ci.nsIHttpChannel &&
aRequest.responseStatus == 450) {
// Cancel the request, but set a flag on the download that can be
// retrieved later when handling the cancellation so that the proper
// blocked by parental controls error can be thrown.
this.download._blockedByParentalControls = true;
aRequest.cancel(Cr.NS_BINDING_ABORTED);
return true;
}
return false;
},
/**
* Returns a static representation of the current object state.
*
@ -1612,7 +1619,14 @@ this.DownloadCopySaver.prototype = {
onStartRequest: function (aRequest, aContext) {
backgroundFileSaver.onStartRequest(aRequest, aContext);
if (this.isResponseParentalBlocked(aRequest)) {
// Check if the request's response has been blocked by Windows
// Parental Controls with an HTTP 450 error code.
if (aRequest instanceof Ci.nsIHttpChannel &&
aRequest.responseStatus == 450) {
// Set a flag that can be retrieved later when handling the
// cancellation so that the proper error can be thrown.
this.download._blockedByParentalControls = true;
aRequest.cancel(Cr.NS_BINDING_ABORTED);
return;
}
@ -1707,6 +1721,13 @@ this.DownloadCopySaver.prototype = {
}.bind(copySaver),
}, null);
// We should check if we have been canceled in the meantime, after
// all the previous asynchronous operations have been executed and
// just before we set the _backgroundFileSaver property.
if (this._canceled) {
throw new DownloadError({ message: "Saver canceled." });
}
// If the operation succeeded, store the object to allow cancellation.
this._backgroundFileSaver = backgroundFileSaver;
} catch (ex) {
@ -1930,10 +1951,6 @@ this.DownloadLegacySaver.prototype = {
ex.result == Cr.NS_ERROR_NOT_RESUMABLE) { }
}
if (this.isResponseParentalBlocked(aRequest)) {
return;
}
// For legacy downloads, we must update the referrer at this time.
if (aRequest instanceof Ci.nsIHttpChannel && aRequest.referrer) {
this.download.source.referrer = aRequest.referrer.spec;

View File

@ -46,7 +46,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
#endif
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",

View File

@ -29,7 +29,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
////////////////////////////////////////////////////////////////////////////////
//// DownloadLegacyTransfer
@ -89,9 +89,25 @@ DownloadLegacyTransfer.prototype = {
if ((aStateFlags & Ci.nsIWebProgressListener.STATE_START) &&
(aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)) {
// If the request's response has been blocked by Windows Parental Controls
// with an HTTP 450 error code, we must cancel the request synchronously.
let blockedByParentalControls = aRequest instanceof Ci.nsIHttpChannel &&
aRequest.responseStatus == 450;
if (blockedByParentalControls) {
aRequest.cancel(Cr.NS_BINDING_ABORTED);
}
// The main request has just started. Wait for the associated Download
// object to be available before notifying.
this._deferDownload.promise.then(download => {
// If the request was blocked, now that we have the download object we
// should set a flag that can be retrieved later when handling the
// cancellation so that the proper error can be thrown.
if (blockedByParentalControls) {
download._blockedByParentalControls = true;
}
download.saver.onTransferStarted(
aRequest,
this._cancelable instanceof Ci.nsIHelperAppLauncher);

View File

@ -37,7 +37,7 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");

View File

@ -27,7 +27,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");

View File

@ -36,7 +36,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadSummary",
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
"resource://gre/modules/DownloadUIHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");

View File

@ -806,7 +806,10 @@ add_task(function test_cancel_immediately_restart_immediately()
continueResponses();
try {
yield promiseAttempt;
do_throw("The download should have been canceled.");
// If we get here, it means that the first attempt actually succeeded. In
// fact, this could be a valid outcome, because the cancellation request may
// not have been processed in time before the download finished.
do_print("The download should have been canceled.");
} catch (ex if ex instanceof Downloads.Error) {
do_check_false(ex.becauseSourceFailed);
do_check_false(ex.becauseTargetFailed);

View File

@ -34,7 +34,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@ -731,6 +731,15 @@ add_task(function test_common_initialize()
gHttpServer.registerDirectory("/", do_get_file("../data"));
gHttpServer.start(-1);
// Cache locks might prevent concurrent requests to the same resource, and
// this may block tests that use the interruptible handlers.
Services.prefs.setBoolPref("browser.cache.disk.enable", false);
Services.prefs.setBoolPref("browser.cache.memory.enable", false);
do_register_cleanup(function () {
Services.prefs.clearUserPref("browser.cache.disk.enable");
Services.prefs.clearUserPref("browser.cache.memory.enable");
});
registerInterruptibleHandler("/interruptible.txt",
function firstPart(aRequest, aResponse) {
aResponse.setHeader("Content-Type", "text/plain", false);

View File

@ -14,20 +14,21 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"nsIMessageSender");
function paymentSuccess(aRequestId) {
return paymentCallback(aRequestId, "Payment:Success");
return function(aResult) {
closePaymentWindow(aRequestId, function() {
cpmm.sendAsyncMessage("Payment:Success", { requestId: aRequestId,
result: aResult });
});
};
}
function paymentFailed(aRequestId) {
return paymentCallback(aRequestId, "Payment:Failed");
}
function paymentCallback(aRequestId, aMsg) {
return function(aResult) {
closePaymentWindow(aRequestId, function() {
cpmm.sendAsyncMessage(aMsg, { result: aResult,
requestId: aRequestId });
});
};
return function(aErrorMsg) {
closePaymentWindow(aRequestId, function() {
cpmm.sendAsyncMessage("Payment:Failed", { requestId: aRequestId,
errorMsg: aErrorMsg });
});
};
}
let payments = {};

View File

@ -1,11 +1,22 @@
Cu.import("resource://gre/modules/Services.jsm");
let { PaymentManager } = Cu.import("resource://gre/modules/Payment.jsm", {});
Cu.import("resource://webapprt/modules/WebappRT.jsm");
function test() {
waitForExplicitFinish();
let providerWindow = null;
let providerUri = "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=";
let curTest = 0;
let tests = [];
tests.push({
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=",
message: "Success."
});
tests.push({
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-failure.html?req=",
message: "Chocolate rejected."
});
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
"HlvdSBhcHAga2V5IGhlcmUhIiwgInJlcXVlc3QiOiB7Im5hbWUiOiAiUG" +
@ -21,17 +32,19 @@ function test() {
PaymentManager.registeredProviders["mock/payments/inapp/v1"] = {
name: "mockprovider",
description: "Mock Payment Provider",
uri: providerUri,
uri: tests[curTest].providerUri,
requestMethod: "GET"
};
let providerWindow;
let winObserver = function(win, topic) {
if (topic == "domwindowopened") {
win.addEventListener("load", function onLoadWindow() {
win.removeEventListener("load", onLoadWindow, false);
if (win.document.getElementById("content").getAttribute("src") ==
(providerUri + jwt)) {
(tests[curTest].providerUri + jwt)) {
ok(true, "Payment provider window shown.");
providerWindow = win;
}
@ -43,25 +56,45 @@ function test() {
let mutObserver = null;
loadWebapp("mozpay.webapp", undefined, function onLoad() {
function onLoad() {
let msg = gAppBrowser.contentDocument.getElementById("msg");
mutObserver = new MutationObserver(function(mutations) {
if (msg.textContent == "Success.") {
ok(true, "Payment success.");
} else {
ok(false, "Payment success.");
}
is(msg.textContent, tests[curTest].message, "Got: " + tests[curTest].message);
if (providerWindow == null) {
if (!providerWindow) {
ok(false, "Payment provider window shown.");
} else {
providerWindow.close();
providerWindow = null;
}
finish();
runNextTest();
});
mutObserver.observe(msg, { childList: true });
});
}
loadWebapp("mozpay.webapp", undefined, onLoad);
function runNextTest() {
providerWindow = null;
if (mutObserver) {
mutObserver.disconnect();
}
curTest++;
if (curTest < tests.length) {
PaymentManager.registeredProviders["mock/payments/inapp/v1"].uri = tests[curTest].providerUri;
gAppBrowser.addEventListener("load", function onLoadH() {
gAppBrowser.removeEventListener("load", onLoadH, true);
onLoad();
}, true);
gAppBrowser.reload();
} else {
finish();
}
}
registerCleanupFunction(function() {
Services.ww.unregisterNotification(winObserver);

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script>
mozPaymentProvider.paymentFailed('Chocolate rejected.');
</script>
<p id="msg">Webapp waiting to pay...</p>
</body>
</html>

View File

@ -37,7 +37,7 @@
document.getElementById("msg").textContent = "Success.";
};
request.onerror = function onerror() {
document.getElementById("msg").textContent = "Failure.";
document.getElementById("msg").textContent = request.error.name;
};
</script>
<p id="msg">Webapp waiting to be paid...</p>

View File

@ -26,6 +26,7 @@ support-files =
mozpay.webapp^headers^
mozpay.html
mozpay-success.html
mozpay-failure.html
getUserMedia.webapp
getUserMedia.webapp^headers^
getUserMedia.html