Merge m-c to s-c.

This commit is contained in:
Richard Newman 2013-01-02 19:35:43 -08:00
commit 8f2b88b111
1338 changed files with 38558 additions and 21921 deletions

View File

@ -150,13 +150,6 @@ SYMBOL_INDEX_NAME = \
buildsymbols:
ifdef MOZ_CRASHREPORTER
ifdef USE_ELF_HACK
ifeq (mobile,$(MOZ_BUILD_APP))
$(MAKE) -C mobile/xul/installer elfhack
else
$(MAKE) -C $(MOZ_BUILD_APP)/installer elfhack
endif
endif
echo building symbol store
$(RM) -r $(DIST)/crashreporter-symbols
$(RM) "$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip"

View File

@ -62,8 +62,8 @@ interface nsIAccessibleProvider : nsISupports
const long XULTab = 0x00001017;
/** Used for XUL tabs element, a container for tab elements */
const long XULTabs = 0x00001018;
/** Used for XUL deck frame */
const long XULDeck = 0x00001019;
/** Used for XUL tabpanels element */
const long XULTabpanels = 0x00001019;
const long XULText = 0x0000101A;
const long XULTextBox = 0x0000101B;

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
@ -117,10 +118,12 @@ AccReorderEvent::IsShowHideEventTarget(const Accessible* aTarget) const
{
uint32_t count = mDependentEvents.Length();
for (uint32_t index = count - 1; index < count; index--) {
if (mDependentEvents[index]->mAccessible == aTarget &&
mDependentEvents[index]->mEventType == nsIAccessibleEvent::EVENT_SHOW ||
mDependentEvents[index]->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
return mDependentEvents[index]->mEventType;
if (mDependentEvents[index]->mAccessible == aTarget) {
uint32_t eventType = mDependentEvents[index]->mEventType;
if (eventType == nsIAccessibleEvent::EVENT_SHOW ||
eventType == nsIAccessibleEvent::EVENT_HIDE) {
return mDependentEvents[index]->mEventType;
}
}
}

View File

@ -52,7 +52,7 @@ enum AccType {
eMenuPopupType,
eProgressType,
eRootType,
eXULDeckType,
eXULTabpanelsType,
eXULTreeType,
eLastAccType = eXULTreeType

View File

@ -49,7 +49,7 @@ DocManager::GetDocAccessible(nsIDocument* aDocument)
// Ensure CacheChildren is called before we query cache.
ApplicationAcc()->EnsureChildren();
DocAccessible* docAcc = mDocAccessibleCache.GetWeak(aDocument);
DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
if (docAcc)
return docAcc;
@ -181,7 +181,7 @@ DocManager::OnStateChange(nsIWebProgress* aWebProgress,
logging::DocLoad("start document loading", aWebProgress, aRequest, aStateFlags);
#endif
DocAccessible* docAcc = mDocAccessibleCache.GetWeak(document);
DocAccessible* docAcc = GetExistingDocAccessible(document);
if (!docAcc)
return NS_OK;
@ -280,7 +280,7 @@ DocManager::HandleEvent(nsIDOMEvent* aEvent)
// We're allowed to not remove listeners when accessible document is
// shutdown since we don't keep strong reference on chrome event target and
// listeners are removed automatically when chrome event target goes away.
DocAccessible* docAccessible = mDocAccessibleCache.GetWeak(document);
DocAccessible* docAccessible = GetExistingDocAccessible(document);
if (docAccessible)
docAccessible->Shutdown();
@ -312,7 +312,7 @@ DocManager::HandleDOMDocumentLoad(nsIDocument* aDocument,
{
// Document accessible can be created before we were notified the DOM document
// was loaded completely. However if it's not created yet then create it.
DocAccessible* docAcc = mDocAccessibleCache.GetWeak(aDocument);
DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
if (!docAcc) {
docAcc = CreateDocOrRootAccessible(aDocument);
if (!docAcc)
@ -358,7 +358,7 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
// Ignore documents without presshell and not having root frame.
nsIPresShell* presShell = aDocument->GetShell();
if (!presShell || !presShell->GetRootFrame() || presShell->IsDestroying())
if (!presShell || presShell->IsDestroying())
return nullptr;
bool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);

View File

@ -59,14 +59,6 @@ public:
*/
Accessible* FindAccessibleInCache(nsINode* aNode) const;
/**
* Return document accessible from the cache. Convenient method for testing.
*/
inline DocAccessible* GetDocAccessibleFromCache(nsIDocument* aDocument) const
{
return mDocAccessibleCache.GetWeak(aDocument);
}
/**
* Called by document accessible when it gets shutdown.
*/
@ -154,6 +146,18 @@ private:
DocAccessibleHashtable mDocAccessibleCache;
};
/**
* Return the existing document accessible for the document if any.
* Note this returns the doc accessible for the primary pres shell if there is
* more than one.
*/
inline DocAccessible*
GetExistingDocAccessible(const nsIDocument* aDocument)
{
nsIPresShell* ps = aDocument->GetShell();
return ps ? ps->GetDocAccessible() : nullptr;
}
} // namespace a11y
} // namespace mozilla

View File

@ -400,8 +400,7 @@ logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
}
nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(DOMDocument));
DocAccessible* document =
GetAccService()->GetDocAccessibleFromCache(documentNode);
DocAccessible* document = GetExistingDocAccessible(documentNode);
LogDocInfo(documentNode, document);
@ -425,8 +424,7 @@ logging::DocLoad(const char* aMsg, nsIDocument* aDocumentNode)
{
MsgBegin(sDocLoadTitle, aMsg);
DocAccessible* document =
GetAccService()->GetDocAccessibleFromCache(aDocumentNode);
DocAccessible* document = GetExistingDocAccessible(aDocumentNode);
LogDocInfo(aDocumentNode, document);
MsgEnd();
@ -486,7 +484,7 @@ logging::DocCreate(const char* aMsg, nsIDocument* aDocumentNode,
DocAccessible* aDocument)
{
DocAccessible* document = aDocument ?
aDocument : GetAccService()->GetDocAccessibleFromCache(aDocumentNode);
aDocument : GetExistingDocAccessible(aDocumentNode);
MsgBegin(sDocCreateTitle, aMsg);
LogDocInfo(aDocumentNode, document);
@ -498,7 +496,7 @@ logging::DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
DocAccessible* aDocument)
{
DocAccessible* document = aDocument ?
aDocument : GetAccService()->GetDocAccessibleFromCache(aDocumentNode);
aDocument : GetExistingDocAccessible(aDocumentNode);
MsgBegin(sDocDestroyTitle, aMsg);
LogDocInfo(aDocumentNode, document);

View File

@ -9,7 +9,7 @@
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "DocAccessible.h"
#include "DocAccessible-inl.h"
#include "nsEventShell.h"
#include "FocusManager.h"
#include "Role.h"
@ -213,6 +213,10 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
"Pending content insertions while initial accessible tree isn't created!");
}
// Initialize scroll support if needed.
if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
mDocument->AddScrollListener();
// Process content inserted notifications to update the tree. Process other
// notifications like DOM events and then flush event queue. If any new
// notifications are queued during this processing then they will be processed
@ -637,7 +641,6 @@ NotificationController::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
void
NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
{
DocAccessible* document = aEvent->GetDocAccessible();
Accessible* container = aEvent->mAccessible->Parent();
if (!container)
return;

View File

@ -249,7 +249,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eNoAction,
eNoLiveAttr,
eSelect,
eListControl | eSelect,
kNoReqStates,
eARIAMultiSelectable,
eARIAReadonly

View File

@ -60,6 +60,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Util.h"
#include "nsDeckFrame.h"
#ifdef MOZ_XUL
#include "XULAlertAccessible.h"
@ -185,6 +186,7 @@ Accessible*
nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
bool aCanCreate)
{
nsIPresShell* ps = aPresShell;
nsIDocument* documentNode = aPresShell->GetDocument();
if (documentNode) {
nsCOMPtr<nsISupports> container = documentNode->GetContainer();
@ -196,11 +198,10 @@ nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(rootTreeItem));
nsCOMPtr<nsIPresShell> presShell;
docShell->GetPresShell(getter_AddRefs(presShell));
documentNode = presShell->GetDocument();
ps = presShell;
}
return aCanCreate ?
GetDocAccessible(documentNode) : GetDocAccessibleFromCache(documentNode);
return aCanCreate ? GetDocAccessible(ps) : ps->GetDocAccessible();
}
}
return nullptr;
@ -254,6 +255,47 @@ nsAccessibilityService::CreatePluginAccessible(nsObjectFrame* aFrame,
return nullptr;
}
void
nsAccessibilityService::DeckPanelSwitched(nsIPresShell* aPresShell,
nsIContent* aDeckNode,
nsIFrame* aPrevBoxFrame,
nsIFrame* aCurrentBoxFrame)
{
// Ignore tabpanels elements (a deck having an accessible) since their
// children are accessible not depending on selected tab.
DocAccessible* document = GetDocAccessible(aPresShell);
if (!document || document->HasAccessible(aDeckNode))
return;
if (aPrevBoxFrame) {
nsIContent* panelNode = aPrevBoxFrame->GetContent();
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "deck panel unselected");
logging::Node("container", panelNode);
logging::Node("content", aDeckNode);
logging::MsgEnd();
}
#endif
document->ContentRemoved(aDeckNode, panelNode);
}
if (aCurrentBoxFrame) {
nsIContent* panelNode = aCurrentBoxFrame->GetContent();
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "deck panel selected");
logging::Node("container", panelNode);
logging::Node("content", aDeckNode);
logging::MsgEnd();
}
#endif
document->ContentInserted(aDeckNode, panelNode, panelNode->GetNextSibling());
}
}
void
nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
nsIContent* aContainer,
@ -364,15 +406,12 @@ nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame)
void
nsAccessibilityService::PresShellActivated(nsIPresShell* aPresShell)
{
nsIDocument* DOMDoc = aPresShell->GetDocument();
if (DOMDoc) {
DocAccessible* document = GetDocAccessibleFromCache(DOMDoc);
if (document) {
RootAccessible* rootDocument = document->RootAccessible();
NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!");
if (rootDocument)
rootDocument->DocumentActivated(document);
}
DocAccessible* document = aPresShell->GetDocAccessible();
if (document) {
RootAccessible* rootDocument = document->RootAccessible();
NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!");
if (rootDocument)
rootDocument->DocumentActivated(document);
}
}
@ -608,7 +647,7 @@ nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
if (!accessible) {
nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
if (document)
accessible = GetDocAccessibleFromCache(document);
accessible = GetExistingDocAccessible(document);
}
NS_IF_ADDREF(*aAccessible = accessible);
@ -804,7 +843,7 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
newAcc = new ARIAGridCellAccessibleWrap(content, document);
}
} else if ((roleMapEntry->accTypes & eTable) &&
} else if ((roleMapEntry->IsOfType(eTable)) &&
frame->AccessibleType() != eHTMLTableType) {
newAcc = new ARIAGridAccessibleWrap(content, document);
}
@ -824,7 +863,7 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
if (!roleMapEntry && newAcc) {
if (frame->AccessibleType() == eHTMLTableRowType) {
nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
if (contextRoleMap && !(contextRoleMap->accTypes & eTable))
if (contextRoleMap && !(contextRoleMap->IsOfType(eTable)))
roleMapEntry = &nsARIAMap::gEmptyRoleMap;
} else if (frame->AccessibleType() == eHTMLTableCellType &&
@ -836,35 +875,50 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
content->Tag() == nsGkAtoms::dd ||
frame->AccessibleType() == eHTMLLiType) {
nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
if (contextRoleMap && !(contextRoleMap->accTypes & eList))
if (contextRoleMap && !(contextRoleMap->IsOfType(eList)))
roleMapEntry = &nsARIAMap::gEmptyRoleMap;
}
}
}
}
if (!newAcc) {
// Accessible XBL types and deck stuff are used in XUL only currently.
if (!newAcc && content->IsXUL()) {
// No accessible for not selected deck panel and its children.
if (!aContext->IsXULTabpanels()) {
nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent());
if (deckFrame && deckFrame->GetSelectedBox() != frame) {
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nullptr;
}
}
// Elements may implement nsIAccessibleProvider via XBL. This allows them to
// say what kind of accessible to create.
newAcc = CreateAccessibleByType(content, document);
// Any XUL box can be used as tabpanel, make sure we create a proper
// accessible for it.
if (!newAcc && aContext->IsXULTabpanels() &&
content->GetParent() == aContext->GetContent()) {
nsIAtom* frameType = frame->GetType();
if (frameType == nsGkAtoms::boxFrame ||
frameType == nsGkAtoms::scrollFrame) {
newAcc = new XULTabpanelAccessible(content, document);
}
}
}
if (!newAcc) {
// xul:deck does not have XBL and nsIFrame::CreateAccessible() is only called
// on HTML elements
nsIAtom* tag = content->Tag();
if ((tag == nsGkAtoms::deck) || (tag == nsGkAtoms::tabpanels)) {
newAcc = new XULDeckAccessible(content, document);
} else if (content->IsSVG(nsGkAtoms::svg)) {
if (content->IsSVG(nsGkAtoms::svg)) {
newAcc = new EnumRoleAccessible(content, document, roles::DIAGRAM);
} else if (content->IsMathML(nsGkAtoms::math)) {
newAcc = new EnumRoleAccessible(content, document, roles::EQUATION);
}
}
if (!newAcc)
newAcc = CreateAccessibleForDeckChild(frame, content, document);
// If no accessible, see if we need to create a generic accessible because
// of some property that makes this object interesting
// We don't do this for <body>, <html>, <window>, <dialog> etc. which
@ -1011,8 +1065,8 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
accessible = new XULComboboxAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULDeck:
accessible = new XULDeckAccessible(aContent, aDoc);
case nsIAccessibleProvider::XULTabpanels:
accessible = new XULTabpanelsAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULDropmarker:
@ -1406,6 +1460,9 @@ nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
case eTextLeafType:
newAcc = new TextLeafAccessibleWrap(aContent, document);
break;
default:
MOZ_ASSERT(false);
break;
}
return newAcc.forget();
@ -1480,37 +1537,6 @@ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
////////////////////////////////////////////////////////////////////////////////
// nsAccessibilityService private (DON'T put methods here)
already_AddRefed<Accessible>
nsAccessibilityService::CreateAccessibleForDeckChild(nsIFrame* aFrame,
nsIContent* aContent,
DocAccessible* aDoc)
{
if (aFrame->GetType() == nsGkAtoms::boxFrame ||
aFrame->GetType() == nsGkAtoms::scrollFrame) {
nsIFrame* parentFrame = aFrame->GetParent();
if (parentFrame && parentFrame->GetType() == nsGkAtoms::deckFrame) {
// If deck frame is for xul:tabpanels element then the given node has
// tabpanel accessible.
nsIContent* parentContent = parentFrame->GetContent();
#ifdef MOZ_XUL
if (parentContent->NodeInfo()->Equals(nsGkAtoms::tabpanels,
kNameSpaceID_XUL)) {
Accessible* accessible = new XULTabpanelAccessible(aContent, aDoc);
NS_ADDREF(accessible);
return accessible;
}
#endif
Accessible* accessible = new EnumRoleAccessible(aContent, aDoc,
roles::PROPERTYPAGE);
NS_ADDREF(accessible);
return accessible;
}
}
return nullptr;
}
#ifdef MOZ_XUL
already_AddRefed<Accessible>
nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,

View File

@ -64,6 +64,13 @@ public:
virtual Accessible* AddNativeRootAccessible(void* aAtkAccessible);
virtual void RemoveNativeRootAccessible(Accessible* aRootAccessible);
/**
* Notification used to update the accessible tree when deck panel is
* switched.
*/
void DeckPanelSwitched(nsIPresShell* aPresShell, nsIContent* aDeckNode,
nsIFrame* aPrevBoxFrame, nsIFrame* aCurrentBoxFrame);
/**
* Notification used to update the accessible tree when new content is
* inserted.
@ -173,13 +180,6 @@ private:
CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent,
Accessible* aContext);
/**
* Create accessible if parent is a deck frame.
*/
already_AddRefed<Accessible>
CreateAccessibleForDeckChild(nsIFrame* aFrame, nsIContent* aContent,
DocAccessible* aDoc);
#ifdef MOZ_XUL
/**
* Create accessible for XUL tree element.

View File

@ -264,6 +264,16 @@ Accessible::Name(nsString& aName)
aName.CompressWhitespace();
return eNameFromTooltip;
}
} else if (mContent->IsSVG()) {
// If user agents need to choose among multiple desc or title elements
// for processing, the user agent shall choose the first one.
for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
childElm = childElm->GetNextSibling()) {
if (childElm->IsSVG(nsGkAtoms::title)) {
nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName);
return eNameFromTooltip;
}
}
}
if (nameFlag != eNoNameOnPurpose)
@ -307,25 +317,40 @@ Accessible::Description(nsString& aDescription)
// Try XUL <description control="[id]">description text</description>
XULDescriptionIterator iter(Document(), mContent);
Accessible* descr = nullptr;
while ((descr = iter.Next()))
while ((descr = iter.Next())) {
nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(),
&aDescription);
}
}
if (aDescription.IsEmpty()) {
nsIAtom *descAtom = isXUL ? nsGkAtoms::tooltiptext :
nsGkAtoms::title;
if (mContent->GetAttr(kNameSpaceID_None, descAtom, aDescription)) {
nsAutoString name;
Name(name);
if (name.IsEmpty() || aDescription == name)
// Don't use tooltip for a description if this object
// has no name or the tooltip is the same as the name
aDescription.Truncate();
if (aDescription.IsEmpty()) {
// Keep the Name() method logic.
if (mContent->IsHTML()) {
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription);
} else if (mContent->IsXUL()) {
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription);
} else if (mContent->IsSVG()) {
for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
childElm = childElm->GetNextSibling()) {
if (childElm->IsSVG(nsGkAtoms::title)) {
nsTextEquivUtils::AppendTextEquivFromContent(this, childElm,
&aDescription);
break;
}
}
}
if (!aDescription.IsEmpty()) {
nsAutoString name;
ENameValueFlag nameFlag = Name(name);
// Don't use tooltip for a description if it was used for a name.
if (nameFlag == eNameFromTooltip)
aDescription.Truncate();
}
}
aDescription.CompressWhitespace();
}
aDescription.CompressWhitespace();
}
NS_IMETHODIMP
@ -612,6 +637,7 @@ Accessible::VisibilityState()
deckFrame->GetContent()->Tag() == nsGkAtoms::tabpanels)
return states::OFFSCREEN;
NS_NOTREACHED("Children of not selected deck panel are not accessible.");
return states::INVISIBLE;
}
@ -1589,17 +1615,44 @@ Accessible::GetValue(nsAString& aValue)
void
Accessible::Value(nsString& aValue)
{
if (mRoleMapEntry) {
if (mRoleMapEntry->valueRule == eNoValue)
return;
if (!mRoleMapEntry)
return;
// aria-valuenow is a number, and aria-valuetext is the optional text equivalent
// For the string value, we will try the optional text equivalent first
if (mRoleMapEntry->valueRule != eNoValue) {
// aria-valuenow is a number, and aria-valuetext is the optional text
// equivalent. For the string value, we will try the optional text
// equivalent first.
if (!mContent->GetAttr(kNameSpaceID_None,
nsGkAtoms::aria_valuetext, aValue)) {
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
aValue);
}
return;
}
// Value of combobox is a text of current or selected item.
if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
Accessible* option = CurrentItem();
if (!option) {
Accessible* listbox = nullptr;
IDRefsIterator iter(mDoc, mContent, nsGkAtoms::aria_owns);
while ((listbox = iter.Next()) && !listbox->IsListControl());
if (!listbox) {
uint32_t childCount = ChildCount();
for (uint32_t idx = 0; idx < childCount; idx++) {
Accessible* child = mChildren.ElementAt(idx);
if (child->IsListControl())
listbox = child;
}
}
if (listbox)
option = listbox->GetSelectedItem(0);
}
if (option)
nsTextEquivUtils::GetNameFromSubtree(option, aValue);
}
}
@ -2466,6 +2519,18 @@ Accessible::NativeName(nsString& aName)
if (mContent->IsXUL())
return GetXULName(aName);
if (mContent->IsSVG()) {
// If user agents need to choose among multiple desc or title elements
// for processing, the user agent shall choose the first one.
for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
childElm = childElm->GetNextSibling()) {
if (childElm->IsSVG(nsGkAtoms::desc)) {
nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName);
return eNameOK;
}
}
}
return eNameOK;
}

View File

@ -520,7 +520,7 @@ public:
bool IsTextLeaf() const { return mType == eTextLeafType; }
TextLeafAccessible* AsTextLeaf();
bool IsXULDeck() const { return mType == eXULDeckType; }
bool IsXULTabpanels() const { return mType == eXULTabpanelsType; }
bool IsXULTree() const { return mType == eXULTreeType; }
XULTreeAccessible* AsXULTree();

View File

@ -65,6 +65,33 @@ DocAccessible::UpdateText(nsIContent* aTextNode)
mNotificationController->ScheduleTextUpdate(aTextNode);
}
inline void
DocAccessible::AddScrollListener()
{
// Delay scroll initializing until the document has a root frame.
if (!mPresShell->GetRootFrame())
return;
mDocFlags |= eScrollInitialized;
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
if (sf) {
sf->AddScrollPositionListener(this);
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocCreate))
logging::Text("add scroll listener");
#endif
}
}
inline void
DocAccessible::RemoveScrollListener()
{
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
if (sf)
sf->RemoveScrollPositionListener(this);
}
inline void
DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
{

View File

@ -75,7 +75,7 @@ DocAccessible::
nsIPresShell* aPresShell) :
HyperTextAccessibleWrap(aRootContent, this),
mDocumentNode(aDocument), mScrollPositionChangedTicks(0),
mLoadState(eTreeConstructionPending), mLoadEventType(0),
mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
mVirtualCursor(nullptr),
mPresShell(aPresShell)
{
@ -93,18 +93,6 @@ DocAccessible::
// If this is a XUL Document, it should not implement nsHyperText
if (mDocumentNode && mDocumentNode->IsXUL())
mGenericTypes &= ~eHyperText;
// For GTK+ native window, we do nothing here.
if (!mDocumentNode)
return;
// DocManager creates document accessible when scrollable frame is
// available already, it should be safe time to add scroll listener.
AddScrollListener();
// We provide a virtual cursor if this is a root doc or if it's a tab doc.
mIsCursorable = (!(mDocumentNode->GetParentDocument()) ||
nsCoreUtils::IsTabDocument(mDocumentNode));
}
DocAccessible::~DocAccessible()
@ -145,7 +133,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleDocument)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleCursorable,
mIsCursorable)
(mDocFlags & eCursorable))
foundInterface = 0;
nsresult status;
@ -502,7 +490,8 @@ DocAccessible::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
if (IsDefunct())
return NS_ERROR_FAILURE;
NS_ENSURE_TRUE(mIsCursorable, NS_ERROR_NOT_IMPLEMENTED);
if (!(mDocFlags & eCursorable))
return NS_OK;
if (!mVirtualCursor) {
mVirtualCursor = new nsAccessiblePivot(this);
@ -603,8 +592,6 @@ DocAccessible::Shutdown()
logging::DocDestroy("document shutdown", mDocumentNode, this);
#endif
mPresShell->SetDocAccessible(nullptr);
if (mNotificationController) {
mNotificationController->Shutdown();
mNotificationController = nullptr;
@ -640,6 +627,7 @@ DocAccessible::Shutdown()
mVirtualCursor = nullptr;
}
mPresShell->SetDocAccessible(nullptr);
mPresShell = nullptr; // Avoid reentrancy
mDependentIDsHash.Clear();
@ -798,36 +786,6 @@ DocAccessible::ScrollTimerCallback(nsITimer* aTimer, void* aClosure)
}
}
// DocAccessible protected member
void
DocAccessible::AddScrollListener()
{
if (!mPresShell)
return;
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollableExternal();
if (sf) {
sf->AddScrollPositionListener(this);
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocCreate))
logging::Text("add scroll listener");
#endif
}
}
// DocAccessible protected member
void
DocAccessible::RemoveScrollListener()
{
if (!mPresShell)
return;
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollableExternal();
if (sf) {
sf->RemoveScrollPositionListener(this);
}
}
////////////////////////////////////////////////////////////////////////////////
// nsIScrollPositionListener
@ -1511,14 +1469,23 @@ DocAccessible::NotifyOfLoading(bool aIsReloading)
void
DocAccessible::DoInitialUpdate()
{
if (nsCoreUtils::IsTabDocument(mDocumentNode))
mDocFlags |= eTabDocument;
// We provide a virtual cursor if this is a root doc or if it's a tab doc.
if (!mDocumentNode->GetParentDocument() || (mDocFlags & eTabDocument))
mDocFlags |= eCursorable;
mLoadState |= eTreeConstructed;
// The content element may be changed before the initial update and then we
// miss the notification (since content tree change notifications are ignored
// prior to initial update). Make sure the content element is valid.
nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
if (mContent != contentElm)
if (mContent != contentElm) {
mContent = contentElm;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}
// Build initial tree.
CacheChildrenInSubtree(this);
@ -1739,8 +1706,10 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
if (aContainer == this) {
// If new root content has been inserted then update it.
nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocumentNode);
if (rootContent != mContent)
if (rootContent != mContent) {
mContent = rootContent;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}
// Continue to update the tree even if we don't have root content.
// For example, elements may be inserted under the document element while

View File

@ -333,8 +333,11 @@ protected:
*/
void ProcessLoad();
void AddScrollListener();
void RemoveScrollListener();
/**
* Add/remove scroll listeners, @see nsIScrollPositionListener interface.
*/
void AddScrollListener();
void RemoveScrollListener();
/**
* Append the given document accessible to this document's child document
@ -482,6 +485,20 @@ protected:
protected:
/**
* State and property flags, kept by mDocFlags.
*/
enum {
// Whether scroll listeners were added.
eScrollInitialized = 1 << 0,
// Whether we support nsIAccessibleCursorable.
eCursorable = 1 << 1,
// Whether the document is a tab document.
eTabDocument = 1 << 2
};
/**
* Cache of accessibles within this document accessible.
*/
@ -496,7 +513,12 @@ protected:
/**
* Bit mask of document load states (@see LoadState).
*/
uint32_t mLoadState;
uint32_t mLoadState : 3;
/**
* Bit mask of other states and props.
*/
uint32_t mDocFlags : 28;
/**
* Type of document load event fired after the document is loaded completely.
@ -516,11 +538,6 @@ protected:
nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
/**
* Whether we support nsIAccessibleCursorable, used when querying the interface.
*/
bool mIsCursorable;
/**
* The virtual cursor of the document when it supports nsIAccessibleCursorable.
*/

View File

@ -358,7 +358,7 @@ HTMLTextFieldAccessible::Value(nsString& aValue)
textArea->GetValue(aValue);
return;
}
nsHTMLInputElement* input = nsHTMLInputElement::FromContent(mContent);
if (input)
input->GetValue(aValue);

View File

@ -502,7 +502,8 @@ HTMLTableAccessible::SelectedCellCount()
int32_t startRow = -1, startCol = -1;
cellFrame->GetRowIndex(startRow);
cellFrame->GetColIndex(startCol);
if (startRow == rowIdx && startCol == colIdx)
if (startRow >= 0 && (uint32_t)startRow == rowIdx &&
startCol >= 0 && (uint32_t)startCol == colIdx)
count++;
}
}
@ -551,7 +552,8 @@ HTMLTableAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
int32_t startCol = -1, startRow = -1;
cellFrame->GetRowIndex(startRow);
cellFrame->GetColIndex(startCol);
if (startRow != rowIdx || startCol != colIdx)
if ((startRow >= 0 && (uint32_t)startRow != rowIdx) ||
(startCol >= 0 && (uint32_t)startCol != colIdx))
continue;
Accessible* cell = mDoc->GetAccessible(cellFrame->GetContent());
@ -577,7 +579,8 @@ HTMLTableAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
int32_t startRow = -1, startCol = -1;
cellFrame->GetColIndex(startCol);
cellFrame->GetRowIndex(startRow);
if (startRow == rowIdx && startCol == colIdx)
if (startRow >= 0 && (uint32_t)startRow == rowIdx &&
startCol >= 0 && (uint32_t)startCol == colIdx)
aCells->AppendElement(CellIndexAt(rowIdx, colIdx));
}
}

View File

@ -191,7 +191,7 @@ this.EventManager = {
if (txtIface.characterCount)
throw x;
}
this.present(Presentation, textChanged(
this.present(Presentation.textChanged(
isInserted, event.start, event.length,
text, event.modifiedText));
}

View File

@ -60,9 +60,9 @@ AccessibleWrap::GetNativeType ()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
if (IsXULDeck())
if (IsXULTabpanels())
return [mozPaneAccessible class];
roles::Role role = Role();
switch (role) {
case roles::PUSHBUTTON:

View File

@ -223,7 +223,7 @@ DocAccessibleWrap::Shutdown()
// Do window emulation specific shutdown if emulation was started.
if (nsWinUtils::IsWindowEmulationStarted()) {
// Destroy window created for root document.
if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
if (mDocFlags & eTabDocument) {
sHWNDCache.Remove(mHWND);
::DestroyWindow(static_cast<HWND>(mHWND));
}
@ -253,7 +253,7 @@ DocAccessibleWrap::DoInitialUpdate()
if (nsWinUtils::IsWindowEmulationStarted()) {
// Create window for tab document.
if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
if (mDocFlags & eTabDocument) {
mozilla::dom::TabChild* tabChild =
mozilla::dom::GetTabChildFrom(mDocumentNode->GetShell());

View File

@ -18,9 +18,7 @@ namespace a11y {
inline DocAccessible*
sdnAccessible::GetDocument() const
{
DocManager* docMgr = GetAccService();
return docMgr ?
docMgr->GetDocAccessibleFromCache(mNode->OwnerDoc()) : nullptr;
return GetExistingDocAccessible(mNode->OwnerDoc());
}
inline Accessible*

View File

@ -163,11 +163,11 @@ XULTabsAccessible::NativeName(nsString& aName)
////////////////////////////////////////////////////////////////////////////////
// XULDeckAccessible
// XULTabpanelsAccessible
////////////////////////////////////////////////////////////////////////////////
role
XULDeckAccessible::NativeRole()
XULTabpanelsAccessible::NativeRole()
{
return roles::PANE;
}

View File

@ -62,12 +62,12 @@ protected:
/**
* A container of tab panels, xul:tabpanels element.
*/
class XULDeckAccessible : public AccessibleWrap
class XULTabpanelsAccessible : public AccessibleWrap
{
public:
XULDeckAccessible(nsIContent* aContent, DocAccessible* aDoc) :
XULTabpanelsAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{ mType = eXULDeckType; }
{ mType = eXULTabpanelsType; }
// Accessible
virtual a11y::role NativeRole();

View File

@ -17,3 +17,16 @@ function testName(aAccOrElmOrID, aName, aMsg)
}
return acc;
}
/**
* Test accessible description for the given accessible.
*/
function testDescr(aAccOrElmOrID, aDescr)
{
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
return;
is(acc.description, aDescr,
"Wrong description for " + prettyName(aAccOrElmOrID));
}

View File

@ -21,6 +21,7 @@ MOCHITEST_A11Y_FILES =\
test_link.html \
test_list.html \
test_markup.html \
test_svg.html \
test_browserui.xul \
test_tree.xul \
markuprules.xml \

View File

@ -0,0 +1,56 @@
<html>
<head>
<title>Accessible name and description for SVG elements</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript">
function doTest()
{
testName("svg1", "A name");
testDescr("svg1", "A description");
testName("svg2", "A tooltip");
testDescr("svg2", "");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=459357"
title="Support accessible name computation for SVG">
Mozilla Bug 459357
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg1">
<title>A description</title>
<desc>A name</desc>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg2">
<title>A tooltip</title>
</svg>
</body>
</html>

View File

@ -32,7 +32,6 @@
"test1: frameDocCheckbox");
testStates(frameDocTextbox, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
"test1: frameDocTextbox");
frameDoc.designMode = "on";
testStates(frameDoc, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
"test2: frameDoc");

View File

@ -20,7 +20,6 @@
<![CDATA[
function doTest()
{
testStates("deck_pane1", STATE_INVISIBLE, 0, STATE_OFFSCREEN);
testStates("deck_pane2", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
testStates("tabs_pane1", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
testStates("tabs_pane2", STATE_OFFSCREEN, 0, STATE_INVISIBLE);

View File

@ -8,18 +8,10 @@
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
<script type="application/javascript"
src="name.js"></script>
<script type="application/javascript">
function testDescr(aAccOrElmOrID, aDescr)
{
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
return;
is(acc.description, aDescr,
"Wrong description for " + prettyName(aAccOrElmOrID));
}
function doTest()
{
// Description from aria-describedby attribute

View File

@ -17,6 +17,7 @@ MOCHITEST_A11Y_FILES =\
test_colorpicker.xul \
test_cssoverflow.html \
test_contextmenu.xul \
test_deck.xul \
test_doc.html \
test_gencontent.html \
test_hidden.html \

View File

@ -0,0 +1,109 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Tree update on XUL deck panel switching">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="../common.js" />
<script type="application/javascript"
src="../role.js" />
<script type="application/javascript"
src="../states.js" />
<script type="application/javascript"
src="../events.js" />
<script type="application/javascript">
<![CDATA[
function switchDeckPanel(aContainerID, aDeckID)
{
this.panelIndex = 0;
this.container = getAccessible(aContainerID);
this.deckNode = getNode(aDeckID);
this.prevPanel = getAccessible(this.deckNode.selectedPanel);
this.panelNode = this.deckNode.childNodes[this.panelIndex];
this.eventSeq = [
new invokerChecker(EVENT_HIDE, this.prevPanel),
new invokerChecker(EVENT_SHOW, this.panelNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function switchDeckPanel_invoke()
{
var tree =
{ GROUPING: [ // role="group"
{ GROUPING: [ // groupbox, a selected panel #2
{ PUSHBUTTON: [ ] } // button
] }
] };
testAccessibleTree(this.container, tree);
this.deckNode.selectedIndex = this.panelIndex;
}
this.finalCheck = function switchDeckPanel_finalCheck()
{
var tree =
{ GROUPING: [ // role="group"
{ LABEL: [ // description, a selected panel #1
{ TEXT_LEAF: [] } // text leaf, a description value
] }
] };
testAccessibleTree(this.container, tree);
}
this.getID = function switchDeckPanel_getID()
{
return "switch deck panel";
}
}
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new switchDeckPanel("container", "deck"));
gQueue.invoke(); // will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=814836"
title=" xul:deck element messes up screen reader">
Mozilla Bug 814836
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1" id="container" role="group">
<deck id="deck" selectedIndex="1">
<description>This is the first page</description>
<groupbox>
<button label="This is the second page"/>
</groupbox>
</deck>
</vbox>
</hbox>
</window>

View File

@ -32,7 +32,7 @@
return getDocNode(aID).body.firstChild;
}
function rootContentReplaced(aID, aTextName)
function rootContentReplaced(aID, aTextName, aRootContentRole)
{
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
@ -42,7 +42,7 @@
this.finalCheck = function rootContentReplaced_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
role: aRootContentRole || ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
@ -142,14 +142,14 @@
docNode.replaceChild(newHTMLNode, docNode.documentElement);
}
this.getID = function replaceIFrameBody_getID()
this.getID = function replaceIFrameHTMLElm_getID()
{
return "replace HTML element";
}
}
/**
* Replace HTML body.
* Replace HTML body on new body having ARIA role.
*/
function replaceIFrameBody(aID)
{
@ -164,26 +164,36 @@
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
}
this.finalCheck = function replaceIFrameBody_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello"
}
]
};
testAccessibleTree(getDocNode(aID), tree);
}
this.getID = function replaceIFrameBody_getID()
{
return "replace body";
}
}
/**
* Replace HTML body on new body having ARIA role.
*/
function replaceIFrameBodyOnARIARoleBody(aID)
{
this.__proto__ = new rootContentReplaced(aID, "New Hello",
ROLE_PUSHBUTTON);
this.invoke = function replaceIFrameBodyOnARIARoleBody_invoke()
{
var docNode = getDocNode(aID);
var newBodyNode = docNode.createElement("body");
var newTextNode = docNode.createTextNode("New Hello");
newBodyNode.appendChild(newTextNode);
newBodyNode.setAttribute("role", "button");
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
}
this.getID = function replaceIFrameBodyOnARIARoleBody_getID()
{
return "replace body on body having ARIA role";
}
}
/**
* Open/close document pair.
*/
@ -401,6 +411,7 @@
gQueue.push(new insertElmUnderDocElmWhileBodyMissed("iframe"));
gQueue.push(new insertBodyToIFrameDoc("iframe"));
gQueue.push(new changeSrc("iframe"));
gQueue.push(new replaceIFrameBodyOnARIARoleBody("iframe"));
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
@ -420,6 +431,9 @@
<a target="_blank"
title="Reorder event for document must be fired after document initial tree creation"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=669263">Mozilla Bug 669263</a>
<a target="_blank"
title="Changing the HTML body doesn't pick up ARIA role"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=818407">Mozilla Bug 818407</a>
<p id="display"></p>
<div id="content" style="display: none"></div>

View File

@ -50,6 +50,21 @@
testValue("aria_main_link", href);
testValue("aria_navigation_link", href);
//////////////////////////////////////////////////////////////////////////
// ARIA comboboxes
// aria-activedescendant defines a current item the value is computed from
testValue("aria_combobox1", kDiscBulletText + "Zoom");
// aria-selected defines a selected item the value is computed from,
// list control is pointed by aria-owns relation.
testValue("aria_combobox2", kDiscBulletText + "Zoom");
// aria-selected defines a selected item the value is computed from,
// list control is a child of combobox.
testValue("aria_combobox3", kDiscBulletText + "2");
//////////////////////////////////////////////////////////////////////////
// HTML controls
testValue("combobox1", "item1");
testValue("combobox2", "item2");
@ -69,7 +84,12 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=494807"
title="Do not expose a11y info specific to hyperlinks when role is overridden using ARIA">
Mozilla Bug 494807
</a><br />
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=819273"
title=" ARIA combobox should have accessible value">
Mozilla Bug 819273
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
@ -88,6 +108,32 @@
<!-- strange edge case: please don't do this in the wild -->
<a id="aria_link_link" role="link" href="foo">link</a>
<div id="aria_combobox1" role="combobox"
aria-owns="aria_combobox1_owned_listbox"
aria-activedescendant="aria_combobox1_selected_option">
</div>
<ul role="listbox" id="aria_combobox1_owned_listbox">
<li role="option">Zebra</li>
<li role="option" id="aria_combobox1_selected_option">Zoom</li>
</ul>
<div id="aria_combobox2" role="combobox"
aria-owns="aria_combobox2_owned_listbox">
</div>
<ul role="listbox" id="aria_combobox2_owned_listbox">
<li role="option">Zebra</li>
<li role="option" aria-selected="true">Zoom</li>
</ul>
<div id="aria_combobox3" role="combobox">
<div role="textbox"></div>
<ul role="listbox">
<li role="option">1</li>
<li role="option" aria-selected="true">2</li>
<li role="option">3</li>
</ul>
</div>
<select id="combobox1">
<option id="cb1_item1">item1</option>
<option id="cb1_item2">item2</option>

View File

@ -363,9 +363,8 @@ AnimationThread(void *)
ANativeWindow const * const window = gNativeWindow.get();
window->query(window, NATIVE_WINDOW_FORMAT, &format);
EGLConfig config = NULL;
CreateConfig(&config, display, format);
if (!config) {
EGLConfig config;
if (!CreateConfig(&config, display, format)) {
LOGW("Could not find config for pixel format");
return nullptr;
}

View File

@ -333,7 +333,7 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
// If an urlclassifier table has not been updated in this number of seconds,
// a gethash request will be forced to check that the result is still in
// the database.
pref("urlclassifier.confirm-age", 2700);
pref("urlclassifier.max-complete-age", 2700);
// URL for checking the reason for a malware warning.
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
@ -356,13 +356,6 @@ pref("content.ime.strict_policy", true);
// $ adb shell start
pref("browser.dom.window.dump.enabled", false);
// Temporarily relax file:// origin checks so that we can use <img>s
// from other dirs as webgl textures and more. Remove me when we have
// installable apps or wifi support.
pref("security.fileuri.strict_origin_policy", false);
// Default Content Security Policy to apply to privileged and certified apps
pref("security.apps.privileged.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'");
pref("security.apps.certified.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self'");
@ -461,9 +454,6 @@ pref("shutdown.watchdog.timeoutSecs", 5);
pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
// Amount of time to wait after the user is idle before prompting to apply an update
pref("b2g.update.apply-idle-timeout", 600000); // milliseconds
// Amount of time the updater waits for the process to exit cleanly before
// forcefully exiting the process
pref("b2g.update.self-destruct-timeout", 5000); // milliseconds
pref("app.update.enabled", true);
pref("app.update.auto", false);
@ -601,6 +591,13 @@ pref("browser.prompt.allowNative", false);
// a restart is required to enable a new value.
pref("network.activity.blipIntervalMilliseconds", 250);
// By default we want the NetworkManager service to manage Gecko's offline
// status for us according to the state of Wifi/cellular data connections.
// In some environments, such as the emulator or hardware with other network
// connectivity, this is not desireable, however, in which case this pref
// can be flipped to false.
pref("network.gonk.manage-offline-status", true);
pref("jsloader.reuseGlobal", true);
// Enable font inflation for browser tab content.

View File

@ -282,14 +282,12 @@ function getJSON(element) {
// Until the input type=date/datetime/time have been implemented
// let's return their real type even if the platform returns 'text'
// Related to Bug 769352 - Implement <input type=date>
// Related to Bug 777279 - Implement <input type=time>
let attributeType = element.getAttribute("type") || "";
if (attributeType) {
var typeLowerCase = attributeType.toLowerCase();
switch (typeLowerCase) {
case "date":
case "time":
case "datetime":
case "datetime-local":

View File

@ -98,6 +98,7 @@ function doInternalWatch() {
function doInternalRequest() {
log("doInternalRequest:", options && isLoaded);
if (options && isLoaded) {
var stringifiedOptions = JSON.stringify(options);
content.wrappedJSObject.BrowserID.internal.get(
options.origin,
function(assertion, internalParams) {
@ -110,7 +111,7 @@ function doInternalRequest() {
}
closeIdentityDialog();
},
options);
stringifiedOptions);
}
}

View File

@ -103,7 +103,7 @@ var shell = {
} catch(e) { }
// Bail if there isn't a valid crashID.
if (!crashID) {
if (!crashID && !this.CrashSubmit.pendingIDs().length) {
return;
}
@ -125,10 +125,20 @@ var shell = {
});
},
// this function submit the pending crashes.
// make sure you are online.
submitQueuedCrashes: function shell_submitQueuedCrashes() {
// submit the pending queue.
let pending = shell.CrashSubmit.pendingIDs();
for (let crashid of pending) {
shell.CrashSubmit.submit(crashid);
}
},
// This function submits a crash when we're online.
submitCrash: function shell_submitCrash(aCrashID) {
if (this.onlineForCrashReport()) {
this.CrashSubmit.submit(aCrashID);
this.submitQueuedCrashes();
return;
}
@ -136,13 +146,7 @@ var shell = {
let network = subject.QueryInterface(Ci.nsINetworkInterface);
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED
&& network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
shell.CrashSubmit.submit(aCrashID);
// submit the pending queue.
let pending = shell.CrashSubmit.pendingIDs();
for (let crashid of pending) {
shell.CrashSubmit.submit(crashid);
}
shell.submitQueuedCrashes();
Services.obs.removeObserver(observer, topic);
}
@ -684,7 +688,7 @@ var AlertsHelper = {
let message = messages[i];
if (message === "notification") {
return helper.fullLaunchPath();
} else if ("notification" in message) {
} else if (typeof message == "object" && "notification" in message) {
return helper.resolveFromOrigin(message["notification"]);
}
}

View File

@ -18,14 +18,9 @@ let log =
function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
function log_noop(msg) { };
const APPLY_PROMPT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
const APPLY_IDLE_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-idle-timeout");
const SELF_DESTRUCT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
const PREF_APPLY_PROMPT_TIMEOUT = "b2g.update.apply-prompt-timeout";
const PREF_APPLY_IDLE_TIMEOUT = "b2g.update.apply-idle-timeout";
const APPLY_IDLE_TIMEOUT_SECONDS = APPLY_IDLE_TIMEOUT / 1000;
const NETWORK_ERROR_OFFLINE = 111;
XPCOMUtils.defineLazyServiceGetter(Services, "aus",
@ -108,6 +103,14 @@ UpdatePrompt.prototype = {
_waitingForIdle: false,
_updateCheckListner: null,
get applyPromptTimeout() {
return Services.prefs.getIntPref(PREF_APPLY_PROMPT_TIMEOUT);
},
get applyIdleTimeout() {
return Services.prefs.getIntPref(PREF_APPLY_IDLE_TIMEOUT);
},
// nsIUpdatePrompt
// FIXME/bug 737601: we should have users opt-in to downloading
@ -130,14 +133,15 @@ UpdatePrompt.prototype = {
// update quietly without user intervention.
this.sendUpdateEvent("update-downloaded", aUpdate);
if (Services.idle.idleTime >= APPLY_IDLE_TIMEOUT) {
if (Services.idle.idleTime >= this.applyIdleTimeout) {
this.showApplyPrompt(aUpdate);
return;
}
let applyIdleTimeoutSeconds = this.applyIdleTimeout / 1000;
// We haven't been idle long enough, so register an observer
log("Update is ready to apply, registering idle timeout of " +
APPLY_IDLE_TIMEOUT_SECONDS + " seconds before prompting.");
applyIdleTimeoutSeconds + " seconds before prompting.");
this._update = aUpdate;
this.waitForIdle();
@ -165,7 +169,7 @@ UpdatePrompt.prototype = {
}
this._waitingForIdle = true;
Services.idle.addIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
Services.idle.addIdleObserver(this, this.applyIdleTimeout / 1000);
Services.obs.addObserver(this, "quit-application", false);
},
@ -185,18 +189,18 @@ UpdatePrompt.prototype = {
// Schedule a fallback timeout in case the UI is unable to respond or show
// a prompt for some reason.
this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
this._applyPromptTimer = this.createTimer(this.applyPromptTimeout);
},
_copyProperties: ["appVersion", "buildID", "detailsURL", "displayVersion",
"errorCode", "isOSUpdate", "platformVersion",
"previousAppVersion", "state", "statusText"],
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
let detail = {
displayVersion: aUpdate.displayVersion,
detailsURL: aUpdate.detailsURL,
statusText: aUpdate.statusText,
state: aUpdate.state,
errorCode: aUpdate.errorCode,
isOSUpdate: aUpdate.isOSUpdate
};
let detail = {};
for each (let property in this._copyProperties) {
detail[property] = aUpdate[property];
}
let patch = aUpdate.selectedPatch;
if (!patch && aUpdate.patchCount > 0) {
@ -429,7 +433,7 @@ UpdatePrompt.prototype = {
this.showApplyPrompt(this._update);
// Fall through
case "quit-application":
Services.idle.removeIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
Services.idle.removeIdleObserver(this, this.applyIdleTimeout / 1000);
Services.obs.removeObserver(this, "quit-application");
break;
case "update-check-start":

View File

@ -16,17 +16,6 @@ XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
.getService(Ci.nsIMessageSender);
});
// Splits parameters in a query string.
function extractParameters(aQuery) {
let params = aQuery.split("&");
let res = {};
params.forEach(function(aParam) {
let obj = aParam.split("=");
res[obj[0]] = decodeURIComponent(obj[1]);
});
return res;
}
function YoutubeProtocolHandler() {
}
@ -61,24 +50,95 @@ YoutubeProtocolHandler.prototype = {
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", infoURI, true);
xhr.addEventListener("load", function() {
// Youtube sends the response as a double wrapped url answer:
// we first extract the url_encoded_fmt_stream_map parameter,
// and from each comma-separated entry in this value, we extract
// other parameters (url and type).
let key = "url_encoded_fmt_stream_map=";
let pos = xhr.responseText.indexOf(key);
if (pos == -1) {
return;
try {
let info = parseYoutubeVideoInfo(xhr.responseText);
cpmm.sendAsyncMessage("content-handler", info);
}
let streams = decodeURIComponent(xhr.responseText
.substring(pos + key.length)).split(",");
let uri;
let mimeType;
catch(e) {
// If parseYoutubeVideoInfo() can't find a video URL, it
// throws an Error. We report the error message here and do
// nothing. This shouldn't happen often. But if it does, the user
// will find that clicking on a video doesn't do anything.
log(e.message);
}
});
xhr.send(null);
// itag is an undocumented value which maps to resolution and mimetype
// see https://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
// Ordered from least to most preferred
let recognizedItags = [
function log(msg) {
msg = "YoutubeProtocolHandler.js: " + (msg.join ? msg.join(" ") : msg);
Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService)
.logStringMessage(msg);
}
//
// Parse the response from a youtube get_video_info query.
//
// If youtube's response is a failure, this function returns an object
// with status, errorcode, type and reason properties. Otherwise, it returns
// an object with status, url, and type properties, and optional
// title, poster, and duration properties.
//
function parseYoutubeVideoInfo(response) {
// Splits parameters in a query string.
function extractParameters(q) {
let params = q.split("&");
let result = {};
for(let i = 0, n = params.length; i < n; i++) {
let param = params[i];
let pos = param.indexOf('=');
if (pos === -1)
continue;
let name = param.substring(0, pos);
let value = param.substring(pos+1);
result[name] = decodeURIComponent(value);
}
return result;
}
let params = extractParameters(response);
// If the request failed, return an object with an error code
// and an error message
if (params.status === 'fail') {
//
// Hopefully this error message will be properly localized.
// Do we need to add any parameters to the XMLHttpRequest to
// specify the language we want?
//
// Note that we include fake type and url properties in the returned
// object. This is because we still need to trigger the video app's
// view activity handler to display the error message from youtube,
// and those parameters are required.
//
return {
status: params.status,
errorcode: params.errorcode,
reason: (params.reason || '').replace(/\+/g, ' '),
type: 'video/3gpp',
url: 'https://m.youtube.com'
}
}
// Otherwise, the query was successful
let result = {
status: params.status,
};
// Now parse the available streams
let streamsText = params.url_encoded_fmt_stream_map;
if (!streamsText)
throw Error("No url_encoded_fmt_stream_map parameter");
let streams = streamsText.split(',');
for(let i = 0, n = streams.length; i < n; i++) {
streams[i] = extractParameters(streams[i]);
}
// This is the list of youtube video formats, ordered from worst
// (but playable) to best. These numbers are values used as the
// itag parameter of each stream description. See
// https://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
let formats = [
"17", // 144p 3GP
"36", // 240p 3GP
"43", // 360p WebM
@ -87,39 +147,39 @@ YoutubeProtocolHandler.prototype = {
#endif
];
let bestItag = -1;
let extras = { }
streams.forEach(function(aStream) {
let params = extractParameters(aStream);
let url = params["url"];
let type = params["type"] ? params["type"].split(";")[0] : null;
let itag = params["itag"];
let index;
if (url && type && ((index = recognizedItags.indexOf(itag)) != -1) &&
index > bestItag) {
uri = url + '&signature=' + (params["sig"] ? params['sig'] : '');
mimeType = type;
bestItag = index;
}
for (let param in params) {
if (["thumbnail_url", "length_seconds", "title"].indexOf(param) != -1) {
extras[param] = decodeURIComponent(params[param]);
}
}
// Sort the array of stream descriptions in order of format
// preference, so that the first item is the most preferred one
streams.sort(function(a, b) {
let x = a.itag ? formats.indexOf(a.itag) : -1;
let y = b.itag ? formats.indexOf(b.itag) : -1;
return y - x;
});
if (uri && mimeType) {
cpmm.sendAsyncMessage("content-handler", {
url: uri,
type: mimeType,
extras: extras
});
let bestStream = streams[0];
// If the best stream is a format we don't support just return
if (formats.indexOf(bestStream.itag) === -1)
throw Error("No supported video formats");
result.url = bestStream.url + '&signature=' + (bestStream.sig || '');
result.type = bestStream.type;
// Strip codec information off of the mime type
if (result.type && result.type.indexOf(';') !== -1) {
result.type = result.type.split(';',1)[0];
}
});
xhr.send(null);
if (params.title) {
result.title = params.title.replace(/\+/g, ' ');
}
if (params.length_seconds) {
result.duration = params.length_seconds;
}
if (params.thumbnail_url) {
result.poster = params.thumbnail_url;
}
return result;
}
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
},

View File

@ -206,7 +206,7 @@ function test_options_pass_through() {
let randomMixedParams = {
loggedInUser: "juanita@mozilla.com",
forceAuthentication: true,
issuer: "https://foo.com",
forceIssuer: "foo.com",
someThing: {
name: "Pertelote",
legs: 4,

View File

@ -1,6 +1,6 @@
[
{
"clang_version": "r170377"
"clang_version": "r170890"
},
{
"size": 47,
@ -9,8 +9,8 @@
"filename": "setup.sh"
},
{
"size": 56131193,
"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
"size": 56126352,
"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

View File

@ -158,6 +158,7 @@
@BINPATH@/components/dom_activities.xpt
@BINPATH@/components/dom_apps.xpt
@BINPATH@/components/dom_base.xpt
@BINPATH@/components/dom_system.xpt
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_telephony.xpt
@BINPATH@/components/dom_wifi.xpt

View File

@ -244,7 +244,6 @@ pref("browser.chrome.site_icons", true);
pref("browser.chrome.favicons", true);
// browser.warnOnQuit == false will override all other possible prompts when quitting or restarting
pref("browser.warnOnQuit", true);
pref("browser.warnOnRestart", false);
// browser.showQuitWarning specifically controls the quit warning dialog. We
// might still show the window closing dialog with showQuitWarning == false.
pref("browser.showQuitWarning", false);
@ -741,7 +740,7 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
// If an urlclassifier table has not been updated in this number of seconds,
// a gethash request will be forced to check that the result is still in
// the database.
pref("urlclassifier.confirm-age", 2700);
pref("urlclassifier.max-complete-age", 2700);
#endif
pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");

View File

@ -5,6 +5,10 @@
var FullScreen = {
_XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
get _fullScrToggler() {
delete this._fullScrToggler;
return this._fullScrToggler = document.getElementById("fullscr-toggler");
},
toggle: function (event) {
var enterFS = window.fullScreen;
@ -46,15 +50,8 @@ var FullScreen = {
// events than raw listening of mouse coords. We don't add the toolbar in DOM full-screen
// mode, only browser full-screen mode.
if (!document.mozFullScreen) {
let fullScrToggler = document.getElementById("fullscr-toggler");
if (!fullScrToggler) {
fullScrToggler = document.createElement("hbox");
fullScrToggler.id = "fullscr-toggler";
fullScrToggler.collapsed = true;
gNavToolbox.parentNode.insertBefore(fullScrToggler, gNavToolbox.nextSibling);
}
fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
}
if (gPrefService.getBoolPref("browser.fullscreen.autohide"))
gBrowser.mPanelContainer.addEventListener("mousemove",
@ -152,13 +149,10 @@ var FullScreen = {
this._cancelAnimation();
this.mouseoverToggle(false);
// If there's a full-screen toggler, remove its listeners, so that mouseover
// Remove listeners on the full-screen toggler, so that mouseover
// the top of the screen will not cause the toolbar to re-appear.
let fullScrToggler = document.getElementById("fullscr-toggler");
if (fullScrToggler) {
fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
}
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
},
cleanup: function () {
@ -170,11 +164,8 @@ var FullScreen = {
document.removeEventListener("popuphidden", this._setPopupOpen, false);
gPrefService.removeObserver("browser.fullscreen", this);
let fullScrToggler = document.getElementById("fullscr-toggler");
if (fullScrToggler) {
fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
}
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
this.cancelWarning();
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
@ -506,10 +497,7 @@ var FullScreen = {
gNavToolbox.style.marginTop =
aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
let toggler = document.getElementById("fullscr-toggler");
if (toggler) {
toggler.collapsed = aShow;
}
this._fullScrToggler.collapsed = aShow;
this._isChromeCollapsed = !aShow;
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
this._shouldAnimate = true;

View File

@ -269,7 +269,11 @@ var PlacesCommandHook = {
var description;
var charset;
try {
title = webNav.document.title || url.spec;
let isErrorPage = /^about:(neterror|certerror|blocked)/
.test(webNav.document.documentURI);
title = isErrorPage ? PlacesUtils.history.getPageTitle(url)
: webNav.document.title;
title = title || url.spec;
description = PlacesUIUtils.getDescriptionFromDocument(webNav.document);
charset = webNav.document.characterSet;
}

View File

@ -448,7 +448,7 @@ var ctrlTab = {
if (tabs.length > 2) {
this.open();
} else if (tabs.length == 2) {
let index = gBrowser.selectedTab == tabs[0] ? 1 : 0;
let index = tabs[0].selected ? 1 : 0;
gBrowser.selectedTab = tabs[index];
}
}
@ -488,7 +488,7 @@ var ctrlTab = {
this.advanceFocus(false);
// If the current tab is removed, another tab can steal our focus.
if (aTab == gBrowser.selectedTab && this.panel.state == "open") {
if (aTab.selected && this.panel.state == "open") {
setTimeout(function (selected) {
selected.focus();
}, 0, this.selected);

View File

@ -0,0 +1,52 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# 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/.
let WebrtcIndicator = {
init: function () {
let temp = {};
Cu.import("resource:///modules/webrtcUI.jsm", temp);
this.UIModule = temp.webrtcUI;
this.updateButton();
},
get button() {
delete this.button;
return this.button = document.getElementById("webrtc-status-button");
},
updateButton: function () {
this.button.hidden = !this.UIModule.showGlobalIndicator;
},
fillPopup: function (aPopup) {
this._menuitemData = new WeakMap;
for (let streamData of this.UIModule.activeStreams) {
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("label", streamData.uri);
menuitem.setAttribute("tooltiptext", streamData.uri);
this._menuitemData.set(menuitem, streamData);
aPopup.appendChild(menuitem);
}
},
clearPopup: function (aPopup) {
while (aPopup.lastChild)
aPopup.removeChild(aPopup.lastChild);
},
menuCommand: function (aMenuitem) {
let streamData = this._menuitemData.get(aMenuitem);
if (!streamData)
return;
let tab = streamData.tab;
let browserWindow = tab.ownerDocument.defaultView;
browserWindow.gBrowser.selectedTab = tab;
browserWindow.focus();
}
}

View File

@ -476,10 +476,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
max-width: 280px;
}
#geolocation-notification {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#geolocation-notification");
}
#addon-progress-notification {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
}

View File

@ -155,6 +155,7 @@ let gInitialPages = [
#include browser-tabPreviews.js
#include browser-tabview.js
#include browser-thumbnails.js
#include browser-webrtcUI.js
#ifdef MOZ_SERVICES_SYNC
#include browser-syncui.js
@ -1254,6 +1255,7 @@ var gBrowserInit = {
gFormSubmitObserver.init();
SocialUI.init();
AddonManager.addAddonListener(AddonsMgrListener);
WebrtcIndicator.init();
gBrowser.addEventListener("pageshow", function(event) {
// Filter out events that are not about the document load we are interested in
@ -1262,7 +1264,7 @@ var gBrowserInit = {
}, true);
// Ensure login manager is up and running.
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
Services.logins;
if (mustLoadSidebar) {
let sidebar = document.getElementById("sidebar");
@ -1341,7 +1343,7 @@ var gBrowserInit = {
// If the user manually opens the download manager before the timeout, the
// downloads will start right away, and getting the service again won't hurt.
setTimeout(function() {
Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
Services.downloads;
#ifdef XP_WIN
if (Win7Features) {
@ -1495,10 +1497,8 @@ var gBrowserInit = {
// End startup crash tracking after a delay to catch crashes while restoring
// tabs and to postpone saving the pref to disk.
try {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
getService(Ci.nsIAppStartup);
const startupCrashEndDelay = 30 * 1000;
setTimeout(appStartup.trackStartupCrashEnd, startupCrashEndDelay);
setTimeout(Services.startup.trackStartupCrashEnd, startupCrashEndDelay);
} catch (ex) {
Cu.reportError("Could not end startup crash tracking: " + ex);
}
@ -1750,7 +1750,6 @@ var nonBrowserWindowShutdown = gBrowserInit.nonBrowserWindowShutdown.bind(
function HandleAppCommandEvent(evt) {
evt.stopPropagation();
switch (evt.command) {
case "Back":
BrowserBack();
@ -1774,9 +1773,35 @@ function HandleAppCommandEvent(evt) {
case "Home":
BrowserHome();
break;
default:
case "New":
BrowserOpenTab();
break;
case "Close":
BrowserCloseTabOrWindow();
break;
case "Find":
gFindBar.onFindCommand();
break;
case "Help":
openHelpLink('firefox-help');
break;
case "Open":
BrowserOpenFileWindow();
break;
case "Print":
PrintUtils.print();
break;
case "Save":
saveDocument(window.content.document);
break;
case "SendMail":
MailIntegration.sendLinkForWindow(window.content);
break;
default:
return;
}
evt.stopPropagation();
evt.preventDefault();
}
function gotoHistoryIndex(aEvent) {
@ -2222,10 +2247,6 @@ function readFromClipboard()
var url;
try {
// Get clipboard.
var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
.getService(Components.interfaces.nsIClipboard);
// Create transferable that will transfer the text.
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
@ -2234,10 +2255,10 @@ function readFromClipboard()
trans.addDataFlavor("text/unicode");
// If available, use selection clipboard, otherwise global one
if (clipboard.supportsSelectionClipboard())
clipboard.getData(trans, clipboard.kSelectionClipboard);
if (Services.clipboard.supportsSelectionClipboard())
Services.clipboard.getData(trans, Services.clipboard.kSelectionClipboard);
else
clipboard.getData(trans, clipboard.kGlobalClipboard);
Services.clipboard.getData(trans, Services.clipboard.kGlobalClipboard);
var data = {};
var dataLen = {};
@ -2303,9 +2324,7 @@ function BrowserViewSourceOfDocument(aDocument)
// imageElement - image to load in the Media Tab of the Page Info window; can be null/omitted
function BrowserPageInfo(doc, initialTab, imageElement) {
var args = {doc: doc, initialTab: initialTab, imageElement: imageElement};
var windows = Cc['@mozilla.org/appshell/window-mediator;1']
.getService(Ci.nsIWindowMediator)
.getEnumerator("Browser:page-info");
var windows = Services.wm.getEnumerator("Browser:page-info");
var documentURL = doc ? doc.location : window.content.document.location;
@ -2468,7 +2487,7 @@ function PageProxyClickHandler(aEvent)
* to the DOM for unprivileged pages.
*/
function BrowserOnAboutPageLoad(document) {
if (/^about:home$/i.test(document.documentURI)) {
if (document.documentURI.toLowerCase() == "about:home") {
// XXX bug 738646 - when Marketplace is launched, remove this statement and
// the hidden attribute set on the apps button in aboutHome.xhtml
if (getBoolPref("browser.aboutHome.apps", false))
@ -2517,16 +2536,14 @@ let BrowserOnClick = {
else if (ownerDoc.documentURI.startsWith("about:neterror")) {
this.onAboutNetError(originalTarget, ownerDoc);
}
else if (/^about:home$/i.test(ownerDoc.documentURI)) {
else if (ownerDoc.documentURI.toLowerCase() == "about:home") {
this.onAboutHome(originalTarget, ownerDoc);
}
},
onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
let elmId = aTargetElm.getAttribute("id");
let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
getService(Ci.nsITelemetry).
getHistogramById("SECURITY_UI");
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
switch (elmId) {
case "exceptionDialogButton":
@ -2571,9 +2588,7 @@ let BrowserOnClick = {
onAboutBlocked: function BrowserOnClick_onAboutBlocked(aTargetElm, aOwnerDoc) {
let elmId = aTargetElm.getAttribute("id");
let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
getService(Ci.nsITelemetry).
getHistogramById("SECURITY_UI");
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
// The event came from a button on a malware/phishing block page
// First check whether it's malware or phishing, so that we can
@ -2743,8 +2758,7 @@ let BrowserOnClick = {
*/
function getMeOutOfHere() {
// Get the start page from the *default* pref branch, not the user's
var prefs = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService).getDefaultBranch(null);
var prefs = Services.prefs.getDefaultBranch(null);
var url = BROWSER_NEW_TAB_URL;
try {
url = prefs.getComplexValue("browser.startup.homepage",
@ -3134,8 +3148,7 @@ const DOMLinkHandler = {
].some(function (re) re.test(targetDoc.documentURI));
if (!isAllowedPage || !uri.schemeIs("chrome")) {
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].
getService(Ci.nsIScriptSecurityManager);
var ssm = Services.scriptSecurityManager;
try {
ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
@ -3768,7 +3781,8 @@ function updateEditUIVisibility()
*/
function mimeTypeIsTextBased(aMimeType)
{
return /^text\/|\+xml$/.test(aMimeType) ||
return aMimeType.startsWith("text/") ||
aMimeType.endsWith("+xml") ||
aMimeType == "application/x-javascript" ||
aMimeType == "application/javascript" ||
aMimeType == "application/xml" ||
@ -3785,7 +3799,7 @@ var XULBrowserWindow = {
startTime: 0,
statusText: "",
isBusy: false,
inContentWhitelist: ["about:addons", "about:permissions",
inContentWhitelist: ["about:addons", "about:downloads", "about:permissions",
"about:sync-progress", "about:preferences"],
QueryInterface: function (aIID) {
@ -4066,7 +4080,7 @@ var XULBrowserWindow = {
let newSpec = location;
let newIndexOfHash = newSpec.indexOf("#");
if (newIndexOfHash != -1)
newSpec = newSpec.substr(0, newSpec.indexOf("#"));
newSpec = newSpec.substr(0, newIndexOfHash);
if (newSpec != oldSpec) {
// Remove all the notifications, except for those which want to
// persist across the first location change.
@ -5083,8 +5097,8 @@ var gHomeButton = {
// use this if we can't find the pref
if (!url) {
var SBS = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
var configBundle = SBS.createBundle("chrome://branding/locale/browserconfig.properties");
var configBundle = Services.strings
.createBundle("chrome://branding/locale/browserconfig.properties");
url = configBundle.GetStringFromName(this.prefDomain);
}
@ -5144,9 +5158,7 @@ function getBrowserSelection(aCharLen) {
selection = RegExp.lastMatch;
}
selection = selection.replace(/^\s+/, "")
.replace(/\s+$/, "")
.replace(/\s+/g, " ");
selection = selection.trim().replace(/\s+/g, " ");
if (selection.length > charLen)
selection = selection.substr(0, charLen);
@ -5278,8 +5290,8 @@ function contentAreaClick(event, isPanelClick)
if (isPanelClick && mainTarget) {
// javascript and data links should be executed in the current browser.
if (linkNode.getAttribute("onclick") ||
href.substr(0, 11) === "javascript:" ||
href.substr(0, 5) === "data:")
href.startsWith("javascript:") ||
href.startsWith("data:"))
return;
try {
@ -6644,16 +6656,12 @@ var gIdentityHandler = {
* Return the eTLD+1 version of the current hostname
*/
getEffectiveHost : function() {
// Cache the eTLDService if this is our first time through
if (!this._eTLDService)
this._eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"]
.getService(Ci.nsIEffectiveTLDService);
if (!this._IDNService)
this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
.getService(Ci.nsIIDNService);
try {
let baseDomain =
this._eTLDService.getBaseDomainFromHost(this._lastLocation.hostname);
Services.eTLD.getBaseDomainFromHost(this._lastLocation.hostname);
return this._IDNService.convertToDisplayIDN(baseDomain, {});
} catch (e) {
// If something goes wrong (e.g. hostname is an IP address) just fail back
@ -7000,8 +7008,7 @@ let gPrivateBrowsingUI = {
}
catch (ex) { }
var bundleService = Cc["@mozilla.org/intl/stringbundle;1"].
getService(Ci.nsIStringBundleService);
var bundleService = Services.strings;
var pbBundle = bundleService.createBundle("chrome://browser/locale/browser.properties");
var brandBundle = bundleService.createBundle("chrome://branding/locale/brand.properties");
@ -7332,9 +7339,7 @@ function safeModeRestart()
buttonFlags, restartText, null, null,
null, {});
if (rv == 0) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
getService(Ci.nsIAppStartup);
appStartup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
}
}
@ -7401,9 +7406,7 @@ XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() {
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
#ifdef XP_WIN
// Only show resizers on Windows 2000 and XP
let sysInfo = Components.classes["@mozilla.org/system-info;1"]
.getService(Components.interfaces.nsIPropertyBag2);
return parseFloat(sysInfo.getProperty("version")) < 6;
return parseFloat(Services.sysinfo.getProperty("version")) < 6;
#else
return false;
#endif
@ -7473,7 +7476,7 @@ var MousePosTracker = {
};
function focusNextFrame(event) {
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
let fm = Services.focus;
let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
let element = fm.moveFocus(window, null, dir, fm.FLAG_BYKEY);
if (element.ownerDocument == document)

View File

@ -464,6 +464,13 @@
</menulist>
</popupnotificationcontent>
</popupnotification>
<popupnotification id="geolocation-notification" hidden="true">
<popupnotificationcontent orient="vertical" align="start">
<separator class="thin"/>
<label id="geolocation-learnmore-link" class="text-link"/>
</popupnotificationcontent>
</popupnotification>
</popupset>
#ifdef CAN_DRAW_IN_TITLEBAR
@ -521,7 +528,7 @@
toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
fullscreentoolbar="true" mode="icons" customizable="true"
iconsize="large"
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
context="toolbar-context-menu">
<toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
@ -578,6 +585,8 @@
<image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="blocked-plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
</box>
<!-- Use onclick instead of normal popup= syntax since the popup
code fires onmousedown, and hence eats our favicon drag events.
@ -653,6 +662,16 @@
<searchbar id="searchbar" flex="1"/>
</toolbaritem>
<toolbarbutton id="webrtc-status-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
type="menu"
hidden="true"
orient="horizontal">
<menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
onpopuphiding="WebrtcIndicator.clearPopup(this);"
oncommand="WebrtcIndicator.menuCommand(event.target);"/>
</toolbarbutton>
<toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class" removable="true"
label="&homeButton.label;"
@ -1050,6 +1069,8 @@
</toolbarpalette>
</toolbox>
<hbox id="fullscr-toggler" collapsed="true"/>
<hbox flex="1" id="browser">
<vbox id="browser-border-start" hidden="true" layer="true"/>
<vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">

View File

@ -851,11 +851,11 @@
var oldTab = this.mCurrentTab;
// Preview mode should not reset the owner
if (!this._previewMode && oldTab != this.selectedTab)
if (!this._previewMode && !oldTab.selected)
oldTab.owner = null;
if (this._lastRelatedTab) {
if (this._lastRelatedTab != this.selectedTab)
if (!this._lastRelatedTab.selected)
this._lastRelatedTab.owner = null;
this._lastRelatedTab = null;
}
@ -876,7 +876,7 @@
newBrowser.docShellIsActive =
(window.windowState != window.STATE_MINIMIZED);
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.selectedTab;
this.mCurrentTab = this.tabContainer.selectedItem;
this.showTab(this.mCurrentTab);
var backForwardContainer = document.getElementById("unified-back-forward-button");
@ -957,8 +957,7 @@
true, false);
}
if (this.mCurrentTab.selected)
this._setCloseKeyState(!this.mCurrentTab.pinned);
this._setCloseKeyState(!this.mCurrentTab.pinned);
// TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code
// that might rely upon the other changes suppressed.
@ -1671,7 +1670,7 @@
const filter = this.mTabFilters[aTab._tPos];
#ifdef MOZ_E10S_COMPAT
// Bug 666801 - WebProgress support for e10s
#else
#else
browser.webProgress.removeProgressListener(filter);
#endif
filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
@ -1825,7 +1824,7 @@
<parameter name="aTab"/>
<body>
<![CDATA[
if (this.mCurrentTab != aTab)
if (!aTab.selected)
return;
if (aTab.owner &&
@ -1875,7 +1874,7 @@
// The tab is definitely not loading.
aNewTab.removeAttribute("busy");
if (aNewTab == this.selectedTab) {
if (aNewTab.selected) {
this.mIsBusy = false;
}
@ -1884,7 +1883,7 @@
// Update the new tab's title.
this.setTabTitle(aNewTab);
if (aNewTab == this.selectedTab) {
if (aNewTab.selected) {
this.updateCurrentBrowser(true);
}
]]>
@ -1923,7 +1922,7 @@
if (isBusy) {
aOurTab.setAttribute("busy", "true");
this._tabAttrModified(aOurTab);
if (aOurTab == this.selectedTab)
if (aOurTab.selected)
this.mIsBusy = true;
}
@ -1939,7 +1938,7 @@
// If the tab was already selected (this happpens in the scenario
// of replaceTabWithWindow), notify onLocationChange, etc.
if (aOurTab == this.selectedTab)
if (aOurTab.selected)
this.updateCurrentBrowser(true);
]]>
</body>
@ -2136,7 +2135,7 @@
<property name="selectedTab">
<getter>
return this.mTabBox.selectedTab;
return this.mCurrentTab;
</getter>
<setter>
<![CDATA[
@ -2203,6 +2202,8 @@
this.mTabFilters.splice(aIndex, 0, this.mTabFilters.splice(aTab._tPos, 1)[0]);
this.mTabListeners.splice(aIndex, 0, this.mTabListeners.splice(aTab._tPos, 1)[0]);
let wasFocused = (document.activeElement == this.mCurrentTab);
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
this.mCurrentTab._selected = false;
@ -2219,6 +2220,10 @@
this.tabs[i]._selected = false;
}
this.mCurrentTab._selected = true;
if (wasFocused)
this.mCurrentTab.focus();
this.tabContainer._handleTabSelect(false);
if (aTab.pinned)
@ -2234,11 +2239,12 @@
<method name="moveTabForward">
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos < this.browsers.length - 1) {
this.moveTabTo(this.mCurrentTab, tabPos + 1);
this.mCurrentTab.focus();
}
let nextTab = this.mCurrentTab.nextSibling;
while (nextTab && nextTab.hidden)
nextTab = nextTab.nextSibling;
if (nextTab)
this.moveTabTo(this.mCurrentTab, nextTab._tPos);
else if (this.arrowKeysShouldWrap)
this.moveTabToStart();
]]>
@ -2248,11 +2254,12 @@
<method name="moveTabBackward">
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos > 0) {
this.moveTabTo(this.mCurrentTab, tabPos - 1);
this.mCurrentTab.focus();
}
let previousTab = this.mCurrentTab.previousSibling;
while (previousTab && previousTab.hidden)
previousTab = previousTab.previousSibling;
if (previousTab)
this.moveTabTo(this.mCurrentTab, previousTab._tPos);
else if (this.arrowKeysShouldWrap)
this.moveTabToEnd();
]]>
@ -2263,10 +2270,8 @@
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos > 0) {
if (tabPos > 0)
this.moveTabTo(this.mCurrentTab, 0);
this.mCurrentTab.focus();
}
]]>
</body>
</method>
@ -2275,11 +2280,8 @@
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos < this.browsers.length - 1) {
this.moveTabTo(this.mCurrentTab,
this.browsers.length - 1);
this.mCurrentTab.focus();
}
if (tabPos < this.browsers.length - 1)
this.moveTabTo(this.mCurrentTab, this.browsers.length - 1);
]]>
</body>
</method>

View File

@ -292,6 +292,7 @@ _BROWSER_FILES = \
browser_bug676619.js \
download_page.html \
browser_URLBarSetURI.js \
browser_bookmark_titles.js \
$(NULL)
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))

View File

@ -0,0 +1,75 @@
/* 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 file is tests for the default titles that new bookmarks get.
let tests = [
['http://example.com/browser/browser/base/content/test/dummy_page.html',
'Dummy test page'],
['data:text/html;charset=utf-8,<title>test data: url</title>',
'test data: url'],
['http://unregistered-domain.example',
'http://unregistered-domain.example/'],
['https://untrusted.example.com/somepage.html',
'https://untrusted.example.com/somepage.html']
];
function generatorTest() {
gBrowser.selectedTab = gBrowser.addTab();
let browser = gBrowser.selectedBrowser;
browser.addEventListener("DOMContentLoaded", nextStep, true);
registerCleanupFunction(function () {
browser.removeEventListener("DOMContentLoaded", nextStep, true);
gBrowser.removeCurrentTab();
});
yield; // Wait for the new tab to load.
// Test that a bookmark of each URI gets the corresponding default title.
for (let i = 0; i < tests.length; ++i) {
let [uri, title] = tests[i];
content.location = uri;
yield;
checkBookmark(uri, title);
}
// Network failure test: now that dummy_page.html is in history, bookmarking
// it should give the last known page title as the default bookmark title.
// Simulate a network outage with offline mode. (Localhost is still
// accessible in offline mode, so disable the test proxy as well.)
BrowserOffline.toggleOfflineStatus();
let proxy = Services.prefs.getIntPref('network.proxy.type');
Services.prefs.setIntPref('network.proxy.type', 0);
registerCleanupFunction(function () {
BrowserOffline.toggleOfflineStatus();
Services.prefs.setIntPref('network.proxy.type', proxy);
});
// LOAD_FLAGS_BYPASS_CACHE isn't good enough. So clear the cache.
Services.cache.evictEntries(Services.cache.STORE_ANYWHERE);
let [uri, title] = tests[0];
content.location = uri;
yield;
// The offline mode test is only good if the page failed to load.
is(content.document.documentURI.substring(0, 14), 'about:neterror',
"Offline mode successfully simulated network outage.");
checkBookmark(uri, title);
}
// Bookmark the current page and confirm that the new bookmark has the expected
// title. (Then delete the bookmark.)
function checkBookmark(uri, expected_title) {
PlacesCommandHook.bookmarkCurrentPage(false);
let id = PlacesUtils.getMostRecentBookmarkForURI(PlacesUtils._uri(uri));
let title = PlacesUtils.bookmarks.getItemTitle(id);
is(title, expected_title, "Bookmark got a good default title.");
PlacesUtils.bookmarks.removeItem(id);
}

View File

@ -82,7 +82,7 @@ var gWebProgressListener = {
}
ok(gNewTab, "There is a new tab.");
ok(isRedirectedURI(aLocation),
ok(isRedirectedURI(aLocation),
"onLocationChange catches only redirected URI.");
if (aLocation.ref == "BG") {
@ -97,7 +97,7 @@ var gWebProgressListener = {
ok(false, "This URI hash is not expected:" + aLocation.ref);
}
let isSelectedTab = (gNewTab == gBrowser.selectedTab);
let isSelectedTab = gNewTab.selected;
setTimeout(delayed, 0, isSelectedTab);
}
};

View File

@ -59,7 +59,7 @@ function test() {
pressCtrlTab(true);
pressCtrlTab(true);
releaseCtrl();
ok(gBrowser.selectedTab == selectedTab,
ok(selectedTab.selected,
"Ctrl+Tab*2 -> Ctrl+W -> Ctrl+Shift+Tab*2 keeps the selected tab");
}
gBrowser.removeTab(gBrowser.tabContainer.lastChild);

View File

@ -707,13 +707,12 @@ function checkPopup(popup, notificationObj) {
is(notification.getAttribute("buttonlabel"), notificationObj.mainAction.label, "main action label matches");
is(notification.getAttribute("buttonaccesskey"), notificationObj.mainAction.accessKey, "main action accesskey matches");
}
let actualSecondaryActions = notification.childNodes;
let actualSecondaryActions = Array.filter(notification.childNodes,
function (child) child.nodeName == "menuitem");
let secondaryActions = notificationObj.secondaryActions || [];
let actualSecondaryActionsCount = actualSecondaryActions.length;
if (secondaryActions.length) {
let lastChild = actualSecondaryActions.item(actualSecondaryActions.length - 1);
is(lastChild.tagName, "menuseparator", "menuseparator exists");
actualSecondaryActionsCount--;
is(notification.lastChild.tagName, "menuseparator", "menuseparator exists");
}
is(actualSecondaryActionsCount, secondaryActions.length, actualSecondaryActions.length + " secondary actions");
secondaryActions.forEach(function (a, i) {

View File

@ -903,50 +903,6 @@
</implementation>
</binding>
<binding id="geolocation-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
<content align="start">
<xul:image class="popup-notification-icon"
xbl:inherits="popupid,src=icon"/>
<xul:vbox flex="1">
<xul:description class="popup-notification-description"
xbl:inherits="xbl:text=label"/>
<xul:spacer flex="1"/>
<xul:hbox class="popup-notification-button-container"
pack="end" align="center">
<xul:label anonid="learnmore" class="text-link geolocation-text-link"/>
<xul:spacer flex="1"/>
<xul:button anonid="button"
type="menu-button"
class="popup-notification-menubutton"
xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
<xul:menupopup anonid="menupopup"
xbl:inherits="oncommand=menucommand">
<children/>
<xul:menuitem class="menuitem-iconic popup-notification-closeitem"
label="&closeNotificationItem.label;"
xbl:inherits="oncommand=closeitemcommand"/>
</xul:menupopup>
</xul:button>
</xul:hbox>
</xul:vbox>
<xul:vbox pack="start">
<xul:toolbarbutton anonid="closebutton"
class="messageCloseButton popup-notification-closebutton tabbable"
xbl:inherits="oncommand=closebuttoncommand"
tooltiptext="&closeNotification.tooltip;"/>
</xul:vbox>
</content>
<implementation>
<constructor><![CDATA[
let link = document.getAnonymousElementByAttribute(this, "anonid", "learnmore");
link.value = gNavigatorBundle.getString("geolocation.learnMore");
let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
link.href = formatter.formatURLPref("browser.geolocation.warning.infoURL");
]]></constructor>
</implementation>
</binding>
<binding id="addon-progress-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
<content align="start">
<xul:image class="popup-notification-icon"

View File

@ -80,6 +80,8 @@ static RedirEntry kRedirMap[] = {
nsIAboutModule::ALLOW_SCRIPT },
{ "preferences", "chrome://browser/content/preferences/in-content/preferences.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul",
nsIAboutModule::ALLOW_SCRIPT },
};
static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);

View File

@ -30,7 +30,6 @@ endif
LOCAL_INCLUDES = \
-I$(srcdir)/../shell/src \
-I$(srcdir)/../feeds/src \
-I$(srcdir)/../privatebrowsing/src \
-I$(srcdir)/../about \
-I$(srcdir)/../dirprovider \
$(NULL)
@ -41,11 +40,15 @@ endif
SHARED_LIBRARY_LIBS = \
../feeds/src/$(LIB_PREFIX)browser_feeds_s.$(LIB_SUFFIX) \
../privatebrowsing/src/$(LIB_PREFIX)privatebrowsing_s.$(LIB_SUFFIX) \
../about/$(LIB_PREFIX)browserabout_s.$(LIB_SUFFIX) \
../dirprovider/$(LIB_PREFIX)browserdir_s.$(LIB_SUFFIX) \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
LOCAL_INCLUDES += -I$(srcdir)/../privatebrowsing/src
SHARED_LIBRARY_LIBS += ../privatebrowsing/src/$(LIB_PREFIX)privatebrowsing_s.$(LIB_SUFFIX)
endif
ifneq (,$(filter windows cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
SHARED_LIBRARY_LIBS += ../shell/src/$(LIB_PREFIX)shellservice_s.$(LIB_SUFFIX)
endif

View File

@ -25,7 +25,9 @@
#include "AboutRedirector.h"
#include "nsIAboutModule.h"
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
#include "nsPrivateBrowsingServiceWrapper.h"
#endif
#include "nsNetCID.h"
using namespace mozilla::browser;
@ -47,7 +49,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrivateBrowsingServiceWrapper, Init)
#endif
NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
#if defined(XP_WIN)
@ -62,7 +66,9 @@ NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
#elif defined(XP_MACOSX)
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
#endif
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
NS_DEFINE_NAMED_CID(NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID);
#endif
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
{ &kNS_BROWSERDIRECTORYPROVIDER_CID, false, NULL, DirectoryProviderConstructor },
@ -78,7 +84,9 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
#elif defined(XP_MACOSX)
{ &kNS_SHELLSERVICE_CID, false, NULL, nsMacShellServiceConstructor },
#endif
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
{ &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID, false, NULL, nsPrivateBrowsingServiceWrapperConstructor },
#endif
{ NULL }
};
@ -108,12 +116,15 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#if defined(XP_WIN)
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
#elif defined(XP_MACOSX)
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#endif
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
{ NS_PRIVATE_BROWSING_SERVICE_CONTRACTID, &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID },
#endif
{ NULL }
};

View File

@ -21,9 +21,10 @@ richlistitem.download {
[state="9"]) /* Blocked (policy) */)
.downloadRemoveFromHistoryMenuItem,
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
[state="5"], /* Starting (queued) */
[state="0"], /* Downloading */
[state="4"]) /* Paused */)
[state="1"], /* Finished */
[state="4"], /* Paused */
[state="5"]) /* Starting (queued) */)
.downloadShowMenuItem,
.download-state[state="7"] .downloadCommandsSeparator

View File

@ -96,7 +96,7 @@ DownloadElementShell.prototype = {
}
else if (this._placesNode) {
this._wasInProgress = false;
this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED;
this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED;
}
this._updateStatusUI();
@ -115,7 +115,7 @@ DownloadElementShell.prototype = {
this._placesNode = aNode;
if (!this._dataItem && this._placesNode) {
this._wasInProgress = false;
this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED;
this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED;
this._updateStatusUI();
}
}
@ -216,42 +216,53 @@ DownloadElementShell.prototype = {
// The target's file size in bytes. If there's no target file, or If we
// cannot determine its size, 0 is returned.
get _fileSize() {
if (!this._file || !this._file.exists())
return 0;
try {
return this._file.fileSize;
}
catch(ex) {
Cu.reportError(ex);
return 0;
if (!("__fileSize" in this)) {
if (!this._file || !this._file.exists())
this.__fileSize = 0;
try {
this.__fileSize = this._file.fileSize;
}
catch(ex) {
Cu.reportError(ex);
this.__fileSize = 0;
}
}
return this.__fileSize;
},
/**
* Get the state of the download
* @param [optional] aForceUpdate
* Whether to force update the cached download state. Default: false.
*/
// The download state (see nsIDownloadManager).
get _state() {
if (this._dataItem)
return this._dataItem.state;
let state = -1;
try {
return this._getAnnotation(DOWNLOAD_STATE_ANNO);
}
catch (ex) {
// The state annotation didn't exist in past releases.
if (!this._file) {
state = nsIDM.DOWNLOAD_FAILED;
}
else if (this._file.exists()) {
state = this._fileSize > 0 ?
nsIDM.DOWNLOAD_FINISHED : nsIDM.DOWNLOAD_FAILED;
getDownloadState: function DES_getDownloadState(aForceUpdate = false) {
if (aForceUpdate || !("_state" in this)) {
if (this._dataItem) {
this._state = this._dataItem.state;
}
else {
// XXXmano I'm not sure if this right. We should probably show no
// status text at all in this case.
state = nsIDM.DOWNLOAD_CANCELED;
try {
this._state = this._getAnnotation(DOWNLOAD_STATE_ANNO);
}
catch (ex) {
// The state annotation didn't exist in past releases.
if (!this._file) {
this._state = nsIDM.DOWNLOAD_FAILED;
}
else if (this._file.exists()) {
this._state = this._fileSize > 0 ?
nsIDM.DOWNLOAD_FINISHED : nsIDM.DOWNLOAD_FAILED;
}
else {
// XXXmano I'm not sure if this right. We should probably show no
// status text at all in this case.
this._state = nsIDM.DOWNLOAD_CANCELED;
}
}
}
}
return state;
return this._state;
},
// The status text for the download
@ -292,7 +303,7 @@ DownloadElementShell.prototype = {
return s.statusSeparator(fullHost, fullDate);
}
switch (this._state) {
switch (this.getDownloadState()) {
case nsIDM.DOWNLOAD_FAILED:
return s.stateFailed;
case nsIDM.DOWNLOAD_CANCELED:
@ -331,7 +342,7 @@ DownloadElementShell.prototype = {
// appropriate buttons and context menu items), the status text label,
// and the progress meter.
_updateDownloadStatusUI: function DES__updateDownloadStatusUI() {
this._element.setAttribute("state", this._state);
this._element.setAttribute("state", this.getDownloadState(true));
this._element.setAttribute("status", this._statusText);
// For past-downloads, we're done. For session-downloads, we may also need
@ -429,7 +440,7 @@ DownloadElementShell.prototype = {
case "downloadsCmd_open": {
return this._file.exists() &&
((this._dataItem && this._dataItem.openable) ||
(this._state == nsIDM.DOWNLOAD_FINISHED));
(this.getDownloadState() == nsIDM.DOWNLOAD_FINISHED));
}
case "downloadsCmd_show": {
return this._getTargetFileOrPartFileIfExists() != null;
@ -547,7 +558,7 @@ DownloadElementShell.prototype = {
}
return "";
}
let command = getDefaultCommandForState(this._state);
let command = getDefaultCommandForState(this.getDownloadState());
if (this.isCommandEnabled(command))
this.doCommand(command);
}
@ -589,6 +600,7 @@ function DownloadsPlacesView(aRichListBox) {
// Make sure to unregister the view if the window is closed.
window.addEventListener("unload", function() {
this._richlistbox.controllers.removeController(this);
downloadsData.removeView(this);
this.result = null;
}.bind(this), true);
@ -759,6 +771,7 @@ DownloadsPlacesView.prototype = {
// sibling first, if any.
if (aElement.nextSibling &&
this._richlistbox.selectedItems &&
this._richlistbox.selectedItems.length > 0 &&
this._richlistbox.selectedItems[0] == aElement) {
this._richlistbox.selectItem(aElement.nextSibling);
}
@ -871,8 +884,8 @@ DownloadsPlacesView.prototype = {
let placesNodes = [];
let selectedElements = this._richlistbox.selectedItems;
for (let elt of selectedElements) {
if (elt.placesNode)
placesNodes.push(elt.placesNode);
if (elt._shell.placesNode)
placesNodes.push(elt._shell.placesNode);
}
return placesNodes;
},
@ -1079,7 +1092,7 @@ DownloadsPlacesView.prototype = {
// Set the state attribute so that only the appropriate items are displayed.
let contextMenu = document.getElementById("downloadsContextMenu");
contextMenu.setAttribute("state", element._shell._state);
contextMenu.setAttribute("state", element._shell.getDownloadState());
return true;
},

View File

@ -2,9 +2,14 @@
* 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/. */
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
let ContentAreaDownloadsView = {
init: function CADV_init() {
let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
view.place = "place:transition=7&sort=4";
// Do not display the Places downloads in private windows
if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
view.place = "place:transition=7&sort=4";
}
}
};

View File

@ -5,12 +5,20 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<?xml-stylesheet href="chrome://global/skin/"?>
<?xml-stylesheet href="chrome://browser/skin/downloads/contentAreaDownloadsView.css"?>
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<!DOCTYPE window [
<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
%downloadsDTD;
]>
<window id="contentAreaDownloadsView"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&downloads.title;"
onload="ContentAreaDownloadsView.init();">
<script type="application/javascript"

View File

@ -57,9 +57,10 @@ richlistitem[type="download"]:not([selected]) button {
.downloadRemoveFromHistoryMenuItem,
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
[state="5"], /* Starting (queued) */
[state="0"], /* Downloading */
[state="4"]) /* Paused */)
[state="1"], /* Finished */
[state="4"], /* Paused */
[state="5"]) /* Starting (queued) */)
.downloadShowMenuItem,
.download-state[state="7"] .downloadCommandsSeparator

View File

@ -32,6 +32,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "gBrowserGlue",
"nsIBrowserGlue");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
////////////////////////////////////////////////////////////////////////////////
//// DownloadsUI
@ -107,50 +109,38 @@ DownloadsUI.prototype = {
},
/**
* Helper function that opens the right download manager UI. Either the
* new Downloads View in Places, or the toolkit download window if the
* Places Downloads View is not enabled.
* Helper function that opens the download manager UI.
*/
_showDownloadManagerUI:
function DUI_showDownloadManagerUI(aWindowContext, aID, aReason)
{
// First, determine if the Places Downloads view is preffed on.
let usePlacesView = false;
try {
usePlacesView =
Services.prefs.getBoolPref("browser.library.useNewDownloadsView");
} catch(e) {}
if (!usePlacesView) {
// If we got here, then the browser.library.useNewDownloadsView pref
// either didn't exist or was false, so just show the toolkit downloads
// manager.
this._toolkitUI.show(aWindowContext, aID, aReason);
return;
}
let organizer = Services.wm.getMostRecentWindow("Places:Organizer");
if (!organizer) {
let parentWindow = aWindowContext;
// If we weren't given a window context, try to find a browser window
// to use as our parent - and if that doesn't work, error out and give
// up.
// If we weren't given a window context, try to find a browser window
// to use as our parent - and if that doesn't work, error out and give up.
let parentWindow = aWindowContext;
if (!parentWindow) {
parentWindow = RecentWindow.getMostRecentBrowserWindow();
if (!parentWindow) {
parentWindow = RecentWindow.getMostRecentBrowserWindow();
if (!parentWindow) {
Components.utils
.reportError("Couldn't find a browser window to open " +
"the Places Downloads View from.");
return;
}
Components.utils.reportError(
"Couldn't find a browser window to open the Places Downloads View " +
"from.");
return;
}
parentWindow.openDialog("chrome://browser/content/places/places.xul",
"", "chrome,toolbar=yes,dialog=no,resizable",
"Downloads");
}
else {
organizer.PlacesOrganizer.selectLeftPaneQuery("Downloads");
organizer.focus();
// If window is private then show it in a tab.
if (PrivateBrowsingUtils.isWindowPrivate(parentWindow)) {
parentWindow.openUILinkIn("about:downloads", "tab");
return;
} else {
let organizer = Services.wm.getMostRecentWindow("Places:Organizer");
if (!organizer) {
parentWindow.openDialog("chrome://browser/content/places/places.xul",
"", "chrome,toolbar=yes,dialog=no,resizable",
"Downloads");
} else {
organizer.PlacesOrganizer.selectLeftPaneQuery("Downloads");
organizer.focus();
}
}
}
};

View File

@ -551,19 +551,21 @@ BrowserGlue.prototype = {
// browser.startup.page == 3 or browser.sessionstore.resume_session_once == true
// 3. browser.warnOnQuit == false
// 4. The browser is currently in Private Browsing mode
// 5. The browser will be restarted.
//
// Otherwise these are the conditions and the associated dialogs that will be shown:
// 1. aQuitType == "lastwindow" or "quit" and browser.showQuitWarning == true
// - The quit dialog will be shown
// 2. aQuitType == "restart" && browser.warnOnRestart == true
// - The restart dialog will be shown
// 3. aQuitType == "lastwindow" && browser.tabs.warnOnClose == true
// 2. aQuitType == "lastwindow" && browser.tabs.warnOnClose == true
// - The "closing multiple tabs" dialog will be shown
//
// aQuitType == "lastwindow" is overloaded. "lastwindow" is used to indicate
// "the last window is closing but we're not quitting (a non-browser window is open)"
// and also "we're quitting by closing the last window".
if (aQuitType == "restart")
return;
var windowcount = 0;
var pagecount = 0;
var browserEnum = Services.wm.getEnumerator("navigator:browser");
@ -586,12 +588,10 @@ BrowserGlue.prototype = {
if (!aQuitType)
aQuitType = "quit";
var showPrompt = false;
var mostRecentBrowserWindow;
// browser.warnOnQuit is a hidden global boolean to override all quit prompts
// browser.showQuitWarning specifically covers quitting
// browser.warnOnRestart specifically covers app-initiated restarts where we restart the app
// browser.tabs.warnOnClose is the global "warn when closing multiple tabs" pref
var sessionWillBeRestored = Services.prefs.getIntPref("browser.startup.page") == 3 ||
@ -601,19 +601,15 @@ BrowserGlue.prototype = {
// On last window close or quit && showQuitWarning, we want to show the
// quit warning.
if (aQuitType != "restart" && Services.prefs.getBoolPref("browser.showQuitWarning")) {
showPrompt = true;
}
else if (aQuitType == "restart" && Services.prefs.getBoolPref("browser.warnOnRestart")) {
showPrompt = true;
}
else if (aQuitType == "lastwindow") {
// If aQuitType is "lastwindow" and we aren't showing the quit warning,
// we should show the window closing warning instead. warnAboutClosing
// tabs checks browser.tabs.warnOnClose and returns if it's ok to close
// the window. It doesn't actually close the window.
mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
aCancelQuit.data = !mostRecentBrowserWindow.gBrowser.warnAboutClosingTabs(true);
if (!Services.prefs.getBoolPref("browser.showQuitWarning")) {
if (aQuitType == "lastwindow") {
// If aQuitType is "lastwindow" and we aren't showing the quit warning,
// we should show the window closing warning instead. warnAboutClosing
// tabs checks browser.tabs.warnOnClose and returns if it's ok to close
// the window. It doesn't actually close the window.
mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
aCancelQuit.data = !mostRecentBrowserWindow.gBrowser.warnAboutClosingTabs(true);
}
return;
}
@ -621,21 +617,15 @@ BrowserGlue.prototype = {
if (allWindowsPrivate)
return;
if (!showPrompt)
return;
var quitBundle = Services.strings.createBundle("chrome://browser/locale/quitDialog.properties");
var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
var appName = brandBundle.GetStringFromName("brandShortName");
var quitTitleString = (aQuitType == "restart" ? "restart" : "quit") + "DialogTitle";
var quitTitleString = "quitDialogTitle";
var quitDialogTitle = quitBundle.formatStringFromName(quitTitleString, [appName], 1);
var message;
if (aQuitType == "restart")
message = quitBundle.formatStringFromName("messageRestart",
[appName], 1);
else if (windowcount == 1)
if (windowcount == 1)
message = quitBundle.formatStringFromName("messageNoWindows",
[appName], 1);
else
@ -646,21 +636,15 @@ BrowserGlue.prototype = {
var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2 +
promptService.BUTTON_POS_0_DEFAULT;
var neverAsk = {value:false};
var button0Title, button2Title;
var button0Title = quitBundle.GetStringFromName("saveTitle");
var button1Title = quitBundle.GetStringFromName("cancelTitle");
var button2Title = quitBundle.GetStringFromName("quitTitle");
var neverAskText = quitBundle.GetStringFromName("neverAsk");
if (aQuitType == "restart")
button0Title = quitBundle.GetStringFromName("restartTitle");
else {
flags += promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2;
button0Title = quitBundle.GetStringFromName("saveTitle");
button2Title = quitBundle.GetStringFromName("quitTitle");
}
// This wouldn't have been set above since we shouldn't be here for
// aQuitType == "lastwindow"
mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
@ -682,12 +666,8 @@ BrowserGlue.prototype = {
case 0: // Save & Quit
this._saveSession = true;
if (neverAsk.value) {
if (aQuitType == "restart")
Services.prefs.setBoolPref("browser.warnOnRestart", false);
else {
// always save state when shutting down
Services.prefs.setIntPref("browser.startup.page", 3);
}
// always save state when shutting down
Services.prefs.setIntPref("browser.startup.page", 3);
}
break;
}
@ -930,13 +910,13 @@ BrowserGlue.prototype = {
*
* - The last accepted/refused policy (either by accepting the prompt or by
* manually flipping the telemetry preference) is already at version
* TELEMETRY_DISPLAY_REV.
* TELEMETRY_DISPLAY_REV or higher (to avoid the prompt in tests).
*/
var telemetryDisplayed;
try {
telemetryDisplayed = Services.prefs.getIntPref(PREF_TELEMETRY_DISPLAYED);
} catch(e) {}
if (telemetryDisplayed === TELEMETRY_DISPLAY_REV)
if (telemetryDisplayed >= TELEMETRY_DISPLAY_REV)
return;
#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
@ -945,7 +925,8 @@ BrowserGlue.prototype = {
*
* - Telemetry is disabled
* - Telemetry was explicitly refused through the UI
* - Opt-in telemetry was enabled and this is the first run with opt-out.
* - Opt-in telemetry was already enabled, don't notify the user until next
* policy update. (Do the check only at first run with opt-out builds)
*/
var telemetryEnabled = Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED);
@ -1791,6 +1772,10 @@ ContentPermissionPrompt.prototype = {
}
}
var link = chromeWin.document.getElementById("geolocation-learnmore-link");
link.value = browserBundle.GetStringFromName("geolocation.learnMore");
link.href = Services.urlFormatter.formatURLPref("browser.geolocation.warning.infoURL");
var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document);
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);

View File

@ -0,0 +1,29 @@
<!-- 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/. -->
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
<overlay id="downloadsViewOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"><![CDATA[
const DOWNLOADS_QUERY = "place:transition=" +
Components.interfaces.nsINavHistoryService.TRANSITION_DOWNLOAD +
"&sort=" +
Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
ContentArea.setContentViewForQueryString(DOWNLOADS_QUERY,
function() new DownloadsPlacesView(document.getElementById("downloadsRichListBox")),
{ showDetailsPane: false });
]]></script>
<window id="places">
<commandset id="downloadCommands"/>
<menupopup id="downloadsContextMenu"/>
</window>
<deck id="placesViewsDeck">
<richlistbox id="downloadsRichListBox"/>
</deck>
</overlay>

View File

@ -5,11 +5,6 @@
Components.utils.import("resource:///modules/MigrationUtils.jsm");
const DOWNLOADS_QUERY = "place:transition=" +
Components.interfaces.nsINavHistoryService.TRANSITION_DOWNLOAD +
"&sort=" +
Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
var PlacesOrganizer = {
_places: null,
@ -87,7 +82,7 @@ var PlacesOrganizer = {
// Select the first item in the content area view.
let view = ContentArea.currentView;
let root = view.result ? view.result.root : null;
if (root && root.containerOpen && root.childCount >= 0)
if (root && root.containerOpen && root.childCount > 0)
view.selectNode(root.getChild(0));
ContentArea.focus();
},
@ -279,6 +274,13 @@ var PlacesOrganizer = {
* Handle focus changes on the places list and the current content view.
*/
updateDetailsPane: function PO_updateDetailsPane() {
let detailsDeck = document.getElementById("detailsDeck");
let detailsPaneDisabled = detailsDeck.hidden =
!ContentArea.currentViewOptions.showDetailsPane;
if (detailsPaneDisabled) {
return;
}
let view = PlacesUIUtils.getViewForNode(document.activeElement);
if (view) {
let selectedNodes = view.selectedNode ?
@ -1246,35 +1248,60 @@ let gPrivateBrowsingListener = {
#endif
let ContentArea = {
_specialViews: new Map(),
init: function CA_init() {
this._deck = document.getElementById("placesViewsDeck");
this._specialViews = new Map();
ContentTree.init();
},
_shouldUseNewDownloadsView: function CA_shouldUseNewDownloadsView() {
try {
return Services.prefs.getBoolPref("browser.library.useNewDownloadsView");
}
catch(ex) { }
return false;
},
/**
* Gets the content view to be used for loading the given query.
* If a custom view was set by setContentViewForQueryString, that
* view would be returned, else the default tree view is returned
*
* @param aQueryString
* a query string
* @return the view to be used for loading aQueryString.
*/
getContentViewForQueryString:
function CA_getContentViewForQueryString(aQueryString) {
if (this._specialViews.has(aQueryString))
return this._specialViews.get(aQueryString);
if (aQueryString == DOWNLOADS_QUERY && this._shouldUseNewDownloadsView()) {
let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
this.setContentViewForQueryString(aQueryString, view);
return view;
try {
if (this._specialViews.has(aQueryString)) {
let { view, options } = this._specialViews.get(aQueryString);
if (typeof view == "function") {
view = view();
this._specialViews.set(aQueryString, { view: view, options: options });
}
return view;
}
}
catch(ex) {
Cu.reportError(ex);
}
return ContentTree.view;
},
/**
* Sets a custom view to be used rather than the default places tree
* whenever the given query is selected in the left pane.
* @param aQueryString
* a query string
* @param aView
* Either the custom view or a function that will return the view
* the first (and only) time it's called.
* @param [optional] aOptions
* Object defining special options for the view.
* @see ContentTree.viewOptions for supported options and default values.
*/
setContentViewForQueryString:
function CA_setContentViewForQueryString(aQueryString, aView) {
this._specialViews.set(aQueryString, aView);
function CA_setContentViewForQueryString(aQueryString, aView, aOptions) {
if (!aQueryString ||
typeof aView != "object" && typeof aView != "function")
throw new Error("Invalid arguments");
this._specialViews.set(aQueryString, { view: aView,
options: aOptions || new Object() });
},
get currentView() PlacesUIUtils.getViewForNode(this._deck.selectedPanel),
@ -1291,6 +1318,23 @@ let ContentArea = {
return aQueryString;
},
/**
* Options for the current view.
*
* @see ContentTree.viewOptions for supported options and default values.
*/
get currentViewOptions() {
// Use ContentTree options as default.
let viewOptions = ContentTree.viewOptions;
if (this._specialViews.has(this.currentPlace)) {
let { view, options } = this._specialViews.get(this.currentPlace);
for (let option in options) {
viewOptions[option] = options[option];
}
}
return viewOptions;
},
focus: function() {
this._deck.selectedPanel.focus();
}
@ -1303,6 +1347,8 @@ let ContentTree = {
get view() this._view,
get viewOptions() Object.seal({ showDetailsPane: true }),
openSelectedNode: function CT_openSelectedNode(aEvent) {
let view = this.view;
PlacesUIUtils.openNodeWithEvent(view.selectedNode, aEvent, view);

View File

@ -12,7 +12,6 @@
<?xml-stylesheet href="chrome://browser/skin/places/organizer.css"?>
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
#ifdef XP_MACOSX
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
@ -405,7 +404,6 @@
</treecols>
<treechildren flex="1"/>
</tree>
<richlistbox id="downloadsRichListBox"/>
</deck>
<deck id="detailsDeck" style="height: 11em;">
<vbox id="itemsCountBox" align="center">
@ -440,7 +438,4 @@
</deck>
</vbox>
</hbox>
<commandset id="downloadCommands"/>
<menupopup id="downloadsContextMenu"/>
</window>

View File

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
% overlay chrome://browser/content/places/places.xul chrome://browser/content/places/downloadsViewOverlay.xul
# Provide another URI for the bookmarkProperties dialog so we can persist the
# attributes separately
content/browser/places/bookmarkProperties2.xul (content/bookmarkProperties.xul)
@ -30,3 +31,4 @@ browser.jar:
content/browser/places/moveBookmarks.js (content/moveBookmarks.js)
content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul)
content/browser/places/editBookmarkOverlay.js (content/editBookmarkOverlay.js)
content/browser/places/downloadsViewOverlay.xul (content/downloadsViewOverlay.xul)

View File

@ -15,42 +15,56 @@ let now = Date.now();
function test() {
waitForExplicitFinish();
function onLibraryReady(win) {
let onLibraryReady = function(win) {
// Add visits to compare contents with.
fastAddVisit("http://mozilla.com",
PlacesUtils.history.TRANSITION_TYPED);
fastAddVisit("http://google.com",
PlacesUtils.history.TRANSITION_DOWNLOAD);
fastAddVisit("http://en.wikipedia.org",
PlacesUtils.history.TRANSITION_TYPED);
fastAddVisit("http://ubuntu.org",
PlacesUtils.history.TRANSITION_DOWNLOAD);
let places = [
{ uri: NetUtil.newURI("http://mozilla.com"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_TYPED) ]
},
{ uri: NetUtil.newURI("http://google.com"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_DOWNLOAD) ]
},
{ uri: NetUtil.newURI("http://en.wikipedia.org"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_TYPED) ]
},
{ uri: NetUtil.newURI("http://ubuntu.org"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_DOWNLOAD) ]
},
]
PlacesUtils.asyncHistory.updatePlaces(places, {
handleResult: function () {},
handleError: function () {
ok(false, "gHistory.updatePlaces() failed");
},
handleCompletion: function () {
// Make sure Downloads is present.
isnot(win.PlacesOrganizer._places.selectedNode, null,
"Downloads is present and selected");
// Make sure Downloads is present.
isnot(win.PlacesOrganizer._places.selectedNode, null,
"Downloads is present and selected");
// Make sure content in right pane exists.
let tree = win.document.getElementById("placeContent");
isnot(tree, null, "placeContent tree exists");
// Check results.
let contentRoot = win.ContentArea.currentView.result.root;
let len = contentRoot.childCount;
const TEST_URIS = ["http://ubuntu.org/", "http://google.com/"];
for (let i = 0; i < len; i++) {
is(contentRoot.getChild(i).uri, TEST_URIS[i],
"Comparing downloads shown at index " + i);
}
// Check results.
var contentRoot = tree.result.root;
var len = contentRoot.childCount;
var testUris = ["http://ubuntu.org/", "http://google.com/"];
for (var i = 0; i < len; i++) {
is(contentRoot.getChild(i).uri, testUris[i],
"Comparing downloads shown at index " + i);
}
win.close();
waitForClearHistory(finish);
win.close();
waitForClearHistory(finish);
}
})
}
openLibrary(onLibraryReady, "Downloads");
}
function fastAddVisit(uri, transition) {
PlacesUtils.history.addVisit(PlacesUtils._uri(uri), now++ * 1000,
null, transition, false, 0);
function VisitInfo(aTransitionType)
{
this.transitionType =
aTransitionType === undefined ?
PlacesUtils.history.TRANSITION_LINK : aTransitionType;
this.visitDate = now++ * 1000;
}
VisitInfo.prototype = {}

View File

@ -11,7 +11,7 @@ browser.jar:
* content/browser/preferences/in-content/tabs.xul
* content/browser/preferences/in-content/tabs.js
content/browser/preferences/in-content/privacy.xul
content/browser/preferences/in-content/privacy.js
* content/browser/preferences/in-content/privacy.js
* content/browser/preferences/in-content/advanced.xul
* content/browser/preferences/in-content/advanced.js
content/browser/preferences/in-content/applications.xul

View File

@ -2,6 +2,9 @@
* 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/. */
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
var gMainPane = {
_pane: null,
@ -18,12 +21,25 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded", null);
},
setupDownloadsWindowOptions: function ()
{
let showWhenDownloading = document.getElementById("showWhenDownloading");
let closeWhenDone = document.getElementById("closeWhenDone");
// These radio buttons should be hidden when the Downloads Panel is enabled.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*

View File

@ -9,6 +9,11 @@ var gPrivacyPane = {
*/
_autoStartPrivateBrowsing: false,
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart: true,
/**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
@ -127,7 +132,8 @@ var gPrivacyPane = {
let pref = document.getElementById("browser.privatebrowsing.autostart");
switch (document.getElementById("historyMode").value) {
case "remember":
pref.value = false;
if (pref.value)
pref.value = false;
// select the remember history option if needed
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
@ -146,7 +152,8 @@ var gPrivacyPane = {
document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false;
break;
case "dontremember":
pref.value = true;
if (!pref.value)
pref.value = true;
break;
}
},
@ -219,19 +226,65 @@ var gPrivacyPane = {
observe: function PPP_observe(aSubject, aTopic, aData)
{
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
if (!gPrivacyPane._shouldPromptForRestart) {
// We're performing a revert. Just let it happen.
gPrivacyPane._shouldPromptForRestart = true;
return;
}
const Cc = Components.classes, Ci = Components.interfaces;
let pref = document.getElementById("browser.privatebrowsing.autostart");
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
let bundle = document.getElementById("bundlePreferences");
let msg = bundle.getFormattedString(pref.value ?
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
[brandName]);
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
let shouldProceed = prompts.confirm(window, title, msg)
if (shouldProceed) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
"restart");
shouldProceed = !cancelQuit.data;
if (shouldProceed) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
return;
}
}
gPrivacyPane._shouldPromptForRestart = false;
pref.value = !pref.value;
let mode = document.getElementById("historyMode");
if (mode.value != "custom") {
mode.selectedIndex = pref.value ? 1 : 0;
mode.doCommand();
} else {
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
rememberHistory.checked = pref.value;
}
#else
// Toggle the private browsing mode without switching the session
let prefValue = document.getElementById("browser.privatebrowsing.autostart").value;
let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session");
keepCurrentSession.value = true;
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
// If activating from within the private browsing mode, reset the
// private session
if (prefValue && privateBrowsingService.privateBrowsingEnabled)
privateBrowsingService.privateBrowsingEnabled = false;
privateBrowsingService.privateBrowsingEnabled = prefValue;
keepCurrentSession.reset();
#endif
}
},

View File

@ -15,22 +15,31 @@ _BROWSER_FILES = \
head.js \
browser_advanced_update.js \
browser_bug410900.js \
browser_bug567487.js \
browser_bug731866.js \
browser_connection.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += \
privacypane_tests.js \
browser_bug567487.js \
browser_privacypane_1.js \
browser_privacypane_2.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += \
browser_privacypane_6.js \
browser_privacypane_7.js \
browser_privacypane_8.js \
$(NULL)
else
_BROWSER_FILES += \
privacypane_tests_perwindow.js \
browser_privacypane_1.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
$(NULL)
endif

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_pane_visibility,

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_historymode_retention("remember", undefined),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("rememberHistory", "remember"),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("acceptCookies", "remember"),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_locbar_suggestion_retention(-1, undefined),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_toggle,

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_ui,

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
// history mode should be initialized to remember

View File

@ -0,0 +1,344 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function runTestOnPrivacyPrefPane(testFunc) {
gBrowser.tabContainer.addEventListener("TabOpen", function(aEvent) {
gBrowser.tabContainer.removeEventListener("TabOpen", arguments.callee, true);
let browser = aEvent.originalTarget.linkedBrowser;
browser.addEventListener("Initialized", function(aEvent) {
browser.removeEventListener("Initialized", arguments.callee, true);
is(browser.contentWindow.location.href, "about:preferences", "Checking if the preferences tab was opened");
testFunc(browser.contentWindow);
gBrowser.removeCurrentTab();
testRunner.runNext();
}, true);
}, true);
gBrowser.selectedTab = gBrowser.addTab("about:preferences");
}
function controlChanged(element) {
element.doCommand();
}
// We can only test the panes that don't trigger a preference update
function test_pane_visibility(win) {
let modes = {
"remember": "historyRememberPane",
"custom": "historyCustomPane"
};
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let historypane = win.document.getElementById("historyPane");
ok(historypane, "history mode pane should exist");
for (let mode in modes) {
historymode.value = mode;
controlChanged(historymode);
is(historypane.selectedPanel, win.document.getElementById(modes[mode]),
"The correct pane should be selected for the " + mode + " mode");
}
}
function test_dependent_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
win.document.getElementById("alwaysClear"),
];
controls.forEach(function(control) {
ok(control, "the dependent controls should exist");
});
let independents = [
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
independents.forEach(function(control) {
ok(control, "the independent controls should exist");
});
let cookieexceptions = win.document.getElementById("cookieExceptions");
ok(cookieexceptions, "the cookie exceptions button should exist");
let keepuntil = win.document.getElementById("keepCookiesUntil");
ok(keepuntil, "the keep cookies until menulist should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let rememberhistory = win.document.getElementById("rememberHistory");
ok(rememberhistory, "the remember history checkbox should exist");
let rememberforms = win.document.getElementById("rememberForms");
ok(rememberforms, "the remember forms checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
is(keepuntil.value, disabled ? 2 : 0,
"the keep cookies until menulist value should be as expected");
if (disabled) {
ok(!alwaysclear.checked,
"the clear data on close checkbox value should be as expected");
ok(!rememberhistory.checked,
"the remember history checkbox value should be as expected");
ok(!rememberforms.checked,
"the remember forms checkbox value should be as expected");
}
}
function check_independents(expected) {
independents.forEach(function(control) {
is(control.disabled, expected,
control.getAttribute("id") + " should " + (expected ? "" : "not ") + "be disabled");
});
ok(!cookieexceptions.disabled,
"the cookie exceptions button should never be disabled");
ok(alwaysclearsettings.disabled,
"the clear data settings button should always be disabled");
}
// controls should only change in custom mode
historymode.value = "remember";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
// setting the mode to custom shouldn't change anything
historymode.value = "custom";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
}
function test_dependent_cookie_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("acceptThirdParty"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
];
controls.forEach(function(control) {
ok(control, "the dependent cookie controls should exist");
});
let acceptcookies = win.document.getElementById("acceptCookies");
ok(acceptcookies, "the accept cookies checkbox should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(false);
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
let accessthirdparty = controls.shift();
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
ok(!accessthirdparty.disabled, "access third party button should be enabled");
}
function test_dependent_clearonclose_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
is(alwaysclearsettings.disabled, disabled,
"the clear data settings should " + (disabled ? "" : "not ") + "be disabled");
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
alwaysclear.checked = true;
controlChanged(alwaysclear);
expect_disabled(false);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
}
function test_dependent_prefs(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
controls.forEach(function(control) {
ok(control, "the micro-management controls should exist");
});
function expect_checked(checked) {
controls.forEach(function(control) {
is(control.checked, checked,
control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked");
});
}
// controls should be checked in remember mode
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
// even if they're unchecked in custom mode
historymode.value = "custom";
controlChanged(historymode);
controls.forEach(function(control) {
control.checked = false;
controlChanged(control);
});
expect_checked(false);
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
}
function test_historymode_retention(mode, expect) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if ((historymode.value == "remember" && mode == "dontremember") ||
(historymode.value == "dontremember" && mode == "remember") ||
(historymode.value == "custom" && mode == "dontremember")) {
return;
}
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = mode;
controlChanged(historymode);
};
}
function test_custom_retention(controlToChange, expect, valueIncrement) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = "custom";
controlChanged(historymode);
controlToChange = win.document.getElementById(controlToChange);
ok(controlToChange, "the control to change should exist");
switch (controlToChange.localName) {
case "checkbox":
controlToChange.checked = !controlToChange.checked;
break;
case "textbox":
controlToChange.value = parseInt(controlToChange.value) + valueIncrement;
break;
case "menulist":
controlToChange.value = valueIncrement;
break;
}
controlChanged(controlToChange);
};
}
function test_locbar_suggestion_retention(mode, expect) {
return function(win) {
let locbarsuggest = win.document.getElementById("locationBarSuggestion");
ok(locbarsuggest, "location bar suggestion menulist should exist");
if (expect !== undefined) {
is(locbarsuggest.value, expect,
"location bar suggestion is expected to remain " + expect);
}
locbarsuggest.value = mode;
controlChanged(locbarsuggest);
};
}
function reset_preferences(win) {
let prefs = win.document.querySelectorAll("#privacyPreferences > preference");
for (let i = 0; i < prefs.length; ++i)
if (prefs[i].hasUserValue)
prefs[i].reset();
}
let testRunner;
function run_test_subset(subset) {
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
waitForExplicitFinish();
registerCleanupFunction(function() {
// Reset pref to its default
Services.prefs.clearUserPref("browser.preferences.instantApply");
});
testRunner = {
tests: subset,
counter: 0,
runNext: function() {
if (this.counter == this.tests.length) {
finish();
} else {
let self = this;
setTimeout(function() {
runTestOnPrivacyPrefPane(self.tests[self.counter++]);
}, 0);
}
}
};
testRunner.runNext();
}

View File

@ -23,12 +23,25 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded", null);
},
setupDownloadsWindowOptions: function ()
{
let showWhenDownloading = document.getElementById("showWhenDownloading");
let closeWhenDone = document.getElementById("closeWhenDone");
// These radio buttons should be hidden when the Downloads Panel is enabled.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*

View File

@ -12,6 +12,11 @@ var gPrivacyPane = {
*/
_autoStartPrivateBrowsing: false,
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart: true,
/**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
@ -130,7 +135,8 @@ var gPrivacyPane = {
let pref = document.getElementById("browser.privatebrowsing.autostart");
switch (document.getElementById("historyMode").value) {
case "remember":
pref.value = false;
if (pref.value)
pref.value = false;
// select the remember history option if needed
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
@ -149,7 +155,8 @@ var gPrivacyPane = {
document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false;
break;
case "dontremember":
pref.value = true;
if (!pref.value)
pref.value = true;
break;
}
},
@ -222,12 +229,54 @@ var gPrivacyPane = {
observe: function PPP_observe(aSubject, aTopic, aData)
{
#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
if (!gPrivacyPane._shouldPromptForRestart) {
// We're performing a revert. Just let it happen.
gPrivacyPane._shouldPromptForRestart = true;
return;
}
const Cc = Components.classes, Ci = Components.interfaces;
let pref = document.getElementById("browser.privatebrowsing.autostart");
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
let bundle = document.getElementById("bundlePreferences");
let msg = bundle.getFormattedString(pref.value ?
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
[brandName]);
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
let shouldProceed = prompts.confirm(window, title, msg)
if (shouldProceed) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
"restart");
shouldProceed = !cancelQuit.data;
if (shouldProceed) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
return;
}
}
gPrivacyPane._shouldPromptForRestart = false;
pref.value = !pref.value;
let mode = document.getElementById("historyMode");
if (mode.value != "custom") {
mode.selectedIndex = pref.value ? 1 : 0;
mode.doCommand();
} else {
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
rememberHistory.checked = pref.value;
}
#else
// Toggle the private browsing mode without switching the session
let prefValue = document.getElementById("browser.privatebrowsing.autostart").value;
let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session");
keepCurrentSession.value = true;
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
@ -236,9 +285,9 @@ var gPrivacyPane = {
if (prefValue && privateBrowsingService.privateBrowsingEnabled)
privateBrowsingService.privateBrowsingEnabled = false;
privateBrowsingService.privateBrowsingEnabled = prefValue;
#endif
keepCurrentSession.reset();
#endif
}
},

View File

@ -14,23 +14,32 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_advanced_update.js \
browser_bug410900.js \
browser_bug567487.js \
browser_bug705422.js \
privacypane_tests.js \
browser_privacypane_1.js \
browser_privacypane_2.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
browser_permissions.js \
browser_chunk_permissions.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += \
privacypane_tests.js \
browser_bug567487.js \
browser_privacypane_1.js \
browser_privacypane_2.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_6.js \
browser_privacypane_7.js \
browser_privacypane_8.js \
$(NULL)
else
_BROWSER_FILES += \
privacypane_tests_perwindow.js \
browser_privacypane_1.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
$(NULL)
endif

View File

@ -12,7 +12,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_pane_visibility,

View File

@ -12,7 +12,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_historymode_retention("remember", undefined),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("rememberHistory", "remember"),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("acceptCookies", "remember"),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_locbar_suggestion_retention(-1, undefined),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_toggle,

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_ui,

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
// history mode should be initialized to remember

View File

@ -0,0 +1,352 @@
/* 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/. */
function runTestOnPrivacyPrefPane(testFunc) {
let observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == "domwindowopened") {
Services.ww.unregisterNotification(this);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function() {
win.removeEventListener("load", arguments.callee, false);
testFunc(dialog.document.defaultView);
Services.ww.registerNotification(observer);
dialog.close();
}, false);
} else if (aTopic == "domwindowclosed") {
Services.ww.unregisterNotification(this);
testRunner.runNext();
}
}
};
Services.ww.registerNotification(observer);
let dialog = openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
"chrome,titlebar,toolbar,centerscreen,dialog=no", "panePrivacy");
}
function controlChanged(element) {
element.doCommand();
}
// We can only test the panes that don't trigger a preference update
function test_pane_visibility(win) {
let modes = {
"remember": "historyRememberPane",
"custom": "historyCustomPane"
};
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let historypane = win.document.getElementById("historyPane");
ok(historypane, "history mode pane should exist");
for (let mode in modes) {
historymode.value = mode;
controlChanged(historymode);
is(historypane.selectedPanel, win.document.getElementById(modes[mode]),
"The correct pane should be selected for the " + mode + " mode");
}
}
function test_dependent_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
win.document.getElementById("alwaysClear"),
];
controls.forEach(function(control) {
ok(control, "the dependent controls should exist");
});
let independents = [
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
independents.forEach(function(control) {
ok(control, "the independent controls should exist");
});
let cookieexceptions = win.document.getElementById("cookieExceptions");
ok(cookieexceptions, "the cookie exceptions button should exist");
let keepuntil = win.document.getElementById("keepCookiesUntil");
ok(keepuntil, "the keep cookies until menulist should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let rememberhistory = win.document.getElementById("rememberHistory");
ok(rememberhistory, "the remember history checkbox should exist");
let rememberforms = win.document.getElementById("rememberForms");
ok(rememberforms, "the remember forms checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
is(keepuntil.value, disabled ? 2 : 0,
"the keep cookies until menulist value should be as expected");
if (disabled) {
ok(!alwaysclear.checked,
"the clear data on close checkbox value should be as expected");
ok(!rememberhistory.checked,
"the remember history checkbox value should be as expected");
ok(!rememberforms.checked,
"the remember forms checkbox value should be as expected");
}
}
function check_independents(expected) {
independents.forEach(function(control) {
is(control.disabled, expected,
control.getAttribute("id") + " should " + (expected ? "" : "not ") + "be disabled");
});
ok(!cookieexceptions.disabled,
"the cookie exceptions button should never be disabled");
ok(alwaysclearsettings.disabled,
"the clear data settings button should always be disabled");
}
// controls should only change in custom mode
historymode.value = "remember";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
// setting the mode to custom shouldn't change anything
historymode.value = "custom";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
}
function test_dependent_cookie_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("acceptThirdParty"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
];
controls.forEach(function(control) {
ok(control, "the dependent cookie controls should exist");
});
let acceptcookies = win.document.getElementById("acceptCookies");
ok(acceptcookies, "the accept cookies checkbox should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(false);
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
let accessthirdparty = controls.shift();
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
ok(!accessthirdparty.disabled, "access third party button should be enabled");
}
function test_dependent_clearonclose_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
is(alwaysclearsettings.disabled, disabled,
"the clear data settings should " + (disabled ? "" : "not ") + "be disabled");
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
alwaysclear.checked = true;
controlChanged(alwaysclear);
expect_disabled(false);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
}
function test_dependent_prefs(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
controls.forEach(function(control) {
ok(control, "the micro-management controls should exist");
});
function expect_checked(checked) {
controls.forEach(function(control) {
is(control.checked, checked,
control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked");
});
}
// controls should be checked in remember mode
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
// even if they're unchecked in custom mode
historymode.value = "custom";
controlChanged(historymode);
controls.forEach(function(control) {
control.checked = false;
controlChanged(control);
});
expect_checked(false);
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
}
function test_historymode_retention(mode, expect) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if ((historymode.value == "remember" && mode == "dontremember") ||
(historymode.value == "dontremember" && mode == "remember") ||
(historymode.value == "custom" && mode == "dontremember")) {
return;
}
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = mode;
controlChanged(historymode);
};
}
function test_custom_retention(controlToChange, expect, valueIncrement) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = "custom";
controlChanged(historymode);
controlToChange = win.document.getElementById(controlToChange);
ok(controlToChange, "the control to change should exist");
switch (controlToChange.localName) {
case "checkbox":
controlToChange.checked = !controlToChange.checked;
break;
case "textbox":
controlToChange.value = parseInt(controlToChange.value) + valueIncrement;
break;
case "menulist":
controlToChange.value = valueIncrement;
break;
}
controlChanged(controlToChange);
};
}
function test_locbar_suggestion_retention(mode, expect) {
return function(win) {
let locbarsuggest = win.document.getElementById("locationBarSuggestion");
ok(locbarsuggest, "location bar suggestion menulist should exist");
if (expect !== undefined) {
is(locbarsuggest.value, expect,
"location bar suggestion is expected to remain " + expect);
}
locbarsuggest.value = mode;
controlChanged(locbarsuggest);
};
}
function reset_preferences(win) {
let prefs = win.document.getElementsByTagName("preference");
for (let i = 0; i < prefs.length; ++i)
if (prefs[i].hasUserValue)
prefs[i].reset();
}
let testRunner;
function run_test_subset(subset) {
let instantApplyOrig = Services.prefs.getBoolPref("browser.preferences.instantApply");
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
waitForExplicitFinish();
testRunner = {
tests: subset,
counter: 0,
runNext: function() {
if (this.counter == this.tests.length) {
// cleanup
Services.prefs.setBoolPref("browser.preferences.instantApply", instantApplyOrig);
finish();
} else {
let self = this;
setTimeout(function() {
runTestOnPrivacyPrefPane(self.tests[self.counter++]);
}, 0);
}
}
};
testRunner.runNext();
}

View File

@ -11,7 +11,9 @@ include $(DEPTH)/config/autoconf.mk
MODULE = privatebrowsing
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
DIRS = src
endif
TEST_DIRS += test

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