Merge f-t to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2016-09-30 23:25:36 -07:00
commit f3a11c5cdb
46 changed files with 11095 additions and 4470 deletions

View File

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

View File

@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {}));
// Use strict in our context only - users might not want it
'use strict';
var pdfjsVersion = '1.5.476';
var pdfjsBuild = 'c0e82db';
var pdfjsVersion = '1.5.498';
var pdfjsBuild = '1564dc3';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@ -115,25 +115,25 @@ var AnnotationFlag = {
};
var AnnotationFieldFlag = {
READONLY: 1,
REQUIRED: 2,
NOEXPORT: 3,
MULTILINE: 13,
PASSWORD: 14,
NOTOGGLETOOFF: 15,
RADIO: 16,
PUSHBUTTON: 17,
COMBO: 18,
EDIT: 19,
SORT: 20,
FILESELECT: 21,
MULTISELECT: 22,
DONOTSPELLCHECK: 23,
DONOTSCROLL: 24,
COMB: 25,
RICHTEXT: 26,
RADIOSINUNISON: 26,
COMMITONSELCHANGE: 27,
READONLY: 0x0000001,
REQUIRED: 0x0000002,
NOEXPORT: 0x0000004,
MULTILINE: 0x0001000,
PASSWORD: 0x0002000,
NOTOGGLETOOFF: 0x0004000,
RADIO: 0x0008000,
PUSHBUTTON: 0x0010000,
COMBO: 0x0020000,
EDIT: 0x0040000,
SORT: 0x0080000,
FILESELECT: 0x0100000,
MULTISELECT: 0x0200000,
DONOTSPELLCHECK: 0x0400000,
DONOTSCROLL: 0x0800000,
COMB: 0x1000000,
RICHTEXT: 0x2000000,
RADIOSINUNISON: 0x2000000,
COMMITONSELCHANGE: 0x4000000,
};
var AnnotationBorderStyleType = {
@ -2365,19 +2365,31 @@ var TextWidgetAnnotationElement = (
var element = null;
if (this.renderInteractiveForms) {
// NOTE: We cannot set the values using `element.value` below, since it
// prevents the AnnotationLayer rasterizer in `test/driver.js`
// from parsing the elements correctly for the reference tests.
if (this.data.multiLine) {
element = document.createElement('textarea');
element.textContent = this.data.fieldValue;
} else {
element = document.createElement('input');
element.type = 'text';
element.setAttribute('value', this.data.fieldValue);
}
element.value = this.data.fieldValue;
element.disabled = this.data.readOnly;
if (this.data.maxLen !== null) {
element.maxLength = this.data.maxLen;
}
if (this.data.comb) {
var fieldWidth = this.data.rect[2] - this.data.rect[0];
var combWidth = fieldWidth / this.data.maxLen;
element.classList.add('comb');
element.style.letterSpacing = 'calc(' + combWidth + 'px - 1ch)';
}
} else {
element = document.createElement('div');
element.textContent = this.data.fieldValue;

View File

@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdfWorker = {}));
// Use strict in our context only - users might not want it
'use strict';
var pdfjsVersion = '1.5.476';
var pdfjsBuild = 'c0e82db';
var pdfjsVersion = '1.5.498';
var pdfjsBuild = '1564dc3';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@ -1101,25 +1101,25 @@ var AnnotationFlag = {
};
var AnnotationFieldFlag = {
READONLY: 1,
REQUIRED: 2,
NOEXPORT: 3,
MULTILINE: 13,
PASSWORD: 14,
NOTOGGLETOOFF: 15,
RADIO: 16,
PUSHBUTTON: 17,
COMBO: 18,
EDIT: 19,
SORT: 20,
FILESELECT: 21,
MULTISELECT: 22,
DONOTSPELLCHECK: 23,
DONOTSCROLL: 24,
COMB: 25,
RICHTEXT: 26,
RADIOSINUNISON: 26,
COMMITONSELCHANGE: 27,
READONLY: 0x0000001,
REQUIRED: 0x0000002,
NOEXPORT: 0x0000004,
MULTILINE: 0x0001000,
PASSWORD: 0x0002000,
NOTOGGLETOOFF: 0x0004000,
RADIO: 0x0008000,
PUSHBUTTON: 0x0010000,
COMBO: 0x0020000,
EDIT: 0x0040000,
SORT: 0x0080000,
FILESELECT: 0x0100000,
MULTISELECT: 0x0200000,
DONOTSPELLCHECK: 0x0400000,
DONOTSCROLL: 0x0800000,
COMB: 0x1000000,
RICHTEXT: 0x2000000,
RADIOSINUNISON: 0x2000000,
COMMITONSELCHANGE: 0x4000000,
};
var AnnotationBorderStyleType = {
@ -10214,7 +10214,7 @@ var error = sharedUtil.error;
* (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)
*/
var JpegImage = (function jpegImage() {
var JpegImage = (function JpegImageClosure() {
var dctZigZag = new Uint8Array([
0,
1, 8,
@ -10242,7 +10242,9 @@ var JpegImage = (function jpegImage() {
var dctSqrt2 = 5793; // sqrt(2)
var dctSqrt1d2 = 2896; // sqrt(2) / 2
function constructor() {
function JpegImage() {
this.decodeTransform = null;
this.colorTransform = -1;
}
function buildHuffmanTable(codeLengths, values) {
@ -10537,6 +10539,12 @@ var JpegImage = (function jpegImage() {
// find marker
bitsCount = 0;
marker = (data[offset] << 8) | data[offset + 1];
// Some bad images seem to pad Scan blocks with zero bytes, skip past
// those to attempt to find a valid marker (fixes issue4090.pdf).
while (data[offset] === 0x00 && offset < data.length - 1) {
offset++;
marker = (data[offset] << 8) | data[offset + 1];
}
if (marker <= 0xFF00) {
error('JPEG error: marker was not found');
}
@ -10759,7 +10767,7 @@ var JpegImage = (function jpegImage() {
return a <= 0 ? 0 : a >= 255 ? 255 : a;
}
constructor.prototype = {
JpegImage.prototype = {
parse: function parse(data) {
function readUint16() {
@ -11076,8 +11084,20 @@ var JpegImage = (function jpegImage() {
// The adobe transform marker overrides any previous setting
return true;
} else if (this.numComponents === 3) {
if (!this.adobe && this.colorTransform === 0) {
// If the Adobe transform marker is not present and the image
// dictionary has a 'ColorTransform' entry, explicitly set to `0`,
// then the colours should *not* be transformed.
return false;
}
return true;
} else {
} else { // `this.numComponents !== 3`
if (!this.adobe && this.colorTransform === 1) {
// If the Adobe transform marker is not present and the image
// dictionary has a 'ColorTransform' entry, explicitly set to `1`,
// then the colours should be transformed.
return true;
}
return false;
}
},
@ -11219,7 +11239,7 @@ var JpegImage = (function jpegImage() {
rgbData[offset++] = grayColor;
}
return rgbData;
} else if (this.numComponents === 3) {
} else if (this.numComponents === 3 && this._isColorConversionNeeded()) {
return this._convertYccToRgb(data);
} else if (this.numComponents === 4) {
if (this._isColorConversionNeeded()) {
@ -11236,7 +11256,7 @@ var JpegImage = (function jpegImage() {
}
};
return constructor;
return JpegImage;
})();
exports.JpegImage = JpegImage;
@ -18829,6 +18849,7 @@ exports.isStream = isStream;
var Util = sharedUtil.Util;
var error = sharedUtil.error;
var info = sharedUtil.info;
var isInt = sharedUtil.isInt;
var isArray = sharedUtil.isArray;
var createObjectURL = sharedUtil.createObjectURL;
var shadow = sharedUtil.shadow;
@ -19686,7 +19707,7 @@ var PredictorStream = (function PredictorStreamClosure() {
* DecodeStreams.
*/
var JpegStream = (function JpegStreamClosure() {
function JpegStream(stream, maybeLength, dict, xref) {
function JpegStream(stream, maybeLength, dict) {
// Some images may contain 'junk' before the SOI (start-of-image) marker.
// Note: this seems to mainly affect inline images.
var ch;
@ -19720,8 +19741,8 @@ var JpegStream = (function JpegStreamClosure() {
var jpegImage = new JpegImage();
// Checking if values need to be transformed before conversion.
if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
var decodeArr = this.dict.getArray('Decode');
var decodeArr = this.dict.getArray('Decode', 'D');
if (this.forceRGB && isArray(decodeArr)) {
var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
var decodeArrLength = decodeArr.length;
var transform = new Int32Array(decodeArrLength);
@ -19738,6 +19759,14 @@ var JpegStream = (function JpegStreamClosure() {
jpegImage.decodeTransform = transform;
}
}
// Fetching the 'ColorTransform' entry, if it exists.
var decodeParams = this.dict.get('DecodeParms', 'DP');
if (isDict(decodeParams)) {
var colorTransform = decodeParams.get('ColorTransform');
if (isInt(colorTransform)) {
jpegImage.colorTransform = colorTransform;
}
}
jpegImage.parse(this.bytes);
var data = jpegImage.getData(this.drawWidth, this.drawHeight,
@ -19859,7 +19888,7 @@ var Jbig2Stream = (function Jbig2StreamClosure() {
var jbig2Image = new Jbig2Image();
var chunks = [];
var decodeParams = this.dict.getArray('DecodeParms');
var decodeParams = this.dict.getArray('DecodeParms', 'DP');
// According to the PDF specification, DecodeParms can be either
// a dictionary, or an array whose elements are dictionaries.
@ -24663,7 +24692,7 @@ var Parser = (function ParserClosure() {
}
if (name === 'DCTDecode' || name === 'DCT') {
xrefStreamStats[StreamType.DCT] = true;
return new JpegStream(stream, maybeLength, stream.dict, this.xref);
return new JpegStream(stream, maybeLength, stream.dict);
}
if (name === 'JPXDecode' || name === 'JPX') {
xrefStreamStats[StreamType.JPX] = true;
@ -30104,7 +30133,14 @@ var Type1Font = (function Type1FontClosure() {
var charStringsIndex = new CFFIndex();
charStringsIndex.add([0x8B, 0x0E]); // .notdef
for (i = 0; i < count; i++) {
charStringsIndex.add(glyphs[i]);
var glyph = glyphs[i];
// If the CharString outline is empty, replace it with .notdef to
// prevent OTS from rejecting the font (fixes bug1252420.pdf).
if (glyph.length === 0) {
charStringsIndex.add([0x8B, 0x0E]); // .notdef
continue;
}
charStringsIndex.add(glyph);
}
cff.charStrings = charStringsIndex;
@ -36074,18 +36110,26 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
*/
NativeImageDecoder.isSupported =
function NativeImageDecoder_isSupported(image, xref, res) {
var cs = ColorSpace.parse(image.dict.get('ColorSpace', 'CS'), xref, res);
var dict = image.dict;
if (dict.has('DecodeParms') || dict.has('DP')) {
return false;
}
var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res);
return (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB') &&
cs.isDefaultDecode(image.dict.getArray('Decode', 'D'));
cs.isDefaultDecode(dict.getArray('Decode', 'D'));
};
/**
* Checks if the image can be decoded by the browser.
*/
NativeImageDecoder.isDecodable =
function NativeImageDecoder_isDecodable(image, xref, res) {
var cs = ColorSpace.parse(image.dict.get('ColorSpace', 'CS'), xref, res);
var dict = image.dict;
if (dict.has('DecodeParms') || dict.has('DP')) {
return false;
}
var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res);
return (cs.numComps === 1 || cs.numComps === 3) &&
cs.isDefaultDecode(image.dict.getArray('Decode', 'D'));
cs.isDefaultDecode(dict.getArray('Decode', 'D'));
};
function PartialEvaluator(pdfManager, xref, handler, pageIndex,
@ -39286,12 +39330,10 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
* @param {Object} ref
* @param {string} uniquePrefix
* @param {Object} idCounters
* @param {boolean} renderInteractiveForms
* @returns {Annotation}
*/
create: function AnnotationFactory_create(xref, ref,
uniquePrefix, idCounters,
renderInteractiveForms) {
uniquePrefix, idCounters) {
var dict = xref.fetchIfRef(ref);
if (!isDict(dict)) {
return;
@ -39310,7 +39352,6 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
ref: isRef(ref) ? ref : null,
subtype: subtype,
id: id,
renderInteractiveForms: renderInteractiveForms,
};
switch (subtype) {
@ -39635,7 +39676,8 @@ var Annotation = (function AnnotationClosure() {
}.bind(this));
},
getOperatorList: function Annotation_getOperatorList(evaluator, task) {
getOperatorList: function Annotation_getOperatorList(evaluator, task,
renderForms) {
if (!this.appearance) {
return Promise.resolve(new OperatorList());
}
@ -39672,13 +39714,13 @@ var Annotation = (function AnnotationClosure() {
};
Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
annotations, opList, partialEvaluator, task, intent) {
annotations, opList, partialEvaluator, task, intent, renderForms) {
var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) {
if ((intent === 'display' && annotations[i].viewable) ||
(intent === 'print' && annotations[i].printable)) {
annotationPromises.push(
annotations[i].getOperatorList(partialEvaluator, task));
annotations[i].getOperatorList(partialEvaluator, task, renderForms));
}
}
return Promise.all(annotationPromises).then(function(operatorLists) {
@ -39896,14 +39938,13 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
*
* @public
* @memberof WidgetAnnotation
* @param {number} flag - Bit position, numbered from one instead of
* zero, to check
* @param {number} flag - Hexadecimal representation for an annotation
* field characteristic
* @return {boolean}
* @see {@link shared/util.js}
*/
hasFieldFlag: function WidgetAnnotation_hasFieldFlag(flag) {
var mask = 1 << (flag - 1);
return !!(this.data.fieldFlags & mask);
return !!(this.data.fieldFlags & flag);
},
});
@ -39914,8 +39955,6 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
function TextWidgetAnnotation(params) {
WidgetAnnotation.call(this, params);
this.renderInteractiveForms = params.renderInteractiveForms;
// Determine the alignment of text in the field.
var alignment = Util.getInheritableProperty(params.dict, 'Q');
if (!isInt(alignment) || alignment < 0 || alignment > 2) {
@ -39933,21 +39972,28 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
// Process field flags for the display layer.
this.data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY);
this.data.multiLine = this.hasFieldFlag(AnnotationFieldFlag.MULTILINE);
this.data.comb = this.hasFieldFlag(AnnotationFieldFlag.COMB) &&
!this.hasFieldFlag(AnnotationFieldFlag.MULTILINE) &&
!this.hasFieldFlag(AnnotationFieldFlag.PASSWORD) &&
!this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) &&
this.data.maxLen !== null;
}
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator,
task) {
getOperatorList:
function TextWidgetAnnotation_getOperatorList(evaluator, task,
renderForms) {
var operatorList = new OperatorList();
// Do not render form elements on the canvas when interactive forms are
// enabled. The display layer is responsible for rendering them instead.
if (this.renderInteractiveForms) {
if (renderForms) {
return Promise.resolve(operatorList);
}
if (this.appearance) {
return Annotation.prototype.getOperatorList.call(this, evaluator, task);
return Annotation.prototype.getOperatorList.call(this, evaluator, task,
renderForms);
}
// Even if there is an appearance stream, ignore it. This is the
@ -40448,8 +40494,6 @@ var Page = (function PageClosure() {
});
});
this.renderInteractiveForms = renderInteractiveForms;
var annotationsPromise = pdfManager.ensure(this, 'annotations');
return Promise.all([pageListPromise, annotationsPromise]).then(
function(datas) {
@ -40462,7 +40506,8 @@ var Page = (function PageClosure() {
}
var annotationsReadyPromise = Annotation.appendToOperatorList(
annotations, pageOpList, partialEvaluator, task, intent);
annotations, pageOpList, partialEvaluator, task, intent,
renderInteractiveForms);
return annotationsReadyPromise.then(function () {
pageOpList.flush(true);
return pageOpList;
@ -40533,8 +40578,7 @@ var Page = (function PageClosure() {
var annotationRef = annotationRefs[i];
var annotation = annotationFactory.create(this.xref, annotationRef,
this.uniquePrefix,
this.idCounters,
this.renderInteractiveForms);
this.idCounters);
if (annotation) {
annotations.push(annotation);
}

View File

@ -137,6 +137,22 @@
border: 1px solid transparent;
}
.annotationLayer .textWidgetAnnotation input.comb {
font-family: monospace;
padding-left: 2px;
padding-right: 0;
}
.annotationLayer .textWidgetAnnotation input.comb:focus {
/*
* Letter spacing is placed on the right side of each character. Hence, the
* letter spacing of the last character may be placed outside the visible
* area, causing horizontal scrolling. We avoid this by extending the width
* when the element has focus and revert this when it loses focus.
*/
width: 115%;
}
.annotationLayer .popupWrapper {
position: absolute;
width: 20em;

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,9 @@
// There are animations in the test page and since, by default, the <body> node
// is selected, animations will be displayed in the timeline, so the timeline
// play/resume button will be displayed
requestLongerTimeout(2);
add_task(function* () {
requestLongerTimeout(2);

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,6 @@ const svg = {
"globe": require("./globe.svg"),
"magnifying-glass": require("./magnifying-glass.svg"),
"pause": require("./pause.svg"),
"pause-circle": require("./pause-circle.svg"),
"pause-exceptions": require("./pause-exceptions.svg"),
"prettyPrint": require("./prettyPrint.svg"),
"resume": require("./resume.svg"),

View File

@ -1,6 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="33" height="12" viewBox="0 0 33 12">
<path id="base-path" d="M27.1,0H1C0.4,0,0,0.4,0,1v10c0,0.6,0.4,1,1,1h26.1 c0.6,0,1.2-0.3,1.5-0.7L33,6l-4.4-5.3C28.2,0.3,27.7,0,27.1,0z"/>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 60 12">
<path id="base-path" d="M53.9,0H1C0.4,0,0,0.4,0,1v10c0,0.6,0.4,1,1,1h52.9c0.6,0,1.2-0.3,1.5-0.7L60,6l-4.4-5.3C55,0.3,54.5,0,53.9,0z"/>
</svg>

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 460 B

View File

@ -46,7 +46,7 @@ var Debugger =
/***/ 0:
/***/ function(module, exports, __webpack_require__) {
var prettyFast = __webpack_require__(366);
var prettyFast = __webpack_require__(438);
self.onmessage = function (msg) {
var _prettyPrint = prettyPrint(msg.data);
@ -100,7 +100,7 @@ var Debugger =
/***/ },
/***/ 366:
/***/ 438:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
@ -122,8 +122,8 @@ var Debugger =
}(this, function () {
"use strict";
var acorn = this.acorn || __webpack_require__(367);
var sourceMap = this.sourceMap || __webpack_require__(368);
var acorn = this.acorn || __webpack_require__(439);
var sourceMap = this.sourceMap || __webpack_require__(440);
var SourceNode = sourceMap.SourceNode;
// If any of these tokens are seen before a "[" token, we know that "[" token
@ -982,7 +982,7 @@ var Debugger =
/***/ },
/***/ 367:
/***/ 439:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Acorn is a tiny, fast JavaScript parser written in JavaScript.
@ -3642,7 +3642,7 @@ var Debugger =
/***/ },
/***/ 368:
/***/ 440:
/***/ function(module, exports, __webpack_require__) {
/*
@ -3650,14 +3650,14 @@ var Debugger =
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
exports.SourceMapGenerator = __webpack_require__(369).SourceMapGenerator;
exports.SourceMapConsumer = __webpack_require__(375).SourceMapConsumer;
exports.SourceNode = __webpack_require__(377).SourceNode;
exports.SourceMapGenerator = __webpack_require__(441).SourceMapGenerator;
exports.SourceMapConsumer = __webpack_require__(447).SourceMapConsumer;
exports.SourceNode = __webpack_require__(449).SourceNode;
/***/ },
/***/ 369:
/***/ 441:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -3671,10 +3671,10 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var base64VLQ = __webpack_require__(370);
var util = __webpack_require__(372);
var ArraySet = __webpack_require__(373).ArraySet;
var MappingList = __webpack_require__(374).MappingList;
var base64VLQ = __webpack_require__(442);
var util = __webpack_require__(444);
var ArraySet = __webpack_require__(445).ArraySet;
var MappingList = __webpack_require__(446).MappingList;
/**
* An instance of the SourceMapGenerator represents a source map which is
@ -4064,7 +4064,7 @@ var Debugger =
/***/ },
/***/ 370:
/***/ 442:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4108,7 +4108,7 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var base64 = __webpack_require__(371);
var base64 = __webpack_require__(443);
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
@ -4213,7 +4213,7 @@ var Debugger =
/***/ },
/***/ 371:
/***/ 443:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4262,7 +4262,7 @@ var Debugger =
/***/ },
/***/ 372:
/***/ 444:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4588,7 +4588,7 @@ var Debugger =
/***/ },
/***/ 373:
/***/ 445:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4602,7 +4602,7 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var util = __webpack_require__(372);
var util = __webpack_require__(444);
/**
* A data structure which is a combination of an array and a set. Adding a new
@ -4692,7 +4692,7 @@ var Debugger =
/***/ },
/***/ 374:
/***/ 446:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4706,7 +4706,7 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var util = __webpack_require__(372);
var util = __webpack_require__(444);
/**
* Determine whether mappingB is after mappingA with respect to generated
@ -4785,7 +4785,7 @@ var Debugger =
/***/ },
/***/ 375:
/***/ 447:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4799,10 +4799,10 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var util = __webpack_require__(372);
var binarySearch = __webpack_require__(376);
var ArraySet = __webpack_require__(373).ArraySet;
var base64VLQ = __webpack_require__(370);
var util = __webpack_require__(444);
var binarySearch = __webpack_require__(448);
var ArraySet = __webpack_require__(445).ArraySet;
var base64VLQ = __webpack_require__(442);
/**
* A SourceMapConsumer instance represents a parsed source map which we can
@ -5367,7 +5367,7 @@ var Debugger =
/***/ },
/***/ 376:
/***/ 448:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -5454,7 +5454,7 @@ var Debugger =
/***/ },
/***/ 377:
/***/ 449:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -5468,8 +5468,8 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var SourceMapGenerator = __webpack_require__(369).SourceMapGenerator;
var util = __webpack_require__(372);
var SourceMapGenerator = __webpack_require__(441).SourceMapGenerator;
var util = __webpack_require__(444);
// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
// operating systems these days (capturing the result).

View File

@ -63,13 +63,17 @@
* 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/. */
:root.theme-light,
:root .theme-light {
--theme-search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
}
* {
box-sizing: border-box;
}
html,
body {
font-family: "SF UI Text", sans-serif;
height: 100%;
margin: 0;
padding: 0;
@ -102,30 +106,6 @@ body {
cursor: pointer;
}
.source-footer {
background: var(--theme-body-background);
position: absolute;
bottom: 0;
right: 0;
z-index: 100;
width: 100px;
opacity: 0.9;
}
.source-footer .command-bar {
float: right;
}
.command-bar > span {
cursor: pointer;
margin-right: 0.7em;
width: 1em;
height: 1.1em;
display: inline-block;
text-align: center;
transition: opacity 200ms;
}
.search-container {
position: absolute;
top: 0;
@ -146,6 +126,94 @@ body {
margin-top: 25px;
margin-right: 20px;
}
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.split-box {
display: flex;
flex: 1;
min-width: 0;
height: 100%;
width: 100%;
}
.split-box.vert {
flex-direction: row;
}
.split-box.horz {
flex-direction: column;
}
.split-box > .uncontrolled {
display: flex;
flex: 1;
min-width: 0;
overflow: auto;
}
.split-box > .controlled {
display: flex;
overflow: auto;
}
.split-box > .splitter {
background-image: none;
border: 0;
border-style: solid;
border-color: transparent;
background-color: var(--theme-splitter-color);
background-clip: content-box;
position: relative;
box-sizing: border-box;
/* Positive z-index positions the splitter on top of its siblings and makes
it clickable on both sides. */
z-index: 1;
}
.split-box.vert > .splitter {
min-width: calc(var(--devtools-splitter-inline-start-width) +
var(--devtools-splitter-inline-end-width) + 1px);
border-left-width: var(--devtools-splitter-inline-start-width);
border-right-width: var(--devtools-splitter-inline-end-width);
margin-left: calc(-1 * var(--devtools-splitter-inline-start-width) - 1px);
margin-right: calc(-1 * var(--devtools-splitter-inline-end-width));
cursor: ew-resize;
}
.split-box.horz > .splitter {
min-height: calc(var(--devtools-splitter-top-width) +
var(--devtools-splitter-bottom-width) + 1px);
border-top-width: var(--devtools-splitter-top-width);
border-bottom-width: var(--devtools-splitter-bottom-width);
margin-top: calc(-1 * var(--devtools-splitter-top-width) - 1px);
margin-bottom: calc(-1 * var(--devtools-splitter-bottom-width));
cursor: ns-resize;
}
.split-box.disabled {
pointer-events: none;
}
/**
* Make sure splitter panels are not processing any mouse
* events. This is good for performance during splitter
* bar dragging.
*/
.split-box.dragging > .controlled,
.split-box.dragging > .uncontrolled {
pointer-events: none;
}
.tree {
-webkit-user-select: none;
-moz-user-select: none;
@ -193,9 +261,19 @@ body {
.sources-header {
height: 30px;
border-bottom: 1px solid var(--theme-splitter-color);
padding-left: 10px;
padding: 0 10px;
line-height: 30px;
font-size: 1.2em;
display: flex;
align-items: baseline;
justify-content: space-between;
}
.sources-header-info {
font-size: 0.7em;
color: var(--theme-comment-alt);
font-weight: lighter;
white-space: nowrap;
}
.sources-list {
@ -313,6 +391,49 @@ ul.sources-list {
.sources-list .tree-node button {
position: fixed;
}
.source-footer {
background: var(--theme-body-background);
border-top: 1px solid var(--theme-splitter-color);
position: absolute;
bottom: 0;
left: 0;
right: 0;
opacity: 1;
z-index: 100;
}
.source-footer .command-bar {
float: right;
}
.command-bar > span {
cursor: pointer;
margin-right: 0.7em;
width: 1em;
height: 1.1em;
display: inline-block;
text-align: center;
transition: opacity 200ms;
}
.source-footer .prettyPrint.pretty {
stroke: var(--theme-highlight-blue);
}
.source-footer input:focus {
border-color: var(--theme-highlight-blue);
outline: none;
}
.source-footer input {
line-height: 16px;
margin: 7px;
border-radius: 2px;
border: 1px solid var(--theme-splitter-color);
padding-left: 4px;
font-size: 10px;
}
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -325,7 +446,7 @@ ul.sources-list {
*/
.editor-wrapper {
position: absolute;
height: calc(100% - 30px);
height: calc(100% - 31px);
width: 100%;
top: 30px;
left: 0px;
@ -391,7 +512,7 @@ ul.sources-list {
}
.welcomebox {
width: 100%;
width: calc(100% - 1px);
/* Offsetting it by 30px for the sources-header area */
height: calc(100% - 30px);
@ -404,45 +525,33 @@ ul.sources-list {
color: var(--theme-comment-alt);
background-color: var(--theme-tab-toolbar-background);
font-weight: lighter;
text-align: center;
z-index: 100;
}
.split-box {
display: flex;
flex: 1;
min-width: 0;
.close-btn path {
fill: var(--theme-body-color);
}
.split-box .uncontrolled {
display: flex;
flex: 1;
min-width: 0;
overflow: auto;
.close-btn .close {
width: 12px;
height: 12px;
padding: 2px;
text-align: center;
margin-top: 2px;
line-height: 5px;
transition: all 0.25s easeinout;
}
.split-box .controlled {
display: flex;
overflow: auto;
.close-btn .close svg {
width: 6px;
}
.split-box .splitter {
background-color: var(--theme-splitter-color);
flex: 0 0 1px;
position: relative;
.close-btn .close:hover {
background: var(--theme-selection-background);
border-radius: 2px;
}
/* The actual handle that users drag is a transparent element that's slightly wider than
the splitter element itself, so it's easier to grab it. */
.split-box .splitter .splitter-handle {
cursor: ew-resize;
position: absolute;
top: 0;
left: -4px;
width: 8px;
height: 100%;
/* Stack above the code-mirror editor so it's actually possible to grab the handle. */
z-index: 5;
.close-btn .close:hover path {
fill: white;
}
.breakpoints-list .breakpoint {
@ -451,6 +560,7 @@ ul.sources-list {
margin: 0.25em 0;
padding: 0.25em 0;
line-height: 1em;
position: relative;
}
.breakpoints-list .breakpoint.paused {
@ -480,6 +590,20 @@ ul.sources-list {
color: var(--theme-comment);
padding-left: 20px;
}
.breakpoint .close-btn {
position: absolute;
right: 6px;
top: 6px;
}
.breakpoint .close {
display: none;
}
.breakpoint:hover .close {
display: block;
}
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -812,10 +936,14 @@ ul.sources-list {
.right-sidebar .accordion {
overflow-y: auto;
overflow-x: hidden;
}
.right-sidebar .command-bar {
border-bottom: 1px solid var(--theme-splitter-color);
}
.command-bar {
border-bottom: 1px solid var(--theme-splitter-color);
height: 30px;
padding: 8px 5px 10px 10px;
}
@ -856,6 +984,14 @@ ul.sources-list {
.disableBreakpoints.breakpoints-disabled path {
stroke: var(--theme-highlight-blue);
}
span.pause-exceptions.uncaught {
stroke: var(--theme-highlight-purple);
}
span.pause-exceptions.all {
stroke: var(--theme-highlight-blue);
}
.source-header {
border-bottom: 1px solid var(--theme-splitter-color);
height: 30px;
@ -891,6 +1027,7 @@ ul.sources-list {
.source-tab.active {
color: var(--theme-body-color);
background-color: var(--theme-body-background);
height: 24px;
}
.source-tab path {
@ -903,10 +1040,16 @@ ul.sources-list {
.source-tab .close-btn {
position: absolute;
right: 7px;
top: 1px;
width: 6px;
height: 6px;
right: 4px;
top: 3px;
}
.source-tab .close {
display: none;
}
.source-tab:hover .close {
display: block;
}
.source-header .subsettings {
@ -944,16 +1087,6 @@ ul.sources-list {
margin: 0;
padding: 0;
}
.source-footer {
border-top: 1px solid var(--theme-splitter-color);
left: 0;
opacity: 1;
width: 100%;
}
.source-footer .prettyPrint.pretty {
stroke: var(--theme-highlight-blue);
}
.autocomplete {
width: 100%;

View File

@ -5,17 +5,24 @@ support-files =
head.js
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
examples/bundle.js
examples/bundle.js.map
examples/doc-scripts.html
examples/doc-script-switching.html
examples/doc-exceptions.html
examples/doc-iframes.html
examples/doc-debugger-statements.html
examples/code-exceptions.js
examples/code-simple1.js
examples/code-simple2.js
examples/code-long.js
examples/code-script-switching-02.js
examples/code-script-switching-01.js
examples/doc-sourcemaps.html
examples/entry.js
examples/exceptions.js
examples/opts.js
examples/long.js
examples/output.js
examples/simple1.js
examples/simple2.js
examples/script-switching-02.js
examples/script-switching-01.js
examples/times2.js
[browser_dbg-breaking.js]
[browser_dbg-breaking-from-console.js]

View File

@ -23,8 +23,7 @@ add_task(function* () {
yield paused;
yield resume(dbg);
const source = getSelectedSource(getState()).toJS();
// TODO: The url of an eval source should be null.
ok(source.url.indexOf("SOURCE") === 0, "It is an eval source");
ok(!source.url, "It is an eval source");
yield addBreakpoint(dbg, source, 5);
invokeInTab("evaledFunc");

View File

@ -8,7 +8,7 @@
add_task(function* () {
const dbg = yield initDebugger("doc-scripts.html");
const { selectors: { getSourceText }, getState } = dbg;
const sourceUrl = EXAMPLE_URL + "code-long.js";
const sourceUrl = EXAMPLE_URL + "long.js";
// The source itself doesn't even exist yet, and using
// `selectSourceURL` will set a pending request to load this source

View File

@ -12,6 +12,11 @@ function isElementVisible(dbg, elementName) {
}
add_task(function* () {
// This test runs too slowly on linux debug. I'd like to figure out
// which is the slowest part of this and make it run faster, but to
// fix a frequent failure allow a longer timeout.
requestLongerTimeout(2);
const dbg = yield initDebugger(
"doc-scripts.html",
"simple1.js", "simple2.js", "long.js"

View File

@ -0,0 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests sourcemaps.
add_task(function* () {
const dbg = yield initDebugger("doc-sourcemaps.html");
yield waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
ok(true, "Original sources exist");
yield selectSource(dbg, "output.js");
ok(dbg.win.cm.getValue().includes("function output"),
"Original source text loaded correctly");
});

View File

@ -0,0 +1,90 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
const times2 = __webpack_require__(1);
const { output } = __webpack_require__(2);
const opts = __webpack_require__(3);
output(times2(1));
output(times2(2));
if(opts.extra) {
output(times2(3));
}
/***/ },
/* 1 */
/***/ function(module, exports) {
module.exports = function(x) {
return x * 2;
}
/***/ },
/* 2 */
/***/ function(module, exports) {
function output(str) {
console.log(str);
}
module.exports = { output };
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = {
extra: true
};
/***/ }
/******/ ]);
//# sourceMappingURL=bundle.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap 54b46cf0214c369e95aa","webpack:///./entry.js","webpack:///./times2.js","webpack:///./output.js","webpack:///./opts.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;ACtCA;AACA,QAAO,SAAS;AAChB;;AAEA;AACA;;AAEA;AACA;AACA;;;;;;;ACTA;AACA;AACA;;;;;;;ACFA;AACA;AACA;;AAEA,mBAAkB;;;;;;;ACJlB;AACA;AACA","file":"bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 54b46cf0214c369e95aa\n **/","const times2 = require(\"./times2\");\nconst { output } = require(\"./output\");\nconst opts = require(\"./opts\");\n\noutput(times2(1));\noutput(times2(2));\n\nif(opts.extra) {\n output(times2(3));\n}\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./entry.js\n ** module id = 0\n ** module chunks = 0\n **/","module.exports = function(x) {\n return x * 2;\n}\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./times2.js\n ** module id = 1\n ** module chunks = 0\n **/","function output(str) {\n console.log(str);\n}\n\nmodule.exports = { output };\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./output.js\n ** module id = 2\n ** module chunks = 0\n **/","module.exports = {\n extra: true\n};\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./opts.js\n ** module id = 3\n ** module chunks = 0\n **/"],"sourceRoot":""}

View File

@ -1,7 +1,7 @@
<html>
<head>
<title>Debugger test page</title>
<script type="text/javascript" src="code-exceptions.js"></script>
<script type="text/javascript" src="exceptions.js"></script>
</head>
<body></body>
</html>

View File

@ -11,8 +11,8 @@
<body>
<button onclick="firstCall()">Click me!</button>
<script type="text/javascript" src="code-script-switching-01.js"></script>
<script type="text/javascript" src="code-script-switching-02.js"></script>
<script type="text/javascript" src="script-switching-01.js"></script>
<script type="text/javascript" src="script-switching-02.js"></script>
</body>
</html>

View File

@ -8,9 +8,9 @@
</head>
<body>
<script src="code-simple1.js"></script>
<script src="code-simple2.js"></script>
<script src="code-long.js"></script>
<script src="simple1.js"></script>
<script src="simple2.js"></script>
<script src="long.js"></script>
<script>
// This inline script allows this HTML page to show up as a
// source. It also needs to introduce a new global variable so

View File

@ -0,0 +1,13 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Debugger test page</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>

View File

@ -0,0 +1,10 @@
const times2 = require("./times2");
const { output } = require("./output");
const opts = require("./opts");
output(times2(1));
output(times2(2));
if(opts.extra) {
output(times2(3));
}

View File

@ -0,0 +1,3 @@
module.exports = {
extra: true
};

View File

@ -0,0 +1,5 @@
function output(str) {
console.log(str);
}
module.exports = { output };

View File

@ -0,0 +1,3 @@
module.exports = function(x) {
return x * 2;
}

View File

@ -0,0 +1,8 @@
module.exports = {
entry: "./entry.js",
output: {
filename: "bundle.js"
},
devtool: "sourcemap"
}

View File

@ -5,6 +5,35 @@
"use strict";
/**
* The Mochitest API documentation
* @module mochitest
*/
/**
* The mochitest API to wait for certain events.
* @module mochitest/waits
* @parent mochitest
*/
/**
* The mochitest API predefined asserts.
* @module mochitest/asserts
* @parent mochitest
*/
/**
* The mochitest API for interacting with the debugger.
* @module mochitest/actions
* @parent mochitest
*/
/**
* Helper methods for the mochitest API.
* @module mochitest/helpers
* @parent mochitest
*/
// shared-head.js handles imports, constants, and utility functions
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this);
var { Toolbox } = require("devtools/client/framework/toolbox");
@ -58,6 +87,17 @@ function _afterDispatchDone(store, type) {
});
}
/**
* Wait for a specific action type to be dispatch.
* If an async action, will wait for it to be done.
*
* @memberof mochitest/waits
* @param {Object} dbg
* @param {String} type
* @param {Number} eventRepeat
* @return {Promise}
* @static
*/
function waitForDispatch(dbg, type, eventRepeat = 1) {
let count = 0;
@ -71,6 +111,15 @@ function waitForDispatch(dbg, type, eventRepeat = 1) {
});
}
/**
* Waits for specific thread events.
*
* @memberof mochitest/waits
* @param {Object} dbg
* @param {String} eventName
* @return {Promise}
* @static
*/
function waitForThreadEvents(dbg, eventName) {
info("Waiting for thread event '" + eventName + "' to fire.");
const thread = dbg.toolbox.threadClient;
@ -84,6 +133,15 @@ function waitForThreadEvents(dbg, eventName) {
});
}
/**
* Waits for `predicate(state)` to be true. `state` is the redux app state.
*
* @memberof mochitest/waits
* @param {Object} dbg
* @param {Function} predicate
* @return {Promise}
* @static
*/
function waitForState(dbg, predicate) {
return new Promise(resolve => {
const unsubscribe = dbg.store.subscribe(() => {
@ -95,6 +153,15 @@ function waitForState(dbg, predicate) {
});
}
/**
* Waits for sources to be loaded.
*
* @memberof mochitest/waits
* @param {Object} dbg
* @param {Array} sources
* @return {Promise}
* @static
*/
function waitForSources(dbg, ...sources) {
if(sources.length === 0) {
return Promise.resolve();
@ -104,7 +171,9 @@ function waitForSources(dbg, ...sources) {
const {selectors: {getSources}, store} = dbg;
return Promise.all(sources.map(url => {
function sourceExists(state) {
return getSources(state).some(s => s.get("url").includes(url));
return getSources(state).some(s => {
return s.get("url").includes(url)
});
}
if(!sourceExists(store.getState())) {
@ -113,6 +182,15 @@ function waitForSources(dbg, ...sources) {
}));
}
/**
* Assert that the debugger is paused at the correct location.
*
* @memberof mochitest/asserts
* @param {Object} dbg
* @param {String} source
* @param {Number} line
* @static
*/
function assertPausedLocation(dbg, source, line) {
const { selectors: { getSelectedSource, getPause }, getState } = dbg;
source = findSource(dbg, source);
@ -130,6 +208,15 @@ function assertPausedLocation(dbg, source, line) {
"Line is highlighted as paused");
}
/**
* Assert that the debugger is highlighting the correct location.
*
* @memberof mochitest/asserts
* @param {Object} dbg
* @param {String} source
* @param {Number} line
* @static
*/
function assertHighlightLocation(dbg, source, line) {
const { selectors: { getSelectedSource, getPause }, getState } = dbg;
source = findSource(dbg, source);
@ -146,11 +233,25 @@ function assertHighlightLocation(dbg, source, line) {
"Line is highlighted");
}
/**
* Returns boolean for whether the debugger is paused.
*
* @memberof mochitest/asserts
* @param {Object} dbg
* @static
*/
function isPaused(dbg) {
const { selectors: { getPause }, getState } = dbg;
return !!getPause(getState());
}
/**
* Waits for the debugger to be fully paused.
*
* @memberof mochitest/waits
* @param {Object} dbg
* @static
*/
function waitForPaused(dbg) {
return Task.spawn(function* () {
// We want to make sure that we get both a real paused event and
@ -187,6 +288,15 @@ function createDebuggerContext(toolbox) {
};
}
/**
* Intilializes the debugger.
*
* @memberof mochitest
* @param {String} url
* @param {Array} sources
* @return {Promise} dbg
* @static
*/
function initDebugger(url, ...sources) {
return Task.spawn(function* () {
const toolbox = yield openNewTabAndToolbox(EXAMPLE_URL + url, "jsdebugger");
@ -197,13 +307,28 @@ function initDebugger(url, ...sources) {
};
window.resumeTest = undefined;
/**
* Pause the test and let you interact with the debugger.
* The test can be resumed by invoking `resumeTest` in the console.
*
* @memberof mochitest
* @static
*/
function pauseTest() {
info("Test paused. Invoke resumeTest to continue.");
return new Promise(resolve => resumeTest = resolve);
}
// Actions
/**
* Returns a source that matches the URL.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {String} url
* @return {Object} source
* @static
*/
function findSource(dbg, url) {
if(typeof url !== "string") {
// Support passing in a source object itelf all APIs that use this
@ -222,6 +347,16 @@ function findSource(dbg, url) {
return source.toJS();
}
/**
* Selects the source.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {String} url
* @param {Number} line
* @return {Promise}
* @static
*/
function selectSource(dbg, url, line) {
info("Selecting source: " + url);
const source = findSource(dbg, url);
@ -233,49 +368,132 @@ function selectSource(dbg, url, line) {
}
}
/**
* Steps over.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @return {Promise}
* @static
*/
function stepOver(dbg) {
info("Stepping over");
dbg.actions.stepOver();
return waitForPaused(dbg);
}
/**
* Steps in.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @return {Promise}
* @static
*/
function stepIn(dbg) {
info("Stepping in");
dbg.actions.stepIn();
return waitForPaused(dbg);
}
/**
* Steps out.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @return {Promise}
* @static
*/
function stepOut(dbg) {
info("Stepping out");
dbg.actions.stepOut();
return waitForPaused(dbg);
}
/**
* Resumes.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @return {Promise}
* @static
*/
function resume(dbg) {
info("Resuming");
dbg.actions.resume();
return waitForThreadEvents(dbg, "resumed");
}
/**
* Reloads the debuggee.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {Array} sources
* @return {Promise}
* @static
*/
function reload(dbg, ...sources) {
return dbg.client.reload().then(() => waitForSources(...sources));
}
/**
* Navigates the debuggee to another url.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {String} url
* @param {Array} sources
* @return {Promise}
* @static
*/
function navigate(dbg, url, ...sources) {
dbg.client.navigate(url);
return waitForSources(dbg, ...sources)
}
/**
* Adds a breakpoint to a source at line/col.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {String} source
* @param {Number} line
* @param {Number} col
* @return {Promise}
* @static
*/
function addBreakpoint(dbg, source, line, col) {
source = findSource(dbg, source);
const sourceId = source.id;
return dbg.actions.addBreakpoint({ sourceId, line, col });
}
/**
* Removes a breakpoint from a source at line/col.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {String} source
* @param {Number} line
* @param {Number} col
* @return {Promise}
* @static
*/
function removeBreakpoint(dbg, sourceId, line, col) {
return dbg.actions.removeBreakpoint({ sourceId, line, col });
}
/**
* Toggles the Pause on exceptions feature in the debugger.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @param {Boolean} pauseOnExceptions
* @param {Boolean} ignoreCaughtExceptions
* @return {Promise}
* @static
*/
function togglePauseOnExceptions(dbg,
pauseOnExceptions, ignoreCaughtExceptions) {
@ -292,7 +510,15 @@ function togglePauseOnExceptions(dbg,
}
// Helpers
// invoke a global function in the debugged tab
/**
* Invokes a global function in the debuggee tab.
*
* @memberof mochitest/helpers
* @param {String} fnc
* @return {Promise}
* @static
*/
function invokeInTab(fnc) {
info(`Invoking function ${fnc} in tab`);
return ContentTask.spawn(gBrowser.selectedBrowser, fnc, function* (fnc) {
@ -309,6 +535,15 @@ const keyMappings = {
stepOutKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux, shiftKey: true } }
};
/**
* Simulates a key press in the debugger window.
*
* @memberof mochitest/helpers
* @param {Object} dbg
* @param {String} keyName
* @return {Promise}
* @static
*/
function pressKey(dbg, keyName) {
let keyEvent = keyMappings[keyName];
const { code, modifiers } = keyEvent;
@ -363,7 +598,16 @@ function findAllElements(dbg, elementName, ...args) {
return dbg.win.document.querySelectorAll(selector);
}
// click an element in the debugger
/**
* Simulates a mouse click in the debugger DOM.
*
* @memberof mochitest/helpers
* @param {Object} dbg
* @param {String} elementName
* @param {Array} args
* @return {Promise}
* @static
*/
function clickElement(dbg, elementName, ...args) {
const selector = getSelector(elementName, ...args);
const doc = dbg.win.document;
@ -374,6 +618,14 @@ function clickElement(dbg, elementName, ...args) {
);
}
/**
* Toggles the debugger call stack accordian.
*
* @memberof mochitest/actions
* @param {Object} dbg
* @return {Promise}
* @static
*/
function toggleCallStack(dbg) {
return findElement(dbg, "callStackHeader").click()
}

View File

@ -1263,21 +1263,15 @@ Toolbox.prototype = {
// Prevent flicker while loading by waiting to make visible until now.
iframe.style.visibility = "visible";
// Try to set the dir attribute as early as possible.
this.setIframeDocumentDir(iframe);
// The build method should return a panel instance, so events can
// be fired with the panel as an argument. However, in order to keep
// backward compatibility with existing extensions do a check
// for a promise return value.
let built = definition.build(iframe.contentWindow, this);
// Set the dir attribute on the documents of panels using HTML.
let docEl = iframe.contentWindow && iframe.contentWindow.document.documentElement;
if (docEl && docEl.namespaceURI === HTML_NS) {
let top = this.win.top;
let topDocEl = top.document.documentElement;
let isRtl = top.getComputedStyle(topDocEl).direction === "rtl";
docEl.setAttribute("dir", isRtl ? "rtl" : "ltr");
}
if (!(typeof built.then == "function")) {
let panel = built;
iframe.panel = panel;
@ -1350,6 +1344,28 @@ Toolbox.prototype = {
return deferred.promise;
},
/**
* Set the dir attribute on the content document element of the provided iframe.
*
* @param {IFrameElement} iframe
*/
setIframeDocumentDir: function (iframe) {
let docEl = iframe.contentWindow && iframe.contentWindow.document.documentElement;
if (!docEl || docEl.namespaceURI !== HTML_NS) {
// Bail out if the content window or document is not ready or if the document is not
// HTML.
return;
}
if (docEl.hasAttribute("dir")) {
// Set the dir attribute value only if dir is already present on the document.
let top = this.win.top;
let topDocEl = top.document.documentElement;
let isRtl = top.getComputedStyle(topDocEl).direction === "rtl";
docEl.setAttribute("dir", isRtl ? "rtl" : "ltr");
}
},
/**
* Mark all in collection as unselected; and id as selected
* @param {string} collection

View File

@ -20,7 +20,7 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html xmlns="http://www.w3.org/1999/xhtml" dir="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="application/javascript;version=1.8"

View File

@ -9,7 +9,7 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<html xmlns="http://www.w3.org/1999/xhtml" dir="">
<head>
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/memory.css" type="text/css"/>

View File

@ -122,18 +122,42 @@ function waitForFrameLoad(ui, targetURL) {
}
function waitForViewportResizeTo(ui, width, height) {
return new Promise(resolve => {
return new Promise(Task.async(function* (resolve) {
let isSizeMatching = (data) => data.width == width && data.height == height;
// If the viewport has already the expected size, we resolve the promise immediately.
let size = yield getContentSize(ui);
if (isSizeMatching(size)) {
resolve();
return;
}
// Otherwise, we'll listen to both content's resize event and browser's load end;
// since a racing condition can happen, where the content's listener is added after
// the resize, because the content's document was reloaded; therefore the test would
// hang forever. See bug 1302879.
let browser = ui.getViewportBrowser();
let onResize = (_, data) => {
if (data.width != width || data.height != height) {
if (!isSizeMatching(data)) {
return;
}
ui.off("content-resize", onResize);
browser.removeEventListener("mozbrowserloadend", onBrowserLoadEnd);
info(`Got content-resize to ${width} x ${height}`);
resolve();
};
let onBrowserLoadEnd = Task.async(function* () {
let data = yield getContentSize(ui);
onResize(undefined, data);
});
info(`Waiting for content-resize to ${width} x ${height}`);
ui.on("content-resize", onResize);
});
browser.addEventListener("mozbrowserloadend",
onBrowserLoadEnd, { once: true });
}));
}
var setViewportSize = Task.async(function* (ui, manager, width, height) {
@ -250,6 +274,13 @@ function getSessionHistory(browser) {
});
}
function getContentSize(ui) {
return spawnViewportTask(ui, {}, () => ({
width: content.screen.width,
height: content.screen.height
}));
}
function waitForPageShow(browser) {
let mm = browser.messageManager;
return new Promise(resolve => {

View File

@ -5,7 +5,7 @@
#sidebar-panel-computedview {
margin: 0;
display : flex;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
@ -61,7 +61,8 @@
}
.property-view {
padding: 2px 17px;
padding: 2px 0px;
padding-inline-start: 5px;
display: flex;
flex-wrap: wrap;
}
@ -105,17 +106,21 @@
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 10px;
padding-inline-start: 14px;
outline: 0 !important;
}
.other-property-value {
background-position: left center;
padding-left: 8px;
padding-inline-start: 8px;
}
.other-property-value:dir(rtl) {
background-position-x: right;
}
.property-content {
padding-left: 17px;
padding-inline-start: 17px;
}
.theme-firebug .property-view,
@ -130,7 +135,6 @@
/* From skin */
.expander {
visibility: hidden;
margin-inline-start: -12px !important;
}
.expandable {
@ -143,7 +147,8 @@
.matchedselectors > p {
clear: both;
margin: 0 2px 0 0;
margin: 0;
margin-inline-end: 2px;
padding: 2px;
overflow-x: hidden;
border-style: dotted;
@ -181,6 +186,11 @@
float: right;
}
/* Workaround until float: inline-end; is enabled by default */
.link:dir(rtl) {
float: left;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */

View File

@ -51,7 +51,8 @@ window {
/* Minimum width for the Inspector main (uncontrolled) area. */
#inspector-splitter-box .uncontrolled {
min-width: 275px;
min-height: 50px;
min-width: 50px;
}
#inspector-splitter-box .controlled.pane-collapsed {

View File

@ -44,6 +44,7 @@ Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/collection_validator.js");
Cu.import("resource://services-common/async.js");
Cu.import("resource://gre/modules/Preferences.jsm");
@ -53,7 +54,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
"resource://gre/modules/addons/AddonRepository.jsm");
this.EXPORTED_SYMBOLS = ["AddonsEngine"];
this.EXPORTED_SYMBOLS = ["AddonsEngine", "AddonValidator"];
// 7 days in milliseconds.
const PRUNE_ADDON_CHANGES_THRESHOLD = 60 * 60 * 24 * 7 * 1000;
@ -176,7 +177,7 @@ AddonsEngine.prototype = {
continue;
}
if (!this._store.isAddonSyncable(addons[id])) {
if (!this.isAddonSyncable(addons[id])) {
continue;
}
@ -234,6 +235,10 @@ AddonsEngine.prototype = {
let cb = Async.makeSpinningCallback();
this._reconciler.refreshGlobalState(cb);
cb.wait();
},
isAddonSyncable(addon, ignoreRepoCheck) {
return this._store.isAddonSyncable(addon, ignoreRepoCheck);
}
};
@ -533,9 +538,12 @@ AddonsStore.prototype = {
*
* @param addon
* Addon instance
* @param ignoreRepoCheck
* Should we skip checking the Addons repository (primarially useful
* for testing and validation).
* @return Boolean indicating whether it is appropriate for Sync
*/
isAddonSyncable: function isAddonSyncable(addon) {
isAddonSyncable: function isAddonSyncable(addon, ignoreRepoCheck = false) {
// Currently, we limit syncable add-ons to those that are:
// 1) In a well-defined set of types
// 2) Installed in the current profile
@ -592,8 +600,9 @@ AddonsStore.prototype = {
// If the AddonRepository's cache isn't enabled (which it typically isn't
// in tests), getCachedAddonByID always returns null - so skip the check
// in that case.
if (!AddonRepository.cacheEnabled) {
// in that case. We also provide a way to specifically opt-out of the check
// even if the cache is enabled, which is used by the validators.
if (ignoreRepoCheck || !AddonRepository.cacheEnabled) {
return true;
}
@ -736,3 +745,69 @@ AddonsTracker.prototype = {
this.reconciler.stopListening();
},
};
class AddonValidator extends CollectionValidator {
constructor(engine = null) {
super("addons", "id", [
"addonID",
"enabled",
"applicationID",
"source"
]);
this.engine = engine;
}
getClientItems() {
return Promise.all([
new Promise(resolve =>
AddonManager.getAllAddons(resolve)),
new Promise(resolve =>
AddonManager.getAddonsWithOperationsByTypes(["extension", "theme"], resolve)),
]).then(([installed, addonsWithPendingOperation]) => {
// Addons pending install won't be in the first list, but addons pending
// uninstall/enable/disable will be in both lists.
let all = new Map(installed.map(addon => [addon.id, addon]));
for (let addon of addonsWithPendingOperation) {
all.set(addon.id, addon);
}
// Convert to an array since Map.prototype.values returns an iterable
return [...all.values()];
});
}
normalizeClientItem(item) {
let enabled = !item.userDisabled;
if (item.pendingOperations & AddonManager.PENDING_ENABLE) {
enabled = true;
} else if (item.pendingOperations & AddonManager.PENDING_DISABLE) {
enabled = false;
}
return {
enabled,
id: item.syncGUID,
addonID: item.id,
applicationID: Services.appinfo.ID,
source: "amo", // check item.foreignInstall?
original: item
};
}
normalizeServerItem(item) {
let guid = this.engine._findDupe(item);
if (guid) {
item.id = guid;
}
return item;
}
clientUnderstands(item) {
return item.applicationID === Services.appinfo.ID;
}
syncedByClient(item) {
return !item.original.hidden &&
!item.original.isSystem &&
!(item.original.pendingOperations & AddonManager.PENDING_UNINSTALL) &&
this.engine.isAddonSyncable(item.original, true);
}
}

View File

@ -33,7 +33,8 @@ Phase("phase01", [
[Sync]
]);
Phase("phase02", [
[Addons.verify, [id], STATE_ENABLED]
[Addons.verify, [id], STATE_ENABLED],
[Sync]
]);
Phase("phase03", [
[Addons.verifyNot, [id]],
@ -41,6 +42,7 @@ Phase("phase03", [
]);
Phase("phase04", [
[Addons.verify, [id], STATE_ENABLED],
[Sync]
]);
// Now we disable the add-on
@ -51,13 +53,15 @@ Phase("phase05", [
]);
Phase("phase06", [
[Addons.verify, [id], STATE_DISABLED],
[Sync]
]);
Phase("phase07", [
[Addons.verify, [id], STATE_ENABLED],
[Sync]
]);
Phase("phase08", [
[Addons.verify, [id], STATE_DISABLED]
[Addons.verify, [id], STATE_DISABLED],
[Sync]
]);
// Now we re-enable it again.
@ -68,13 +72,15 @@ Phase("phase09", [
]);
Phase("phase10", [
[Addons.verify, [id], STATE_ENABLED],
[Sync]
]);
Phase("phase11", [
[Addons.verify, [id], STATE_DISABLED],
[Sync]
]);
Phase("phase12", [
[Addons.verify, [id], STATE_ENABLED]
[Addons.verify, [id], STATE_ENABLED],
[Sync]
]);
// And we uninstall it
@ -86,12 +92,14 @@ Phase("phase13", [
[Sync]
]);
Phase("phase14", [
[Addons.verifyNot, [id]]
[Addons.verifyNot, [id]],
[Sync]
]);
Phase("phase15", [
[Addons.verify, [id], STATE_ENABLED],
[Sync]
]);
Phase("phase16", [
[Addons.verifyNot, [id]]
[Addons.verifyNot, [id]],
[Sync]
]);

View File

@ -34,6 +34,9 @@ Phase("phase02", [
Phase("phase03", [
[Sync], // Get GUID updates, potentially.
[Addons.setEnabled, [id], STATE_DISABLED],
// We've changed the state, but don't want this profile to sync until phase5,
// so if we ran a validation now we'd be expecting to find errors.
[Addons.skipValidation]
]);
Phase("phase04", [
[EnsureTracking],

View File

@ -25,5 +25,6 @@ Phase("phase1", [
Phase("phase2", [
// Add-on should be present after restart
[Addons.verify, [id], STATE_ENABLED]
[Addons.verify, [id], STATE_ENABLED],
[Sync] // Sync to ensure everything is initialized enough for the addon validator to run
]);

View File

@ -30,5 +30,6 @@ Phase("phase02", [
]);
Phase("phase03", [
[Addons.verify, [id1], STATE_ENABLED],
[Addons.verify, [id2], STATE_ENABLED]
[Addons.verify, [id2], STATE_ENABLED],
[Sync] // Sync to ensure that the addon validator can run without error
]);

View File

@ -26,6 +26,7 @@ Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/bookmark_validator.js");
Cu.import("resource://services-sync/engines/passwords.js");
Cu.import("resource://services-sync/engines/forms.js");
Cu.import("resource://services-sync/engines/addons.js");
// TPS modules
Cu.import("resource://tps/logger.jsm");
@ -113,6 +114,7 @@ var TPS = {
_triggeredSync: false,
_usSinceEpoch: 0,
_requestedQuit: false,
shouldValidateAddons: false,
shouldValidateBookmarks: false,
shouldValidatePasswords: false,
shouldValidateForms: false,
@ -464,6 +466,7 @@ var TPS = {
},
HandleAddons: function (addons, action, state) {
this.shouldValidateAddons = true;
for (let entry of addons) {
Logger.logInfo("executing action " + action.toUpperCase() +
" on addon " + JSON.stringify(entry));
@ -661,66 +664,64 @@ var TPS = {
Logger.logInfo("Bookmark validation finished");
},
ValidatePasswords() {
let serverRecordDumpStr;
try {
Logger.logInfo("About to perform password validation");
let pwEngine = Weave.Service.engineManager.get("passwords");
let validator = new PasswordValidator();
let serverRecords = validator.getServerItems(pwEngine);
let clientRecords = Async.promiseSpinningly(validator.getClientItems());
serverRecordDumpStr = JSON.stringify(serverRecords);
let { problemData } = validator.compareClientWithServer(clientRecords, serverRecords);
for (let { name, count } of problemData.getSummary()) {
if (count) {
Logger.logInfo(`Validation problem: "${name}": ${JSON.stringify(problemData[name])}`);
}
Logger.AssertEqual(count, 0, `Password validation error of type ${name}`);
}
} catch (e) {
// Dump the client records (should always be doable)
DumpPasswords();
// Dump the server records if gotten them already.
if (serverRecordDumpStr) {
Logger.logInfo("Server password records:\n" + serverRecordDumpStr + "\n");
}
this.DumpError("Password validation failed", e);
}
Logger.logInfo("Password validation finished");
},
ValidateForms() {
ValidateCollection(engineName, ValidatorType) {
let serverRecordDumpStr;
let clientRecordDumpStr;
try {
Logger.logInfo("About to perform form validation");
let engine = Weave.Service.engineManager.get("forms");
let validator = new FormValidator();
Logger.logInfo(`About to perform validation for "${engineName}"`);
let engine = Weave.Service.engineManager.get(engineName);
let validator = new ValidatorType(engine);
let serverRecords = validator.getServerItems(engine);
let clientRecords = Async.promiseSpinningly(validator.getClientItems());
clientRecordDumpStr = JSON.stringify(clientRecords, undefined, 2);
serverRecordDumpStr = JSON.stringify(serverRecords, undefined, 2);
try {
// This substantially improves the logs for addons while not making a
// substantial difference for the other two
clientRecordDumpStr = JSON.stringify(clientRecords.map(r => {
let res = validator.normalizeClientItem(r);
delete res.original; // Try and prevent cyclic references
return res;
}));
} catch (e) {
// ignore the error, the dump string is just here to make debugging easier.
clientRecordDumpStr = "<Cyclic value>";
}
try {
serverRecordDumpStr = JSON.stringify(serverRecords);
} catch (e) {
// as above
serverRecordDumpStr = "<Cyclic value>";
}
let { problemData } = validator.compareClientWithServer(clientRecords, serverRecords);
for (let { name, count } of problemData.getSummary()) {
if (count) {
Logger.logInfo(`Validation problem: "${name}": ${JSON.stringify(problemData[name])}`);
}
Logger.AssertEqual(count, 0, `Form validation error of type ${name}`);
Logger.AssertEqual(count, 0, `Validation error for "${engineName}" of type "${name}"`);
}
} catch (e) {
// Dump the client records if possible
if (clientRecordDumpStr) {
Logger.logInfo("Client forms records:\n" + clientRecordDumpStr + "\n");
Logger.logInfo(`Client state for ${engineName}:\n${clientRecordDumpStr}\n`);
}
// Dump the server records if gotten them already.
if (serverRecordDumpStr) {
Logger.logInfo("Server forms records:\n" + serverRecordDumpStr + "\n");
Logger.logInfo(`Server state for ${engineName}:\n${serverRecordDumpStr}\n`);
}
this.DumpError("Form validation failed", e);
this.DumpError(`Validation failed for ${engineName}`, e);
}
Logger.logInfo("Form validation finished");
Logger.logInfo(`Validation finished for ${engineName}`);
},
ValidatePasswords() {
return this.ValidateCollection("passwords", PasswordValidator);
},
ValidateForms() {
return this.ValidateCollection("forms", FormValidator);
},
ValidateAddons() {
return this.ValidateCollection("addons", AddonValidator);
},
RunNextTestAction: function() {
@ -737,6 +738,9 @@ var TPS = {
if (this.shouldValidateForms) {
this.ValidateForms();
}
if (this.shouldValidateAddons) {
this.ValidateAddons();
}
// we're all done
Logger.logInfo("test phase " + this._currentPhase + ": " +
(this._errors ? "FAIL" : "PASS"));
@ -1137,6 +1141,9 @@ var Addons = {
verifyNot: function Addons__verifyNot(addons) {
TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
},
skipValidation() {
TPS.shouldValidateAddons = false;
}
};
var Bookmarks = {