merge m-c into fig

This commit is contained in:
Margaret Leibovic 2013-07-22 12:11:05 -07:00
commit b2c048be2d
1428 changed files with 46246 additions and 26756 deletions

View File

@ -17,5 +17,5 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 889503 - Move Settings API to WebIDL.
Requires a clobber due to Bug 890744.
Bug 886886 - replace fixed-ratio capture resampler in webrtc with speex resampler
Requires a clobber due to modification of a .gypi file without a .gyp or configure.in change

View File

@ -11,7 +11,7 @@ typedef long AccessibleTextBoundary;
interface nsIAccessible;
interface nsIPersistentProperties;
[scriptable, uuid(0f4633b1-550c-4b50-8c04-0eb1005eef2f)]
[scriptable, uuid(43d81eb0-1215-4dc4-9226-a4355bd2d20d)]
interface nsIAccessibleText : nsISupports
{
// In parameters for character offsets:
@ -27,7 +27,6 @@ interface nsIAccessibleText : nsISupports
const AccessibleTextBoundary BOUNDARY_SENTENCE_END = 4; // don't use, deprecated
const AccessibleTextBoundary BOUNDARY_LINE_START = 5;
const AccessibleTextBoundary BOUNDARY_LINE_END = 6;
const AccessibleTextBoundary BOUNDARY_ATTRIBUTE_RANGE = 7;
/**
* The current current caret offset.

View File

@ -112,7 +112,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoLiveAttr,
eTableCell,
kNoReqStates,
eARIASelectable,
eARIASelectableIfDefined,
eARIAReadonlyOrEditableIfDefined
},
{ // combobox
@ -463,7 +463,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoLiveAttr,
eTableCell,
kNoReqStates,
eARIASelectable,
eARIASelectableIfDefined,
eARIAReadonlyOrEditableIfDefined
},
{ // scrollbar

View File

@ -300,6 +300,16 @@ aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState)
return true;
}
case eARIASelectableIfDefined:
{
static const TokenTypeData data(
nsGkAtoms::aria_selected, eBoolType,
states::SELECTABLE, states::SELECTED);
MapTokenType(aElement, aState, data);
return true;
}
case eReadonlyUntilEditable:
{
if (!(*aState & states::EDITABLE))

View File

@ -42,6 +42,7 @@ enum EStateRule
eARIAReadonlyOrEditableIfDefined,
eARIARequired,
eARIASelectable,
eARIASelectableIfDefined,
eReadonlyUntilEditable,
eIndeterminateIfNoValue
};

View File

@ -300,7 +300,7 @@ IDRefsIterator::GetElem(const nsDependentSubstring& aID)
// In case of bound element check its anonymous subtree.
if (!mContent->IsInAnonymousSubtree()) {
dom::Element* refElm = mContent->OwnerDoc()->GetElementById(aID);
if (refElm || !mContent->OwnerDoc()->BindingManager()->GetBinding(mContent))
if (refElm || !mContent->GetXBLBinding())
return refElm;
}
@ -318,7 +318,7 @@ IDRefsIterator::GetElem(const nsDependentSubstring& aID)
}
// Check inside the binding of the element.
if (mContent->OwnerDoc()->BindingManager()->GetBinding(mContent)) {
if (mContent->GetXBLBinding()) {
return mContent->OwnerDoc()->
GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid, aID);
}

View File

@ -871,7 +871,10 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
if (content->IsNodeOfType(nsINode::eTEXT)) {
nsAutoString text;
frame->GetRenderedText(&text, nullptr, nullptr, 0, UINT32_MAX);
if (text.IsEmpty()) {
// Ignore not rendered text nodes and whitespace text nodes between table
// cells.
if (text.IsEmpty() ||
(aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text))) {
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;

View File

@ -654,6 +654,20 @@ nsCoreUtils::ScrollTo(nsIPresShell* aPresShell, nsIContent* aContent,
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
}
bool
nsCoreUtils::IsWhitespaceString(const nsSubstring& aString)
{
nsSubstring::const_char_iterator iterBegin, iterEnd;
aString.BeginReading(iterBegin);
aString.EndReading(iterEnd);
while (iterBegin != iterEnd && IsWhitespace(*iterBegin))
++iterBegin;
return iterBegin == iterEnd;
}
////////////////////////////////////////////////////////////////////////////////
// nsAccessibleDOMStringList

View File

@ -6,7 +6,6 @@
#ifndef nsCoreUtils_h_
#define nsCoreUtils_h_
#include "nsIContent.h"
#include "nsIBoxObject.h"
#include "nsIPresShell.h"
@ -294,6 +293,21 @@ public:
aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scope);
}
/**
* Returns true if the given string is empty or contains whitespace symbols
* only. In contrast to nsWhitespaceTokenizer class it takes into account
* non-breaking space (0xa0).
*/
static bool IsWhitespaceString(const nsSubstring& aString);
/**
* Returns true if the given character is whitespace symbol.
*/
static bool IsWhitespace(PRUnichar aChar)
{
return aChar == ' ' || aChar == '\n' ||
aChar == '\r' || aChar == '\t' || aChar == 0xa0;
}
};

View File

@ -45,7 +45,7 @@ nsTextEquivUtils::GetNameFromSubtree(Accessible* aAccessible,
nsAutoString name;
AppendFromAccessibleChildren(aAccessible, &name);
name.CompressWhitespace();
if (!IsWhitespaceString(name))
if (!nsCoreUtils::IsWhitespaceString(name))
aName = name;
}
}
@ -351,38 +351,17 @@ nsTextEquivUtils::AppendString(nsAString *aString,
return false;
// Insert spaces to insure that words from controls aren't jammed together.
if (!aString->IsEmpty() && !IsWhitespace(aString->Last()))
if (!aString->IsEmpty() && !nsCoreUtils::IsWhitespace(aString->Last()))
aString->Append(PRUnichar(' '));
aString->Append(aTextEquivalent);
if (!IsWhitespace(aString->Last()))
if (!nsCoreUtils::IsWhitespace(aString->Last()))
aString->Append(PRUnichar(' '));
return true;
}
bool
nsTextEquivUtils::IsWhitespaceString(const nsSubstring& aString)
{
nsSubstring::const_char_iterator iterBegin, iterEnd;
aString.BeginReading(iterBegin);
aString.EndReading(iterEnd);
while (iterBegin != iterEnd && IsWhitespace(*iterBegin))
++iterBegin;
return iterBegin == iterEnd;
}
bool
nsTextEquivUtils::IsWhitespace(PRUnichar aChar)
{
return aChar == ' ' || aChar == '\n' ||
aChar == '\r' || aChar == '\t' || aChar == 0xa0;
}
uint32_t
nsTextEquivUtils::GetRoleRule(role aRole)
{

View File

@ -137,18 +137,6 @@ private:
static bool AppendString(nsAString *aString,
const nsAString& aTextEquivalent);
/**
* Returns true if the given string is empty or contains whitespace symbols
* only. In contrast to nsWhitespaceTokenizer class it takes into account
* non-breaking space (0xa0).
*/
static bool IsWhitespaceString(const nsSubstring& aString);
/**
* Returns true if the given character is whitespace symbol.
*/
static bool IsWhitespace(PRUnichar aChar);
/**
* Returns the rule (constant of ETextEquivRule) for a given role.
*/

View File

@ -465,8 +465,8 @@ ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), aNotify);
else
rv = content->UnsetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected, aNotify);
rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("false"), aNotify);
NS_ENSURE_SUCCESS(rv, rv);
@ -533,6 +533,7 @@ ARIAGridCellAccessible::
ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
HyperTextAccessibleWrap(aContent, aDoc), xpcAccessibleTableCell(this)
{
mGenericTypes |= eTableCell;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -515,6 +515,7 @@ public:
bool IsTable() const { return HasGenericType(eTable); }
virtual TableAccessible* AsTable() { return nullptr; }
bool IsTableCell() const { return HasGenericType(eTableCell); }
virtual TableCellAccessible* AsTableCell() { return nullptr; }
const TableCellAccessible* AsTableCell() const
{ return const_cast<Accessible*>(this)->AsTableCell(); }

View File

@ -878,186 +878,6 @@ HyperTextAccessible::FindLineBoundary(int32_t aOffset,
return -1;
}
/*
Gets the specified text relative to aBoundaryType, which means:
BOUNDARY_CHAR The character before/at/after the offset is returned.
BOUNDARY_WORD_START From the word start before/at/after the offset to the next word start.
BOUNDARY_WORD_END From the word end before/at/after the offset to the next work end.
BOUNDARY_LINE_START From the line start before/at/after the offset to the next line start.
BOUNDARY_LINE_END From the line end before/at/after the offset to the next line start.
*/
nsresult
HyperTextAccessible::GetTextHelper(EGetTextType aType,
AccessibleTextBoundary aBoundaryType,
int32_t aOffset,
int32_t* aStartOffset, int32_t* aEndOffset,
nsAString& aText)
{
aText.Truncate();
NS_ENSURE_ARG_POINTER(aStartOffset);
NS_ENSURE_ARG_POINTER(aEndOffset);
*aStartOffset = *aEndOffset = 0;
int32_t offset = ConvertMagicOffset(aOffset);
if (offset < 0)
return NS_ERROR_INVALID_ARG;
if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET && offset > 0 &&
(aBoundaryType == BOUNDARY_LINE_START ||
aBoundaryType == BOUNDARY_LINE_END)) {
// It is the same character offset when the caret is visually at
// the very end of a line or the start of a new line. Getting text at
// the line should provide the line with the visual caret,
// otherwise screen readers will announce the wrong line as the user
// presses up or down arrow and land at the end of a line.
nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
if (frameSelection &&
frameSelection->GetHint() == nsFrameSelection::HINTLEFT) {
-- offset; // We are at the start of a line
}
}
nsSelectionAmount amount;
bool needsStart = false;
switch (aBoundaryType) {
case BOUNDARY_WORD_START:
needsStart = true;
amount = eSelectWord;
break;
case BOUNDARY_WORD_END:
amount = eSelectWord;
break;
case BOUNDARY_LINE_START:
// Newlines are considered at the end of a line. Since getting
// the BOUNDARY_LINE_START gets the text from the line-start to the next
// line-start, the newline is included at the end of the string.
needsStart = true;
amount = eSelectLine;
break;
case BOUNDARY_LINE_END:
// Newlines are considered at the end of a line. Since getting
// the BOUNDARY_END_START gets the text from the line-end to the next
//line-end, the newline is included at the beginning of the string.
amount = eSelectLine;
break;
case BOUNDARY_ATTRIBUTE_RANGE:
{
nsresult rv = GetTextAttributes(false, offset,
aStartOffset, aEndOffset, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
return GetText(*aStartOffset, *aEndOffset, aText);
}
default: // Note, sentence support is deprecated and falls through to here
return NS_ERROR_INVALID_ARG;
}
int32_t startOffset = offset + (aBoundaryType == BOUNDARY_LINE_END); // Avoid getting the previous line
int32_t endOffset = startOffset;
// Convert offsets to frame-relative
nsRefPtr<Accessible> startAcc;
nsIFrame *startFrame = GetPosAndText(startOffset, endOffset, nullptr, nullptr,
nullptr, getter_AddRefs(startAcc));
if (!startFrame) {
int32_t textLength = CharacterCount();
if (aBoundaryType == BOUNDARY_LINE_START && offset > 0 && offset == textLength) {
// Asking for start of line, while on last character
if (startAcc)
startFrame = startAcc->GetFrame();
}
if (!startFrame) {
return offset > textLength ? NS_ERROR_FAILURE : NS_OK;
}
else {
// We're on the last continuation since we're on the last character
startFrame = startFrame->GetLastContinuation();
}
}
int32_t finalStartOffset = 0, finalEndOffset = 0;
EWordMovementType wordMovementType = needsStart ? eStartWord : eEndWord;
nsIPresShell* presShell = mDoc->PresShell();
// If aType == eGetAt we'll change both the start and end offset from
// the original offset
if (aType == eGetAfter) {
finalStartOffset = offset;
}
else {
finalStartOffset = GetRelativeOffset(presShell, startFrame, startOffset,
startAcc,
(amount == eSelectLine ? eSelectBeginLine : amount),
eDirPrevious, needsStart,
wordMovementType);
NS_ENSURE_TRUE(finalStartOffset >= 0, NS_ERROR_FAILURE);
}
if (aType == eGetBefore) {
finalEndOffset = offset;
}
else {
// Start moving forward from the start so that we don't get
// 2 words/lines if the offset occurred on whitespace boundary
// Careful, startOffset and endOffset are passed by reference to GetPosAndText() and changed
// For BOUNDARY_LINE_END, make sure we start of this line
startOffset = endOffset = finalStartOffset + (aBoundaryType == BOUNDARY_LINE_END);
nsRefPtr<Accessible> endAcc;
nsIFrame *endFrame = GetPosAndText(startOffset, endOffset, nullptr, nullptr,
nullptr, getter_AddRefs(endAcc));
if (endAcc && endAcc->Role() == roles::STATICTEXT) {
// Static text like list bullets will ruin our forward calculation,
// since the caret cannot be in the static text. Start just after the static text.
startOffset = endOffset = finalStartOffset +
(aBoundaryType == BOUNDARY_LINE_END) +
nsAccUtils::TextLength(endAcc);
endFrame = GetPosAndText(startOffset, endOffset, nullptr, nullptr,
nullptr, getter_AddRefs(endAcc));
}
if (!endFrame) {
return NS_ERROR_FAILURE;
}
finalEndOffset = GetRelativeOffset(presShell, endFrame, endOffset, endAcc,
(amount == eSelectLine ? eSelectEndLine : amount),
eDirNext, needsStart, wordMovementType);
NS_ENSURE_TRUE(endOffset >= 0, NS_ERROR_FAILURE);
if (finalEndOffset == offset) {
if (aType == eGetAt && amount == eSelectWord) {
// Fix word error for the first character in word: PeekOffset() will return the previous word when
// offset points to the first character of the word, but accessibility APIs want the current word
// that the first character is in
return GetTextHelper(eGetAfter, aBoundaryType, offset,
aStartOffset, aEndOffset, aText);
}
int32_t textLength = CharacterCount();
if (finalEndOffset < textLength) {
// This happens sometimes when current character at finalStartOffset
// is an embedded object character representing another hypertext, that
// the AT really needs to dig into separately
++ finalEndOffset;
}
}
}
*aStartOffset = finalStartOffset;
*aEndOffset = finalEndOffset;
NS_ASSERTION((finalStartOffset < offset && finalEndOffset >= offset) || aType != eGetBefore, "Incorrect results for GetTextHelper");
NS_ASSERTION((finalStartOffset <= offset && finalEndOffset > offset) || aType == eGetBefore, "Incorrect results for GetTextHelper");
GetPosAndText(finalStartOffset, finalEndOffset, &aText);
return NS_OK;
}
/**
* nsIAccessibleText impl.
*/
@ -1120,10 +940,6 @@ HyperTextAccessible::GetTextBeforeOffset(int32_t aOffset,
*aStartOffset = FindLineBoundary(*aEndOffset, ePrevLineEnd);
return GetText(*aStartOffset, *aEndOffset, aText);
case BOUNDARY_ATTRIBUTE_RANGE:
return GetTextHelper(eGetBefore, aBoundaryType, aOffset,
aStartOffset, aEndOffset, aText);
default:
return NS_ERROR_INVALID_ARG;
}
@ -1177,10 +993,6 @@ HyperTextAccessible::GetTextAtOffset(int32_t aOffset,
*aEndOffset = FindLineBoundary(offset, eThisLineEnd);
return GetText(*aStartOffset, *aEndOffset, aText);
case BOUNDARY_ATTRIBUTE_RANGE:
return GetTextHelper(eGetAt, aBoundaryType, aOffset,
aStartOffset, aEndOffset, aText);
default:
return NS_ERROR_INVALID_ARG;
}
@ -1243,10 +1055,6 @@ HyperTextAccessible::GetTextAfterOffset(int32_t aOffset,
*aEndOffset = FindLineBoundary(offset, eNextLineEnd);
return GetText(*aStartOffset, *aEndOffset, aText);
case BOUNDARY_ATTRIBUTE_RANGE:
return GetTextHelper(eGetAfter, aBoundaryType, aOffset,
aStartOffset, aEndOffset, aText);
default:
return NS_ERROR_INVALID_ARG;
}

View File

@ -334,22 +334,8 @@ protected:
nsSelectionAmount aAmount,
EWordMovementType aWordMovementType = eDefaultBehavior);
/*
* This does the work for nsIAccessibleText::GetText[At|Before|After]Offset
* @param aType, eGetBefore, eGetAt, eGetAfter
* @param aBoundaryType, char/word-start/word-end/line-start/line-end/paragraph/attribute
* @param aOffset, offset into the hypertext to start from
* @param *aStartOffset, the resulting start offset for the returned substring
* @param *aEndOffset, the resulting end offset for the returned substring
* @param aText, the resulting substring
* @return success/failure code
*/
nsresult GetTextHelper(EGetTextType aType, AccessibleTextBoundary aBoundaryType,
int32_t aOffset, int32_t *aStartOffset, int32_t *aEndOffset,
nsAString & aText);
/**
* Used by GetTextHelper() to move backward/forward from a given point
* Used by FindOffset() to move backward/forward from a given point
* by word/line/etc.
*
* @param aPresShell the current presshell we're moving in

View File

@ -48,6 +48,7 @@ HTMLTableCellAccessible::
HTMLTableCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
HyperTextAccessibleWrap(aContent, aDoc), xpcAccessibleTableCell(this)
{
mGenericTypes |= eTableCell;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -356,7 +356,56 @@ this.AccessFu = {
// Keep track of message managers tha already have a 'content-script.js'
// injected.
_processedMessageManagers: []
_processedMessageManagers: [],
/**
* Adjusts the given bounds relative to the given browser. Converts from screen
* or device pixels to either device or CSS pixels.
* @param {Rect} aJsonBounds the bounds to adjust
* @param {browser} aBrowser the browser we want the bounds relative to
* @param {bool} aToCSSPixels whether to convert to CSS pixels (as opposed to
* device pixels)
* @param {bool} aFromDevicePixels whether to convert from device pixels (as
* opposed to screen pixels)
*/
adjustContentBounds: function(aJsonBounds, aBrowser, aToCSSPixels, aFromDevicePixels) {
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
aJsonBounds.right - aJsonBounds.left,
aJsonBounds.bottom - aJsonBounds.top);
let win = Utils.win;
let dpr = win.devicePixelRatio;
let vp = Utils.getViewport(win);
let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY };
if (!aBrowser.contentWindow) {
// OOP browser, add offset of browser.
// The offset of the browser element in relation to its parent window.
let clientRect = aBrowser.getBoundingClientRect();
let win = aBrowser.ownerDocument.defaultView;
offset.left += clientRect.left + win.mozInnerScreenX;
offset.top += clientRect.top + win.mozInnerScreenY;
}
// Here we scale from screen pixels to layout device pixels by dividing by
// the resolution (caused by pinch-zooming). The resolution is the viewport
// zoom divided by the devicePixelRatio. If there's no viewport, then we're
// on a platform without pinch-zooming and we can just ignore this.
if (!aFromDevicePixels && vp) {
bounds = bounds.scale(vp.zoom / dpr, vp.zoom / dpr);
}
// Add the offset; the offset is in CSS pixels, so multiply the
// devicePixelRatio back in before adding to preserve unit consistency.
bounds = bounds.translate(offset.left * dpr, offset.top * dpr);
// If we want to get to CSS pixels from device pixels, this needs to be
// further divided by the devicePixelRatio due to widget scaling.
if (aToCSSPixels) {
bounds = bounds.scale(1 / dpr, 1 / dpr);
}
return bounds.expandToIntegers();
}
};
var Output = {
@ -472,7 +521,7 @@ var Output = {
}
let padding = aDetails.padding;
let r = this._adjustBounds(aDetails.bounds, aBrowser);
let r = AccessFu.adjustContentBounds(aDetails.bounds, aBrowser, true);
// First hide it to avoid flickering when changing the style.
highlightBox.style.display = 'none';
@ -536,7 +585,7 @@ var Output = {
for each (let androidEvent in aDetails) {
androidEvent.type = 'Accessibility:Event';
if (androidEvent.bounds)
androidEvent.bounds = this._adjustBounds(androidEvent.bounds, aBrowser, true);
androidEvent.bounds = AccessFu.adjustContentBounds(androidEvent.bounds, aBrowser);
switch(androidEvent.eventType) {
case ANDROID_VIEW_TEXT_CHANGED:
@ -559,33 +608,6 @@ var Output = {
Braille: function Braille(aDetails, aBrowser) {
Logger.debug('Braille output: ' + aDetails.text);
},
_adjustBounds: function(aJsonBounds, aBrowser, aIncludeZoom) {
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
aJsonBounds.right - aJsonBounds.left,
aJsonBounds.bottom - aJsonBounds.top);
let vp = Utils.getViewport(Utils.win) || { zoom: 1.0, offsetY: 0 };
let root = Utils.win;
let offset = { left: -root.mozInnerScreenX, top: -root.mozInnerScreenY };
let scale = 1 / Utils.getPixelsPerCSSPixel(Utils.win);
if (!aBrowser.contentWindow) {
// OOP browser, add offset of browser.
// The offset of the browser element in relation to its parent window.
let clientRect = aBrowser.getBoundingClientRect();
let win = aBrowser.ownerDocument.defaultView;
offset.left += clientRect.left + win.mozInnerScreenX;
offset.top += clientRect.top + win.mozInnerScreenY;
}
let newBounds = bounds.scale(scale, scale).translate(offset.left, offset.top);
if (aIncludeZoom) {
newBounds = newBounds.scale(vp.zoom, vp.zoom);
}
return newBounds.expandToIntegers();
}
};
@ -615,9 +637,6 @@ var Input = {
this._handleKeypress(aEvent);
break;
case 'mozAccessFuGesture':
let vp = Utils.getViewport(Utils.win) || { zoom: 1.0 };
aEvent.detail.x *= vp.zoom;
aEvent.detail.y *= vp.zoom;
this._handleGesture(aEvent.detail);
break;
}
@ -796,10 +815,10 @@ var Input = {
activateContextMenu: function activateContextMenu(aMessage) {
if (Utils.MozBuildApp === 'mobile/android') {
let vp = Utils.getViewport(Utils.win) || { zoom: 1.0 };
let p = AccessFu.adjustContentBounds(aMessage.bounds, Utils.CurrentBrowser,
true, true).center();
Services.obs.notifyObservers(null, 'Gesture:LongPress',
JSON.stringify({x: aMessage.x / vp.zoom,
y: aMessage.y / vp.zoom}));
JSON.stringify({x: p.x, y: p.y}));
}
},

View File

@ -326,8 +326,8 @@ this.TouchAdapter = {
* of one single touch.
*/
function TouchPoint(aTouch, aTime, aDPI) {
this.startX = this.x = aTouch.screenX;
this.startY = this.y = aTouch.screenY;
this.startX = this.x = aTouch.screenX * this.scaleFactor;
this.startY = this.y = aTouch.screenY * this.scaleFactor;
this.startTime = aTime;
this.distanceTraveled = 0;
this.dpi = aDPI;
@ -338,8 +338,8 @@ TouchPoint.prototype = {
update: function TouchPoint_update(aTouch, aTime) {
let lastX = this.x;
let lastY = this.y;
this.x = aTouch.screenX;
this.y = aTouch.screenY;
this.x = aTouch.screenX * this.scaleFactor;
this.y = aTouch.screenY * this.scaleFactor;
this.time = aTime;
this.distanceTraveled += this.getDistanceToCoord(lastX, lastY);
@ -349,6 +349,20 @@ TouchPoint.prototype = {
return Math.sqrt(Math.pow(this.x - aX, 2) + Math.pow(this.y - aY, 2));
},
get scaleFactor() {
if (!this._scaleFactor) {
// Android events come with the x, y coordinates affected by the widget
// scaling; we restore it to normal here.
if (Utils.MozBuildApp == 'mobile/android') {
this._scaleFactor = Utils.win.devicePixelRatio;
} else {
this._scaleFactor = 1;
}
}
return this._scaleFactor;
},
finish: function TouchPoint_finish() {
this.done = true;
},

View File

@ -221,11 +221,6 @@ this.Utils = {
return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
},
getPixelsPerCSSPixel: function getPixelsPerCSSPixel(aWindow) {
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
},
getBounds: function getBounds(aAccessible) {
let objX = {}, objY = {}, objW = {}, objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
@ -684,4 +679,4 @@ PrefCache.prototype = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};
};

View File

@ -97,10 +97,8 @@ function moveToPoint(aMessage) {
let rule = TraversalRules[details.rule];
try {
if (!this._ppcp) {
this._ppcp = Utils.getPixelsPerCSSPixel(content);
}
vc.moveToPoint(rule, details.x * this._ppcp, details.y * this._ppcp, true);
let dpr = content.devicePixelRatio;
vc.moveToPoint(rule, details.x * dpr, details.y * dpr, true);
forwardToChild(aMessage, moveToPoint, vc.position);
} catch (x) {
Logger.logException(x, 'Failed move to point');
@ -219,9 +217,7 @@ function activateCurrent(aMessage) {
function activateContextMenu(aMessage) {
function sendContextMenuCoordinates(aAccessible) {
let bounds = Utils.getBounds(aAccessible);
sendAsyncMessage('AccessFu:ActivateContextMenu',
{ x: bounds.left + bounds.width / 2,
y: bounds.top + bounds.height / 2 });
sendAsyncMessage('AccessFu:ActivateContextMenu', {bounds: bounds});
}
let position = Utils.getVirtualCursor(content.document).position;

View File

@ -731,6 +731,7 @@ XULListCellAccessible::
XULListCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
HyperTextAccessibleWrap(aContent, aDoc), xpcAccessibleTableCell(this)
{
mGenericTypes |= eTableCell;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -453,6 +453,7 @@ XULTreeGridCellAccessible::
{
mParent = aRowAcc;
mStateFlags |= eSharedNode;
mGenericTypes |= eTableCell;
NS_ASSERTION(mTreeView, "mTreeView is null");

View File

@ -361,7 +361,8 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg)
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
var isColSelected = true;
for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
if (aCellsArray[rowIdx][colIdx] == false) {
if (aCellsArray[rowIdx][colIdx] == false ||
aCellsArray[rowIdx][colIdx] == undefined) {
isColSelected = false;
break;
}
@ -401,7 +402,8 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg)
for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
var isRowSelected = true;
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
if (aCellsArray[rowIdx][colIdx] == false) {
if (aCellsArray[rowIdx][colIdx] == false ||
aCellsArray[rowIdx][colIdx] == undefined) {
isRowSelected = false;
break;
}
@ -442,7 +444,8 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg)
if (aCellsArray[rowIdx][colIdx] & kSpanned)
continue;
is(acc.isCellSelected(rowIdx, colIdx), aCellsArray[rowIdx][colIdx],
var isSelected = aCellsArray[rowIdx][colIdx] == true;
is(acc.isCellSelected(rowIdx, colIdx), isSelected,
msg + "Wrong selection state of cell at " + rowIdx + " row and " +
colIdx + " column for " + prettyName(aIdentifier));
@ -496,7 +499,9 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg)
var cell = acc.getCellAt(rowIdx, colIdx);
var isSel = aCellsArray[rowIdx][colIdx];
if (isSel)
if (isSel == undefined)
testStates(cell, 0, 0, STATE_SELECTABLE | STATE_SELECTED);
else if (isSel == true)
testStates(cell, STATE_SELECTED);
else
testStates(cell, STATE_SELECTABLE, 0, STATE_SELECTED);

View File

@ -54,6 +54,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
testUnselectTableColumn("grid2", 0, cellsArray);
testUnselectTableRow("grid2", 0, cellsArray);
//////////////////////////////////////////////////////////////////////////
// ARIA grid (column and row headers)
cellsArray =
[
[ undefined, true, false],
[ undefined, true, false]
];
testTableSelection("grid3", cellsArray);
testSelectTableColumn("grid3", 0, cellsArray);
testSelectTableRow("grid3", 0, cellsArray);
testUnselectTableColumn("grid3", 0, cellsArray);
testUnselectTableRow("grid3", 0, cellsArray);
SimpleTest.finish();
}
@ -65,10 +80,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
<a target="_blank"
title="implement nsIAccessibleTable selection methods for ARIA grids"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Mozilla Bug 410052</a>
href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Bug 410052</a>
<a target="_blank"
title="nsHTMLTableCellAccessible is used in dojo's crazy ARIA grid"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=513848">Mozilla Bug 513848</a>
href="https://bugzilla.mozilla.org/show_bug.cgi?id=513848">Bug 513848</a>
<a target="_blank"
title="ARIA columnheader/rowheader shouldn't be selectable by default"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=888247">Bug 888247</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
@ -112,8 +130,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
<div role="row">
<table role="presentation">
<tr>
<td role="columnheader">header1</td>
<td role="columnheader">header2</td>
<td role="columnheader" aria-selected="false">header1</td>
<td role="columnheader" aria-selected="false">header2</td>
</tr>
</table>
</div>
@ -127,5 +145,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
</div>
</div>
<div role="grid" id="grid3">
<div role="row">
<div role="columnheader" id="colheader_default">col header1</div>
<div role="columnheader" id="colheader_selected" aria-selected="true">col header2</div>
<div role="columnheader" id="colheader_notselected" aria-selected="false">col header3</div>
</div>
<div role="row">
<div role="rowheader" id="rowheader_default">row header1</div>
<div role="rowheader" id="rowheader_selected" aria-selected="true">row header2</div>
<div role="rowheader" id="rowheader_notselected" aria-selected="false">row header3</div>
</div>
</div>
</body>
</html>

View File

@ -6,7 +6,6 @@ const BOUNDARY_WORD_START = nsIAccessibleText.BOUNDARY_WORD_START;
const BOUNDARY_WORD_END = nsIAccessibleText.BOUNDARY_WORD_END;
const BOUNDARY_LINE_START = nsIAccessibleText.BOUNDARY_LINE_START;
const BOUNDARY_LINE_END = nsIAccessibleText.BOUNDARY_LINE_END;
const BOUNDARY_ATTRIBUTE_RANGE = nsIAccessibleText.BOUNDARY_ATTRIBUTE_RANGE;
const kTextEndOffset = nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT;
const kCaretOffset = nsIAccessibleText.TEXT_OFFSET_CARET;
@ -585,7 +584,5 @@ function boundaryToString(aBoundaryType)
return "line start";
case BOUNDARY_LINE_END:
return "line end";
case BOUNDARY_ATTRIBUTE_RANGE:
return "attr range";
}
}

View File

@ -151,6 +151,26 @@
testAccessibleTree("crazy_grid4", accTree);
//////////////////////////////////////////////////////////////////////////
// grids that could contain whitespace accessibles but shouldn't.
var accTree =
{ TREE_TABLE: [
{ ROW: [
{ GRID_CELL: [
{ TEXT_LEAF: [ ] }
] },
{ GRID_CELL: [
{ TEXT_LEAF: [ ] }
] },
{ GRID_CELL: [
{ TEXT_LEAF: [ ] }
] }
] },
] };
testAccessibleTree("whitespaces-grid", accTree);
SimpleTest.finish();
}
@ -227,5 +247,13 @@
</div>
</div>
</div>
<div role="treegrid" id="whitespaces-grid">
<div role="row" aria-selected="false" tabindex="-1">
<span role="gridcell">03:30PM-04:30PM</span>
<span role="gridcell" style="font-weight:bold;">test</span>
<span role="gridcell">a user1</span>
</div>
</div>
</body>
</html>

View File

@ -421,7 +421,6 @@ pref("services.push.udp.port", 2442);
// NetworkStats
#ifdef MOZ_B2G_RIL
pref("dom.mozNetworkStats.enabled", true);
pref("ril.lastKnownMcc", "724");
pref("ril.cellbroadcast.disabled", false);
#endif

View File

@ -62,43 +62,6 @@ var SettingsListener = {
SettingsListener.init();
// =================== Audio ====================
SettingsListener.observe('audio.volume.master', 1.0, function(value) {
let audioManager = Services.audioManager;
if (!audioManager)
return;
audioManager.masterVolume = Math.max(0.0, Math.min(value, 1.0));
});
let audioChannelSettings = [];
if ("nsIAudioManager" in Ci) {
const nsIAudioManager = Ci.nsIAudioManager;
audioChannelSettings = [
// settings name, max value, apply to stream types
['audio.volume.content', 15, [nsIAudioManager.STREAM_TYPE_SYSTEM, nsIAudioManager.STREAM_TYPE_MUSIC]],
['audio.volume.notification', 15, [nsIAudioManager.STREAM_TYPE_RING, nsIAudioManager.STREAM_TYPE_NOTIFICATION]],
['audio.volume.alarm', 15, [nsIAudioManager.STREAM_TYPE_ALARM]],
['audio.volume.telephony', 5, [nsIAudioManager.STREAM_TYPE_VOICE_CALL]],
['audio.volume.bt_sco', 15, [nsIAudioManager.STREAM_TYPE_BLUETOOTH_SCO]],
];
}
for each (let [setting, maxValue, streamTypes] in audioChannelSettings) {
(function AudioStreamSettings(setting, maxValue, streamTypes) {
SettingsListener.observe(setting, maxValue, function(value) {
let audioManager = Services.audioManager;
if (!audioManager)
return;
for each(let streamType in streamTypes) {
audioManager.setStreamVolumeIndex(streamType, Math.min(value, maxValue));
}
});
})(setting, maxValue, streamTypes);
}
// =================== Console ======================
SettingsListener.observe('debug.console.enabled', true, function(value) {

View File

@ -39,16 +39,6 @@ XPCOMUtils.defineLazyServiceGetter(this, 'gSystemMessenger',
'@mozilla.org/system-message-internal;1',
'nsISystemMessagesInternal');
#ifdef MOZ_WIDGET_GONK
XPCOMUtils.defineLazyServiceGetter(Services, 'audioManager',
'@mozilla.org/telephony/audiomanager;1',
'nsIAudioManager');
#else
Services.audioManager = {
'masterVolume': 0
};
#endif
XPCOMUtils.defineLazyServiceGetter(Services, 'fm',
'@mozilla.org/focus-manager;1',
'nsIFocusManager');
@ -344,9 +334,6 @@ var shell = {
this.timer = null;
}
#ifndef MOZ_WIDGET_GONK
delete Services.audioManager;
#endif
UserAgentOverrides.uninit();
IndexedDBPromptHelper.uninit();
},

View File

@ -1,12 +0,0 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk

View File

@ -1,4 +1,4 @@
{
"revision": "34a53279dad496e201616f5e782bd58ef6d38ae5",
"revision": "e04bb3527c33dd6771e63397a3b52a4b9a5fce4e",
"repo_path": "/integration/gaia-central"
}

View File

@ -1,4 +1,5 @@
. "$topsrcdir/b2g/config/mozconfigs/common"
. "$topsrcdir/build/unix/mozconfig.linux32"
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
@ -8,9 +9,6 @@ ac_add_options --enable-signmar
# Nightlies only since this has a cost in performance
#ac_add_options --enable-js-diagnostics
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# This will overwrite the default of stripping everything and keep the symbol table.
# This is useful for profiling and debugging and only increases the package size
# by 2 MBs.

View File

@ -1,4 +1,5 @@
. "$topsrcdir/b2g/config/mozconfigs/common"
. "$topsrcdir/build/unix/mozconfig.linux"
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
@ -8,9 +9,6 @@ ac_add_options --enable-signmar
# Nightlies only since this has a cost in performance
#ac_add_options --enable-js-diagnostics
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# This will overwrite the default of stripping everything and keep the symbol table.
# This is useful for profiling and debugging and only increases the package size
# by 2 MBs.

View File

@ -175,7 +175,6 @@
#ifdef MOZ_B2G_FM
@BINPATH@/components/dom_fm.xpt
#endif
@BINPATH@/components/dom_battery.xpt
#ifdef MOZ_B2G_BT
@BINPATH@/components/dom_bluetooth.xpt
#endif

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1373408730000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1374187152000">
<emItems>
<emItem blockID="i350" id="sqlmoz@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -1052,6 +1052,9 @@
</targetApplication>
</versionRange>
</pluginItem>
<pluginItem blockID="p428">
<match name="filename" exp="np[dD]eployJava1\.dll" /> <versionRange severity="0" vulnerabilitystatus="2"></versionRange>
</pluginItem>
</pluginItems>
<gfxItems>

View File

@ -16,20 +16,22 @@ function init(aEvent)
var distroId = Services.prefs.getCharPref("distribution.id");
if (distroId) {
var distroVersion = Services.prefs.getCharPref("distribution.version");
var distroAbout = Services.prefs.getComplexValue("distribution.about",
Components.interfaces.nsISupportsString);
var distroField = document.getElementById("distribution");
distroField.value = distroAbout;
distroField.style.display = "block";
var distroIdField = document.getElementById("distributionId");
distroIdField.value = distroId + " - " + distroVersion;
distroIdField.style.display = "block";
// This must be set last because it might not exist due to bug 895473.
var distroAbout = Services.prefs.getComplexValue("distribution.about",
Components.interfaces.nsISupportsString);
var distroField = document.getElementById("distribution");
distroField.value = distroAbout;
distroField.style.display = "block";
}
}
catch (e) {
// Pref is unset
Components.utils.reportError(e);
}
// Include the build ID and display warning if this is an "a#" (nightly or aurora) build

View File

@ -571,7 +571,7 @@ HistoryMenu.prototype = {
m.setAttribute("label", strings.getString("menuRestoreAllTabs.label"));
m.addEventListener("command", function() {
for (var i = 0; i < undoItems.length; i++)
undoCloseTab();
undoCloseTab(0);
}, false);
},

View File

@ -217,14 +217,21 @@ var gPluginHandler = {
},
handleEvent : function(event) {
let plugin = event.target;
let doc = plugin.ownerDocument;
// We're expecting the target to be a plugin.
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
let plugin;
let doc;
let eventType = event.type;
if (eventType === "PluginRemoved") {
doc = event.target;
}
else {
plugin = event.target;
doc = plugin.ownerDocument;
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
}
if (eventType == "PluginBindingAttached") {
// The plugin binding fires this event when it is created.
// As an untrusted event, ensure that this object actually has a binding
@ -243,6 +250,7 @@ var gPluginHandler = {
}
}
let shouldShowNotification = false;
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
switch (eventType) {
@ -268,7 +276,7 @@ var gPluginHandler = {
case "PluginBlocklisted":
case "PluginOutdated":
this._showClickToPlayNotification(browser);
shouldShowNotification = true;
break;
case "PluginVulnerableUpdatable":
@ -290,7 +298,7 @@ var gPluginHandler = {
let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus");
vulnerabilityText.textContent = vulnerabilityString;
}
this._showClickToPlayNotification(browser);
shouldShowNotification = true;
break;
case "PluginPlayPreview":
@ -300,20 +308,27 @@ var gPluginHandler = {
case "PluginDisabled":
let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
this.addLinkClickCallback(manageLink, "managePlugins");
this._showClickToPlayNotification(browser);
shouldShowNotification = true;
break;
case "PluginInstantiated":
this._showClickToPlayNotification(browser);
case "PluginRemoved":
shouldShowNotification = true;
break;
}
// Hide the in-content UI if it's too big. The crashed plugin handler already did this.
if (eventType != "PluginCrashed") {
if (eventType != "PluginCrashed" && eventType != "PluginRemoved") {
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
if (overlay != null && this.isTooSmall(plugin, overlay))
overlay.style.visibility = "hidden";
}
// Only show the notification after we've done the isTooSmall check, so
// that the notification can decide whether to show the "alert" icon
if (shouldShowNotification) {
this._showClickToPlayNotification(browser);
}
},
isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) {
@ -686,18 +701,12 @@ var gPluginHandler = {
switch (aNewState) {
case "allownow":
if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
expireTime = Date.now() + Services.prefs.getIntPref(this.PREF_SESSION_PERSIST_MINUTES) * 60 * 1000;
break;
case "allowalways":
if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
expireTime = Date.now() +
@ -705,25 +714,28 @@ var gPluginHandler = {
break;
case "block":
if (aPluginInfo.fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.PROMPT_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_NEVER;
expireTime = 0;
break;
// In case a plugin has already been allowed in another tab, the "continue allowing" button
// shouldn't change any permissions but should run the plugin-enablement code below.
case "continue":
break;
default:
Cu.reportError(Error("Unexpected plugin state: " + aNewState));
return;
}
let browser = aNotification.browser;
Services.perms.add(browser.currentURI, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState != "continue") {
Services.perms.add(browser.currentURI, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState == "block") {
return;
if (aNewState == "block") {
return;
}
}
// Manually activate the plugins that would have been automatically
@ -749,6 +761,7 @@ var gPluginHandler = {
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
let contentWindow = aBrowser.contentWindow;
let contentDoc = aBrowser.contentDocument;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins;
@ -759,15 +772,25 @@ var gPluginHandler = {
return;
}
let haveVulnerablePlugin = plugins.some(function(plugin) {
let icon = 'plugins-notification-icon';
for (let plugin of plugins) {
let fallbackType = plugin.pluginFallbackType;
return fallbackType == plugin.PLUGIN_VULNERABLE_UPDATABLE ||
fallbackType == plugin.PLUGIN_VULNERABLE_NO_UPDATE ||
fallbackType == plugin.PLUGIN_BLOCKLISTED;
});
if (fallbackType == plugin.PLUGIN_VULNERABLE_UPDATABLE ||
fallbackType == plugin.PLUGIN_VULNERABLE_NO_UPDATE ||
fallbackType == plugin.PLUGIN_BLOCKLISTED) {
icon = 'blocked-plugins-notification-icon';
break;
}
if (fallbackType == plugin.PLUGIN_CLICK_TO_PLAY) {
let overlay = contentDoc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
if (!overlay || overlay.style.visibility == 'hidden') {
icon = 'alert-plugins-notification-icon';
}
}
}
let dismissed = notification ? notification.dismissed : true;
// Always show the doorhanger if the anchor is not available.
if (!isElementVisible(gURLBar) || aPrimaryPlugin)
if (aPrimaryPlugin)
dismissed = false;
let primaryPluginPermission = null;
@ -780,7 +803,6 @@ var gPluginHandler = {
eventCallback: this._clickToPlayNotificationEventCallback,
primaryPlugin: primaryPluginPermission
};
let icon = haveVulnerablePlugin ? "blocked-plugins-notification-icon" : "plugins-notification-icon";
PopupNotifications.show(aBrowser, "click-to-play-plugins",
"", icon,
null, null, options);

View File

@ -755,6 +755,7 @@ var gBrowserInit = {
gBrowser.addEventListener("PluginCrashed", gPluginHandler, true);
gBrowser.addEventListener("PluginOutdated", gPluginHandler, true);
gBrowser.addEventListener("PluginInstantiated", gPluginHandler, true);
gBrowser.addEventListener("PluginRemoved", gPluginHandler, true);
gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
@ -823,7 +824,8 @@ var gBrowserInit = {
// setup history swipe animation
gHistorySwipeAnimation.init();
if (window.opener && !window.opener.closed) {
if (window.opener && !window.opener.closed &&
PrivateBrowsingUtils.isWindowPrivate(window) == PrivateBrowsingUtils.isWindowPrivate(window.opener)) {
let openerSidebarBox = window.opener.document.getElementById("sidebar-box");
// If the opener had a sidebar, open the same sidebar in our window.
// The opener can be the hidden window too, if we're coming from the state
@ -2305,11 +2307,11 @@ function BrowserOnAboutPageLoad(doc) {
}
docElt.setAttribute("snippetsVersion", AboutHomeUtils.snippetsVersion);
function updateSearchEngine() {
let updateSearchEngine = function() {
let engine = AboutHomeUtils.defaultSearchEngine;
docElt.setAttribute("searchEngineName", engine.name);
docElt.setAttribute("searchEngineURL", engine.searchURL);
}
};
updateSearchEngine();
// Listen for the event that's triggered when the user changes search engine.
@ -4432,6 +4434,10 @@ nsBrowserAccess.prototype = {
isTabContentWindow: function (aWindow) {
return gBrowser.browsers.some(function (browser) browser.contentWindow == aWindow);
},
get contentWindow() {
return gBrowser.contentWindow;
}
}
@ -6259,15 +6265,31 @@ function undoCloseTab(aIndex) {
var tab = null;
var ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
if (ss.getClosedTabCount(window) > (aIndex || 0)) {
TabView.prepareUndoCloseTab(blankTabToRemove);
tab = ss.undoCloseTab(window, aIndex || 0);
TabView.afterUndoCloseTab();
if (blankTabToRemove)
gBrowser.removeTab(blankTabToRemove);
let numberOfTabsToUndoClose = 0;
if (Number.isInteger(aIndex)) {
if (ss.getClosedTabCount(window) > aIndex) {
numberOfTabsToUndoClose = 1;
} else {
return tab;
}
} else {
numberOfTabsToUndoClose = ss.getNumberOfTabsClosedLast(window);
aIndex = 0;
}
while (numberOfTabsToUndoClose > 0 &&
numberOfTabsToUndoClose--) {
TabView.prepareUndoCloseTab(blankTabToRemove);
tab = ss.undoCloseTab(window, aIndex);
TabView.afterUndoCloseTab();
if (blankTabToRemove) {
gBrowser.removeTab(blankTabToRemove);
blankTabToRemove = null;
}
}
// Reset the number of tabs closed last time to the default.
ss.setNumberOfTabsClosedLast(window, 1);
return tab;
}
@ -7061,10 +7083,15 @@ var TabContextMenu = {
menuItem.disabled = disabled;
// Session store
document.getElementById("context_undoCloseTab").disabled =
Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore).
getClosedTabCount(window) == 0;
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
let undoCloseTabElement = document.getElementById("context_undoCloseTab");
let closedTabCount = ss.getNumberOfTabsClosedLast(window);
undoCloseTabElement.disabled = closedTabCount == 0;
// Change the label of "Undo Close Tab" to specify if it will undo a batch-close
// or a single close.
let visibleLabel = closedTabCount <= 1 ? "singletablabel" : "multipletablabel";
undoCloseTabElement.setAttribute("label", undoCloseTabElement.getAttribute(visibleLabel));
// Only one of pin/unpin should be visible
document.getElementById("context_pinTab").hidden = this.contextTab.pinned;

View File

@ -103,7 +103,8 @@
oncommand="gBrowser.removeAllTabsBut(TabContextMenu.contextTab);"/>
<menuseparator/>
<menuitem id="context_undoCloseTab"
label="&undoCloseTab.label;"
singletablabel="&undoCloseTab.label;"
multipletablabel="&undoCloseTabs.label;"
accesskey="&undoCloseTab.accesskey;"
observes="History:UndoCloseTab"/>
<menuitem id="context_closeTab" label="&closeTab.label;" accesskey="&closeTab.accesskey;"
@ -504,6 +505,7 @@
<image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="alert-plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="blocked-plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="plugin-install-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/>

View File

@ -150,7 +150,7 @@ function onCheckboxClick(aPartId)
var command = document.getElementById("cmd_" + aPartId + "Toggle");
var checkbox = document.getElementById(aPartId + "Def");
if (checkbox.checked) {
SitePermissions.remove(gPermURI.host, aPartId);
SitePermissions.remove(gPermURI, aPartId);
command.setAttribute("disabled", "true");
var perm = SitePermissions.getDefault(aPartId);
setRadioState(aPartId, perm);

View File

@ -1565,13 +1565,9 @@
throw new Error("Invalid argument: " + aCloseTabs);
}
if (tabsToClose <= 1)
return true;
const pref = aCloseTabs == this.closingTabsEnum.ALL ?
"browser.tabs.warnOnClose" : "browser.tabs.warnOnCloseOtherTabs";
var shouldPrompt = Services.prefs.getBoolPref(pref);
if (!shouldPrompt)
if (tabsToClose <= 1 ||
aCloseTabs != this.closingTabsEnum.ALL ||
!Services.prefs.getBoolPref("browser.tabs.warnOnClose"))
return true;
var ps = Services.prompt;
@ -1595,13 +1591,12 @@
+ (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1),
bundle.getString("tabs.closeButtonMultiple"),
null, null,
aCloseTabs == this.closingTabsEnum.ALL ?
bundle.getString("tabs.closeWarningPromptMe") : null,
bundle.getString("tabs.closeWarningPromptMe"),
warnOnClose);
var reallyClose = (buttonPressed == 0);
// don't set the pref unless they press OK and it's false
if (aCloseTabs == this.closingTabsEnum.ALL && reallyClose && !warnOnClose.value)
if (reallyClose && !warnOnClose.value)
Services.prefs.setBoolPref(pref, false);
return reallyClose;
@ -1629,9 +1624,13 @@
<![CDATA[
if (this.warnAboutClosingTabs(this.closingTabsEnum.TO_END, aTab)) {
let tabs = this.getTabsToTheEndFrom(aTab);
for (let i = tabs.length - 1; i >= 0; --i) {
let numberOfTabsToClose = tabs.length;
for (let i = numberOfTabsToClose - 1; i >= 0; --i) {
this.removeTab(tabs[i], {animate: true});
}
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
ss.setNumberOfTabsClosedLast(window, numberOfTabsToClose);
}
]]>
</body>
@ -1648,10 +1647,16 @@
let tabs = this.visibleTabs;
this.selectedTab = aTab;
let closedTabs = 0;
for (let i = tabs.length - 1; i >= 0; --i) {
if (tabs[i] != aTab && !tabs[i].pinned)
if (tabs[i] != aTab && !tabs[i].pinned) {
this.removeTab(tabs[i]);
closedTabs++;
}
}
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
ss.setNumberOfTabsClosedLast(window, closedTabs);
}
]]>
</body>
@ -1680,6 +1685,10 @@
var byMouse = aParams.byMouse;
}
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
ss.setNumberOfTabsClosedLast(window, 1);
// Handle requests for synchronously removing an already
// asynchronously closing tab.
if (!animate &&
@ -2089,8 +2098,9 @@
if (otherFindBar &&
otherFindBar.findMode == otherFindBar.FIND_NORMAL) {
let ourFindBar = this.getFindBar(aOurTab);
ourFindBar.hidden = otherFindBar.hidden;
ourFindBar._findField.value = otherFindBar._findField.value;
if (!otherFindBar.hidden)
ourFindBar.onFindCommand();
}
// Finish tearing down the tab that's going away.

View File

@ -184,6 +184,7 @@ MOCHITEST_BROWSER_FILES = \
browser_bug832435.js \
browser_bug839103.js \
browser_bug882977.js \
browser_bug887515.js \
browser_canonizeURL.js \
browser_clearplugindata_noage.html \
browser_clearplugindata.html \

View File

@ -111,8 +111,6 @@ let gTests = [
doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
is(e.detail, engineName, "Detail is search engine name");
gBrowser.stop();
getNumberOfSearches(engineName).then(num => {
is(num, numSearchesBefore + 1, "One more search recorded.");
deferred.resolve();
@ -126,6 +124,7 @@ let gTests = [
info("Perform a search.");
doc.getElementById("searchText").value = "a search";
doc.getElementById("searchSubmit").click();
gBrowser.stop();
});
return deferred.promise;

View File

@ -98,6 +98,8 @@ function checkNewWindow() {
ok(!newWindow.gFindBar.hidden, "New window shows find bar!");
is(newWindow.gFindBar._findField.value, texts[1],
"New window find bar has correct find value!");
ok(!newWindow.gFindBar.getElement("find-next").disabled,
"New window findbar has enabled buttons!");
newWindow.close();
finish();
}

View File

@ -0,0 +1,75 @@
function numClosedTabs()
Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore).
getNumberOfTabsClosedLast(window);
var originalTab;
var tab1Loaded = false;
var tab2Loaded = false;
function verifyUndoMultipleClose() {
if (!tab1Loaded || !tab2Loaded)
return;
gBrowser.removeAllTabsBut(originalTab);
updateTabContextMenu();
let undoCloseTabElement = document.getElementById("context_undoCloseTab");
ok(!undoCloseTabElement.disabled, "Undo Close Tabs should be enabled.");
is(numClosedTabs(), 2, "There should be 2 closed tabs.");
is(gBrowser.tabs.length, 1, "There should only be 1 open tab");
updateTabContextMenu();
is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("multipletablabel"),
"The label should be showing that the command will restore multiple tabs");
undoCloseTab();
is(gBrowser.tabs.length, 3, "There should be 3 open tabs");
updateTabContextMenu();
is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("singletablabel"),
"The label should be showing that the command will restore a single tab");
gBrowser.removeTabsToTheEndFrom(originalTab);
updateTabContextMenu();
ok(!undoCloseTabElement.disabled, "Undo Close Tabs should be enabled.");
is(numClosedTabs(), 2, "There should be 2 closed tabs.");
is(gBrowser.tabs.length, 1, "There should only be 1 open tab");
updateTabContextMenu();
is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("multipletablabel"),
"The label should be showing that the command will restore multiple tabs");
finish();
}
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
originalTab.linkedBrowser.loadURI("about:blank");
originalTab = null;
});
let undoCloseTabElement = document.getElementById("context_undoCloseTab");
updateTabContextMenu();
is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("singletablabel"),
"The label should be showing that the command will restore a single tab");
originalTab = gBrowser.selectedTab;
gBrowser.selectedBrowser.loadURI("http://mochi.test:8888/");
var tab1 = gBrowser.addTab("http://mochi.test:8888/");
var tab2 = gBrowser.addTab("http://mochi.test:8888/");
var browser1 = gBrowser.getBrowserForTab(tab1);
browser1.addEventListener("load", function onLoad1() {
browser1.removeEventListener("load", onLoad1, true);
tab1Loaded = true;
tab1 = null;
verifyUndoMultipleClose();
}, true);
var browser2 = gBrowser.getBrowserForTab(tab2);
browser2.addEventListener("load", function onLoad2() {
browser2.removeEventListener("load", onLoad2, true);
tab2Loaded = true;
tab2 = null;
verifyUndoMultipleClose();
}, true);
}

View File

@ -1574,12 +1574,19 @@
this.appendChild(item);
this._items.push(item);
}
if (this.notification.options.centerActions.length == 1) {
this._setState(this._states.SINGLE);
} else if (this.notification.options.primaryPlugin) {
this._setState(this._states.MULTI_COLLAPSED);
} else {
this._setState(this._states.MULTI_EXPANDED);
switch (this.notification.options.centerActions.length) {
case 0:
PopupNotifications._dismiss();
break;
case 1:
this._setState(this._states.SINGLE);
break;
default:
if (this.notification.options.primaryPlugin) {
this._setState(this._states.MULTI_COLLAPSED);
} else {
this._setState(this._states.MULTI_EXPANDED);
}
}
]]></constructor>
<method name="_setState">
@ -1645,7 +1652,7 @@
button2 = {
label: "pluginContinue.label",
accesskey: "pluginContinue.accesskey",
action: "_cancel",
action: "_singleContinue",
default: true
};
switch (action.blocklistState) {
@ -1819,6 +1826,14 @@
this._cancel();
]]></body>
</method>
<method name="_singleContinue">
<body><![CDATA[
gPluginHandler._updatePluginPermission(this.notification,
this.notification.options.centerActions[0],
"continue");
this._cancel();
]]></body>
</method>
<method name="_multiAccept">
<body><![CDATA[
for (let item of this._items) {

View File

@ -1,12 +0,0 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk

View File

@ -273,13 +273,18 @@ DistributionCustomizer.prototype = {
let partnerAbout = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
if (globalPrefs["about." + this._locale]) {
partnerAbout.data = this._ini.getString("Global", "about." + this._locale);
} else {
partnerAbout.data = this._ini.getString("Global", "about");
try {
if (globalPrefs["about." + this._locale]) {
partnerAbout.data = this._ini.getString("Global", "about." + this._locale);
} else {
partnerAbout.data = this._ini.getString("Global", "about");
}
defaults.setComplexValue("distribution.about",
Ci.nsISupportsString, partnerAbout);
} catch (e) {
/* ignore bad prefs due to bug 895473 and move on */
Cu.reportError(e);
}
defaults.setComplexValue("distribution.about",
Ci.nsISupportsString, partnerAbout);
if (sections["Preferences"]) {
for (let key in enumerate(this._ini.getKeys("Preferences"))) {

View File

@ -1,12 +0,0 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk

View File

@ -45,6 +45,7 @@ MOCHITEST_BROWSER_FILES = \
browser_privatebrowsing_popupblocker.js \
browser_privatebrowsing_protocolhandler.js \
browser_privatebrowsing_protocolhandler_page.html \
browser_privatebrowsing_sidebar.js \
browser_privatebrowsing_theming.js \
browser_privatebrowsing_ui.js \
browser_privatebrowsing_urlbarfocus.js \

View File

@ -0,0 +1,92 @@
/* 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/. */
// This test makes sure that Sidebars do not migrate across windows with
// different privacy states
// See Bug 885054: https://bugzilla.mozilla.org/show_bug.cgi?id=885054
function test() {
waitForExplicitFinish();
let { utils: Cu } = Components;
let { Promise: { defer } } = Cu.import("resource://gre/modules/Promise.jsm", {});
// opens a sidebar
function openSidebar(win) {
let { promise, resolve } = defer();
let doc = win.document;
let sidebarID = 'viewBookmarksSidebar';
let sidebar = doc.getElementById('sidebar');
let sidebarurl = doc.getElementById(sidebarID).getAttribute('sidebarurl');
sidebar.addEventListener('load', function onSidebarLoad() {
if (sidebar.contentWindow.location.href != sidebarurl)
return;
sidebar.removeEventListener('load', onSidebarLoad, true);
resolve(win);
}, true);
win.toggleSidebar(sidebarID, true);
return promise;
}
let windowCache = [];
function cacheWindow(w) {
windowCache.push(w);
return w;
}
function closeCachedWindows () {
windowCache.forEach(function(w) w.close());
}
// Part 1: NON PRIVATE WINDOW -> PRIVATE WINDOW
openWindow(window, {}, 1).
then(cacheWindow).
then(openSidebar).
then(function(win) openWindow(win, { private: true })).
then(cacheWindow).
then(function({ document }) {
let sidebarBox = document.getElementById("sidebar-box");
is(sidebarBox.hidden, true, 'Opening a private window from reg window does not open the sidebar');
}).
// Part 2: NON PRIVATE WINDOW -> NON PRIVATE WINDOW
then(function() openWindow(window)).
then(cacheWindow).
then(openSidebar).
then(function(win) openWindow(win)).
then(cacheWindow).
then(function({ document }) {
let sidebarBox = document.getElementById("sidebar-box");
is(sidebarBox.hidden, false, 'Opening a reg window from reg window does open the sidebar');
}).
// Part 3: PRIVATE WINDOW -> NON PRIVATE WINDOW
then(function() openWindow(window, { private: true })).
then(cacheWindow).
then(openSidebar).
then(function(win) openWindow(win)).
then(cacheWindow).
then(function({ document }) {
let sidebarBox = document.getElementById("sidebar-box");
is(sidebarBox.hidden, true, 'Opening a reg window from a private window does not open the sidebar');
}).
// Part 4: PRIVATE WINDOW -> PRIVATE WINDOW
then(function() openWindow(window, { private: true })).
then(cacheWindow).
then(openSidebar).
then(function(win) openWindow(win, { private: true })).
then(cacheWindow).
then(function({ document }) {
let sidebarBox = document.getElementById("sidebar-box");
is(sidebarBox.hidden, false, 'Opening a private window from private window does open the sidebar');
}).
then(closeCachedWindows).
then(finish);
}

View File

@ -31,6 +31,20 @@ function whenNewWindowLoaded(aOptions, aCallback) {
return win;
}
function openWindow(aParent, aOptions, a3) {
let { Promise: { defer } } = Components.utils.import("resource://gre/modules/Promise.jsm", {});
let { promise, resolve } = defer();
let win = aParent.OpenBrowserWindow(aOptions);
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
resolve(win);
}, false);
return promise;
}
function newDirectory() {
let FileUtils =
Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils;
@ -62,4 +76,3 @@ function _initTest() {
}
_initTest();

View File

@ -25,7 +25,7 @@ interface nsIDOMNode;
* |gBrowser.tabContainer| such as e.g. |gBrowser.selectedTab|.
*/
[scriptable, uuid(59bfaf00-e3d8-4728-b4f0-cc0b9dfb4806)]
[scriptable, uuid(0aa5492c-15ad-4376-8eac-28895796826e)]
interface nsISessionStore : nsISupports
{
/**
@ -105,6 +105,20 @@ interface nsISessionStore : nsISupports
nsIDOMNode duplicateTab(in nsIDOMWindow aWindow, in nsIDOMNode aTab,
[optional] in long aDelta);
/**
* Set the number of tabs that was closed during the last close-tabs
* operation. This helps us keep track of batch-close operations so
* we can restore multiple tabs at once.
*/
void setNumberOfTabsClosedLast(in nsIDOMWindow aWindow, in unsigned long aNumber);
/**
* Get the number of tabs that was closed during the last close-tabs
* operation. This helps us keep track of batch-close operations so
* we can restore multiple tabs at once.
*/
unsigned long getNumberOfTabsClosedLast(in nsIDOMWindow aWindow);
/**
* Get the number of restore-able tabs for a browser window
*/

View File

@ -170,6 +170,14 @@ this.SessionStore = {
return SessionStoreInternal.duplicateTab(aWindow, aTab, aDelta);
},
getNumberOfTabsClosedLast: function ss_getNumberOfTabsClosedLast(aWindow) {
return SessionStoreInternal.getNumberOfTabsClosedLast(aWindow);
},
setNumberOfTabsClosedLast: function ss_setNumberOfTabsClosedLast(aWindow, aNumber) {
return SessionStoreInternal.setNumberOfTabsClosedLast(aWindow, aNumber);
},
getClosedTabCount: function ss_getClosedTabCount(aWindow) {
return SessionStoreInternal.getClosedTabCount(aWindow);
},
@ -1529,6 +1537,28 @@ let SessionStoreInternal = {
return newTab;
},
setNumberOfTabsClosedLast: function ssi_setNumberOfTabsClosedLast(aWindow, aNumber) {
if ("__SSi" in aWindow) {
return NumberOfTabsClosedLastPerWindow.set(aWindow, aNumber);
}
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
},
/* Used to undo batch tab-close operations. Defaults to 1. */
getNumberOfTabsClosedLast: function ssi_getNumberOfTabsClosedLast(aWindow) {
if ("__SSi" in aWindow) {
// Blank tabs cannot be undo-closed, so the number returned by
// the NumberOfTabsClosedLastPerWindow can be greater than the
// return value of getClosedTabCount. We won't restore blank
// tabs, so we return the minimum of these two values.
return Math.min(NumberOfTabsClosedLastPerWindow.get(aWindow) || 1,
this.getClosedTabCount(aWindow));
}
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
},
getClosedTabCount: function ssi_getClosedTabCount(aWindow) {
if ("__SSi" in aWindow) {
return this._windows[aWindow.__SSi]._closedTabs.length;
@ -4694,6 +4724,11 @@ let DyingWindowCache = {
}
};
// A map storing the number of tabs last closed per windoow. This only
// stores the most recent tab-close operation, and is used to undo
// batch tab-closing operations.
let NumberOfTabsClosedLastPerWindow = new WeakMap();
// A set of tab attributes to persist. We will read a given list of tab
// attributes when collecting tab data and will re-set those attributes when
// the given tab data is restored to a new tab.

View File

@ -40,4 +40,8 @@ function test() {
"Invalid window for getWindowValue throws");
ok(test(function() ss.setWindowValue({}, "", "")),
"Invalid window for setWindowValue throws");
ok(test(function() ss.getNumberOfTabsClosedLast({})),
"Invalid window for getNumberOfTabsClosedLast throws");
ok(test(function() ss.setNumberOfTabsClosedLast({}, 1)),
"Invalid window for setNumberOfTabsClosedLast throws");
}

View File

@ -38,5 +38,5 @@ function onTabViewWindowLoaded() {
gBrowser.removeTab(tabTwo);
finish();
});
});
}, 0);
}

View File

@ -64,7 +64,7 @@ function test() {
createBlankTab();
afterAllTabsLoaded(testUndoCloseWithSelectedBlankPinnedTab);
});
}, 0);
});
}
@ -94,7 +94,7 @@ function test() {
gBrowser.removeTab(gBrowser.tabs[0]);
afterAllTabsLoaded(finishTest);
});
}, 0);
});
}

View File

@ -81,7 +81,7 @@ function test() {
gBrowser.removeTab(gBrowser.tabs[1]);
gBrowser.removeTab(gBrowser.tabs[1]);
hideTabView(finishTest);
});
}, 0);
}
waitForExplicitFinish();

View File

@ -20,7 +20,7 @@ function test() {
whenTabViewIsHidden(function() {
win.gBrowser.removeTab(win.gBrowser.selectedTab);
executeSoon(function() {
win.undoCloseTab();
win.undoCloseTab(0);
groupItemTwo.addSubscriber("childAdded", function onChildAdded(data) {
groupItemTwo.removeSubscriber("childAdded", onChildAdded);

View File

@ -359,7 +359,7 @@ function newWindowWithState(state, callback) {
function restoreTab(callback, index, win) {
win = win || window;
let tab = win.undoCloseTab(index || 0);
let tab = win.undoCloseTab(index);
let tabItem = tab._tabViewTabItem;
let finalize = function () {

View File

@ -6,9 +6,6 @@ ac_add_options --with-google-api-keyfile=/builds/gapi.data
. $topsrcdir/build/unix/mozconfig.linux32
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -4,9 +4,6 @@ ac_add_options --enable-signmar
. $topsrcdir/build/unix/mozconfig.linux32
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -8,9 +8,6 @@ ac_add_options --enable-valgrind
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View File

@ -2,9 +2,6 @@ ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
. $topsrcdir/build/unix/mozconfig.linux32
export MOZILLA_OFFICIAL=1

View File

@ -10,9 +10,6 @@ ac_add_options --enable-codesighs
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View File

@ -6,9 +6,6 @@ ac_add_options --with-google-api-keyfile=/builds/gapi.data
. $topsrcdir/build/unix/mozconfig.linux
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -4,9 +4,6 @@ ac_add_options --enable-signmar
. $topsrcdir/build/unix/mozconfig.linux
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -8,9 +8,6 @@ ac_add_options --enable-valgrind
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View File

@ -9,7 +9,4 @@ export CXX="$topsrcdir/clang/bin/clang++"
# Add the static checker
ac_add_options --enable-clang-plugin
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -2,9 +2,6 @@ ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
. $topsrcdir/build/unix/mozconfig.linux
export MOZILLA_OFFICIAL=1

View File

@ -10,9 +10,6 @@ ac_add_options --enable-codesighs
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View File

@ -600,6 +600,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
});
XPCOMUtils.defineLazyGetter(this, 'supportsString', function() {
return Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
});
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
@ -719,7 +724,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
gcli.addCommand(commandSpec);
commands.push(commandSpec.name);
});
},
function onError(reason) {
console.error("OS.File.read(" + aFileEntry.path + ") failed.");
@ -733,7 +737,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
*/
gcli.addCommand({
name: "cmd",
get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
get hidden() {
return !prefBranch.prefHasUserValue(PREF_DIR);
},
description: gcli.lookup("cmdDesc")
});
@ -743,10 +749,49 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
gcli.addCommand({
name: "cmd refresh",
description: gcli.lookup("cmdRefreshDesc"),
get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
exec: function Command_cmdRefresh(args, context) {
get hidden() {
return !prefBranch.prefHasUserValue(PREF_DIR);
},
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
CmdCommands.refreshAutoCommands(chromeWindow);
let dirName = prefBranch.getComplexValue(PREF_DIR,
Ci.nsISupportsString).data.trim();
return gcli.lookupFormat("cmdStatus", [ commands.length, dirName ]);
}
});
/**
* 'cmd setdir' command
*/
gcli.addCommand({
name: "cmd setdir",
description: gcli.lookup("cmdSetdirDesc"),
params: [
{
name: "directory",
description: gcli.lookup("cmdSetdirDirectoryDesc"),
type: {
name: "file",
filetype: "directory",
existing: "yes"
},
defaultValue: null
}
],
returnType: "string",
get hidden() {
return true; // !prefBranch.prefHasUserValue(PREF_DIR);
},
exec: function(args, context) {
supportsString.data = args.directory;
prefBranch.setComplexValue(PREF_DIR, Ci.nsISupportsString, supportsString);
let chromeWindow = context.environment.chromeDocument.defaultView;
CmdCommands.refreshAutoCommands(chromeWindow);
return gcli.lookupFormat("cmdStatus", [ commands.length, args.directory ]);
}
});
}(this));
@ -1493,7 +1538,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
params: [
{
name: "srcdir",
type: "string",
type: "string" /* {
name: "file",
filetype: "directory",
existing: "yes"
} */,
description: gcli.lookup("toolsSrcdirDir")
}
],
@ -2167,3 +2216,49 @@ gcli.addCommand({
}
});
}(this));
/* CmdMedia ------------------------------------------------------- */
(function(module) {
/**
* 'media' command
*/
gcli.addCommand({
name: "media",
description: gcli.lookup("mediaDesc")
});
gcli.addCommand({
name: "media emulate",
description: gcli.lookup("mediaEmulateDesc"),
manual: gcli.lookup("mediaEmulateManual"),
params: [
{
name: "type",
description: gcli.lookup("mediaEmulateType"),
type: {
name: "selection",
data: ["braille", "embossed", "handheld", "print", "projection",
"screen", "speech", "tty", "tv"]
}
}
],
exec: function(args, context) {
let markupDocumentViewer = context.environment.chromeWindow
.gBrowser.markupDocumentViewer;
markupDocumentViewer.emulateMedium(args.type);
}
});
gcli.addCommand({
name: "media reset",
description: gcli.lookup("mediaResetDesc"),
manual: gcli.lookup("mediaEmulateManual"),
exec: function(args, context) {
let markupDocumentViewer = context.environment.chromeWindow
.gBrowser.markupDocumentViewer;
markupDocumentViewer.stopEmulatingMedium();
}
});
}(this));

View File

@ -35,6 +35,8 @@ MOCHITEST_BROWSER_FILES = \
browser_cmd_cookie.js \
browser_cmd_jsb.js \
browser_cmd_jsb_script.jsi \
browser_cmd_media.html \
browser_cmd_media.js \
browser_cmd_pagemod_export.html \
browser_cmd_pagemod_export.js \
browser_cmd_pref.js \
@ -42,10 +44,14 @@ MOCHITEST_BROWSER_FILES = \
browser_cmd_screenshot.html \
browser_cmd_screenshot.js \
browser_cmd_settings.js \
browser_gcli_async.js \
browser_gcli_canon.js \
browser_gcli_cli.js \
browser_gcli_completion.js \
browser_gcli_date.js \
browser_gcli_exec.js \
browser_gcli_fail.js \
browser_gcli_file.js \
browser_gcli_focus.js \
browser_gcli_history.js \
browser_gcli_incomplete.js \

View File

@ -0,0 +1,28 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>GCLI Test for Bug 819930</title>
<style>
@media braille {
body {
background-color: yellow;
}
}
@media embossed {
body {
background-color: indigo;
}
}
@media screen {
body {
background-color: white;
}
}
</style>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that screenshot command works properly
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
"test/browser_cmd_media.html";
let tests = {
testInput: function(options) {
return helpers.audit(options, [
{
setup: "media emulate braille",
check: {
input: "media emulate braille",
markup: "VVVVVVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
type: { value: "braille"},
}
},
},
{
setup: "media reset",
check: {
input: "media reset",
markup: "VVVVVVVVVVV",
status: "VALID",
args: {
}
},
},
]);
},
testEmulateMedia: function(options) {
return helpers.audit(options, [
{
setup: "media emulate braille",
check: {
args: {
type: { value: "braille"}
}
},
exec: {
output: ""
},
post: function() {
let body = options.window.document.body;
let style = options.window.getComputedStyle(body);
is(style.backgroundColor, "rgb(255, 255, 0)", "media correctly emulated");
}
}
]);
},
testEndMediaEmulation: function(options) {
return helpers.audit(options, [
{
setup: function() {
let mDV = options.browser.markupDocumentViewer;
mDV.emulateMedium("embossed");
return helpers.setInput(options, "media reset");
},
exec: {
output: ""
},
post: function() {
let body = options.window.document.body;
let style = options.window.getComputedStyle(body);
is(style.backgroundColor, "rgb(255, 255, 255)", "media reset");
}
}
]);
}
};
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, tests);
}).then(finish);
}

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

View File

@ -217,10 +217,11 @@ exports.testAltCanon = function(options) {
var commandSpecs = altCanon.getCommandSpecs();
assert.is(JSON.stringify(commandSpecs),
'{"tss":{"name":"tss","params":[' +
'{"name":"str","type":"string"},' +
'{"name":"num","type":"number"},' +
'{"name":"opt","type":{"name":"selection","data":["1","2","3"]}}]}}',
'{"tss":{"name":"tss","description":"(No description)","params":[' +
'{"name":"str","type":"string","description":"(No description)"},' +
'{"name":"num","type":"number","description":"(No description)"},' +
'{"name":"opt","type":{"name":"selection","data":["1","2","3"]},"description":"(No description)"}'+
'],"isParent":false}}',
'JSON.stringify(commandSpecs)');
var remoter = function(args, context) {

View File

@ -37,26 +37,17 @@ function test() {
// var helpers = require('gclitest/helpers');
// var mockCommands = require('gclitest/mockCommands');
var cli = require('gcli/cli');
var origLogErrors = undefined;
exports.setup = function(options) {
mockCommands.setup();
origLogErrors = cli.logErrors;
cli.logErrors = false;
};
exports.shutdown = function(options) {
mockCommands.shutdown();
cli.logErrors = origLogErrors;
origLogErrors = undefined;
};
exports.testBaseline = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
// These 3 establish a baseline for comparison when we have used the
// context command
{
@ -100,7 +91,7 @@ exports.testBaseline = function(options) {
};
exports.testContext = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
// Use the 'tsn' context
{
setup: 'context tsn',

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
@ -80,8 +90,10 @@ exports.testIncrement = function(options) {
};
exports.testInput = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
// See bug 892901
skipRemainingIf: options.isFirefox,
setup: 'tsdate 2001-01-01 1980-01-03',
check: {
input: 'tsdate 2001-01-01 1980-01-03',
@ -132,8 +144,10 @@ exports.testInput = function(options) {
};
exports.testIncrDecr = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
// See bug 892901
skipRemainingIf: options.isFirefox,
setup: 'tsdate 2001-01-01<UP>',
check: {
input: 'tsdate 2001-01-02',
@ -224,14 +238,14 @@ exports.testIncrDecr = function(options) {
message: ''
},
d2: {
value: function(d1) {
assert.is(d1.getFullYear(), 2000, 'd1 year');
assert.is(d1.getMonth(), 1, 'd1 month');
assert.is(d1.getDate(), 28, 'd1 date');
assert.is(d1.getHours(), 0, 'd1 hours');
assert.is(d1.getMinutes(), 0, 'd1 minutes');
assert.is(d1.getSeconds(), 0, 'd1 seconds');
assert.is(d1.getMilliseconds(), 0, 'd1 millis');
value: function(d2) {
assert.is(d2.getFullYear(), 2000, 'd2 year');
assert.is(d2.getMonth(), 1, 'd2 month');
assert.is(d2.getDate(), 28, 'd2 date');
assert.is(d2.getHours(), 0, 'd2 hours');
assert.is(d2.getMinutes(), 0, 'd2 minutes');
assert.is(d2.getSeconds(), 0, 'd2 seconds');
assert.is(d2.getMilliseconds(), 0, 'd2 millis');
},
arg: ' "2000-02-28"',
status: 'VALID',

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
@ -27,22 +37,13 @@ function test() {
// var helpers = require('gclitest/helpers');
// var mockCommands = require('gclitest/mockCommands');
var cli = require('gcli/cli');
var origLogErrors = undefined;
exports.setup = function(options) {
mockCommands.setup();
origLogErrors = cli.logErrors;
cli.logErrors = false;
};
exports.shutdown = function(options) {
mockCommands.shutdown();
cli.logErrors = origLogErrors;
origLogErrors = undefined;
};
exports.testBasic = function(options) {

View File

@ -0,0 +1,848 @@
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
// <INJECTED SOURCE:START>
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
// DO NOT EDIT IT DIRECTLY
var exports = {};
const TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFile.js</p>";
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, exports);
}).then(finish);
}
// <INJECTED SOURCE:END>
'use strict';
// var helpers = require('gclitest/helpers');
// var mockCommands = require('gclitest/mockCommands');
exports.setup = function(options) {
mockCommands.setup();
};
exports.shutdown = function(options) {
mockCommands.shutdown();
};
var local = false;
exports.testBasic = function(options) {
var isPhantomjsFromFilesystem = (!options.isHttp && options.isPhantomjs);
return helpers.audit(options, [
{
// These tests require us to be using node directly or to be in
// phantomjs connected to an allowexec enabled node server or to be in
// firefox. In short they only don't work when in phantomjs reading
// from the filesystem, but they do work in Firefox
skipRemainingIf: isPhantomjsFromFilesystem || options.isFirefox,
setup: 'tsfile open /',
check: {
input: 'tsfile open /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
setup: 'tsfile open /zxcv',
check: {
input: 'tsfile open /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVIIIII',
cursor: 17,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile open /mach_kernel',
check: {
input: 'tsfile open /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile open' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile saveas /',
check: {
input: 'tsfile saveas /',
hints: '',
markup: 'VVVVVVVVVVVVVVI',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
setup: 'tsfile saveas /zxcv',
check: {
input: 'tsfile saveas /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVVVV',
cursor: 19,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile saveas /mach_kernel',
check: {
input: 'tsfile saveas /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 26,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
setup: 'tsfile save /',
check: {
input: 'tsfile save /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile save' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
setup: 'tsfile save /zxcv',
check: {
input: 'tsfile save /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVV',
cursor: 17,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile save /mach_kernel',
check: {
input: 'tsfile save /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /',
check: {
input: 'tsfile cd /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile cd' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /zxcv',
check: {
input: 'tsfile cd /zxcv',
// hints: ' -> /dev/',
markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: true || !local,
setup: 'tsfile cd /etc/passwd',
check: {
input: 'tsfile cd /etc/passwd',
hints: ' -> /etc/pam.d/',
markup: 'VVVVVVVVVVIIIIIIIIIII',
cursor: 21,
current: 'p1',
status: 'ERROR',
message: '\'/etc/passwd\' is not a directory',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /etc/passwd',
status: 'INCOMPLETE',
message: '\'/etc/passwd\' is not a directory'
}
}
}
},
{
setup: 'tsfile mkdir /',
check: {
input: 'tsfile mkdir /',
hints: '',
markup: 'VVVVVVVVVVVVVI',
cursor: 14,
current: 'p1',
status: 'ERROR',
message: ''/' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
setup: 'tsfile mkdir /zxcv',
check: {
input: 'tsfile mkdir /zxcv',
// hints: ' -> /dev/',
markup: 'VVVVVVVVVVVVVVVVVV',
cursor: 18,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile mkdir /mach_kernel',
check: {
input: 'tsfile mkdir /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 25,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
setup: 'tsfile rm /',
check: {
input: 'tsfile rm /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile rm /zxcv',
check: {
input: 'tsfile rm /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile rm' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile rm /mach_kernel',
check: {
input: 'tsfile rm /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVV',
cursor: 22,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
}
]);
};
exports.testFirefoxBasic = function(options) {
return helpers.audit(options, [
{
// These tests are just like the ones above tailored for running in
// Firefox
skipRemainingIf: true,
// skipRemainingIf: !options.isFirefox,
skipIf: true,
setup: 'tsfile open /',
check: {
input: 'tsfile open /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
skipIf: true,
setup: 'tsfile open /zxcv',
check: {
input: 'tsfile open /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVIIIII',
cursor: 17,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile open' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile open /mach_kernel',
check: {
input: 'tsfile open /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile open' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: true,
setup: 'tsfile saveas /',
check: {
input: 'tsfile saveas /',
hints: '',
markup: 'VVVVVVVVVVVVVVI',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
skipIf: true,
setup: 'tsfile saveas /zxcv',
check: {
input: 'tsfile saveas /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVVVV',
cursor: 19,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile saveas /mach_kernel',
check: {
input: 'tsfile saveas /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 26,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile saveas' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
skipIf: true,
setup: 'tsfile save /',
check: {
input: 'tsfile save /',
hints: '',
markup: 'VVVVVVVVVVVVI',
cursor: 13,
current: 'p1',
status: 'ERROR',
message: '\'/\' is not a file',
args: {
command: { name: 'tsfile save' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' is not a file'
}
}
}
},
{
skipIf: true,
setup: 'tsfile save /zxcv',
check: {
input: 'tsfile save /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVVVVVVVV',
cursor: 17,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile save /mach_kernel',
check: {
input: 'tsfile save /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 24,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile save' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /',
check: {
input: 'tsfile cd /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile cd' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
setup: 'tsfile cd /zxcv',
check: {
input: 'tsfile cd /zxcv',
// hints: ' -> /dev/',
// markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
// status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /zxcv',
// status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: true || !local,
setup: 'tsfile cd /etc/passwd',
check: {
input: 'tsfile cd /etc/passwd',
hints: ' -> /etc/pam.d/',
markup: 'VVVVVVVVVVIIIIIIIIIII',
cursor: 21,
current: 'p1',
status: 'ERROR',
message: '\'/etc/passwd\' is not a directory',
args: {
command: { name: 'tsfile cd' },
p1: {
value: undefined,
arg: ' /etc/passwd',
status: 'INCOMPLETE',
message: '\'/etc/passwd\' is not a directory'
}
}
}
},
{
setup: 'tsfile mkdir /',
check: {
input: 'tsfile mkdir /',
hints: '',
markup: 'VVVVVVVVVVVVVI',
cursor: 14,
current: 'p1',
status: 'ERROR',
message: ''/' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /',
status: 'INCOMPLETE',
message: '\'/\' already exists'
}
}
}
},
{
setup: 'tsfile mkdir /zxcv',
check: {
input: 'tsfile mkdir /zxcv',
// hints: ' -> /dev/',
markup: 'VVVVVVVVVVVVVVVVVV',
cursor: 18,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: '/zxcv',
arg: ' /zxcv',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: !local,
setup: 'tsfile mkdir /mach_kernel',
check: {
input: 'tsfile mkdir /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVIIIIIIIIIIII',
cursor: 25,
current: 'p1',
status: 'ERROR',
message: '\'/mach_kernel\' already exists',
args: {
command: { name: 'tsfile mkdir' },
p1: {
value: undefined,
arg: ' /mach_kernel',
status: 'INCOMPLETE',
message: '\'/mach_kernel\' already exists'
}
}
}
},
{
skipIf: true,
setup: 'tsfile rm /',
check: {
input: 'tsfile rm /',
hints: '',
markup: 'VVVVVVVVVVV',
cursor: 11,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/',
arg: ' /',
status: 'VALID',
message: ''
}
}
}
},
{
skipIf: true,
setup: 'tsfile rm /zxcv',
check: {
input: 'tsfile rm /zxcv',
// hints: ' -> /etc/',
markup: 'VVVVVVVVVVIIIII',
cursor: 15,
current: 'p1',
status: 'ERROR',
message: '\'/zxcv\' doesn\'t exist',
args: {
command: { name: 'tsfile rm' },
p1: {
value: undefined,
arg: ' /zxcv',
status: 'INCOMPLETE',
message: '\'/zxcv\' doesn\'t exist'
}
}
}
},
{
skipIf: !local,
setup: 'tsfile rm /mach_kernel',
check: {
input: 'tsfile rm /mach_kernel',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVV',
cursor: 22,
current: 'p1',
status: 'VALID',
message: '',
args: {
command: { name: 'tsfile rm' },
p1: {
value: '/mach_kernel',
arg: ' /mach_kernel',
status: 'VALID',
message: ''
}
}
}
}
]);
};
// });

View File

@ -0,0 +1,57 @@
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
// <INJECTED SOURCE:START>
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
// DO NOT EDIT IT DIRECTLY
var exports = {};
const TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFileparser.js</p>";
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, exports);
}).then(finish);
}
// <INJECTED SOURCE:END>
'use strict';
// var assert = require('test/assert');
var fileparser = require('util/fileparser');
var local = false;
exports.testGetPredictor = function(options) {
if (!options.isNode || !local) {
return;
}
var options = { filetype: 'file', existing: 'yes' };
var predictor = fileparser.getPredictor('/usr/locl/bin/nmp', options);
return predictor().then(function(replies) {
assert.is(replies[0].name,
'/usr/local/bin/npm',
'predict npm');
});
};
// });

View File

@ -0,0 +1,78 @@
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {
// <INJECTED SOURCE:START>
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
// DO NOT EDIT IT DIRECTLY
var exports = {};
const TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFilesystem.js</p>";
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.runTests(options, exports);
}).then(finish);
}
// <INJECTED SOURCE:END>
'use strict';
// var assert = require('test/assert');
// var helpers = require('gclitest/helpers');
var filesystem = require('util/filesystem');
exports.testSplit = function(options) {
if (!options.isNode) {
return;
}
helpers.arrayIs(filesystem.split('', '/'),
[ '.' ],
'split <blank>');
helpers.arrayIs(filesystem.split('a', '/'),
[ 'a' ],
'split a');
helpers.arrayIs(filesystem.split('a/b/c', '/'),
[ 'a', 'b', 'c' ],
'split a/b/c');
helpers.arrayIs(filesystem.split('/a/b/c/', '/'),
[ 'a', 'b', 'c' ],
'split a/b/c');
helpers.arrayIs(filesystem.split('/a/b///c/', '/'),
[ 'a', 'b', 'c' ],
'split a/b/c');
};
exports.testJoin = function(options) {
if (!options.isNode) {
return;
}
assert.is(filesystem.join('usr', 'local', 'bin'),
'usr/local/bin',
'join to usr/local/bin');
};
// });

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

View File

@ -1,7 +1,17 @@
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// define(function(require, exports, module) {

View File

@ -48,6 +48,7 @@ exports.shutdown = function(options) {
};
exports.testRemote = function(options) {
var connected = false;
return helpers.audit(options, [
{
skipRemainingIf: !options.isHttp,
@ -65,6 +66,72 @@ exports.testRemote = function(options) {
unassigned: [ ],
}
},
{
setup: 'connect remote',
check: {
input: 'connect remote',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVV',
cursor: 14,
current: 'prefix',
status: 'VALID',
options: [ ],
message: '',
predictions: [ ],
unassigned: [ ],
args: {
command: { name: 'connect' },
prefix: { value: 'remote', arg: ' remote', status: 'VALID', message: '' },
host: { value: undefined, arg: '', status: 'VALID', message: '' },
port: { value: undefined, arg: '', status: 'VALID', message: '' },
}
},
exec: {
completed: false,
error: false
},
post: function(output, data) {
connected = !output.error;
if (!connected) {
console.log('Failure from "connect remote". Run server with "node gcli server start --websocket --allowexec" to allow remote command testing');
}
}
},
{
// We do a connect-disconnect dance for 2 reasons, partly re-establishing
// a connection is a good test, and secondly it lets us have minimal
// testing on the first connection so we don't need to turn websockets
// on all the time
setup: 'disconnect remote --force',
skipRemainingIf: !connected,
check: {
input: 'disconnect remote --force',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
cursor: 25,
current: 'force',
status: 'VALID',
message: '',
unassigned: [ ],
args: {
command: { name: 'disconnect' },
prefix: {
value: function(connection) {
assert.is(connection.prefix, 'remote', 'disconnecting remote');
},
arg: ' remote',
status: 'VALID',
message: ''
}
}
},
exec: {
output: /^Removed [0-9]* commands.$/,
completed: true,
type: 'string',
error: false
}
},
{
setup: 'connect remote',
check: {

View File

@ -35,7 +35,7 @@ function test() {
'use strict';
// var assert = require('test/assert');
var spell = require('gcli/types/spell');
var spell = require('util/spell');
exports.testSpellerSimple = function(options) {
var alternatives = Object.keys(options.window);
@ -54,5 +54,34 @@ exports.testSpellerSimple = function(options) {
assert.is(spell.correct('=========', alternatives), undefined);
};
exports.testRank = function(options) {
var distances = spell.rank('fred', [ 'banana', 'fred', 'ed', 'red', 'FRED' ]);
assert.is(distances.length, 5, 'rank length');
assert.is(distances[0].name, 'fred', 'fred name #0');
assert.is(distances[1].name, 'FRED', 'FRED name #1');
assert.is(distances[2].name, 'red', 'red name #2');
assert.is(distances[3].name, 'ed', 'ed name #3');
assert.is(distances[4].name, 'banana', 'banana name #4');
assert.is(distances[0].dist, 0, 'fred dist 0');
assert.is(distances[1].dist, 4, 'FRED dist 4');
assert.is(distances[2].dist, 10, 'red dist 10');
assert.is(distances[3].dist, 20, 'ed dist 20');
assert.is(distances[4].dist, 100, 'banana dist 100');
};
exports.testRank2 = function(options) {
var distances = spell.rank('caps', [ 'CAPS', 'false' ]);
assert.is(JSON.stringify(distances),
'[{"name":"CAPS","dist":4},{"name":"false","dist":50}]',
'spell.rank("caps", [ "CAPS", "false" ]');
};
exports.testDistancePrefix = function(options) {
assert.is(spell.distancePrefix('fred', 'freddy'), 0, 'distancePrefix fred');
assert.is(spell.distancePrefix('FRED', 'freddy'), 4, 'distancePrefix FRED');
};
// });

View File

@ -47,7 +47,7 @@ exports.shutdown = function(options) {
};
exports.testNewLine = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'echo a\\nb',
check: {
@ -72,7 +72,7 @@ exports.testNewLine = function(options) {
};
exports.testTab = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'echo a\\tb',
check: {
@ -97,7 +97,7 @@ exports.testTab = function(options) {
};
exports.testEscape = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
// What's typed is actually:
// tsrsrsr a\\ b c
@ -143,7 +143,7 @@ exports.testEscape = function(options) {
};
exports.testBlank = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'tsrsrsr a "" c',
check: {
@ -213,7 +213,7 @@ exports.testBlank = function(options) {
};
exports.testBlankWithParam = function(options) {
helpers.audit(options, [
return helpers.audit(options, [
{
setup: 'tsrsrsr a --p3',
check: {

View File

@ -30,6 +30,7 @@ let promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js",
let assert = { ok: ok, is: is, log: info };
var util = require('util/util');
var cli = require('gcli/cli');
var converters = require('gcli/converters');
@ -566,7 +567,7 @@ helpers._check = function(options, name, checks) {
if ('predictions' in checks) {
var predictionsCheck = function(actualPredictions) {
helpers._arrayIs(actualPredictions,
helpers.arrayIs(actualPredictions,
checks.predictions,
'predictions' + suffix);
};
@ -585,7 +586,7 @@ helpers._check = function(options, name, checks) {
}
if ('unassigned' in checks) {
helpers._arrayIs(helpers._actual.unassigned(options),
helpers.arrayIs(helpers._actual.unassigned(options),
checks.unassigned,
'unassigned' + suffix);
}
@ -613,7 +614,7 @@ helpers._check = function(options, name, checks) {
}
if ('options' in checks) {
helpers._arrayIs(helpers._actual.options(options),
helpers.arrayIs(helpers._actual.options(options),
checks.options,
'options' + suffix);
}
@ -718,6 +719,11 @@ helpers._exec = function(options, name, expected) {
return promise.resolve({});
}
var origLogErrors = cli.logErrors;
if (expected.error) {
cli.logErrors = false;
}
var output;
try {
output = options.display.requisition.exec({ hidden: true });
@ -726,6 +732,9 @@ helpers._exec = function(options, name, expected) {
assert.ok(false, 'Failure executing \'' + name + '\': ' + ex);
util.errorHandler(ex);
if (expected.error) {
cli.logErrors = origLogErrors;
}
return promise.resolve({});
}
@ -737,10 +746,17 @@ helpers._exec = function(options, name, expected) {
if (!options.window.document.createElement) {
assert.log('skipping output tests (missing doc.createElement) for ' + name);
if (expected.error) {
cli.logErrors = origLogErrors;
}
return promise.resolve({ output: output });
}
if (!('output' in expected)) {
if (expected.error) {
cli.logErrors = origLogErrors;
}
return promise.resolve({ output: output });
}
@ -788,6 +804,9 @@ helpers._exec = function(options, name, expected) {
doTest(expected.output, actualOutput);
}
if (expected.error) {
cli.logErrors = origLogErrors;
}
return { output: output, text: actualOutput };
});
};
@ -940,17 +959,6 @@ helpers.audit = function(options, audits) {
log('- START \'' + name + '\' in ' + assert.currentTest);
}
if (audit.skipIf) {
var skip = (typeof audit.skipIf === 'function') ?
audit.skipIf(options) :
!!audit.skipIf;
if (skip) {
var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : '';
assert.log('Skipped ' + name + ' ' + reason);
return promise.resolve(undefined);
}
}
if (audit.skipRemainingIf) {
var skipRemainingIf = (typeof audit.skipRemainingIf === 'function') ?
audit.skipRemainingIf(options) :
@ -964,6 +972,17 @@ helpers.audit = function(options, audits) {
}
}
if (audit.skipIf) {
var skip = (typeof audit.skipIf === 'function') ?
audit.skipIf(options) :
!!audit.skipIf;
if (skip) {
var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : '';
assert.log('Skipped ' + name + ' ' + reason);
return promise.resolve(undefined);
}
}
if (skipReason != null) {
assert.log('Skipped ' + name + ' ' + skipReason);
return promise.resolve(undefined);
@ -1008,7 +1027,7 @@ helpers.audit = function(options, audits) {
/**
* Compare 2 arrays.
*/
helpers._arrayIs = function(actual, expected, message) {
helpers.arrayIs = function(actual, expected, message) {
assert.ok(Array.isArray(actual), 'actual is not an array: ' + message);
assert.ok(Array.isArray(expected), 'expected is not an array: ' + message);

View File

@ -482,6 +482,116 @@ var tsfail = {
}
};
var tsfile = {
item: 'command',
name: 'tsfile',
description: 'test file params',
};
var tsfileOpen = {
item: 'command',
name: 'tsfile open',
description: 'a file param in open mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'file',
existing: 'yes'
}
}
],
exec: createExec('tsfile open')
};
var tsfileSaveas = {
item: 'command',
name: 'tsfile saveas',
description: 'a file param in saveas mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'file',
existing: 'no'
}
}
],
exec: createExec('tsfile saveas')
};
var tsfileSave = {
item: 'command',
name: 'tsfile save',
description: 'a file param in save mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'file',
existing: 'maybe'
}
}
],
exec: createExec('tsfile save')
};
var tsfileCd = {
item: 'command',
name: 'tsfile cd',
description: 'a file param in cd mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'directory',
existing: 'yes'
}
}
],
exec: createExec('tsfile cd')
};
var tsfileMkdir = {
item: 'command',
name: 'tsfile mkdir',
description: 'a file param in mkdir mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'directory',
existing: 'no'
}
}
],
exec: createExec('tsfile mkdir')
};
var tsfileRm = {
item: 'command',
name: 'tsfile rm',
description: 'a file param in rm mode',
params: [
{
name: 'p1',
type: {
name: 'file',
filetype: 'any',
existing: 'yes'
}
}
],
exec: createExec('tsfile rm')
};
mockCommands.commands = {};
/**
@ -533,6 +643,13 @@ mockCommands.setup = function(opts) {
mockCommands.commands.tslong = canon.addCommand(tslong);
mockCommands.commands.tsdate = canon.addCommand(tsdate);
mockCommands.commands.tsfail = canon.addCommand(tsfail);
mockCommands.commands.tsfile = canon.addCommand(tsfile);
mockCommands.commands.tsfileOpen = canon.addCommand(tsfileOpen);
mockCommands.commands.tsfileSaveas = canon.addCommand(tsfileSaveas);
mockCommands.commands.tsfileSave = canon.addCommand(tsfileSave);
mockCommands.commands.tsfileCd = canon.addCommand(tsfileCd);
mockCommands.commands.tsfileMkdir = canon.addCommand(tsfileMkdir);
mockCommands.commands.tsfileRm = canon.addCommand(tsfileRm);
};
mockCommands.shutdown = function(opts) {
@ -564,6 +681,13 @@ mockCommands.shutdown = function(opts) {
canon.removeCommand(tslong);
canon.removeCommand(tsdate);
canon.removeCommand(tsfail);
canon.removeCommand(tsfile);
canon.removeCommand(tsfileOpen);
canon.removeCommand(tsfileSaveas);
canon.removeCommand(tsfileSave);
canon.removeCommand(tsfileCd);
canon.removeCommand(tsfileMkdir);
canon.removeCommand(tsfileRm);
types.removeType(mockCommands.optionType);
types.removeType(mockCommands.optionValue);

View File

@ -707,6 +707,7 @@ FilterView.prototype = {
this._searchbox = document.getElementById("searchbox");
this._searchboxHelpPanel = document.getElementById("searchbox-help-panel");
this._filterLabel = document.getElementById("filter-label");
this._globalOperatorButton = document.getElementById("global-operator-button");
this._globalOperatorLabel = document.getElementById("global-operator-label");
this._functionOperatorButton = document.getElementById("function-operator-button");
@ -737,6 +738,8 @@ FilterView.prototype = {
this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
this._variableOperatorButton.setAttribute("label", SEARCH_VARIABLE_FLAG);
this._filterLabel.setAttribute("value",
L10N.getFormatStr("searchPanelFilter", this._fileSearchKey));
this._globalOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelGlobal", this._globalSearchKey));
this._functionOperatorLabel.setAttribute("value",
@ -780,7 +783,7 @@ FilterView.prototype = {
placeholder = L10N.getFormatStr("emptyChromeGlobalsFilterText", this._fileSearchKey);
break;
case DebuggerView.Sources:
placeholder = L10N.getFormatStr("emptyFilterText", this._fileSearchKey);
placeholder = L10N.getFormatStr("emptySearchText", this._fileSearchKey);
break;
}
this._searchbox.setAttribute("placeholder", placeholder);

View File

@ -310,8 +310,11 @@
noautofocus="true"
position="before_start">
<vbox>
<label id="searchbox-panel-description"
value="&debuggerUI.searchPanelTitle;"/>
<hbox>
<label id="filter-label"/>
</hbox>
<label id="searchbox-panel-operators"
value="&debuggerUI.searchPanelOperators;"/>
<hbox align="center">
<button id="global-operator-button"
class="searchbox-panel-operator-button"

View File

@ -106,6 +106,8 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_source_maps-01.js \
browser_dbg_source_maps-02.js \
browser_dbg_step-out.js \
browser_dbg_event-listeners.js \
browser_dbg_break-on-dom-event.js \
head.js \
$(NULL)
@ -145,6 +147,7 @@ MOCHITEST_BROWSER_PAGES = \
test-location-changes-bp.html \
test-step-out.html \
test-pause-exceptions-reload.html \
test-event-listeners.html \
$(NULL)
# Bug 888811 & bug 891176:

View File

@ -0,0 +1,158 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that the break-on-dom-events request works.
var gClient = null;
var gTab = null;
var gThreadClient = null;
var gInput = null;
var gButton = null;
const DEBUGGER_TAB_URL = EXAMPLE_URL + "test-event-listeners.html";
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(type, traits) {
gTab = addTab(DEBUGGER_TAB_URL, function() {
attach_thread_actor_for_url(gClient,
DEBUGGER_TAB_URL,
function(threadClient) {
gThreadClient = threadClient;
gInput = content.document.querySelector("input");
gButton = content.document.querySelector("button");
testBreakOnAll();
});
});
});
}
// Test pause on all events.
function testBreakOnAll()
{
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "debuggerStatement", "debugger statement was hit.");
// Test calling pauseOnDOMEvents from a paused state.
gThreadClient.pauseOnDOMEvents("*", function(packet) {
is(packet, undefined, "The pause-on-any-event request completed successfully.");
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "keyupHandler", "The keyupHandler is entered.");
gThreadClient.resume(function() {
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "clickHandler", "The clickHandler is entered.");
gThreadClient.resume(function() {
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "onchange", "The onchange handler is entered.");
gThreadClient.resume(testBreakOnDisabled);
});
gInput.focus();
gInput.value = "foo";
gInput.blur();
});
});
EventUtils.sendMouseEvent({ type: "click" }, gButton);
});
});
gThreadClient.resume(function() {
gInput.focus();
EventUtils.synthesizeKey("e", {}, content);
});
});
});
EventUtils.sendMouseEvent({ type: "click" }, gButton);
}
// Test that removing events from the array disables them.
function testBreakOnDisabled()
{
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], function(packet) {
is(packet.error, undefined, "The pause-on-click-only request completed successfully.");
gClient.addListener("paused", unexpectedListener);
// This non-capturing event listener is guaranteed to run after the page's
// capturing one had a chance to execute and modify window.foobar.
gInput.addEventListener("keyup", function tempHandler() {
gInput.removeEventListener("keyup", tempHandler, false);
is(content.wrappedJSObject.foobar, "keyupHandler", "No hidden breakpoint was hit.");
gClient.removeListener("paused", unexpectedListener);
testBreakOnNone();
}, false);
gInput.focus();
EventUtils.synthesizeKey("e", {}, content);
});
}
// Test that specifying an empty event array clears all hidden breakpoints.
function testBreakOnNone()
{
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents([], function(packet) {
is(packet.error, undefined, "The pause-on-none request completed successfully.");
gClient.addListener("paused", unexpectedListener);
// This non-capturing event listener is guaranteed to run after the page's
// capturing one had a chance to execute and modify window.foobar.
gInput.addEventListener("keyup", function tempHandler() {
gInput.removeEventListener("keyup", tempHandler, false);
is(content.wrappedJSObject.foobar, "keyupHandler", "No hidden breakpoint was hit.");
gClient.removeListener("paused", unexpectedListener);
testBreakOnClick();
}, false);
gInput.focus();
EventUtils.synthesizeKey("g", {}, content);
});
}
function unexpectedListener(event, packet, callback) {
gClient.removeListener("paused", unexpectedListener);
ok(false, "An unexpected hidden breakpoint was hit.");
gThreadClient.resume(testBreakOnClick);
}
// Test pause on a single event.
function testBreakOnClick()
{
// Test calling pauseOnDOMEvents from a running state.
gThreadClient.pauseOnDOMEvents(["click"], function(packet) {
is(packet.error, undefined, "The pause-on-click request completed successfully.");
gClient.addOneTimeListener("paused", function(event, packet) {
is(packet.why.type, "pauseOnDOMEvents", "A hidden breakpoint was hit.");
is(packet.frame.callee.name, "clickHandler", "The clickHandler is entered.");
gThreadClient.resume(function() {
gClient.close(finish);
});
});
EventUtils.sendMouseEvent({ type: "click" }, gButton);
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gTab = null;
gClient = null;
gThreadClient = null;
gInput = null;
gButton = null;
});

View File

@ -54,35 +54,33 @@ function test() {
cmd("dbg step out", function() {
is(output.value, "step out", "debugger stepped out");
cmd("dbg continue", function() {
cmd("dbg continue", function() {
is(output.value, "dbg continue", "debugger continued");
is(output.value, "dbg continue", "debugger continued");
function closeDebugger(cb) {
helpers.audit(options, [{
setup: "dbg close",
completed: false,
exec: { output: "" }
}]);
function closeDebugger(cb) {
helpers.audit(options, [{
setup: "dbg close",
completed: false,
exec: { output: "" }
}]);
let toolbox = gDevTools.getToolbox(options.target);
if (!toolbox) {
let toolbox = gDevTools.getToolbox(options.target);
if (!toolbox) {
ok(true, "Debugger was closed.");
cb();
} else {
toolbox.on("destroyed", function () {
ok(true, "Debugger was closed.");
cb();
} else {
toolbox.on("destroyed", function () {
ok(true, "Debugger was closed.");
cb();
});
}
});
}
}
// We're closing the debugger twice to make sure
// 'dbg close' doesn't error when toolbox is already
// closed. See bug 884638 for more info.
// We're closing the debugger twice to make sure
// 'dbg close' doesn't error when toolbox is already
// closed. See bug 884638 for more info.
closeDebugger(() => {
closeDebugger(() => deferred.resolve());
});
closeDebugger(() => {
closeDebugger(() => deferred.resolve());
});
});
});

View File

@ -0,0 +1,91 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that the eventListeners request works.
var gClient = null;
var gTab = null;
var gThreadClient = null;
const DEBUGGER_TAB_URL = EXAMPLE_URL + "test-event-listeners.html";
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
gTab = addTab(DEBUGGER_TAB_URL, function() {
attach_thread_actor_for_url(gClient,
DEBUGGER_TAB_URL,
function(threadClient) {
gThreadClient = threadClient;
testEventListeners();
});
});
});
}
function testEventListeners()
{
gClient.addOneTimeListener("paused", function(aEvent, aPacket) {
is(aPacket.why.type, "debuggerStatement", "debugger statement was hit.");
gThreadClient.eventListeners(function(aPacket) {
is(aPacket.listeners.length, 4, "Found all event listeners.");
let types = [];
for (let l of aPacket.listeners) {
let node = l.node;
ok(node, "There is a node property.");
ok(node.object, "There is a node object property.");
ok(node.selector == "window" ||
content.document.querySelectorAll(node.selector).length == 1,
"The node property is a unique CSS selector");
ok(l.function, "There is a function property.");
is(l.function.type, "object", "The function form is of type 'object'.");
is(l.function.class, "Function", "The function form is of class 'Function'.");
is(l.function.url, DEBUGGER_TAB_URL, "The function url is correct.");
is(l.allowsUntrusted, true,
"allowsUntrusted property has the right value.");
is(l.inSystemEventGroup, false,
"inSystemEventGroup property has the right value.");
types.push(l.type);
if (l.type == "keyup") {
is(l.capturing, true, "Capturing property has the right value.");
is(l.isEventHandler, false,
"isEventHandler property has the right value.");
} else if (l.type == "load") {
is(l.capturing, false, "Capturing property has the right value.");
is(l.isEventHandler, false,
"isEventHandler property has the right value.");
} else {
is(l.capturing, false, "Capturing property has the right value.");
is(l.isEventHandler, true,
"isEventHandler property has the right value.");
}
}
ok(types.indexOf("click") != -1, "Found the click handler.");
ok(types.indexOf("change") != -1, "Found the change handler.");
ok(types.indexOf("keyup") != -1, "Found the keyup handler.");
finish_test();
});
});
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"));
}
function finish_test()
{
gThreadClient.resume(function() {
gClient.close(finish);
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gTab = null;
gClient = null;
gThreadClient = null;
});

View File

@ -37,6 +37,13 @@ let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
Services.prefs.setBoolPref("devtools.debugger.log", true);
// Redeclare dbg_assert with a fatal behavior.
function dbg_assert(cond, e) {
if (!cond) {
throw e;
}
}
registerCleanupFunction(function() {
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", gEnableRemote);
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
@ -143,11 +150,11 @@ function attach_tab_actor_for_url(aClient, aURL, aCallback) {
function attach_thread_actor_for_url(aClient, aURL, aCallback) {
attach_tab_actor_for_url(aClient, aURL, function(aTabActor, aResponse) {
aClient.attachThread(actor.threadActor, function(aResponse, aThreadClient) {
aClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
// We don't care about the pause right now (use
// get_actor_for_url() if you do), so resume it.
aThreadClient.resume(function(aResponse) {
aCallback(actor);
aCallback(aThreadClient);
});
});
});

Some files were not shown because too many files have changed in this diff Show More