mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Merge mozilla-central into build-system
This commit is contained in:
commit
86ec7725e5
@ -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;
|
||||
|
@ -52,7 +52,7 @@ enum AccType {
|
||||
eMenuPopupType,
|
||||
eProgressType,
|
||||
eRootType,
|
||||
eXULDeckType,
|
||||
eXULTabpanelsType,
|
||||
eXULTreeType,
|
||||
|
||||
eLastAccType = eXULTreeType
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
@ -843,28 +882,43 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
@ -1480,37 +1534,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,
|
||||
|
@ -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.
|
||||
|
@ -612,6 +612,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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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*
|
||||
|
@ -163,11 +163,11 @@ XULTabsAccessible::NativeName(nsString& aName)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XULDeckAccessible
|
||||
// XULTabpanelsAccessible
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
role
|
||||
XULDeckAccessible::NativeRole()
|
||||
XULTabpanelsAccessible::NativeRole()
|
||||
{
|
||||
return roles::PANE;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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 \
|
||||
|
109
accessible/tests/mochitest/treeupdate/test_deck.xul
Normal file
109
accessible/tests/mochitest/treeupdate/test_deck.xul
Normal 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>
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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":
|
||||
|
@ -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"]);
|
||||
}
|
||||
}
|
||||
|
@ -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,7 +189,7 @@ 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);
|
||||
},
|
||||
|
||||
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
|
||||
@ -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":
|
||||
|
@ -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;
|
||||
},
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
52
browser/base/content/browser-webrtcUI.js
Normal file
52
browser/base/content/browser-webrtcUI.js
Normal 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();
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
@ -3772,7 +3774,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) {
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -600,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);
|
||||
@ -770,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);
|
||||
}
|
||||
@ -882,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;
|
||||
},
|
||||
|
@ -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"
|
||||
|
@ -107,28 +107,11 @@ 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;
|
||||
|
@ -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;
|
||||
}
|
||||
@ -1791,6 +1771,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);
|
||||
|
29
browser/components/places/content/downloadsViewOverlay.xul
Normal file
29
browser/components/places/content/downloadsViewOverlay.xul
Normal 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>
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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 = {}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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"),
|
||||
|
@ -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"),
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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"),
|
||||
|
@ -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"),
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -11,7 +11,9 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = privatebrowsing
|
||||
|
||||
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
|
||||
DIRS = src
|
||||
endif
|
||||
|
||||
TEST_DIRS += test
|
||||
|
||||
|
@ -3728,6 +3728,9 @@ let SessionStoreInternal = {
|
||||
for (let i = oState.windows.length - 1; i >= 0; i--) {
|
||||
if (oState.windows[i].isPrivate) {
|
||||
oState.windows.splice(i, 1);
|
||||
if (oState.selectedWindow >= i) {
|
||||
oState.selectedWindow--;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = oState._closedWindows.length - 1; i >= 0; i--) {
|
||||
|
@ -141,6 +141,7 @@ ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_354894_perwindowpb.js \
|
||||
browser_394759_perwindowpb.js \
|
||||
browser_819510_perwindowpb.js \
|
||||
$(NULL)
|
||||
else
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
|
@ -38,7 +38,7 @@ function test() {
|
||||
tab = window.gBrowser.tabs[i];
|
||||
}
|
||||
|
||||
ok(tab.pinned || gBrowser.selectedTab == tab,
|
||||
ok(tab.pinned || tab.selected,
|
||||
"load came from pinned or selected tab");
|
||||
|
||||
// We should get 4 loads: 3 app tabs + 1 normal selected tab
|
||||
|
@ -37,7 +37,7 @@ function test() {
|
||||
}
|
||||
|
||||
// Check that the load only comes from the selected tab.
|
||||
ok(gBrowser.selectedTab == tab, "load came from selected tab");
|
||||
ok(tab.selected, "load came from selected tab");
|
||||
is(aNeedRestore, 6, "six tabs left to restore");
|
||||
is(aRestoring, 1, "one tab is restoring");
|
||||
is(aRestored, 0, "no tabs have been restored, yet");
|
||||
|
@ -0,0 +1,181 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const originalState = ss.getBrowserState();
|
||||
|
||||
/** Private Browsing Test for Bug 819510 **/
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
ss.setBrowserState(originalState);
|
||||
});
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
let tests = [test_1, test_2, test_3 ];
|
||||
|
||||
const testState = {
|
||||
windows: [{
|
||||
tabs: [
|
||||
{ entries: [{ url: "about:blank" }] },
|
||||
]
|
||||
}]
|
||||
};
|
||||
|
||||
function runNextTest() {
|
||||
// Set an empty state
|
||||
closeAllButPrimaryWindow();
|
||||
|
||||
// Run the next test, or finish
|
||||
if (tests.length) {
|
||||
let currentTest = tests.shift();
|
||||
waitForBrowserState(testState, currentTest);
|
||||
} else {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
ss.setBrowserState(originalState);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
// Test opening default mochitest-normal-private-normal-private windows
|
||||
// (saving the state with last window being private)
|
||||
function test_1() {
|
||||
testOnWindow(false, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/1");
|
||||
testOnWindow(true, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/2");
|
||||
testOnWindow(false, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/3");
|
||||
testOnWindow(true, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/4");
|
||||
|
||||
let curState = JSON.parse(ss.getBrowserState());
|
||||
is (curState.windows.length, 5, "Browser has opened 5 windows");
|
||||
is (curState.windows[2].isPrivate, true, "Window is private");
|
||||
is (curState.windows[4].isPrivate, true, "Last window is private");
|
||||
is (curState.selectedWindow, 5, "Last window opened is the one selected");
|
||||
|
||||
forceWriteState(function(state) {
|
||||
is(state.windows.length, 3,
|
||||
"sessionstore state: 3 windows in data being written to disk");
|
||||
is (state.selectedWindow, 3,
|
||||
"Selected window is updated to match one of the saved windows");
|
||||
state.windows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Saved window is not private");
|
||||
});
|
||||
is(state._closedWindows.length, 0,
|
||||
"sessionstore state: no closed windows in data being written to disk");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Test opening default mochitest window + 2 private windows
|
||||
function test_2() {
|
||||
testOnWindow(true, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/1");
|
||||
testOnWindow(true, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/2");
|
||||
|
||||
let curState = JSON.parse(ss.getBrowserState());
|
||||
is (curState.windows.length, 3, "Browser has opened 3 windows");
|
||||
is (curState.windows[1].isPrivate, true, "Window 1 is private");
|
||||
is (curState.windows[2].isPrivate, true, "Window 2 is private");
|
||||
is (curState.selectedWindow, 3, "Last window opened is the one selected");
|
||||
|
||||
forceWriteState(function(state) {
|
||||
is(state.windows.length, 1,
|
||||
"sessionstore state: 1 windows in data being writted to disk");
|
||||
is (state.selectedWindow, 1,
|
||||
"Selected window is updated to match one of the saved windows");
|
||||
is(state._closedWindows.length, 0,
|
||||
"sessionstore state: no closed windows in data being writted to disk");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Test opening default-normal-private-normal windows and closing a normal window
|
||||
function test_3() {
|
||||
testOnWindow(false, function(normalWindow) {
|
||||
let tab = normalWindow.gBrowser.addTab("http://www.example.com/1");
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
testOnWindow(true, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/2");
|
||||
testOnWindow(false, function(aWindow) {
|
||||
aWindow.gBrowser.addTab("http://www.example.com/3");
|
||||
|
||||
let curState = JSON.parse(ss.getBrowserState());
|
||||
is (curState.windows.length, 4, "Browser has opened 4 windows");
|
||||
is (curState.windows[2].isPrivate, true, "Window 2 is private");
|
||||
is (curState.selectedWindow, 4, "Last window opened is the one selected");
|
||||
|
||||
waitForWindowClose(normalWindow, function() {
|
||||
forceWriteState(function(state) {
|
||||
is(state.windows.length, 2,
|
||||
"sessionstore state: 2 windows in data being writted to disk");
|
||||
is(state.selectedWindow, 2,
|
||||
"Selected window is updated to match one of the saved windows");
|
||||
state.windows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Saved window is not private");
|
||||
});
|
||||
is(state._closedWindows.length, 1,
|
||||
"sessionstore state: 1 closed window in data being writted to disk");
|
||||
state._closedWindows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Closed window is not private");
|
||||
});
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForWindowClose(aWin, aCallback) {
|
||||
Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowclosed" && aWin == aSubject) {
|
||||
Services.obs.removeObserver(observe, aTopic);
|
||||
checkWindowIsClosed(aWin, aCallback);
|
||||
}
|
||||
}, "domwindowclosed", false);
|
||||
aWin.close();
|
||||
}
|
||||
|
||||
function checkWindowIsClosed(aWin, aCallback) {
|
||||
if (aWin.closed) {
|
||||
info("Window is closed");
|
||||
executeSoon(aCallback);
|
||||
} else {
|
||||
executeSoon(function() {
|
||||
checkWindowIsClosed(aWin, aCallback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function forceWriteState(aCallback) {
|
||||
Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "sessionstore-state-write") {
|
||||
Services.obs.removeObserver(observe, aTopic);
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
aCallback(JSON.parse(aSubject.data));
|
||||
}
|
||||
}, "sessionstore-state-write", false);
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 0);
|
||||
}
|
||||
|
||||
function testOnWindow(aIsPrivate, aCallback) {
|
||||
let win = OpenBrowserWindow({private: aIsPrivate});
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
executeSoon(function() { aCallback(win); });
|
||||
}, false);
|
||||
}
|
@ -1004,7 +1004,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
|
||||
// if it matches the selected tab or no active tab and the browser
|
||||
// tab is hidden, the active group item would be set.
|
||||
if (item.tab == gBrowser.selectedTab ||
|
||||
if (item.tab.selected ||
|
||||
(!GroupItems.getActiveGroupItem() && !item.tab.hidden))
|
||||
UI.setActive(this);
|
||||
}
|
||||
@ -2542,7 +2542,7 @@ let GroupItems = {
|
||||
let groupItem;
|
||||
|
||||
// switch to the appropriate tab first.
|
||||
if (gBrowser.selectedTab == tab) {
|
||||
if (tab.selected) {
|
||||
if (gBrowser.visibleTabs.length > 1) {
|
||||
gBrowser._blurTab(tab);
|
||||
shouldUpdateTabBar = true;
|
||||
|
@ -277,7 +277,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
|
||||
// if it matches the selected tab or no active tab and the browser
|
||||
// tab is hidden, the active group item would be set.
|
||||
if (this.tab == gBrowser.selectedTab ||
|
||||
if (this.tab.selected ||
|
||||
(!GroupItems.getActiveGroupItem() && !this.tab.hidden))
|
||||
UI.setActive(this.parent);
|
||||
}
|
||||
@ -539,11 +539,11 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
|
||||
UI.goToTab(tab);
|
||||
|
||||
// tab might not be selected because hideTabView() is invoked after
|
||||
// tab might not be selected because hideTabView() is invoked after
|
||||
// UI.goToTab() so we need to setup everything for the gBrowser.selectedTab
|
||||
if (tab != gBrowser.selectedTab) {
|
||||
if (!tab.selected) {
|
||||
UI.onTabSelect(gBrowser.selectedTab);
|
||||
} else {
|
||||
} else {
|
||||
if (isNewBlankTab)
|
||||
gWindow.gURLBar.focus();
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ function onTabViewLoadedAndShown() {
|
||||
gBrowser.pinTab(appTab);
|
||||
|
||||
// verify that the normal tab is selected
|
||||
ok(gBrowser.selectedTab == originalTab, "the normal tab is selected");
|
||||
ok(originalTab.selected, "the normal tab is selected");
|
||||
|
||||
// hit the exit button for the first time
|
||||
exitButton = contentWindow.document.getElementById("exit-button");
|
||||
@ -50,11 +50,11 @@ function onTabViewHiddenForNormalTab() {
|
||||
ok(!TabView.isVisible(), "Tab View is not visible");
|
||||
|
||||
// verify that the normal tab is still selected
|
||||
ok(gBrowser.selectedTab == originalTab, "the normal tab is still selected");
|
||||
ok(originalTab.selected, "the normal tab is still selected");
|
||||
|
||||
// select the app tab
|
||||
gBrowser.selectedTab = appTab;
|
||||
ok(gBrowser.selectedTab == appTab, "the app tab is now selected");
|
||||
ok(appTab.selected, "the app tab is now selected");
|
||||
|
||||
// go back to tabview
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
@ -77,14 +77,14 @@ function onTabViewHiddenForAppTab() {
|
||||
ok(!TabView.isVisible(), "Tab View is not visible");
|
||||
|
||||
// verify that the app tab is still selected
|
||||
ok(gBrowser.selectedTab == appTab, "the app tab is still selected");
|
||||
ok(appTab.selected, "the app tab is still selected");
|
||||
|
||||
// clean up
|
||||
gBrowser.selectedTab = originalTab;
|
||||
gBrowser.selectedTab = originalTab;
|
||||
gBrowser.removeTab(appTab);
|
||||
|
||||
is(gBrowser.tabs.length, 1, "we finish with one tab");
|
||||
ok(gBrowser.selectedTab == originalTab,
|
||||
ok(originalTab.selected,
|
||||
"we finish with the normal tab selected");
|
||||
ok(!TabView.isVisible(), "we finish with Tab View not visible");
|
||||
|
||||
|
@ -823,7 +823,7 @@ let UI = {
|
||||
// Selects the given xul:tab in the browser.
|
||||
goToTab: function UI_goToTab(xulTab) {
|
||||
// If it's not focused, the onFocus listener would handle it.
|
||||
if (gBrowser.selectedTab == xulTab)
|
||||
if (xulTab.selected)
|
||||
this.onTabSelect(xulTab);
|
||||
else
|
||||
gBrowser.selectedTab = xulTab;
|
||||
@ -936,7 +936,7 @@ let UI = {
|
||||
// TabView is hidden and that the correct group is activated. When a modal
|
||||
// dialog is shown for currently selected tab the onTabSelect event handler
|
||||
// is not called, so we need to do it.
|
||||
if (gBrowser.selectedTab == tab && this._currentTab == tab)
|
||||
if (tab.selected && this._currentTab == tab)
|
||||
this.onTabSelect(tab);
|
||||
},
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
. $topsrcdir/build/macosx/mozconfig.leopard
|
||||
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-trace-malloc
|
||||
ac_add_options --enable-signmar
|
||||
ENABLE_MARIONETTE=1
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
ac_add_options --with-macbundlename-prefix=Firefox
|
||||
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"clang_version": "r170377"
|
||||
"clang_version": "r170890"
|
||||
},
|
||||
{
|
||||
"size": 47,
|
||||
@ -9,8 +9,8 @@
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 61878564,
|
||||
"digest": "bc344ad6cb8f4d7b25447a8f06ae3a22c6b90283fcc70f28f12578bdaf01ec960a774cdc215bdda4960cef04b6a991e462daeeda4f7e802bf65e6c9a3967f66c",
|
||||
"size": 61878284,
|
||||
"digest": "a3f924e7a6d8651b3466f3dc4625eaa00f90ee6cc824ddd4da7a27ce26916220615c1aa33e4a286b757b9283c536b8311edddf469d23e9e1306b90dff19ae11f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"clang_version": "r170377"
|
||||
"clang_version": "r170890"
|
||||
},
|
||||
{
|
||||
"size": 47,
|
||||
@ -9,8 +9,8 @@
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 62277867,
|
||||
"digest": "b9c6ab4069e336fcbe705f07fd2beda37aecfd4078863898826c9591305b92f3f3f762e7f5c1b0eeb7e0fb1c0dacbca60f24868e0b3181bd34dcd9c5d44d20ee",
|
||||
"size": 62279506,
|
||||
"digest": "aa886361161a7d32aad71dfe5fd6b6cdff25610d8e32153a80caea66a8475aa8526d8529d8ac26e8ac26bd32878ee0df6d8dbef95dfd9faacec45b4ab918d52d",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2"
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
[
|
||||
{
|
||||
"clang_version": "r170377"
|
||||
},
|
||||
{
|
||||
"size": 47,
|
||||
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 56131193,
|
||||
"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2"
|
||||
}
|
||||
]
|
@ -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"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 0.6.172
|
||||
Current extension version is: 0.7.28
|
||||
|
||||
|
@ -30,31 +30,19 @@ const PDF_CONTENT_TYPE = 'application/pdf';
|
||||
const PREF_PREFIX = 'pdfjs';
|
||||
const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
|
||||
const MAX_DATABASE_LENGTH = 4096;
|
||||
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/NetUtil.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
|
||||
'resource://gre/modules/PrivateBrowsingUtils.jsm');
|
||||
|
||||
let appInfo = Cc['@mozilla.org/xre/app-info;1']
|
||||
.getService(Ci.nsIXULAppInfo);
|
||||
let Svc = {};
|
||||
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
|
||||
'@mozilla.org/mime;1',
|
||||
'nsIMIMEService');
|
||||
|
||||
let isInPrivateBrowsing;
|
||||
if (appInfo.ID === FIREFOX_ID) {
|
||||
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
|
||||
.getService(Ci.nsIPrivateBrowsingService);
|
||||
isInPrivateBrowsing = function getInPrivateBrowsing() {
|
||||
return privateBrowsing.privateBrowsingEnabled;
|
||||
};
|
||||
} else {
|
||||
isInPrivateBrowsing = function() { return false; };
|
||||
}
|
||||
|
||||
function getChromeWindow(domWindow) {
|
||||
var containingBrowser = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
@ -71,6 +59,14 @@ function getBoolPref(pref, def) {
|
||||
}
|
||||
}
|
||||
|
||||
function getIntPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getIntPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function setStringPref(pref, value) {
|
||||
let str = Cc['@mozilla.org/supports-string;1']
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
@ -211,6 +207,30 @@ function ChromeActions(domWindow, dataListener) {
|
||||
}
|
||||
|
||||
ChromeActions.prototype = {
|
||||
isInPrivateBrowsing: function() {
|
||||
let docIsPrivate;
|
||||
try {
|
||||
docIsPrivate = PrivateBrowsingUtils.isWindowPrivate(this.domWindow);
|
||||
} catch (x) {
|
||||
// unable to use PrivateBrowsingUtils, e.g. FF15
|
||||
}
|
||||
if (typeof docIsPrivate === 'undefined') {
|
||||
// per-window Private Browsing is not supported, trying global service
|
||||
try {
|
||||
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
|
||||
.getService(Ci.nsIPrivateBrowsingService);
|
||||
docIsPrivate = privateBrowsing.privateBrowsingEnabled;
|
||||
} catch (x) {
|
||||
// unable to get nsIPrivateBrowsingService (e.g. not Firefox)
|
||||
docIsPrivate = false;
|
||||
}
|
||||
}
|
||||
// caching the result
|
||||
this.isInPrivateBrowsing = function isInPrivateBrowsingCached() {
|
||||
return docIsPrivate;
|
||||
};
|
||||
return docIsPrivate;
|
||||
},
|
||||
download: function(data, sendResponse) {
|
||||
var originalUrl = data.originalUrl;
|
||||
// The data may not be downloaded so we need just retry getting the pdf with
|
||||
@ -223,16 +243,7 @@ ChromeActions.prototype = {
|
||||
var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1'].
|
||||
getService(Ci.nsIWindowWatcher).activeWindow;
|
||||
|
||||
let docIsPrivate = false;
|
||||
try {
|
||||
docIsPrivate = this.domWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsILoadContext)
|
||||
.usePrivateBrowsing;
|
||||
} catch (x) {
|
||||
}
|
||||
|
||||
let docIsPrivate = this.isInPrivateBrowsing();
|
||||
let netChannel = NetUtil.newChannel(blobUri);
|
||||
if ('nsIPrivateBrowsingChannel' in Ci &&
|
||||
netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
|
||||
@ -281,7 +292,7 @@ ChromeActions.prototype = {
|
||||
});
|
||||
},
|
||||
setDatabase: function(data) {
|
||||
if (isInPrivateBrowsing())
|
||||
if (this.isInPrivateBrowsing())
|
||||
return;
|
||||
// Protect against something sending tons of data to setDatabase.
|
||||
if (data.length > MAX_DATABASE_LENGTH)
|
||||
@ -289,7 +300,7 @@ ChromeActions.prototype = {
|
||||
setStringPref(PREF_PREFIX + '.database', data);
|
||||
},
|
||||
getDatabase: function() {
|
||||
if (isInPrivateBrowsing())
|
||||
if (this.isInPrivateBrowsing())
|
||||
return '{}';
|
||||
return getStringPref(PREF_PREFIX + '.database', '{}');
|
||||
},
|
||||
@ -351,6 +362,10 @@ ChromeActions.prototype = {
|
||||
getChromeWindow(this.domWindow).gFindBar &&
|
||||
'updateControlState' in getChromeWindow(this.domWindow).gFindBar;
|
||||
},
|
||||
supportsDocumentFonts: function() {
|
||||
var pref = getIntPref('browser.display.use_document_fonts', 1);
|
||||
return !!pref;
|
||||
},
|
||||
fallback: function(url, sendResponse) {
|
||||
var self = this;
|
||||
var domWindow = this.domWindow;
|
||||
|
@ -156,6 +156,13 @@ let PdfJs = {
|
||||
types.push(PDF_CONTENT_TYPE);
|
||||
}
|
||||
prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(','));
|
||||
|
||||
// Update the category manager in case the plugins are already loaded.
|
||||
let categoryManager = Cc["@mozilla.org/categorymanager;1"];
|
||||
categoryManager.getService(Ci.nsICategoryManager).
|
||||
deleteCategoryEntry("Gecko-Content-Viewers",
|
||||
PDF_CONTENT_TYPE,
|
||||
false);
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -521,7 +521,7 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
|
||||
.splitToolbarButton:hover > .splitToolbarButtonSeparator,
|
||||
.splitToolbarButton.toggled > .splitToolbarButtonSeparator {
|
||||
padding: 12px 0;
|
||||
margin: 0;
|
||||
margin: 1px 0;
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.03);
|
||||
-webkit-transition-property: padding;
|
||||
-webkit-transition-duration: 10ms;
|
||||
|
@ -936,6 +936,21 @@ var PDFView = {
|
||||
return support;
|
||||
},
|
||||
|
||||
get supportsDocumentFonts() {
|
||||
var support = true;
|
||||
support = FirefoxCom.requestSync('supportsDocumentFonts');
|
||||
Object.defineProperty(this, 'supportsDocumentFonts', { value: support,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: false });
|
||||
return support;
|
||||
},
|
||||
|
||||
get isHorizontalScrollbarEnabled() {
|
||||
var div = document.getElementById('viewerContainer');
|
||||
return div.scrollWidth > div.clientWidth;
|
||||
},
|
||||
|
||||
initPassiveLoading: function pdfViewInitPassiveLoading() {
|
||||
if (!PDFView.loadingBar) {
|
||||
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
|
||||
@ -2037,6 +2052,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
if (outputScale.scaled) {
|
||||
ctx.scale(outputScale.sx, outputScale.sy);
|
||||
}
|
||||
// Checking if document fonts are used only once
|
||||
var checkIfDocumentFontsUsed = !PDFView.pdfDocument.embeddedFontsUsed;
|
||||
|
||||
// Rendering area
|
||||
|
||||
@ -2049,6 +2066,12 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
delete self.loadingIconDiv;
|
||||
}
|
||||
|
||||
if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed &&
|
||||
!PDFView.supportsDocumentFonts) {
|
||||
console.error(mozL10n.get('web_fonts_disabled', null,
|
||||
'Web fonts are disabled: unable to use embedded PDF fonts.'));
|
||||
PDFView.fallback();
|
||||
}
|
||||
if (error) {
|
||||
PDFView.error(mozL10n.get('rendering_error', null,
|
||||
'An error occurred while rendering the page.'), error);
|
||||
@ -3095,6 +3118,7 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
case 61: // FF/Mac '='
|
||||
case 107: // FF '+' and '='
|
||||
case 187: // Chrome '+'
|
||||
case 171: // FF with German keyboard
|
||||
PDFView.zoomIn();
|
||||
handled = true;
|
||||
break;
|
||||
@ -3105,6 +3129,7 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
handled = true;
|
||||
break;
|
||||
case 48: // '0'
|
||||
case 96: // '0' on Numpad of Swedish keyboard
|
||||
PDFView.parseScale(DEFAULT_SCALE, true);
|
||||
handled = true;
|
||||
break;
|
||||
@ -3152,6 +3177,10 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
}
|
||||
// in fullscreen mode falls throw here
|
||||
case 37: // left arrow
|
||||
// horizontal scrolling using arrow keys
|
||||
if (PDFView.isHorizontalScrollbarEnabled) {
|
||||
break;
|
||||
}
|
||||
case 75: // 'k'
|
||||
case 80: // 'p'
|
||||
PDFView.page--;
|
||||
@ -3165,6 +3194,10 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
}
|
||||
// in fullscreen mode falls throw here
|
||||
case 39: // right arrow
|
||||
// horizontal scrolling using arrow keys
|
||||
if (PDFView.isHorizontalScrollbarEnabled) {
|
||||
break;
|
||||
}
|
||||
case 74: // 'j'
|
||||
case 78: // 'n'
|
||||
PDFView.page++;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user