mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Merge backout
This commit is contained in:
commit
3f850f954b
@ -56,7 +56,7 @@ interface nsIDOMWindow;
|
||||
* nsIAccessNode::GetAccessibleDocument() or
|
||||
* nsIAccessibleEvent::GetAccessibleDocument()
|
||||
*/
|
||||
[scriptable, uuid(03c6ce8a-aa40-4484-9282-e6579c56e054)]
|
||||
[scriptable, uuid(451242bd-8a0c-4198-ae88-c053609a4e5d)]
|
||||
interface nsIAccessibleDocument : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -99,4 +99,19 @@ interface nsIAccessibleDocument : nsISupports
|
||||
* For example, in Windows you can static cast it to an HWND.
|
||||
*/
|
||||
[noscript] readonly attribute voidPtr windowHandle;
|
||||
|
||||
/**
|
||||
* Return the parent document accessible.
|
||||
*/
|
||||
readonly attribute nsIAccessibleDocument parentDocument;
|
||||
|
||||
/**
|
||||
* Return the count of child document accessibles.
|
||||
*/
|
||||
readonly attribute unsigned long childDocumentCount;
|
||||
|
||||
/**
|
||||
* Return the child document accessible at the given index.
|
||||
*/
|
||||
nsIAccessibleDocument getChildDocumentAt(in unsigned long index);
|
||||
};
|
||||
|
@ -133,11 +133,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
|
||||
cb.NoteXPCOMChild(tmp->mEventQueue.get());
|
||||
|
||||
PRUint32 i, length = tmp->mChildDocuments.Length();
|
||||
for (i = 0; i < length; ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildDocuments[i]");
|
||||
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mChildDocuments[i].get()));
|
||||
}
|
||||
|
||||
CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
|
||||
ClearCache(tmp->mAccessibleCache);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -498,6 +505,44 @@ nsDocAccessible::GetDOMDocument(nsIDOMDocument **aDOMDocument)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetParentDocument(nsIAccessibleDocument** aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
*aDocument = nsnull;
|
||||
|
||||
if (!IsDefunct())
|
||||
NS_IF_ADDREF(*aDocument = ParentDocument());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetChildDocumentCount(PRUint32* aCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCount);
|
||||
*aCount = 0;
|
||||
|
||||
if (!IsDefunct())
|
||||
*aCount = ChildDocumentCount();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetChildDocumentAt(PRUint32 aIndex,
|
||||
nsIAccessibleDocument** aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
*aDocument = nsnull;
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_OK;
|
||||
|
||||
NS_IF_ADDREF(*aDocument = GetChildDocumentAt(aIndex));
|
||||
return *aDocument ? NS_OK : NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// nsIAccessibleHyperText method
|
||||
NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
|
||||
{
|
||||
@ -531,6 +576,7 @@ NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsDocAccessible public method
|
||||
nsAccessible *
|
||||
nsDocAccessible::GetCachedAccessible(void *aUniqueID)
|
||||
{
|
||||
@ -603,6 +649,10 @@ nsDocAccessible::Init()
|
||||
|
||||
AddEventListeners();
|
||||
|
||||
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
|
||||
if (parentDocument)
|
||||
parentDocument->AppendChildDocument(this);
|
||||
|
||||
// Fire reorder event to notify new accessible document has been created and
|
||||
// attached to the tree.
|
||||
nsRefPtr<AccEvent> reorderEvent =
|
||||
@ -629,8 +679,15 @@ nsDocAccessible::Shutdown()
|
||||
|
||||
RemoveEventListeners();
|
||||
|
||||
if (mParent)
|
||||
if (mParent) {
|
||||
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
|
||||
if (parentDocument)
|
||||
parentDocument->RemoveChildDocument(this);
|
||||
|
||||
mParent->RemoveChild(this);
|
||||
}
|
||||
|
||||
mChildDocuments.Clear();
|
||||
|
||||
mWeakShell = nsnull; // Avoid reentrancy
|
||||
|
||||
@ -1278,6 +1335,23 @@ nsDocAccessible::HandleAccEvent(AccEvent* aAccEvent)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public members
|
||||
|
||||
nsAccessible*
|
||||
nsDocAccessible::GetCachedAccessibleInSubtree(void* aUniqueID)
|
||||
{
|
||||
nsAccessible* child = GetCachedAccessible(aUniqueID);
|
||||
if (child)
|
||||
return child;
|
||||
|
||||
PRUint32 childDocCount = mChildDocuments.Length();
|
||||
for (PRUint32 childDocIdx= 0; childDocIdx < childDocCount; childDocIdx++) {
|
||||
nsDocAccessible* childDocument = mChildDocuments.ElementAt(childDocIdx);
|
||||
child = childDocument->GetCachedAccessibleInSubtree(aUniqueID);
|
||||
if (child)
|
||||
return child;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected members
|
||||
|
@ -141,6 +141,24 @@ public:
|
||||
*/
|
||||
void MarkAsLoaded() { mIsLoaded = PR_TRUE; }
|
||||
|
||||
/**
|
||||
* Return the parent document.
|
||||
*/
|
||||
nsDocAccessible* ParentDocument() const
|
||||
{ return mParent ? mParent->GetDocAccessible() : nsnull; }
|
||||
|
||||
/**
|
||||
* Return the child document count.
|
||||
*/
|
||||
PRUint32 ChildDocumentCount() const
|
||||
{ return mChildDocuments.Length(); }
|
||||
|
||||
/**
|
||||
* Return the child document at the given index.
|
||||
*/
|
||||
nsDocAccessible* GetChildDocumentAt(PRUint32 aIndex) const
|
||||
{ return mChildDocuments.SafeElementAt(aIndex, nsnull); }
|
||||
|
||||
/**
|
||||
* Non-virtual method to fire a delayed event after a 0 length timeout.
|
||||
*
|
||||
@ -188,6 +206,12 @@ public:
|
||||
*/
|
||||
nsAccessible* GetCachedAccessible(void *aUniqueID);
|
||||
|
||||
/**
|
||||
* Return the cached accessible by the given unique ID looking through
|
||||
* this and nested documents.
|
||||
*/
|
||||
nsAccessible* GetCachedAccessibleInSubtree(void* aUniqueID);
|
||||
|
||||
/**
|
||||
* Cache the accessible.
|
||||
*
|
||||
@ -217,6 +241,24 @@ protected:
|
||||
void AddScrollListener();
|
||||
void RemoveScrollListener();
|
||||
|
||||
/**
|
||||
* Append the given document accessible to this document's child document
|
||||
* accessibles.
|
||||
*/
|
||||
bool AppendChildDocument(nsDocAccessible* aChildDocument)
|
||||
{
|
||||
return mChildDocuments.AppendElement(aChildDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given document accessible from this document's child document
|
||||
* accessibles.
|
||||
*/
|
||||
void RemoveChildDocument(nsDocAccessible* aChildDocument)
|
||||
{
|
||||
mChildDocuments.RemoveElement(aChildDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate parent-child relations for any cached accessible in the DOM
|
||||
* subtree. Accessible objects aren't destroyed.
|
||||
@ -337,6 +379,8 @@ protected:
|
||||
|
||||
static PRUint32 gLastFocusedAccessiblesState;
|
||||
static nsIAtom *gLastFocusedFrameType;
|
||||
|
||||
nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
|
||||
|
@ -282,24 +282,21 @@ STDMETHODIMP nsAccessibleWrap::get_accChild(
|
||||
{
|
||||
__try {
|
||||
*ppdispChild = NULL;
|
||||
if (!mWeakShell || varChild.vt != VT_I4)
|
||||
if (IsDefunct())
|
||||
return E_FAIL;
|
||||
|
||||
if (varChild.lVal == CHILDID_SELF) {
|
||||
*ppdispChild = static_cast<IDispatch*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
// IAccessible::accChild is used to return this accessible or child accessible
|
||||
// at the given index or to get an accessible by child ID in the case of
|
||||
// document accessible (it's handled by overriden GetXPAccessibleFor method
|
||||
// on the document accessible). The getting an accessible by child ID is used
|
||||
// by AccessibleObjectFromEvent() called by AT when AT handles our MSAA event.
|
||||
nsAccessible* child = GetXPAccessibleFor(varChild);
|
||||
if (child)
|
||||
*ppdispChild = NativeAccessible(child);
|
||||
|
||||
if (!nsAccUtils::MustPrune(this)) {
|
||||
nsAccessible* child = GetChildAt(varChild.lVal - 1);
|
||||
if (child) {
|
||||
*ppdispChild = NativeAccessible(child);
|
||||
}
|
||||
}
|
||||
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
|
||||
|
||||
return (*ppdispChild)? S_OK: E_FAIL;
|
||||
return (*ppdispChild)? S_OK: E_INVALIDARG;
|
||||
}
|
||||
|
||||
STDMETHODIMP nsAccessibleWrap::get_accName(
|
||||
@ -1804,7 +1801,7 @@ nsAccessibleWrap::UnattachIEnumVariant()
|
||||
nsAccessible*
|
||||
nsAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
|
||||
{
|
||||
if (IsDefunct())
|
||||
if (aVarChild.vt != VT_I4)
|
||||
return nsnull;
|
||||
|
||||
// if its us real easy - this seems to always be the case
|
||||
|
@ -103,39 +103,13 @@ nsDocAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
|
||||
// accessible through whole accessible subtree including subdocuments.
|
||||
// Otherwise we treat lVal as index in parent.
|
||||
|
||||
if (aVarChild.lVal < 0)
|
||||
return IsDefunct() ? nsnull : GetXPAccessibleForChildID(aVarChild);
|
||||
|
||||
return nsAccessibleWrap::GetXPAccessibleFor(aVarChild);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsDocAccessibleWrap::get_accChild(VARIANT varChild,
|
||||
IDispatch __RPC_FAR *__RPC_FAR *ppdispChild)
|
||||
{
|
||||
__try {
|
||||
*ppdispChild = NULL;
|
||||
|
||||
if (varChild.vt == VT_I4 && varChild.lVal < 0) {
|
||||
// IAccessible::accChild can be used to get an accessible by child ID.
|
||||
// It is used by AccessibleObjectFromEvent() called by AT when AT handles
|
||||
// our MSAA event.
|
||||
|
||||
nsAccessible *xpAccessible = GetXPAccessibleForChildID(varChild);
|
||||
if (!xpAccessible)
|
||||
return E_FAIL;
|
||||
|
||||
IAccessible *msaaAccessible = NULL;
|
||||
xpAccessible->GetNativeInterface((void**)&msaaAccessible);
|
||||
*ppdispChild = static_cast<IDispatch*>(msaaAccessible);
|
||||
|
||||
return S_OK;
|
||||
if (aVarChild.vt == VT_I4 && aVarChild.lVal < 0) {
|
||||
// Convert child ID to unique ID.
|
||||
void* uniqueID = reinterpret_cast<void*>(-aVarChild.lVal);
|
||||
return GetCachedAccessibleInSubtree(uniqueID);
|
||||
}
|
||||
|
||||
// Otherwise, the normal get_accChild() will do
|
||||
return nsAccessibleWrap::get_accChild(varChild, ppdispChild);
|
||||
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
|
||||
return E_FAIL;
|
||||
return nsAccessibleWrap::GetXPAccessibleFor(aVarChild);
|
||||
}
|
||||
|
||||
STDMETHODIMP nsDocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
|
||||
@ -271,14 +245,3 @@ STDMETHODIMP nsDocAccessibleWrap::get_accValue(
|
||||
|
||||
return get_URL(pszValue);
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsDocAccessibleWrap::GetXPAccessibleForChildID(const VARIANT& aVarChild)
|
||||
{
|
||||
NS_PRECONDITION(aVarChild.vt == VT_I4 && aVarChild.lVal < 0,
|
||||
"Variant doesn't point to child ID!");
|
||||
|
||||
// Convert child ID to unique ID.
|
||||
void *uniqueID = reinterpret_cast<void*>(-aVarChild.lVal);
|
||||
return GetAccService()->FindAccessibleInCache(uniqueID);
|
||||
}
|
||||
|
@ -83,10 +83,6 @@ public:
|
||||
/* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
|
||||
|
||||
// IAccessible
|
||||
// Override get_accChild so that it can get any child via the unique ID
|
||||
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild(
|
||||
/* [in] */ VARIANT varChild,
|
||||
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild);
|
||||
|
||||
// Override get_accValue to provide URL when no other value is available
|
||||
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
|
||||
@ -95,15 +91,6 @@ public:
|
||||
|
||||
// nsAccessibleWrap
|
||||
virtual nsAccessible *GetXPAccessibleFor(const VARIANT& varChild);
|
||||
|
||||
// nsDocAccessibleWrap
|
||||
|
||||
/**
|
||||
* Find an accessible by the given child ID in cached documents.
|
||||
*
|
||||
* @param aVarChild [in] variant pointing to the child ID
|
||||
*/
|
||||
static nsAccessible *GetXPAccessibleForChildID(const VARIANT& aVarChild);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -4,7 +4,7 @@
|
||||
<!-- Firefox tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||
type="text/css"?>
|
||||
<!-- Seamonkey tabbrowser -->
|
||||
<!-- SeaMonkey tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<!-- Firefox tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||
type="text/css"?>
|
||||
<!-- Seamonkey tabbrowser -->
|
||||
<!-- SeaMonkey tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
@ -13,11 +13,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=418368
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/role.js"></script>
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/states.js"></script>
|
||||
src="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function testThis(aID, aAcc, aRole, aAnchors, aName, aValid, aStartIndex,
|
||||
|
@ -12,11 +12,11 @@
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/common.js" />
|
||||
src="../common.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/role.js" />
|
||||
src="../role.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/states.js" />
|
||||
src="../states.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
@ -4,7 +4,7 @@
|
||||
<!-- Firefox tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||
type="text/css"?>
|
||||
<!-- Seamonkey tabbrowser -->
|
||||
<!-- SeaMonkey tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
@ -2,8 +2,13 @@
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<!-- Firefox tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||
type="text/css"?>
|
||||
<!-- SeaMonkey tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Accessible XUL tabbrowser relation tests">
|
||||
|
@ -2,8 +2,7 @@
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/treeview.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="../treeview.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="XUL tree selectable tests">
|
||||
|
@ -2,8 +2,7 @@
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/treeview.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="../treeview.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="XUL tree selectable tests">
|
||||
|
@ -2,8 +2,7 @@
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/treeview.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="../treeview.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="XUL tree selectable tests">
|
||||
|
@ -53,6 +53,7 @@ _TEST_FILES =\
|
||||
test_colorpicker.xul \
|
||||
test_combobox.xul \
|
||||
test_cssoverflow.html \
|
||||
test_dochierarchy.html \
|
||||
test_filectrl.html \
|
||||
test_formctrl.html \
|
||||
test_formctrl.xul \
|
||||
|
83
accessible/tests/mochitest/tree/test_dochierarchy.html
Normal file
83
accessible/tests/mochitest/tree/test_dochierarchy.html
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test document hierarchy</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
// tabDoc and testDoc are different documents depending on whether test
|
||||
// is running in standalone mode or not.
|
||||
|
||||
var root = getRootAccessible();
|
||||
var tabDoc = window.parent ?
|
||||
getAccessible(window.parent.document, [nsIAccessibleDocument]) :
|
||||
getAccessible(document, [nsIAccessibleDocument]);
|
||||
var testDoc = getAccessible(document, [nsIAccessibleDocument]);
|
||||
var iframeDoc = getAccessible("iframe").firstChild.
|
||||
QueryInterface(nsIAccessibleDocument);
|
||||
|
||||
is(root.parentDocument, null,
|
||||
"Wrong parent document of root accessible");
|
||||
is(root.childDocumentCount, 1,
|
||||
"Wrong child document count of root accessible");
|
||||
is(root.getChildDocumentAt(0), tabDoc,
|
||||
"Wrong child document at index 0 of root accessible");
|
||||
|
||||
is(tabDoc.parentDocument, root,
|
||||
"Wrong parent document of tab document");
|
||||
is(tabDoc.childDocumentCount, 1,
|
||||
"Wrong child document count of tab document");
|
||||
is(tabDoc.getChildDocumentAt(0), (tabDoc == testDoc ? iframeDoc : testDoc),
|
||||
"Wrong child document at index 0 of tab document");
|
||||
|
||||
if (tabDoc != testDoc) {
|
||||
is(testDoc.parentDocument, tabDoc,
|
||||
"Wrong parent document of test document");
|
||||
is(testDoc.childDocumentCount, 1,
|
||||
"Wrong child document count of test document");
|
||||
is(testDoc.getChildDocumentAt(0), iframeDoc,
|
||||
"Wrong child document at index 0 of test document");
|
||||
}
|
||||
|
||||
is(iframeDoc.parentDocument, (tabDoc == testDoc ? tabDoc : testDoc),
|
||||
"Wrong parent document of iframe document");
|
||||
is(iframeDoc.childDocumentCount, 0,
|
||||
"Wrong child document count of iframe document");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=592913"
|
||||
title="Provide a way to quickly determine whether an accessible object is a descendant of a tab document">
|
||||
Mozilla Bug 592913
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<iframe src="about:mozilla" id="iframe"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -4,7 +4,7 @@
|
||||
<!-- Firefox tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||
type="text/css"?>
|
||||
<!-- Seamonkey tabbrowser -->
|
||||
<!-- SeaMonkey tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
@ -172,7 +172,7 @@ image.study-result {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 2px;
|
||||
-moz-border-radius: 10000px;
|
||||
border-radius: 10000px;
|
||||
margin-right: 25px;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ src: url('chrome://testpilot/skin/fonts/DroidSans-Bold.ttf') format('truetype');
|
||||
font-size: 16px;
|
||||
padding: 8px 12px;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-moz-box-shadow:
|
||||
inset rgba(0, 0, 0, 0.2) 0 1px 1px,
|
||||
@ -122,7 +122,7 @@ src: url('chrome://testpilot/skin/fonts/DroidSans-Bold.ttf') format('truetype');
|
||||
padding: 8px 12px;
|
||||
width: 240px;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-moz-box-shadow:
|
||||
inset rgba(0, 0, 0, 0.2) 0 1px 1px,
|
||||
@ -143,7 +143,7 @@ src: url('chrome://testpilot/skin/fonts/DroidSans-Bold.ttf') format('truetype');
|
||||
padding: 8px 24px;
|
||||
margin: 24px auto;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
background: rgba(220, 240, 247, 0.8) url('chrome://testpilot/skin/callout.png') no-repeat top center;
|
||||
-moz-box-shadow:
|
||||
@ -161,7 +161,7 @@ src: url('chrome://testpilot/skin/fonts/DroidSans-Bold.ttf') format('truetype');
|
||||
padding: 8px 24px;
|
||||
margin: 8px auto;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
background: rgba(220, 240, 247, 0.8) url('chrome://testpilot/skin/callout.png') no-repeat top center;
|
||||
-moz-box-shadow:
|
||||
@ -197,7 +197,7 @@ src: url('chrome://testpilot/skin/fonts/DroidSans-Bold.ttf') format('truetype');
|
||||
padding: 4px 40px;
|
||||
width: 800px;
|
||||
text-align: left;
|
||||
-moz-border-radius: 0.25em;
|
||||
border-radius: 0.25em;
|
||||
-webkit-border-radius: 0.25em;
|
||||
border-top: 1px solid #adb6ba;
|
||||
border-left: 1px solid #adb6ba;
|
||||
|
@ -13,7 +13,7 @@
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>3.5</em:minVersion>
|
||||
<em:maxVersion>4.0b5</em:maxVersion>
|
||||
<em:maxVersion>4.0.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
@ -52,7 +52,7 @@ body {
|
||||
.dataBox {
|
||||
font-size: 16px;
|
||||
padding: 6px 20px 20px 20px;
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
background: rgba(220, 240, 247, 0.8) url('chrome://testpilot/skin/images/callout.png') no-repeat top center;
|
||||
//display: inline;
|
||||
@ -113,7 +113,7 @@ body {
|
||||
font-size: 16px;
|
||||
padding: 8px 12px;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-moz-box-shadow:
|
||||
inset rgba(0, 0, 0, 0.2) 0 1px 1px,
|
||||
@ -132,7 +132,7 @@ body {
|
||||
padding: 8px 12px;
|
||||
width: 240px;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-moz-box-shadow:
|
||||
inset rgba(0, 0, 0, 0.2) 0 1px 1px,
|
||||
@ -151,7 +151,7 @@ body {
|
||||
padding: 8px 24px;
|
||||
margin: 24px auto;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
background: rgba(220, 240, 247, 0.8) url('chrome://testpilot/skin/images/callout.png') no-repeat top center;
|
||||
-moz-box-shadow:
|
||||
@ -173,7 +173,7 @@ body {
|
||||
padding: 8px 24px;
|
||||
margin: 8px auto;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
background: rgba(220, 240, 247, 0.8) url('chrome://testpilot/skin/images/callout.png') no-repeat top center;
|
||||
-moz-box-shadow:
|
||||
@ -190,7 +190,7 @@ body {
|
||||
padding: 8px 24px;
|
||||
margin: 8px auto;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
-moz-border-radius: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
background: rgba(220, 240, 247, 0.8) url('chrome://testpilot/skin/images/callout_continue.png') no-repeat top center;
|
||||
-moz-box-shadow:
|
||||
@ -237,7 +237,7 @@ body {
|
||||
padding: 4px 40px;
|
||||
width: 800px;
|
||||
text-align: left;
|
||||
-moz-border-radius: 0.25em;
|
||||
border-radius: 0.25em;
|
||||
-webkit-border-radius: 0.25em;
|
||||
border-top: 1px solid #adb6ba;
|
||||
border-left: 1px solid #adb6ba;
|
||||
|
@ -8,7 +8,7 @@
|
||||
background-image: -moz-linear-gradient(hsla(0,0%,100%,.2), transparent);
|
||||
-moz-box-shadow: inset 0 0 10px hsla(0,0%,100%,.2),
|
||||
inset 0 1px 0 hsla(0,0%,100%,.3);
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid Menu;
|
||||
margin: -6px 0 0 0;
|
||||
width: 480px;
|
||||
|
@ -7,7 +7,7 @@
|
||||
rgba(60,60,60,.9) 51%, rgba(50,50,50,.9));
|
||||
background-clip: padding-box;
|
||||
background-origin: padding-box;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(0,0,0,.65);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2),
|
||||
inset 0 0 1px rgba(255,255,255,.1),
|
||||
|
@ -395,11 +395,9 @@ pref("browser.bookmarks.max_backups", 10);
|
||||
|
||||
// Scripts & Windows prefs
|
||||
pref("dom.disable_open_during_load", true);
|
||||
#ifdef DEBUG
|
||||
pref("javascript.options.showInConsole", true);
|
||||
#ifdef DEBUG
|
||||
pref("general.warnOnAboutConfig", false);
|
||||
#else
|
||||
pref("javascript.options.showInConsole", false);
|
||||
#endif
|
||||
|
||||
#ifdef WINCE
|
||||
@ -782,6 +780,8 @@ pref("browser.sessionstore.postdata", 0);
|
||||
// on which sites to save text data, POSTDATA and cookies
|
||||
// 0 = everywhere, 1 = unencrypted sites, 2 = nowhere
|
||||
pref("browser.sessionstore.privacy_level", 1);
|
||||
// the same as browser.sessionstore.privacy_level, but for saving deferred session data
|
||||
pref("browser.sessionstore.privacy_level_deferred", 2);
|
||||
// how many tabs can be reopened (per window)
|
||||
pref("browser.sessionstore.max_tabs_undo", 10);
|
||||
// how many windows can be reopened (per session) - on non-OS X platforms this
|
||||
@ -1030,3 +1030,9 @@ pref("services.sync.prefs.sync.signon.rememberSignons", true);
|
||||
pref("services.sync.prefs.sync.spellchecker.dictionary", true);
|
||||
pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
|
||||
#endif
|
||||
|
||||
// Disable the Error Console
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
// disable the Inspector
|
||||
pref("devtools.inspector.enabled", false);
|
||||
|
@ -54,7 +54,7 @@ html {
|
||||
|
||||
#brandStart {
|
||||
background: -moz-linear-gradient(top, #42607C, #1E4262 30%, #1E4262 80%, #143552 98%, #244665);
|
||||
-moz-border-radius: 5.6px;
|
||||
border-radius: 5.6px;
|
||||
padding-bottom: 0.2em;
|
||||
-moz-padding-start: 0.5em;
|
||||
font-size: 250%;
|
||||
@ -82,7 +82,7 @@ body[dir="rtl"] #brandStart:before {
|
||||
|
||||
#searchContainer {
|
||||
border: 1px solid ThreeDShadow;
|
||||
-moz-border-radius: 5.6px;
|
||||
border-radius: 5.6px;
|
||||
padding: 3em;
|
||||
}
|
||||
#searchEngineLinks {
|
||||
|
@ -41,7 +41,7 @@
|
||||
const SEARCH_ENGINES = {
|
||||
"Google": {
|
||||
image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAAAYCAMAAABwdHsxAAADAFBMVEVogZYwjM9NtOspS2u0KAfYZBb3rRTiurCMjYrUWhIaPlzDNgfVRgjaVgvoizTI9f2ta17/9Wzrs0v46M/+7VOW6vrJQAsBLochdr+nmF/++o+UDQK88vzaYQarq6scarXT+f68vLzjdRrjewp5d3WqGATkUwaTq9uk7PnUaydkICTJSBD4uCDgZAz9+LiK6PjRZFH33Xv01qbrlxznhgvwx5gCBCbOUhLjfCzhaxHztXG8RhX93UP5yTRGl9QhRGT5wigkRmXniRj70zoKWrT2yUdqjs3UhzXvl0JwU0teu+EBElGD2fH83FZo1vTPilT0vDmd0Z3dbhrWrHLhcQir8PzTTDfPrVGrajv03cf5+vkwUG6z8PrSUw571uzvpCGPTzBsPDMxMEcHagXrkg7voBHf/P8FGHHhzrbyryOQZAeDNCudnZyTJBL2zlT+xByoUCG1wspyY1nRiH7STA3yiB7Jjx/pqT/Pz8/7lhDvfBxTUkl95PY/RE0DI2SQbT7LzJjxdg1OMTzutynnm2v+5DWsNBX+/tVDqOa7tnX57OPGYSHysziEo5a3XBe3l3j+0SXCoaCsjTL++fMgQmLmxXdv0ezsv0ycQxf8p0X1hwrenDU/Tnj9//tkyNj3+fX89fDv22QXHEWQydee7/xEdKG84uRWi5bwaxyK3/L++/iU5PMWM2Q6GS7UXg81l9gmSGgXOVewsKO3x+ECK8h8x3j7/fs5bMBke6kuTmwoRV/SbArKeSrB1snY373x5aSIRz85YIvragDD5+lnorUvSWF80PCQr6o4KGKysrIeQmIgXJ1Vb4j///8+XXjs7ewaUZSutsKFkqY4T3IhXqgYSHtwiJwUNVLExcbk5eU4SGcrcLEsP1wPKV77+/vy8/NBkcBmrN+drLklNGIONHQ5WXVxyuk0VXHHz9dmxuonZahTrNqPobEcP19CVXMURIljzvE/odz29vYcP3VieZHo6OhCYHxOW29y2vNYwe79/f33+PnU2eExgcLX2Nje397NKLzjAAACjElEQVR42q2UMWvbQBTHPRgro6CDKIJOPQSeVH+CDuZ2E3BIVmNkBB5agTF0NYV00y7jdMji0XqxvNljAzmEPASrQ0Vwhk41tPZiC6l3OjmNXYeYujfo3nF3v/fe/+le5hX5HyOTzv1Of88bnXelq0q8C9NRHMcpFrHd3gPTD0qV17uisWeDqE269gyguU88pcrRDowNXrqYTt1/xkQwXi8mZ2Q/TO9vDNa2FVkJLUPocDsYDoe1lB6EURzZ4RrDThHi0RF7mRh+bFGirCEYCJnMLpzUase5XI2aZxhjKM6wS64YJlDZqWxAPEq6ztjFm01KEzGdTxGirgoNFpRfrU7IEg8IiQFoqRlmqYp0p4VGDEO8zB1sYoLyKJlFVCdxjotwntNpISJqYfjKMQKi1fDVvJlqg2G6gWmh98l8iuRoWL1O7Bc53b2TJoSFc88xquwKqig8SGyDFvxRMGyriEdDUF140+DR9HN6hGHOBJIsjinLpvHoV84EIPGCL/ClAzOiojzfKeejz9WX3H6ru98Td6GWaqOi3lbBQQsTlyzzOU1ajjimTgpUkxRDN7Uvtl1kmTGMgT5+28BcAAC/SBSJBl7mWS1kkwRVnpWvs8n1HP6nMswFQmJyp71+DK4mgZ0ssEarFsiyQe0sg9V03acnG2luClgcQx+DKaOyTwTjAUNiS5OKWFGwZbGYw5GsiqKYNI6erp8XTo7TGigAToecVSofjvrEzMuyPBIe9xvXux2MvXCZZroQhNU6a7/mJ5VsK87l+FaD2TLpTvTTbTbj7bb13PiJZ0zAT+u6PtH9nhuKxD270s0hGAfSBOCgaJLHxDrlffcQzOoXSKyYjksOwdDWOLcG2H5i8zf27La6kVLrqwAAAABJRU5ErkJggg=="
|
||||
, params: "source=hp"
|
||||
, params: "source=hp&channel=np"
|
||||
, links: {
|
||||
advanced: "http://www.google.com/advanced_search"
|
||||
, preferences: "http://www.google.com/preferences"
|
||||
|
@ -397,6 +397,11 @@
|
||||
oncommand="BrowserOpenSyncTabs();"
|
||||
disabled="true"/>
|
||||
#endif
|
||||
<menuitem id="historyRestoreLastSession"
|
||||
class="restoreLastSession"
|
||||
label="&historyRestoreLastSession.label;"
|
||||
oncommand="restoreLastSession();"
|
||||
disabled="true"/>
|
||||
<menu id="historyUndoMenu"
|
||||
class="recentlyClosedTabsMenu"
|
||||
label="&historyUndoMenu.label;"
|
||||
@ -535,11 +540,13 @@
|
||||
<menuseparator id="devToolsSeparator"/>
|
||||
<menuitem id="menu_pageinspect"
|
||||
type="checkbox"
|
||||
hidden="true"
|
||||
label="&inspectMenu.label;"
|
||||
accesskey="&inspectMenu.accesskey;"
|
||||
key="key_inspect"
|
||||
command="Tools:Inspect"/>
|
||||
<menuitem id="javascriptConsole"
|
||||
hidden="true"
|
||||
label="&errorConsoleCmd.label;"
|
||||
accesskey="&errorConsoleCmd.accesskey;"
|
||||
key="key_errorConsole"
|
||||
|
@ -758,6 +758,15 @@ HistoryMenu.prototype = {
|
||||
#endif
|
||||
},
|
||||
|
||||
toggleRestoreLastSession: function PHM_toggleRestoreLastSession() {
|
||||
let restoreItem = this._rootElt.getElementsByClassName("restoreLastSession")[0];
|
||||
|
||||
if (this._ss.canRestoreLastSession)
|
||||
restoreItem.removeAttribute("disabled");
|
||||
else
|
||||
restoreItem.setAttribute("disabled", true);
|
||||
},
|
||||
|
||||
_onPopupShowing: function HM__onPopupShowing(aEvent) {
|
||||
PlacesMenu.prototype._onPopupShowing.apply(this, arguments);
|
||||
|
||||
@ -768,6 +777,7 @@ HistoryMenu.prototype = {
|
||||
this.toggleRecentlyClosedTabs();
|
||||
this.toggleRecentlyClosedWindows();
|
||||
this.toggleTabsFromOtherComputers();
|
||||
this.toggleRestoreLastSession();
|
||||
},
|
||||
|
||||
_onCommand: function HM__onCommand(aEvent) {
|
||||
|
@ -126,7 +126,7 @@
|
||||
|
||||
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
|
||||
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
|
||||
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();"/>
|
||||
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
|
||||
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
|
||||
<command id="Tools:Sanitize"
|
||||
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
|
||||
@ -236,7 +236,7 @@
|
||||
<key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
|
||||
#endif
|
||||
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
|
||||
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift"/>
|
||||
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
|
||||
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();" modifiers="accel,shift"/>
|
||||
<key id="key_inspect" key="&inspectMenu.commandkey;" command="Tools:Inspect" modifiers="accel,shift"/>
|
||||
<key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile" modifiers="accel"/>
|
||||
|
@ -150,8 +150,11 @@ let TabView = {
|
||||
let activeGroup = tab.tabItem.parent;
|
||||
let groupItems = self._window.GroupItems.groupItems;
|
||||
|
||||
groupItems.forEach(function(groupItem) {
|
||||
if (groupItem.getTitle().length > 0 &&
|
||||
groupItems.forEach(function(groupItem) {
|
||||
// if group has title, it's not hidden and there is no active group or
|
||||
// the active group id doesn't match the group id, a group menu item
|
||||
// would be added.
|
||||
if (groupItem.getTitle().length > 0 && !groupItem.hidden &&
|
||||
(!activeGroup || activeGroup.id != groupItem.id)) {
|
||||
let menuItem = self._createGroupMenuItem(groupItem);
|
||||
popup.insertBefore(menuItem, separator);
|
||||
|
@ -366,7 +366,9 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
||||
}
|
||||
|
||||
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
|
||||
#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon {
|
||||
#notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
|
||||
#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
|
||||
#notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
|
@ -1321,6 +1321,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
IndexedDBPromptHelper.init();
|
||||
|
||||
gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
|
||||
|
||||
@ -1513,6 +1514,23 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
|
||||
TabView.init();
|
||||
|
||||
// Enable Inspector?
|
||||
let enabled = gPrefService.getBoolPref(InspectorUI.prefEnabledName);
|
||||
if (enabled) {
|
||||
document.getElementById("menu_pageinspect").setAttribute("hidden", false);
|
||||
document.getElementById("Tools:Inspect").removeAttribute("disabled");
|
||||
let appMenuInspect = document.getElementById("appmenu_pageInspect");
|
||||
if (appMenuInspect)
|
||||
appMenuInspect.setAttribute("hidden", false);
|
||||
}
|
||||
|
||||
// Enable Error Console?
|
||||
let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled");
|
||||
if (consoleEnabled) {
|
||||
document.getElementById("javascriptConsole").hidden = false;
|
||||
document.getElementById("key_errorConsole").removeAttribute("disabled");
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
|
||||
}
|
||||
|
||||
@ -1563,6 +1581,7 @@ function BrowserShutdown()
|
||||
OfflineApps.uninit();
|
||||
DownloadMonitorPanel.uninit();
|
||||
gPrivateBrowsingUI.uninit();
|
||||
IndexedDBPromptHelper.uninit();
|
||||
|
||||
var enumerator = Services.wm.getEnumerator(null);
|
||||
enumerator.getNext();
|
||||
@ -2870,25 +2889,7 @@ var browserDragAndDrop = {
|
||||
},
|
||||
|
||||
drop: function (aEvent, aName) Services.droppedLinkHandler.dropLink(aEvent, aName)
|
||||
}
|
||||
|
||||
var proxyIconDNDObserver = {
|
||||
onDragStart: function (aEvent, aXferData, aDragAction)
|
||||
{
|
||||
if (gProxyFavIcon.getAttribute("pageproxystate") != "valid")
|
||||
return;
|
||||
|
||||
var value = content.location.href;
|
||||
var urlString = value + "\n" + content.document.title;
|
||||
var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
|
||||
|
||||
var dt = aEvent.dataTransfer;
|
||||
dt.setData("text/x-moz-url", urlString);
|
||||
dt.setData("text/uri-list", value);
|
||||
dt.setData("text/plain", value);
|
||||
dt.setData("text/html", htmlString);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var homeButtonObserver = {
|
||||
onDrop: function (aEvent)
|
||||
@ -5853,6 +5854,92 @@ var OfflineApps = {
|
||||
}
|
||||
};
|
||||
|
||||
var IndexedDBPromptHelper = {
|
||||
_permissionsPrompt: "indexedDB-permissions-prompt",
|
||||
_permissionsResponse: "indexedDB-permissions-response",
|
||||
|
||||
_quotaPrompt: "indexedDB-quota-prompt",
|
||||
_quotaResponse: "indexedDB-quota-response",
|
||||
|
||||
_notificationIcon: "indexedDB-notification-icon",
|
||||
|
||||
init:
|
||||
function IndexedDBPromptHelper_init() {
|
||||
Services.obs.addObserver(this, this._permissionsPrompt, false);
|
||||
Services.obs.addObserver(this, this._quotaPrompt, false);
|
||||
},
|
||||
|
||||
uninit:
|
||||
function IndexedDBPromptHelper_uninit() {
|
||||
Services.obs.removeObserver(this, this._permissionsPrompt, false);
|
||||
Services.obs.removeObserver(this, this._quotaPrompt, false);
|
||||
},
|
||||
|
||||
observe:
|
||||
function IndexedDBPromptHelper_observe(subject, topic, data) {
|
||||
if (topic != this._permissionsPrompt &&
|
||||
topic != this._quotaPrompt) {
|
||||
throw new Error("Unexpected topic!");
|
||||
}
|
||||
|
||||
var requestor = subject.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
|
||||
var contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
|
||||
var contentDocument = contentWindow.document;
|
||||
var browserWindow =
|
||||
OfflineApps._getBrowserWindowForContentWindow(contentWindow);
|
||||
var browser =
|
||||
OfflineApps._getBrowserForContentWindow(browserWindow, contentWindow);
|
||||
|
||||
if (!browser) {
|
||||
// Must belong to some other window.
|
||||
return;
|
||||
}
|
||||
|
||||
var host = contentDocument.documentURIObject.asciiHost;
|
||||
|
||||
var message;
|
||||
var responseTopic;
|
||||
if (topic == this._permissionsPrompt) {
|
||||
message = gNavigatorBundle.getFormattedString("offlineApps.available",
|
||||
[ host ]);
|
||||
responseTopic = this._permissionsResponse;
|
||||
}
|
||||
else if (topic == this._quotaPrompt) {
|
||||
message = gNavigatorBundle.getFormattedString("indexedDB.usage",
|
||||
[ host, data ]);
|
||||
responseTopic = this._quotaResponse;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var observer = requestor.getInterface(Ci.nsIObserver);
|
||||
|
||||
var mainAction = {
|
||||
label: gNavigatorBundle.getString("offlineApps.allow"),
|
||||
accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"),
|
||||
callback: function() {
|
||||
observer.observe(null, responseTopic,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
};
|
||||
|
||||
var secondaryActions = [
|
||||
{
|
||||
label: gNavigatorBundle.getString("offlineApps.never"),
|
||||
accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"),
|
||||
callback: function() {
|
||||
observer.observe(null, responseTopic,
|
||||
Ci.nsIPermissionManager.DENY_ACTION);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
PopupNotifications.show(browser, topic, message, this._notificationIcon,
|
||||
mainAction, secondaryActions);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function WindowIsClosing()
|
||||
{
|
||||
var reallyClose = closeWindow(false, warnAboutClosingWindow);
|
||||
@ -7225,6 +7312,22 @@ var gIdentityHandler = {
|
||||
|
||||
// Now open the popup, anchored off the primary chrome element
|
||||
this._identityPopup.openPopup(this._identityBox, position);
|
||||
},
|
||||
|
||||
onDragStart: function (event) {
|
||||
if (gURLBar.getAttribute("pageproxystate") != "valid")
|
||||
return;
|
||||
|
||||
var value = content.location.href;
|
||||
var urlString = value + "\n" + content.document.title;
|
||||
var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
|
||||
|
||||
var dt = event.dataTransfer;
|
||||
dt.setData("text/x-moz-url", urlString);
|
||||
dt.setData("text/uri-list", value);
|
||||
dt.setData("text/plain", value);
|
||||
dt.setData("text/html", htmlString);
|
||||
dt.setDragImage(event.currentTarget, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -7886,6 +7989,12 @@ function switchToTabHavingURI(aURI, aOpenNew, aCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function restoreLastSession() {
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
ss.restoreLastSession();
|
||||
}
|
||||
|
||||
var TabContextMenu = {
|
||||
contextTab: null,
|
||||
updateContextMenu: function updateContextMenu(aPopupMenu) {
|
||||
|
@ -120,11 +120,11 @@
|
||||
accesskey="&openTabInNewWindow.accesskey;"
|
||||
tbattr="tabbrowser-multiple"
|
||||
oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
|
||||
<menuitem id="context_pinTab" label="&pinTab.label;"
|
||||
accesskey="&pinTab.accesskey;"
|
||||
<menuitem id="context_pinTab" label="&pinAppTab.label;"
|
||||
accesskey="&pinAppTab.accesskey;"
|
||||
oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
|
||||
<menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
|
||||
accesskey="&unpinTab.accesskey;"
|
||||
<menuitem id="context_unpinTab" label="&unpinAppTab.label;" hidden="true"
|
||||
accesskey="&unpinAppTab.accesskey;"
|
||||
oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
|
||||
<menu id="context_tabViewMenu" label="&moveToGroup.label;"
|
||||
accesskey="&moveToGroup.accesskey;">
|
||||
@ -268,12 +268,7 @@
|
||||
class="toolbarbutton-text"
|
||||
oncommand="InspectorUI.toggleDOMPanel();"/>
|
||||
</toolbar>
|
||||
<iframe id="inspector-tree-iframe"
|
||||
flex="1"
|
||||
type="content"
|
||||
src="chrome://browser/content/inspector.html"
|
||||
onclick="InspectorUI.onTreeClick(event);" />
|
||||
<hbox align="end">
|
||||
<hbox id="tree-panel-resizer-box" align="end">
|
||||
<spacer flex="1" />
|
||||
<resizer dir="bottomend" />
|
||||
</hbox>
|
||||
@ -451,8 +446,8 @@
|
||||
<vbox id="appmenuPrimaryPane">
|
||||
<hbox flex="1"
|
||||
class="split-menuitem">
|
||||
<menuitem id="menuitem-tooltip appmenu_newTab"
|
||||
class="split-menuitem-item"
|
||||
<menuitem id="appmenu_newTab"
|
||||
class="menuitem-tooltip split-menuitem-item"
|
||||
flex="1"
|
||||
label="&tabCmd.label;"
|
||||
command="cmd_newNavigatorTab"
|
||||
@ -483,9 +478,9 @@
|
||||
command="Tools:PrivateBrowsing"
|
||||
key="key_privatebrowsing"/>
|
||||
<menuseparator class="appmenu-menuseparator"/>
|
||||
<hbox class="split-menuitem">
|
||||
<menuitem id="appmenu-edit-menuitem"
|
||||
label="&editMenu.label;"
|
||||
<hbox>
|
||||
<menuitem id="appmenu-edit-label"
|
||||
label="&appMenuEdit.label;"
|
||||
disabled="true"/>
|
||||
<toolbarbutton id="appmenu-cut"
|
||||
class="appmenu-edit-button"
|
||||
@ -530,7 +525,8 @@
|
||||
<menuitem id="appmenu_print_popup"
|
||||
class="menuitem-iconic"
|
||||
label="&printCmd.label;"
|
||||
command="cmd_print"/>
|
||||
command="cmd_print"
|
||||
key="printKb"/>
|
||||
<menuitem id="appmenu_printPreview"
|
||||
label="&printPreviewCmd.label;"
|
||||
command="cmd_printPreview"/>
|
||||
@ -550,6 +546,7 @@
|
||||
oncommand="HUDConsoleUI.toggleHUD();"
|
||||
key="key_webConsole"/>
|
||||
<menuitem id="appmenu_pageInspect"
|
||||
hidden="true"
|
||||
label="&inspectMenu.label;"
|
||||
type="checkbox"
|
||||
command="Tools:Inspect"
|
||||
@ -670,6 +667,11 @@
|
||||
key="key_sanitize"
|
||||
command="Tools:Sanitize"/>
|
||||
<menuseparator class="hide-if-empty-places-result"/>
|
||||
<menuitem id="appmenu_restoreLastSession"
|
||||
class="restoreLastSession"
|
||||
label="&historyRestoreLastSession.label;"
|
||||
oncommand="restoreLastSession();"
|
||||
disabled="true"/>
|
||||
<menu id="appmenu_recentlyClosedTabsMenu"
|
||||
class="recentlyClosedTabsMenu"
|
||||
label="&historyUndoMenu.label;"
|
||||
@ -879,6 +881,8 @@
|
||||
<box id="notification-popup-box" hidden="true" align="center">
|
||||
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="password-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.
|
||||
@ -886,14 +890,14 @@
|
||||
has focus, otherwise pressing F6 focuses it instead of the location bar -->
|
||||
<box id="identity-box" role="button"
|
||||
onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
|
||||
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);">
|
||||
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
|
||||
ondragstart="gIdentityHandler.onDragStart(event);">
|
||||
<hbox id="identity-box-inner" align="center">
|
||||
<stack id="page-proxy-stack"
|
||||
onclick="PageProxyClickHandler(event);">
|
||||
<image id="urlbar-throbber" busy="false"/>
|
||||
<image id="page-proxy-favicon" validate="never"
|
||||
pageproxystate="invalid"
|
||||
ondragstart="proxyIconDNDObserver.onDragStart(event);"
|
||||
onerror="this.removeAttribute('src');"/>
|
||||
</stack>
|
||||
<hbox id="identity-icon-labels">
|
||||
|
@ -335,6 +335,8 @@ var InspectorUI = {
|
||||
selectEventsSuppressed: false,
|
||||
showTextNodesWithWhitespace: false,
|
||||
inspecting: false,
|
||||
treeLoaded: false,
|
||||
prefEnabledName: "devtools.inspector.enabled",
|
||||
|
||||
/**
|
||||
* Toggle the inspector interface elements on or off.
|
||||
@ -434,6 +436,21 @@ var InspectorUI = {
|
||||
return doc.documentElement.lastElementChild;
|
||||
},
|
||||
|
||||
initializeTreePanel: function IUI_initializeTreePanel()
|
||||
{
|
||||
this.treeBrowserDocument = this.treeIFrame.contentDocument;
|
||||
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
|
||||
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
|
||||
this.treePanelDiv.ownerPanel = this;
|
||||
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
|
||||
this.ioBox.createObjectBox(this.win.document.documentElement);
|
||||
this.treeLoaded = true;
|
||||
if (this.isTreePanelOpen && this.isStylePanelOpen &&
|
||||
this.isDOMPanelOpen && this.treeLoaded) {
|
||||
this.notifyReady();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the inspector's tree panel and initialize it.
|
||||
*/
|
||||
@ -444,6 +461,17 @@ var InspectorUI = {
|
||||
this.treePanel.hidden = false;
|
||||
}
|
||||
|
||||
this.treeIFrame = document.getElementById("inspector-tree-iframe");
|
||||
if (!this.treeIFrame) {
|
||||
let resizerBox = document.getElementById("tree-panel-resizer-box");
|
||||
this.treeIFrame = document.createElement("iframe");
|
||||
this.treeIFrame.setAttribute("id", "inspector-tree-iframe");
|
||||
this.treeIFrame.setAttribute("flex", "1");
|
||||
this.treeIFrame.setAttribute("type", "content");
|
||||
this.treeIFrame.setAttribute("onclick", "InspectorUI.onTreeClick(event)");
|
||||
this.treeIFrame = this.treePanel.insertBefore(this.treeIFrame, resizerBox);
|
||||
}
|
||||
|
||||
const panelWidthRatio = 7 / 8;
|
||||
const panelHeightRatio = 1 / 5;
|
||||
this.treePanel.openPopup(this.browser, "overlap", 80, this.win.innerHeight,
|
||||
@ -451,13 +479,18 @@ var InspectorUI = {
|
||||
this.treePanel.sizeTo(this.win.outerWidth * panelWidthRatio,
|
||||
this.win.outerHeight * panelHeightRatio);
|
||||
|
||||
this.treeIFrame = document.getElementById("inspector-tree-iframe");
|
||||
this.treeBrowserDocument = this.treeIFrame.contentDocument;
|
||||
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
|
||||
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
|
||||
this.treePanelDiv.ownerPanel = this;
|
||||
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
|
||||
this.ioBox.createObjectBox(this.win.document.documentElement);
|
||||
let src = this.treeIFrame.getAttribute("src");
|
||||
if (src != "chrome://browser/content/inspector.html") {
|
||||
let self = this;
|
||||
this.treeIFrame.addEventListener("DOMContentLoaded", function() {
|
||||
self.treeIFrame.removeEventListener("DOMContentLoaded", arguments.callee, true);
|
||||
self.initializeTreePanel();
|
||||
}, true);
|
||||
|
||||
this.treeIFrame.setAttribute("src", "chrome://browser/content/inspector.html");
|
||||
} else {
|
||||
this.initializeTreePanel();
|
||||
}
|
||||
},
|
||||
|
||||
createObjectBox: function IUI_createObjectBox(object, isRoot)
|
||||
@ -773,6 +806,7 @@ var InspectorUI = {
|
||||
this.browser = this.win = null; // null out references to browser and window
|
||||
this.winID = null;
|
||||
this.selection = null;
|
||||
this.treeLoaded = false;
|
||||
this.closing = false;
|
||||
Services.obs.notifyObservers(null, "inspector-closed", null);
|
||||
},
|
||||
@ -964,6 +998,12 @@ var InspectorUI = {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//// Event Handling
|
||||
|
||||
notifyReady: function IUI_notifyReady()
|
||||
{
|
||||
document.removeEventListener("popupshowing", this, false);
|
||||
Services.obs.notifyObservers(null, "inspector-opened", null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Main callback handler for events.
|
||||
*
|
||||
@ -981,9 +1021,9 @@ var InspectorUI = {
|
||||
if (event.target.id == "inspector-tree-panel" ||
|
||||
event.target.id == "inspector-style-panel" ||
|
||||
event.target.id == "inspector-dom-panel")
|
||||
if (this.isTreePanelOpen && this.isStylePanelOpen && this.isDOMPanelOpen) {
|
||||
document.removeEventListener("popupshowing", this, false);
|
||||
Services.obs.notifyObservers(null, "inspector-opened", null);
|
||||
if (this.isTreePanelOpen && this.isStylePanelOpen &&
|
||||
this.isDOMPanelOpen && this.treeLoaded) {
|
||||
this.notifyReady();
|
||||
}
|
||||
break;
|
||||
case "TabSelect":
|
||||
|
@ -89,11 +89,13 @@
|
||||
<command id="cmd_cookieDef" oncommand="onCheckboxClick('cookie');"/>
|
||||
<command id="cmd_installDef" oncommand="onCheckboxClick('install');"/>
|
||||
<command id="cmd_geoDef" oncommand="onCheckboxClick('geo');"/>
|
||||
<command id="cmd_indexedDBDef" oncommand="onCheckboxClick('indexedDB');"/>
|
||||
<command id="cmd_imageToggle" oncommand="onRadioClick('image');"/>
|
||||
<command id="cmd_popupToggle" oncommand="onRadioClick('popup');"/>
|
||||
<command id="cmd_cookieToggle" oncommand="onRadioClick('cookie');"/>
|
||||
<command id="cmd_installToggle" oncommand="onRadioClick('install');"/>
|
||||
<command id="cmd_geoToggle" oncommand="onRadioClick('geo');"/>
|
||||
<command id="cmd_indexedDBToggle" oncommand="onRadioClick('indexedDB');"/>
|
||||
</commandset>
|
||||
|
||||
<keyset>
|
||||
@ -375,6 +377,23 @@
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox class="permission">
|
||||
<label class="permissionLabel" id="permIndexedDBLabel"
|
||||
value="&permIndexedDB;" control="indexedDBRadioGroup"/>
|
||||
<hbox role="group" aria-labelledby="permIndexedDBLabel">
|
||||
<checkbox id="indexedDBDef" command="cmd_indexedDBDef" label="&permAskAlways;"/>
|
||||
<spacer flex="1"/>
|
||||
<vbox pack="center">
|
||||
<label id="indexedDBStatus" control="indexedDBClear"/>
|
||||
</vbox>
|
||||
<button id="indexedDBClear" label="&permClearStorage;"
|
||||
accesskey="&permClearStorage.accesskey;" onclick="onIndexedDBClear();"/>
|
||||
<radiogroup id="indexedDBRadioGroup" orient="horizontal">
|
||||
<radio id="indexedDB#1" command="cmd_indexedDBToggle" label="&permAllow;"/>
|
||||
<radio id="indexedDB#2" command="cmd_indexedDBToggle" label="&permBlock;"/>
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
|
@ -36,6 +36,10 @@
|
||||
const ALLOW = nsIPermissionManager.ALLOW_ACTION; // 1
|
||||
const BLOCK = nsIPermissionManager.DENY_ACTION; // 2
|
||||
const SESSION = nsICookiePermission.ACCESS_SESSION;// 8
|
||||
|
||||
const nsIIndexedDatabaseManager =
|
||||
Components.interfaces.nsIIndexedDatabaseManager;
|
||||
|
||||
var gPermURI;
|
||||
var gPrefs;
|
||||
|
||||
@ -73,7 +77,11 @@ var gPermObj = {
|
||||
},
|
||||
geo: function getGeoDefaultPermissions()
|
||||
{
|
||||
return BLOCK;
|
||||
return BLOCK;
|
||||
},
|
||||
indexedDB: function getIndexedDBDefaultPermissions()
|
||||
{
|
||||
return BLOCK;
|
||||
}
|
||||
};
|
||||
|
||||
@ -137,6 +145,10 @@ function initRow(aPartId)
|
||||
perm = gPermObj[aPartId]();
|
||||
}
|
||||
setRadioState(aPartId, perm);
|
||||
|
||||
if (aPartId == "indexedDB") {
|
||||
initIndexedDBRow();
|
||||
}
|
||||
}
|
||||
|
||||
function onCheckboxClick(aPartId)
|
||||
@ -148,6 +160,9 @@ function onCheckboxClick(aPartId)
|
||||
var checkbox = document.getElementById(aPartId + "Def");
|
||||
if (checkbox.checked) {
|
||||
permissionManager.remove(gPermURI.host, aPartId);
|
||||
if (aPartId == "indexedDB") {
|
||||
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
|
||||
}
|
||||
command.setAttribute("disabled", "true");
|
||||
var perm = gPermObj[aPartId]();
|
||||
setRadioState(aPartId, perm);
|
||||
@ -167,6 +182,9 @@ function onRadioClick(aPartId)
|
||||
var id = radioGroup.selectedItem.id;
|
||||
var permission = id.split('#')[1];
|
||||
permissionManager.add(gPermURI, aPartId, permission);
|
||||
if (aPartId == "indexedDB" && permission == BLOCK) {
|
||||
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
|
||||
}
|
||||
}
|
||||
|
||||
function setRadioState(aPartId, aValue)
|
||||
@ -174,3 +192,41 @@ function setRadioState(aPartId, aValue)
|
||||
var radio = document.getElementById(aPartId + "#" + aValue);
|
||||
radio.radioGroup.selectedItem = radio;
|
||||
}
|
||||
|
||||
function initIndexedDBRow()
|
||||
{
|
||||
var status = document.getElementById("indexedDBStatus");
|
||||
var button = document.getElementById("indexedDBClear");
|
||||
|
||||
var usage = Components.classes["@mozilla.org/dom/indexeddb/manager;1"]
|
||||
.getService(nsIIndexedDatabaseManager)
|
||||
.getUsageForURI(gPermURI);
|
||||
if (usage) {
|
||||
if (!("DownloadUtils" in window)) {
|
||||
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
}
|
||||
status.value =
|
||||
gBundle.getFormattedString("indexedDBUsage",
|
||||
DownloadUtils.convertByteUnits(usage));
|
||||
status.removeAttribute("hidden");
|
||||
button.removeAttribute("hidden");
|
||||
}
|
||||
else {
|
||||
status.value = "";
|
||||
status.setAttribute("hidden", "true");
|
||||
button.setAttribute("hidden", "true");
|
||||
}
|
||||
}
|
||||
|
||||
function onIndexedDBClear()
|
||||
{
|
||||
Components.classes["@mozilla.org/dom/indexeddb/manager;1"]
|
||||
.getService(nsIIndexedDatabaseManager)
|
||||
.clearDatabasesForURI(gPermURI);
|
||||
|
||||
var permissionManager = Components.classes[PERMISSION_CONTRACTID]
|
||||
.getService(nsIPermissionManager);
|
||||
permissionManager.remove(gPermURI.host, "indexedDB");
|
||||
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
|
||||
initIndexedDBRow();
|
||||
}
|
||||
|
@ -185,6 +185,10 @@
|
||||
aTab.setAttribute("pinned", "true");
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("TabPin", true, false);
|
||||
aTab.dispatchEvent(event);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
@ -200,6 +204,10 @@
|
||||
aTab.style.MozMarginStart = "";
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("TabUnpin", true, false);
|
||||
aTab.dispatchEvent(event);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
@ -432,7 +440,7 @@
|
||||
this.mTabBrowser.setTabTitleLoading(this.mTab);
|
||||
}
|
||||
|
||||
if (this.mTabBrowser.mCurrentTab == this.mTab)
|
||||
if (this.mTab.selected)
|
||||
this.mTabBrowser.mIsBusy = true;
|
||||
}
|
||||
}
|
||||
@ -468,7 +476,7 @@
|
||||
if (this.mTab.label == this.mTabBrowser.mStringBundle.getString("tabs.loading"))
|
||||
this.mTabBrowser.setTabTitle(this.mTab);
|
||||
|
||||
if (this.mTabBrowser.mCurrentTab == this.mTab)
|
||||
if (this.mTab.selected)
|
||||
this.mTabBrowser.mIsBusy = false;
|
||||
}
|
||||
|
||||
@ -937,6 +945,10 @@
|
||||
aTab.label = title;
|
||||
aTab.crop = crop;
|
||||
this._tabAttrModified(aTab);
|
||||
|
||||
if (aTab.selected)
|
||||
this.updateTitlebar();
|
||||
|
||||
return true;
|
||||
]]>
|
||||
</body>
|
||||
@ -2470,12 +2482,7 @@
|
||||
|
||||
var tab = this._getTabForContentWindow(contentWin);
|
||||
var titleChanged = this.setTabTitle(tab);
|
||||
if (!titleChanged)
|
||||
return;
|
||||
|
||||
if (tab == this.mCurrentTab)
|
||||
this.updateTitlebar();
|
||||
else if (!tab.hasAttribute("busy"))
|
||||
if (titleChanged && !tab.selected && !tab.hasAttribute("busy"))
|
||||
tab.setAttribute("titlechanged", "true");
|
||||
]]>
|
||||
</handler>
|
||||
|
@ -64,7 +64,6 @@
|
||||
// title - the title for the groupItem; otherwise blank
|
||||
// dontPush - true if this groupItem shouldn't push away on creation; default is false
|
||||
function GroupItem(listOfEls, options) {
|
||||
try {
|
||||
if (typeof options == 'undefined')
|
||||
options = {};
|
||||
|
||||
@ -78,6 +77,7 @@ function GroupItem(listOfEls, options) {
|
||||
this.expanded = null;
|
||||
this.locked = (options.locked ? Utils.copy(options.locked) : {});
|
||||
this.topChild = null;
|
||||
this.hidden = false;
|
||||
|
||||
this.keepProportional = false;
|
||||
|
||||
@ -130,8 +130,7 @@ function GroupItem(listOfEls, options) {
|
||||
.click(function() {
|
||||
self.newTab();
|
||||
})
|
||||
.attr('title',
|
||||
"New tab")
|
||||
.attr('title', tabviewString('groupItem.newTabButton'))
|
||||
.appendTo($container);
|
||||
|
||||
// ___ Resizer
|
||||
@ -187,7 +186,7 @@ function GroupItem(listOfEls, options) {
|
||||
}
|
||||
};
|
||||
|
||||
var handleKeyPress = function(e) {
|
||||
var handleKeyDown = function(e) {
|
||||
if (e.which == 13 || e.which == 27) { // return & escape
|
||||
(self.$title)[0].blur();
|
||||
self.$title
|
||||
@ -195,9 +194,16 @@ function GroupItem(listOfEls, options) {
|
||||
.one("mouseout", function() {
|
||||
self.$title.removeClass("transparentBorder");
|
||||
});
|
||||
} else
|
||||
self.adjustTitleSize();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
var handleKeyUp = function(e) {
|
||||
// NOTE: When user commits or cancels IME composition, the last key
|
||||
// event fires only a keyup event. Then, we shouldn't take any
|
||||
// reactions but we should update our status.
|
||||
self.adjustTitleSize();
|
||||
self.save();
|
||||
};
|
||||
|
||||
@ -216,7 +222,8 @@ function GroupItem(listOfEls, options) {
|
||||
.val('');
|
||||
}
|
||||
})
|
||||
.keyup(handleKeyPress);
|
||||
.keydown(handleKeyDown)
|
||||
.keyup(handleKeyUp);
|
||||
|
||||
titleUnfocus();
|
||||
|
||||
@ -246,6 +253,16 @@ function GroupItem(listOfEls, options) {
|
||||
.appendTo($container)
|
||||
.hide();
|
||||
|
||||
// ___ app tabs: create app tab tray and populate it
|
||||
this.$appTabTray = iQ("<div/>")
|
||||
.addClass("appTabTray")
|
||||
.appendTo($container);
|
||||
|
||||
AllTabs.tabs.forEach(function(xulTab) {
|
||||
if (xulTab.pinned && xulTab.ownerDocument.defaultView == gWindow)
|
||||
self.addAppTab(xulTab);
|
||||
});
|
||||
|
||||
// ___ locking
|
||||
if (this.locked.bounds)
|
||||
$container.css({cursor: 'default'});
|
||||
@ -253,6 +270,9 @@ function GroupItem(listOfEls, options) {
|
||||
if (this.locked.close)
|
||||
$close.hide();
|
||||
|
||||
// ___ Undo Close
|
||||
this.$undoContainer = null;
|
||||
|
||||
// ___ Superclass initialization
|
||||
this._init($container[0]);
|
||||
|
||||
@ -285,10 +305,6 @@ function GroupItem(listOfEls, options) {
|
||||
|
||||
this._inited = true;
|
||||
this.save();
|
||||
} catch(e) {
|
||||
Utils.log("Error in GroupItem()");
|
||||
Utils.log(e.stack);
|
||||
}
|
||||
};
|
||||
|
||||
// ----------
|
||||
@ -296,19 +312,23 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
// ----------
|
||||
// Variable: defaultName
|
||||
// The prompt text for the title field.
|
||||
defaultName: "Name this tab group…",
|
||||
defaultName: tabviewString('groupItem.defaultName'),
|
||||
|
||||
// -----------
|
||||
// Function: setActiveTab
|
||||
// Sets the active <TabItem> for this groupItem
|
||||
// Sets the active <TabItem> for this groupItem; can be null, but only
|
||||
// if there are no children.
|
||||
setActiveTab: function GroupItem_setActiveTab(tab) {
|
||||
Utils.assert(tab && tab.isATabItem, 'tab must be a TabItem');
|
||||
Utils.assertThrow((!tab && this._children.length == 0) || tab.isATabItem,
|
||||
"tab must be null (if no children) or a TabItem");
|
||||
|
||||
this._activeTab = tab;
|
||||
},
|
||||
|
||||
// -----------
|
||||
// Function: getActiveTab
|
||||
// Gets the active <TabItem> for this groupItem
|
||||
// Gets the active <TabItem> for this groupItem; can be null, but only
|
||||
// if there are no children.
|
||||
getActiveTab: function GroupItem_getActiveTab() {
|
||||
return this._activeTab;
|
||||
},
|
||||
@ -390,6 +410,8 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
box.top += titleHeight;
|
||||
box.height -= titleHeight;
|
||||
|
||||
box.width -= this.$appTabTray.width();
|
||||
|
||||
// Make the computed bounds' "padding" and new tab button margin actually be
|
||||
// themeable --OR-- compute this from actual bounds. Bug 586546
|
||||
box.inset(6, 6);
|
||||
@ -523,9 +545,16 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
GroupItems.unregister(this);
|
||||
this._sendToSubscribers("close");
|
||||
this.removeTrenches();
|
||||
iQ(this.container).fadeOut(function() {
|
||||
iQ(this).remove();
|
||||
Items.unsquish();
|
||||
|
||||
iQ(this.container).animate({
|
||||
opacity: 0,
|
||||
"-moz-transform": "scale(.3)",
|
||||
}, {
|
||||
duration: 170,
|
||||
complete: function() {
|
||||
iQ(this).remove();
|
||||
Items.unsquish();
|
||||
}
|
||||
});
|
||||
|
||||
Storage.deleteGroupItem(gWindow, this.id);
|
||||
@ -535,17 +564,137 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
// Function: closeAll
|
||||
// Closes the groupItem and all of its children.
|
||||
closeAll: function GroupItem_closeAll() {
|
||||
var self = this;
|
||||
if (this._children.length) {
|
||||
var toClose = this._children.concat();
|
||||
if (this._children.length > 0) {
|
||||
this._children.forEach(function(child) {
|
||||
iQ(child.container).hide();
|
||||
});
|
||||
|
||||
iQ(this.container).animate({
|
||||
opacity: 0,
|
||||
"-moz-transform": "scale(.3)",
|
||||
}, {
|
||||
duration: 170,
|
||||
complete: function() {
|
||||
iQ(this).hide();
|
||||
}
|
||||
});
|
||||
|
||||
this._createUndoButton();
|
||||
} else {
|
||||
if (!this.locked.close)
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _createUndoButton
|
||||
// Makes the affordance for undo a close group action
|
||||
_createUndoButton: function() {
|
||||
let self = this;
|
||||
this.$undoContainer = iQ("<div/>")
|
||||
.addClass("undo")
|
||||
.attr("type", "button")
|
||||
.text("Undo Close Group")
|
||||
.appendTo("body");
|
||||
let undoClose = iQ("<span/>")
|
||||
.addClass("close")
|
||||
.appendTo(this.$undoContainer);
|
||||
|
||||
this.$undoContainer.css({
|
||||
left: this.bounds.left + this.bounds.width/2 - iQ(self.$undoContainer).width()/2,
|
||||
top: this.bounds.top + this.bounds.height/2 - iQ(self.$undoContainer).height()/2,
|
||||
"-moz-transform": "scale(.1)",
|
||||
opacity: 0
|
||||
});
|
||||
this.hidden = true;
|
||||
|
||||
setTimeout(function() {
|
||||
self.$undoContainer.animate({
|
||||
"-moz-transform": "scale(1)",
|
||||
"opacity": 1
|
||||
}, {
|
||||
easing: "tabviewBounce",
|
||||
duration: 170,
|
||||
complete: function() {
|
||||
self._sendToSubscribers("groupHidden", { groupItemId: self.id });
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
|
||||
let remove = function() {
|
||||
// close all children
|
||||
let toClose = self._children.concat();
|
||||
toClose.forEach(function(child) {
|
||||
child.removeSubscriber(self, "close");
|
||||
child.close();
|
||||
});
|
||||
}
|
||||
|
||||
// remove all children
|
||||
self.removeAll();
|
||||
GroupItems.unregister(self);
|
||||
self._sendToSubscribers("close");
|
||||
self.removeTrenches();
|
||||
|
||||
if (!this.locked.close)
|
||||
this.close();
|
||||
iQ(self.container).remove();
|
||||
self.$undoContainer.remove();
|
||||
self.$undoContainer = null;
|
||||
Items.unsquish();
|
||||
|
||||
Storage.deleteGroupItem(gWindow, self.id);
|
||||
};
|
||||
|
||||
this.$undoContainer.click(function(e) {
|
||||
// Only do this for clicks on this actual element.
|
||||
if (e.target.nodeName != self.$undoContainer[0].nodeName)
|
||||
return;
|
||||
|
||||
self.$undoContainer.fadeOut(function() {
|
||||
iQ(this).remove();
|
||||
self.hidden = false;
|
||||
self.$undoContainer = null;
|
||||
|
||||
iQ(self.container).show().animate({
|
||||
"-moz-transform": "scale(1)",
|
||||
"opacity": 1
|
||||
}, {
|
||||
duration: 170,
|
||||
complete: function() {
|
||||
self._children.forEach(function(child) {
|
||||
iQ(child.container).show();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
self._sendToSubscribers("groupShown", { groupItemId: self.id });
|
||||
});
|
||||
});
|
||||
|
||||
undoClose.click(function() {
|
||||
self.$undoContainer.fadeOut(remove);
|
||||
});
|
||||
|
||||
// After 15 seconds, fade away.
|
||||
const WAIT = 15000;
|
||||
const FADE = 300;
|
||||
|
||||
let fadeaway = function() {
|
||||
if (self.$undoContainer)
|
||||
self.$undoContainer.animate({
|
||||
color: "transparent",
|
||||
opacity: 0
|
||||
}, {
|
||||
duration: FADE,
|
||||
complete: remove
|
||||
});
|
||||
};
|
||||
|
||||
let timeoutId = setTimeout(fadeaway, WAIT);
|
||||
// Cancel the fadeaway if you move the mouse over the undo
|
||||
// button, and restart the countdown once you move out of it.
|
||||
this.$undoContainer.mouseover(function() clearTimeout(timeoutId));
|
||||
this.$undoContainer.mouseout(function() {
|
||||
timeoutId = setTimeout(fadeaway, WAIT);
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
@ -573,9 +722,6 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
|
||||
item.removeTrenches();
|
||||
|
||||
if (!dropPos)
|
||||
dropPos = {top:window.innerWidth, left:window.innerHeight};
|
||||
|
||||
if (typeof options == 'undefined')
|
||||
options = {};
|
||||
|
||||
@ -629,7 +775,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
}
|
||||
|
||||
// Insert the tab into the right position.
|
||||
var index = findInsertionPoint(dropPos);
|
||||
var index = dropPos ? findInsertionPoint(dropPos) : this._children.length;
|
||||
this._children.splice(index, 0, item);
|
||||
|
||||
item.setZ(this.getZ() + 1);
|
||||
@ -691,6 +837,13 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
var index = this._children.indexOf(item);
|
||||
if (index != -1)
|
||||
this._children.splice(index, 1);
|
||||
|
||||
if (item == this._activeTab) {
|
||||
if (this._children.length)
|
||||
this._activeTab = this._children[0];
|
||||
else
|
||||
this._activeTab = null;
|
||||
}
|
||||
|
||||
item.setParent(null);
|
||||
item.removeClass("tabInGroupItem");
|
||||
@ -728,6 +881,33 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Adds the given xul:tab as an app tab in this group's apptab tray
|
||||
addAppTab: function GroupItem_addAppTab(xulTab) {
|
||||
let self = this;
|
||||
|
||||
let icon = xulTab.image || Utils.defaultFaviconURL;
|
||||
let $appTab = iQ("<img>")
|
||||
.addClass("appTabIcon")
|
||||
.attr("src", icon)
|
||||
.data("xulTab", xulTab)
|
||||
.appendTo(this.$appTabTray)
|
||||
.click(function(event) {
|
||||
if (Utils.isRightClick(event))
|
||||
return;
|
||||
|
||||
GroupItems.setActiveGroupItem(self);
|
||||
GroupItems._updateTabBar();
|
||||
UI.goToTab(iQ(this).data("xulTab"));
|
||||
});
|
||||
|
||||
let columnWidth = $appTab.width();
|
||||
if (parseInt(this.$appTabTray.css("width")) != columnWidth) {
|
||||
this.$appTabTray.css({width: columnWidth});
|
||||
this.arrange();
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: hideExpandControl
|
||||
// Hide the control which expands a stacked groupItem into a quick-look view.
|
||||
@ -1125,6 +1305,8 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
className.indexOf('name') != -1 ||
|
||||
className.indexOf('close') != -1 ||
|
||||
className.indexOf('newTabButton') != -1 ||
|
||||
className.indexOf('appTabTray') != -1 ||
|
||||
className.indexOf('appTabIcon') != -1 ||
|
||||
className.indexOf('stackExpander') != -1) {
|
||||
return;
|
||||
}
|
||||
@ -1177,7 +1359,9 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
GroupItems.setActiveGroupItem(this);
|
||||
let newTab = gBrowser.loadOneTab(url || "about:blank", {inBackground: true});
|
||||
|
||||
// TabItems will have handled the new tab and added the tabItem property
|
||||
// TabItems will have handled the new tab and added the tabItem property.
|
||||
// We don't have to check if it's an app tab (and therefore wouldn't have a
|
||||
// TabItem), since we've just created it.
|
||||
let newItem = newTab.tabItem;
|
||||
|
||||
var self = this;
|
||||
@ -1541,14 +1725,13 @@ let GroupItems = {
|
||||
|
||||
// ----------
|
||||
// Function: setActiveGroupItem
|
||||
// Sets the active groupItem, thereby showing only the relevent tabs, and
|
||||
// Sets the active groupItem, thereby showing only the relevant tabs and
|
||||
// setting the groupItem which will receive new tabs.
|
||||
//
|
||||
// Paramaters:
|
||||
// groupItem - the active <GroupItem> or <null> if no groupItem is active
|
||||
// (which means we have an orphaned tab selected)
|
||||
setActiveGroupItem: function GroupItems_setActiveGroupItem(groupItem) {
|
||||
|
||||
if (this._activeGroupItem)
|
||||
iQ(this._activeGroupItem.container).removeClass('activeGroupItem');
|
||||
|
||||
@ -1600,16 +1783,18 @@ let GroupItems = {
|
||||
|
||||
// ----------
|
||||
// Function: updateActiveGroupItemAndTabBar
|
||||
// Sets active group item and updates tab bar
|
||||
// Sets active TabItem and GroupItem, and updates tab bar appropriately.
|
||||
updateActiveGroupItemAndTabBar: function GroupItems_updateActiveGroupItemAndTabBar(tabItem) {
|
||||
if (tabItem.parent) {
|
||||
let groupItem = tabItem.parent;
|
||||
this.setActiveGroupItem(groupItem);
|
||||
Utils.assertThrow(tabItem && tabItem.isATabItem, "tabItem must be a TabItem");
|
||||
|
||||
let groupItem = tabItem.parent;
|
||||
this.setActiveGroupItem(groupItem);
|
||||
|
||||
if (groupItem)
|
||||
groupItem.setActiveTab(tabItem);
|
||||
} else {
|
||||
this.setActiveGroupItem(null);
|
||||
else
|
||||
this.setActiveOrphanTab(tabItem);
|
||||
}
|
||||
|
||||
this._updateTabBar();
|
||||
},
|
||||
|
||||
@ -1641,10 +1826,12 @@ let GroupItems = {
|
||||
if (!activeGroupItem) {
|
||||
if (groupItems.length > 0) {
|
||||
groupItems.some(function(groupItem) {
|
||||
var child = groupItem.getChild(0);
|
||||
if (child) {
|
||||
tabItem = child;
|
||||
return true;
|
||||
if (!groupItem.hidden) {
|
||||
var child = groupItem.getChild(0);
|
||||
if (child) {
|
||||
tabItem = child;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@ -1652,7 +1839,7 @@ let GroupItems = {
|
||||
} else {
|
||||
var currentIndex;
|
||||
groupItems.some(function(groupItem, index) {
|
||||
if (groupItem == activeGroupItem) {
|
||||
if (!groupItem.hidden && groupItem == activeGroupItem) {
|
||||
currentIndex = index;
|
||||
return true;
|
||||
}
|
||||
@ -1660,10 +1847,12 @@ let GroupItems = {
|
||||
});
|
||||
var firstGroupItems = groupItems.slice(currentIndex + 1);
|
||||
firstGroupItems.some(function(groupItem) {
|
||||
var child = groupItem.getChild(0);
|
||||
if (child) {
|
||||
tabItem = child;
|
||||
return true;
|
||||
if (!groupItem.hidden) {
|
||||
var child = groupItem.getChild(0);
|
||||
if (child) {
|
||||
tabItem = child;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@ -1675,10 +1864,12 @@ let GroupItems = {
|
||||
if (!tabItem) {
|
||||
var secondGroupItems = groupItems.slice(0, currentIndex);
|
||||
secondGroupItems.some(function(groupItem) {
|
||||
var child = groupItem.getChild(0);
|
||||
if (child) {
|
||||
tabItem = child;
|
||||
return true;
|
||||
if (!groupItem.hidden) {
|
||||
var child = groupItem.getChild(0);
|
||||
if (child) {
|
||||
tabItem = child;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@ -1689,10 +1880,17 @@ let GroupItems = {
|
||||
|
||||
// ----------
|
||||
// Function: moveTabToGroupItem
|
||||
// Used for the right click menu in the tab strip; moves the given tab
|
||||
// into the given group. Does nothing if the tab is an app tab.
|
||||
// Paramaters:
|
||||
// tab - the <xul:tab>.
|
||||
// groupItemId - the <groupItem>'s id. If nothing, create a new <groupItem>.
|
||||
moveTabToGroupItem : function GroupItems_moveTabToGroupItem (tab, groupItemId) {
|
||||
if (tab.pinned)
|
||||
return;
|
||||
|
||||
Utils.assertThrow(tab.tabItem, "tab must be linked to a TabItem");
|
||||
|
||||
let shouldUpdateTabBar = false;
|
||||
let shouldShowTabView = false;
|
||||
let groupItem;
|
||||
@ -1747,6 +1945,8 @@ let GroupItems = {
|
||||
// Function: killNewTabGroup
|
||||
// Removes the New Tab Group, which is now defunct. See bug 575851 and comments therein.
|
||||
killNewTabGroup: function GroupItems_killNewTabGroup() {
|
||||
// not localized as the original "New Tabs" group title was never localized
|
||||
// to begin with
|
||||
let newTabGroupTitle = "New Tabs";
|
||||
this.groupItems.forEach(function(groupItem) {
|
||||
if (groupItem.getTitle() == newTabGroupTitle && groupItem.locked.title) {
|
||||
@ -1754,5 +1954,25 @@ let GroupItems = {
|
||||
groupItem.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: removeHiddenGroups
|
||||
// Removes all hidden groups' data and its browser tabs.
|
||||
removeHiddenGroups: function GroupItems_removeHiddenGroups() {
|
||||
iQ(".undo").remove();
|
||||
|
||||
// ToDo: encapsulate this in the group item. bug 594863
|
||||
this.groupItems.forEach(function(groupItem) {
|
||||
if (groupItem.hidden) {
|
||||
let toClose = groupItem._children.concat();
|
||||
toClose.forEach(function(child) {
|
||||
child.removeSubscriber(groupItem, "close");
|
||||
child.close();
|
||||
});
|
||||
|
||||
Storage.deleteGroupItem(gWindow, groupItem.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -322,6 +322,20 @@ Range.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: overlaps
|
||||
// Whether the <Range> overlaps with the given <Range> or value or not.
|
||||
//
|
||||
// Paramaters
|
||||
// - a number or <Range>
|
||||
overlaps: function Rect_overlaps(value) {
|
||||
if (Utils.isNumber(value))
|
||||
return this.contains(value);
|
||||
if (Utils.isRange(value))
|
||||
return !(value.max < this.min || this.max < value.min);
|
||||
return false;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: proportion
|
||||
// Maps the given value to the range [0,1], so that it returns 0 if the value is <= the min,
|
||||
@ -464,8 +478,9 @@ Subscribable.prototype = {
|
||||
// Class: Utils
|
||||
// Singelton with common utility functions.
|
||||
let Utils = {
|
||||
// ___ Logging
|
||||
defaultFaviconURL: "chrome://mozapps/skin/places/defaultFavicon.png",
|
||||
|
||||
// ___ Logging
|
||||
useConsole: true, // as opposed to dump
|
||||
showTime: false,
|
||||
|
||||
|
@ -49,7 +49,6 @@
|
||||
// Parameters:
|
||||
// tab - a xul:tab
|
||||
function TabItem(tab) {
|
||||
|
||||
Utils.assert(tab, "tab");
|
||||
|
||||
this.tab = tab;
|
||||
@ -506,6 +505,10 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
// Parameters:
|
||||
// isNewBlankTab - boolean indicates whether it is a newly opened blank tab.
|
||||
zoomIn: function TabItem_zoomIn(isNewBlankTab) {
|
||||
// don't allow zoom in if its group is hidden
|
||||
if (this.parent && this.parent.hidden)
|
||||
return;
|
||||
|
||||
var self = this;
|
||||
var $tabEl = iQ(this.container);
|
||||
var childHitResult = { shouldZoom: true };
|
||||
@ -525,11 +528,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
.css(orig.css())
|
||||
.removeClass("front");
|
||||
|
||||
// If it's not focused, the onFocus lsitener would handle it.
|
||||
if (gBrowser.selectedTab == tab)
|
||||
UI.onTabSelect(tab);
|
||||
else
|
||||
gBrowser.selectedTab = tab;
|
||||
UI.goToTab(tab);
|
||||
|
||||
if (isNewBlankTab)
|
||||
gWindow.gURLBar.focus();
|
||||
@ -663,7 +662,7 @@ let TabItems = {
|
||||
|
||||
// When a tab is opened, create the TabItem
|
||||
this._eventListeners["open"] = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
|
||||
self.link(tab);
|
||||
@ -671,14 +670,14 @@ let TabItems = {
|
||||
// When a tab's content is loaded, show the canvas and hide the cached data
|
||||
// if necessary.
|
||||
this._eventListeners["attrModified"] = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
|
||||
self.update(tab);
|
||||
}
|
||||
// When a tab is closed, unlink.
|
||||
this._eventListeners["close"] = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
|
||||
self.unlink(tab);
|
||||
@ -689,7 +688,7 @@ let TabItems = {
|
||||
|
||||
// For each tab, create the link.
|
||||
AllTabs.tabs.forEach(function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
|
||||
self.link(tab);
|
||||
@ -722,6 +721,8 @@ let TabItems = {
|
||||
update: function TabItems_update(tab) {
|
||||
try {
|
||||
Utils.assertThrow(tab, "tab");
|
||||
Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
|
||||
Utils.assertThrow(tab.tabItem, "should already be linked");
|
||||
|
||||
let shouldDefer = (
|
||||
this.isPaintingPaused() ||
|
||||
@ -763,7 +764,7 @@ let TabItems = {
|
||||
// ___ icon
|
||||
let iconUrl = tab.image;
|
||||
if (iconUrl == null)
|
||||
iconUrl = "chrome://mozapps/skin/places/defaultFavicon.png";
|
||||
iconUrl = Utils.defaultFaviconURL;
|
||||
|
||||
if (iconUrl != tabItem.favEl.src)
|
||||
tabItem.favEl.src = iconUrl;
|
||||
@ -812,10 +813,11 @@ let TabItems = {
|
||||
|
||||
// ----------
|
||||
// Function: link
|
||||
// Takes in a xul:tab.
|
||||
// Takes in a xul:tab, creates a TabItem for it and adds it to the scene.
|
||||
link: function TabItems_link(tab){
|
||||
try {
|
||||
Utils.assertThrow(tab, "tab");
|
||||
Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
|
||||
Utils.assertThrow(!tab.tabItem, "shouldn't already be linked");
|
||||
new TabItem(tab); // sets tab.tabItem to itself
|
||||
} catch(e) {
|
||||
@ -825,10 +827,11 @@ let TabItems = {
|
||||
|
||||
// ----------
|
||||
// Function: unlink
|
||||
// Takes in a xul:tab.
|
||||
// Takes in a xul:tab and destroys the TabItem associated with it.
|
||||
unlink: function TabItems_unlink(tab) {
|
||||
try {
|
||||
Utils.assertThrow(tab, "tab");
|
||||
Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
|
||||
Utils.assertThrow(tab.tabItem, "should already be linked");
|
||||
|
||||
this.unregister(tab.tabItem);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Platform-independent structural styling for
|
||||
/* Platform-independent structural styling for
|
||||
* <strike>Tab Candy</strike> Panorama
|
||||
----------------------------------*/
|
||||
|
||||
@ -82,16 +82,35 @@ body {
|
||||
|
||||
.front {
|
||||
z-index: 999999 !important;
|
||||
-moz-border-radius: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
-moz-box-shadow: none !important;
|
||||
-moz-transform: none !important;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
}
|
||||
|
||||
/* Groups
|
||||
----------------------------------*/
|
||||
|
||||
.groupItem {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.appTabTray {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Other Items
|
||||
----------------------------------*/
|
||||
|
||||
.groupItem,
|
||||
.undo {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.undo .close {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
position: absolute;
|
||||
}
|
||||
@ -167,6 +186,12 @@ body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Exit button
|
||||
----------------------------------*/
|
||||
#exit-button {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/* Search
|
||||
----------------------------------*/
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
<body transparent="true">
|
||||
<div id="content">
|
||||
<input id="exit-button" type="image" onclick="UI.onExitButtonPressed();"
|
||||
alt="" />
|
||||
<div id="actions">
|
||||
<input type="button" id="searchbutton"/>
|
||||
</div>
|
||||
|
@ -25,6 +25,13 @@ XPCOMUtils.defineLazyGetter(this, "gTabViewFrame", function() {
|
||||
return gWindow.document.getElementById("tab-view");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
|
||||
return Services.strings.
|
||||
createBundle("chrome://browser/locale/tabview.properties");
|
||||
});
|
||||
|
||||
function tabviewString(name) tabviewBundle.GetStringFromName('tabview.' + name);
|
||||
|
||||
# NB: Certain files need to evaluate before others
|
||||
|
||||
#include iq.js
|
||||
|
@ -382,7 +382,7 @@ Trench.prototype = {
|
||||
ruleOverlaps: function Trench_ruleOverlaps(position, range) {
|
||||
return (this.position - this.radius < position &&
|
||||
position < this.position + this.radius &&
|
||||
this.activeRange.contains(range));
|
||||
this.activeRange.overlaps(range));
|
||||
},
|
||||
|
||||
//----------
|
||||
|
@ -106,9 +106,9 @@ let UI = {
|
||||
|
||||
// ___ Dev Menu
|
||||
// This dev menu is not meant for shipping, nor is it of general
|
||||
// interest, but we still need it for the time being. Change the
|
||||
// false below to enable; just remember to change back before
|
||||
// committing. Bug 586721 will track the ultimate removal.
|
||||
// interest, but we still need it for the time being. Change the
|
||||
// false below to enable; just remember to change back before
|
||||
// committing. Bug 586721 will track the ultimate removal.
|
||||
if (false)
|
||||
this._addDevMenu();
|
||||
|
||||
@ -163,7 +163,7 @@ let UI = {
|
||||
if (firstTime) {
|
||||
var padding = 10;
|
||||
var infoWidth = 350;
|
||||
var infoHeight = 350;
|
||||
var infoHeight = 232;
|
||||
var pageBounds = Items.getPageBounds();
|
||||
pageBounds.inset(padding, padding);
|
||||
|
||||
@ -187,15 +187,10 @@ let UI = {
|
||||
});
|
||||
|
||||
// ___ make info item
|
||||
let welcome = "How to organize your tabs";
|
||||
let more = "";
|
||||
let video = "http://videos-cdn.mozilla.net/firefox4beta/tabcandy_howto.webm";
|
||||
var html =
|
||||
"<div class='intro'>"
|
||||
+ "<h1>" + welcome + "</h1>"
|
||||
+ ( more && more.length ? "<div>" + more + "</div><br>" : "")
|
||||
+ "<video src='" + video + "' "
|
||||
+ "width='100%' preload controls>"
|
||||
+ "<video src='" + video + "' width='100%' preload controls>"
|
||||
+ "</div>";
|
||||
|
||||
box.left = box.right + padding;
|
||||
@ -219,8 +214,10 @@ let UI = {
|
||||
var observer = {
|
||||
observe : function(subject, topic, data) {
|
||||
if (topic == "quit-application-requested") {
|
||||
if (self._isTabViewVisible())
|
||||
if (self._isTabViewVisible()) {
|
||||
GroupItems.removeHiddenGroups();
|
||||
TabItems.saveAll(true);
|
||||
}
|
||||
self._save();
|
||||
}
|
||||
}
|
||||
@ -358,6 +355,7 @@ let UI = {
|
||||
if (!this._isTabViewVisible())
|
||||
return;
|
||||
|
||||
GroupItems.removeHiddenGroups();
|
||||
TabItems.pausePainting();
|
||||
|
||||
this._reorderTabsOnHide.forEach(function(groupItem) {
|
||||
@ -471,6 +469,16 @@ let UI = {
|
||||
AllTabs.unregister(name, this._eventListeners[name]);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// 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)
|
||||
this.onTabSelect(xulTab);
|
||||
else
|
||||
gBrowser.selectedTab = xulTab;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: onTabSelect
|
||||
// Called when the user switches from one tab to another outside of the TabView UI.
|
||||
@ -496,7 +504,7 @@ let UI = {
|
||||
|
||||
let oldItem = null;
|
||||
let newItem = null;
|
||||
|
||||
|
||||
if (currentTab && currentTab.tabItem)
|
||||
oldItem = currentTab.tabItem;
|
||||
if (tab && tab.tabItem) {
|
||||
@ -567,7 +575,8 @@ let UI = {
|
||||
|
||||
function getClosestTabBy(norm) {
|
||||
var centers =
|
||||
[[item.bounds.center(), item] for each(item in TabItems.getItems())];
|
||||
[[item.bounds.center(), item]
|
||||
for each(item in TabItems.getItems()) if (!item.parent || !item.parent.hidden)];
|
||||
var myCenter = self.getActiveTab().bounds.center();
|
||||
var matches = centers
|
||||
.filter(function(item){return norm(item[0], myCenter)})
|
||||
@ -619,13 +628,13 @@ let UI = {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
} else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE ||
|
||||
} else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE ||
|
||||
event.keyCode == KeyEvent.DOM_VK_RETURN ||
|
||||
event.keyCode == KeyEvent.DOM_VK_ENTER) {
|
||||
let activeTab = self.getActiveTab();
|
||||
let activeGroupItem = GroupItems.getActiveGroupItem();
|
||||
|
||||
if (activeGroupItem && activeGroupItem.expanded &&
|
||||
if (activeGroupItem && activeGroupItem.expanded &&
|
||||
event.keyCode == KeyEvent.DOM_VK_ESCAPE)
|
||||
activeGroupItem.collapse();
|
||||
else if (activeTab)
|
||||
@ -875,6 +884,17 @@ let UI = {
|
||||
this._save();
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: onExitButtonPressed
|
||||
// Exits TabView UI.
|
||||
onExitButtonPressed: function() {
|
||||
let activeTab = this.getActiveTab();
|
||||
if (!activeTab)
|
||||
activeTab = gBrowser.selectedTab.tabItem;
|
||||
if (activeTab)
|
||||
activeTab.zoomIn();
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _addDevMenu
|
||||
// Fills out the "dev menu" in the TabView UI.
|
||||
|
@ -47,7 +47,7 @@ function runOneTest() {
|
||||
});
|
||||
}, true);
|
||||
|
||||
browser.contentWindow.location =
|
||||
"chrome://mochikit/content/browser/browser/base/content/test/test_bug462673.html";
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
browser.contentWindow.location = rootDir + "test_bug462673.html"
|
||||
}, false);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testPath = "chrome://mochikit/content/browser/browser/base/content/test/";
|
||||
let testPath = getRootDirectory(gTestPath);
|
||||
|
||||
let tab = gBrowser.addTab(testPath + "file_bug550565_popup.html");
|
||||
|
||||
|
@ -4,9 +4,19 @@
|
||||
|
||||
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||
const TESTROOT2 = "http://example.org/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||
const CHROMEROOT = "chrome://mochikit/content/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
var path = rootDir.split('/');
|
||||
var chromeName = path[0] + '//' + path[2];
|
||||
var croot = chromeName + "/content/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||
var jar = getJar(croot);
|
||||
if (jar) {
|
||||
var tmpdir = extractJarToTmp(jar);
|
||||
croot = 'file://' + tmpdir.path + '/';
|
||||
}
|
||||
const CHROMEROOT = croot;
|
||||
|
||||
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
|
||||
var gVersion = Services.appinfo.version;
|
||||
|
||||
@ -313,8 +323,11 @@ function test_url() {
|
||||
function test_localfile() {
|
||||
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Components.interfaces.nsIChromeRegistry);
|
||||
var path = cr.convertChromeURL(makeURI(CHROMEROOT + "corrupt.xpi")).spec;
|
||||
|
||||
try {
|
||||
var path = cr.convertChromeURL(makeURI(CHROMEROOT + "corrupt.xpi")).spec;
|
||||
} catch (ex) {
|
||||
var path = CHROMEROOT + "corrupt.xpi";
|
||||
}
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(path);
|
||||
|
||||
|
@ -43,9 +43,9 @@ function test() {
|
||||
// -------------
|
||||
// Test clean-up
|
||||
function endTest() {
|
||||
gBrowser.removeTab(tab);
|
||||
FullZoom._applyPrefToSetting = oldAPTS;
|
||||
FullZoom.onLocationChange = oldOLC;
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
oldAPTS = null;
|
||||
oldOLC = null;
|
||||
|
@ -19,7 +19,8 @@ function test() {
|
||||
event.currentTarget.removeEventListener("load", arguments.callee, true);
|
||||
iconDiscovery();
|
||||
}, true);
|
||||
content.location = "chrome://mochikit/content/browser/browser/base/content/test/discovery.html";
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
content.location = rootDir + "discovery.html";
|
||||
}
|
||||
|
||||
var iconDiscoveryTests = [
|
||||
@ -56,8 +57,9 @@ function iconDiscovery() {
|
||||
var head = doc().getElementById("linkparent");
|
||||
var link = doc().createElement("link");
|
||||
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
var rel = test.rel || "icon";
|
||||
var href = test.href || "chrome://mochikit/content/browser/browser/base/content/test/moz.png";
|
||||
var href = test.href || rootDir + "/moz.png";
|
||||
var type = test.type || "image/png";
|
||||
if (test.pass == undefined)
|
||||
test.pass = true;
|
||||
|
@ -17,12 +17,11 @@ function test()
|
||||
data : htmlString }
|
||||
] ];
|
||||
// set the valid attribute so dropping is allowed
|
||||
var proxyicon = document.getElementById("page-proxy-favicon")
|
||||
var oldstate = proxyicon.getAttribute("pageproxystate");
|
||||
proxyicon.setAttribute("pageproxystate", "valid");
|
||||
var dt = EventUtils.synthesizeDragStart(proxyicon, expected);
|
||||
var oldstate = gURLBar.getAttribute("pageproxystate");
|
||||
gURLBar.setAttribute("pageproxystate", "valid");
|
||||
var dt = EventUtils.synthesizeDragStart(document.getElementById("identity-box"), expected);
|
||||
is(dt, null, "drag on proxy icon");
|
||||
proxyicon.setAttribute("pageproxystate", oldstate);
|
||||
gURLBar.setAttribute("pageproxystate", oldstate);
|
||||
// Now, the identity information panel is opened by the proxy icon click.
|
||||
// We need to close it for next tests.
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, window);
|
||||
|
@ -50,6 +50,8 @@ function runInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runInspectorTests, "inspector-opened", false);
|
||||
Services.obs.addObserver(finishInspectorTests, "inspector-closed", false);
|
||||
let iframe = document.getElementById("inspector-tree-iframe");
|
||||
is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches");
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open");
|
||||
|
@ -4,8 +4,8 @@ function test() {
|
||||
var tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.linkedBrowser.addEventListener("load", checkPageStyleMenu, true);
|
||||
content.location =
|
||||
"chrome://mochikit/content/browser/browser/base/content/test/page_style_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
content.location = rootDir + "page_style_sample.html";
|
||||
}
|
||||
|
||||
function checkPageStyleMenu() {
|
||||
|
@ -11,6 +11,23 @@ function indexTest(tab, expectedIndex, msg) {
|
||||
is(index(tabs[tab]), expectedIndex, msg);
|
||||
}
|
||||
|
||||
function PinUnpinHandler(tab, eventName) {
|
||||
this.eventCount = 0;
|
||||
var self = this;
|
||||
tab.addEventListener(eventName, function() {
|
||||
tab.removeEventListener(eventName, arguments.callee, true);
|
||||
|
||||
self.eventCount++;
|
||||
}, true);
|
||||
gBrowser.tabContainer.addEventListener(eventName, function(e) {
|
||||
gBrowser.tabContainer.removeEventListener(eventName, arguments.callee, true);
|
||||
|
||||
if (e.originalTarget == tab) {
|
||||
self.eventCount++;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
tabs = [gBrowser.selectedTab, gBrowser.addTab(), gBrowser.addTab(), gBrowser.addTab()];
|
||||
indexTest(0, 0);
|
||||
@ -18,13 +35,17 @@ function test() {
|
||||
indexTest(2, 2);
|
||||
indexTest(3, 3);
|
||||
|
||||
var eh = new PinUnpinHandler(tabs[3], "TabPin");
|
||||
gBrowser.pinTab(tabs[3]);
|
||||
is(eh.eventCount, 2, "TabPin event should be fired");
|
||||
indexTest(0, 1);
|
||||
indexTest(1, 2);
|
||||
indexTest(2, 3);
|
||||
indexTest(3, 0);
|
||||
|
||||
eh = new PinUnpinHandler(tabs[1], "TabPin");
|
||||
gBrowser.pinTab(tabs[1]);
|
||||
is(eh.eventCount, 2, "TabPin event should be fired");
|
||||
indexTest(0, 2);
|
||||
indexTest(1, 1);
|
||||
indexTest(2, 3);
|
||||
@ -36,10 +57,14 @@ function test() {
|
||||
gBrowser.moveTabTo(tabs[2], 0);
|
||||
indexTest(2, 2, "shouldn't be able to mix a normal tab into pinned tabs");
|
||||
|
||||
eh = new PinUnpinHandler(tabs[1], "TabUnpin");
|
||||
gBrowser.unpinTab(tabs[1]);
|
||||
is(eh.eventCount, 2, "TabUnpin event should be fired");
|
||||
indexTest(1, 1, "unpinning a tab should move a tab to the start of normal tabs");
|
||||
|
||||
eh = new PinUnpinHandler(tabs[3], "TabUnpin");
|
||||
gBrowser.unpinTab(tabs[3]);
|
||||
is(eh.eventCount, 2, "TabUnpin event should be fired");
|
||||
indexTest(3, 0, "unpinning a tab should move a tab to the start of normal tabs");
|
||||
|
||||
gBrowser.removeTab(tabs[1]);
|
||||
|
@ -1,4 +1,5 @@
|
||||
const gTestRoot = "chrome://mochikit/content/browser/browser/base/content/test/";
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
const gTestRoot = rootDir;
|
||||
|
||||
var gTestBrowser = null;
|
||||
var gNextTest = null;
|
||||
|
@ -4,7 +4,7 @@
|
||||
<title>Test file for bug 550565.</title>
|
||||
|
||||
<!--Set a favicon; that's the whole point of this file.-->
|
||||
<link rel="icon" href="chrome://mochikit/content/browser/browser/base/content/test/file_bug550565_favicon.ico">
|
||||
<link rel="icon" href="file_bug550565_favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
Test file for bug 550565.
|
||||
|
@ -48,6 +48,11 @@ _BROWSER_FILES = \
|
||||
browser_tabview_dragdrop.js \
|
||||
browser_tabview_group.js \
|
||||
browser_tabview_search.js \
|
||||
browser_tabview_snapping.js \
|
||||
browser_tabview_bug591706.js \
|
||||
browser_tabview_apptabs.js \
|
||||
browser_tabview_undo_group.js \
|
||||
browser_tabview_exit_button.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
|
89
browser/base/content/test/tabview/browser_tabview_apptabs.js
Normal file
89
browser/base/content/test/tabview/browser_tabview_apptabs.js
Normal file
@ -0,0 +1,89 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is tabview group test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
* Ian Gilman <ian@iangilman.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
TabView.toggle();
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
|
||||
// establish initial state
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "we start with one group (the default)");
|
||||
is(gBrowser.tabs.length, 1, "we start with one tab");
|
||||
|
||||
// create an app tab
|
||||
let appXulTab = gBrowser.loadOneTab("about:blank");
|
||||
gBrowser.pinTab(appXulTab);
|
||||
is(gBrowser.tabs.length, 2, "we now have two tabs");
|
||||
|
||||
// Create a group
|
||||
let box = new contentWindow.Rect(20, 20, 180, 180);
|
||||
let groupItem = new contentWindow.GroupItem([], { bounds: box });
|
||||
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
|
||||
|
||||
// find app tab in group and hit it
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
ok(!TabView.isVisible(), "Tab View is hidden because we clicked on the app tab");
|
||||
|
||||
// clean up
|
||||
gBrowser.unpinTab(appXulTab);
|
||||
gBrowser.removeTab(appXulTab);
|
||||
is(gBrowser.tabs.length, 1, "we finish with one tab");
|
||||
|
||||
groupItem.close();
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "we finish with one group");
|
||||
|
||||
ok(!TabView.isVisible(), "Tab View is not visible");
|
||||
|
||||
finish();
|
||||
};
|
||||
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
let appTabButtons = groupItem.$appTabTray[0].getElementsByTagName("img");
|
||||
ok(appTabButtons.length == 1, "there is one app tab button");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, appTabButtons[0], contentWindow);
|
||||
}
|
142
browser/base/content/test/tabview/browser_tabview_bug591706.js
Normal file
142
browser/base/content/test/tabview/browser_tabview_bug591706.js
Normal file
@ -0,0 +1,142 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is bug 591706 test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
if (TabView.isVisible())
|
||||
onTabViewWindowLoaded();
|
||||
else
|
||||
TabView.show();
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
let [originalTab] = gBrowser.visibleTabs;
|
||||
|
||||
// Create a first tab and orphan it
|
||||
let firstTab = gBrowser.loadOneTab("about:blank#1", {inBackground: true});
|
||||
let firstTabItem = firstTab.tabItem;
|
||||
let currentGroup = contentWindow.GroupItems.getActiveGroupItem();
|
||||
ok(currentGroup.getChildren().some(function(child) child == firstTabItem),"The first tab was made in the current group");
|
||||
contentWindow.GroupItems.getActiveGroupItem().remove(firstTabItem);
|
||||
ok(!currentGroup.getChildren().some(function(child) child == firstTabItem),"The first tab was orphaned");
|
||||
|
||||
// Create a group and make it active
|
||||
let box = new contentWindow.Rect(10, 10, 300, 300);
|
||||
let group = new contentWindow.GroupItem([], { bounds: box });
|
||||
ok(group.isEmpty(), "This group is empty");
|
||||
contentWindow.GroupItems.setActiveGroupItem(group);
|
||||
|
||||
// Create a second tab in this new group
|
||||
let secondTab = gBrowser.loadOneTab("about:blank#2", {inBackground: true});
|
||||
let secondTabItem = secondTab.tabItem;
|
||||
ok(group.getChildren().some(function(child) child == secondTabItem),"The second tab was made in our new group");
|
||||
is(group.getChildren().length, 1, "Only one tab in the first group");
|
||||
isnot(firstTab.linkedBrowser.contentWindow.location, secondTab.linkedBrowser.contentWindow.location, "The two tabs must have different locations");
|
||||
|
||||
// Add the first tab to the group *programmatically*, without specifying a dropPos
|
||||
group.add(firstTabItem);
|
||||
is(group.getChildren().length, 2, "Two tabs in the group");
|
||||
is(group.getChildren()[0].tab.linkedBrowser.contentWindow.location, secondTab.linkedBrowser.contentWindow.location, "The second tab was there first");
|
||||
is(group.getChildren()[1].tab.linkedBrowser.contentWindow.location, firstTab.linkedBrowser.contentWindow.location, "The first tab was just added and went to the end of the line");
|
||||
|
||||
group.addSubscriber(group, "close", function() {
|
||||
group.removeSubscriber(group, "close");
|
||||
|
||||
ok(group.isEmpty(), "The group is empty again");
|
||||
|
||||
is(contentWindow.GroupItems.getActiveGroupItem(), null, "The active group is gone");
|
||||
contentWindow.GroupItems.setActiveGroupItem(currentGroup);
|
||||
isnot(contentWindow.GroupItems.getActiveGroupItem(), null, "There is an active group");
|
||||
is(gBrowser.tabs.length, 1, "There is only one tab left");
|
||||
is(gBrowser.visibleTabs.length, 1, "There is also only one visible tab");
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
finish();
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
gBrowser.selectedTab = originalTab;
|
||||
|
||||
TabView.hide();
|
||||
});
|
||||
|
||||
// Get rid of the group and its children
|
||||
group.closeAll();
|
||||
// close undo group
|
||||
let closeButton = group.$undoContainer.find(".close");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" }, closeButton[0], contentWindow);
|
||||
}
|
||||
|
||||
function simulateDragDrop(srcElement, offsetX, offsetY, contentWindow) {
|
||||
// enter drag mode
|
||||
let dataTransfer;
|
||||
|
||||
EventUtils.synthesizeMouse(
|
||||
srcElement, 1, 1, { type: "mousedown" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 1, null, dataTransfer);
|
||||
srcElement.dispatchEvent(event);
|
||||
|
||||
// drag over
|
||||
for (let i = 4; i >= 0; i--)
|
||||
EventUtils.synthesizeMouse(
|
||||
srcElement, Math.round(offsetX/5), Math.round(offsetY/4),
|
||||
{ type: "mousemove" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"dragover", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 0, null, dataTransfer);
|
||||
srcElement.dispatchEvent(event);
|
||||
|
||||
// drop
|
||||
EventUtils.synthesizeMouse(srcElement, 0, 0, { type: "mouseup" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"drop", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 0, null, dataTransfer);
|
||||
srcElement.dispatchEvent(event);
|
||||
}
|
@ -52,10 +52,6 @@ function onTabViewWindowLoaded() {
|
||||
let [originalTab] = gBrowser.visibleTabs;
|
||||
|
||||
// create group one and two
|
||||
let padding = 10;
|
||||
let pageBounds = contentWindow.Items.getPageBounds();
|
||||
pageBounds.inset(padding, padding);
|
||||
|
||||
let boxOne = new contentWindow.Rect(20, 20, 300, 300);
|
||||
let groupOne = new contentWindow.GroupItem([], { bounds: boxOne });
|
||||
ok(groupOne.isEmpty(), "This group is empty");
|
||||
@ -118,7 +114,11 @@ function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
groupTwo.closeAll();
|
||||
groupTwo.closeAll();
|
||||
// close undo group
|
||||
let closeButton = groupTwo.$undoContainer.find(".close");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" }, closeButton[0], contentWindow);
|
||||
};
|
||||
groupTwo.addSubscriber(groupTwo, "close", function() {
|
||||
groupTwo.removeSubscriber(groupTwo, "close");
|
||||
|
@ -0,0 +1,62 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is tabview exit button test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let onTabViewShown = function() {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
let button = contentWindow.document.getElementById("exit-button");
|
||||
|
||||
ok(button, "Exit button exists");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, button, contentWindow);
|
||||
}
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
finish();
|
||||
}
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
TabView.toggle();
|
||||
}
|
202
browser/base/content/test/tabview/browser_tabview_snapping.js
Normal file
202
browser/base/content/test/tabview/browser_tabview_snapping.js
Normal file
@ -0,0 +1,202 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Tab View snapping test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
if (TabView.isVisible())
|
||||
onTabViewWindowLoaded();
|
||||
else
|
||||
TabView.show();
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
let [originalTab] = gBrowser.visibleTabs;
|
||||
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "There is only one group");
|
||||
let currentActiveGroup = contentWindow.GroupItems.getActiveGroupItem();
|
||||
|
||||
// Create a group
|
||||
// Note: 150 x 150 should be larger than the minimum size for a group item
|
||||
let firstBox = new contentWindow.Rect(80, 80, 160, 160);
|
||||
let firstGroup = new contentWindow.GroupItem([], { bounds: firstBox });
|
||||
ok(firstGroup.getBounds().equals(firstBox), "This group got its bounds");
|
||||
|
||||
// Create a second group
|
||||
let secondBox = new contentWindow.Rect(80, 280, 160, 160);
|
||||
let secondGroup = new contentWindow.GroupItem([], { bounds: secondBox });
|
||||
ok(secondGroup.getBounds().equals(secondBox), "This second group got its bounds");
|
||||
|
||||
// A third group is created later, but multiple functions need access to it.
|
||||
let thirdGroup = null;
|
||||
|
||||
is(secondGroup.getBounds().top - firstGroup.getBounds().bottom, 40,
|
||||
"There's currently 40 px between the first group and second group");
|
||||
|
||||
let endGame = function() {
|
||||
dump("END GAME!");
|
||||
firstGroup.container.parentNode.removeChild(firstGroup.container);
|
||||
firstGroup.close();
|
||||
thirdGroup.container.parentNode.removeChild(thirdGroup.container);
|
||||
thirdGroup.close();
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
ok(!TabView.isVisible(), "TabView is shown");
|
||||
finish();
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
ok(TabView.isVisible(), "TabView is shown");
|
||||
|
||||
gBrowser.selectedTab = originalTab;
|
||||
TabView.hide();
|
||||
}
|
||||
|
||||
let continueWithPart2 = function() {
|
||||
|
||||
ok(firstGroup.getBounds().equals(firstBox), "The first group should still have its bounds");
|
||||
|
||||
// Create a third group
|
||||
let thirdBox = new contentWindow.Rect(80, 280, 200, 160);
|
||||
thirdGroup = new contentWindow.GroupItem([], { bounds: thirdBox });
|
||||
ok(thirdGroup.getBounds().equals(thirdBox), "This third group got its bounds");
|
||||
|
||||
is(thirdGroup.getBounds().top - firstGroup.getBounds().bottom, 40,
|
||||
"There's currently 40 px between the first group and third group");
|
||||
|
||||
// Just move it to the left and drop it.
|
||||
checkSnap(thirdGroup, 0, 0, contentWindow, function(snapped){
|
||||
ok(!snapped,"Offset: Just move it to the left and drop it");
|
||||
|
||||
// Move the second group up 10 px. It shouldn't snap yet.
|
||||
checkSnap(thirdGroup, 0, -10, contentWindow, function(snapped){
|
||||
ok(!snapped,"Offset: Moving up 10 should not snap");
|
||||
|
||||
// Move the second group up 10 px. It now should snap.
|
||||
checkSnap(thirdGroup, 0, -10, contentWindow, function(snapped){
|
||||
ok(snapped,"Offset: Moving up 10 again should snap!");
|
||||
contentWindow.Utils.log('endGame!');
|
||||
endGame();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
let part1 = function() {
|
||||
// Just pick it up and drop it.
|
||||
checkSnap(secondGroup, 0, 0, contentWindow, function(snapped){
|
||||
ok(!snapped,"Right under: Just pick it up and drop it");
|
||||
|
||||
// Move the second group up 10 px. It shouldn't snap yet.
|
||||
checkSnap(secondGroup, 0, -10, contentWindow, function(snapped){
|
||||
ok(!snapped,"Right under: Moving up 10 should not snap");
|
||||
|
||||
// Move the second group up 10 px. It now should snap.
|
||||
checkSnap(secondGroup, 0, -10, contentWindow, function(snapped){
|
||||
ok(snapped,"Right under: Moving up 10 again should snap!");
|
||||
// cheat by removing the second group, so that we disappear immediately
|
||||
secondGroup.container.parentNode.removeChild(secondGroup.container);
|
||||
secondGroup.close();
|
||||
continueWithPart2();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
part1();
|
||||
}
|
||||
|
||||
function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
|
||||
// enter drag mode
|
||||
let dataTransfer;
|
||||
|
||||
EventUtils.synthesizeMouse(
|
||||
tabItem.container, 1, 1, { type: "mousedown" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 1, null, dataTransfer);
|
||||
tabItem.container.dispatchEvent(event);
|
||||
|
||||
// drag over
|
||||
if (offsetX || offsetY) {
|
||||
let Ci = Components.interfaces;
|
||||
let utils = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils);
|
||||
let rect = tabItem.getBounds();
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
let left = rect.left + 1 + Math.round(i * offsetX / 5);
|
||||
let top = rect.top + 1 + Math.round(i * offsetY / 5);
|
||||
utils.sendMouseEvent("mousemove", left, top, 0, 1, 0);
|
||||
}
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"dragover", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 0, null, dataTransfer);
|
||||
tabItem.container.dispatchEvent(event);
|
||||
}
|
||||
|
||||
// drop
|
||||
EventUtils.synthesizeMouse(
|
||||
tabItem.container, 0, 0, { type: "mouseup" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"drop", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 0, null, dataTransfer);
|
||||
tabItem.container.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function checkSnap(item, offsetX, offsetY, contentWindow, callback) {
|
||||
let firstTop = item.getBounds().top;
|
||||
let firstLeft = item.getBounds().left;
|
||||
let onDrop = function() {
|
||||
let snapped = false;
|
||||
item.container.removeEventListener('drop', onDrop, false);
|
||||
if (item.getBounds().top != firstTop + offsetY)
|
||||
snapped = true;
|
||||
if (item.getBounds().left != firstLeft + offsetX)
|
||||
snapped = true;
|
||||
callback(snapped);
|
||||
};
|
||||
item.container.addEventListener('drop', onDrop, false);
|
||||
simulateDragDrop(item, offsetX, offsetY, contentWindow);
|
||||
}
|
168
browser/base/content/test/tabview/browser_tabview_undo_group.js
Normal file
168
browser/base/content/test/tabview/browser_tabview_undo_group.js
Normal file
@ -0,0 +1,168 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is tabview undo group test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
TabView.toggle();
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
|
||||
// create a group item
|
||||
let box = new contentWindow.Rect(20, 400, 300, 300);
|
||||
let groupItem = new contentWindow.GroupItem([], { bounds: box });
|
||||
|
||||
// create a tab item in the new group
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
ok(!TabView.isVisible(), "Tab View is hidden because we just opened a tab");
|
||||
// show tab view
|
||||
TabView.toggle();
|
||||
};
|
||||
let onTabViewShown = function() {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
|
||||
is(groupItem.getChildren().length, 1, "The new group has a tab item");
|
||||
// start the tests
|
||||
testUndoGroup(contentWindow, groupItem);
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
|
||||
// click on the + button
|
||||
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
|
||||
ok(newTabButton[0], "New tab button exists");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow);
|
||||
}
|
||||
|
||||
function testUndoGroup(contentWindow, groupItem) {
|
||||
groupItem.addSubscriber(groupItem, "groupHidden", function() {
|
||||
groupItem.removeSubscriber(groupItem, "groupHidden");
|
||||
|
||||
// check the data of the group
|
||||
let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id);
|
||||
ok(theGroupItem, "The group item still exists");
|
||||
is(theGroupItem.getChildren().length, 1,
|
||||
"The tab item in the group still exists");
|
||||
|
||||
// check the visibility of the group element and undo element
|
||||
is(theGroupItem.container.style.display, "none",
|
||||
"The group element is hidden");
|
||||
ok(theGroupItem.$undoContainer, "Undo container is avaliable");
|
||||
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" }, theGroupItem.$undoContainer[0], contentWindow);
|
||||
});
|
||||
|
||||
groupItem.addSubscriber(groupItem, "groupShown", function() {
|
||||
groupItem.removeSubscriber(groupItem, "groupShown");
|
||||
|
||||
// check the data of the group
|
||||
let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id);
|
||||
ok(theGroupItem, "The group item still exists");
|
||||
is(theGroupItem.getChildren().length, 1,
|
||||
"The tab item in the group still exists");
|
||||
|
||||
// check the visibility of the group element and undo element
|
||||
is(theGroupItem.container.style.display, "", "The group element is visible");
|
||||
ok(!theGroupItem.$undoContainer, "Undo container is not avaliable");
|
||||
|
||||
// start the next test
|
||||
testCloseUndoGroup(contentWindow, groupItem);
|
||||
});
|
||||
|
||||
let closeButton = groupItem.container.getElementsByClassName("close");
|
||||
ok(closeButton, "Group item close button exists");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
|
||||
}
|
||||
|
||||
function testCloseUndoGroup(contentWindow, groupItem) {
|
||||
groupItem.addSubscriber(groupItem, "groupHidden", function() {
|
||||
groupItem.removeSubscriber(groupItem, "groupHidden");
|
||||
|
||||
// check the data of the group
|
||||
let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id);
|
||||
ok(theGroupItem, "The group item still exists");
|
||||
is(theGroupItem.getChildren().length, 1,
|
||||
"The tab item in the group still exists");
|
||||
|
||||
// check the visibility of the group element and undo element
|
||||
is(theGroupItem.container.style.display, "none",
|
||||
"The group element is hidden");
|
||||
ok(theGroupItem.$undoContainer, "Undo container is avaliable");
|
||||
|
||||
// click on close
|
||||
let closeButton = theGroupItem.$undoContainer.find(".close");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" }, closeButton[0], contentWindow);
|
||||
});
|
||||
|
||||
groupItem.addSubscriber(groupItem, "close", function() {
|
||||
groupItem.removeSubscriber(groupItem, "close");
|
||||
|
||||
let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id);
|
||||
ok(!theGroupItem, "The group item doesn't exists");
|
||||
|
||||
let endGame = function() {
|
||||
window.removeEventListener("tabviewhidden", endGame, false);
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
finish();
|
||||
};
|
||||
window.addEventListener("tabviewhidden", endGame, false);
|
||||
|
||||
// after the last selected tabitem is closed, there would be not active
|
||||
// tabitem on the UI so we set the active tabitem before toggling the
|
||||
// visibility of tabview
|
||||
let tabItems = contentWindow.TabItems.getItems();
|
||||
ok(tabItems[0], "A tab item exists");
|
||||
contentWindow.UI.setActiveTab(tabItems[0]);
|
||||
|
||||
TabView.toggle();
|
||||
});
|
||||
|
||||
let closeButton = groupItem.container.getElementsByClassName("close");
|
||||
ok(closeButton, "Group item close button exists");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
|
||||
}
|
@ -1,2 +1,2 @@
|
||||
# Do NOT localize or otherwise change these values
|
||||
browser.startup.homepage=http://www.mozilla.org/projects/minefield/
|
||||
browser.startup.homepage=about:home
|
||||
|
@ -1,3 +1,2 @@
|
||||
# Do NOT localize or otherwise change these values
|
||||
browser.startup.homepage=http://www.mozilla.org/projects/devpreview/
|
||||
|
||||
browser.startup.homepage=about:home
|
||||
|
@ -29,5 +29,5 @@ category command-line-validator b-browser @mozilla.org/browser/clh;1 application
|
||||
component {eab9012e-5f74-4cbc-b2b5-a590235513cc} nsBrowserGlue.js
|
||||
contract @mozilla.org/browser/browserglue;1 {eab9012e-5f74-4cbc-b2b5-a590235513cc}
|
||||
category app-startup nsBrowserGlue service,@mozilla.org/browser/browserglue;1
|
||||
component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} nsBrowserGlue.js
|
||||
contract @mozilla.org/geolocation/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}
|
||||
component {d8903bf6-68d5-4e97-bcd1-e4d3012f721a} nsBrowserGlue.js
|
||||
contract @mozilla.org/content-permission/prompt;1 {d8903bf6-68d5-4e97-bcd1-e4d3012f721a}
|
||||
|
@ -1323,15 +1323,20 @@ BrowserGlue.prototype = {
|
||||
_xpcom_factory: BrowserGlueServiceFactory,
|
||||
}
|
||||
|
||||
function GeolocationPrompt() {}
|
||||
function ContentPermissionPrompt() {}
|
||||
|
||||
GeolocationPrompt.prototype = {
|
||||
classID: Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"),
|
||||
ContentPermissionPrompt.prototype = {
|
||||
classID: Components.ID("{d8903bf6-68d5-4e97-bcd1-e4d3012f721a}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGeolocationPrompt]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
|
||||
|
||||
prompt: function GP_prompt(request) {
|
||||
var requestingURI = request.requestingURI;
|
||||
prompt: function CPP_prompt(request) {
|
||||
|
||||
if (request.type != "geolocation") {
|
||||
return;
|
||||
}
|
||||
|
||||
var requestingURI = request.uri;
|
||||
|
||||
// Ignore requests from non-nsIStandardURLs
|
||||
if (!(requestingURI instanceof Ci.nsIStandardURL))
|
||||
@ -1382,7 +1387,7 @@ GeolocationPrompt.prototype = {
|
||||
// Different message/options if it is a local file
|
||||
if (requestingURI.schemeIs("file")) {
|
||||
message = browserBundle.formatStringFromName("geolocation.fileWantsToKnow",
|
||||
[request.requestingURI.path], 1);
|
||||
[requestingURI.path], 1);
|
||||
} else {
|
||||
message = browserBundle.formatStringFromName("geolocation.siteWantsToKnow",
|
||||
[requestingURI.host], 1);
|
||||
@ -1412,7 +1417,7 @@ GeolocationPrompt.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
var requestingWindow = request.requestingWindow.top;
|
||||
var requestingWindow = request.window.top;
|
||||
var chromeWin = getChromeWindow(requestingWindow).wrappedJSObject;
|
||||
var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document);
|
||||
|
||||
@ -1421,5 +1426,5 @@ GeolocationPrompt.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
var components = [BrowserGlue, GeolocationPrompt];
|
||||
var components = [BrowserGlue, ContentPermissionPrompt];
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
// Load DownloadUtils module for convertByteUnits
|
||||
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gAdvancedPane = {
|
||||
_inited: false,
|
||||
@ -170,6 +171,17 @@ var gAdvancedPane = {
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
/**
|
||||
* When the user toggles the layers.accelerate-none pref,
|
||||
* sync its new value to the gfx.direct2d.disabled pref too.
|
||||
*/
|
||||
updateHardwareAcceleration: function()
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
var pref = document.getElementById("layers.accelerate-none");
|
||||
Services.prefs.setBoolPref("gfx.direct2d.disabled", !pref.value);
|
||||
#endif
|
||||
},
|
||||
|
||||
// NETWORK TAB
|
||||
|
||||
|
@ -68,9 +68,8 @@
|
||||
|
||||
<preference id="general.autoScroll" name="general.autoScroll" type="bool"/>
|
||||
<preference id="general.smoothScroll" name="general.smoothScroll" type="bool"/>
|
||||
#ifdef XP_WIN
|
||||
<preference id="gfx.direct2d.disabled" name="gfx.direct2d.disabled" type="bool" inverted="true"/>
|
||||
#endif
|
||||
<preference id="layers.accelerate-none" name="layers.accelerate-none" type="bool" inverted="true"
|
||||
onchange="gAdvancedPane.updateHardwareAcceleration()"/>
|
||||
<preference id="layout.spellcheckDefault" name="layout.spellcheckDefault" type="int"/>
|
||||
|
||||
#ifdef HAVE_SHELL_SERVICE
|
||||
@ -177,12 +176,10 @@
|
||||
label="&useSmoothScrolling.label;"
|
||||
accesskey="&useSmoothScrolling.accesskey;"
|
||||
preference="general.smoothScroll"/>
|
||||
#ifdef XP_WIN
|
||||
<checkbox id="allowHWAccel"
|
||||
label="&allowHWAccel.label;"
|
||||
accesskey="&allowHWAccel.accesskey;"
|
||||
preference="gfx.direct2d.disabled"/>
|
||||
#endif
|
||||
preference="layers.accelerate-none"/>
|
||||
<checkbox id="checkSpelling"
|
||||
label="&checkSpelling.label;"
|
||||
accesskey="&checkSpelling.accesskey;"
|
||||
|
@ -38,7 +38,14 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_pane_visibility,
|
||||
|
@ -38,7 +38,14 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_historymode_retention("remember", undefined),
|
||||
|
@ -38,7 +38,13 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("rememberHistory", "remember"),
|
||||
|
@ -38,7 +38,13 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("acceptCookies", "remember"),
|
||||
|
@ -38,7 +38,13 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_locbar_suggestion_retention(-1, undefined),
|
||||
|
@ -38,7 +38,13 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_privatebrowsing_toggle,
|
||||
|
@ -38,7 +38,13 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_privatebrowsing_ui,
|
||||
|
@ -37,7 +37,13 @@
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
// history mode should be initialized to remember
|
||||
|
@ -43,7 +43,7 @@
|
||||
* - and allows to restore everything into one window.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(c0b185e7-0d21-46ac-8eee-7b5065ee7ecd)]
|
||||
[scriptable, uuid(e7bb7828-0e32-4995-a848-4aa35df603c7)]
|
||||
interface nsISessionStartup: nsISupports
|
||||
{
|
||||
// Get session state as string
|
||||
@ -55,13 +55,18 @@ interface nsISessionStartup: nsISupports
|
||||
boolean doRestore();
|
||||
|
||||
/**
|
||||
* What type of session we're restoring. If we have a session, we're
|
||||
* either restoring state from a crash or restoring state that the user
|
||||
* requested we save on shutdown.
|
||||
* What type of session we're restoring.
|
||||
* NO_SESSION There is no data available from the previous session
|
||||
* RECOVER_SESSION The last session crashed. It will either be restored or
|
||||
* about:sessionrestore will be shown.
|
||||
* RESUME_SESSION The previous session should be restored at startup
|
||||
* DEFER_SESSION The previous session is fine, but it shouldn't be restored
|
||||
* without explicit action (with the exception of pinned tabs)
|
||||
*/
|
||||
const unsigned long NO_SESSION = 0;
|
||||
const unsigned long RECOVER_SESSION = 1;
|
||||
const unsigned long RESUME_SESSION = 2;
|
||||
const unsigned long DEFER_SESSION = 3;
|
||||
|
||||
readonly attribute unsigned long sessionType;
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ interface nsIDOMNode;
|
||||
* |gBrowser.tabContainer| such as e.g. |gBrowser.selectedTab|.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(70592a0d-87d3-459c-8db7-dcb8d47af78e)]
|
||||
[scriptable, uuid(59bfaf00-e3d8-4728-b4f0-cc0b9dfb4806)]
|
||||
interface nsISessionStore : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -67,6 +67,24 @@ interface nsISessionStore : nsISupports
|
||||
*/
|
||||
void init(in nsIDOMWindow aWindow);
|
||||
|
||||
/**
|
||||
* Is it possible to restore the previous session. Will always be false when
|
||||
* in Private Browsing mode.
|
||||
*/
|
||||
attribute boolean canRestoreLastSession;
|
||||
|
||||
/**
|
||||
* Restore the previous session if possible. This will not overwrite the
|
||||
* current session. Instead the previous session will be merged into the
|
||||
* current session. Current windows will be reused if they were windows that
|
||||
* pinned tabs were previously restored into. New windows will be opened as
|
||||
* needed.
|
||||
*
|
||||
* Note: This will throw if there is no previous state to restore. Check with
|
||||
* canRestoreLastSession first to avoid thrown errors.
|
||||
*/
|
||||
void restoreLastSession();
|
||||
|
||||
/**
|
||||
* Get the current browsing state.
|
||||
* @returns a JSON string representing the session state.
|
||||
|
@ -152,10 +152,12 @@ SessionStartup.prototype = {
|
||||
this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
|
||||
else if (!lastSessionCrashed && doResumeSession)
|
||||
this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
|
||||
else if (initialState)
|
||||
this._sessionType = Ci.nsISessionStartup.DEFER_SESSION;
|
||||
else
|
||||
this._iniString = null; // reset the state string
|
||||
|
||||
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION) {
|
||||
if (this.doRestore()) {
|
||||
// wait for the first browser window to open
|
||||
|
||||
// Don't reset the initial window's default args (i.e. the home page(s))
|
||||
@ -252,7 +254,8 @@ SessionStartup.prototype = {
|
||||
* @returns bool
|
||||
*/
|
||||
doRestore: function sss_doRestore() {
|
||||
return this._sessionType != Ci.nsISessionStartup.NO_SESSION;
|
||||
return this._sessionType == Ci.nsISessionStartup.RECOVER_SESSION ||
|
||||
this._sessionType == Ci.nsISessionStartup.RESUME_SESSION;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -201,6 +201,23 @@ SessionStoreService.prototype = {
|
||||
// whether the last window was closed and should be restored
|
||||
_restoreLastWindow: false,
|
||||
|
||||
// The state from the previous session (after restoring pinned tabs)
|
||||
_lastSessionState: null,
|
||||
|
||||
/* ........ Public Getters .............. */
|
||||
|
||||
get canRestoreLastSession() {
|
||||
// Always disallow restoring the previous session when in private browsing
|
||||
return this._lastSessionState && !this._inPrivateBrowsing;
|
||||
},
|
||||
|
||||
set canRestoreLastSession(val) {
|
||||
// Cheat a bit; only allow false.
|
||||
if (val)
|
||||
return;
|
||||
this._lastSessionState = null;
|
||||
},
|
||||
|
||||
/* ........ Global Event Handlers .............. */
|
||||
|
||||
/**
|
||||
@ -250,40 +267,54 @@ SessionStoreService.prototype = {
|
||||
|
||||
// get string containing session state
|
||||
var iniString;
|
||||
var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
||||
getService(Ci.nsISessionStartup);
|
||||
try {
|
||||
var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
||||
getService(Ci.nsISessionStartup);
|
||||
if (ss.doRestore())
|
||||
if (ss.doRestore() ||
|
||||
ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION)
|
||||
iniString = ss.state;
|
||||
}
|
||||
catch(ex) { dump(ex + "\n"); } // no state to restore, which is ok
|
||||
|
||||
if (iniString) {
|
||||
try {
|
||||
// parse the session state into JS objects
|
||||
this._initialState = JSON.parse(iniString);
|
||||
|
||||
let lastSessionCrashed =
|
||||
this._initialState.session && this._initialState.session.state &&
|
||||
this._initialState.session.state == STATE_RUNNING_STR;
|
||||
if (lastSessionCrashed) {
|
||||
this._recentCrashes = (this._initialState.session &&
|
||||
this._initialState.session.recentCrashes || 0) + 1;
|
||||
|
||||
if (this._needsRestorePage(this._initialState, this._recentCrashes)) {
|
||||
// replace the crashed session with a restore-page-only session
|
||||
let pageData = {
|
||||
url: "about:sessionrestore",
|
||||
formdata: { "#sessionData": iniString }
|
||||
};
|
||||
this._initialState = { windows: [{ tabs: [{ entries: [pageData] }] }] };
|
||||
}
|
||||
// If we're doing a DEFERRED session, then we want to pull pinned tabs
|
||||
// out so they can be restored.
|
||||
if (ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) {
|
||||
let [iniState, remainingState] = this._prepDataForDeferredRestore(iniString);
|
||||
// If we have a iniState with windows, that means that we have windows
|
||||
// with app tabs to restore.
|
||||
if (iniState.windows.length)
|
||||
this._initialState = iniState;
|
||||
if (remainingState.windows.length)
|
||||
this._lastSessionState = remainingState;
|
||||
}
|
||||
else {
|
||||
// parse the session state into JS objects
|
||||
this._initialState = JSON.parse(iniString);
|
||||
|
||||
let lastSessionCrashed =
|
||||
this._initialState.session && this._initialState.session.state &&
|
||||
this._initialState.session.state == STATE_RUNNING_STR;
|
||||
if (lastSessionCrashed) {
|
||||
this._recentCrashes = (this._initialState.session &&
|
||||
this._initialState.session.recentCrashes || 0) + 1;
|
||||
|
||||
if (this._needsRestorePage(this._initialState, this._recentCrashes)) {
|
||||
// replace the crashed session with a restore-page-only session
|
||||
let pageData = {
|
||||
url: "about:sessionrestore",
|
||||
formdata: { "#sessionData": iniString }
|
||||
};
|
||||
this._initialState = { windows: [{ tabs: [{ entries: [pageData] }] }] };
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that at least the first window doesn't have anything hidden
|
||||
delete this._initialState.windows[0].hidden;
|
||||
// Since nothing is hidden in the first window, it cannot be a popup
|
||||
delete this._initialState.windows[0].isPopup;
|
||||
}
|
||||
|
||||
// make sure that at least the first window doesn't have anything hidden
|
||||
delete this._initialState.windows[0].hidden;
|
||||
// Since nothing is hidden in the first window, it cannot be a popup
|
||||
delete this._initialState.windows[0].isPopup;
|
||||
}
|
||||
catch (ex) { debug("The session file is invalid: " + ex); }
|
||||
}
|
||||
@ -317,11 +348,6 @@ SessionStoreService.prototype = {
|
||||
// save all data for session resuming
|
||||
this.saveState(true);
|
||||
|
||||
if (!this._doResumeSession()) {
|
||||
// discard all session related data
|
||||
this._clearDisk();
|
||||
}
|
||||
|
||||
// Make sure to break our cycle with the save timer
|
||||
if (this._saveTimer) {
|
||||
this._saveTimer.cancel();
|
||||
@ -1134,6 +1160,78 @@ SessionStoreService.prototype = {
|
||||
this.saveStateDelayed();
|
||||
},
|
||||
|
||||
/**
|
||||
* Restores the session state stored in _lastSessionState. This will attempt
|
||||
* to merge data into the current session. If a window was opened at startup
|
||||
* with pinned tab(s), then the remaining data from the previous session for
|
||||
* that window will be opened into that winddow. Otherwise new windows will
|
||||
* be opened.
|
||||
*/
|
||||
restoreLastSession: function sss_restoreLastSession() {
|
||||
// Use the public getter since it also checks PB mode
|
||||
if (!this.canRestoreLastSession)
|
||||
throw (Components.returnCode = Cr.NS_ERROR_FAILURE);
|
||||
|
||||
// First collect each window with its id...
|
||||
let windows = {};
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
if (aWindow.__SS_lastSessionWindowID)
|
||||
windows[aWindow.__SS_lastSessionWindowID] = aWindow;
|
||||
});
|
||||
|
||||
let lastSessionState = this._lastSessionState;
|
||||
|
||||
// This shouldn't ever be the case...
|
||||
if (!lastSessionState.windows.length)
|
||||
throw (Components.returnCode = Cr.NS_ERROR_UNEXPECTED);
|
||||
|
||||
// We're technically doing a restore, so set things up so we send the
|
||||
// notification when we're done. We want to send "sessionstore-browser-state-restored".
|
||||
this._restoreCount = lastSessionState.windows.length;
|
||||
this._browserSetState = true;
|
||||
|
||||
// Restore into windows or open new ones as needed.
|
||||
for (let i = 0; i < lastSessionState.windows.length; i++) {
|
||||
let winState = lastSessionState.windows[i];
|
||||
let lastSessionWindowID = winState.__lastSessionWindowID;
|
||||
// delete lastSessionWindowID so we don't add that to the window again
|
||||
delete winState.__lastSessionWindowID;
|
||||
// Look to see if this window is already open...
|
||||
if (windows[lastSessionWindowID]) {
|
||||
// Since we're not overwriting existing tabs, we want to merge _closedTabs,
|
||||
// putting existing ones first. Then make sure we're respecting the max pref.
|
||||
if (winState._closedTabs && winState._closedTabs.length) {
|
||||
let curWinState = this._windows[windows[lastSessionWindowID].__SSi];
|
||||
curWinState._closedTabs = curWinState._closedTabs.concat(winState._closedTabs);
|
||||
curWinState._closedTabs.splice(this._prefBranch.getIntPref("sessionstore.max_tabs_undo"));
|
||||
}
|
||||
|
||||
// Restore into that window - pretend it's a followup since we'll already
|
||||
// have a focused window.
|
||||
//XXXzpao This is going to merge extData together (taking what was in
|
||||
// winState over what is in the window already), so this is going
|
||||
// to have an effect on Tab Candy.
|
||||
// Bug 588217 should make this go away by merging the group data.
|
||||
this.restoreWindow(windows[lastSessionWindowID], { windows: [winState] },
|
||||
false, true);
|
||||
}
|
||||
else {
|
||||
this._openWindowWithState({ windows: [winState] });
|
||||
}
|
||||
}
|
||||
|
||||
// Merge closed windows from this session with ones from last session
|
||||
if (lastSessionState._closedWindows) {
|
||||
this._closedWindows = this._closedWindows.concat(lastSessionState._closedWindows);
|
||||
this._capClosedWindows();
|
||||
}
|
||||
// Set recent crashes
|
||||
this._recentCrashes = lastSessionState.session &&
|
||||
lastSessionState.session.recentCrashes || 0;
|
||||
|
||||
this._lastSessionState = null;
|
||||
},
|
||||
|
||||
/* ........ Saving Functionality .............. */
|
||||
|
||||
/**
|
||||
@ -1191,9 +1289,11 @@ SessionStoreService.prototype = {
|
||||
tabData.index = history.index + 1;
|
||||
}
|
||||
else if (history && history.count > 0) {
|
||||
for (var j = 0; j < history.count; j++)
|
||||
tabData.entries.push(this._serializeHistoryEntry(history.getEntryAtIndex(j, false),
|
||||
aFullData));
|
||||
for (var j = 0; j < history.count; j++) {
|
||||
let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false),
|
||||
aFullData, aTab.pinned);
|
||||
tabData.entries.push(entry);
|
||||
}
|
||||
tabData.index = history.index + 1;
|
||||
|
||||
// make sure not to cache privacy sensitive data which shouldn't get out
|
||||
@ -1242,7 +1342,8 @@ SessionStoreService.prototype = {
|
||||
delete tabData.extData;
|
||||
|
||||
if (history && browser.docShell instanceof Ci.nsIDocShell)
|
||||
this._serializeSessionStorage(tabData, history, browser.docShell, aFullData);
|
||||
this._serializeSessionStorage(tabData, history, browser.docShell, aFullData,
|
||||
aTab.pinned);
|
||||
|
||||
return tabData;
|
||||
},
|
||||
@ -1254,9 +1355,12 @@ SessionStoreService.prototype = {
|
||||
* nsISHEntry instance
|
||||
* @param aFullData
|
||||
* always return privacy sensitive data (use with care)
|
||||
* @param aIsPinned
|
||||
* the tab is pinned and should be treated differently for privacy
|
||||
* @returns object
|
||||
*/
|
||||
_serializeHistoryEntry: function sss_serializeHistoryEntry(aEntry, aFullData) {
|
||||
_serializeHistoryEntry:
|
||||
function sss_serializeHistoryEntry(aEntry, aFullData, aIsPinned) {
|
||||
var entry = { url: aEntry.URI.spec };
|
||||
|
||||
if (aEntry.title && aEntry.title != entry.url) {
|
||||
@ -1291,8 +1395,8 @@ SessionStoreService.prototype = {
|
||||
|
||||
try {
|
||||
var prefPostdata = this._prefBranch.getIntPref("sessionstore.postdata");
|
||||
if (aEntry.postData && (aFullData ||
|
||||
prefPostdata && this._checkPrivacyLevel(aEntry.URI.schemeIs("https")))) {
|
||||
if (aEntry.postData && (aFullData || prefPostdata &&
|
||||
this._checkPrivacyLevel(aEntry.URI.schemeIs("https"), aIsPinned))) {
|
||||
aEntry.postData.QueryInterface(Ci.nsISeekableStream).
|
||||
seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
var stream = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
@ -1355,7 +1459,8 @@ SessionStoreService.prototype = {
|
||||
for (var i = 0; i < aEntry.childCount; i++) {
|
||||
var child = aEntry.GetChildAt(i);
|
||||
if (child) {
|
||||
entry.children.push(this._serializeHistoryEntry(child, aFullData));
|
||||
entry.children.push(this._serializeHistoryEntry(child, aFullData,
|
||||
aIsPinned));
|
||||
}
|
||||
else { // to maintain the correct frame order, insert a dummy entry
|
||||
entry.children.push({ url: "about:blank" });
|
||||
@ -1381,9 +1486,11 @@ SessionStoreService.prototype = {
|
||||
* That tab's docshell (containing the sessionStorage)
|
||||
* @param aFullData
|
||||
* always return privacy sensitive data (use with care)
|
||||
* @param aIsPinned
|
||||
* the tab is pinned and should be treated differently for privacy
|
||||
*/
|
||||
_serializeSessionStorage:
|
||||
function sss_serializeSessionStorage(aTabData, aHistory, aDocShell, aFullData) {
|
||||
function sss_serializeSessionStorage(aTabData, aHistory, aDocShell, aFullData, aIsPinned) {
|
||||
let storageData = {};
|
||||
let hasContent = false;
|
||||
|
||||
@ -1396,7 +1503,8 @@ SessionStoreService.prototype = {
|
||||
domain = uri.prePath;
|
||||
}
|
||||
catch (ex) { /* this throws for host-less URIs (such as about: or jar:) */ }
|
||||
if (storageData[domain] || !(aFullData || this._checkPrivacyLevel(uri.schemeIs("https"))))
|
||||
if (storageData[domain] ||
|
||||
!(aFullData || this._checkPrivacyLevel(uri.schemeIs("https"), aIsPinned)))
|
||||
continue;
|
||||
|
||||
let storage, storageItemCount = 0;
|
||||
@ -1479,7 +1587,8 @@ SessionStoreService.prototype = {
|
||||
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aBrowser.contentWindow,
|
||||
aTabData.entries[tabIndex],
|
||||
!aTabData._formDataSaved, aFullData);
|
||||
!aTabData._formDataSaved, aFullData,
|
||||
!!aTabData.pinned);
|
||||
aTabData._formDataSaved = true;
|
||||
if (aBrowser.currentURI.spec == "about:config")
|
||||
aTabData.entries[tabIndex].formdata = {
|
||||
@ -1500,18 +1609,21 @@ SessionStoreService.prototype = {
|
||||
* update all form data for this tab
|
||||
* @param aFullData
|
||||
* always return privacy sensitive data (use with care)
|
||||
* @param aIsPinned
|
||||
* the tab is pinned and should be treated differently for privacy
|
||||
*/
|
||||
_updateTextAndScrollDataForFrame:
|
||||
function sss_updateTextAndScrollDataForFrame(aWindow, aContent, aData,
|
||||
aUpdateFormData, aFullData) {
|
||||
aUpdateFormData, aFullData, aIsPinned) {
|
||||
for (var i = 0; i < aContent.frames.length; i++) {
|
||||
if (aData.children && aData.children[i])
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aContent.frames[i],
|
||||
aData.children[i], aUpdateFormData, aFullData);
|
||||
aData.children[i], aUpdateFormData,
|
||||
aFullData, aIsPinned);
|
||||
}
|
||||
var isHTTPS = this._getURIFromString((aContent.parent || aContent).
|
||||
document.location.href).schemeIs("https");
|
||||
if (aFullData || this._checkPrivacyLevel(isHTTPS) ||
|
||||
if (aFullData || this._checkPrivacyLevel(isHTTPS, aIsPinned) ||
|
||||
aContent.top.document.location.href == "about:sessionrestore") {
|
||||
if (aFullData || aUpdateFormData) {
|
||||
let formData = this._collectFormDataForFrame(aContent.document);
|
||||
@ -1642,6 +1754,42 @@ SessionStoreService.prototype = {
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* extract the base domain from a history entry and its children
|
||||
* @param aEntry
|
||||
* the history entry, serialized
|
||||
* @param aHosts
|
||||
* the hash that will be used to store hosts eg, { hostname: true }
|
||||
* @param aCheckPrivacy
|
||||
* should we check the privacy level for https
|
||||
* @param aIsPinned
|
||||
* is the entry we're evaluating for a pinned tab; used only if
|
||||
* aCheckPrivacy
|
||||
*/
|
||||
_extractHostsForCookies:
|
||||
function sss__extractHostsForCookies(aEntry, aHosts, aCheckPrivacy, aIsPinned) {
|
||||
let match;
|
||||
|
||||
if ((match = /^https?:\/\/(?:[^@\/\s]+@)?([\w.-]+)/.exec(aEntry.url)) != null) {
|
||||
if (!aHosts[match[1]] &&
|
||||
(!aCheckPrivacy ||
|
||||
this._checkPrivacyLevel(this._getURIFromString(aEntry.url).schemeIs("https"),
|
||||
aIsPinned))) {
|
||||
// By setting this to true or false, we can determine when looking at
|
||||
// the host in _updateCookies if we should check for privacy.
|
||||
aHosts[match[1]] = aIsPinned;
|
||||
}
|
||||
}
|
||||
else if ((match = /^file:\/\/([^\/]*)/.exec(aEntry.url)) != null) {
|
||||
aHosts[match[1]] = true;
|
||||
}
|
||||
if (aEntry.children) {
|
||||
aEntry.children.forEach(function(entry) {
|
||||
this._extractHostsForCookies(entry, aHosts, aCheckPrivacy, aIsPinned);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* store all hosts for a URL
|
||||
* @param aWindow
|
||||
@ -1649,25 +1797,12 @@ SessionStoreService.prototype = {
|
||||
*/
|
||||
_updateCookieHosts: function sss_updateCookieHosts(aWindow) {
|
||||
var hosts = this._windows[aWindow.__SSi]._hosts = {};
|
||||
|
||||
// get the domain for each URL
|
||||
function extractHosts(aEntry) {
|
||||
var match;
|
||||
if ((match = /^https?:\/\/(?:[^@\/\s]+@)?([\w.-]+)/.exec(aEntry.url)) != null) {
|
||||
if (!hosts[match[1]] && _this._checkPrivacyLevel(_this._getURIFromString(aEntry.url).schemeIs("https"))) {
|
||||
hosts[match[1]] = true;
|
||||
}
|
||||
}
|
||||
else if ((match = /^file:\/\/([^\/]*)/.exec(aEntry.url)) != null) {
|
||||
hosts[match[1]] = true;
|
||||
}
|
||||
if (aEntry.children) {
|
||||
aEntry.children.forEach(extractHosts);
|
||||
}
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
this._windows[aWindow.__SSi].tabs.forEach(function(aTabData) { aTabData.entries.forEach(extractHosts); });
|
||||
this._windows[aWindow.__SSi].tabs.forEach(function(aTabData) {
|
||||
aTabData.entries.forEach(function(entry) {
|
||||
this._extractHostsForCookies(entry, hosts, true, !!aTabData.pinned);
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1695,11 +1830,16 @@ SessionStoreService.prototype = {
|
||||
// MAX_EXPIRY should be 2^63-1, but JavaScript can't handle that precision
|
||||
var MAX_EXPIRY = Math.pow(2, 62);
|
||||
aWindows.forEach(function(aWindow) {
|
||||
for (var host in aWindow._hosts) {
|
||||
if (!aWindow._hosts)
|
||||
return;
|
||||
for (var [host, isPinned] in Iterator(aWindow._hosts)) {
|
||||
var list = CookieSvc.getCookiesFromHost(host);
|
||||
while (list.hasMoreElements()) {
|
||||
var cookie = list.getNext().QueryInterface(Ci.nsICookie2);
|
||||
if (cookie.isSession && _this._checkPrivacyLevel(cookie.isSecure)) {
|
||||
// aWindow._hosts will only have hosts with the right privacy rules,
|
||||
// so there is no need to do anything special with this call to
|
||||
// _checkPrivacyLevel.
|
||||
if (cookie.isSession && _this._checkPrivacyLevel(cookie.isSecure, isPinned)) {
|
||||
// use the cookie's host, path, and name as keys into a hash,
|
||||
// to make sure we serialize each cookie only once
|
||||
if (!(cookie.host in jscookies &&
|
||||
@ -1870,7 +2010,13 @@ SessionStoreService.prototype = {
|
||||
this._updateTextAndScrollData(aWindow);
|
||||
this._updateCookieHosts(aWindow);
|
||||
this._updateWindowFeatures(aWindow);
|
||||
|
||||
|
||||
// Make sure we keep __SS_lastSessionWindowID around for cases like entering
|
||||
// or leaving PB mode.
|
||||
if (aWindow.__SS_lastSessionWindowID)
|
||||
this._windows[aWindow.__SSi].__lastSessionWindowID =
|
||||
aWindow.__SS_lastSessionWindowID;
|
||||
|
||||
this._dirtyWindows[aWindow.__SSi] = false;
|
||||
},
|
||||
|
||||
@ -1968,6 +2114,13 @@ SessionStoreService.prototype = {
|
||||
tabs[t].hidden = winData.tabs[t].hidden;
|
||||
}
|
||||
|
||||
// We want to correlate the window with data from the last session, so
|
||||
// assign another id if we have one. Otherwise clear so we don't do
|
||||
// anything with it.
|
||||
delete aWindow.__SS_lastSessionWindowID;
|
||||
if (winData.__lastSessionWindowID)
|
||||
aWindow.__SS_lastSessionWindowID = winData.__lastSessionWindowID;
|
||||
|
||||
// when overwriting tabs, remove all superflous ones
|
||||
if (aOverwriteTabs && newTabCount < openTabCount) {
|
||||
Array.slice(tabbrowser.tabs, newTabCount, openTabCount)
|
||||
@ -2618,11 +2771,9 @@ SessionStoreService.prototype = {
|
||||
if (this._inPrivateBrowsing)
|
||||
return;
|
||||
|
||||
var pinnedOnly = false;
|
||||
if (this._loadState == STATE_QUITTING && !this._doResumeSession() ||
|
||||
/* if crash recovery is disabled, only save session resuming information */
|
||||
this._loadState == STATE_RUNNING && !this._resume_from_crash)
|
||||
pinnedOnly = true;
|
||||
// If crash recovery is disabled, we only want to resume with pinned tabs
|
||||
// if we crash.
|
||||
let pinnedOnly = this._loadState == STATE_RUNNING && !this._resume_from_crash;
|
||||
|
||||
var oState = this._getCurrentState(aUpdateAll, pinnedOnly);
|
||||
if (!oState)
|
||||
@ -2816,10 +2967,18 @@ SessionStoreService.prototype = {
|
||||
* (distinguishes between encrypted and non-encrypted sites)
|
||||
* @param aIsHTTPS
|
||||
* Bool is encrypted
|
||||
* @param aUseDefaultPref
|
||||
* don't do normal check for deferred
|
||||
* @returns bool
|
||||
*/
|
||||
_checkPrivacyLevel: function sss_checkPrivacyLevel(aIsHTTPS) {
|
||||
return this._prefBranch.getIntPref("sessionstore.privacy_level") < (aIsHTTPS ? PRIVACY_ENCRYPTED : PRIVACY_FULL);
|
||||
_checkPrivacyLevel: function sss_checkPrivacyLevel(aIsHTTPS, aUseDefaultPref) {
|
||||
let pref = "sessionstore.privacy_level";
|
||||
// If we're in the process of quitting and we're not autoresuming the session
|
||||
// then we should treat it as a deferred session. We have a different privacy
|
||||
// pref for that case.
|
||||
if (!aUseDefaultPref && this._loadState == STATE_QUITTING && !this._doResumeSession())
|
||||
pref = "sessionstore.privacy_level_deferred";
|
||||
return this._prefBranch.getIntPref(pref) < (aIsHTTPS ? PRIVACY_ENCRYPTED : PRIVACY_FULL);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2931,6 +3090,133 @@ SessionStoreService.prototype = {
|
||||
sessionAge && sessionAge >= SIX_HOURS_IN_MS);
|
||||
},
|
||||
|
||||
/**
|
||||
* This is going to take a state as provided at startup (via
|
||||
* nsISessionStartup.state) and split it into 2 parts. The first part
|
||||
* (defaultState) will be a state that should still be restored at startup,
|
||||
* while the second part (state) is a state that should be saved for later.
|
||||
* defaultState will be comprised of windows with only pinned tabs, extracted
|
||||
* from state. It will contain the cookies that go along with the history
|
||||
* entries in those tabs. It will also contain window position information.
|
||||
*
|
||||
* defaultState will be restored at startup. state will be placed into
|
||||
* this._lastSessionState and will be kept in case the user explicitly wants
|
||||
* to restore the previous session (publicly exposed as restoreLastSession).
|
||||
*
|
||||
* @param stateString
|
||||
* The state string, presumably from nsISessionStartup.state
|
||||
* @returns [defaultState, state]
|
||||
*/
|
||||
_prepDataForDeferredRestore: function sss__prepDataForDeferredRestore(stateString) {
|
||||
let state = JSON.parse(stateString);
|
||||
let defaultState = { windows: [], selectedWindow: 1 };
|
||||
|
||||
state.selectedWindow = state.selectedWindow || 1;
|
||||
|
||||
// Look at each window, remove pinned tabs, adjust selectedindex,
|
||||
// remove window if necessary.
|
||||
for (let wIndex = 0; wIndex < state.windows.length;) {
|
||||
let window = state.windows[wIndex];
|
||||
window.selected = window.selected || 1;
|
||||
// We're going to put the state of the window into this object
|
||||
let pinnedWindowState = { tabs: [], cookies: []};
|
||||
for (let tIndex = 0; tIndex < window.tabs.length;) {
|
||||
if (window.tabs[tIndex].pinned) {
|
||||
// Adjust window.selected
|
||||
if (tIndex + 1 < window.selected)
|
||||
window.selected -= 1;
|
||||
else if (tIndex + 1 == window.selected)
|
||||
pinnedWindowState.selected = pinnedWindowState.tabs.length + 2;
|
||||
// + 2 because the tab isn't actually in the array yet
|
||||
|
||||
// Now add the pinned tab to our window
|
||||
pinnedWindowState.tabs =
|
||||
pinnedWindowState.tabs.concat(window.tabs.splice(tIndex, 1));
|
||||
// We don't want to increment tIndex here.
|
||||
continue;
|
||||
}
|
||||
tIndex++;
|
||||
}
|
||||
|
||||
// At this point the window in the state object has been modified (or not)
|
||||
// We want to build the rest of this new window object if we have pinnedTabs.
|
||||
if (pinnedWindowState.tabs.length) {
|
||||
// First get the other attributes off the window
|
||||
WINDOW_ATTRIBUTES.forEach(function(attr) {
|
||||
if (attr in window) {
|
||||
pinnedWindowState[attr] = window[attr];
|
||||
delete window[attr];
|
||||
}
|
||||
});
|
||||
// We're just copying position data into the pinned window.
|
||||
// Not copying over:
|
||||
// - _closedTabs
|
||||
// - extData
|
||||
// - isPopup
|
||||
// - hidden
|
||||
|
||||
// Assign a unique ID to correlate the window to be opened with the
|
||||
// remaining data
|
||||
window.__lastSessionWindowID = pinnedWindowState.__lastSessionWindowID
|
||||
= "" + Date.now() + Math.random();
|
||||
|
||||
// Extract the cookies that belong with each pinned tab
|
||||
this._splitCookiesFromWindow(window, pinnedWindowState);
|
||||
|
||||
// Actually add this window to our defaultState
|
||||
defaultState.windows.push(pinnedWindowState);
|
||||
// Remove the window from the state if it doesn't have any tabs
|
||||
if (!window.tabs.length) {
|
||||
if (wIndex + 1 <= state.selectedWindow)
|
||||
state.selectedWindow -= 1;
|
||||
else if (wIndex + 1 == state.selectedWindow)
|
||||
defaultState.selectedIndex = defaultState.windows.length + 1;
|
||||
|
||||
state.windows.splice(wIndex, 1);
|
||||
// We don't want to increment wIndex here.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
wIndex++;
|
||||
}
|
||||
|
||||
return [defaultState, state];
|
||||
},
|
||||
|
||||
/**
|
||||
* Splits out the cookies from aWinState into aTargetWinState based on the
|
||||
* tabs that are in aTargetWinState.
|
||||
* This alters the state of aWinState and aTargetWinState.
|
||||
*/
|
||||
_splitCookiesFromWindow:
|
||||
function sss__splitCookiesFromWindow(aWinState, aTargetWinState) {
|
||||
if (!aWinState.cookies || !aWinState.cookies.length)
|
||||
return;
|
||||
|
||||
// Get the hosts for history entries in aTargetWinState
|
||||
let cookieHosts = {};
|
||||
aTargetWinState.tabs.forEach(function(tab) {
|
||||
tab.entries.forEach(function(entry) {
|
||||
this._extractHostsForCookies(entry, cookieHosts, false)
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
// By creating a regex we reduce overhead and there is only one loop pass
|
||||
// through either array (cookieHosts and aWinState.cookies).
|
||||
let hosts = Object.keys(cookieHosts).join("|").replace("\\.", "\\.", "g");
|
||||
let cookieRegex = new RegExp(".*(" + hosts + ")");
|
||||
for (let cIndex = 0; cIndex < aWinState.cookies.length;) {
|
||||
if (cookieRegex.test(aWinState.cookies[cIndex].host)) {
|
||||
aTargetWinState.cookies =
|
||||
aTargetWinState.cookies.concat(aWinState.cookies.splice(cIndex, 1));
|
||||
continue;
|
||||
}
|
||||
cIndex++;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a JavaScript object into a JSON string
|
||||
* (see http://www.json.org/ for more information).
|
||||
@ -2941,9 +3227,16 @@ SessionStoreService.prototype = {
|
||||
* @returns the object's JSON representation
|
||||
*/
|
||||
_toJSONString: function sss_toJSONString(aJSObject) {
|
||||
// We never want to save __lastSessionWindowID across sessions, but we do
|
||||
// want it exported to consumers when running (eg. Private Browsing).
|
||||
let internalKeys = INTERNAL_KEYS;
|
||||
if (this._loadState == STATE_QUITTING) {
|
||||
internalKeys = internalKeys.slice();
|
||||
internalKeys.push("__lastSessionWindowID");
|
||||
}
|
||||
function exclude(key, value) {
|
||||
// returning undefined results in the exclusion of that key
|
||||
return INTERNAL_KEYS.indexOf(key) == -1 ? value : undefined;
|
||||
return internalKeys.indexOf(key) == -1 ? value : undefined;
|
||||
}
|
||||
return JSON.stringify(aJSObject, exclude);
|
||||
},
|
||||
|
@ -117,8 +117,8 @@ function test() {
|
||||
// Test (B) : Session data restoration between modes //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
const testURL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_248970_b_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
const testURL = rootDir + "browser_248970_b_sample.html";
|
||||
const testURL2 = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_248970_b_sample.html";
|
||||
|
||||
|
@ -117,8 +117,8 @@ function test() {
|
||||
// make sure we don't save form data at all (except for tab duplication)
|
||||
gPrefService.setIntPref("browser.sessionstore.privacy_level", 2);
|
||||
|
||||
let testURL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_346337_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_346337_sample.html";
|
||||
let tab = tabbrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
@ -40,8 +40,8 @@ function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let pendingCount = 1;
|
||||
let testUrl = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_408470_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testUrl = rootDir + "browser_408470_sample.html";
|
||||
let tab = gBrowser.addTab(testUrl);
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
|
@ -47,8 +47,8 @@ function test() {
|
||||
// make sure we do save form data
|
||||
gPrefService.setIntPref("browser.sessionstore.privacy_level", 0);
|
||||
|
||||
let testURL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_454908_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_454908_sample.html";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
@ -42,8 +42,8 @@ function test() {
|
||||
// make sure we do save form data
|
||||
gPrefService.setIntPref("browser.sessionstore.privacy_level", 0);
|
||||
|
||||
let testURL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_456342_sample.xhtml";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_456342_sample.xhtml";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
@ -22,8 +22,7 @@
|
||||
var documentInjected = false;
|
||||
document.getElementsByTagName("iframe")[0].onload =
|
||||
function() { documentInjected = true; };
|
||||
frames[0].location = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_459906_empty.html";
|
||||
frames[0].location = "browser_459906_empty.html";
|
||||
|
||||
// ... and ensure that it has time to load
|
||||
for (var c = 0; !documentInjected && c < 20; c++) {
|
||||
|
@ -39,15 +39,14 @@ function test() {
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testURL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_463205_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_463205_sample.html";
|
||||
|
||||
let doneURL = "done";
|
||||
|
||||
let mainURL = testURL;
|
||||
let frame1URL = "data:text/html,<input%20id='original'>";
|
||||
let frame2URL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_463205_helper.html";
|
||||
let frame2URL = rootDir + "browser_463205_helper.html";
|
||||
let frame3URL = "data:text/html,mark2";
|
||||
|
||||
let frameCount = 0;
|
||||
@ -100,8 +99,7 @@ function test() {
|
||||
mainURL = testURL;
|
||||
frame1URL = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_463205_helper.html";
|
||||
frame2URL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_463205_helper.html";
|
||||
frame2URL = rootDir + "browser_463205_helper.html";
|
||||
frame3URL = "data:text/html,mark2";
|
||||
|
||||
frameCount = 0;
|
||||
|
@ -41,8 +41,8 @@ function test() {
|
||||
|
||||
let uniqueValue = Math.random();
|
||||
|
||||
let testURL = "chrome://mochikit/content/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_485482_sample.html";
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_485482_sample.html";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
@ -154,9 +154,7 @@ function PreviewController(win, tab) {
|
||||
this.linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
this.linkedBrowser.addEventListener("MozAfterPaint", this, false);
|
||||
this.linkedBrowser.addEventListener("DOMTitleChanged", this, false);
|
||||
// pageshow is needed for when a tab is dragged across windows.
|
||||
this.linkedBrowser.addEventListener("pageshow", this, false);
|
||||
this.tab.addEventListener("TabAttrModified", this, false);
|
||||
|
||||
// Cannot perform the lookup during construction. See TabWindow.newTab
|
||||
XPCOMUtils.defineLazyGetter(this, "preview", function () this.win.previewFromTab(this.tab));
|
||||
@ -180,8 +178,7 @@ PreviewController.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsITaskbarPreviewController,
|
||||
Ci.nsIDOMEventListener]),
|
||||
destroy: function () {
|
||||
this.linkedBrowser.removeEventListener("pageshow", this, false);
|
||||
this.linkedBrowser.removeEventListener("DOMTitleChanged", this, false);
|
||||
this.tab.removeEventListener("TabAttrModified", this, false);
|
||||
this.linkedBrowser.removeEventListener("MozAfterPaint", this, false);
|
||||
|
||||
// Break cycles, otherwise we end up leaking the window with everything
|
||||
@ -355,11 +352,7 @@ PreviewController.prototype = {
|
||||
if (preview.visible)
|
||||
preview.invalidate();
|
||||
break;
|
||||
case "pageshow":
|
||||
case "DOMTitleChanged":
|
||||
// The tab's label is sometimes empty when dragging tabs between windows
|
||||
// so we force the tab title to be updated (see bug 520579)
|
||||
this.win.tabbrowser.setTabTitle(this.tab);
|
||||
case "TabAttrModified":
|
||||
this.updateTitleAndTooltip();
|
||||
break;
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ var gTabCloseCount = 0;
|
||||
var gTabMoveCount = 0;
|
||||
var gPageLoadCount = 0;
|
||||
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
const CHROMEROOT = rootDir;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
@ -21,7 +24,7 @@ function test() {
|
||||
activeWin.events.addListener("TabClose", onTabClose);
|
||||
activeWin.events.addListener("TabMove", onTabMove);
|
||||
|
||||
gPageA = activeWin.open(makeURI("chrome://mochikit/content/browser/browser/fuel/test/ContentA.html"));
|
||||
gPageA = activeWin.open(makeURI(CHROMEROOT + "ContentA.html"));
|
||||
gPageA.events.addListener("load", onPageAFirstLoad);
|
||||
|
||||
is(activeWin.tabs.length, 2, "Checking length of 'Browser.tabs' after opening 1 additional tab");
|
||||
@ -30,7 +33,7 @@ function test() {
|
||||
gPageA.events.removeListener("load", onPageAFirstLoad);
|
||||
is(gPageA.uri.spec, event.data.uri.spec, "Checking event browser tab is equal to page A");
|
||||
|
||||
gPageB = activeWin.open(makeURI("chrome://mochikit/content/browser/browser/fuel/test/ContentB.html"));
|
||||
gPageB = activeWin.open(makeURI(CHROMEROOT + "ContentB.html"));
|
||||
gPageB.events.addListener("load", delayAfterOpen);
|
||||
gPageB.focus();
|
||||
|
||||
@ -46,8 +49,8 @@ function test() {
|
||||
function afterOpen(event) {
|
||||
gPageB.events.removeListener("load", delayAfterOpen);
|
||||
// check actuals
|
||||
is(gPageA.uri.spec, "chrome://mochikit/content/browser/browser/fuel/test/ContentA.html", "Checking 'BrowserTab.uri' after opening");
|
||||
is(gPageB.uri.spec, "chrome://mochikit/content/browser/browser/fuel/test/ContentB.html", "Checking 'BrowserTab.uri' after opening");
|
||||
is(gPageA.uri.spec, CHROMEROOT + "ContentA.html", "Checking 'BrowserTab.uri' after opening");
|
||||
is(gPageB.uri.spec, CHROMEROOT + "ContentB.html", "Checking 'BrowserTab.uri' after opening");
|
||||
|
||||
// check event
|
||||
is(gTabOpenCount, 2, "Checking event handler for tab open");
|
||||
@ -91,7 +94,7 @@ function test() {
|
||||
// test loading new content with a frame into a tab
|
||||
// the event will be checked in onPageBLoadComplete
|
||||
gPageB.events.addListener("load", onPageBLoadWithFrames);
|
||||
gPageB.load(makeURI("chrome://mochikit/content/browser/browser/fuel/test/ContentWithFrames.html"));
|
||||
gPageB.load(makeURI(CHROMEROOT + "ContentWithFrames.html"));
|
||||
}
|
||||
|
||||
function onPageBLoadWithFrames(event) {
|
||||
@ -107,12 +110,12 @@ function test() {
|
||||
// test loading new content into a tab
|
||||
// the event will be checked in onPageASecondLoad
|
||||
gPageA.events.addListener("load", onPageASecondLoad);
|
||||
gPageA.load(makeURI("chrome://mochikit/content/browser/browser/fuel/test/ContentB.html"));
|
||||
gPageA.load(makeURI(CHROMEROOT + "ContentB.html"));
|
||||
}
|
||||
|
||||
function onPageASecondLoad(event) {
|
||||
gPageA.events.removeListener("load", onPageASecondLoad);
|
||||
is(gPageA.uri.spec, "chrome://mochikit/content/browser/browser/fuel/test/ContentB.html", "Checking 'BrowserTab.uri' after loading new content");
|
||||
is(gPageA.uri.spec, CHROMEROOT + "ContentB.html", "Checking 'BrowserTab.uri' after loading new content");
|
||||
|
||||
// start testing closing tabs
|
||||
// the event will be checked in afterClose
|
||||
|
@ -149,6 +149,7 @@
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
@BINPATH@/components/dom_events.xpt
|
||||
@BINPATH@/components/dom_geolocation.xpt
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
@BINPATH@/components/dom_html.xpt
|
||||
@BINPATH@/components/dom_indexeddb.xpt
|
||||
@BINPATH@/components/dom_offline.xpt
|
||||
@ -364,6 +365,7 @@
|
||||
@BINPATH@/components/satchel.manifest
|
||||
@BINPATH@/components/nsFormAutoComplete.js
|
||||
@BINPATH@/components/nsFormHistory.js
|
||||
@BINPATH@/components/nsInputListAutoComplete.js
|
||||
@BINPATH@/components/contentSecurityPolicy.manifest
|
||||
@BINPATH@/components/contentSecurityPolicy.js
|
||||
@BINPATH@/components/contentAreaDropListener.manifest
|
||||
|
@ -20,10 +20,16 @@
|
||||
<!ENTITY closeOtherTabs.accesskey "o">
|
||||
<!ENTITY openTabInNewWindow.label "Open in a New Window">
|
||||
<!ENTITY openTabInNewWindow.accesskey "W">
|
||||
<!ENTITY pinTab.label "Make into App Tab">
|
||||
<!ENTITY pinTab.accesskey "p">
|
||||
<!ENTITY unpinTab.label "Make into Normal Tab">
|
||||
<!ENTITY unpinTab.accesskey "k">
|
||||
|
||||
<!-- LOCALIZATION NOTE (pinAppTab.label, unpinAppTab.label): "Pin" is being
|
||||
used as a metaphor for expressing the fact that these tabs are "pinned" to the
|
||||
left edge of the tabstrip. Really we just want the string to express the idea
|
||||
that this is a lightweight and reversible action that keeps your tab where you
|
||||
can reach it easily. -->
|
||||
<!ENTITY pinAppTab.label "Pin as App Tab">
|
||||
<!ENTITY pinAppTab.accesskey "P">
|
||||
<!ENTITY unpinAppTab.label "Unpin Tab">
|
||||
<!ENTITY unpinAppTab.accesskey "b">
|
||||
<!ENTITY moveToGroup.label "Move to Group">
|
||||
<!ENTITY moveToGroup.accesskey "M">
|
||||
<!ENTITY moveToNewGroup.label "New Group">
|
||||
@ -259,11 +265,13 @@
|
||||
<!ENTITY historyUndoMenu.label "Recently Closed Tabs">
|
||||
<!-- LOCALIZATION NOTE (historyUndoWindowMenu): see bug 394759 -->
|
||||
<!ENTITY historyUndoWindowMenu.label "Recently Closed Windows">
|
||||
<!ENTITY historyRestoreLastSession.label "Restore Previous Session">
|
||||
|
||||
<!ENTITY historyHomeCmd.label "Home">
|
||||
<!ENTITY showAllHistoryCmd2.label "Show All History">
|
||||
<!ENTITY showAllHistoryCmd.commandkey "H">
|
||||
|
||||
<!ENTITY appMenuEdit.label "Edit">
|
||||
<!ENTITY appMenuCustomize.label "Customize">
|
||||
<!ENTITY appMenuToolbarLayout.label "Toolbar Layout…">
|
||||
<!ENTITY appMenuSidebars.label "Sidebars">
|
||||
|
@ -185,6 +185,10 @@ offlineApps.usage=This website (%S) is now storing more than %SMB of data on you
|
||||
offlineApps.manageUsage=Show settings
|
||||
offlineApps.manageUsageAccessKey=S
|
||||
|
||||
# LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
|
||||
# %2$S a number of megabytes.
|
||||
indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
|
||||
|
||||
identity.identified.verifier=Verified by: %S
|
||||
identity.identified.verified_by_you=You have added a security exception for this site.
|
||||
identity.identified.state_and_country=%S, %S
|
||||
|
@ -99,6 +99,10 @@
|
||||
<!ENTITY permInstall "Install Extensions or Themes">
|
||||
<!ENTITY permGeo "Share Location">
|
||||
|
||||
<!ENTITY permIndexedDB "Maintain Offline Storage">
|
||||
<!ENTITY permClearStorage "Clear Storage">
|
||||
<!ENTITY permClearStorage.accesskey "C">
|
||||
|
||||
<!ENTITY securityTab "Security">
|
||||
<!ENTITY securityTab.accesskey "S">
|
||||
<!ENTITY securityHeader "Security information for this page">
|
||||
|
@ -79,3 +79,10 @@ feedXML=XML
|
||||
securityNoOwner=This web site does not supply ownership information.
|
||||
securityOneVisit=Yes, once
|
||||
securityNVisits=Yes, %S times
|
||||
|
||||
# LOCALIZATION NOTE: The next string is for the disk usage of the
|
||||
# database
|
||||
# e.g. indexedDBUsage : "50.23 MB"
|
||||
# %1$S = size (in bytes or megabytes, ...)
|
||||
# %2$S = unit of measure (bytes, KB, MB, ...)
|
||||
indexedDBUsage=This web site is using %1$S %2$S
|
||||
|
2
browser/locales/en-US/chrome/browser/tabview.properties
Normal file
2
browser/locales/en-US/chrome/browser/tabview.properties
Normal file
@ -0,0 +1,2 @@
|
||||
tabview.groupItem.newTabButton=New tab
|
||||
tabview.groupItem.defaultName=Name this tab group…
|
@ -32,6 +32,7 @@
|
||||
locale/browser/shellservice.properties (%chrome/browser/shellservice.properties)
|
||||
locale/browser/tabbrowser.dtd (%chrome/browser/tabbrowser.dtd)
|
||||
locale/browser/tabbrowser.properties (%chrome/browser/tabbrowser.properties)
|
||||
locale/browser/tabview.properties (%chrome/browser/tabview.properties)
|
||||
locale/browser/taskbar.properties (%chrome/browser/taskbar.properties)
|
||||
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)
|
||||
locale/browser/places/places.properties (%chrome/browser/places/places.properties)
|
||||
|
@ -67,7 +67,7 @@ h2 {
|
||||
max-width: 52em;
|
||||
margin: 4em auto;
|
||||
border: 1px solid #FFBD09; /* pale yellow extracted from yellow passport icon */
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
padding: 3em;
|
||||
-moz-padding-start: 30px;
|
||||
background: url("chrome://global/skin/icons/sslWarning.png") left 0 no-repeat -moz-Field;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user