Merge mozilla-central to tracemonkey.
|
@ -93,7 +93,7 @@ nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
|
|||
nsDocAccessible::
|
||||
nsDocAccessible(nsIDocument *aDocument, nsIContent *aRootContent,
|
||||
nsIWeakReference *aShell) :
|
||||
nsHyperTextAccessibleWrap(aRootContent, aShell), mWnd(nsnull),
|
||||
nsHyperTextAccessibleWrap(aRootContent, aShell),
|
||||
mDocument(aDocument), mScrollPositionChangedTicks(0), mIsLoaded(PR_FALSE)
|
||||
{
|
||||
// XXX aaronl should we use an algorithm for the initial cache size?
|
||||
|
@ -103,17 +103,6 @@ nsDocAccessible::
|
|||
if (!mDocument)
|
||||
return;
|
||||
|
||||
// Initialize mWnd
|
||||
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
|
||||
nsIViewManager* vm = shell->GetViewManager();
|
||||
if (vm) {
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
mWnd = widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
}
|
||||
}
|
||||
|
||||
// nsAccDocManager creates document accessible when scrollable frame is
|
||||
// available already, it should be safe time to add scroll listener.
|
||||
AddScrollListener();
|
||||
|
@ -473,7 +462,8 @@ NS_IMETHODIMP nsDocAccessible::GetNameSpaceURIForID(PRInt16 aNameSpaceID, nsAStr
|
|||
|
||||
NS_IMETHODIMP nsDocAccessible::GetWindowHandle(void **aWindow)
|
||||
{
|
||||
*aWindow = mWnd;
|
||||
NS_ENSURE_ARG_POINTER(aWindow);
|
||||
*aWindow = GetNativeWindow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1335,6 +1325,20 @@ nsDocAccessible::HandleAccEvent(AccEvent* aAccEvent)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public members
|
||||
|
||||
void*
|
||||
nsDocAccessible::GetNativeWindow() const
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
|
||||
nsIViewManager* vm = shell->GetViewManager();
|
||||
if (vm) {
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget)
|
||||
return widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsDocAccessible::GetCachedAccessibleInSubtree(void* aUniqueID)
|
||||
{
|
||||
|
|
|
@ -141,6 +141,11 @@ public:
|
|||
*/
|
||||
void MarkAsLoaded() { mIsLoaded = PR_TRUE; }
|
||||
|
||||
/**
|
||||
* Return a native window handler or pointer depending on platform.
|
||||
*/
|
||||
virtual void* GetNativeWindow() const;
|
||||
|
||||
/**
|
||||
* Return the parent document.
|
||||
*/
|
||||
|
@ -363,7 +368,6 @@ protected:
|
|||
*/
|
||||
nsAccessibleHashtable mAccessibleCache;
|
||||
|
||||
void *mWnd;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsITimer> mScrollWatchTimer;
|
||||
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
|
||||
|
|
|
@ -594,9 +594,13 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
|
|||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
nsAccessibleWrap *accWrap = static_cast<nsAccessibleWrap*>(mGeckoAccessible);
|
||||
|
||||
// Get a pointer to the native window (NSWindow) we reside in.
|
||||
NSWindow *nativeWindow = nil;
|
||||
accWrap->GetNativeWindow ((void**)&nativeWindow);
|
||||
|
||||
nsDocAccessible* docAcc = accWrap->GetDocAccessible();
|
||||
if (docAcc)
|
||||
nativeWindow = static_cast<NSWindow*>(docAcc->GetNativeWindow());
|
||||
|
||||
NSAssert1(nativeWindow, @"Could not get native window for %@", self);
|
||||
return nativeWindow;
|
||||
|
||||
|
|
|
@ -71,10 +71,7 @@ class nsAccessibleWrap : public nsAccessible
|
|||
// should be instantied with. used on runtime to determine the
|
||||
// right type for this accessible's associated native object.
|
||||
virtual objc_class* GetNativeType ();
|
||||
|
||||
// returns a pointer to the native window for this accessible tree.
|
||||
void GetNativeWindow (void **aOutNativeWindow);
|
||||
|
||||
|
||||
virtual void Shutdown ();
|
||||
virtual void InvalidateChildren();
|
||||
|
||||
|
|
|
@ -86,17 +86,6 @@ nsAccessibleWrap::GetNativeInterface (void **aOutInterface)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// get the native NSWindow we reside in.
|
||||
void
|
||||
nsAccessibleWrap::GetNativeWindow (void **aOutNativeWindow)
|
||||
{
|
||||
*aOutNativeWindow = nsnull;
|
||||
|
||||
nsDocAccessible *docAcc = GetDocAccessible();
|
||||
if (docAcc)
|
||||
docAcc->GetWindowHandle (aOutNativeWindow);
|
||||
}
|
||||
|
||||
// overridden in subclasses to create the right kind of object. by default we create a generic
|
||||
// 'mozAccessible' node.
|
||||
objc_class*
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsApplicationAccessibleWrap.h"
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsWinUtils.h"
|
||||
|
||||
#include "nsAttrName.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -63,6 +64,7 @@
|
|||
HINSTANCE nsAccessNodeWrap::gmAccLib = nsnull;
|
||||
HINSTANCE nsAccessNodeWrap::gmUserLib = nsnull;
|
||||
LPFNACCESSIBLEOBJECTFROMWINDOW nsAccessNodeWrap::gmAccessibleObjectFromWindow = nsnull;
|
||||
LPFNLRESULTFROMOBJECT nsAccessNodeWrap::gmLresultFromObject = NULL;
|
||||
LPFNNOTIFYWINEVENT nsAccessNodeWrap::gmNotifyWinEvent = nsnull;
|
||||
LPFNGETGUITHREADINFO nsAccessNodeWrap::gmGetGUIThreadInfo = nsnull;
|
||||
|
||||
|
@ -569,7 +571,14 @@ void nsAccessNodeWrap::InitAccessibility()
|
|||
}
|
||||
|
||||
DoATSpecificProcessing();
|
||||
|
||||
|
||||
// Register window class that'll be used for document accessibles associated
|
||||
// with tabs.
|
||||
if (nsWinUtils::IsWindowEmulationEnabled()) {
|
||||
nsWinUtils::RegisterNativeWindow(kClassNameTabContent);
|
||||
sHWNDCache.Init(4);
|
||||
}
|
||||
|
||||
nsAccessNode::InitXPAccessibility();
|
||||
}
|
||||
|
||||
|
@ -578,6 +587,11 @@ void nsAccessNodeWrap::ShutdownAccessibility()
|
|||
NS_IF_RELEASE(gTextEvent);
|
||||
::DestroyCaret();
|
||||
|
||||
// Unregister window call that's used for document accessibles associated
|
||||
// with tabs.
|
||||
if (nsWinUtils::IsWindowEmulationEnabled())
|
||||
::UnregisterClassW(kClassNameTabContent, GetModuleHandle(NULL));
|
||||
|
||||
nsAccessNode::ShutdownXPAccessibility();
|
||||
}
|
||||
|
||||
|
@ -624,7 +638,7 @@ GetHRESULT(nsresult aResult)
|
|||
|
||||
PRBool nsAccessNodeWrap::IsOnlyMsaaCompatibleJawsPresent()
|
||||
{
|
||||
HMODULE jhookhandle = ::GetModuleHandleW(L"jhook");
|
||||
HMODULE jhookhandle = ::GetModuleHandleW(kJAWSModuleHandle);
|
||||
if (!jhookhandle)
|
||||
return PR_FALSE; // No JAWS, or some other screen reader, use IA2
|
||||
|
||||
|
@ -655,10 +669,10 @@ PRBool nsAccessNodeWrap::IsOnlyMsaaCompatibleJawsPresent()
|
|||
|
||||
void nsAccessNodeWrap::TurnOffNewTabSwitchingForJawsAndWE()
|
||||
{
|
||||
HMODULE srHandle = ::GetModuleHandleW(L"jhook");
|
||||
HMODULE srHandle = ::GetModuleHandleW(kJAWSModuleHandle);
|
||||
if (!srHandle) {
|
||||
// No JAWS, try Window-Eyes
|
||||
srHandle = ::GetModuleHandleW(L"gwm32inc");
|
||||
srHandle = ::GetModuleHandleW(kWEModuleHandle);
|
||||
if (!srHandle) {
|
||||
// no screen reader we're interested in. Bail out.
|
||||
return;
|
||||
|
@ -694,3 +708,49 @@ void nsAccessNodeWrap::DoATSpecificProcessing()
|
|||
|
||||
TurnOffNewTabSwitchingForJawsAndWE();
|
||||
}
|
||||
|
||||
nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible> nsAccessNodeWrap::sHWNDCache;
|
||||
|
||||
LRESULT CALLBACK
|
||||
nsAccessNodeWrap::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_GETOBJECT:
|
||||
{
|
||||
if (lParam == OBJID_CLIENT) {
|
||||
nsDocAccessible* document = sHWNDCache.GetWeak(static_cast<void*>(hWnd));
|
||||
if (document) {
|
||||
IAccessible* msaaAccessible = NULL;
|
||||
document->GetNativeInterface((void**)&msaaAccessible); // does an addref
|
||||
if (msaaAccessible) {
|
||||
LRESULT result = LresultFromObject(IID_IAccessible, wParam,
|
||||
msaaAccessible); // does an addref
|
||||
msaaAccessible->Release(); // release extra addref
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ::DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(LRESULT)
|
||||
nsAccessNodeWrap::LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc)
|
||||
{
|
||||
// open the dll dynamically
|
||||
if (!gmAccLib)
|
||||
gmAccLib =::LoadLibraryW(L"OLEACC.DLL");
|
||||
|
||||
if (gmAccLib) {
|
||||
if (!gmLresultFromObject)
|
||||
gmLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(gmAccLib,"LresultFromObject");
|
||||
|
||||
if (gmLresultFromObject)
|
||||
return gmLresultFromObject(riid, wParam, pAcc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@
|
|||
#include "nsICrashReporter.h"
|
||||
#endif
|
||||
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
typedef LRESULT (STDAPICALLTYPE *LPFNNOTIFYWINEVENT)(DWORD event,HWND hwnd,LONG idObjectType,LONG idObject);
|
||||
typedef LRESULT (STDAPICALLTYPE *LPFNGETGUITHREADINFO)(DWORD idThread, GUITHREADINFO* pgui);
|
||||
|
||||
|
@ -154,6 +156,7 @@ public: // construction, destruction
|
|||
static HINSTANCE gmAccLib;
|
||||
static HINSTANCE gmUserLib;
|
||||
static LPFNACCESSIBLEOBJECTFROMWINDOW gmAccessibleObjectFromWindow;
|
||||
static LPFNLRESULTFROMOBJECT gmLresultFromObject;
|
||||
static LPFNNOTIFYWINEVENT gmNotifyWinEvent;
|
||||
static LPFNGETGUITHREADINFO gmGetGUIThreadInfo;
|
||||
|
||||
|
@ -165,6 +168,13 @@ public: // construction, destruction
|
|||
|
||||
static void DoATSpecificProcessing();
|
||||
|
||||
static STDMETHODIMP_(LRESULT) LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc);
|
||||
|
||||
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg,
|
||||
WPARAM WParam, LPARAM lParam);
|
||||
|
||||
static nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible> sHWNDCache;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsAccUtils.h"
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsRelUtils.h"
|
||||
#include "nsWinUtils.h"
|
||||
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIAccessibleEvent.h"
|
||||
|
@ -193,58 +194,23 @@ STDMETHODIMP nsAccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *pp
|
|||
{
|
||||
__try {
|
||||
*ppdispParent = NULL;
|
||||
if (!mWeakShell)
|
||||
return E_FAIL; // We've been shut down
|
||||
|
||||
nsIFrame *frame = GetFrame();
|
||||
HWND hwnd = 0;
|
||||
if (frame) {
|
||||
nsIView *view = frame->GetViewExternal();
|
||||
if (view) {
|
||||
// This code is essentially our implementation of WindowFromAccessibleObject,
|
||||
// because MSAA iterates get_accParent() until it sees an object of ROLE_WINDOW
|
||||
// to know where the window for a given accessible is. We must expose the native
|
||||
// window accessible that MSAA creates for us. This must be done for the document
|
||||
// object as well as any layout that creates its own window (e.g. via overflow: scroll)
|
||||
nsIWidget *widget = view->GetWidget();
|
||||
if (widget) {
|
||||
hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
NS_ASSERTION(hwnd, "No window handle for window");
|
||||
if (IsDefunct())
|
||||
return E_FAIL;
|
||||
|
||||
nsIViewManager* viewManager = view->GetViewManager();
|
||||
if (!viewManager)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
nsIView *rootView;
|
||||
viewManager->GetRootView(rootView);
|
||||
if (rootView == view) {
|
||||
// If the client accessible (OBJID_CLIENT) has a window but its window
|
||||
// was created by an outer window then we want the native accessible
|
||||
// for that outer window. If the accessible was created for outer
|
||||
// window (if the outer window has inner windows then they share the
|
||||
// same client accessible with it) then return native accessible for
|
||||
// the outer window.
|
||||
HWND parenthwnd = ::GetParent(hwnd);
|
||||
if (parenthwnd)
|
||||
hwnd = parenthwnd;
|
||||
|
||||
NS_ASSERTION(hwnd, "No window handle for window");
|
||||
}
|
||||
nsRefPtr<nsDocAccessible> doc(do_QueryObject(this));
|
||||
if (doc) {
|
||||
// Return window system accessible object for root document and tab document
|
||||
// accessibles.
|
||||
if (!doc->ParentDocument() ||
|
||||
nsWinUtils::IsWindowEmulationEnabled() &&
|
||||
nsWinUtils::IsTabDocument(doc->GetDocumentNode())) {
|
||||
HWND hwnd = static_cast<HWND>(doc->GetNativeWindow());
|
||||
if (hwnd && SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_WINDOW,
|
||||
IID_IAccessible,
|
||||
(void**)ppdispParent))) {
|
||||
return S_OK;
|
||||
}
|
||||
else {
|
||||
// If a frame is a scrollable frame, then it has one window for the client area,
|
||||
// not an extra parent window for just the scrollbars
|
||||
nsIScrollableFrame *scrollFrame = do_QueryFrame(frame);
|
||||
if (scrollFrame) {
|
||||
hwnd = (HWND)scrollFrame->GetScrolledFrame()->GetNearestWidget()->GetNativeData(NS_NATIVE_WINDOW);
|
||||
NS_ASSERTION(hwnd, "No window handle for window");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hwnd && SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible,
|
||||
(void**)ppdispParent))) {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,6 +353,9 @@ STDMETHODIMP nsAccessibleWrap::get_accRole(
|
|||
__try {
|
||||
VariantInit(pvarRole);
|
||||
|
||||
if (IsDefunct())
|
||||
return E_FAIL;
|
||||
|
||||
nsAccessible *xpAccessible = GetXPAccessibleFor(varChild);
|
||||
if (!xpAccessible)
|
||||
return E_FAIL;
|
||||
|
@ -1187,6 +1156,9 @@ nsAccessibleWrap::role(long *aRole)
|
|||
__try {
|
||||
*aRole = 0;
|
||||
|
||||
if (IsDefunct())
|
||||
return E_FAIL;
|
||||
|
||||
NS_ASSERTION(gWindowsRoleMap[nsIAccessibleRole::ROLE_LAST_ENTRY].ia2Role == ROLE_WINDOWS_LAST_ENTRY,
|
||||
"MSAA role map skewed");
|
||||
|
||||
|
@ -1662,45 +1634,11 @@ PRInt32 nsAccessibleWrap::GetChildIDFor(nsIAccessible* aAccessible)
|
|||
HWND
|
||||
nsAccessibleWrap::GetHWNDFor(nsAccessible *aAccessible)
|
||||
{
|
||||
HWND hWnd = 0;
|
||||
if (!aAccessible)
|
||||
return hWnd;
|
||||
return 0;
|
||||
|
||||
nsIFrame *frame = aAccessible->GetFrame();
|
||||
if (frame) {
|
||||
nsIWidget *window = frame->GetNearestWidget();
|
||||
PRBool isVisible;
|
||||
window->IsVisible(isVisible);
|
||||
if (isVisible) {
|
||||
// Short explanation:
|
||||
// If HWND for frame is inside a hidden window, fire the event on the
|
||||
// containing document's visible window.
|
||||
//
|
||||
// Long explanation:
|
||||
// This is really just to fix combo boxes with JAWS. Window-Eyes already
|
||||
// worked with combo boxes because they use the value change event in
|
||||
// the closed combo box case. JAWS will only pay attention to the focus
|
||||
// events on the list items. The JAWS developers haven't fixed that, so
|
||||
// we'll use the focus events to make JAWS work. However, JAWS is
|
||||
// ignoring events on a hidden window. So, in order to fix the bug where
|
||||
// JAWS doesn't echo the current option as it changes in a closed
|
||||
// combo box, we need to use an ensure that we never fire an event with
|
||||
// an HWND for a hidden window.
|
||||
hWnd = (HWND)frame->GetNearestWidget()->GetNativeData(NS_NATIVE_WINDOW);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hWnd) {
|
||||
void* handle = nsnull;
|
||||
nsDocAccessible *accessibleDoc = aAccessible->GetDocAccessible();
|
||||
if (!accessibleDoc)
|
||||
return 0;
|
||||
|
||||
accessibleDoc->GetWindowHandle(&handle);
|
||||
hWnd = (HWND)handle;
|
||||
}
|
||||
|
||||
return hWnd;
|
||||
nsDocAccessible* document = aAccessible->GetDocAccessible();
|
||||
return document ? static_cast<HWND>(document->GetNativeWindow()) : 0;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#include "nsDocAccessibleWrap.h"
|
||||
#include "ISimpleDOMDocument_i.c"
|
||||
#include "nsIAccessibilityService.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsWinUtils.h"
|
||||
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeNode.h"
|
||||
#include "nsIFrame.h"
|
||||
|
@ -60,7 +63,7 @@
|
|||
nsDocAccessibleWrap::
|
||||
nsDocAccessibleWrap(nsIDocument *aDocument, nsIContent *aRootContent,
|
||||
nsIWeakReference *aShell) :
|
||||
nsDocAccessible(aDocument, aRootContent, aShell)
|
||||
nsDocAccessible(aDocument, aRootContent, aShell), mHWND(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -245,3 +248,53 @@ STDMETHODIMP nsDocAccessibleWrap::get_accValue(
|
|||
|
||||
return get_URL(pszValue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccessNode
|
||||
|
||||
PRBool
|
||||
nsDocAccessibleWrap::Init()
|
||||
{
|
||||
if (nsWinUtils::IsWindowEmulationEnabled()) {
|
||||
// Create window for tab document.
|
||||
if (nsWinUtils::IsTabDocument(mDocument)) {
|
||||
nsRefPtr<nsRootAccessible> root = GetRootAccessible();
|
||||
mHWND = nsWinUtils::CreateNativeWindow(kClassNameTabContent,
|
||||
static_cast<HWND>(root->GetNativeWindow()));
|
||||
|
||||
nsAccessibleWrap::sHWNDCache.Put(mHWND, this);
|
||||
|
||||
} else {
|
||||
nsDocAccessible* parentDocument = ParentDocument();
|
||||
if (parentDocument)
|
||||
mHWND = parentDocument->GetNativeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
return nsDocAccessible::Init();
|
||||
}
|
||||
|
||||
void
|
||||
nsDocAccessibleWrap::Shutdown()
|
||||
{
|
||||
if (nsWinUtils::IsWindowEmulationEnabled()) {
|
||||
// Destroy window created for root document.
|
||||
if (nsWinUtils::IsTabDocument(mDocument)) {
|
||||
nsAccessibleWrap::sHWNDCache.Remove(mHWND);
|
||||
::DestroyWindow(static_cast<HWND>(mHWND));
|
||||
}
|
||||
|
||||
mHWND = nsnull;
|
||||
}
|
||||
|
||||
nsDocAccessible::Shutdown();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsDocAccessible
|
||||
|
||||
void*
|
||||
nsDocAccessibleWrap::GetNativeWindow() const
|
||||
{
|
||||
return mHWND ? mHWND : nsDocAccessible::GetNativeWindow();
|
||||
}
|
||||
|
|
|
@ -89,8 +89,18 @@ public:
|
|||
/* [optional][in] */ VARIANT varChild,
|
||||
/* [retval][out] */ BSTR __RPC_FAR *pszValue);
|
||||
|
||||
// nsAccessNode
|
||||
virtual PRBool Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
// nsAccessibleWrap
|
||||
virtual nsAccessible *GetXPAccessibleFor(const VARIANT& varChild);
|
||||
|
||||
// nsDocAccessible
|
||||
virtual void* GetNativeWindow() const;
|
||||
|
||||
protected:
|
||||
void* mHWND;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "nsAccessibleWrap.h"
|
||||
#include "nsIWinAccessNode.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
|
||||
HRESULT
|
||||
nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array,
|
||||
|
@ -96,3 +97,57 @@ nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array,
|
|||
*aIA2ArrayLen = length;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
wc.style = CS_GLOBALCLASS;
|
||||
wc.lpfnWndProc = nsAccessNodeWrap::WindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.hIcon = NULL;
|
||||
wc.hCursor = NULL;
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = aWindowClass;
|
||||
::RegisterClassW(&wc);
|
||||
}
|
||||
|
||||
HWND
|
||||
nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd)
|
||||
{
|
||||
return ::CreateWindowW(aWindowClass,
|
||||
L"NetscapeDispatchWnd",
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
0, 0,
|
||||
aParentWnd,
|
||||
NULL,
|
||||
GetModuleHandle(NULL),
|
||||
NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
nsWinUtils::IsWindowEmulationEnabled()
|
||||
{
|
||||
return ::GetModuleHandleW(kJAWSModuleHandle) ||
|
||||
::GetModuleHandleW(kWEModuleHandle) ||
|
||||
::GetModuleHandleW(kDolphnModuleHandle);
|
||||
}
|
||||
|
||||
bool
|
||||
nsWinUtils::IsTabDocument(nsIDocument* aDocumentNode)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aDocumentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
||||
treeItem->GetParent(getter_AddRefs(parentTreeItem));
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
|
||||
treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
|
||||
|
||||
return parentTreeItem == rootTreeItem;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,14 @@
|
|||
#include "Accessible2.h"
|
||||
|
||||
#include "nsIArray.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
const LPCWSTR kClassNameRoot = L"MozillaUIWindowClass";
|
||||
const LPCWSTR kClassNameTabContent = L"MozillaContentWindowClass";
|
||||
|
||||
const LPCWSTR kJAWSModuleHandle = L"jhook";
|
||||
const LPCWSTR kWEModuleHandle = L"gwm32inc";
|
||||
const LPCWSTR kDolphnModuleHandle = L"dolwinhk";
|
||||
|
||||
class nsWinUtils
|
||||
{
|
||||
|
@ -54,6 +62,26 @@ public:
|
|||
*/
|
||||
static HRESULT ConvertToIA2Array(nsIArray *aCollection,
|
||||
IUnknown ***aAccessibles, long *aCount);
|
||||
|
||||
/**
|
||||
* Helper to register window class.
|
||||
*/
|
||||
static void RegisterNativeWindow(LPCWSTR aWindowClass);
|
||||
|
||||
/**
|
||||
* Helper to create a window.
|
||||
*/
|
||||
static HWND CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd);
|
||||
|
||||
/**
|
||||
* Return true if window emulation is enabled.
|
||||
*/
|
||||
static bool IsWindowEmulationEnabled();
|
||||
|
||||
/**
|
||||
* Return true if the given document node is for tab document accessible.
|
||||
*/
|
||||
static bool IsTabDocument(nsIDocument* aDocumentNode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -50,19 +50,7 @@
|
|||
role: ROLE_ENTRY,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF // hello1 text
|
||||
},
|
||||
{
|
||||
role: ROLE_WHITESPACE
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF, // hello2 text
|
||||
},
|
||||
{
|
||||
role: ROLE_WHITESPACE
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF, // whitepsace text
|
||||
role: ROLE_TEXT_LEAF // hello1\nhello2 text
|
||||
},
|
||||
{
|
||||
role: ROLE_WHITESPACE
|
||||
|
|
|
@ -73,6 +73,8 @@ pref("extensions.blocklist.level", 2);
|
|||
pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
|
||||
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
|
||||
|
||||
pref("extensions.update.autoUpdateDefault", true);
|
||||
|
||||
// Dictionary download preference
|
||||
pref("browser.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/%APP%/dictionaries/");
|
||||
|
||||
|
@ -89,6 +91,11 @@ pref("app.update.timer", 600000);
|
|||
// Enables some extra Application Update Logging (can reduce performance)
|
||||
pref("app.update.log", false);
|
||||
|
||||
// The number of general background check failures to allow before notifying the
|
||||
// user of the failure. User initiated update checks always notify the user of
|
||||
// the failure.
|
||||
pref("app.update.backgroundMaxErrors", 10);
|
||||
|
||||
// When |app.update.cert.requireBuiltIn| is true or not specified the
|
||||
// final certificate and all certificates the connection is redirected to before
|
||||
// the final certificate for the url specified in the |app.update.url|
|
||||
|
@ -793,6 +800,8 @@ pref("browser.sessionstore.max_windows_undo", 3);
|
|||
// number of crashes that can occur before the about:sessionrestore page is displayed
|
||||
// (this pref has no effect if more than 6 hours have passed since the last crash)
|
||||
pref("browser.sessionstore.max_resumed_crashes", 1);
|
||||
// number of tabs to restore concurrently
|
||||
pref("browser.sessionstore.max_concurrent_tabs", 3);
|
||||
|
||||
// allow META refresh by default
|
||||
pref("accessibility.blockautorefresh", false);
|
||||
|
|
|
@ -3,104 +3,82 @@
|
|||
-moz-padding-end: 0;
|
||||
padding-bottom: 10px;
|
||||
-moz-padding-start: 0;
|
||||
width: 299px;
|
||||
}
|
||||
|
||||
#modes {
|
||||
min-height: 400px;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
#clientBox {
|
||||
/* Add a min-width equal to chrome://branding/content/about.png's
|
||||
* width, to maintain the dialog layout on OS X where the dialog is
|
||||
* align="end" to right-align the button.
|
||||
*/
|
||||
min-width: 300px;
|
||||
background-image: url("chrome://branding/content/about.png");
|
||||
background-color: #F7F7F7;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
#leftBox {
|
||||
background-image: url("chrome://branding/content/about-logo.png");
|
||||
background-repeat: no-repeat;
|
||||
background-color: #FFFFFF;
|
||||
padding-top: 203px;
|
||||
color: #000000;
|
||||
/* min-width and min-height create room for the logo */
|
||||
min-width: 210px;
|
||||
min-height: 210px;
|
||||
margin-top:20px;
|
||||
-moz-margin-start: 30px;
|
||||
}
|
||||
|
||||
#brandName {
|
||||
font-weight: bold; font-size: larger;
|
||||
#rightBox {
|
||||
background-image: url("chrome://branding/content/about-wordmark.png");
|
||||
background-repeat: no-repeat;
|
||||
/* padding-top creates room for the wordmark */
|
||||
padding-top: 38px;
|
||||
margin-top:20px;
|
||||
-moz-margin-end: 30px;
|
||||
-moz-margin-start: 30px;
|
||||
}
|
||||
|
||||
#userAgent {
|
||||
direction: ltr;
|
||||
margin-top: 10px;
|
||||
-moz-margin-end: 13px;
|
||||
margin-bottom: 0;
|
||||
-moz-margin-start: 13px;
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
padding-top: 1px;
|
||||
-moz-padding-end: 1px;
|
||||
padding-bottom: 1px;
|
||||
-moz-padding-start: 3px;
|
||||
-moz-appearance: none;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
#rightBox:-moz-locale-dir(rtl) {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
|
||||
#groove {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#creditsIframe {
|
||||
cursor: default;
|
||||
-moz-user-select: none;
|
||||
border: 0;
|
||||
#bottomBox {
|
||||
padding: 15px 10px 0;
|
||||
}
|
||||
|
||||
#version {
|
||||
font-weight: bold;
|
||||
color: #909090;
|
||||
margin-top: 1em;
|
||||
-moz-margin-end: 0;
|
||||
margin-bottom: 10px;
|
||||
-moz-margin-start: 17px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#distribution {
|
||||
font-weight: bold;
|
||||
color: #909090;
|
||||
display: none;
|
||||
margin-top: 0;
|
||||
-moz-margin-end: 0;
|
||||
margin-bottom: 0;
|
||||
-moz-margin-start: 17px;
|
||||
#released {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
#distribution,
|
||||
#distributionId {
|
||||
font-weight: bold;
|
||||
color: #909090;
|
||||
display: none;
|
||||
margin-top: 0;
|
||||
-moz-margin-end: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#checkForUpdatesButton,
|
||||
.text-blurb {
|
||||
margin-bottom: 10px;
|
||||
-moz-margin-start: 17px;
|
||||
}
|
||||
|
||||
#copyright {
|
||||
margin-top: 0;
|
||||
-moz-margin-end: 16px;
|
||||
margin-bottom: 3px;
|
||||
-moz-margin-start: 16px;
|
||||
}
|
||||
|
||||
button[dlgtype="extra2"] {
|
||||
-moz-margin-start: 13px;
|
||||
}
|
||||
|
||||
button[dlgtype="accept"] {
|
||||
-moz-margin-end: 13px;
|
||||
-moz-margin-start: 0;
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
.version-label,
|
||||
.trademark-label,
|
||||
.text-link,
|
||||
.text-link:focus {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.bottom-link,
|
||||
.bottom-link:focus {
|
||||
text-align: center;
|
||||
margin: 0 40px;
|
||||
}
|
||||
|
||||
#trademark {
|
||||
font-size: xx-small;
|
||||
text-align: center;
|
||||
color: #999999;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#
|
||||
# Contributor(s):
|
||||
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
# Margaret Leibovic <margaret.leibovic@gmail.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
|
||||
|
@ -35,27 +36,25 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
var gSelectedPage = 0;
|
||||
// Services = object with smart getters for common XPCOM services
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function init(aEvent)
|
||||
{
|
||||
if (aEvent.target != document)
|
||||
return;
|
||||
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
try {
|
||||
var distroId = prefs.getCharPref("distribution.id");
|
||||
var distroId = Services.prefs.getCharPref("distribution.id");
|
||||
if (distroId) {
|
||||
var distroVersion = prefs.getCharPref("distribution.version");
|
||||
var distroAbout = prefs.getComplexValue("distribution.about",
|
||||
var distroVersion = Services.prefs.getCharPref("distribution.version");
|
||||
var distroAbout = Services.prefs.getComplexValue("distribution.about",
|
||||
Components.interfaces.nsISupportsString);
|
||||
|
||||
|
||||
var distroField = document.getElementById("distribution");
|
||||
distroField.value = distroAbout;
|
||||
distroField.style.display = "block";
|
||||
|
||||
|
||||
var distroIdField = document.getElementById("distributionId");
|
||||
distroIdField.value = distroId + " - " + distroVersion;
|
||||
distroIdField.style.display = "block";
|
||||
|
@ -65,19 +64,9 @@ function init(aEvent)
|
|||
// Pref is unset
|
||||
}
|
||||
|
||||
var userAgentField = document.getElementById("userAgent");
|
||||
userAgentField.value = navigator.userAgent;
|
||||
|
||||
var button = document.documentElement.getButton("extra2");
|
||||
button.setAttribute("label", document.documentElement.getAttribute("creditslabel"));
|
||||
button.setAttribute("accesskey", document.documentElement.getAttribute("creditsaccesskey"));
|
||||
button.addEventListener("command", switchPage, false);
|
||||
|
||||
var acceptButton = document.documentElement.getButton("accept");
|
||||
#ifdef XP_UNIX
|
||||
acceptButton.setAttribute("icon", "close");
|
||||
#ifdef MOZ_UPDATER
|
||||
initUpdates();
|
||||
#endif
|
||||
acceptButton.focus();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// it may not be sized at this point, and we need its width to calculate its position
|
||||
|
@ -86,34 +75,27 @@ function init(aEvent)
|
|||
#endif
|
||||
}
|
||||
|
||||
function uninit(aEvent)
|
||||
#ifdef MOZ_UPDATER
|
||||
/**
|
||||
* Creates "Last Updated" message and sets up "Check for Updates..." button.
|
||||
*/
|
||||
function initUpdates()
|
||||
{
|
||||
if (aEvent.target != document)
|
||||
return;
|
||||
var iframe = document.getElementById("creditsIframe");
|
||||
iframe.setAttribute("src", "");
|
||||
}
|
||||
var um = Components.classes["@mozilla.org/updates/update-manager;1"].
|
||||
getService(Components.interfaces.nsIUpdateManager);
|
||||
var browserBundle = Services.strings.
|
||||
createBundle("chrome://browser/locale/browser.properties");
|
||||
|
||||
function switchPage(aEvent)
|
||||
{
|
||||
var button = aEvent.target;
|
||||
if (button.localName != "button")
|
||||
return;
|
||||
|
||||
var iframe = document.getElementById("creditsIframe");
|
||||
if (gSelectedPage == 0) {
|
||||
iframe.setAttribute("src", "chrome://browser/content/credits.xhtml");
|
||||
button.setAttribute("label", document.documentElement.getAttribute("aboutlabel"));
|
||||
button.setAttribute("accesskey", document.documentElement.getAttribute("aboutaccesskey"));
|
||||
gSelectedPage = 1;
|
||||
if (um.updateCount) {
|
||||
let buildID = um.getUpdateAt(0).buildID;
|
||||
let released = browserBundle.formatStringFromName("aboutdialog.released",
|
||||
[buildID.substring(0, 4),
|
||||
buildID.substring(4, 6),
|
||||
buildID.substring(6, 8)], 3);
|
||||
document.getElementById("released").setAttribute("value", released);
|
||||
}
|
||||
else {
|
||||
iframe.setAttribute("src", "");
|
||||
button.setAttribute("label", document.documentElement.getAttribute("creditslabel"));
|
||||
button.setAttribute("accesskey", document.documentElement.getAttribute("creditsaccesskey"));
|
||||
gSelectedPage = 0;
|
||||
}
|
||||
var modes = document.getElementById("modes");
|
||||
modes.setAttribute("selectedIndex", gSelectedPage);
|
||||
}
|
||||
|
||||
var checkForUpdates = document.getElementById("checkForUpdatesButton");
|
||||
setupCheckForUpdates(checkForUpdates, browserBundle);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#
|
||||
# Contributor(s):
|
||||
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
# Margaret Leibovic <margaret.leibovic@gmail.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
|
||||
|
@ -51,55 +52,62 @@
|
|||
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
|
||||
#endif
|
||||
|
||||
<dialog xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
<window xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="aboutDialog"
|
||||
windowtype="Browser:About"
|
||||
onload="init(event);" onunload="uninit(event);"
|
||||
onload="init(event);"
|
||||
#ifdef XP_MACOSX
|
||||
inwindowmenu="false"
|
||||
buttons="extra2"
|
||||
align="end"
|
||||
#else
|
||||
title="&aboutDialog.title;"
|
||||
buttons="accept,extra2"
|
||||
#ifdef XP_UNIX
|
||||
buttonlabelaccept="&closeCmdGNOME.label;"
|
||||
buttonaccesskeyaccept="&closeCmdGNOME.accesskey;"
|
||||
#endif
|
||||
#endif
|
||||
creditslabel="©right;"
|
||||
#ifdef XP_UNIX
|
||||
creditsaccesskey="©rightGNOME.accesskey;"
|
||||
#else
|
||||
creditsaccesskey="©right.accesskey;"
|
||||
#endif
|
||||
aboutlabel="&aboutLink;"
|
||||
aboutaccesskey="&aboutLink.accesskey;">
|
||||
|
||||
>
|
||||
|
||||
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/aboutDialog.js"/>
|
||||
|
||||
<deck id="modes" flex="1">
|
||||
<vbox flex="1" id="clientBox">
|
||||
#expand <label id="version" value="&aboutVersion; __MOZ_APP_VERSION__"/>
|
||||
<label id="distribution"/>
|
||||
<label id="distributionId"/>
|
||||
<description id="copyright">
|
||||
<label
|
||||
class="text-link" href="about:license"
|
||||
>&licenseLinkText;</label>&licenseLinkSuffix;&trademarkInfo;
|
||||
<vbox>
|
||||
<hbox id="clientBox">
|
||||
<vbox id="leftBox" flex="1"/>
|
||||
<vbox id="rightBox" flex="1">
|
||||
<description id="version">
|
||||
#expand <label class="version-label" value="__MOZ_APP_VERSION__"/> <label class="version-label" id="released"/>
|
||||
</description>
|
||||
<label id="distribution" class="text-blurb"/>
|
||||
<label id="distributionId" class="text-blurb"/>
|
||||
#ifdef MOZ_UPDATER
|
||||
<hbox>
|
||||
<button id="checkForUpdatesButton" oncommand="checkForUpdates();" align="start"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
#endif
|
||||
<description class="text-blurb">
|
||||
&community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
|
||||
</description>
|
||||
<description class="text-blurb">
|
||||
&contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
|
||||
</description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<vbox id="bottomBox">
|
||||
<hbox pack="center">
|
||||
<label class="text-link bottom-link" href="about:license">&bottomLinks.license;</label>
|
||||
<label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</label>
|
||||
<label class="text-link bottom-link" href="http://www.mozilla.com/legal/privacy/">&bottomLinks.privacy;</label>
|
||||
</hbox>
|
||||
<description id="trademark">
|
||||
<label class="trademark-label">&trademarkInfo.part1;</label>
|
||||
<label class="trademark-label">&trademarkInfo.part2;</label>
|
||||
</description>
|
||||
<textbox id="userAgent" multiline="true" readonly="true" flex="1"/>
|
||||
</vbox>
|
||||
<vbox flex="1" id="creditsBox">
|
||||
<iframe id="creditsIframe" flex="1"/>
|
||||
</vbox>
|
||||
</deck>
|
||||
<separator class="groove" id="groove"/>
|
||||
</vbox>
|
||||
|
||||
<keyset>
|
||||
<key keycode="VK_ESCAPE" oncommand="window.close();"/>
|
||||
</keyset>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include browserMountPoints.inc
|
||||
#endif
|
||||
|
||||
</dialog>
|
||||
|
||||
</window>
|
||||
|
|
|
@ -55,7 +55,8 @@ html {
|
|||
#brandStart {
|
||||
background: -moz-linear-gradient(top, #42607C, #1E4262 30%, #1E4262 80%, #143552 98%, #244665);
|
||||
border-radius: 5.6px;
|
||||
padding-bottom: 0.2em;
|
||||
padding-top: 0.1em;
|
||||
padding-bottom: 0.1em;
|
||||
-moz-padding-start: 0.5em;
|
||||
font-size: 250%;
|
||||
font-weight: bold;
|
||||
|
|
|
@ -141,7 +141,6 @@ function loadSnippets()
|
|||
Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
|
||||
// Try to update from network.
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.mozBackgroundRequest = true;
|
||||
xhr.open('GET', updateURL, true);
|
||||
xhr.onerror = function (event) {
|
||||
showSnippets();
|
||||
|
|
|
@ -109,11 +109,13 @@
|
|||
oncommand="openFeedbackPage()"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
<menuseparator id="updateSeparator"/>
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef MOZ_UPDATER
|
||||
<menuitem id="checkForUpdates"
|
||||
label="&updateCmd.label;"
|
||||
class="menuitem-iconic"
|
||||
oncommand="checkForUpdates();"/>
|
||||
#endif
|
||||
#endif
|
||||
<menuseparator id="aboutSeparator"/>
|
||||
<menuitem id="aboutName"
|
||||
|
|
|
@ -19,5 +19,7 @@
|
|||
<!ENTITY % safebrowsingDTD SYSTEM "chrome://browser/locale/safebrowsing/phishing-afterload-warning-message.dtd">
|
||||
%safebrowsingDTD;
|
||||
#endif
|
||||
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
|
||||
%aboutHomeDTD;
|
||||
]>
|
||||
|
||||
|
|
|
@ -209,8 +209,8 @@
|
|||
accesskey="&viewMenu.accesskey;">
|
||||
<menupopup id="menu_viewPopup">
|
||||
<menuitem id="menu_tabview"
|
||||
label="&showTabView2.label;"
|
||||
accesskey="&showTabView2.accesskey;"
|
||||
label="&viewTabGroups.label;"
|
||||
accesskey="&viewTabGroups.accesskey;"
|
||||
command="Browser:ToggleTabView"/>
|
||||
<menu id="viewToolbarsMenu"
|
||||
label="&viewToolbarsMenu.label;"
|
||||
|
@ -513,29 +513,13 @@
|
|||
<menuitem id="sync-setup"
|
||||
label="&syncSetup.label;"
|
||||
accesskey="&syncSetup.accesskey;"
|
||||
observes="sync-setup-state"
|
||||
oncommand="gSyncUI.openSetup()"/>
|
||||
<menu id="sync-menu"
|
||||
label="&syncMenu.label;"
|
||||
accesskey="&syncMenu.accesskey;">
|
||||
<menupopup id="sync-menu-popup"
|
||||
onpopupshowing="if (event.target == this) gSyncUI.doUpdateMenu(event);">
|
||||
<menuitem id="sync-loginitem"
|
||||
label="&syncLogInItem.label;"
|
||||
accesskey="&syncLogInItem.accesskey;"
|
||||
oncommand="gSyncUI.doLogin();"/>
|
||||
<menuitem id="sync-logoutitem"
|
||||
label="&syncLogOutItem.label;"
|
||||
accesskey="&syncLogOutItem.accesskey;"
|
||||
oncommand="gSyncUI.doLogout();"/>
|
||||
<menuitem id="sync-syncnowitem"
|
||||
label="&syncSyncNowItem.label;"
|
||||
accesskey="&syncSyncNowItem.accesskey;"
|
||||
oncommand="gSyncUI.doSync(event);"/>
|
||||
<menuseparator id="sync-lastsyncsep" hidden="true"/>
|
||||
<menuitem id="sync-lastsyncitem"
|
||||
disabled="true" hidden="true"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuitem id="sync-syncnowitem"
|
||||
label="&syncSyncNowItem.label;"
|
||||
accesskey="&syncSyncNowItem.accesskey;"
|
||||
observes="sync-syncnow-state"
|
||||
oncommand="gSyncUI.doSync(event);"/>
|
||||
#endif
|
||||
<menuseparator id="devToolsSeparator"/>
|
||||
<menuitem id="menu_pageinspect"
|
||||
|
|
|
@ -192,6 +192,10 @@
|
|||
<broadcaster id="singleFeedMenuitemState" disabled="true"/>
|
||||
<broadcaster id="multipleFeedsMenuState" hidden="true"/>
|
||||
<broadcaster id="tabviewGroupsNumber" groups="0"/>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<broadcaster id="sync-setup-state"/>
|
||||
<broadcaster id="sync-syncnow-state"/>
|
||||
#endif
|
||||
</broadcasterset>
|
||||
|
||||
<keyset id="mainKeyset">
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
# Chris Beard <cbeard@mozilla.com>
|
||||
# Dan Mosedale <dmose@mozilla.org>
|
||||
# Paul O’Shannessy <paul@oshannessy.com>
|
||||
# Philipp von Weitershausen <philipp@weitershausen.de>
|
||||
#
|
||||
# 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
|
||||
|
@ -56,6 +57,7 @@ let gSyncUI = {
|
|||
"weave:service:sync:finish",
|
||||
"weave:service:sync:error",
|
||||
"weave:service:sync:delayed",
|
||||
"weave:service:quota:remaining",
|
||||
"weave:service:setup-complete",
|
||||
"weave:service:login:start",
|
||||
"weave:service:login:finish",
|
||||
|
@ -103,22 +105,20 @@ let gSyncUI = {
|
|||
|
||||
updateUI: function SUI_updateUI() {
|
||||
let needsSetup = this._needsSetup();
|
||||
document.getElementById("sync-setup").hidden = !needsSetup;
|
||||
document.getElementById("sync-menu").hidden = needsSetup;
|
||||
document.getElementById("sync-setup-state").hidden = !needsSetup;
|
||||
document.getElementById("sync-syncnow-state").hidden = needsSetup;
|
||||
|
||||
if (gBrowser) {
|
||||
let showLabel = !this._isLoggedIn() && !needsSetup;
|
||||
let button = document.getElementById("sync-status-button");
|
||||
button.setAttribute("class", showLabel ? "statusbarpanel-iconic-text"
|
||||
: "statusbarpanel-iconic");
|
||||
button.image = "chrome://browser/skin/sync-16.png";
|
||||
if (!gBrowser)
|
||||
return;
|
||||
|
||||
if (!this._isLoggedIn()) {
|
||||
//XXXzpao When we move the string bundle, we can add more and make this
|
||||
// say "needs setup" or something similar. (bug 583381)
|
||||
button.removeAttribute("tooltiptext");
|
||||
}
|
||||
}
|
||||
let button = document.getElementById("sync-button");
|
||||
if (!button)
|
||||
return;
|
||||
|
||||
button.removeAttribute("status");
|
||||
this._updateLastSyncTime();
|
||||
if (needsSetup)
|
||||
button.removeAttribute("tooltiptext");
|
||||
},
|
||||
|
||||
alltabsPopupShowing: function(event) {
|
||||
|
@ -151,10 +151,14 @@ let gSyncUI = {
|
|||
|
||||
// Functions called by observers
|
||||
onActivityStart: function SUI_onActivityStart() {
|
||||
//XXXzpao Followup: Do this with a class. (bug 583384)
|
||||
if (gBrowser)
|
||||
document.getElementById("sync-status-button").image =
|
||||
"chrome://browser/skin/sync-16-throbber.png";
|
||||
if (!gBrowser)
|
||||
return;
|
||||
|
||||
let button = document.getElementById("sync-button");
|
||||
if (!button)
|
||||
return;
|
||||
|
||||
button.setAttribute("status", "active");
|
||||
},
|
||||
|
||||
onSyncFinish: function SUI_onSyncFinish() {
|
||||
|
@ -180,7 +184,7 @@ let gSyncUI = {
|
|||
Weave.Notifications.removeAll(title);
|
||||
|
||||
this.updateUI();
|
||||
this._updateLastSyncItem();
|
||||
this._updateLastSyncTime();
|
||||
},
|
||||
|
||||
onLoginError: function SUI_onLoginError() {
|
||||
|
@ -218,6 +222,21 @@ let gSyncUI = {
|
|||
this.updateUI();
|
||||
},
|
||||
|
||||
onQuotaNotice: function onQuotaNotice(subject, data) {
|
||||
let title = this._stringBundle.GetStringFromName("warning.sync.quota.label");
|
||||
let description = this._stringBundle.GetStringFromName("warning.sync.quota.description");
|
||||
let buttons = [];
|
||||
buttons.push(new Weave.NotificationButton(
|
||||
this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.label"),
|
||||
this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.accesskey"),
|
||||
function() { gSyncUI.openQuotaDialog(); return true; }
|
||||
));
|
||||
|
||||
let notification = new Weave.Notification(
|
||||
title, description, null, Weave.Notifications.PRIORITY_WARNING, buttons);
|
||||
Weave.Notifications.replaceTitle(notification);
|
||||
},
|
||||
|
||||
onNotificationAdded: function SUI_onNotificationAdded() {
|
||||
if (!gBrowser)
|
||||
return;
|
||||
|
@ -249,32 +268,6 @@ let gSyncUI = {
|
|||
},
|
||||
|
||||
// Commands
|
||||
doUpdateMenu: function SUI_doUpdateMenu(event) {
|
||||
this._updateLastSyncItem();
|
||||
|
||||
let loginItem = document.getElementById("sync-loginitem");
|
||||
let logoutItem = document.getElementById("sync-logoutitem");
|
||||
let syncItem = document.getElementById("sync-syncnowitem");
|
||||
|
||||
// Don't allow "login" to be selected in some cases
|
||||
let offline = Services.io.offline;
|
||||
let locked = Weave.Service.locked;
|
||||
let noUser = Weave.Service.username == "";
|
||||
let notReady = offline || locked || noUser;
|
||||
loginItem.setAttribute("disabled", notReady);
|
||||
logoutItem.setAttribute("disabled", notReady);
|
||||
|
||||
// Don't allow "sync now" to be selected in some cases
|
||||
let loggedIn = Weave.Service.isLoggedIn;
|
||||
let noNode = Weave.Status.sync == Weave.NO_SYNC_NODE_FOUND;
|
||||
let disableSync = notReady || !loggedIn || noNode;
|
||||
syncItem.setAttribute("disabled", disableSync);
|
||||
|
||||
// Only show one of login/logout
|
||||
loginItem.setAttribute("hidden", loggedIn);
|
||||
logoutItem.setAttribute("hidden", !loggedIn);
|
||||
},
|
||||
|
||||
doLogin: function SUI_doLogin() {
|
||||
Weave.Service.login();
|
||||
},
|
||||
|
@ -284,16 +277,15 @@ let gSyncUI = {
|
|||
},
|
||||
|
||||
doSync: function SUI_doSync() {
|
||||
Weave.Service.sync();
|
||||
if (Weave.Service.isLoggedIn || Weave.Service.login())
|
||||
Weave.Service.sync();
|
||||
},
|
||||
|
||||
handleStatusbarButton: function SUI_handleStatusbarButton() {
|
||||
if (Weave.Service.isLoggedIn)
|
||||
Weave.Service.sync();
|
||||
else if (this._needsSetup())
|
||||
handleToolbarButton: function SUI_handleStatusbarButton() {
|
||||
if (this._needsSetup())
|
||||
this.openSetup();
|
||||
else
|
||||
Weave.Service.login();
|
||||
this.doSync();
|
||||
},
|
||||
|
||||
//XXXzpao should be part of syncCommon.js - which we might want to make a module...
|
||||
|
@ -308,34 +300,46 @@ let gSyncUI = {
|
|||
}
|
||||
},
|
||||
|
||||
openQuotaDialog: function SUI_openQuotaDialog() {
|
||||
let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
|
||||
if (win)
|
||||
win.focus();
|
||||
else
|
||||
Services.ww.activeWindow.openDialog(
|
||||
"chrome://browser/content/syncQuota.xul", "",
|
||||
"centerscreen,chrome,dialog,modal");
|
||||
},
|
||||
|
||||
openPrefs: function SUI_openPrefs() {
|
||||
openPreferences("paneSync");
|
||||
},
|
||||
|
||||
|
||||
// Helpers
|
||||
_updateLastSyncItem: function SUI__updateLastSyncItem() {
|
||||
_updateLastSyncTime: function SUI__updateLastSyncTime() {
|
||||
if (!gBrowser)
|
||||
return;
|
||||
|
||||
let syncButton = document.getElementById("sync-button");
|
||||
if (!syncButton)
|
||||
return;
|
||||
|
||||
let lastSync;
|
||||
try {
|
||||
lastSync = Services.prefs.getCharPref("services.sync.lastSync");
|
||||
}
|
||||
catch (e) { };
|
||||
if (!lastSync)
|
||||
if (!lastSync || this._needsSetup()) {
|
||||
syncButton.removeAttribute("tooltiptext");
|
||||
return;
|
||||
|
||||
let lastSyncItem = document.getElementById("sync-lastsyncitem");
|
||||
}
|
||||
|
||||
// Show the day-of-week and time (HH:MM) of last sync
|
||||
let lastSyncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
|
||||
let lastSyncLabel =
|
||||
this._stringBundle.formatStringFromName("lastSync.label", [lastSyncDate], 1);
|
||||
lastSyncItem.setAttribute("label", lastSyncLabel);
|
||||
lastSyncItem.setAttribute("hidden", "false");
|
||||
document.getElementById("sync-lastsyncsep").hidden = false;
|
||||
|
||||
if (gBrowser)
|
||||
document.getElementById("sync-status-button").
|
||||
setAttribute("tooltiptext", lastSyncLabel);
|
||||
syncButton.setAttribute("tooltiptext", lastSyncLabel);
|
||||
},
|
||||
|
||||
_onSyncEnd: function SUI__onSyncEnd(success) {
|
||||
|
@ -352,7 +356,18 @@ let gSyncUI = {
|
|||
let priority = Weave.Notifications.PRIORITY_WARNING;
|
||||
let buttons = [];
|
||||
|
||||
if (!Weave.Status.enforceBackoff) {
|
||||
if (Weave.Status.sync == Weave.OVER_QUOTA) {
|
||||
description = this._stringBundle.GetStringFromName(
|
||||
"error.sync.quota.description");
|
||||
buttons.push(new Weave.NotificationButton(
|
||||
this._stringBundle.GetStringFromName(
|
||||
"error.sync.viewQuotaButton.label"),
|
||||
this._stringBundle.GetStringFromName(
|
||||
"error.sync.viewQuotaButton.accesskey"),
|
||||
function() { gSyncUI.openQuotaDialog(); return true; } )
|
||||
);
|
||||
}
|
||||
else if (!Weave.Status.enforceBackoff) {
|
||||
priority = Weave.Notifications.PRIORITY_INFO;
|
||||
buttons.push(new Weave.NotificationButton(
|
||||
this._stringBundle.GetStringFromName("error.sync.tryAgainButton.label"),
|
||||
|
@ -377,7 +392,7 @@ let gSyncUI = {
|
|||
}
|
||||
|
||||
this.updateUI();
|
||||
this._updateLastSyncItem();
|
||||
this._updateLastSyncTime();
|
||||
},
|
||||
|
||||
observe: function SUI_observe(subject, topic, data) {
|
||||
|
@ -394,6 +409,9 @@ let gSyncUI = {
|
|||
case "weave:service:sync:delayed":
|
||||
this.onSyncDelay();
|
||||
break;
|
||||
case "weave:service:quota:remaining":
|
||||
this.onQuotaNotice();
|
||||
break;
|
||||
case "weave:service:setup-complete":
|
||||
this.onLoginFinish();
|
||||
break;
|
||||
|
|
|
@ -136,6 +136,20 @@ let TabView = {
|
|||
else
|
||||
this.show();
|
||||
},
|
||||
|
||||
getActiveGroupName: function Tabview_getActiveGroupName() {
|
||||
// We get the active group this way, instead of querying
|
||||
// GroupItems.getActiveGroupItem() because the tabSelect event
|
||||
// will not have happened by the time the browser tries to
|
||||
// update the title.
|
||||
let activeTab = window.gBrowser.selectedTab;
|
||||
if (activeTab.tabItem && activeTab.tabItem.parent){
|
||||
let groupName = activeTab.tabItem.parent.getTitle();
|
||||
if (groupName)
|
||||
return groupName;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// ----------
|
||||
updateContextMenu: function(tab, popup) {
|
||||
|
|
|
@ -37,15 +37,17 @@ tabbrowser {
|
|||
min-width: 1px;
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not([fadein]):not([pinned]) > .tab-text,
|
||||
.tabbrowser-tab:not([fadein]):not([pinned]) > .tab-icon-image,
|
||||
.tabbrowser-tab:not([fadein]):not([pinned]) > .tab-close-button {
|
||||
.tab-progress:not([fadein]):not([pinned]),
|
||||
.tab-label:not([fadein]):not([pinned]),
|
||||
.tab-icon-image:not([fadein]):not([pinned]),
|
||||
.tab-close-button:not([fadein]):not([pinned]) {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.tabbrowser-tab > .tab-text,
|
||||
.tabbrowser-tab > .tab-icon-image,
|
||||
.tabbrowser-tab > .tab-close-button {
|
||||
.tab-progress,
|
||||
.tab-label,
|
||||
.tab-icon-image,
|
||||
.tab-close-button {
|
||||
-moz-transition: opacity .25s;
|
||||
}
|
||||
|
||||
|
@ -54,14 +56,6 @@ tabbrowser {
|
|||
display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
|
||||
}
|
||||
|
||||
.tabbrowser-tab[pinned] > .tab-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[pinned] > .tab-icon-image {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#alltabs-popup {
|
||||
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
|
||||
}
|
||||
|
@ -148,16 +142,69 @@ toolbar[mode="icons"] > #reload-button[displaystop] {
|
|||
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
|
||||
}
|
||||
|
||||
#urlbar-progress {
|
||||
-moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter");
|
||||
}
|
||||
|
||||
/* Some child nodes want to be ordered based on the locale's direction, while
|
||||
everything else should be ltr. */
|
||||
#urlbar:-moz-locale-dir(rtl) > .autocomplete-textbox-container > .textbox-input-box {
|
||||
.urlbar-input-box:-moz-locale-dir(rtl) {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
#urlbar html|*.autocomplete-textbox {
|
||||
html|*.urlbar-input {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
/* over-link in location bar */
|
||||
|
||||
.urlbar-over-link-layer[overlinkstate="fade-in"],
|
||||
.urlbar-textbox-container:not([overlinkstate]) {
|
||||
-moz-transition-property: color;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-delay: 50ms;
|
||||
-moz-transition-timing-function: cubic-bezier(0.0, 0.6, 1.0, 1.0);
|
||||
}
|
||||
|
||||
.urlbar-textbox-container[overlinkstate="fade-in"],
|
||||
.urlbar-over-link-layer:not([overlinkstate]) {
|
||||
-moz-transition-property: color;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-delay: 50ms;
|
||||
-moz-transition-timing-function: linear;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.urlbar-over-link-box[overlinkstate="fade-in"],
|
||||
.urlbar-textbox-container-children:not([overlinkstate]) {
|
||||
-moz-transition-property: opacity;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-delay: 50ms;
|
||||
-moz-transition-timing-function: cubic-bezier(0.0, 0.6, 1.0, 1.0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.urlbar-textbox-container-children[overlinkstate="fade-in"],
|
||||
.urlbar-over-link-box:not([overlinkstate]) {
|
||||
-moz-transition-property: opacity;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-delay: 50ms;
|
||||
-moz-transition-timing-function: linear;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.urlbar-textbox-container[overlinkstate="showing"] {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.urlbar-over-link-box[overlinkstate="showing"] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.urlbar-textbox-container-children[overlinkstate="showing"] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* For results that are actions, their description text is shown instead of
|
||||
the URL - this needs to follow the locale's direction, unlike URLs. */
|
||||
richlistitem[type~="action"]:-moz-locale-dir(rtl) > .ac-url-box {
|
||||
|
@ -186,15 +233,6 @@ richlistitem[type~="action"]:-moz-locale-dir(rtl) > .ac-url-box {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#feed-button > .button-box > .box-inherit > .button-text,
|
||||
#feed-button > .button-box > .button-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#feed-menu > .feed-menuitem:-moz-locale-dir(rtl) {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
#urlbar-container[combined] > #urlbar > #urlbar-icons > #go-button,
|
||||
#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button),
|
||||
#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button,
|
||||
|
|
|
@ -2327,56 +2327,6 @@ function BrowserPageInfo(doc, initialTab, imageElement) {
|
|||
"chrome,toolbar,dialog=no,resizable", args);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Initialize the LeakDetector class.
|
||||
function LeakDetector(verbose)
|
||||
{
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
const NS_LEAKDETECTOR_CONTRACTID = "@mozilla.org/xpcom/leakdetector;1";
|
||||
|
||||
if (NS_LEAKDETECTOR_CONTRACTID in Components.classes) {
|
||||
try {
|
||||
LeakDetector.prototype = Components.classes[NS_LEAKDETECTOR_CONTRACTID]
|
||||
.createInstance(Components.interfaces.nsILeakDetector);
|
||||
} catch (err) {
|
||||
LeakDetector.prototype = Object.prototype;
|
||||
}
|
||||
} else {
|
||||
LeakDetector.prototype = Object.prototype;
|
||||
}
|
||||
|
||||
var leakDetector = new LeakDetector(false);
|
||||
|
||||
// Dumps current set of memory leaks.
|
||||
function dumpMemoryLeaks()
|
||||
{
|
||||
leakDetector.dumpLeaks();
|
||||
}
|
||||
|
||||
// Traces all objects reachable from the chrome document.
|
||||
function traceChrome()
|
||||
{
|
||||
leakDetector.traceObject(document, leakDetector.verbose);
|
||||
}
|
||||
|
||||
// Traces all objects reachable from the content document.
|
||||
function traceDocument()
|
||||
{
|
||||
// keep the chrome document out of the dump.
|
||||
leakDetector.markObject(document, true);
|
||||
leakDetector.traceObject(content, leakDetector.verbose);
|
||||
leakDetector.markObject(document, false);
|
||||
}
|
||||
|
||||
// Controls whether or not we do verbose tracing.
|
||||
function traceVerbose(verbose)
|
||||
{
|
||||
leakDetector.verbose = (verbose == "true");
|
||||
}
|
||||
#endif
|
||||
|
||||
function URLBarSetURI(aURI) {
|
||||
var value = gBrowser.userTypedValue;
|
||||
var valid = false;
|
||||
|
@ -2979,8 +2929,6 @@ function openHomeDialog(aURL)
|
|||
str.data = aURL;
|
||||
gPrefService.setComplexValue("browser.startup.homepage",
|
||||
Components.interfaces.nsISupportsString, str);
|
||||
var homeButton = document.getElementById("home-button");
|
||||
homeButton.setAttribute("tooltiptext", aURL);
|
||||
} catch (ex) {
|
||||
dump("Failed to set the home page.\n"+ex+"\n");
|
||||
}
|
||||
|
@ -3233,32 +3181,8 @@ const BrowserSearch = {
|
|||
|
||||
if (hidden)
|
||||
browser.hiddenEngines = engines;
|
||||
else {
|
||||
browser.engines = engines;
|
||||
if (browser == gBrowser.selectedBrowser)
|
||||
this.updateSearchButton();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the browser UI to show whether or not additional engines are
|
||||
* available when a page is loaded or the user switches tabs to a page that
|
||||
* has search engines.
|
||||
*/
|
||||
updateSearchButton: function() {
|
||||
var searchBar = this.searchBar;
|
||||
|
||||
// The search bar binding might not be applied even though the element is
|
||||
// in the document (e.g. when the navigation toolbar is hidden), so check
|
||||
// for .searchButton specifically.
|
||||
if (!searchBar || !searchBar.searchButton)
|
||||
return;
|
||||
|
||||
var engines = gBrowser.selectedBrowser.engines;
|
||||
if (engines && engines.length > 0)
|
||||
searchBar.searchButton.setAttribute("addengines", "true");
|
||||
else
|
||||
searchBar.searchButton.removeAttribute("addengines");
|
||||
browser.engines = engines;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4010,7 +3934,6 @@ var XULBrowserWindow = {
|
|||
defaultStatus: "",
|
||||
jsStatus: "",
|
||||
jsDefaultStatus: "",
|
||||
overLink: "",
|
||||
startTime: 0,
|
||||
statusText: "",
|
||||
isBusy: false,
|
||||
|
@ -4029,7 +3952,7 @@ var XULBrowserWindow = {
|
|||
|
||||
get statusMeter () {
|
||||
delete this.statusMeter;
|
||||
return this.statusMeter = document.getElementById("statusbar-icon");
|
||||
return this.statusMeter = document.getElementById("urlbar-progress");
|
||||
},
|
||||
get stopCommand () {
|
||||
delete this.stopCommand;
|
||||
|
@ -4093,16 +4016,16 @@ var XULBrowserWindow = {
|
|||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setOverLink: function (link, b) {
|
||||
setOverLink: function (link) {
|
||||
// Encode bidirectional formatting characters.
|
||||
// (RFC 3987 sections 3.2 and 4.1 paragraph 6)
|
||||
this.overLink = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
|
||||
encodeURIComponent);
|
||||
this.updateStatusField();
|
||||
link = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
|
||||
encodeURIComponent);
|
||||
gURLBar.setOverLink(link);
|
||||
},
|
||||
|
||||
updateStatusField: function () {
|
||||
var text = this.overLink || this.status || this.jsStatus || this.jsDefaultStatus || this.defaultStatus;
|
||||
var text = this.status || this.jsStatus || this.jsDefaultStatus || this.defaultStatus;
|
||||
|
||||
// check the current value so we don't trigger an attribute change
|
||||
// and cause needless (slow!) UI updates
|
||||
|
@ -4165,7 +4088,7 @@ var XULBrowserWindow = {
|
|||
this._progressCollapseTimer = 0;
|
||||
}
|
||||
else
|
||||
this.statusMeter.parentNode.collapsed = false;
|
||||
this.statusMeter.collapsed = false;
|
||||
|
||||
// XXX: This needs to be based on window activity...
|
||||
this.stopCommand.removeAttribute("disabled");
|
||||
|
@ -4229,7 +4152,7 @@ var XULBrowserWindow = {
|
|||
|
||||
// Turn the progress meter and throbber off.
|
||||
this._progressCollapseTimer = setTimeout(function (self) {
|
||||
self.statusMeter.parentNode.collapsed = true;
|
||||
self.statusMeter.collapsed = true;
|
||||
self._progressCollapseTimer = 0;
|
||||
}, 100, this);
|
||||
|
||||
|
@ -4366,7 +4289,6 @@ var XULBrowserWindow = {
|
|||
|
||||
asyncUpdateUI: function () {
|
||||
FeedHandler.updateFeeds();
|
||||
BrowserSearch.updateSearchButton();
|
||||
},
|
||||
|
||||
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
|
||||
|
@ -5001,7 +4923,10 @@ var gHomeButton = {
|
|||
if (homeButton) {
|
||||
var homePage = this.getHomePage();
|
||||
homePage = homePage.replace(/\|/g,', ');
|
||||
homeButton.setAttribute("tooltiptext", homePage);
|
||||
if (homePage.toLowerCase() == "about:home")
|
||||
homeButton.setAttribute("tooltiptext", homeButton.getAttribute("aboutHomeOverrideTooltip"));
|
||||
else
|
||||
homeButton.setAttribute("tooltiptext", homePage);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -6705,23 +6630,7 @@ function convertFromUnicode(charset, str)
|
|||
*/
|
||||
var FeedHandler = {
|
||||
/**
|
||||
* The click handler for the Feed icon in the location bar. Opens the
|
||||
* subscription page if user is not given a choice of feeds.
|
||||
* (Otherwise the list of available feeds will be presented to the
|
||||
* user in a popup menu.)
|
||||
*/
|
||||
onFeedButtonClick: function(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if (event.target.hasAttribute("feed") &&
|
||||
event.eventPhase == Event.AT_TARGET &&
|
||||
(event.button == 0 || event.button == 1)) {
|
||||
this.subscribeToFeed(null, event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the user clicks on the Feed icon in the location bar.
|
||||
* Called when the user clicks on the Subscribe to This Page... menu item.
|
||||
* Builds a menu of unique feeds associated with the page, and if there
|
||||
* is only one, shows the feed inline in the browser window.
|
||||
* @param menuPopup
|
||||
|
@ -6746,13 +6655,6 @@ var FeedHandler = {
|
|||
while (menuPopup.firstChild)
|
||||
menuPopup.removeChild(menuPopup.firstChild);
|
||||
|
||||
if (feeds.length == 1) {
|
||||
var feedButton = document.getElementById("feed-button");
|
||||
if (feedButton)
|
||||
feedButton.setAttribute("feed", feeds[0].href);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the menu showing the available feed choices for viewing.
|
||||
for (var i = 0; i < feeds.length; ++i) {
|
||||
var feedInfo = feeds[i];
|
||||
|
@ -6824,30 +6726,16 @@ var FeedHandler = {
|
|||
* a page is loaded or the user switches tabs to a page that has feeds.
|
||||
*/
|
||||
updateFeeds: function() {
|
||||
var feedButton = document.getElementById("feed-button");
|
||||
|
||||
var feeds = gBrowser.selectedBrowser.feeds;
|
||||
if (!feeds || feeds.length == 0) {
|
||||
if (feedButton) {
|
||||
feedButton.collapsed = true;
|
||||
feedButton.removeAttribute("feed");
|
||||
}
|
||||
this._feedMenuitem.setAttribute("disabled", "true");
|
||||
this._feedMenupopup.setAttribute("hidden", "true");
|
||||
this._feedMenuitem.removeAttribute("hidden");
|
||||
} else {
|
||||
if (feedButton)
|
||||
feedButton.collapsed = false;
|
||||
|
||||
if (feeds.length > 1) {
|
||||
this._feedMenuitem.setAttribute("hidden", "true");
|
||||
this._feedMenupopup.removeAttribute("hidden");
|
||||
if (feedButton)
|
||||
feedButton.removeAttribute("feed");
|
||||
} else {
|
||||
if (feedButton)
|
||||
feedButton.setAttribute("feed", feeds[0].href);
|
||||
|
||||
this._feedMenuitem.setAttribute("feed", feeds[0].href);
|
||||
this._feedMenuitem.removeAttribute("disabled");
|
||||
this._feedMenuitem.removeAttribute("hidden");
|
||||
|
@ -6868,12 +6756,6 @@ var FeedHandler = {
|
|||
browserForLink.feeds = [];
|
||||
|
||||
browserForLink.feeds.push({ href: link.href, title: link.title });
|
||||
|
||||
if (browserForLink == gBrowser.selectedBrowser) {
|
||||
var feedButton = document.getElementById("feed-button");
|
||||
if (feedButton)
|
||||
feedButton.collapsed = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -116,10 +116,6 @@
|
|||
tbattr="tabbrowser-multiple"
|
||||
oncommand="gBrowser.reloadAllTabs();"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="context_openTabInWindow" label="&openTabInNewWindow.label;"
|
||||
accesskey="&openTabInNewWindow.accesskey;"
|
||||
tbattr="tabbrowser-multiple"
|
||||
oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
|
||||
<menuitem id="context_pinTab" label="&pinAppTab.label;"
|
||||
accesskey="&pinAppTab.accesskey;"
|
||||
oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
|
||||
|
@ -135,6 +131,10 @@
|
|||
oncommand="TabView.moveTabTo(TabContextMenu.contextTab, null);"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
|
||||
accesskey="&moveToNewWindow.accesskey;"
|
||||
tbattr="tabbrowser-multiple"
|
||||
oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="context_bookmarkAllTabs"
|
||||
label="&bookmarkAllTabs.label;"
|
||||
|
@ -415,7 +415,7 @@
|
|||
<stack id="allTabs-stack">
|
||||
<vbox id="allTabs-container"><hbox/></vbox>
|
||||
<toolbarbutton id="allTabs-tab-close-button"
|
||||
class="tab-close-button"
|
||||
class="tabs-closebutton"
|
||||
oncommand="allTabs.closeTab(event);"
|
||||
tooltiptext="&closeCmd.label;"
|
||||
style="visibility:hidden"/>
|
||||
|
@ -441,10 +441,18 @@
|
|||
<hbox id="appmenu-button-container" align="start">
|
||||
<button id="appmenu-button"
|
||||
type="menu"
|
||||
#ifdef XP_WIN
|
||||
label="&brandShortName;"
|
||||
#else
|
||||
label="&appMenuButton.label;"
|
||||
#endif
|
||||
style="-moz-user-focus: ignore;">
|
||||
<menupopup id="appmenu-popup"
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
onpopupshowing="updateEditUIVisibility();gSyncUI.updateUI();">
|
||||
#else
|
||||
onpopupshowing="updateEditUIVisibility();">
|
||||
#endif
|
||||
<hbox>
|
||||
<vbox id="appmenuPrimaryPane">
|
||||
<hbox flex="1"
|
||||
|
@ -760,6 +768,18 @@
|
|||
</menupopup>
|
||||
</menu>
|
||||
</hbox>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<spacer flex="1"/>
|
||||
<!-- only one of sync-setup or sync-syncnow will be showing at once -->
|
||||
<menuitem id="sync-setup-appmenu"
|
||||
label="&syncSetup.label;"
|
||||
observes="sync-setup-state"
|
||||
oncommand="gSyncUI.openSetup()"/>
|
||||
<menuitem id="sync-syncnowitem-appmenu"
|
||||
label="&syncSyncNowItem.label;"
|
||||
observes="sync-syncnow-state"
|
||||
oncommand="gSyncUI.doSync(event);"/>
|
||||
#endif
|
||||
</vbox>
|
||||
</hbox>
|
||||
</menupopup>
|
||||
|
@ -856,7 +876,8 @@
|
|||
ondragenter="homeButtonObserver.onDragOver(event)"
|
||||
ondrop="homeButtonObserver.onDrop(event)"
|
||||
ondragleave="homeButtonObserver.onDragLeave(event)"
|
||||
onclick="BrowserGoHome(event);"/>
|
||||
onclick="BrowserGoHome(event);"
|
||||
aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
|
||||
|
||||
<toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
|
||||
title="&locationItem.title;" class="chromeclass-location" removable="true">
|
||||
|
@ -911,19 +932,6 @@
|
|||
</box>
|
||||
<label id="urlbar-display" value="&urlbar.switchToTab.label;"/>
|
||||
<hbox id="urlbar-icons">
|
||||
<button type="menu"
|
||||
style="-moz-user-focus: none"
|
||||
class="plain urlbar-icon"
|
||||
id="feed-button"
|
||||
collapsed="true"
|
||||
tooltiptext="&feedButton.tooltip;"
|
||||
onclick="return FeedHandler.onFeedButtonClick(event);">
|
||||
<menupopup position="after_end"
|
||||
id="feed-menu"
|
||||
onpopupshowing="return FeedHandler.buildFeedList(this);"
|
||||
oncommand="return FeedHandler.subscribeToFeed(null, event);"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
</button>
|
||||
<image id="star-button"
|
||||
class="urlbar-icon"
|
||||
onclick="PlacesStarButton.onClick(event);"/>
|
||||
|
@ -932,6 +940,7 @@
|
|||
tooltiptext="&goEndCap.tooltip;"
|
||||
onclick="gURLBar.handleCommand(event);"/>
|
||||
</hbox>
|
||||
<progressmeter id="urlbar-progress" mode="normal"/>
|
||||
<toolbarbutton id="urlbar-go-button"
|
||||
onclick="gURLBar.handleCommand(event);"
|
||||
tooltiptext="&goEndCap.tooltip;"/>
|
||||
|
@ -985,6 +994,19 @@
|
|||
if (!this.parentNode._placesView)
|
||||
new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
|
||||
tooltip="bhTooltip" popupsinherittooltip="true">
|
||||
<menuitem id="BMB_subscribeToPageMenuitem"
|
||||
label="&subscribeToPageMenuitem.label;"
|
||||
oncommand="return FeedHandler.subscribeToFeed(null, event);"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
observes="singleFeedMenuitemState"/>
|
||||
<menu id="BMB_subscribeToPageMenupopup"
|
||||
label="&subscribeToPageMenupopup.label;"
|
||||
observes="multipleFeedsMenuState">
|
||||
<menupopup id="BMB_subscribeToPageSubmenuMenupopup"
|
||||
onpopupshowing="return FeedHandler.buildFeedList(event.target);"
|
||||
oncommand="return FeedHandler.subscribeToFeed(null, event);"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
</menu>
|
||||
<menuitem id="BMB_bookmarkAllTabs"
|
||||
label="&addCurPagesCmd.label;"
|
||||
command="Browser:BookmarkAllTabs"
|
||||
|
@ -1138,9 +1160,9 @@
|
|||
</toolbarbutton>
|
||||
|
||||
<toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
label="&tabViewButton2.label;"
|
||||
label="&tabGroupsButton.label;"
|
||||
command="Browser:ToggleTabView"
|
||||
tooltiptext="&tabViewButton2.tooltip;"
|
||||
tooltiptext="&tabGroupsButton.tooltip;"
|
||||
removable="true"
|
||||
observes="tabviewGroupsNumber"/>
|
||||
|
||||
|
@ -1228,7 +1250,12 @@
|
|||
command="cmd_fullZoomEnlarge"
|
||||
tooltiptext="&zoomInButton.tooltip;"/>
|
||||
</toolbaritem>
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<toolbarbutton id="sync-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
label="&syncToolbarButton.label;"
|
||||
oncommand="gSyncUI.handleToolbarButton()"/>
|
||||
#endif
|
||||
</toolbarpalette>
|
||||
</toolbox>
|
||||
|
||||
|
@ -1261,9 +1288,6 @@
|
|||
#endif
|
||||
>
|
||||
<statusbarpanel id="statusbar-display" label="" flex="1"/>
|
||||
<statusbarpanel class="statusbarpanel-progress" collapsed="true" id="statusbar-progresspanel">
|
||||
<progressmeter class="progressmeter-statusbar" id="statusbar-icon" mode="normal" value="0"/>
|
||||
</statusbarpanel>
|
||||
<statusbarpanel id="download-monitor" class="statusbarpanel-iconic-text"
|
||||
tooltiptext="&downloadMonitor2.tooltip;" hidden="true"
|
||||
command="Tools:Downloads"/>
|
||||
|
@ -1271,14 +1295,6 @@
|
|||
hidden="true"
|
||||
onclick="if (event.button == 0 && event.detail == 1) displaySecurityInfo();"/>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<statusbarpanel id="sync-status-button"
|
||||
class="statusbarpanel-iconic"
|
||||
image="chrome://browser/skin/sync-16.png"
|
||||
label="&syncLogInItem.label;"
|
||||
oncommand="gSyncUI.handleStatusbarButton();"
|
||||
onmousedown="event.preventDefault();">
|
||||
</statusbarpanel>
|
||||
<separator class="thin"/>
|
||||
<statusbarpanel id="sync-notifications-button"
|
||||
class="statusbarpanel-iconic-text"
|
||||
hidden="true"
|
||||
|
|
|
@ -1,648 +0,0 @@
|
|||
<!-- -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
# ***** 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 Firefox Credits.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Ben Goodger.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2004
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Ben Goodger <ben@mozilla.org>
|
||||
# David Baron <dbaron@mozilla.org>
|
||||
# Ehsan Akhgari <ehsan.akhgari@gmail.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 *****
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
||||
[
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
%brandDTD;
|
||||
<!ENTITY % creditsDTD SYSTEM "chrome://browser/locale/credits.dtd">
|
||||
%creditsDTD;
|
||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
]
|
||||
>
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>&brandFullName; Credits</title>
|
||||
|
||||
<style>
|
||||
html {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
* {
|
||||
cursor: default;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
#titleBox {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: auto;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#footerBox {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: auto;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#creditsBox {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
bottom: 8px;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
width: 280px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
font-size: small;
|
||||
text-align: center;
|
||||
margin: 15px 0px 5px 0px;
|
||||
}
|
||||
|
||||
.creditsGroup {
|
||||
margin-bottom: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
font-size: x-small;
|
||||
text-align: justify;
|
||||
line-height: 110%;
|
||||
}
|
||||
|
||||
h2.title {
|
||||
margin-top: 200px;
|
||||
margin-bottom: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.links {
|
||||
font-weight: normal;
|
||||
font-size: small;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
margin: 0px 0px 100px 0px;
|
||||
}
|
||||
|
||||
.motto {
|
||||
margin-top: 2px;
|
||||
font-style: italic;
|
||||
font-size: small;
|
||||
font-weight: normal;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
#gecko {
|
||||
margin-top: 100px;
|
||||
margin-bottom: 100px;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 0px;
|
||||
margin-left: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
var gCreditsInterval = -1;
|
||||
|
||||
function uninit()
|
||||
{
|
||||
if (gCreditsInterval > -1)
|
||||
clearInterval(gCreditsInterval);
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
var cb = document.getElementById("creditsBox");
|
||||
cb.scrollTop = 0;
|
||||
setTimeout(runCredits, 3000);
|
||||
}
|
||||
|
||||
function runCredits()
|
||||
{
|
||||
gCreditsInterval = setInterval("creditsCallback()", 25);
|
||||
}
|
||||
|
||||
function creditsCallback()
|
||||
{
|
||||
var cb = document.getElementById("creditsBox");
|
||||
var newtop = cb.scrollTop + 1;
|
||||
cb.scrollTop = newtop;
|
||||
if (cb.scrollTop != newtop) {
|
||||
// we're at the bottom
|
||||
clearInterval(gCreditsInterval);
|
||||
setTimeout(function() { cb.scrollTop = 0 }, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init();" onunload="uninit();">
|
||||
<div id="titleBox">
|
||||
<img src="chrome://branding/content/aboutCredits.png" />
|
||||
</div>
|
||||
|
||||
<div id="creditsBox">
|
||||
<h2 class="title" dir="&locale.dir;">&brandFullName;™
|
||||
<div class="motto">&brandMotto;</div>
|
||||
</h2>
|
||||
<div class="links" dir="&locale.dir;">
|
||||
&credit.thanks2; <a href="" link="about:credits" onclick="visitLink(event);">&credit.contributors2;</a>
|
||||
</div>
|
||||
|
||||
<div class="creditsGroup">
|
||||
<ul>
|
||||
<li>Josh Aas</li>
|
||||
<li>Robert Accettura</li>
|
||||
<li>Lucas Adamski</li>
|
||||
<li>Raymond Etornam Agbeame</li>
|
||||
<li>Ehsan Akhgari</li>
|
||||
<li>Sean Alamares</li>
|
||||
<li>Pedro Alves</li>
|
||||
<li>David Anderson</li>
|
||||
<li>Harvey Anderson</li>
|
||||
<li>Smokey Ardisson</li>
|
||||
<li>Rob Arnold</li>
|
||||
<li>Tomoya Asai</li>
|
||||
<li>Chris AtLee</li>
|
||||
<li>Dietrich Ayala</li>
|
||||
<li>Mitchell Baker</li>
|
||||
<li>Rhian Baker</li>
|
||||
<li>Jeff Balogh</li>
|
||||
<li>Jan Bambas</li>
|
||||
<li>Rey Bango</li>
|
||||
<li>Mark Banner</li>
|
||||
<li>Jason Barnabe</li>
|
||||
<li>David Baron</li>
|
||||
<li>Colin Barrett</li>
|
||||
<li>Curtis Bartley</li>
|
||||
<li>Bo Bayles</li>
|
||||
<li>Christopher Beard</li>
|
||||
<li>Glen Beasley</li>
|
||||
<li>Juan Becerra</li>
|
||||
<li>Brian Behlendorf</li>
|
||||
<li>Mike Beltzner</li>
|
||||
<li>Mic Berman</li>
|
||||
<li>Uri Bernstein</li>
|
||||
<li>Christian Biesinger</li>
|
||||
<li>Al Billings</li>
|
||||
<li>Seth Bindernagel</li>
|
||||
<li>Lukas Blakk</li>
|
||||
<li>Jim Blandy</li>
|
||||
<li>Chris Blizzard</li>
|
||||
<li>Jamey Boje</li>
|
||||
<li>David Bolter</li>
|
||||
<li>Nelson Bolyard</li>
|
||||
<li>Marco Bonardo</li>
|
||||
<li>Carsten Book</li>
|
||||
<li>Paul Booker</li>
|
||||
<li>Jennifer Boriss</li>
|
||||
<li>Dan Born</li>
|
||||
<li>Arpad Borsos</li>
|
||||
<li>David Boswell</li>
|
||||
<li>Ondřej Brablc</li>
|
||||
<li>Catherine Brady</li>
|
||||
<li>Dave Bragsalla</li>
|
||||
<li>Alex Buchanan</li>
|
||||
<li>Igor Bukanov</li>
|
||||
<li>Simon Bünzli</li>
|
||||
<li>Lapo Calamandrei</li>
|
||||
<li>Dave Camp</li>
|
||||
<li>Rob Campbell</li>
|
||||
<li>Regis Caspar</li>
|
||||
<li>Garrett Casto</li>
|
||||
<li>Tony Chang</li>
|
||||
<li>Wan-Teh Chang</li>
|
||||
<li>Emily Chen</li>
|
||||
<li>Ginn Chen</li>
|
||||
<li>Pascal Chevrel</li>
|
||||
<li>Adam Christian</li>
|
||||
<li>Tony Chung</li>
|
||||
<li>Bob Clary</li>
|
||||
<li>Wil Clouser</li>
|
||||
<li>Mary Colvig</li>
|
||||
<li>Majken Connor</li>
|
||||
<li>Mike Connor</li>
|
||||
<li>Chris Cooper</li>
|
||||
<li>Eric Cooper</li>
|
||||
<li>Paul Craciunoiu</li>
|
||||
<li>Brian Crowder</li>
|
||||
<li>John Daggett</li>
|
||||
<li>David Dahl</li>
|
||||
<li>Michael Davis</li>
|
||||
<li>Neil Deakin</li>
|
||||
<li>Julie Deroche</li>
|
||||
<li>Aakash Desai</li>
|
||||
<li>Ryan Doherty</li>
|
||||
<li>Justin Dolske</li>
|
||||
<li>Stephen Donner</li>
|
||||
<li>Asa Dotzler</li>
|
||||
<li>Chris Double</li>
|
||||
<li>Joe Drew</li>
|
||||
<li>Jason Duell</li>
|
||||
<li>Karsten Düsterloh</li>
|
||||
<li>Brendan Eich</li>
|
||||
<li>Daniel Einspanjer</li>
|
||||
<li>Kai Engert</li>
|
||||
<li>Steve England</li>
|
||||
<li>Madhava Enros</li>
|
||||
<li>Behdad Esfahbod</li>
|
||||
<li>Elika Etemad</li>
|
||||
<li>Anthony Evans</li>
|
||||
<li>Jason Evans</li>
|
||||
<li>Alex Faaborg</li>
|
||||
<li>Jane Finette</li>
|
||||
<li>Mark Finkle</li>
|
||||
<li>Darin Fisher</li>
|
||||
<li>Jayson Fittipaldi</li>
|
||||
<li>Justin Fitzhugh</li>
|
||||
<li>Ryan Flint</li>
|
||||
<li>Alix Franquet</li>
|
||||
<li>Eli Friedman</li>
|
||||
<li>Andreas Gal</li>
|
||||
<li>Steven Garrity</li>
|
||||
<li>Armen Zambrano Gasparnian</li>
|
||||
<li>Serge Gautherie</li>
|
||||
<li>Kevin Gerich</li>
|
||||
<li>Taras Glek</li>
|
||||
<li>Aravind Gottipati</li>
|
||||
<li>Dão Gottwald</li>
|
||||
<li>Zak Greant</li>
|
||||
<li>Matthew Gregan</li>
|
||||
<li>Will Guaraldi</li>
|
||||
<li>Adam Guthrie</li>
|
||||
<li>Mohammad Reza Haghighat</li>
|
||||
<li>Andrei Hajdukewycz</li>
|
||||
<li>Trevor Hardcastle</li>
|
||||
<li>Basil Hashem</li>
|
||||
<li>Ian Hayward</li>
|
||||
<li>Ben Hearsum</li>
|
||||
<li>Axel Hecht</li>
|
||||
<li>Frank Hecker</li>
|
||||
<li>Robert Helmer</li>
|
||||
<li>Stefan Hermes</li>
|
||||
<li>Jon Hicks</li>
|
||||
<li>Graydon Hoare</li>
|
||||
<li>Chris Hofmann</li>
|
||||
<li>Timothy Hogan</li>
|
||||
<li>Daniel Holbert</li>
|
||||
<li>Bobby Holley</li>
|
||||
<li>Mike Hommey</li>
|
||||
<li>Stephen Horlander</li>
|
||||
<li>Barbara Hueppe</li>
|
||||
<li>Anthony Hughes</li>
|
||||
<li>David Humphrey</li>
|
||||
<li>Takeshi Ichimaru</li>
|
||||
<li>Chris Ilias</li>
|
||||
<li>Eri Inoue</li>
|
||||
<li>Joichi Ito</li>
|
||||
<li>Steven Johnson</li>
|
||||
<li>Laurent Jouanneau</li>
|
||||
<li>Robert Kaiser</li>
|
||||
<li>Gen Kanai</li>
|
||||
<li>Masanori Kaneko</li>
|
||||
<li>Blake Kaplan</li>
|
||||
<li>Mike Kaplinskiy</li>
|
||||
<li>Michael Kaply</li>
|
||||
<li>Mitch Kapor</li>
|
||||
<li>Kazuyoshi Kato</li>
|
||||
<li>Tomomi Kato</li>
|
||||
<li>Alfred Kayser</li>
|
||||
<li>Jonathan Kew</li>
|
||||
<li>Paul Kim</li>
|
||||
<li>Masatoshi Kimura</li>
|
||||
<li>Austin King</li>
|
||||
<li>Ria Klaassen</li>
|
||||
<li>Marcia Knous</li>
|
||||
<li>Nelson Ko</li>
|
||||
<li>Michael Kohler</li>
|
||||
<li>Gary Kwong</li>
|
||||
<li>David Lanham</li>
|
||||
<li>Brad Lassey</li>
|
||||
<li>Delphine Lebédel</li>
|
||||
<li>Edward Lee</li>
|
||||
<li>Neil Lee</li>
|
||||
<li>Raymond Lee</li>
|
||||
<li>Garrett LeSage</li>
|
||||
<li>Aaron Leventhal</li>
|
||||
<li>Anne-Julie Ligneau</li>
|
||||
<li>John Lilly</li>
|
||||
<li>Zach Lipton</li>
|
||||
<li>Kai Liu</li>
|
||||
<li>Reed Loden</li>
|
||||
<li>Lars Lohn</li>
|
||||
<li>Robert Longson</li>
|
||||
<li>Bob Lord</li>
|
||||
<li>Phil Machalski</li>
|
||||
<li>Joel Maher</li>
|
||||
<li>Ere Maijala</li>
|
||||
<li>David Mandelin</li>
|
||||
<li>Gervase Markham</li>
|
||||
<li>Sean Martell</li>
|
||||
<li>Jim Mathies</li>
|
||||
<li>Blair McBride</li>
|
||||
<li>Erica McClure</li>
|
||||
<li>Graeme McCutcheon</li>
|
||||
<li>Patrick McManus</li>
|
||||
<li>Heather Meeker</li>
|
||||
<li>Walter Meinl</li>
|
||||
<li>Myk Melez</li>
|
||||
<li>Federico Mena-Quintero</li>
|
||||
<li>Mark Mentovai</li>
|
||||
<li>Laura Mesa</li>
|
||||
<li>Steven Michaud</li>
|
||||
<li>Matthew Middleton</li>
|
||||
<li>Ted Mielczarek</li>
|
||||
<li>Bernd Mielke</li>
|
||||
<li>Dave Miller</li>
|
||||
<li>Dan Mills</li>
|
||||
<li>Michael Monreal</li>
|
||||
<li>Simon Montagu</li>
|
||||
<li>Derek Moore</li>
|
||||
<li>Mike Morgan</li>
|
||||
<li>Tiffney Mortensen</li>
|
||||
<li>Dan Mosedale</li>
|
||||
<li>Michael Moy</li>
|
||||
<li>Jeff Muizelaar</li>
|
||||
<li>Masayuki Nakano</li>
|
||||
<li>Murali Nandigama</li>
|
||||
<li>Marria Nazif</li>
|
||||
<li>Kev Needham</li>
|
||||
<li>Kaori Negoro</li>
|
||||
<li>Nicholas Nethercote</li>
|
||||
<li>Ben Newman</li>
|
||||
<li>Nick Nguyen</li>
|
||||
<li>Johnathan Nightingale</li>
|
||||
<li>Timothy Nikkel</li>
|
||||
<li>Andreas Nilsson</li>
|
||||
<li>Tristan Nitot</li>
|
||||
<li>Alice Nodelman</li>
|
||||
<li>Matthew Noorenberghe</li>
|
||||
<li>Michal Novotny</li>
|
||||
<li>Robert O'Callahan</li>
|
||||
<li>John O'Duinn</li>
|
||||
<li>Paul O'Shannessy</li>
|
||||
<li>Jan Odvárko</li>
|
||||
<li>Tomoyuki Okazaki</li>
|
||||
<li>Les Orchard</li>
|
||||
<li>Jeremy Orem</li>
|
||||
<li>Jason Orendorff</li>
|
||||
<li>Hideo Oshima</li>
|
||||
<li>Mats Palmgren</li>
|
||||
<li>Stuart Parmenter</li>
|
||||
<li>Jay Patel</li>
|
||||
<li>Chris Pearce</li>
|
||||
<li>Javier Pedemonte</li>
|
||||
<li>Alfred Peng</li>
|
||||
<li>Christian Persch</li>
|
||||
<li>Kalle Persson</li>
|
||||
<li>Ulisse Perusin</li>
|
||||
<li>Olli Pettay</li>
|
||||
<li>Julien Pierre</li>
|
||||
<li>Anthony Piraino</li>
|
||||
<li>Alex Polvi</li>
|
||||
<li>Nickolay Ponomarev</li>
|
||||
<li>Dan Portillo</li>
|
||||
<li>Karen Prescott</li>
|
||||
<li>Florian Quèze</li>
|
||||
<li>Krupa Raj</li>
|
||||
<li>Arun Ranganathan</li>
|
||||
<li>Neil Rashbrook</li>
|
||||
<li>Bret Reckard</li>
|
||||
<li>J. Paul Reed</li>
|
||||
<li>Rick Reitmaier</li>
|
||||
<li>Robert Relyea</li>
|
||||
<li>John Resig</li>
|
||||
<li>Deb Richardson</li>
|
||||
<li>Tim Riley</li>
|
||||
<li>Phil Ringnalda</li>
|
||||
<li>Julien Rivaud</li>
|
||||
<li>Mikeal Rogers</li>
|
||||
<li>David Rolnitzky</li>
|
||||
<li>Asaf Romano</li>
|
||||
<li>Oleg Romashin</li>
|
||||
<li>Paul Rouget</li>
|
||||
<li>Tim Rowley</li>
|
||||
<li>Jesse Ruderman</li>
|
||||
<li>Brian Ryner</li>
|
||||
<li>Alexander Sack</li>
|
||||
<li>Hideo Saito</li>
|
||||
<li>Atsushi Sakai</li>
|
||||
<li>Eiko Sakuma</li>
|
||||
<li>Andrei Saprykin</li>
|
||||
<li>Aki Sasaki</li>
|
||||
<li>Ken Saunders</li>
|
||||
<li>Robert Sayre</li>
|
||||
<li>Mike Schroepfer</li>
|
||||
<li>Kurt Schultz</li>
|
||||
<li>Keith Schwarz</li>
|
||||
<li>Justin Scott</li>
|
||||
<li>Hiroshi Sekiya</li>
|
||||
<li>Tara Shahian</li>
|
||||
<li>Melissa Shapiro</li>
|
||||
<li>Gavin Sharp</li>
|
||||
<li>Mike Shaver</li>
|
||||
<li>Eric Shepherd</li>
|
||||
<li>Hiroshi Shimoda</li>
|
||||
<li>Atsushi Shimono</li>
|
||||
<li>Jungshik Shin</li>
|
||||
<li>Jonas Sicking</li>
|
||||
<li>Damon Sicore</li>
|
||||
<li>Roger B. Sidje</li>
|
||||
<li>Samuel Sidler</li>
|
||||
<li>Henrik Skupin</li>
|
||||
<li>John Slater</li>
|
||||
<li>Benjamin Smedberg</li>
|
||||
<li>Andrew Smith</li>
|
||||
<li>Edwin Smith</li>
|
||||
<li>Mark Smith</li>
|
||||
<li>Window Snyder</li>
|
||||
<li>Josh Soref</li>
|
||||
<li>Nochum Sossonko</li>
|
||||
<li>Ian Spence</li>
|
||||
<li>Seth Spitzer</li>
|
||||
<li>Markus Stange</li>
|
||||
<li>Jakub Steiner</li>
|
||||
<li>Johnny Stenback</li>
|
||||
<li>Brandon Sterne</li>
|
||||
<li>Rob Stradling</li>
|
||||
<li>Robert Strong</li>
|
||||
<li>Jay Sullivan</li>
|
||||
<li>Vicky Sun</li>
|
||||
<li>Alexander Surkov</li>
|
||||
<li>Mark Surman</li>
|
||||
<li>Andrew Sutherland</li>
|
||||
<li>Clint Talbert</li>
|
||||
<li>Margaret Tallman</li>
|
||||
<li>David Tenser</li>
|
||||
<li>Chris Thomas</li>
|
||||
<li>Nick Thomas</li>
|
||||
<li>Laura Thomson</li>
|
||||
<li>Karl Tomlinson</li>
|
||||
<li>Dave Townsend</li>
|
||||
<li>Aaron Train</li>
|
||||
<li>Phong Tran</li>
|
||||
<li>Ben Turner</li>
|
||||
<li>Doug Turner</li>
|
||||
<li>Amié Tyrrel</li>
|
||||
<li>Peter Van der Beken</li>
|
||||
<li>Peter van der Woude</li>
|
||||
<li>Teune van Steeg</li>
|
||||
<li>Ryan VanderMeulen</li>
|
||||
<li>Daniel Veditz</li>
|
||||
<li>Michael Ventnor</li>
|
||||
<li>Alexei Volkov</li>
|
||||
<li>Vladimir Vukićević</li>
|
||||
<li>Håkan Waara</li>
|
||||
<li>Jeff Walden</li>
|
||||
<li>Tracy Walker</li>
|
||||
<li>Cheng Wang</li>
|
||||
<li>Martijn Wargers</li>
|
||||
<li>Jonathan Watt</li>
|
||||
<li>Peter Weilbacher</li>
|
||||
<li>Zack Weinberg</li>
|
||||
<li>Frédéric Wenzel</li>
|
||||
<li>Steffen Wilberg</li>
|
||||
<li>Drew Willcoxon</li>
|
||||
<li>Shawn Wilsher</li>
|
||||
<li>Kathleen Wilson</li>
|
||||
<li>Dan Witte</li>
|
||||
<li>John Wolfe</li>
|
||||
<li>Steve Won</li>
|
||||
<li>Justin Wood</li>
|
||||
<li>Michael Wu</li>
|
||||
<li>Masahiro Yamada</li>
|
||||
<li>Satoko Takita Yamaguchi (Chibi)</li>
|
||||
<li>Christine Yen</li>
|
||||
<li>Kohei Yoshino</li>
|
||||
<li>Shigeru Yoshitake</li>
|
||||
<li>Tanner M. Young</li>
|
||||
<li>Boris Zbarsky</li>
|
||||
<li>Marco Zehe</li>
|
||||
<li>Matthew Zeier</li>
|
||||
</ul>
|
||||
|
||||
<div dir="&locale.dir;">
|
||||
&credit.translation;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- organizational supporters -->
|
||||
<div class="creditsGroup">
|
||||
<h3 dir="&locale.dir;">&credit.thanks;</h3>
|
||||
<ul>
|
||||
<li>Google</li>
|
||||
<li>Yahoo!</li>
|
||||
<li>IBM</li>
|
||||
<li>Sun Microsystems</li>
|
||||
<li>Red Hat</li>
|
||||
<li></li>
|
||||
<li>Oregon State University - Open Source Lab</li>
|
||||
<li></li>
|
||||
<li>Global Netoptex, Inc</li>
|
||||
<li>Internet Software Consortium</li>
|
||||
<li></li>
|
||||
<li>Cooley Godward, LLP</li>
|
||||
<li>Greenburg Traurig, LLP</li>
|
||||
<li></li>
|
||||
<li>OutCast Communications</li>
|
||||
<li></li>
|
||||
<li>The Royal Order of Experience Design</li>
|
||||
<li>Nobox</li>
|
||||
<li>silverorange</li>
|
||||
<li>Glaxstar</li>
|
||||
<li></li>
|
||||
<li>MozillaZine Community</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p id="gecko" class="center" dir="&locale.dir;">&credit.poweredByGeckoReg;</p>
|
||||
|
||||
<p class="footnote">
|
||||
Mozilla Firefox® and the Firefox logo are registered trademarks of the
|
||||
Mozilla Foundation. You are not granted rights or licenses to the trademarks
|
||||
of the Mozilla Foundation or any party, including without limitation the
|
||||
Firefox name or logo. Gecko® is a registered trademark of Netscape
|
||||
Communications Corporation.</p>
|
||||
|
||||
<p class="footnote">
|
||||
U.S. GOVERNMENT END USERS. The Software is a “commercial item,”
|
||||
as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of
|
||||
“commercial computer software” and “commercial computer software
|
||||
documentation,” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995).
|
||||
Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through
|
||||
227.7202-4 (June 1995), all U.S. Government End Users acquire the
|
||||
Software with only those rights set forth herein.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footerBox">
|
||||
<img src="chrome://branding/content/aboutFooter.png" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -105,7 +105,7 @@ let Change = {
|
|||
document.title = this._str("change.synckey.title");
|
||||
introText.innerHTML = this._str("change.synckey.introText");
|
||||
introText2.innerHTML = this._str("change.synckey.introText2");
|
||||
warningText.innerHTML = this._str("change.synckey.warningText");
|
||||
warningText.innerHTML = this._str("change.synckey2.warningText");
|
||||
this._dialog.getButton("accept")
|
||||
.setAttribute("label", this._str("change.synckey.acceptButton"));
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ let Change = {
|
|||
else {
|
||||
document.title = this._str("change.password.title");
|
||||
box2label.value = this._str("new.password.confirm");
|
||||
introText.textContent = this._str("change.password.introText");
|
||||
introText.textContent = this._str("change.password2.introText");
|
||||
warningText.textContent = this._str("change.password.warningText");
|
||||
this._dialog.getButton("accept")
|
||||
.setAttribute("label", this._str("change.password.acceptButton"));
|
||||
|
@ -181,7 +181,7 @@ let Change = {
|
|||
if (this._updatingPassphrase) {
|
||||
Weave.Service.passphrase = pp;
|
||||
if (Weave.Service.login()) {
|
||||
this._updateStatus("change.synckey.success", "success");
|
||||
this._updateStatus("change.synckey2.success", "success");
|
||||
Weave.Service.persistLogin();
|
||||
}
|
||||
else {
|
||||
|
@ -192,9 +192,9 @@ let Change = {
|
|||
this._updateStatus("change.synckey.label", "active");
|
||||
|
||||
if (Weave.Service.changePassphrase(pp))
|
||||
this._updateStatus("change.synckey.success", "success");
|
||||
this._updateStatus("change.synckey2.success", "success");
|
||||
else
|
||||
this._updateStatus("change.synckey.error", "error");
|
||||
this._updateStatus("change.synckey2.error", "error");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -40,23 +40,44 @@
|
|||
<!DOCTYPE html [
|
||||
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
|
||||
%htmlDTD;
|
||||
<!ENTITY % syncSetupDTD SYSTEM "chrome://browser/locale/syncSetup.dtd">
|
||||
%syncSetupDTD;
|
||||
<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
|
||||
%syncBrandDTD;
|
||||
<!ENTITY % syncKeyDTD SYSTEM "chrome://browser/locale/syncKey.dtd">
|
||||
%syncKeyDTD;
|
||||
]>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>&page.syncKeyBackup.title;</title>
|
||||
<title>&syncKey.page.title;</title>
|
||||
<style type="text/css">
|
||||
#synckey { font-size: 150% }
|
||||
footer { font-size: 70% }
|
||||
# Bug 575675: Need to have an a:visited rule in a chrome document.
|
||||
a:visited { color: purple; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>&page.syncKeyBackup.title;</h1>
|
||||
<h1>&syncKey.page.title;</h1>
|
||||
|
||||
<p id="synckey">SYNCKEY</p>
|
||||
|
||||
<p>&page.syncKeyBackup.descr;</p>
|
||||
<p>&syncKey.page.description;</p>
|
||||
|
||||
<div id="column1">
|
||||
<h2>&syncKey.keepItSecret.heading;</h2>
|
||||
<p>&syncKey.keepItSecret.description;</p>
|
||||
</div>
|
||||
|
||||
<div id="column2">
|
||||
<h2>&syncKey.keepItSafe.heading;</h2>
|
||||
<p><em>&syncKey.keepItSafe1.description;</em>&syncKey.keepItSafe2.description;<em>&syncKey.keepItSafe3.description;</em>&syncKey.keepItSafe4.description;</p>
|
||||
</div>
|
||||
|
||||
<p>&syncKey.findOutMore1.label;<a href="https://services.mozilla.com">https://services.mozilla.com</a>&syncKey.findOutMore2.label;</p>
|
||||
|
||||
<footer>
|
||||
&syncKey.footer1.label;<a id="tosLink" href="termsURL">termsURL</a>&syncKey.footer2.label;<a id="ppLink" href="privacyURL">privacyURL</a>&syncKey.footer3.label;
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
/* ***** 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 Firefox Sync.
|
||||
*
|
||||
* 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):
|
||||
* Philipp von Weitershausen <philipp@weitershausen.de>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://services-sync/main.js");
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
|
||||
let gSyncQuota = {
|
||||
|
||||
init: function init() {
|
||||
this.bundle = document.getElementById("quotaStrings");
|
||||
let caption = document.getElementById("treeCaption");
|
||||
caption.firstChild.nodeValue = this.bundle.getString("quota.treeCaption.label");
|
||||
|
||||
gUsageTreeView.init();
|
||||
this.tree = document.getElementById("usageTree");
|
||||
this.tree.view = gUsageTreeView;
|
||||
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
loadData: function loadData() {
|
||||
window.setTimeout(function() {
|
||||
let usage = Weave.Service.getCollectionUsage();
|
||||
gUsageTreeView.displayUsageData(usage);
|
||||
}, 0);
|
||||
|
||||
let usageLabel = document.getElementById("usageLabel");
|
||||
let bundle = this.bundle;
|
||||
window.setTimeout(function() {
|
||||
let quota = Weave.Service.getQuota();
|
||||
if (!quota) {
|
||||
usageLabel.value = bundle.getString("quota.usageError.label");
|
||||
return;
|
||||
}
|
||||
let used = gSyncQuota.convertKB(quota[0]);
|
||||
if (!quota[1]) {
|
||||
// No quota on the server.
|
||||
usageLabel.value = bundle.getFormattedString(
|
||||
"quota.usageNoQuota.label", used);
|
||||
return;
|
||||
}
|
||||
let percent = Math.round(100 * quota[0] / quota[1]);
|
||||
let total = gSyncQuota.convertKB(quota[1]);
|
||||
usageLabel.value = bundle.getFormattedString(
|
||||
"quota.usagePercentage.label", [percent].concat(used).concat(total));
|
||||
}, 0);
|
||||
},
|
||||
|
||||
onAccept: function onAccept() {
|
||||
let engines = gUsageTreeView.getEnginesToDisable();
|
||||
for each (let engine in engines) {
|
||||
Weave.Engines.get(engine).enabled = false;
|
||||
}
|
||||
if (engines.length) {
|
||||
// The 'Weave' object will disappear once the window closes.
|
||||
let Service = Weave.Service;
|
||||
Weave.Utils.delay(function() Service.sync(), 0);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
convertKB: function convertKB(value) {
|
||||
return DownloadUtils.convertByteUnits(value * 1024);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let gUsageTreeView = {
|
||||
|
||||
_ignored: {keys: true,
|
||||
meta: true,
|
||||
clients: true},
|
||||
|
||||
/*
|
||||
* Internal data structures underlaying the tree.
|
||||
*/
|
||||
_collections: [],
|
||||
_byname: {},
|
||||
|
||||
init: function init() {
|
||||
let retrievingLabel = gSyncQuota.bundle.getString("quota.retrieving.label");
|
||||
for each (let engine in Weave.Engines.getEnabled()) {
|
||||
if (this._ignored[engine.name])
|
||||
continue;
|
||||
|
||||
// Some engines use the same pref, which means they can only be turned on
|
||||
// and off together. We need to combine them here as well.
|
||||
let existing = this._byname[engine.prefName];
|
||||
if (existing) {
|
||||
existing.engines.push(engine.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
let obj = {name: engine.prefName,
|
||||
title: this._collectionTitle(engine),
|
||||
engines: [engine.name],
|
||||
enabled: true,
|
||||
sizeLabel: retrievingLabel};
|
||||
this._collections.push(obj);
|
||||
this._byname[engine.prefName] = obj;
|
||||
}
|
||||
},
|
||||
|
||||
_collectionTitle: function _collectionTitle(engine) {
|
||||
try {
|
||||
return gSyncQuota.bundle.getString(
|
||||
"collection." + engine.prefName + ".label");
|
||||
} catch (ex) {
|
||||
return engine.Name;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Process the quota information as returned by info/collection_usage.
|
||||
*/
|
||||
displayUsageData: function displayUsageData(data) {
|
||||
data = data || {};
|
||||
for each (let coll in this._collections) {
|
||||
coll.size = 0;
|
||||
for each (let engineName in coll.engines)
|
||||
coll.size += data[engineName] || 0;
|
||||
let sizeLabel = "";
|
||||
if (coll.size)
|
||||
sizeLabel = gSyncQuota.bundle.getFormattedString(
|
||||
"quota.sizeValueUnit.label", gSyncQuota.convertKB(coll.size));
|
||||
coll.sizeLabel = sizeLabel;
|
||||
}
|
||||
let sizeColumn = this.treeBox.columns.getNamedColumn("size");
|
||||
this.treeBox.invalidateColumn(sizeColumn);
|
||||
},
|
||||
|
||||
/*
|
||||
* Handle click events on the tree.
|
||||
*/
|
||||
onTreeClick: function onTreeClick(event) {
|
||||
if (event.button == 2)
|
||||
return;
|
||||
|
||||
let row = {}, col = {};
|
||||
this.treeBox.getCellAt(event.clientX, event.clientY, row, col, {});
|
||||
if (col.value && col.value.id == "enabled")
|
||||
this.toggle(row.value);
|
||||
},
|
||||
|
||||
/*
|
||||
* Toggle enabled state of an engine.
|
||||
*/
|
||||
toggle: function toggle(row) {
|
||||
// Update the tree
|
||||
let collection = this._collections[row];
|
||||
collection.enabled = !collection.enabled;
|
||||
this.treeBox.invalidateRow(row);
|
||||
|
||||
// Display which ones will be removed
|
||||
let freeup = 0;
|
||||
let toremove = [];
|
||||
for each (collection in this._collections) {
|
||||
if (collection.enabled)
|
||||
continue;
|
||||
toremove.push(collection.name);
|
||||
freeup += collection.size;
|
||||
}
|
||||
|
||||
let caption = document.getElementById("treeCaption");
|
||||
if (!toremove.length) {
|
||||
caption.className = "";
|
||||
caption.firstChild.nodeValue = gSyncQuota.bundle.getString(
|
||||
"quota.treeCaption.label");
|
||||
return;
|
||||
}
|
||||
|
||||
toremove = [this._byname[coll].title for each (coll in toremove)];
|
||||
toremove = toremove.join(gSyncQuota.bundle.getString("quota.list.separator"));
|
||||
caption.firstChild.nodeValue = gSyncQuota.bundle.getFormattedString(
|
||||
"quota.removal.label", [toremove]);
|
||||
if (freeup)
|
||||
caption.firstChild.nodeValue += gSyncQuota.bundle.getFormattedString(
|
||||
"quota.freeup.label", gSyncQuota.convertKB(freeup));
|
||||
caption.className = "captionWarning";
|
||||
},
|
||||
|
||||
/*
|
||||
* Return a list of engines (or rather their pref names) that should be
|
||||
* disabled.
|
||||
*/
|
||||
getEnginesToDisable: function getEnginesToDisable() {
|
||||
return [coll.name for each (coll in this._collections) if (!coll.enabled)];
|
||||
},
|
||||
|
||||
// nsITreeView
|
||||
|
||||
get rowCount() {
|
||||
return this._collections.length;
|
||||
},
|
||||
|
||||
getRowProperties: function(index, properties) {},
|
||||
getCellProperties: function(row, col, properties) {},
|
||||
getColumnProperties: function(col, properties) {},
|
||||
isContainer: function(index) { return false; },
|
||||
isContainerOpen: function(index) { return false; },
|
||||
isContainerEmpty: function(index) { return false; },
|
||||
isSeparator: function(index) { return false; },
|
||||
isSorted: function() { return false; },
|
||||
canDrop: function(index, orientation, dataTransfer) { return false; },
|
||||
drop: function(row, orientation, dataTransfer) {},
|
||||
getParentIndex: function(rowIndex) {},
|
||||
hasNextSibling: function(rowIndex, afterIndex) { return false; },
|
||||
getLevel: function(index) { return 0; },
|
||||
getImageSrc: function(row, col) {},
|
||||
|
||||
getCellValue: function(row, col) {
|
||||
return this._collections[row].enabled;
|
||||
},
|
||||
|
||||
getCellText: function getCellText(row, col) {
|
||||
let collection = this._collections[row];
|
||||
switch (col.id) {
|
||||
case "collection":
|
||||
return collection.title;
|
||||
case "size":
|
||||
return collection.sizeLabel;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
setTree: function setTree(tree) {
|
||||
this.treeBox = tree;
|
||||
},
|
||||
|
||||
toggleOpenState: function(index) {},
|
||||
cycleHeader: function(col) {},
|
||||
selectionChanged: function() {},
|
||||
cycleCell: function(row, col) {},
|
||||
isEditable: function(row, col) { return false; },
|
||||
isSelectable: function (row, col) { return false; },
|
||||
setCellValue: function(row, col, value) {},
|
||||
setCellText: function(row, col, value) {},
|
||||
performAction: function(action) {},
|
||||
performActionOnRow: function(action, row) {},
|
||||
performActionOnCell: function(action, row, col) {}
|
||||
|
||||
};
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
# ***** 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 Firefox Sync.
|
||||
#
|
||||
# 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):
|
||||
# Philipp von Weitershausen <philipp@weitershausen.de>
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/syncQuota.css"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
|
||||
<!ENTITY % syncQuotaDTD SYSTEM "chrome://browser/locale/syncQuota.dtd">
|
||||
%brandDTD;
|
||||
%syncBrandDTD;
|
||||
%syncQuotaDTD;
|
||||
]>
|
||||
<dialog id="quotaDialog"
|
||||
windowtype="Sync:ViewQuota"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
onload="gSyncQuota.init()"
|
||||
buttons="accept,cancel"
|
||||
title=""a.dialogTitle.label;"
|
||||
ondialogcancel="return true;"
|
||||
ondialogaccept="return gSyncQuota.onAccept();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/syncQuota.js"/>
|
||||
|
||||
<stringbundleset id="stringbundleset">
|
||||
<stringbundle id="quotaStrings"
|
||||
src="chrome://browser/locale/syncQuota.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<vbox flex="1">
|
||||
<label id="usageLabel"
|
||||
value=""a.retrievingInfo.label;"/>
|
||||
<separator/>
|
||||
<tree id="usageTree"
|
||||
seltype="single"
|
||||
hidecolumnpicker="true"
|
||||
onclick="gUsageTreeView.onTreeClick(event);"
|
||||
flex="1">
|
||||
<treecols>
|
||||
<treecol id="enabled"
|
||||
type="checkbox"
|
||||
fixed="true"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="collection"
|
||||
label="Type"
|
||||
flex="1"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="size"
|
||||
label="Size"
|
||||
flex="1"/>
|
||||
</treecols>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
<separator/>
|
||||
<description id="treeCaption"> </description>
|
||||
</vbox>
|
||||
|
||||
</dialog>
|
|
@ -71,7 +71,6 @@ var gSyncSetup = {
|
|||
_remoteSites: [Weave.Service.serverURL, "https://api-secure.recaptcha.net"],
|
||||
|
||||
status: {
|
||||
username: false,
|
||||
password: false,
|
||||
email: false,
|
||||
server: false
|
||||
|
@ -221,7 +220,7 @@ var gSyncSetup = {
|
|||
case NEW_ACCOUNT_PP_PAGE:
|
||||
return this._haveSyncKeyBackup && this.checkPassphrase();
|
||||
case EXISTING_ACCOUNT_LOGIN_PAGE:
|
||||
let hasUser = document.getElementById("existingUsername").value != "";
|
||||
let hasUser = document.getElementById("existingAccountName").value != "";
|
||||
let hasPass = document.getElementById("existingPassword").value != "";
|
||||
if (hasUser && hasPass) {
|
||||
if (this._usingMainServers)
|
||||
|
@ -238,29 +237,42 @@ var gSyncSetup = {
|
|||
return true;
|
||||
},
|
||||
|
||||
onUsernameChange: function () {
|
||||
let feedback = document.getElementById("usernameFeedbackRow");
|
||||
let val = document.getElementById("weaveUsername").value;
|
||||
let availCheck = "", str = "";
|
||||
let available = true;
|
||||
if (val) {
|
||||
availCheck = Weave.Service.checkUsername(val);
|
||||
available = availCheck == "available";
|
||||
onEmailChange: function () {
|
||||
let value = document.getElementById("weaveEmail").value;
|
||||
if (!value) {
|
||||
this.status.email = false;
|
||||
this.checkFields();
|
||||
return;
|
||||
}
|
||||
// Do this async to avoid blocking the widget while we go to the server.
|
||||
window.setTimeout(function() {
|
||||
gSyncSetup.checkAccount(value);
|
||||
}, 0);
|
||||
},
|
||||
|
||||
checkAccount: function(value) {
|
||||
let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
let feedback = document.getElementById("emailFeedbackRow");
|
||||
let valid = re.test(value);
|
||||
|
||||
let str = "";
|
||||
if (!valid) {
|
||||
str = "invalidEmail.label";
|
||||
} else {
|
||||
let availCheck = Weave.Service.checkAccount(value);
|
||||
valid = availCheck == "available";
|
||||
if (!valid) {
|
||||
if (availCheck == "notAvailable")
|
||||
str = "usernameNotAvailable.label";
|
||||
else
|
||||
str = availCheck;
|
||||
}
|
||||
}
|
||||
|
||||
if (!available) {
|
||||
if (availCheck == "notAvailable")
|
||||
str = "usernameNotAvailable.label";
|
||||
else
|
||||
str = availCheck;
|
||||
}
|
||||
|
||||
this._setFeedbackMessage(feedback, available, str);
|
||||
|
||||
this.status.username = val && available;
|
||||
if (available)
|
||||
Weave.Service.username = val;
|
||||
|
||||
this._setFeedbackMessage(feedback, valid, str);
|
||||
this.status.email = valid;
|
||||
if (valid)
|
||||
Weave.Service.account = value;
|
||||
this.checkFields();
|
||||
},
|
||||
|
||||
|
@ -284,22 +296,19 @@ var gSyncSetup = {
|
|||
this.checkFields();
|
||||
},
|
||||
|
||||
onEmailChange: function () {
|
||||
//XXXzpao Not sure about this regex. Look into it in followup (bug 583650)
|
||||
let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
this.status.email = re.test(document.getElementById("weaveEmail").value);
|
||||
|
||||
this._setFeedbackMessage(document.getElementById("emailFeedbackRow"),
|
||||
this.status.email,
|
||||
"invalidEmail.label");
|
||||
|
||||
this.checkFields();
|
||||
},
|
||||
|
||||
onPassphraseChange: function () {
|
||||
// Ignore if there's no actual change from the generated one.
|
||||
let el = document.getElementById("weavePassphrase");
|
||||
if (gSyncUtils.normalizePassphrase(el.value) == Weave.Service.passphrase) {
|
||||
el = document.getElementById("generatePassphraseButton");
|
||||
el.hidden = true;
|
||||
this._haveCustomSyncKey = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this._haveSyncKeyBackup = true;
|
||||
this._haveCustomSyncKey = true;
|
||||
let el = document.getElementById("generatePassphraseButton");
|
||||
el = document.getElementById("generatePassphraseButton");
|
||||
el.hidden = false;
|
||||
this.checkFields();
|
||||
},
|
||||
|
@ -420,17 +429,16 @@ var gSyncSetup = {
|
|||
label.value = this._stringBundle.GetStringFromName("verifying.label");
|
||||
feedback.hidden = false;
|
||||
|
||||
let username = document.getElementById("weaveUsername").value;
|
||||
let password = document.getElementById("weavePassword").value;
|
||||
let email = document.getElementById("weaveEmail").value;
|
||||
let challenge = getField("challenge");
|
||||
let response = getField("response");
|
||||
|
||||
let error = Weave.Service.createAccount(username, password, email,
|
||||
let error = Weave.Service.createAccount(email, password,
|
||||
challenge, response);
|
||||
|
||||
if (error == null) {
|
||||
Weave.Service.username = username;
|
||||
Weave.Service.account = email;
|
||||
Weave.Service.password = password;
|
||||
this._handleNoScript(false);
|
||||
this.wizard.pageIndex = SETUP_SUCCESS_PAGE;
|
||||
|
@ -449,7 +457,7 @@ var gSyncSetup = {
|
|||
this.captchaBrowser.loadURI(Weave.Service.miscAPI + "captcha_html");
|
||||
break;
|
||||
case EXISTING_ACCOUNT_LOGIN_PAGE:
|
||||
Weave.Service.username = document.getElementById("existingUsername").value;
|
||||
Weave.Service.account = document.getElementById("existingAccountName").value;
|
||||
Weave.Service.password = document.getElementById("existingPassword").value;
|
||||
Weave.Service.passphrase = document.getElementById("existingPassphrase").value;
|
||||
// verifyLogin() will likely return false because we probably don't
|
||||
|
@ -622,9 +630,9 @@ var gSyncSetup = {
|
|||
this._setFeedbackMessage(feedback, true);
|
||||
}
|
||||
|
||||
// recheck username against the new server
|
||||
// Recheck account against the new server.
|
||||
if (valid)
|
||||
this.onUsernameChange();
|
||||
this.onEmailChange();
|
||||
|
||||
this.status.server = valid;
|
||||
this.checkFields();
|
||||
|
@ -646,7 +654,7 @@ var gSyncSetup = {
|
|||
if (uri && checkRemote) {
|
||||
function isValid(uri) {
|
||||
Weave.Service.serverURL = uri.spec;
|
||||
let check = Weave.Service.checkUsername("a");
|
||||
let check = Weave.Service.checkAccount("a");
|
||||
return (check == "available" || check == "notAvailable");
|
||||
}
|
||||
|
||||
|
@ -721,7 +729,7 @@ var gSyncSetup = {
|
|||
document.getElementById("historyCount").value =
|
||||
PluralForm.get(daysOfHistory,
|
||||
this._stringBundle.GetStringFromName("historyDaysCount.label"))
|
||||
.replace("#1", daysOfHistory);
|
||||
.replace("%S", daysOfHistory);
|
||||
|
||||
// bookmarks
|
||||
let bookmarks = 0;
|
||||
|
@ -736,14 +744,14 @@ var gSyncSetup = {
|
|||
document.getElementById("bookmarkCount").value =
|
||||
PluralForm.get(bookmarks,
|
||||
this._stringBundle.GetStringFromName("bookmarksCount.label"))
|
||||
.replace("#1", bookmarks);
|
||||
.replace("%S", bookmarks);
|
||||
|
||||
// passwords
|
||||
let logins = Weave.Svc.Login.getAllLogins({});
|
||||
document.getElementById("passwordCount").value =
|
||||
PluralForm.get(logins.length,
|
||||
this._stringBundle.GetStringFromName("passwordsCount.label"))
|
||||
.replace("#1", logins.length);
|
||||
.replace("%S", logins.length);
|
||||
this._case1Setup = true;
|
||||
break;
|
||||
case 2:
|
||||
|
@ -771,7 +779,7 @@ var gSyncSetup = {
|
|||
let label =
|
||||
PluralForm.get(count - 5,
|
||||
this._stringBundle.GetStringFromName("additionalClientCount.label"))
|
||||
.replace("#1", count - 5);
|
||||
.replace("%S", count - 5);
|
||||
appendNode(label);
|
||||
}
|
||||
this._case2Setup = true;
|
||||
|
|
|
@ -107,16 +107,14 @@
|
|||
<column class="inputColumn" flex="1"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row id="usernameRow" align="center">
|
||||
<label value="&signIn.username.label;"
|
||||
accesskey="&signIn.username.accesskey;"
|
||||
control="weaveUsername"/>
|
||||
<textbox id="weaveUsername"
|
||||
onchange="gSyncSetup.onUsernameChange()"/>
|
||||
<row id="emailRow" align="center">
|
||||
<label value="&setup.emailAddress.label;"
|
||||
accesskey="&setup.emailAddress.accesskey;"
|
||||
control="weaveEmail"/>
|
||||
<textbox id="weaveEmail"
|
||||
onchange="gSyncSetup.onEmailChange()"/>
|
||||
</row>
|
||||
<row id="usernameFeedbackRow"
|
||||
align="center"
|
||||
hidden="true">
|
||||
<row id="emailFeedbackRow" align="center" hidden="true">
|
||||
<spacer/>
|
||||
<hbox>
|
||||
<image class="statusIcon"/>
|
||||
|
@ -146,20 +144,6 @@
|
|||
<label class="status" value=" "/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row id="emailRow" align="center">
|
||||
<label value="&setup.emailAddress.label;"
|
||||
accesskey="&setup.emailAddress.accesskey;"
|
||||
control="weaveEmail"/>
|
||||
<textbox id="weaveEmail"
|
||||
onchange="gSyncSetup.onEmailChange()"/>
|
||||
</row>
|
||||
<row id="emailFeedbackRow" align="center" hidden="true">
|
||||
<spacer/>
|
||||
<hbox>
|
||||
<image class="statusIcon"/>
|
||||
<label class="status" value=" "/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row align="center">
|
||||
<label control="serverType"
|
||||
value="&server.label;"/>
|
||||
|
@ -308,16 +292,16 @@
|
|||
<textbox id="existingServerURL"
|
||||
onchange="gSyncSetup.checkFields(event)"/>
|
||||
</row>
|
||||
<row id="existingUsernameRow" align="center">
|
||||
<label id="existingUsernameLabel"
|
||||
value="&signIn.username.label;"
|
||||
accesskey="&signIn.username.accesskey;"
|
||||
control="existingUsername"/>
|
||||
<textbox id="existingUsername"
|
||||
<row id="existingAccountRow" align="center">
|
||||
<label id="existingAccountLabel"
|
||||
value="&signIn.account.label;"
|
||||
accesskey="&signIn.account.accesskey;"
|
||||
control="existingAccount"/>
|
||||
<textbox id="existingAccountName"
|
||||
oninput="gSyncSetup.checkFields(event)"
|
||||
onchange="gSyncSetup.checkFields(event)"/>
|
||||
</row>
|
||||
<row id="existingUsernameFeedbackRow" align="center" hidden="true">
|
||||
<row id="existingAccountFeedbackRow" align="center" hidden="true">
|
||||
<spacer/>
|
||||
<hbox>
|
||||
<image class="statusIcon"/>
|
||||
|
|
|
@ -153,9 +153,19 @@ let gSyncUtils = {
|
|||
*/
|
||||
passphraseEmail: function(elid) {
|
||||
let pp = document.getElementById(elid).value;
|
||||
let subject = this.bundle.GetStringFromName("email.synckey.subject");
|
||||
let body = this.bundle.formatStringFromName("email.synckey.body", [pp], 1);
|
||||
let uri = Weave.Utils.makeURI("mailto:?subject=" + subject + "&body=" + body);
|
||||
let subject = this.bundle.GetStringFromName("email.syncKey.subject");
|
||||
let label = this.bundle.formatStringFromName("email.syncKey.label", [pp], 1);
|
||||
let body = "&body=" + label + "%0A%0A" +
|
||||
this.bundle.GetStringFromName("email.syncKey.description")
|
||||
+ "%0A%0A" +
|
||||
this.bundle.GetStringFromName("email.keepItSecret.label") +
|
||||
this.bundle.GetStringFromName("email.keepItSecret.description")
|
||||
+ "%0A%0A" +
|
||||
this.bundle.GetStringFromName("email.keepItSafe.label") +
|
||||
this.bundle.GetStringFromName("email.keepItSafe.description")
|
||||
+ "%0A%0A" +
|
||||
this.bundle.GetStringFromName("email.findOutMore.label");
|
||||
let uri = Weave.Utils.makeURI("mailto:?subject=" + subject + body);
|
||||
let protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]
|
||||
.getService(Ci.nsIExternalProtocolService);
|
||||
protoSvc.loadURI(uri);
|
||||
|
@ -183,6 +193,17 @@ let gSyncUtils = {
|
|||
let el = iframe.contentDocument.getElementById("synckey");
|
||||
el.firstChild.nodeValue = pp;
|
||||
|
||||
// Insert the TOS and Privacy Policy URLs into the page.
|
||||
let termsURL = Weave.Svc.Prefs.get("termsURL");
|
||||
el = iframe.contentDocument.getElementById("tosLink");
|
||||
el.setAttribute("href", termsURL);
|
||||
el.firstChild.nodeValue = termsURL;
|
||||
|
||||
let privacyURL = Weave.Svc.Prefs.get("privacyURL");
|
||||
el = iframe.contentDocument.getElementById("ppLink");
|
||||
el.setAttribute("href", privacyURL);
|
||||
el.firstChild.nodeValue = privacyURL;
|
||||
|
||||
callback(iframe);
|
||||
}, false);
|
||||
},
|
||||
|
@ -237,6 +258,9 @@ let gSyncUtils = {
|
|||
|
||||
let serializer = new XMLSerializer();
|
||||
let output = serializer.serializeToString(iframe.contentDocument);
|
||||
output = output.replace(/<!DOCTYPE (.|\n)*?]>/,
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
|
||||
'"DTD/xhtml1-strict.dtd">');
|
||||
output = Weave.Utils.encodeUTF8(output);
|
||||
stream.write(output, output.length);
|
||||
}
|
||||
|
@ -262,6 +286,8 @@ let gSyncUtils = {
|
|||
valid = val1.length >= Weave.MIN_PASS_LENGTH;
|
||||
else if (val1 && val1 == Weave.Service.username)
|
||||
error = "change.password.pwSameAsUsername";
|
||||
else if (val1 && val1 == Weave.Service.account)
|
||||
error = "change.password.pwSameAsEmail";
|
||||
else if (val1 && val1 == Weave.Service.password)
|
||||
error = "change.password.pwSameAsPassword";
|
||||
else if (val1 && val1 == Weave.Service.passphrase)
|
||||
|
@ -293,6 +319,8 @@ let gSyncUtils = {
|
|||
|
||||
if (val == Weave.Service.username)
|
||||
error = "change.synckey.sameAsUsername";
|
||||
else if (val == Weave.Service.account)
|
||||
error = "change.synckey.sameAsEmail";
|
||||
else if (val == Weave.Service.password)
|
||||
error = "change.synckey.sameAsPassword";
|
||||
else if (change && val == Weave.Service.passphrase)
|
||||
|
|
|
@ -11,11 +11,25 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.tabbrowser-tabs:not([closebuttons="noclose"]):not([closebuttons="closeatend"]) > .tabbrowser-tab[selected="true"]:not([pinned]) > .tab-close-button,
|
||||
.tabbrowser-tabs[closebuttons="alltabs"] > .tabbrowser-tab:not([pinned]) > .tab-close-button {
|
||||
.tabbrowser-tabs:not([closebuttons="noclose"]):not([closebuttons="closeatend"]) > * > * > * .tab-close-button:not([pinned])[selected="true"],
|
||||
.tabbrowser-tabs[closebuttons="alltabs"] > * > * > * > .tab-close-button:not([pinned]) {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.tab-close-button[selected="true"] {
|
||||
/* Make this button focusable so clicking on it will not focus the tab while
|
||||
it's getting closed */
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
.tab-label[pinned] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-stack {
|
||||
vertical-align: middle; /* for pinned tabs */
|
||||
}
|
||||
|
||||
tabpanels {
|
||||
background-color: white;
|
||||
}
|
||||
|
@ -24,3 +38,20 @@ tabpanels {
|
|||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* tab progress */
|
||||
|
||||
.tab-progress {
|
||||
-moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter") !important;
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.tab-progress[selected],
|
||||
.tab-progress:not([busy]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-progress-container {
|
||||
-moz-box-pack: start;
|
||||
}
|
||||
|
|
|
@ -372,13 +372,8 @@
|
|||
return;
|
||||
|
||||
if (this.mTotalProgress) {
|
||||
const STATES = 8;
|
||||
let state = Math.ceil(STATES * this.mTotalProgress);
|
||||
if (state != this.mTab.getAttribute("progress")) {
|
||||
this.mTab.setAttribute("progress", state);
|
||||
this.mTab.removeAttribute("stalled");
|
||||
this._startStalledTimer();
|
||||
}
|
||||
let value = Math.ceil(this.mTotalProgress * 100);
|
||||
this.mTab.setAttribute("progresspercent", value);
|
||||
}
|
||||
|
||||
this._callProgressListeners("onProgressChange",
|
||||
|
@ -435,6 +430,7 @@
|
|||
if (!this.mBlank) {
|
||||
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
|
||||
this.mTab.setAttribute("busy", "true");
|
||||
this.mTab.setAttribute("progresspercent", "0");
|
||||
this._startStalledTimer();
|
||||
this.mTabBrowser.updateIcon(this.mTab);
|
||||
this.mTabBrowser.setTabTitleLoading(this.mTab);
|
||||
|
@ -462,7 +458,7 @@
|
|||
this.mBlank = false;
|
||||
|
||||
this.mTab.removeAttribute("busy");
|
||||
this.mTab.removeAttribute("progress");
|
||||
this.mTab.removeAttribute("progresspercent");
|
||||
this.mTab.removeAttribute("stalled");
|
||||
this._cancelStalledTimer();
|
||||
this.mTabBrowser.updateIcon(this.mTab);
|
||||
|
@ -733,6 +729,12 @@
|
|||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (window.TabView) {
|
||||
let groupName = TabView.getActiveGroupName();
|
||||
if (groupName)
|
||||
newTitle = groupName + sep + newTitle;
|
||||
}
|
||||
|
||||
return newTitle;
|
||||
]]>
|
||||
</body>
|
||||
|
@ -745,7 +747,8 @@
|
|||
// ToDo: this will be removed when we gain ability to draw to the menu bar.
|
||||
// Bug 586175
|
||||
this.ownerDocument.title = TabView.windowTitle;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
this.ownerDocument.title = this.getWindowTitleForBrowser(this.mCurrentBrowser);
|
||||
}
|
||||
]]>
|
||||
|
@ -3322,17 +3325,26 @@
|
|||
</resources>
|
||||
|
||||
<content context="tabContextMenu" closetabtext="&closeTab.label;">
|
||||
<xul:image xbl:inherits="validate,src=image"
|
||||
class="tab-icon-image"
|
||||
role="presentation"/>
|
||||
<xul:label flex="1"
|
||||
xbl:inherits="value=label,crop,accesskey"
|
||||
class="tab-text"
|
||||
role="presentation"/>
|
||||
<xul:toolbarbutton anonid="close-button"
|
||||
tabindex="-1"
|
||||
clickthrough="never"
|
||||
class="tab-close-button"/>
|
||||
<xul:stack class="tab-stack" flex="1">
|
||||
<xul:vbox class="tab-progress-container">
|
||||
<xul:progressmeter class="tab-progress" mode="normal"
|
||||
xbl:inherits="value=progresspercent,busy,stalled,fadein,selected"/>
|
||||
</xul:vbox>
|
||||
<xul:hbox class="tab-content" align="center">
|
||||
<xul:image xbl:inherits="validate,src=image,fadein,pinned,busy,stalled,selected"
|
||||
class="tab-icon-image"
|
||||
role="presentation"/>
|
||||
<xul:label flex="1"
|
||||
xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected"
|
||||
class="tab-text tab-label"
|
||||
role="presentation"/>
|
||||
<xul:toolbarbutton anonid="close-button"
|
||||
xbl:inherits="fadein,pinned,selected"
|
||||
tabindex="-1"
|
||||
clickthrough="never"
|
||||
class="tab-close-button"/>
|
||||
</xul:hbox>
|
||||
</xul:stack>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
|
|
|
@ -790,7 +790,14 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
if (typeof item.setResizable == 'function')
|
||||
item.setResizable(false);
|
||||
|
||||
if (item.tab == gBrowser.selectedTab)
|
||||
// if it is visually active, set it as the active tab.
|
||||
if (iQ(item.container).hasClass("focus"))
|
||||
this.setActiveTab(item);
|
||||
|
||||
// if it matches the selected tab or no active tab and the browser
|
||||
// tab is hidden, the active group item would be set.
|
||||
if (item.tab == gBrowser.selectedTab ||
|
||||
(!GroupItems.getActiveGroupItem() && !item.tab.hidden))
|
||||
GroupItems.setActiveGroupItem(this);
|
||||
}
|
||||
|
||||
|
@ -835,7 +842,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
this._children.splice(index, 1);
|
||||
|
||||
if (item == this._activeTab) {
|
||||
if (this._children.length)
|
||||
if (this._children.length > 0)
|
||||
this._activeTab = this._children[0];
|
||||
else
|
||||
this._activeTab = null;
|
||||
|
@ -882,6 +889,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
addAppTab: function GroupItem_addAppTab(xulTab) {
|
||||
let self = this;
|
||||
|
||||
// add the icon
|
||||
let icon = xulTab.image || Utils.defaultFaviconURL;
|
||||
let $appTab = iQ("<img>")
|
||||
.addClass("appTabIcon")
|
||||
|
@ -897,6 +905,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
UI.goToTab(iQ(this).data("xulTab"));
|
||||
});
|
||||
|
||||
// adjust the tray
|
||||
let columnWidth = $appTab.width();
|
||||
if (parseInt(this.$appTabTray.css("width")) != columnWidth) {
|
||||
this.$appTabTray.css({width: columnWidth});
|
||||
|
@ -904,6 +913,25 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Removes the given xul:tab as an app tab in this group's apptab tray
|
||||
removeAppTab: function GroupItem_removeAppTab(xulTab) {
|
||||
// remove the icon
|
||||
iQ(".appTabIcon", this.$appTabTray).each(function(icon) {
|
||||
let $icon = iQ(icon);
|
||||
if ($icon.data("xulTab") != xulTab)
|
||||
return;
|
||||
|
||||
$icon.remove();
|
||||
});
|
||||
|
||||
// adjust the tray
|
||||
if (!iQ(".appTabIcon", this.$appTabTray).length) {
|
||||
this.$appTabTray.css({width: 0});
|
||||
this.arrange();
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: hideExpandControl
|
||||
// Hide the control which expands a stacked groupItem into a quick-look view.
|
||||
|
@ -1502,12 +1530,14 @@ let GroupItems = {
|
|||
// ----------
|
||||
// Function: uninit
|
||||
uninit : function GroupItems_uninit () {
|
||||
// call our cleanup functions
|
||||
this._cleanupFunctions.forEach(function(func) {
|
||||
func();
|
||||
});
|
||||
|
||||
this._cleanupFunctions = [];
|
||||
|
||||
// additional clean up
|
||||
this.groupItems = null;
|
||||
},
|
||||
|
||||
|
@ -1530,6 +1560,22 @@ let GroupItems = {
|
|||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// when a tab becomes pinned, add it to the app tab tray in all groups
|
||||
handleTabPin: function GroupItems_handleTabPin(xulTab) {
|
||||
this.groupItems.forEach(function(groupItem) {
|
||||
groupItem.addAppTab(xulTab);
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// when a tab becomes unpinned, remove it from the app tab tray in all groups
|
||||
handleTabUnpin: function GroupItems_handleTabUnpin(xulTab) {
|
||||
this.groupItems.forEach(function(groupItem) {
|
||||
groupItem.removeAppTab(xulTab);
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: getNextID
|
||||
// Returns the next unused groupItem ID.
|
||||
|
|
|
@ -334,7 +334,7 @@ function hideSearch(event){
|
|||
iQ("#searchbox").val("");
|
||||
iQ("#search").hide();
|
||||
|
||||
iQ("#searchbutton").css({top: 0, left: 0, opacity:.8});
|
||||
iQ("#searchbutton").css({ opacity:.8 });
|
||||
|
||||
var mainWindow = gWindow.document.getElementById("main-window");
|
||||
mainWindow.setAttribute("activetitlebarcolor", "#C4C4C4");
|
||||
|
@ -350,6 +350,10 @@ function hideSearch(event){
|
|||
let newEvent = document.createEvent("Events");
|
||||
newEvent.initEvent("tabviewsearchdisabled", false, false);
|
||||
dispatchEvent(newEvent);
|
||||
|
||||
// Return focus to the tab window
|
||||
UI.blurAll();
|
||||
gTabViewFrame.contentWindow.focus();
|
||||
}
|
||||
|
||||
function performSearch() {
|
||||
|
@ -360,7 +364,7 @@ function performSearch() {
|
|||
function ensureSearchShown(event){
|
||||
var $search = iQ("#search");
|
||||
var $searchbox = iQ("#searchbox");
|
||||
iQ("#searchbutton").css({top: -78, left: -300, opacity: 1});
|
||||
iQ("#searchbutton").css({ opacity: 1 });
|
||||
|
||||
|
||||
if ($search.css("display") == "none") {
|
||||
|
|
|
@ -489,6 +489,9 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// Updates this item to visually indicate that it's active.
|
||||
makeActive: function TabItem_makeActive() {
|
||||
iQ(this.container).addClass("focus");
|
||||
|
||||
if (this.parent)
|
||||
this.parent.setActiveTab(this);
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -831,8 +834,8 @@ let TabItems = {
|
|||
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");
|
||||
// note that it's ok to unlink an app tab; see .handleTabUnpin
|
||||
|
||||
this.unregister(tab.tabItem);
|
||||
tab.tabItem._sendToSubscribers("close");
|
||||
|
@ -851,6 +854,19 @@ let TabItems = {
|
|||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// when a tab becomes pinned, destroy its TabItem
|
||||
handleTabPin: function TabItems_handleTabPin(xulTab) {
|
||||
this.unlink(xulTab);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// when a tab becomes unpinned, create a TabItem for it
|
||||
handleTabUnpin: function TabItems_handleTabUnpin(xulTab) {
|
||||
this.link(xulTab);
|
||||
this.update(xulTab);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: heartbeat
|
||||
// Allows us to spreadout update calls over a period of time.
|
||||
|
@ -993,7 +1009,10 @@ let TabItems = {
|
|||
if (groupItem) {
|
||||
groupItem.add(item);
|
||||
|
||||
if (item.tab == gBrowser.selectedTab)
|
||||
// if it matches the selected tab or no active tab and the browser
|
||||
// tab is hidden, the active group item would be set.
|
||||
if (item.tab == gBrowser.selectedTab ||
|
||||
(!GroupItems.getActiveGroupItem() && !item.tab.hidden))
|
||||
GroupItems.setActiveGroupItem(item.parent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
|
||||
* Ehsan Akhgari <ehsan@mozilla.com>
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
* Sean Dunn <seanedunn@yahoo.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
|
||||
|
@ -48,9 +49,9 @@ let Keys = { meta: false };
|
|||
// Class: UI
|
||||
// Singleton top-level UI manager.
|
||||
let UI = {
|
||||
// Variable: _frameInitalized
|
||||
// Variable: _frameInitialized
|
||||
// True if the Tab View UI frame has been initialized.
|
||||
_frameInitalized: false,
|
||||
_frameInitialized: false,
|
||||
|
||||
// Variable: _pageBounds
|
||||
// Stores the page bounds.
|
||||
|
@ -83,6 +84,10 @@ let UI = {
|
|||
// Keeps track of event listeners added to the AllTabs object.
|
||||
_eventListeners: {},
|
||||
|
||||
// Variable: _cleanupFunctions
|
||||
// An array of functions to be called at uninit time
|
||||
_cleanupFunctions: [],
|
||||
|
||||
// ----------
|
||||
// Function: init
|
||||
// Must be called after the object is created.
|
||||
|
@ -225,14 +230,28 @@ let UI = {
|
|||
Services.obs.addObserver(observer, "quit-application-requested", false);
|
||||
|
||||
// ___ Done
|
||||
this._frameInitalized = true;
|
||||
this._frameInitialized = true;
|
||||
this._save();
|
||||
|
||||
// fire an iframe initialized event so everyone knows tab view is
|
||||
// initialized.
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("tabviewframeinitialized", true, false);
|
||||
dispatchEvent(event);
|
||||
} catch(e) {
|
||||
Utils.log(e);
|
||||
}
|
||||
},
|
||||
|
||||
uninit: function UI_uninit() {
|
||||
// call our cleanup functions
|
||||
this._cleanupFunctions.forEach(function(func) {
|
||||
func();
|
||||
});
|
||||
|
||||
this._cleanupFunctions = [];
|
||||
|
||||
// additional clean up
|
||||
TabItems.uninit();
|
||||
GroupItems.uninit();
|
||||
Storage.uninit();
|
||||
|
@ -242,6 +261,16 @@ let UI = {
|
|||
this._pageBounds = null;
|
||||
this._reorderTabItemsOnShow = null;
|
||||
this._reorderTabsOnHide = null;
|
||||
this._frameInitialized = false;
|
||||
},
|
||||
|
||||
// Function: blurAll
|
||||
// Blurs any currently focused element
|
||||
//
|
||||
blurAll: function UI_blurAll() {
|
||||
iQ(":focus").each(function(element) {
|
||||
element.blur();
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -419,6 +448,13 @@ let UI = {
|
|||
} else {
|
||||
// if not closing the last tab
|
||||
if (gBrowser.tabs.length > 1) {
|
||||
// Don't return to TabView if there are any app tabs
|
||||
for (let a = 0; a < gBrowser.tabs.length; a++) {
|
||||
let theTab = gBrowser.tabs[a];
|
||||
if (theTab.pinned && gBrowser._removingTabs.indexOf(theTab) == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
var groupItem = GroupItems.getActiveGroupItem();
|
||||
|
||||
// 1) Only go back to the TabView tab when there you close the last
|
||||
|
@ -429,7 +465,7 @@ let UI = {
|
|||
// Can't use timeout here because user would see a flicker of
|
||||
// switching to another tab before the TabView interface shows up.
|
||||
if ((groupItem && groupItem._children.length == 1) ||
|
||||
(groupItem == null && gBrowser.visibleTabs.length == 1)) {
|
||||
(groupItem == null && gBrowser.visibleTabs.length <= 1)) {
|
||||
// for the tab focus event to pick up.
|
||||
self._closedLastVisibleTab = true;
|
||||
// remove the zoom prep.
|
||||
|
@ -459,6 +495,28 @@ let UI = {
|
|||
|
||||
for (let name in this._eventListeners)
|
||||
AllTabs.register(name, this._eventListeners[name]);
|
||||
|
||||
// Start watching for tab pin events, and set up our uninit for same.
|
||||
function handleTabPin(event) {
|
||||
TabItems.handleTabPin(event.originalTarget);
|
||||
GroupItems.handleTabPin(event.originalTarget);
|
||||
}
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabPinned", handleTabPin, false);
|
||||
this._cleanupFunctions.push(function() {
|
||||
gBrowser.tabContainer.removeEventListener("TabPinned", handleTabPin, false);
|
||||
});
|
||||
|
||||
// Start watching for tab unpin events, and set up our uninit for same.
|
||||
function handleTabUnpin(event) {
|
||||
TabItems.handleTabUnpin(event.originalTarget);
|
||||
GroupItems.handleTabUnpin(event.originalTarget);
|
||||
}
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabUnpinned", handleTabUnpin, false);
|
||||
this._cleanupFunctions.push(function() {
|
||||
gBrowser.tabContainer.removeEventListener("TabUnpinned", handleTabUnpin, false);
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -582,7 +640,7 @@ let UI = {
|
|||
|
||||
function getClosestTabBy(norm) {
|
||||
var centers =
|
||||
[[item.bounds.center(), item]
|
||||
[[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
|
||||
|
@ -900,6 +958,8 @@ let UI = {
|
|||
activeTab = gBrowser.selectedTab.tabItem;
|
||||
if (activeTab)
|
||||
activeTab.zoomIn();
|
||||
|
||||
this.blurAll();
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -997,7 +1057,7 @@ let UI = {
|
|||
// Function: _save
|
||||
// Saves the data for this object to persistent storage
|
||||
_save: function UI__save() {
|
||||
if (!this._frameInitalized)
|
||||
if (!this._frameInitialized)
|
||||
return;
|
||||
|
||||
var data = {
|
||||
|
|
|
@ -94,6 +94,7 @@ endif
|
|||
|
||||
_BROWSER_FILES = \
|
||||
browser_typeAheadFind.js \
|
||||
browser_keywordSearch.js \
|
||||
browser_NetworkPrioritizer.js \
|
||||
browser_allTabsPanel.js \
|
||||
browser_alltabslistener.js \
|
||||
|
@ -183,6 +184,9 @@ _BROWSER_FILES = \
|
|||
browser_sanitizeDialog.js \
|
||||
browser_scope.js \
|
||||
browser_selectTabAtIndex.js \
|
||||
browser_tab_dragdrop.js \
|
||||
browser_tab_dragdrop2.js \
|
||||
browser_tab_dragdrop2_frame1.xul \
|
||||
browser_tabfocus.js \
|
||||
browser_tabs_owner.js \
|
||||
browser_visibleTabs.js \
|
||||
|
@ -208,6 +212,8 @@ _BROWSER_FILES = \
|
|||
browser_tabMatchesInAwesomebar.js \
|
||||
file_bug550565_popup.html \
|
||||
file_bug550565_favicon.ico \
|
||||
browser_overLinkInLocationBar.js \
|
||||
browser_overLinkInLocationBar.html \
|
||||
$(NULL)
|
||||
|
||||
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
|
|
|
@ -72,13 +72,14 @@ function imageZoomSwitch() {
|
|||
finishTest();
|
||||
});
|
||||
gBrowser.selectedTab = gTab2;
|
||||
|
||||
finishTest();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var finishTestStarted = false;
|
||||
function finishTest() {
|
||||
ok(!finishTestStarted, "finishTest called more than once");
|
||||
finishTestStarted = true;
|
||||
gBrowser.selectedTab = gTab1;
|
||||
FullZoom.reset();
|
||||
gBrowser.removeTab(gTab1);
|
||||
|
@ -94,7 +95,8 @@ function zoomTest(tab, val, msg) {
|
|||
}
|
||||
|
||||
function load(tab, url, cb) {
|
||||
let didLoad = didZoom = false;
|
||||
let didLoad = false;
|
||||
let didZoom = false;
|
||||
tab.linkedBrowser.addEventListener("load", function (event) {
|
||||
event.currentTarget.removeEventListener("load", arguments.callee, true);
|
||||
didLoad = true;
|
||||
|
@ -112,7 +114,8 @@ function load(tab, url, cb) {
|
|||
}
|
||||
|
||||
function navigate(direction, cb) {
|
||||
let didPs = didZoom = false;
|
||||
let didPs = false;
|
||||
let didZoom = false;
|
||||
gBrowser.addEventListener("pageshow", function (event) {
|
||||
gBrowser.removeEventListener("pageshow", arguments.callee, true);
|
||||
didPs = true;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
**/
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
let searchText = "test search";
|
||||
|
||||
let listener = {
|
||||
onStateChange: function onLocationChange(webProgress, req, flags, status) {
|
||||
ok(flags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT, "only notified for document");
|
||||
|
||||
// Only care about starts
|
||||
if (!(flags & Ci.nsIWebProgressListener.STATE_START))
|
||||
return;
|
||||
|
||||
ok(req instanceof Ci.nsIChannel, "req is a channel");
|
||||
|
||||
let searchURL = Services.search.originalDefaultEngine.getSubmission(searchText).uri.spec;
|
||||
is(req.originalURI.spec, searchURL, "search URL was loaded");
|
||||
info("Actual URI: " + req.URI.spec);
|
||||
|
||||
Services.ww.unregisterNotification(observer);
|
||||
gBrowser.removeProgressListener(this);
|
||||
executeSoon(function () {
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
gBrowser.addProgressListener(listener, Ci.nsIWebProgressListener.NOTIFY_STATE_DOCUMENT);
|
||||
|
||||
let observer = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowopened") {
|
||||
ok(false, "Alert window opened");
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
|
||||
win.addEventListener("load", function() {
|
||||
win.removeEventListener("load", arguments.callee, false);
|
||||
win.close();
|
||||
}, false);
|
||||
gBrowser.removeProgressListener(listener);
|
||||
executeSoon(function () {
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
Services.ww.unregisterNotification(this);
|
||||
}
|
||||
};
|
||||
Services.ww.registerNotification(observer);
|
||||
|
||||
// Simulate a user entering search terms
|
||||
gURLBar.value = searchText;
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<p>
|
||||
<a href="http://example.com/" id="link">LINK</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,177 @@
|
|||
/* ***** 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 browser test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Drew Willcoxon <adw@mozilla.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 ***** */
|
||||
|
||||
/**
|
||||
* This tests the "over-link" that appears in the location bar when the user
|
||||
* mouses over a link. See bug 587908.
|
||||
*/
|
||||
|
||||
const TEST_URL = "http://mochi.test:8888/browser/browser/base/content/test/browser_overLinkInLocationBar.html";
|
||||
|
||||
var gTestIter;
|
||||
|
||||
// TESTS //////////////////////////////////////////////////////////////////////
|
||||
|
||||
function smokeTestGenerator() {
|
||||
let tab = openTestPage();
|
||||
yield;
|
||||
|
||||
let contentDoc = gBrowser.contentDocument;
|
||||
let link = contentDoc.getElementById("link");
|
||||
|
||||
mouseover(link);
|
||||
yield;
|
||||
checkURLBar(true);
|
||||
|
||||
mouseout(link);
|
||||
yield;
|
||||
checkURLBar(false);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gTestIter = smokeTestGenerator();
|
||||
cont();
|
||||
}
|
||||
|
||||
// HELPERS ////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Advances the test iterator. When all iterations have completed, the entire
|
||||
* suite is finish()ed.
|
||||
*/
|
||||
function cont() {
|
||||
try {
|
||||
gTestIter.next();
|
||||
}
|
||||
catch (err if err instanceof StopIteration) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the location bar looks like it should.
|
||||
*
|
||||
* @param shouldShowOverLink
|
||||
* True if you expect the over-link to be showing and false otherwise.
|
||||
*/
|
||||
function checkURLBar(shouldShowOverLink) {
|
||||
let overLink = window.getComputedStyle(gURLBar._overLinkBox, null);
|
||||
let origin = window.getComputedStyle(gURLBar._originLabel, null);
|
||||
let editLayer = window.getComputedStyle(gURLBar._textboxContainer, null);
|
||||
if (shouldShowOverLink) {
|
||||
isnot(origin.color, "transparent",
|
||||
"Origin color in over-link layer should not be transparent");
|
||||
is(overLink.opacity, 1, "Over-link should be opaque");
|
||||
is(editLayer.color, "transparent",
|
||||
"Edit layer color should be transparent");
|
||||
}
|
||||
else {
|
||||
is(origin.color, "transparent",
|
||||
"Origin color in over-link layer should be transparent");
|
||||
is(overLink.opacity, 0, "Over-link should be transparent");
|
||||
isnot(editLayer.color, "transparent",
|
||||
"Edit layer color should not be transparent");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the test URL in a new foreground tab. When the page has finished
|
||||
* loading, the test iterator is advanced, so you should yield after calling.
|
||||
*
|
||||
* @return The opened <tab>.
|
||||
*/
|
||||
function openTestPage() {
|
||||
gBrowser.addEventListener("load", function onLoad(event) {
|
||||
if (event.target.URL == TEST_URL) {
|
||||
gBrowser.removeEventListener("load", onLoad, true);
|
||||
cont();
|
||||
}
|
||||
}, true);
|
||||
return gBrowser.loadOneTab(TEST_URL, { inBackground: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a mouseover event to a given anchor node. When the over-link fade-in
|
||||
* transition has completed, the test iterator is advanced, so you should yield
|
||||
* after calling.
|
||||
*
|
||||
* @param anchorNode
|
||||
* An anchor node.
|
||||
*/
|
||||
function mouseover(anchorNode) {
|
||||
mouseAnchorNode(anchorNode, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a mouseout event to a given anchor node. When the over-link fade-out
|
||||
* transition has completed, the test iterator is advanced, so you should yield
|
||||
* after calling.
|
||||
*
|
||||
* @param anchorNode
|
||||
* An anchor node.
|
||||
*/
|
||||
function mouseout(anchorNode) {
|
||||
mouseAnchorNode(anchorNode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for mouseover and mouseout. Sends a mouse event to a given node.
|
||||
* When the over-link fade-in or -out transition has completed, the test
|
||||
* iterator is advanced, so you should yield after calling.
|
||||
*
|
||||
* @param node
|
||||
* An anchor node in a content document.
|
||||
* @param over
|
||||
* True for "mouseover" and false for "mouseout".
|
||||
*/
|
||||
function mouseAnchorNode(node, over) {
|
||||
let overLink = gURLBar._overLinkBox;
|
||||
overLink.addEventListener("transitionend", function onTrans(event) {
|
||||
if (event.target == overLink) {
|
||||
overLink.removeEventListener("transitionend", onTrans, false);
|
||||
cont();
|
||||
}
|
||||
}, false);
|
||||
let offset = over ? 0 : -1;
|
||||
let eventType = over ? "mouseover" : "mouseout";
|
||||
EventUtils.synthesizeMouse(node, offset, offset,
|
||||
{ type: eventType, clickCount: 0 },
|
||||
node.ownerDocument.defaultView);
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Gavin Sharp <gavin@gavinsharp.com>
|
||||
* Sylvain Pasche <sylvain.pasche@gmail.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
|
||||
|
@ -142,6 +143,25 @@ function basicNotification() {
|
|||
}
|
||||
}
|
||||
];
|
||||
this.options = {
|
||||
eventCallback: function (eventName) {
|
||||
switch (eventName) {
|
||||
case "dismissed":
|
||||
self.dismissalCallbackTriggered = true;
|
||||
break;
|
||||
case "shown":
|
||||
self.shownCallbackTriggered = true;
|
||||
break;
|
||||
case "removed":
|
||||
self.removedCallbackTriggered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
this.addOptions = function(options) {
|
||||
for (let [name, value] in Iterator(options))
|
||||
self.options[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
var wrongBrowserNotificationObject = new basicNotification();
|
||||
|
@ -184,7 +204,9 @@ var tests = [
|
|||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// test opening a notification for a background browser
|
||||
|
@ -199,6 +221,7 @@ var tests = [
|
|||
is(PopupNotifications.isPanelOpen, false, "panel isn't open");
|
||||
ok(!wrongBrowserNotificationObject.mainActionClicked, "main action wasn't clicked");
|
||||
ok(!wrongBrowserNotificationObject.secondaryActionClicked, "secondary action wasn't clicked");
|
||||
ok(!wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback wasn't called");
|
||||
}
|
||||
},
|
||||
// now select that browser and test to see that the notification appeared
|
||||
|
@ -217,7 +240,10 @@ var tests = [
|
|||
},
|
||||
onHidden: function (popup) {
|
||||
// actually remove the notification to prevent it from reappearing
|
||||
ok(!wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback wasn't called");
|
||||
wrongBrowserNotification.remove();
|
||||
ok(!wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback wasn't called after remove()");
|
||||
ok(wrongBrowserNotificationObject.removedCallbackTriggered, "removed callback triggered");
|
||||
wrongBrowserNotification = null;
|
||||
}
|
||||
},
|
||||
|
@ -270,9 +296,11 @@ var tests = [
|
|||
onHidden: function (popup) {
|
||||
ok(this.testNotif1.mainActionClicked, "main action #1 was clicked");
|
||||
ok(!this.testNotif1.secondaryActionClicked, "secondary action #1 wasn't clicked");
|
||||
ok(!this.testNotif1.dismissalCallbackTriggered, "dismissal callback #1 wasn't called");
|
||||
|
||||
ok(!this.testNotif2.mainActionClicked, "main action #2 wasn't clicked");
|
||||
ok(this.testNotif2.secondaryActionClicked, "secondary action #2 was clicked");
|
||||
ok(!this.testNotif2.dismissalCallbackTriggered, "dismissal callback #2 wasn't called");
|
||||
}
|
||||
},
|
||||
// Test notification without mainAction
|
||||
|
@ -310,6 +338,7 @@ var tests = [
|
|||
onHidden: function (popup) {
|
||||
// Remove the first notification
|
||||
this.firstNotification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test optional params
|
||||
|
@ -324,7 +353,9 @@ var tests = [
|
|||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test that icons appear
|
||||
|
@ -354,9 +385,9 @@ var tests = [
|
|||
let self = this;
|
||||
loadURI("http://example.com/", function() {
|
||||
self.notifyObj = new basicNotification();
|
||||
self.notifyObj.options = {
|
||||
self.notifyObj.addOptions({
|
||||
persistence: 2
|
||||
};
|
||||
});
|
||||
self.notification = showNotification(self.notifyObj);
|
||||
});
|
||||
},
|
||||
|
@ -391,9 +422,9 @@ var tests = [
|
|||
loadURI("http://example.com/", function() {
|
||||
self.notifyObj = new basicNotification();
|
||||
// Set a timeout of 10 minutes that should never be hit
|
||||
self.notifyObj.options = {
|
||||
self.notifyObj.addOptions({
|
||||
timeout: Date.now() + 600000
|
||||
};
|
||||
});
|
||||
self.notification = showNotification(self.notifyObj);
|
||||
});
|
||||
},
|
||||
|
@ -433,7 +464,7 @@ var tests = [
|
|||
// The notification should open up on the box
|
||||
this.notifyObj = new basicNotification();
|
||||
this.notifyObj.anchorID = this.box.id = "nested-box";
|
||||
this.notifyObj.options = {dismissed: true};
|
||||
this.notifyObj.addOptions({dismissed: true});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
|
||||
EventUtils.synthesizeMouse(button, 1, 1, {});
|
||||
|
@ -452,7 +483,7 @@ var tests = [
|
|||
run: function() {
|
||||
let notifyObj = new basicNotification();
|
||||
notifyObj.anchorID = "geo-notification-icon";
|
||||
notifyObj.options = {neverShow: true};
|
||||
notifyObj.addOptions({neverShow: true});
|
||||
showNotification(notifyObj);
|
||||
},
|
||||
updateNotShowing: function() {
|
||||
|
@ -474,8 +505,10 @@ function showNotification(notifyObj) {
|
|||
|
||||
function checkPopup(popup, notificationObj) {
|
||||
info("[Test #" + gTestIndex + "] checking popup");
|
||||
let notifications = popup.childNodes;
|
||||
|
||||
ok(notificationObj.shownCallbackTriggered, "shown callback was triggered");
|
||||
|
||||
let notifications = popup.childNodes;
|
||||
is(notifications.length, 1, "only one notification displayed");
|
||||
let notification = notifications[0];
|
||||
let icon = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-icon");
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
function test()
|
||||
{
|
||||
var embed = '<embed type="application/x-test" allowscriptaccess="always" allowfullscreen="true" wmode="window" width="640" height="480"></embed>'
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// create a few tabs
|
||||
var tabs = [
|
||||
gBrowser.tabs[0],
|
||||
gBrowser.addTab("about:blank", {skipAnimation: true}),
|
||||
gBrowser.addTab("about:blank", {skipAnimation: true}),
|
||||
gBrowser.addTab("about:blank", {skipAnimation: true}),
|
||||
gBrowser.addTab("about:blank", {skipAnimation: true})
|
||||
];
|
||||
|
||||
function setLocation(i, url) {
|
||||
gBrowser.getBrowserForTab(tabs[i]).contentWindow.location = url;
|
||||
}
|
||||
function moveTabTo(a, b) {
|
||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.tabs[b], gBrowser.tabs[a]);
|
||||
}
|
||||
function clickTest(doc, win) {
|
||||
var clicks = doc.defaultView.clicks;
|
||||
EventUtils.synthesizeMouse(doc.body, 100, 600, {}, win);
|
||||
is(doc.defaultView.clicks, clicks+1, "adding 1 more click on BODY");
|
||||
}
|
||||
function test1() {
|
||||
moveTabTo(2, 3); // now: 0 1 2 4
|
||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||
is(gBrowser.tabs[2], tabs[3], "tab3");
|
||||
|
||||
var plugin = gBrowser.getBrowserForTab(tabs[4]).docShell.contentViewer.DOMDocument.wrappedJSObject.body.firstChild;
|
||||
var tab4_plugin_object = plugin.getObjectValue();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.tabs[2];
|
||||
moveTabTo(3, 2); // now: 0 1 4
|
||||
gBrowser.selectedTab = tabs[4];
|
||||
var doc = gBrowser.getBrowserForTab(gBrowser.tabs[2]).docShell.contentViewer.DOMDocument.wrappedJSObject;
|
||||
plugin = doc.body.firstChild;
|
||||
ok(plugin && plugin.checkObjectValue(tab4_plugin_object), "same plugin instance");
|
||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||
is(gBrowser.tabs[2], tabs[3], "tab4");
|
||||
is(doc.defaultView.clicks, 0, "no click on BODY so far");
|
||||
clickTest(doc, window);
|
||||
|
||||
moveTabTo(2, 1); // now: 0 4
|
||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||
doc = gBrowser.getBrowserForTab(gBrowser.tabs[1]).docShell.contentViewer.DOMDocument.wrappedJSObject;
|
||||
plugin = doc.body.firstChild;
|
||||
ok(plugin && plugin.checkObjectValue(tab4_plugin_object), "same plugin instance");
|
||||
clickTest(doc, window);
|
||||
|
||||
// Load a new document (about:blank) in tab4, then detach that tab into a new window.
|
||||
// In the new window, navigate back to the original document and click on its <body>,
|
||||
// verify that its onclick was called.
|
||||
var t = tabs[1];
|
||||
var b = gBrowser.getBrowserForTab(t);
|
||||
gBrowser.selectedTab = t;
|
||||
b.addEventListener("load", function() {
|
||||
b.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
executeSoon(function () {
|
||||
var win = gBrowser.replaceTabWithWindow(t);
|
||||
win.addEventListener("load", function () {
|
||||
win.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
// Verify that the original window now only has the initial tab left in it.
|
||||
is(gBrowser.tabs[0], tabs[0], "tab0");
|
||||
is(gBrowser.getBrowserForTab(gBrowser.tabs[0]).contentWindow.location, "about:blank", "tab0 uri");
|
||||
|
||||
executeSoon(function () {
|
||||
win.gBrowser.addEventListener("pageshow", function () {
|
||||
win.gBrowser.removeEventListener("pageshow", arguments.callee, false);
|
||||
executeSoon(function () {
|
||||
t = win.gBrowser.tabs[0];
|
||||
b = win.gBrowser.getBrowserForTab(t);
|
||||
var doc = b.docShell.contentViewer.DOMDocument.wrappedJSObject;
|
||||
clickTest(doc, win);
|
||||
win.close();
|
||||
finish();
|
||||
});
|
||||
}, false);
|
||||
win.gBrowser.goBack();
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
}, true);
|
||||
b.loadURI("about:blank");
|
||||
|
||||
}
|
||||
|
||||
var loads = 0;
|
||||
function waitForLoad(tab) {
|
||||
gBrowser.getBrowserForTab(gBrowser.tabs[tab]).removeEventListener("load", arguments.callee, true);
|
||||
++loads;
|
||||
if (loads == tabs.length - 1) {
|
||||
executeSoon(test1);
|
||||
}
|
||||
}
|
||||
|
||||
function fn(f, arg) {
|
||||
return function () { return f(arg); };
|
||||
}
|
||||
for (var i = 1; i < tabs.length; ++i) {
|
||||
gBrowser.getBrowserForTab(tabs[i]).addEventListener("load", fn(waitForLoad,i), true);
|
||||
}
|
||||
|
||||
setLocation(1, "data:text/html,<title>tab1</title><body>tab1<iframe>");
|
||||
setLocation(2, "data:text/plain,tab2");
|
||||
setLocation(3, "data:text/html,<title>tab3</title><body>tab3<iframe>");
|
||||
setLocation(4, "data:text/html,<body onload='clicks=0' onclick='++clicks'>"+embed);
|
||||
gBrowser.selectedTab = tabs[3];
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
var level1 = false;
|
||||
var level2 = false;
|
||||
function test1() {
|
||||
// Load the following URI (which runs some child popup tests) in a new window (B),
|
||||
// then add a blank tab to B and call replaceTabWithWindow to detach the URI tab
|
||||
// into yet a new window (C), then close B.
|
||||
// Now run the tests again and then close C.
|
||||
// The test results does not matter, all this is just to exercise some code to
|
||||
// catch assertions or crashes.
|
||||
var uri = "chrome://mochikit/content/browser/" +
|
||||
"browser/base/content/test/browser_tab_dragdrop2_frame1.xul";
|
||||
let window_B = openDialog(location, "_blank", "chrome,all,dialog=no,left=200,top=200,width=200,height=200", uri);
|
||||
window_B.addEventListener("load", function(aEvent) {
|
||||
window_B.removeEventListener("load", arguments.callee, false);
|
||||
if (level1) return; level1=true;
|
||||
executeSoon(function () {
|
||||
window_B.gBrowser.addEventListener("load", function(aEvent) {
|
||||
window_B.removeEventListener("load", arguments.callee, true);
|
||||
if (level2) return; level2=true;
|
||||
is(window_B.gBrowser.getBrowserForTab(window_B.gBrowser.tabs[0]).contentWindow.location, uri, "sanity check");
|
||||
//alert("1:"+window_B.gBrowser.getBrowserForTab(window_B.gBrowser.tabs[0]).contentWindow.location);
|
||||
var windowB_tab2 = window_B.gBrowser.addTab("about:blank", {skipAnimation: true});
|
||||
setTimeout(function () {
|
||||
//alert("2:"+window_B.gBrowser.getBrowserForTab(window_B.gBrowser.tabs[0]).contentWindow.location);
|
||||
window_B.gBrowser.addEventListener("pagehide", function(aEvent) {
|
||||
window_B.gBrowser.removeEventListener("pagehide", arguments.callee, true);
|
||||
executeSoon(function () {
|
||||
// alert("closing window_B which has "+ window_B.gBrowser.tabs.length+" tabs\n"+
|
||||
// window_B.gBrowser.getBrowserForTab(window_B.gBrowser.tabs[0]).contentWindow.location);
|
||||
window_B.close();
|
||||
|
||||
var doc = window_C.gBrowser.getBrowserForTab(window_C.gBrowser.tabs[0])
|
||||
.docShell.contentViewer.DOMDocument.wrappedJSObject;
|
||||
var elems = document.documentElement.childNodes;
|
||||
var calls = doc.defaultView.test_panels();
|
||||
window_C.close();
|
||||
finish();
|
||||
});
|
||||
}, true);
|
||||
window_B.gBrowser.selectedTab = window_B.gBrowser.tabs[0];
|
||||
var window_C = window_B.gBrowser.replaceTabWithWindow(window_B.gBrowser.tabs[0]);
|
||||
}, 1000); // 1 second to allow the tests to create the popups
|
||||
}, true);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
test1();
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<!--
|
||||
XUL Widget Test for panels
|
||||
-->
|
||||
<window title="Titlebar" width="200" height="200"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<tree id="tree" seltype="single" width="100" height="100">
|
||||
<treecols>
|
||||
<treecol flex="1"/>
|
||||
<treecol flex="1"/>
|
||||
</treecols>
|
||||
<treechildren id="treechildren">
|
||||
<treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
|
||||
<treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
|
||||
<treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
|
||||
<treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
|
||||
<treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
|
||||
<treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var currentTest = null;
|
||||
|
||||
var i = 0;
|
||||
var my_debug = false;
|
||||
function test_panels()
|
||||
{
|
||||
checkTreeCoords();
|
||||
|
||||
addEventListener("popupshown", popupShown, false);
|
||||
addEventListener("popuphidden", nextTest, false);
|
||||
return nextTest();
|
||||
}
|
||||
|
||||
function nextTest()
|
||||
{
|
||||
ok(true,"popuphidden " + i)
|
||||
if (i == tests.length) {
|
||||
SimpleTest.finish();
|
||||
return i;
|
||||
}
|
||||
|
||||
currentTest = tests[i];
|
||||
var panel = createPanel(currentTest.attrs);
|
||||
currentTest.test(panel);
|
||||
return i;
|
||||
}
|
||||
|
||||
var waitSteps = 0;
|
||||
function popupShown(event)
|
||||
{
|
||||
var panel = event.target;
|
||||
if (waitSteps > 0 && navigator.platform.indexOf("Linux") >= 0 &&
|
||||
panel.boxObject.screenY == 210) {
|
||||
waitSteps--;
|
||||
setTimeout(popupShown, 10, event);
|
||||
return;
|
||||
}
|
||||
++i;
|
||||
|
||||
currentTest.result(currentTest.testname + " ", panel);
|
||||
panel.hidePopup();
|
||||
}
|
||||
|
||||
function createPanel(attrs)
|
||||
{
|
||||
var panel = document.createElement("panel");
|
||||
for (var a in attrs) {
|
||||
panel.setAttribute(a, attrs[a]);
|
||||
}
|
||||
|
||||
var button = document.createElement("button");
|
||||
panel.appendChild(button);
|
||||
button.label = "OK";
|
||||
button.width = 120;
|
||||
button.height = 40;
|
||||
button.setAttribute("style", "-moz-appearance: none; border: 0; margin: 0;");
|
||||
panel.setAttribute("style", "-moz-appearance: none; border: 0; margin: 0;");
|
||||
return document.documentElement.appendChild(panel);
|
||||
}
|
||||
|
||||
function checkTreeCoords()
|
||||
{
|
||||
var tree = $("tree");
|
||||
var treechildren = $("treechildren");
|
||||
tree.currentIndex = 0;
|
||||
tree.treeBoxObject.scrollToRow(0);
|
||||
synthesizeMouse(treechildren, 10, tree.treeBoxObject.rowHeight + 2, { });
|
||||
|
||||
tree.treeBoxObject.scrollToRow(2);
|
||||
synthesizeMouse(treechildren, 10, tree.treeBoxObject.rowHeight + 2, { });
|
||||
}
|
||||
|
||||
var tests = [
|
||||
{
|
||||
testname: "normal panel",
|
||||
attrs: { },
|
||||
test: function(panel) {
|
||||
panel.openPopupAtScreen(200, 210);
|
||||
},
|
||||
result: function(testname, panel) {
|
||||
if (my_debug) alert(testname);
|
||||
var panelrect = panel.getBoundingClientRect();
|
||||
}
|
||||
},
|
||||
{
|
||||
// only noautohide panels support titlebars, so one shouldn't be shown here
|
||||
testname: "autohide panel with titlebar",
|
||||
attrs: { titlebar: "normal" },
|
||||
test: function(panel) {
|
||||
panel.openPopupAtScreen(200, 210);
|
||||
},
|
||||
result: function(testname, panel) {
|
||||
if (my_debug) alert(testname);
|
||||
var panelrect = panel.getBoundingClientRect();
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "noautohide panel with titlebar",
|
||||
attrs: { noautohide: true, titlebar: "normal" },
|
||||
test: function(panel) {
|
||||
waitSteps = 25;
|
||||
panel.openPopupAtScreen(200, 210);
|
||||
},
|
||||
result: function(testname, panel) {
|
||||
if (my_debug) alert(testname);
|
||||
var panelrect = panel.getBoundingClientRect();
|
||||
|
||||
var gotMouseEvent = false;
|
||||
function mouseMoved(event)
|
||||
{
|
||||
gotMouseEvent = true;
|
||||
}
|
||||
|
||||
panel.addEventListener("mousemove", mouseMoved, true);
|
||||
synthesizeMouse(panel, 10, 10, { type: "mousemove" });
|
||||
panel.removeEventListener("mousemove", mouseMoved, true);
|
||||
|
||||
var tree = $("tree");
|
||||
tree.currentIndex = 0;
|
||||
panel.appendChild(tree);
|
||||
checkTreeCoords();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
SimpleTest.waitForFocus(test_panels);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</window>
|
|
@ -44,15 +44,20 @@ include $(DEPTH)/config/autoconf.mk
|
|||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_FILES = \
|
||||
browser_tabview_launch.js \
|
||||
browser_tabview_apptabs.js \
|
||||
browser_tabview_bug587040.js \
|
||||
browser_tabview_bug587990.js \
|
||||
browser_tabview_bug591706.js \
|
||||
browser_tabview_bug595191.js \
|
||||
browser_tabview_bug595518.js \
|
||||
browser_tabview_bug595943.js \
|
||||
browser_tabview_dragdrop.js \
|
||||
browser_tabview_exit_button.js \
|
||||
browser_tabview_group.js \
|
||||
browser_tabview_launch.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)
|
||||
|
|
|
@ -52,38 +52,77 @@ function onTabViewWindowLoaded() {
|
|||
// 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");
|
||||
let originalTab = gBrowser.tabs[0];
|
||||
|
||||
// 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
|
||||
// create a group
|
||||
let box = new contentWindow.Rect(20, 20, 180, 180);
|
||||
let groupItem = new contentWindow.GroupItem([], { bounds: box });
|
||||
let groupItemOne = new contentWindow.GroupItem([], { bounds: box, title: "test1" });
|
||||
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
|
||||
contentWindow.GroupItems.setActiveGroupItem(groupItemOne);
|
||||
|
||||
// create a tab
|
||||
let xulTab = gBrowser.loadOneTab("about:blank");
|
||||
is(gBrowser.tabs.length, 2, "we now have two tabs");
|
||||
is(groupItemOne._children.length, 1, "the new tab was added to the group");
|
||||
|
||||
// make sure the group has no app tabs
|
||||
let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
||||
is(appTabIcons.length, 0, "there are no app tab icons");
|
||||
|
||||
// pin the tab, make sure the TabItem goes away and the icon comes on
|
||||
gBrowser.pinTab(xulTab);
|
||||
|
||||
is(groupItemOne._children.length, 0, "the app tab's TabItem was removed from the group");
|
||||
|
||||
appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
||||
is(appTabIcons.length, 1, "there's now one app tab icon");
|
||||
|
||||
// create a second group and make sure it gets the icon too
|
||||
box.offset(box.width + 20, 0);
|
||||
let groupItemTwo = new contentWindow.GroupItem([], { bounds: box, title: "test2" });
|
||||
is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
|
||||
appTabIcons = groupItemTwo.container.getElementsByClassName("appTabIcon");
|
||||
is(appTabIcons.length, 1, "there's an app tab icon in the second group");
|
||||
|
||||
// unpin the tab, make sure the icon goes away and the TabItem comes on
|
||||
gBrowser.unpinTab(xulTab);
|
||||
|
||||
is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
|
||||
|
||||
appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
||||
is(appTabIcons.length, 0, "the icon is gone from group one");
|
||||
|
||||
appTabIcons = groupItemTwo.container.getElementsByClassName("appTabIcon");
|
||||
is(appTabIcons.length, 0, "the icon is gone from group 2");
|
||||
|
||||
// pin the tab again
|
||||
gBrowser.pinTab(xulTab);
|
||||
|
||||
// close the second group
|
||||
groupItemTwo.close();
|
||||
|
||||
// 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);
|
||||
gBrowser.selectedTab = originalTab;
|
||||
|
||||
gBrowser.unpinTab(xulTab);
|
||||
gBrowser.removeTab(xulTab);
|
||||
is(gBrowser.tabs.length, 1, "we finish with one tab");
|
||||
|
||||
groupItem.close();
|
||||
groupItemOne.close();
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "we finish with one group");
|
||||
|
||||
ok(!TabView.isVisible(), "Tab View is not visible");
|
||||
ok(!TabView.isVisible(), "we finish with Tab View 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);
|
||||
appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/* ***** 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 test for bug 587040.
|
||||
*
|
||||
* 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 [originalTab] = gBrowser.visibleTabs;
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
|
||||
// create a group
|
||||
let box = new contentWindow.Rect(20, 20, 300, 300);
|
||||
let groupItem = new contentWindow.GroupItem([], { bounds: box });
|
||||
|
||||
let onTabViewShown = function() {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
|
||||
is(groupItem.getChildren().length, 2, "The new group has two tab items");
|
||||
// start the test
|
||||
testSameTabItemAndClickGroup(contentWindow, groupItem);
|
||||
};
|
||||
|
||||
// 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");
|
||||
|
||||
let anotherTab = gBrowser.addTab("http://mochi.test:8888/");
|
||||
let browser = gBrowser.getBrowserForTab(anotherTab);
|
||||
let onLoad = function() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
TabView.toggle();
|
||||
}
|
||||
browser.addEventListener("load", onLoad, true);
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
// click on the + button to create a blank tab
|
||||
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
|
||||
ok(newTabButton[0], "New tab button exists");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow);
|
||||
}
|
||||
|
||||
function testSameTabItemAndClickGroup(contentWindow, groupItem, originalTab) {
|
||||
let activeTabItem = groupItem.getActiveTab();
|
||||
ok(activeTabItem, "Has active item");
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
is(activeTabItem.tab, gBrowser.selectedTab, "The correct tab is selected");
|
||||
TabView.toggle();
|
||||
};
|
||||
|
||||
let onTabViewShown = function() {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
|
||||
testDifferentTabItemAndClickGroup(contentWindow, groupItem, originalTab);
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
|
||||
let groupElement = groupItem.container;
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, groupElement, contentWindow);
|
||||
EventUtils.sendMouseEvent({ type: "mouseup" }, groupElement, contentWindow);
|
||||
}
|
||||
|
||||
function testDifferentTabItemAndClickGroup(contentWindow, groupItem, originalTab) {
|
||||
let activeTabItem = groupItem.getActiveTab();
|
||||
ok(activeTabItem, "Has old active item");
|
||||
|
||||
// press tab
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, contentWindow);
|
||||
|
||||
let newActiveTabItem = groupItem.getActiveTab();
|
||||
ok(newActiveTabItem, "Has new active item");
|
||||
|
||||
isnot(newActiveTabItem, activeTabItem, "The old and new active items are different");
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
is(newActiveTabItem.tab, gBrowser.selectedTab, "The correct tab is selected");
|
||||
|
||||
// clean up and finish the test
|
||||
groupItem.addSubscriber(groupItem, "close", function() {
|
||||
groupItem.removeSubscriber(groupItem, "close");
|
||||
finish();
|
||||
});
|
||||
gBrowser.selectedTab = originalTab;
|
||||
|
||||
groupItem.closeAll();
|
||||
// close undo group
|
||||
let closeButton = groupItem.$undoContainer.find(".close");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" }, closeButton[0], contentWindow);
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
// press the group Item
|
||||
let groupElement = groupItem.container;
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, groupElement, contentWindow);
|
||||
EventUtils.sendMouseEvent({ type: "mouseup" }, groupElement, contentWindow);
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/* ***** 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 587990 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 ***** */
|
||||
|
||||
let newTab;
|
||||
let win;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
win = window.openDialog(getBrowserURL(), "_blank", "all,dialog=no", "about:blank");
|
||||
|
||||
let onLoad = function() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
|
||||
newTab = win.gBrowser.addTab();
|
||||
|
||||
let onTabViewFrameInitialized = function() {
|
||||
win.removeEventListener(
|
||||
"tabviewframeinitialized", onTabViewFrameInitialized, false);
|
||||
|
||||
win.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
win.TabView.toggle();
|
||||
}
|
||||
win.addEventListener(
|
||||
"tabviewframeinitialized", onTabViewFrameInitialized, false);
|
||||
win.TabView.updateContextMenu(
|
||||
newTab, win.document.getElementById("context_tabViewMenuPopup"));
|
||||
}
|
||||
win.addEventListener("load", onLoad, false);
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
win.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
|
||||
ok(win.TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = win.document.getElementById("tab-view").contentWindow;
|
||||
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
|
||||
|
||||
let groupItem = contentWindow.GroupItems.groupItems[0];
|
||||
let tabItems = groupItem.getChildren();
|
||||
|
||||
is(tabItems[tabItems.length - 1].tab, newTab, "The new tab exists in the group");
|
||||
|
||||
win.gBrowser.removeTab(newTab);
|
||||
whenWindowObservesOnce(win, "domwindowclosed", function() {
|
||||
finish();
|
||||
});
|
||||
win.close();
|
||||
}
|
||||
|
||||
function whenWindowObservesOnce(win, topic, func) {
|
||||
let windowWatcher = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
let origWin = win;
|
||||
let origTopic = topic;
|
||||
let origFunc = func;
|
||||
function windowObserver(aSubject, aTopic, aData) {
|
||||
let theWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
if (origWin && theWin != origWin)
|
||||
return;
|
||||
if(aTopic == origTopic) {
|
||||
windowWatcher.unregisterNotification(windowObserver);
|
||||
origFunc.apply(this, []);
|
||||
}
|
||||
}
|
||||
windowWatcher.registerNotification(windowObserver);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/* ***** 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 search 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):
|
||||
* Sean Dunn <seanedunn@yahoo.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();
|
||||
|
||||
// show the tab view
|
||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
TabView.toggle();
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
let searchButton = contentWindow.document.getElementById("searchbutton");
|
||||
|
||||
ok(searchButton, "Search button exists");
|
||||
|
||||
let onSearchEnabled = function() {
|
||||
let search = contentWindow.document.getElementById("search");
|
||||
ok(search.style.display != "none", "Search is enabled");
|
||||
contentWindow.removeEventListener(
|
||||
"tabviewsearchenabled", onSearchEnabled, false);
|
||||
escapeTest(contentWindow);
|
||||
}
|
||||
contentWindow.addEventListener("tabviewsearchenabled", onSearchEnabled,
|
||||
false);
|
||||
// enter search mode
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, searchButton,
|
||||
contentWindow);
|
||||
}
|
||||
|
||||
function escapeTest(contentWindow) {
|
||||
let onSearchDisabled = function() {
|
||||
let search = contentWindow.document.getElementById("search");
|
||||
|
||||
ok(search.style.display == "none", "Search is disabled");
|
||||
|
||||
contentWindow.removeEventListener(
|
||||
"tabviewsearchdisabled", onSearchDisabled, false);
|
||||
toggleTabViewTest(contentWindow);
|
||||
}
|
||||
contentWindow.addEventListener("tabviewsearchdisabled", onSearchDisabled,
|
||||
false);
|
||||
// the search box focus()es in a function on the timeout queue, so we just
|
||||
// want to queue behind it.
|
||||
setTimeout( function() {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function toggleTabViewTest(contentWindow) {
|
||||
let onTabViewHidden = function() {
|
||||
contentWindow.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
|
||||
finish();
|
||||
}
|
||||
contentWindow.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
// When search is hidden, it focus()es on the background, so avert the
|
||||
// race condition by delaying ourselves on the timeout queue
|
||||
setTimeout( function() {
|
||||
// Use keyboard shortcut to toggle back to browser view
|
||||
if(navigator.platform.indexOf("Mac") >= 0) {
|
||||
EventUtils.synthesizeKey("VK_SPACE", {altKey : true}, contentWindow);
|
||||
} else {
|
||||
EventUtils.synthesizeKey("VK_SPACE", {ctrlKey : true}, contentWindow);
|
||||
}
|
||||
}, 0);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* ***** 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 595518 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();
|
||||
|
||||
// show tab view
|
||||
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;
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
// verify exit button worked
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
|
||||
// verify that the exit button no longer has focus
|
||||
is(contentWindow.iQ("#exit-button:focus").length, 0,
|
||||
"The exit button doesn't have the focus");
|
||||
|
||||
// verify that the keyboard combo works (this is the crux of bug 595518)
|
||||
// Prepare the key combo
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
let utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
let keyCode = 0;
|
||||
let charCode;
|
||||
let eventObject;
|
||||
if (navigator.platform.indexOf("Mac") != -1) {
|
||||
charCode = 160; // character code for option (alt) + space
|
||||
eventObject = { altKey: true };
|
||||
} else {
|
||||
charCode = KeyEvent.DOM_VK_SPACE;
|
||||
eventObject = { ctrlKey: true };
|
||||
}
|
||||
|
||||
// Fire off the key combo
|
||||
let modifiers = EventUtils._parseModifiers(eventObject);
|
||||
let keyDownDefaultHappened =
|
||||
utils.sendKeyEvent("keydown", keyCode, charCode, modifiers);
|
||||
utils.sendKeyEvent("keypress", keyCode, charCode, modifiers,
|
||||
!keyDownDefaultHappened);
|
||||
utils.sendKeyEvent("keyup", keyCode, charCode, modifiers);
|
||||
}
|
||||
|
||||
let onTabViewShown = function() {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
|
||||
// test if the key combo worked
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
// clean up
|
||||
let endGame = function() {
|
||||
window.removeEventListener("tabviewhidden", endGame, false);
|
||||
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
finish();
|
||||
}
|
||||
window.addEventListener("tabviewhidden", endGame, false);
|
||||
TabView.toggle();
|
||||
}
|
||||
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
// locate exit button
|
||||
let button = contentWindow.document.getElementById("exit-button");
|
||||
ok(button, "Exit button exists");
|
||||
|
||||
// click exit button
|
||||
button.focus();
|
||||
EventUtils.sendMouseEvent({ type: "click" }, button, contentWindow);
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/* ***** 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 bug 959943 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();
|
||||
|
||||
// Show TabView
|
||||
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");
|
||||
|
||||
let originalTab = gBrowser.tabs[0];
|
||||
ok(contentWindow.GroupItems.groupItems[0]._children[0].tab == originalTab,
|
||||
"the original tab is in the original group");
|
||||
|
||||
// create a second 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");
|
||||
contentWindow.GroupItems.setActiveGroupItem(groupItem);
|
||||
|
||||
// create a second tab
|
||||
let normalXulTab = gBrowser.loadOneTab("about:blank");
|
||||
is(gBrowser.tabs.length, 2, "we now have two tabs");
|
||||
is(groupItem._children.length, 1, "the new tab was added to the group");
|
||||
|
||||
// create a third tab
|
||||
let appXulTab = gBrowser.loadOneTab("about:blank");
|
||||
is(gBrowser.tabs.length, 3, "we now have three tabs");
|
||||
gBrowser.pinTab(appXulTab);
|
||||
is(groupItem._children.length, 1, "the app tab is not in the group");
|
||||
|
||||
// We now have two groups with one tab each, plus an app tab.
|
||||
// Click into one of the tabs, close it and make sure we don't go back to Tab View.
|
||||
function onTabViewHidden() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
ok(!TabView.isVisible(), "Tab View is hidden because we clicked on the app tab");
|
||||
|
||||
// Remove the tab we're looking at. Note: this will also close groupItem (verified below)
|
||||
gBrowser.removeTab(normalXulTab);
|
||||
|
||||
// Make sure we haven't returned to TabView; this is the crux of this test
|
||||
ok(!TabView.isVisible(), "Tab View remains hidden");
|
||||
|
||||
// clean up
|
||||
gBrowser.selectedTab = originalTab;
|
||||
|
||||
gBrowser.unpinTab(appXulTab);
|
||||
gBrowser.removeTab(appXulTab);
|
||||
|
||||
// Verify ending state
|
||||
is(gBrowser.tabs.length, 1, "we finish with one tab");
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "we finish with one group");
|
||||
ok(!TabView.isVisible(), "we finish with Tab View hidden");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, normalXulTab.tabItem.container, contentWindow);
|
||||
EventUtils.sendMouseEvent({ type: "mouseup" }, normalXulTab.tabItem.container, contentWindow);
|
||||
}
|
|
@ -83,5 +83,5 @@ function test() {
|
|||
|
||||
let button = document.getElementById("tabview-button");
|
||||
ok(button, "Tab View button exists");
|
||||
EventUtils.synthesizeMouse(button, 1, 1, {});
|
||||
button.doCommand();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dão Gottwald <dao@design-noir.de>
|
||||
# Dão Gottwald <dao@design-noir.de>
|
||||
# Drew Willcoxon <adw@mozilla.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
|
||||
|
@ -39,10 +40,68 @@
|
|||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
<bindings id="urlbarBindings" xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
|
||||
<binding id="urlbar" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
|
||||
|
||||
<content sizetopopup="pref">
|
||||
<xul:vbox class="urlbar-contents" flex="1">
|
||||
<xul:hbox class="urlbar-frontcap-and-textbox" flex="1">
|
||||
<xul:hbox class="urlbar-frontcap">
|
||||
<children includes="image|deck|stack|box">
|
||||
<xul:image class="autocomplete-icon" allowevents="true"/>
|
||||
</children>
|
||||
</xul:hbox>
|
||||
<xul:stack anonid="stack" class="urlbar-stack" flex="1">
|
||||
<xul:scrollbox class="urlbar-over-link-layer" flex="1"
|
||||
xbl:inherits="overlinkstate" align="center">
|
||||
<xul:label anonid="origin-label" class="urlbar-origin-label" flex="1"
|
||||
crop="end"/>
|
||||
<xul:hbox anonid="over-link-box" class="urlbar-over-link-box"
|
||||
xbl:inherits="overlinkstate" align="center">
|
||||
<xul:label anonid="over-link-host-label"
|
||||
class="urlbar-over-link-host-label"/>
|
||||
<xul:label anonid="over-link-path-label"
|
||||
class="urlbar-over-link-path-label" flex="1"/>
|
||||
</xul:hbox>
|
||||
</xul:scrollbox>
|
||||
<xul:hbox anonid="textbox-container"
|
||||
class="autocomplete-textbox-container urlbar-textbox-container"
|
||||
flex="1" xbl:inherits="focused,overlinkstate">
|
||||
<xul:hbox anonid="textbox-input-box"
|
||||
class="textbox-input-box urlbar-input-box"
|
||||
flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
|
||||
<xul:hbox class="urlbar-textbox-container-children"
|
||||
xbl:inherits="overlinkstate">
|
||||
<children/>
|
||||
</xul:hbox>
|
||||
<html:input anonid="input"
|
||||
class="autocomplete-textbox urlbar-input textbox-input"
|
||||
flex="1" allowevents="true"
|
||||
xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox class="urlbar-textbox-container-children"
|
||||
xbl:inherits="overlinkstate">
|
||||
<children includes="hbox"/>
|
||||
</xul:hbox>
|
||||
</xul:hbox>
|
||||
</xul:stack>
|
||||
<xul:dropmarker anonid="historydropmarker"
|
||||
class="autocomplete-history-dropmarker urlbar-history-dropmarker"
|
||||
allowevents="true"
|
||||
xbl:inherits="open,enablehistory,parentfocused=focused"/>
|
||||
<xul:popupset anonid="popupset"
|
||||
class="autocomplete-result-popupset"/>
|
||||
</xul:hbox>
|
||||
<xul:vbox class="urlbar-progress-container" flex="1" pack="end">
|
||||
<children includes="progressmeter"/>
|
||||
</xul:vbox>
|
||||
</xul:vbox>
|
||||
<children includes="toolbarbutton"/>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIObserver, nsIDOMEventListener">
|
||||
<constructor><![CDATA[
|
||||
this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
|
@ -64,6 +123,26 @@
|
|||
this.inputField.addEventListener("mouseout", this, false);
|
||||
this.inputField.addEventListener("overflow", this, false);
|
||||
this.inputField.addEventListener("underflow", this, false);
|
||||
this._overLinkBox.addEventListener("transitionend", this, false);
|
||||
|
||||
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
var textBox = document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "textbox-input-box");
|
||||
var cxmenu = document.getAnonymousElementByAttribute(textBox,
|
||||
"anonid", "input-box-contextmenu");
|
||||
var insertLocation = cxmenu.firstChild;
|
||||
while (insertLocation.nextSibling &&
|
||||
insertLocation.getAttribute("cmd") != "cmd_paste")
|
||||
insertLocation = insertLocation.nextSibling;
|
||||
if (insertLocation) {
|
||||
let element = document.createElement("menuitem");
|
||||
let label = Services.strings.createBundle("chrome://browser/locale/browser.properties").
|
||||
GetStringFromName("pasteAndGo.label");
|
||||
element.setAttribute("label", label);
|
||||
element.setAttribute("cmd", "cmd_paste");
|
||||
element.setAttribute("oncommand", "goDoCommand('cmd_paste'); gURLBar.handleCommand();");
|
||||
cxmenu.insertBefore(element, insertLocation.nextSibling);
|
||||
}
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
|
@ -75,6 +154,7 @@
|
|||
this.inputField.removeEventListener("mouseout", this, false);
|
||||
this.inputField.removeEventListener("overflow", this, false);
|
||||
this.inputField.removeEventListener("underflow", this, false);
|
||||
this._overLinkBox.removeEventListener("transitionend", this, false);
|
||||
]]></destructor>
|
||||
|
||||
<field name="_value"></field>
|
||||
|
@ -238,7 +318,7 @@
|
|||
// Tack www. and suffix on. If user has appended directories, insert
|
||||
// suffix before them (bug 279035). Be careful not to get two slashes.
|
||||
// Also, don't add the suffix if it's in the original url (bug 233853).
|
||||
|
||||
|
||||
let firstSlash = url.indexOf("/");
|
||||
let existingSuffix = url.indexOf(suffix.substring(0, suffix.length - 1));
|
||||
|
||||
|
@ -248,7 +328,7 @@
|
|||
// Yes slash, no suffix: Insert suffix (mozilla/stuff)
|
||||
// Yes slash, suffix before slash: Do nothing (mozilla.com/stuff)
|
||||
// Yes slash, suffix after slash: Insert suffix (mozilla/?stuff=.com)
|
||||
|
||||
|
||||
if (firstSlash >= 0) {
|
||||
if (existingSuffix == -1 || existingSuffix > firstSlash)
|
||||
url = url.substring(0, firstSlash) + suffix +
|
||||
|
@ -444,6 +524,12 @@
|
|||
this._contentIsCropped = false;
|
||||
this._hideURLTooltip();
|
||||
break;
|
||||
case "transitionend":
|
||||
if (aEvent.target == this._overLinkBox &&
|
||||
aEvent.propertyName == "opacity") {
|
||||
this._overLinkTransitioning = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -481,6 +567,100 @@
|
|||
return {type: action, param: param};
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="_stack" readonly="true"><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "stack");
|
||||
]]></field>
|
||||
|
||||
<field name="_originLabel" readonly="true"><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "origin-label");
|
||||
]]></field>
|
||||
|
||||
<field name="_overLinkBox" readonly="true"><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"over-link-box");
|
||||
]]></field>
|
||||
|
||||
<field name="_overLinkHostLabel" readonly="true"><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"over-link-host-label");
|
||||
]]></field>
|
||||
|
||||
<field name="_overLinkPathLabel" readonly="true"><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"over-link-path-label");
|
||||
]]></field>
|
||||
|
||||
<field name="_textboxContainer" readonly="true"><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"textbox-container");
|
||||
]]></field>
|
||||
|
||||
<method name="setOverLink">
|
||||
<parameter name="aURL"/>
|
||||
<body><![CDATA[
|
||||
// Hide the over-link if aURL is falsey or if the URL bar is focused.
|
||||
if (!aURL || this.focused) {
|
||||
if (this.hasAttribute("overlinkstate")) {
|
||||
this.removeAttribute("overlinkstate");
|
||||
this._overLinkTransitioning = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the width of the bar before we go modifying it.
|
||||
var barWidth = this._stack.boxObject.width;
|
||||
|
||||
// Determine the pre-path and path of the over-link. Include the
|
||||
// path's leading slash in the pre-path so that if the path is
|
||||
// truncated its leading slash is visible.
|
||||
var re = new RegExp("([a-z0-9+.-]+://[^/]+/)(.*)");
|
||||
var match = re.exec(aURL);
|
||||
var host = match ? match[1] : "";
|
||||
var path = match ? match[2] : aURL;
|
||||
|
||||
var overLink = this._overLinkBox;
|
||||
var overLinkHost = this._overLinkHostLabel;
|
||||
var overLinkPath = this._overLinkPathLabel;
|
||||
|
||||
overLinkHost.value = host;
|
||||
overLinkPath.value = path;
|
||||
|
||||
// Remove restrictions on the over-link's width.
|
||||
overLinkHost.flex = 0;
|
||||
overLinkHost.crop = "none";
|
||||
overLinkPath.crop = "none";
|
||||
overLink.style.minWidth = "";
|
||||
overLink.style.maxWidth = "";
|
||||
|
||||
// Cap the width of the over-link to 2/3 of the location bar's.
|
||||
var maxWidth = barWidth * 0.67;
|
||||
var overLinkWidth = overLinkHost.boxObject.width +
|
||||
overLinkPath.boxObject.width;
|
||||
if (overLinkWidth > maxWidth) {
|
||||
// If the host is wider than the cap and therefore the path is not
|
||||
// visible at all, crop the host at the end.
|
||||
if (overLinkHost.boxObject.width > maxWidth) {
|
||||
overLinkHost.flex = 1;
|
||||
overLinkHost.crop = "end";
|
||||
}
|
||||
overLinkPath.crop = host ? "start" : "end";
|
||||
overLink.style.minWidth = maxWidth + "px";
|
||||
overLink.style.maxWidth = maxWidth + "px";
|
||||
}
|
||||
|
||||
this._originLabel.value = this.value;
|
||||
|
||||
// Finally, show the over-link. If its animation is currently in
|
||||
// transition, show it immediately rather than animating it again.
|
||||
if (this._overLinkTransitioning)
|
||||
this.setAttribute("overlinkstate", "showing");
|
||||
else {
|
||||
this.setAttribute("overlinkstate", "fade-in");
|
||||
this._overLinkTransitioning = true;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
@ -513,7 +693,12 @@
|
|||
dt.effectAllowed = "copyLink";
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
<handler event="focus" phase="capturing" action="this._hideURLTooltip();"/>
|
||||
|
||||
<handler event="focus" phase="capturing"><![CDATA[
|
||||
this._hideURLTooltip();
|
||||
this.setOverLink(null);
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragover" phase="capturing" action="this.onDragOver(event, this);"/>
|
||||
<handler event="drop" phase="capturing" action="this.onDrop(event, this);"/>
|
||||
<handler event="select"><![CDATA[
|
||||
|
@ -572,7 +757,7 @@
|
|||
if (searchBar && searchBar.textbox == this.mInput) {
|
||||
// Handle search bar popup clicks
|
||||
var search = controller.getValueAt(this.selectedIndex);
|
||||
|
||||
|
||||
// close the autocomplete popup and revert the entered search term
|
||||
this.closePopup();
|
||||
controller.handleEscape();
|
||||
|
|
|
@ -496,14 +496,12 @@ function checkForUpdates()
|
|||
}
|
||||
#endif
|
||||
|
||||
function buildHelpMenu()
|
||||
{
|
||||
// Enable/disable the "Report Web Forgery" menu item. safebrowsing object
|
||||
// may not exist in OSX
|
||||
if (typeof safebrowsing != "undefined")
|
||||
safebrowsing.setReportPhishingMenu();
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
/**
|
||||
* Updates an element to reflect the state of available update services.
|
||||
*/
|
||||
function setupCheckForUpdates(checkForUpdates, aStringBundle)
|
||||
{
|
||||
var updates =
|
||||
Components.classes["@mozilla.org/updates/update-service;1"].
|
||||
getService(Components.interfaces.nsIApplicationUpdateService);
|
||||
|
@ -513,23 +511,21 @@ function buildHelpMenu()
|
|||
|
||||
// Disable the UI if the update enabled pref has been locked by the
|
||||
// administrator or if we cannot update for some other reason
|
||||
var checkForUpdates = document.getElementById("checkForUpdates");
|
||||
var canCheckForUpdates = updates.canCheckForUpdates;
|
||||
checkForUpdates.setAttribute("disabled", !canCheckForUpdates);
|
||||
if (!canCheckForUpdates)
|
||||
return;
|
||||
|
||||
var strings = document.getElementById("bundle_browser");
|
||||
var activeUpdate = um.activeUpdate;
|
||||
|
||||
|
||||
// If there's an active update, substitute its name into the label
|
||||
// we show for this item, otherwise display a generic label.
|
||||
function getStringWithUpdateName(key) {
|
||||
if (activeUpdate && activeUpdate.name)
|
||||
return strings.getFormattedString(key, [activeUpdate.name]);
|
||||
return strings.getString(key + "Fallback");
|
||||
return aStringBundle.formatStringFromName(key, [activeUpdate.name], 1);
|
||||
return aStringBundle.GetStringFromName(key + "Fallback");
|
||||
}
|
||||
|
||||
|
||||
// By default, show "Check for Updates..."
|
||||
var key = "default";
|
||||
if (activeUpdate) {
|
||||
|
@ -548,11 +544,31 @@ function buildHelpMenu()
|
|||
}
|
||||
}
|
||||
checkForUpdates.label = getStringWithUpdateName("updatesItem_" + key);
|
||||
checkForUpdates.accessKey = strings.getString("updatesItem_" + key + ".accesskey");
|
||||
checkForUpdates.accessKey = aStringBundle.
|
||||
GetStringFromName("updatesItem_" + key + ".accesskey");
|
||||
if (um.activeUpdate && updates.isDownloading)
|
||||
checkForUpdates.setAttribute("loading", "true");
|
||||
else
|
||||
checkForUpdates.removeAttribute("loading");
|
||||
}
|
||||
#endif
|
||||
|
||||
function buildHelpMenu()
|
||||
{
|
||||
// Enable/disable the "Report Web Forgery" menu item. safebrowsing object
|
||||
// may not exist in OSX
|
||||
if (typeof safebrowsing != "undefined")
|
||||
safebrowsing.setReportPhishingMenu();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef MOZ_UPDATER
|
||||
var checkForUpdates = document.getElementById("checkForUpdates");
|
||||
var browserBundle = document.getElementById("bundle_browser").stringBundle;
|
||||
setupCheckForUpdates(checkForUpdates, browserBundle);
|
||||
#else
|
||||
// Needed by safebrowsing for inserting its menuitem so just hide it
|
||||
document.getElementById("updateSeparator").hidden = true;
|
||||
#endif
|
||||
#else
|
||||
// Needed by safebrowsing for inserting its menuitem so just hide it
|
||||
document.getElementById("updateSeparator").hidden = true;
|
||||
|
|
|
@ -26,7 +26,6 @@ browser.jar:
|
|||
* content/browser/browser.js (content/browser.js)
|
||||
* content/browser/browser.xul (content/browser.xul)
|
||||
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
|
||||
* content/browser/credits.xhtml (content/credits.xhtml)
|
||||
* content/browser/fullscreen-video.xhtml (content/fullscreen-video.xhtml)
|
||||
* content/browser/inspector.html (content/inspector.html)
|
||||
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
|
||||
|
@ -68,6 +67,8 @@ browser.jar:
|
|||
content/browser/syncGenericChange.js (content/syncGenericChange.js)
|
||||
* content/browser/syncKey.xhtml (content/syncKey.xhtml)
|
||||
* content/browser/syncNotification.xml (content/syncNotification.xml)
|
||||
* content/browser/syncQuota.xul (content/syncQuota.xul)
|
||||
content/browser/syncQuota.js (content/syncQuota.js)
|
||||
content/browser/syncUtils.js (content/syncUtils.js)
|
||||
#endif
|
||||
# XXX: We should exclude this one as well (bug 71895)
|
||||
|
|
После Ширина: | Высота: | Размер: 25 KiB |
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичные данные
browser/branding/nightly/content/aboutCredits.png
До Ширина: | Высота: | Размер: 17 KiB |
Двоичные данные
browser/branding/nightly/content/aboutFooter.png
До Ширина: | Высота: | Размер: 227 B |
|
@ -1,8 +1,8 @@
|
|||
browser.jar:
|
||||
% content branding %content/branding/ contentaccessible=yes
|
||||
content/branding/about.png (about.png)
|
||||
content/branding/aboutCredits.png (aboutCredits.png)
|
||||
content/branding/aboutFooter.png (aboutFooter.png)
|
||||
content/branding/about-logo.png (about-logo.png)
|
||||
content/branding/about-wordmark.png (about-wordmark.png)
|
||||
content/branding/icon48.png (icon48.png)
|
||||
content/branding/icon64.png (icon64.png)
|
||||
content/branding/icon128.png (../mozicon128.png)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<!ENTITY brandShortName "Minefield">
|
||||
<!ENTITY brandFullName "Minefield">
|
||||
<!ENTITY vendorShortName "Mozilla">
|
||||
<!ENTITY trademarkInfo " ">
|
||||
<!ENTITY trademarkInfo.part1 " ">
|
||||
<!ENTITY trademarkInfo.part2 " ">
|
||||
|
|
После Ширина: | Высота: | Размер: 29 KiB |
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичные данные
browser/branding/unofficial/content/aboutCredits.png
До Ширина: | Высота: | Размер: 18 KiB |
Двоичные данные
browser/branding/unofficial/content/aboutFooter.png
До Ширина: | Высота: | Размер: 764 B |
|
@ -1,8 +1,8 @@
|
|||
browser.jar:
|
||||
% content branding %content/branding/ contentaccessible=yes
|
||||
content/branding/about.png (about.png)
|
||||
content/branding/aboutCredits.png (aboutCredits.png)
|
||||
content/branding/aboutFooter.png (aboutFooter.png)
|
||||
content/branding/about-logo.png (about-logo.png)
|
||||
content/branding/about-wordmark.png (about-wordmark.png)
|
||||
content/branding/icon48.png (icon48.png)
|
||||
content/branding/icon64.png (icon64.png)
|
||||
content/branding/icon128.png (../mozicon128.png)
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<!ENTITY brandShortName "Mozilla Developer Preview">
|
||||
<!ENTITY brandFullName "Mozilla Developer Preview">
|
||||
<!ENTITY vendorShortName "mozilla.org">
|
||||
<!ENTITY trademarkInfo " ">
|
||||
|
||||
<!-- LOCALIZATION NOTE (releaseBaseURL): The about: page appends __MOZ_APP_VERSION__.html, e.g. 2.0.html -->
|
||||
<!ENTITY releaseBaseURL "http://www.mozilla.org/projects/devpreview/releases/">
|
||||
<!ENTITY trademarkInfo.part1 " ">
|
||||
<!ENTITY trademarkInfo.part2 " ">
|
||||
|
|
|
@ -70,6 +70,7 @@ var gAdvancedPane = {
|
|||
#ifdef MOZ_CRASHREPORTER
|
||||
this.initSubmitCrashes();
|
||||
#endif
|
||||
this.updateActualCacheSize();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -190,6 +191,8 @@ var gAdvancedPane = {
|
|||
*
|
||||
* browser.cache.disk.capacity
|
||||
* - the size of the browser cache in KB
|
||||
* browser.cache.disk.smart_size.enabled
|
||||
* - If disabled, disk.capacity is used
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -200,7 +203,50 @@ var gAdvancedPane = {
|
|||
document.documentElement.openSubDialog("chrome://browser/content/preferences/connection.xul",
|
||||
"", null);
|
||||
},
|
||||
|
||||
// Retrieves the amount of space currently used by disk cache
|
||||
updateActualCacheSize: function ()
|
||||
{
|
||||
var visitor = {
|
||||
visitDevice: function (deviceID, deviceInfo)
|
||||
{
|
||||
if (deviceID == "disk") {
|
||||
var actualSizeLabel = document.getElementById("actualCacheSize");
|
||||
var sizeStrings = DownloadUtils.convertByteUnits(deviceInfo.totalSize);
|
||||
var prefStrBundle = document.getElementById("bundlePreferences");
|
||||
var sizeStr = prefStrBundle.getFormattedString("actualCacheSize",
|
||||
sizeStrings);
|
||||
actualSizeLabel.value = sizeStr;
|
||||
}
|
||||
// Do not enumerate entries
|
||||
return false;
|
||||
},
|
||||
|
||||
visitEntry: function (deviceID, entryInfo)
|
||||
{
|
||||
// Do not enumerate entries.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
cacheService.visitEntries(visitor);
|
||||
},
|
||||
|
||||
updateCacheSizeUI: function (smartSizeEnabled)
|
||||
{
|
||||
document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
|
||||
document.getElementById("cacheSize").disabled = smartSizeEnabled;
|
||||
document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
|
||||
},
|
||||
|
||||
readSmartSizeEnabled: function ()
|
||||
{
|
||||
var enabled = document.getElementById("browser.cache.disk.smart_size.enabled").value;
|
||||
this.updateCacheSizeUI(enabled);
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the cache size from units of KB to units of MB and returns that
|
||||
* value.
|
||||
|
@ -232,6 +278,7 @@ var gAdvancedPane = {
|
|||
try {
|
||||
cacheService.evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
} catch(ex) {}
|
||||
this.updateActualCacheSize();
|
||||
},
|
||||
|
||||
readOfflineNotify: function()
|
||||
|
|
|
@ -85,8 +85,12 @@
|
|||
<!-- Network tab -->
|
||||
<preference id="browser.cache.disk.capacity" name="browser.cache.disk.capacity" type="int"/>
|
||||
<preference id="browser.offline-apps.notify" name="browser.offline-apps.notify" type="bool"/>
|
||||
|
||||
<!-- Update tab -->
|
||||
|
||||
<preference id="browser.cache.disk.smart_size.enabled"
|
||||
name="browser.cache.disk.smart_size.enabled"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Update tab -->
|
||||
#ifdef MOZ_UPDATER
|
||||
<preference id="app.update.enabled" name="app.update.enabled" type="bool"
|
||||
onchange="gAdvancedPane.updateAppUpdateItems();
|
||||
|
@ -214,65 +218,71 @@
|
|||
<!-- Network -->
|
||||
<tabpanel id="networkPanel" orient="vertical">
|
||||
|
||||
<!-- Connection -->
|
||||
<groupbox id="connectionGroup">
|
||||
<caption label="&connection.label;"/>
|
||||
<!-- Connection -->
|
||||
<groupbox id="connectionGroup">
|
||||
<caption label="&connection.label;"/>
|
||||
|
||||
<hbox align="center">
|
||||
<description flex="1" control="connectionSettings">&connectionDesc.label;</description>
|
||||
<button id="connectionSettings" icon="network" label="&connectionSettings.label;"
|
||||
accesskey="&connectionSettings.accesskey;"
|
||||
oncommand="gAdvancedPane.showConnections();"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
<hbox align="center">
|
||||
<description flex="1" control="connectionSettings">&connectionDesc.label;</description>
|
||||
<button id="connectionSettings" icon="network" label="&connectionSettings.label;"
|
||||
accesskey="&connectionSettings.accesskey;"
|
||||
oncommand="gAdvancedPane.showConnections();"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- Cache/Offline apps -->
|
||||
<groupbox id="offlineGroup">
|
||||
<caption label="&offlineStorage.label;"/>
|
||||
|
||||
<hbox align="center">
|
||||
<label id="useCacheBefore" control="cacheSize"
|
||||
accesskey="&useCacheBefore.accesskey;" value="&useCacheBefore.label;"/>
|
||||
<textbox id="cacheSize" type="number" size="2"
|
||||
preference="browser.cache.disk.capacity"
|
||||
onsyncfrompreference="return gAdvancedPane.readCacheSize();"
|
||||
onsynctopreference="return gAdvancedPane.writeCacheSize();"
|
||||
aria-labelledby="useCacheBefore cacheSize useCacheAfter"/>
|
||||
<label id="useCacheAfter" flex="1">&useCacheAfter.label;</label>
|
||||
<button id="clearCacheButton" icon="clear"
|
||||
label="&clearCacheNow.label;" accesskey="&clearCacheNow.accesskey;"
|
||||
oncommand="gAdvancedPane.clearCache();"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<checkbox id="offlineNotify" flex="1"
|
||||
label="&offlineNotify.label;" accesskey="&offlineNotify.accesskey;"
|
||||
preference="browser.offline-apps.notify"
|
||||
onsyncfrompreference="return gAdvancedPane.readOfflineNotify();"/>
|
||||
<button id="offlineNotifyExceptions"
|
||||
label="&offlineNotifyExceptions.label;"
|
||||
accesskey="&offlineNotifyExceptions.accesskey;"
|
||||
oncommand="gAdvancedPane.showOfflineExceptions();"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<vbox flex="1">
|
||||
|
||||
<label id="offlineAppsListLabel">&offlineAppsList.label;</label>
|
||||
<listbox id="offlineAppsList"
|
||||
style="height: &offlineAppsList.height;;"
|
||||
flex="1"
|
||||
aria-labelledby="offlineAppsListLabel"
|
||||
onselect="gAdvancedPane.offlineAppSelected(event);">
|
||||
</listbox>
|
||||
</vbox>
|
||||
<vbox pack="end">
|
||||
<button id="offlineAppsListRemove"
|
||||
disabled="true"
|
||||
label="&offlineAppsListRemove.label;"
|
||||
accesskey="&offlineAppsListRemove.accesskey;"
|
||||
oncommand="gAdvancedPane.removeOfflineApp();"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
<!-- Cache/Offline apps -->
|
||||
<groupbox id="offlineGroup">
|
||||
<caption label="&offlineStorage.label;"/>
|
||||
|
||||
<hbox align="center">
|
||||
<label id="actualCacheSize" flex="1"/>
|
||||
<button id="clearCacheButton" icon="clear"
|
||||
label="&clearCacheNow.label;" accesskey="&clearCacheNow.accesskey;"
|
||||
oncommand="gAdvancedPane.clearCache();"/>
|
||||
</hbox>
|
||||
<checkbox preference="browser.cache.disk.smart_size.enabled"
|
||||
id="allowSmartSize" flex="1"
|
||||
onsyncfrompreference="return gAdvancedPane.readSmartSizeEnabled();"
|
||||
label="&smartSizeCache.label;" accesskey="&smartSizeCache.accesskey;"/>
|
||||
<hbox align="center" class="indent">
|
||||
<label id="useCacheBefore" control="cacheSize"
|
||||
accesskey="&useCacheBefore.accesskey;" value="&useCacheBefore.label;"/>
|
||||
<textbox id="cacheSize" type="number" size="4" max="1024"
|
||||
preference="browser.cache.disk.capacity"
|
||||
onsyncfrompreference="return gAdvancedPane.readCacheSize();"
|
||||
onsynctopreference="return gAdvancedPane.writeCacheSize();"
|
||||
aria-labelledby="useCacheBefore cacheSize useCacheAfter"/>
|
||||
<label id="useCacheAfter" flex="1">&useCacheAfter.label;</label>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<checkbox id="offlineNotify" flex="1"
|
||||
label="&offlineNotify.label;" accesskey="&offlineNotify.accesskey;"
|
||||
preference="browser.offline-apps.notify"
|
||||
onsyncfrompreference="return gAdvancedPane.readOfflineNotify();"/>
|
||||
<button id="offlineNotifyExceptions"
|
||||
label="&offlineNotifyExceptions.label;"
|
||||
accesskey="&offlineNotifyExceptions.accesskey;"
|
||||
oncommand="gAdvancedPane.showOfflineExceptions();"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<vbox flex="1">
|
||||
<label id="offlineAppsListLabel">&offlineAppsList.label;</label>
|
||||
<listbox id="offlineAppsList"
|
||||
style="height: &offlineAppsList.height;;"
|
||||
flex="1"
|
||||
aria-labelledby="offlineAppsListLabel"
|
||||
onselect="gAdvancedPane.offlineAppSelected(event);">
|
||||
</listbox>
|
||||
</vbox>
|
||||
<vbox pack="end">
|
||||
<button id="offlineAppsListRemove"
|
||||
disabled="true"
|
||||
label="&offlineAppsListRemove.label;"
|
||||
accesskey="&offlineAppsListRemove.accesskey;"
|
||||
oncommand="gAdvancedPane.removeOfflineApp();"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
|
||||
<!-- Update -->
|
||||
|
|
|
@ -51,6 +51,13 @@ var gMainPane = {
|
|||
// set up the "use current page" label-changing listener
|
||||
this._updateUseCurrentButton();
|
||||
window.addEventListener("focus", this._updateUseCurrentButton, false);
|
||||
|
||||
this.updateBrowserStartupLastSession();
|
||||
|
||||
// Notify observers that the UI is now ready
|
||||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService)
|
||||
.notifyObservers(window, "main-pane-loaded", null);
|
||||
},
|
||||
|
||||
// HOME PAGE
|
||||
|
@ -74,6 +81,35 @@ var gMainPane = {
|
|||
* option is preserved.
|
||||
*/
|
||||
|
||||
syncFromHomePref: function ()
|
||||
{
|
||||
let homePref = document.getElementById("browser.startup.homepage");
|
||||
|
||||
// If the pref is set to about:home, set the value to "" to show the
|
||||
// placeholder text (about:home title).
|
||||
if (homePref.value.toLowerCase() == "about:home")
|
||||
return "";
|
||||
|
||||
// If the pref is actually "", show about:blank. The actual home page
|
||||
// loading code treats them the same, and we don't want the placeholder text
|
||||
// to be shown.
|
||||
if (homePref.value == "")
|
||||
return "about:blank";
|
||||
|
||||
// Otherwise, show the actual pref value.
|
||||
return undefined;
|
||||
},
|
||||
|
||||
syncToHomePref: function (value)
|
||||
{
|
||||
// If the value is "", use about:home.
|
||||
if (value == "")
|
||||
return "about:home";
|
||||
|
||||
// Otherwise, use the actual textbox value.
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the home page to the current displayed page (or frontmost tab, if the
|
||||
* most recent browser window contains multiple tabs), updating preference
|
||||
|
@ -462,5 +498,26 @@ var gMainPane = {
|
|||
showAddonsMgr: function ()
|
||||
{
|
||||
openUILinkIn("about:addons", "window");
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide/show the "Show my windows and tabs from last time" option based
|
||||
* on the value of the browser.privatebrowsing.autostart pref.
|
||||
*/
|
||||
updateBrowserStartupLastSession: function()
|
||||
{
|
||||
let pbAutoStartPref = document.getElementById("browser.privatebrowsing.autostart");
|
||||
let startupPref = document.getElementById("browser.startup.page");
|
||||
let menu = document.getElementById("browserStartupPage");
|
||||
let option = document.getElementById("browserStartupLastSession");
|
||||
if (pbAutoStartPref.value) {
|
||||
option.setAttribute("disabled", "true");
|
||||
if (option.selected) {
|
||||
menu.selectedItem = document.getElementById("browserStartupHomePage");
|
||||
}
|
||||
} else {
|
||||
option.removeAttribute("disabled");
|
||||
startupPref.updateElements(); // select the correct index in the startup menulist
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -43,8 +43,10 @@
|
|||
<!DOCTYPE overlay [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
<!ENTITY % mainDTD SYSTEM "chrome://browser/locale/preferences/main.dtd">
|
||||
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
|
||||
%brandDTD;
|
||||
%mainDTD;
|
||||
%aboutHomeDTD;
|
||||
]>
|
||||
|
||||
<overlay id="MainPaneOverlay"
|
||||
|
@ -77,6 +79,11 @@
|
|||
name="pref.browser.homepage.disable_button.restore_default"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.privatebrowsing.autostart"
|
||||
name="browser.privatebrowsing.autostart"
|
||||
type="bool"
|
||||
onchange="gMainPane.updateBrowserStartupLastSession();"/>
|
||||
|
||||
<!-- Downloads -->
|
||||
<preference id="browser.download.manager.showWhenStarting"
|
||||
name="browser.download.manager.showWhenStarting"
|
||||
|
@ -107,17 +114,20 @@
|
|||
control="browserStartupPage"/>
|
||||
<menulist id="browserStartupPage" preference="browser.startup.page">
|
||||
<menupopup>
|
||||
<menuitem label="&startupHomePage.label;" value="1"/>
|
||||
<menuitem label="&startupBlankPage.label;" value="0"/>
|
||||
<menuitem label="&startupLastSession.label;" value="3"/>
|
||||
<menuitem label="&startupHomePage.label;" value="1" id="browserStartupHomePage"/>
|
||||
<menuitem label="&startupBlankPage.label;" value="0" id="browserStartupBlank"/>
|
||||
<menuitem label="&startupLastSession.label;" value="3" id="browserStartupLastSession"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
<separator class="thin"/>
|
||||
<hbox align="center">
|
||||
<label value="&location.label;" accesskey="&location.accesskey;" control="browserHomePage"/>
|
||||
<label value="&homepage.label;" accesskey="&homepage.accesskey;" control="browserHomePage"/>
|
||||
<textbox id="browserHomePage" class="padded uri-element" flex="1"
|
||||
type="autocomplete" autocompletesearch="history"
|
||||
onsyncfrompreference="return gMainPane.syncFromHomePref();"
|
||||
onsynctopreference="return gMainPane.syncToHomePref(this.value);"
|
||||
placeholder="&abouthome.pageTitle;"
|
||||
preference="browser.startup.homepage"/>
|
||||
</hbox>
|
||||
<hbox align="center" pack="end">
|
||||
|
|
|
@ -119,7 +119,7 @@ let gSyncPane = {
|
|||
this.page = PAGE_NO_ACCOUNT;
|
||||
else {
|
||||
this.page = PAGE_HAS_ACCOUNT;
|
||||
document.getElementById("currentUser").value = Weave.Service.username;
|
||||
document.getElementById("currentAccount").value = Weave.Service.account;
|
||||
document.getElementById("syncComputerName").value = Weave.Clients.localName;
|
||||
if (Weave.Status.service == Weave.LOGIN_FAILED)
|
||||
this.onLoginError();
|
||||
|
@ -144,7 +144,7 @@ let gSyncPane = {
|
|||
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL;
|
||||
let buttonChoice =
|
||||
Services.prompt.confirmEx(window,
|
||||
this._stringBundle.GetStringFromName("differentAccount.title"),
|
||||
this._stringBundle.GetStringFromName("stopUsingAccount.title"),
|
||||
this._stringBundle.GetStringFromName("differentAccount.label"),
|
||||
flags,
|
||||
this._stringBundle.GetStringFromName("differentAccountConfirm.label"),
|
||||
|
@ -206,6 +206,15 @@ let gSyncPane = {
|
|||
}
|
||||
},
|
||||
|
||||
openQuotaDialog: function () {
|
||||
let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
|
||||
if (win)
|
||||
win.focus();
|
||||
else
|
||||
window.openDialog("chrome://browser/content/syncQuota.xul", "",
|
||||
"centerscreen,chrome,dialog,modal");
|
||||
},
|
||||
|
||||
resetSync: function () {
|
||||
this.openSetup(true);
|
||||
}
|
||||
|
|
|
@ -90,8 +90,8 @@
|
|||
<grid>
|
||||
<rows>
|
||||
<row align="center">
|
||||
<label value="¤tUser.label;" control="currentUser"/>
|
||||
<textbox id="currentUser" readonly="true">
|
||||
<label value="¤tAccount.label;" control="currentAccount"/>
|
||||
<textbox id="currentAccount" readonly="true">
|
||||
<image/>
|
||||
</textbox>
|
||||
<hbox align="center">
|
||||
|
@ -117,6 +117,9 @@
|
|||
<row id="manageAccountControls" hidden="true">
|
||||
<spacer/>
|
||||
<vbox class="indent">
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.openQuotaDialog(); return false;"
|
||||
value="&viewQuota.label;"/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncUtils.changePassword(); return false;"
|
||||
value="&changePassword.label;"/>
|
||||
|
@ -128,7 +131,7 @@
|
|||
value="&resetSync.label;"/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.startOver(true); return false;"
|
||||
value="&differentAccount.label;"/>
|
||||
value="&stopUsingAccount.label;"/>
|
||||
</vbox>
|
||||
<spacer/>
|
||||
</row>
|
||||
|
@ -189,7 +192,7 @@
|
|||
onclick="event.stopPropagation();gSyncUtils.openToS();"
|
||||
value="&prefs.tosLink.label;"/>
|
||||
<label class="text-link"
|
||||
onclick="event.stopPropagation();gSyncUtils.openPP();"
|
||||
onclick="event.stopPropagation();gSyncUtils.openPrivacyPolicy();"
|
||||
value="&prefs.ppLink.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
|
|
@ -45,6 +45,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_BROWSER_FILES = \
|
||||
browser_bug410900.js \
|
||||
browser_bug567487.js \
|
||||
privacypane_tests.js \
|
||||
browser_privacypane_1.js \
|
||||
browser_privacypane_2.js \
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
function observer(win, topic, data) {
|
||||
if (topic != "main-pane-loaded")
|
||||
return;
|
||||
|
||||
Services.obs.removeObserver(observer, "main-pane-loaded");
|
||||
runTest(win);
|
||||
}
|
||||
Services.obs.addObserver(observer, "main-pane-loaded", false);
|
||||
|
||||
openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
|
||||
"chrome,titlebar,toolbar,centerscreen,dialog=no", "paneMain");
|
||||
}
|
||||
|
||||
function runTest(win) {
|
||||
let doc = win.document;
|
||||
let pbAutoStartPref = doc.getElementById("browser.privatebrowsing.autostart");
|
||||
let startupPref = doc.getElementById("browser.startup.page");
|
||||
let menu = doc.getElementById("browserStartupPage");
|
||||
let option = doc.getElementById("browserStartupLastSession");
|
||||
let defOption = doc.getElementById("browserStartupHomePage");
|
||||
let otherOption = doc.getElementById("browserStartupBlank");
|
||||
|
||||
ok(!pbAutoStartPref.value, "Sanity check");
|
||||
is(startupPref.value, startupPref.defaultValue, "Sanity check");
|
||||
|
||||
// First, check to make sure that setting pbAutoStartPref disables the menu item
|
||||
pbAutoStartPref.value = true;
|
||||
is(option.getAttribute("disabled"), "true", "Setting private browsing to autostart " +
|
||||
"should disable the 'Show my tabs and windows from last time' option");
|
||||
pbAutoStartPref.value = false;
|
||||
|
||||
// Now ensure the correct behavior when pbAutoStartPref is set with option enabled
|
||||
startupPref.value = option.getAttribute("value");
|
||||
is(menu.selectedItem, option, "Sanity check");
|
||||
pbAutoStartPref.value = true;
|
||||
is(option.getAttribute("disabled"), "true", "Setting private browsing to autostart " +
|
||||
"should disable the 'Show my tabs and windows from last time' option");
|
||||
is(menu.selectedItem, defOption, "The 'Show home page' option should be selected");
|
||||
is(startupPref.value, option.getAttribute("value"), "But the value of the startup " +
|
||||
"pref itself shouldn't change");
|
||||
menu.selectedItem = otherOption;
|
||||
menu.doCommand();
|
||||
is(startupPref.value, otherOption.getAttribute("value"), "And we should be able to " +
|
||||
"chnage it!");
|
||||
pbAutoStartPref.value = false;
|
||||
|
||||
// Now, ensure that with 'Show my windows and tabs from last time' enabled, toggling
|
||||
// pbAutoStartPref would restore that value in the menulist.
|
||||
startupPref.value = option.getAttribute("value");
|
||||
is(menu.selectedItem, option, "Sanity check");
|
||||
pbAutoStartPref.value = true;
|
||||
is(menu.selectedItem, defOption, "The 'Show home page' option should be selected");
|
||||
pbAutoStartPref.value = false;
|
||||
is(menu.selectedItem, option, "The correct value should be restored");
|
||||
|
||||
// cleanup
|
||||
[pbAutoStartPref, startupPref].forEach(function (pref) {
|
||||
if (pref.hasUserValue)
|
||||
pref.reset();
|
||||
});
|
||||
|
||||
win.close();
|
||||
finish();
|
||||
}
|
|
@ -45,6 +45,13 @@
|
|||
%globalDTD;
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
||||
%browserDTD;
|
||||
#ifdef XP_WIN
|
||||
<!ENTITY basePBMenu.label "<span class='appMenuButton'>&brandShortName;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
|
||||
#elifdef XP_MACOSX
|
||||
<!ENTITY basePBMenu.label "&toolsMenu.label;">
|
||||
#else
|
||||
<!ENTITY basePBMenu.label "<span class='appMenuButton'>&appMenuButton.label;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
|
||||
#endif
|
||||
<!ENTITY % privatebrowsingpageDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
|
||||
%privatebrowsingpageDTD;
|
||||
]>
|
||||
|
@ -58,6 +65,12 @@
|
|||
body.private .showNormal {
|
||||
display: none;
|
||||
}
|
||||
body.appMenuButtonVisible .toolsMenu {
|
||||
display: none;
|
||||
}
|
||||
body.appMenuButtonInvisible .appMenuButton {
|
||||
display: none;
|
||||
}
|
||||
]]></style>
|
||||
<script type="application/javascript;version=1.7"><![CDATA[
|
||||
const Cc = Components.classes;
|
||||
|
@ -113,6 +126,13 @@
|
|||
let moreInfoLink = document.getElementById("moreInfoLink");
|
||||
if (moreInfoLink)
|
||||
moreInfoLink.setAttribute("href", moreInfoURL + "private-browsing");
|
||||
|
||||
// Show the correct menu structure based on whether the App Menu button is
|
||||
// shown or not.
|
||||
var menuBar = mainWindow.document.getElementById("toolbar-menubar");
|
||||
var appMenuButtonIsVisible = menuBar.getAttribute("autohide") == "true";
|
||||
document.body.classList.add(appMenuButtonIsVisible ? "appMenuButtonVisible" :
|
||||
"appMenuButtonInvisible");
|
||||
}, false);
|
||||
|
||||
function togglePrivateBrowsing() {
|
||||
|
@ -157,8 +177,8 @@
|
|||
|
||||
<!-- Footer -->
|
||||
<div id="footerDesc">
|
||||
<p id="footerText" class="showPrivate">&privatebrowsingpage.howToStop;</p>
|
||||
<p id="footerTextNormal" class="showNormal">&privatebrowsingpage.howToStart;</p>
|
||||
<p id="footerText" class="showPrivate">&privatebrowsingpage.howToStop2;</p>
|
||||
<p id="footerTextNormal" class="showNormal">&privatebrowsingpage.howToStart2;</p>
|
||||
</div>
|
||||
|
||||
<!-- More Info -->
|
||||
|
|
|
@ -45,6 +45,12 @@ function test() {
|
|||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
|
||||
// clear the history of closed windows (that other tests have created)
|
||||
// to avoid the issue in bug 596592
|
||||
// XXX remove this when bug 597071 is fixed
|
||||
while (ss.getClosedWindowCount())
|
||||
ss.forgetClosedWindow(0);
|
||||
|
||||
// backup our state
|
||||
let stateBackup = ss.getWindowState(window);
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
os.addObserver(this, "browser-search-engine-modified", false);
|
||||
|
||||
|
||||
this._addedObserver = true;
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -275,7 +275,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
BrowserSearch.updateSearchButton();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -303,7 +302,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
BrowserSearch.updateSearchButton();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -581,15 +579,30 @@
|
|||
var cxmenu = document.getAnonymousElementByAttribute(textBox,
|
||||
"anonid", "input-box-contextmenu");
|
||||
|
||||
var element = document.createElementNS(kXULNS, "menuseparator");
|
||||
var element, label, akey;
|
||||
|
||||
element = document.createElementNS(kXULNS, "menuseparator");
|
||||
cxmenu.appendChild(element);
|
||||
|
||||
var insertLocation = cxmenu.firstChild;
|
||||
while (insertLocation.nextSibling &&
|
||||
insertLocation.getAttribute("cmd") != "cmd_paste")
|
||||
insertLocation = insertLocation.nextSibling;
|
||||
if (insertLocation) {
|
||||
element = document.createElementNS(kXULNS, "menuitem");
|
||||
label = this._stringBundle.getString("cmd_pasteAndSearch");
|
||||
element.setAttribute("label", label);
|
||||
element.setAttribute("cmd", "cmd_paste");
|
||||
element.setAttribute("oncommand", "goDoCommand('cmd_paste'); document.getElementById('searchbar').handleSearchCommand();");
|
||||
cxmenu.insertBefore(element, insertLocation.nextSibling);
|
||||
}
|
||||
|
||||
element = document.createElementNS(kXULNS, "menuitem");
|
||||
var label = this._stringBundle.getString("cmd_clearHistory");
|
||||
var akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
|
||||
label = this._stringBundle.getString("cmd_clearHistory");
|
||||
akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
|
||||
element.setAttribute("label", label);
|
||||
element.setAttribute("accesskey", akey);
|
||||
element.setAttribute("cmd", "cmd_clearhistory");
|
||||
|
||||
cxmenu.appendChild(element);
|
||||
|
||||
element = document.createElementNS(kXULNS, "menuitem");
|
||||
|
@ -602,7 +615,6 @@
|
|||
element.setAttribute("type", "checkbox");
|
||||
element.setAttribute("checked", this._suggestEnabled);
|
||||
element.setAttribute("autocheck", "false");
|
||||
|
||||
this._suggestMenuItem = element;
|
||||
cxmenu.appendChild(element);
|
||||
|
||||
|
@ -631,7 +643,7 @@
|
|||
popup.mInput = this;
|
||||
popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
|
||||
popup.invalidate();
|
||||
|
||||
|
||||
popup.showCommentColumn = this.showCommentColumn;
|
||||
popup.showImageColumn = this.showImageColumn;
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ const CAPABILITIES = [
|
|||
// that gets saved to disk nor part of the strings returned by the API.
|
||||
const INTERNAL_KEYS = ["_tabStillLoading", "_hosts", "_formDataSaved"];
|
||||
|
||||
// These are tab events that we listen to.
|
||||
const TAB_EVENTS = ["TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide"];
|
||||
|
||||
#ifndef XP_WIN
|
||||
#define BROKEN_WM_Z_ORDER
|
||||
#endif
|
||||
|
@ -201,6 +204,13 @@ SessionStoreService.prototype = {
|
|||
// whether the last window was closed and should be restored
|
||||
_restoreLastWindow: false,
|
||||
|
||||
// tabs to restore in order
|
||||
_tabsToRestore: { visible: [], hidden: [] },
|
||||
_tabsRestoringCount: 0,
|
||||
|
||||
// number of tabs to restore concurrently, pref controlled.
|
||||
_maxConcurrentTabRestores: null,
|
||||
|
||||
// The state from the previous session (after restoring pinned tabs)
|
||||
_lastSessionState: null,
|
||||
|
||||
|
@ -259,6 +269,14 @@ SessionStoreService.prototype = {
|
|||
this._sessionhistory_max_entries =
|
||||
this._prefBranch.getIntPref("sessionhistory.max_entries");
|
||||
|
||||
this._maxConcurrentTabRestores =
|
||||
this._prefBranch.getIntPref("sessionstore.max_concurrent_tabs");
|
||||
this._prefBranch.addObserver("sessionstore.max_concurrent_tabs", this, true);
|
||||
|
||||
// Make sure gRestoreTabsProgressListener has a reference to sessionstore
|
||||
// so that it can make calls back in
|
||||
gRestoreTabsProgressListener.ss = this;
|
||||
|
||||
// get file references
|
||||
this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
||||
this._sessionFileBackup = this._sessionFile.clone();
|
||||
|
@ -348,6 +366,13 @@ SessionStoreService.prototype = {
|
|||
// save all data for session resuming
|
||||
this.saveState(true);
|
||||
|
||||
// clear out _tabsToRestore in case it's still holding refs
|
||||
this._tabsToRestore.visible = null;
|
||||
this._tabsToRestore.hidden = null;
|
||||
|
||||
// remove the ref to us from the progress listener
|
||||
gRestoreTabsProgressListener.ss = null;
|
||||
|
||||
// Make sure to break our cycle with the save timer
|
||||
if (this._saveTimer) {
|
||||
this._saveTimer.cancel();
|
||||
|
@ -403,6 +428,7 @@ SessionStoreService.prototype = {
|
|||
this._forEachBrowserWindow(function(aWindow) {
|
||||
Array.forEach(aWindow.gBrowser.browsers, function(aBrowser) {
|
||||
delete aBrowser.__SS_data;
|
||||
delete aBrowser.__SS_needsRestore;
|
||||
});
|
||||
openWindows[aWindow.__SSi] = true;
|
||||
});
|
||||
|
@ -507,6 +533,10 @@ SessionStoreService.prototype = {
|
|||
this._clearDisk();
|
||||
this.saveState(true);
|
||||
break;
|
||||
case "sessionstore.max_concurrent_tabs":
|
||||
this._maxConcurrentTabRestores =
|
||||
this._prefBranch.getIntPref("sessionstore.max_concurrent_tabs");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "timer-callback": // timer call back for delayed saving
|
||||
|
@ -547,6 +577,9 @@ SessionStoreService.prototype = {
|
|||
// to objects that can change (specifically this._windows[x]).
|
||||
this._stateBackup = JSON.parse(this._toJSONString(this._getCurrentState(true)));
|
||||
}
|
||||
// Make sure _tabsToRestore is cleared. It will be repopulated when
|
||||
// entering/exiting private browsing (by calls to setBrowserState).
|
||||
this._resetRestoringState();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -575,21 +608,23 @@ SessionStoreService.prototype = {
|
|||
this.onTabInput(win, aEvent.currentTarget);
|
||||
break;
|
||||
case "TabOpen":
|
||||
this.onTabAdd(win, aEvent.originalTarget);
|
||||
break;
|
||||
case "TabClose":
|
||||
let browser = aEvent.originalTarget.linkedBrowser;
|
||||
if (aEvent.type == "TabOpen") {
|
||||
this.onTabAdd(win, browser);
|
||||
}
|
||||
else {
|
||||
// aEvent.detail determines if the tab was closed by moving to a different window
|
||||
if (!aEvent.detail)
|
||||
this.onTabClose(win, aEvent.originalTarget);
|
||||
this.onTabRemove(win, browser);
|
||||
}
|
||||
// aEvent.detail determines if the tab was closed by moving to a different window
|
||||
if (!aEvent.detail)
|
||||
this.onTabClose(win, aEvent.originalTarget);
|
||||
this.onTabRemove(win, aEvent.originalTarget);
|
||||
break;
|
||||
case "TabSelect":
|
||||
this.onTabSelect(win);
|
||||
break;
|
||||
case "TabShow":
|
||||
this.onTabShow(aEvent.originalTarget);
|
||||
break;
|
||||
case "TabHide":
|
||||
this.onTabHide(aEvent.originalTarget);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -692,13 +727,13 @@ SessionStoreService.prototype = {
|
|||
var tabbrowser = aWindow.gBrowser;
|
||||
|
||||
// add tab change listeners to all already existing tabs
|
||||
for (let i = 0; i < tabbrowser.browsers.length; i++) {
|
||||
this.onTabAdd(aWindow, tabbrowser.browsers[i], true);
|
||||
for (let i = 0; i < tabbrowser.tabs.length; i++) {
|
||||
this.onTabAdd(aWindow, tabbrowser.tabs[i], true);
|
||||
}
|
||||
// notification of tab add/remove/selection
|
||||
tabbrowser.tabContainer.addEventListener("TabOpen", this, true);
|
||||
tabbrowser.tabContainer.addEventListener("TabClose", this, true);
|
||||
tabbrowser.tabContainer.addEventListener("TabSelect", this, true);
|
||||
// notification of tab add/remove/selection/show/hide
|
||||
TAB_EVENTS.forEach(function(aEvent) {
|
||||
tabbrowser.tabContainer.addEventListener(aEvent, this, true);
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -730,10 +765,13 @@ SessionStoreService.prototype = {
|
|||
|
||||
var tabbrowser = aWindow.gBrowser;
|
||||
|
||||
tabbrowser.tabContainer.removeEventListener("TabOpen", this, true);
|
||||
tabbrowser.tabContainer.removeEventListener("TabClose", this, true);
|
||||
tabbrowser.tabContainer.removeEventListener("TabSelect", this, true);
|
||||
|
||||
TAB_EVENTS.forEach(function(aEvent) {
|
||||
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
||||
}, this);
|
||||
|
||||
// remove the progress listener for this window
|
||||
tabbrowser.removeTabsProgressListener(gRestoreTabsProgressListener);
|
||||
|
||||
let winData = this._windows[aWindow.__SSi];
|
||||
if (this._loadState == STATE_RUNNING) { // window not closed during a regular shut-down
|
||||
// update all window data for a last time
|
||||
|
@ -760,8 +798,8 @@ SessionStoreService.prototype = {
|
|||
this.saveStateDelayed();
|
||||
}
|
||||
|
||||
for (let i = 0; i < tabbrowser.browsers.length; i++) {
|
||||
this.onTabRemove(aWindow, tabbrowser.browsers[i], true);
|
||||
for (let i = 0; i < tabbrowser.tabs.length; i++) {
|
||||
this.onTabRemove(aWindow, tabbrowser.tabs[i], true);
|
||||
}
|
||||
|
||||
// cache the window state until the window is completely gone
|
||||
|
@ -774,18 +812,19 @@ SessionStoreService.prototype = {
|
|||
* set up listeners for a new tab
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
* @param aBrowser
|
||||
* Browser reference
|
||||
* @param aTab
|
||||
* Tab reference
|
||||
* @param aNoNotification
|
||||
* bool Do not save state if we're updating an existing tab
|
||||
*/
|
||||
onTabAdd: function sss_onTabAdd(aWindow, aBrowser, aNoNotification) {
|
||||
aBrowser.addEventListener("load", this, true);
|
||||
aBrowser.addEventListener("pageshow", this, true);
|
||||
aBrowser.addEventListener("change", this, true);
|
||||
aBrowser.addEventListener("input", this, true);
|
||||
aBrowser.addEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
onTabAdd: function sss_onTabAdd(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("load", this, true);
|
||||
browser.addEventListener("pageshow", this, true);
|
||||
browser.addEventListener("change", this, true);
|
||||
browser.addEventListener("input", this, true);
|
||||
browser.addEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
|
@ -797,20 +836,33 @@ SessionStoreService.prototype = {
|
|||
* remove listeners for a tab
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
* @param aBrowser
|
||||
* Browser reference
|
||||
* @param aTab
|
||||
* Tab reference
|
||||
* @param aNoNotification
|
||||
* bool Do not save state if we're updating an existing tab
|
||||
*/
|
||||
onTabRemove: function sss_onTabRemove(aWindow, aBrowser, aNoNotification) {
|
||||
aBrowser.removeEventListener("load", this, true);
|
||||
aBrowser.removeEventListener("pageshow", this, true);
|
||||
aBrowser.removeEventListener("change", this, true);
|
||||
aBrowser.removeEventListener("input", this, true);
|
||||
aBrowser.removeEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
delete aBrowser.__SS_data;
|
||||
|
||||
onTabRemove: function sss_onTabRemove(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.removeEventListener("load", this, true);
|
||||
browser.removeEventListener("pageshow", this, true);
|
||||
browser.removeEventListener("change", this, true);
|
||||
browser.removeEventListener("input", this, true);
|
||||
browser.removeEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
delete browser.__SS_data;
|
||||
|
||||
// If this tab was in the middle of restoring, we want to restore the next
|
||||
// tab. If the tab hasn't been restored, we want to remove it from the array.
|
||||
if (browser.__SS_restoring) {
|
||||
this.restoreNextTab(true);
|
||||
}
|
||||
else if (browser.__SS_needsRestore) {
|
||||
if (aTab.hidden)
|
||||
this._tabsToRestore.hidden.splice(this._tabsToRestore.hidden.indexOf(aTab));
|
||||
else
|
||||
this._tabsToRestore.visible.splice(this._tabsToRestore.visible.indexOf(aTab));
|
||||
}
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
|
@ -904,11 +956,37 @@ SessionStoreService.prototype = {
|
|||
if (this._loadState == STATE_RUNNING) {
|
||||
this._windows[aWindow.__SSi].selected = aWindow.gBrowser.tabContainer.selectedIndex;
|
||||
|
||||
let tab = aWindow.gBrowser.selectedTab;
|
||||
// If __SS_needsRestore is still on the browser, then we haven't restored
|
||||
// this tab yet. Explicitly call restoreTab to kick off the restore.
|
||||
if (tab.linkedBrowser.__SS_needsRestore) {
|
||||
this._tabsToRestore.visible.splice(this._tabsToRestore.visible.indexOf(tab));
|
||||
this.restoreTab(tab);
|
||||
}
|
||||
|
||||
// attempt to update the current URL we send in a crash report
|
||||
this._updateCrashReportURL(aWindow);
|
||||
}
|
||||
},
|
||||
|
||||
onTabShow: function sss_onTabShow(aTab) {
|
||||
// If the tab hasn't been restored yet, move it into the right _tabsToRestore bucket
|
||||
if (aTab.linkedBrowser.__SS_needsRestore) {
|
||||
this._tabsToRestore.hidden.splice(this._tabsToRestore.hidden.indexOf(aTab));
|
||||
// Just put it at the end of the list of visible tabs;
|
||||
this._tabsToRestore.visible.push(aTab);
|
||||
}
|
||||
},
|
||||
|
||||
onTabHide: function sss_onTabHide(aTab) {
|
||||
// If the tab hasn't been restored yet, move it into the right _tabsToRestore bucket
|
||||
if (aTab.linkedBrowser.__SS_needsRestore) {
|
||||
this._tabsToRestore.visible.splice(this._tabsToRestore.visible.indexOf(aTab));
|
||||
// Just put it at the end of the list of hidden tabs;
|
||||
this._tabsToRestore.hidden.push(aTab);
|
||||
}
|
||||
},
|
||||
|
||||
/* ........ nsISessionStore API .............. */
|
||||
|
||||
getBrowserState: function sss_getBrowserState() {
|
||||
|
@ -927,6 +1005,9 @@ SessionStoreService.prototype = {
|
|||
|
||||
this._browserSetState = true;
|
||||
|
||||
// Make sure _tabsToRestore is emptied out
|
||||
this._resetRestoringState();
|
||||
|
||||
var window = this._getMostRecentBrowserWindow();
|
||||
if (!window) {
|
||||
this._restoreCount = 1;
|
||||
|
@ -2175,7 +2256,14 @@ SessionStoreService.prototype = {
|
|||
restoreHistoryPrecursor:
|
||||
function sss_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount) {
|
||||
var tabbrowser = aWindow.gBrowser;
|
||||
|
||||
|
||||
// In order for setTabState to add gTabsProgressListener, we want to add it
|
||||
// here. We'll only attempt to do it when aCount == 0 though so we don't add
|
||||
// it multiple times.
|
||||
if (aCount == 0 &&
|
||||
tabbrowser.mTabsProgressListeners.indexOf(gRestoreTabsProgressListener) == -1)
|
||||
tabbrowser.addTabsProgressListener(gRestoreTabsProgressListener);
|
||||
|
||||
// make sure that all browsers and their histories are available
|
||||
// - if one's not, resume this check in 100ms (repeat at most 10 times)
|
||||
for (var t = aIx; t < aTabs.length; t++) {
|
||||
|
@ -2208,6 +2296,12 @@ SessionStoreService.prototype = {
|
|||
tab.hidden = tabData.hidden;
|
||||
|
||||
tabData._tabStillLoading = true;
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
browser.__SS_data = tabData;
|
||||
browser.__SS_needsRestore = true;
|
||||
|
||||
if (!tabData.entries || tabData.entries.length == 0) {
|
||||
// make sure to blank out this tab's content
|
||||
// (just purging the tab's history won't be enough)
|
||||
|
@ -2219,17 +2313,16 @@ SessionStoreService.prototype = {
|
|||
|
||||
tab.setAttribute("busy", "true");
|
||||
tabbrowser.updateIcon(tab);
|
||||
tabbrowser.setTabTitleLoading(tab);
|
||||
|
||||
// wall-paper fix for bug 439675: make sure that the URL to be loaded
|
||||
// is always visible in the address bar
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
let activePageData = tabData.entries[activeIndex] || null;
|
||||
browser.userTypedValue = activePageData ? activePageData.url || null : null;
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
browser.__SS_data = tabData;
|
||||
|
||||
// If the page has a title, set it.
|
||||
if (activePageData && activePageData.title)
|
||||
tab.label = activePageData.title;
|
||||
}
|
||||
|
||||
if (aTabs.length > 0) {
|
||||
|
@ -2358,39 +2451,124 @@ SessionStoreService.prototype = {
|
|||
var event = aWindow.document.createEvent("Events");
|
||||
event.initEvent("SSTabRestoring", true, false);
|
||||
tab.dispatchEvent(event);
|
||||
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
if (activeIndex >= tabData.entries.length)
|
||||
activeIndex = tabData.entries.length - 1;
|
||||
try {
|
||||
if (activeIndex >= 0)
|
||||
browser.webNavigation.gotoIndex(activeIndex);
|
||||
}
|
||||
catch (ex) {
|
||||
// ignore page load errors
|
||||
tab.removeAttribute("busy");
|
||||
}
|
||||
|
||||
if (tabData.entries.length > 0) {
|
||||
// restore those aspects of the currently active documents
|
||||
// which are not preserved in the plain history entries
|
||||
// (mainly scroll state and text data)
|
||||
browser.__SS_restore_data = tabData.entries[activeIndex] || {};
|
||||
browser.__SS_restore_pageStyle = tabData.pageStyle || "";
|
||||
browser.__SS_restore_tab = tab;
|
||||
}
|
||||
|
||||
// Handle userTypedValue. Setting userTypedValue seems to update gURLbar
|
||||
// as needed. Calling loadURI will cancel form filling in restoreDocument_proxy
|
||||
if (tabData.userTypedValue) {
|
||||
browser.userTypedValue = tabData.userTypedValue;
|
||||
if (tabData.userTypedClear)
|
||||
browser.loadURI(tabData.userTypedValue, null, null, true);
|
||||
}
|
||||
|
||||
// Restore the history in the next tab
|
||||
aWindow.setTimeout(function(){
|
||||
_this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap);
|
||||
}, 0);
|
||||
|
||||
// This could cause us to ignore the max_concurrent_tabs pref a bit, but
|
||||
// it ensures each window will have its selected tab loaded.
|
||||
if (aWindow.gBrowser.selectedBrowser == browser) {
|
||||
this.restoreTab(tab);
|
||||
}
|
||||
else {
|
||||
// Put the tab into the right bucket
|
||||
if (tabData.hidden)
|
||||
this._tabsToRestore.hidden.push(tab);
|
||||
else
|
||||
this._tabsToRestore.visible.push(tab);
|
||||
this.restoreNextTab();
|
||||
}
|
||||
},
|
||||
|
||||
restoreTab: function(aTab) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
let tabData = browser.__SS_data;
|
||||
|
||||
// There are cases within where we haven't actually started a load and so we
|
||||
// should call restoreNextTab. We don't want to do it immediately though
|
||||
// since we might not set userTypedValue in a timely fashion.
|
||||
let shouldRestoreNextTab = false;
|
||||
|
||||
// Increase our internal count.
|
||||
this._tabsRestoringCount++;
|
||||
|
||||
delete browser.__SS_needsRestore;
|
||||
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
if (activeIndex >= tabData.entries.length)
|
||||
activeIndex = tabData.entries.length - 1;
|
||||
|
||||
// Attach data that will be restored on "load" event, after tab is restored.
|
||||
if (activeIndex > -1) {
|
||||
// restore those aspects of the currently active documents which are not
|
||||
// preserved in the plain history entries (mainly scroll state and text data)
|
||||
browser.__SS_restore_data = tabData.entries[activeIndex] || {};
|
||||
browser.__SS_restore_pageStyle = tabData.pageStyle || "";
|
||||
browser.__SS_restore_tab = aTab;
|
||||
|
||||
try {
|
||||
// Get the tab title (set in restoreHistoryPrecursor) for later
|
||||
let label = aTab.label;
|
||||
browser.__SS_restoring = true;
|
||||
browser.webNavigation.gotoIndex(activeIndex);
|
||||
// gotoIndex will force the "loading" string, so set the title
|
||||
aTab.label = label;
|
||||
}
|
||||
catch (ex) {
|
||||
// ignore page load errors
|
||||
aTab.removeAttribute("busy");
|
||||
shouldRestoreNextTab = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If there is no active index, then we'll never set __SS_restore_data
|
||||
// and even if there is a load event, we won't kick of the next tab
|
||||
// (restoreDocument won't get called), so do it ourselves.
|
||||
shouldRestoreNextTab = true;
|
||||
}
|
||||
|
||||
// Handle userTypedValue. Setting userTypedValue seems to update gURLbar
|
||||
// as needed. Calling loadURI will cancel form filling in restoreDocument
|
||||
if (tabData.userTypedValue) {
|
||||
browser.userTypedValue = tabData.userTypedValue;
|
||||
if (tabData.userTypedClear) {
|
||||
browser.__SS_restoring = true;
|
||||
browser.loadURI(tabData.userTypedValue, null, null, true);
|
||||
}
|
||||
else {
|
||||
shouldRestoreNextTab = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldRestoreNextTab)
|
||||
this.restoreNextTab(true);
|
||||
},
|
||||
|
||||
restoreNextTab: function sss_restoreNextTab(aFromTabFinished) {
|
||||
// If we call in here while quitting, we don't actually want to do anything
|
||||
if (this._loadState == STATE_QUITTING)
|
||||
return;
|
||||
if (aFromTabFinished)
|
||||
this._tabsRestoringCount--;
|
||||
|
||||
// If it's not possible to restore anything, then just bail out.
|
||||
if (this._maxConcurrentTabRestores >= 0 &&
|
||||
this._tabsRestoringCount >= this._maxConcurrentTabRestores)
|
||||
return;
|
||||
|
||||
// Look in visible, then hidden
|
||||
let nextTabArray;
|
||||
if (this._tabsToRestore.visible.length) {
|
||||
nextTabArray = this._tabsToRestore.visible;
|
||||
}
|
||||
else if (this._tabsToRestore.hidden.length) {
|
||||
nextTabArray = this._tabsToRestore.hidden;
|
||||
}
|
||||
|
||||
if (nextTabArray) {
|
||||
let tab = nextTabArray.shift();
|
||||
this.restoreTab(tab);
|
||||
}
|
||||
else {
|
||||
// Remove the progress listener from windows. It will get re-added as needed.
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
// This won't fail since removeTabsProgressListener just filters. It
|
||||
// doesn't attempt to splice.
|
||||
aWindow.gBrowser.removeTabsProgressListener(gRestoreTabsProgressListener)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3304,6 +3482,15 @@ SessionStoreService.prototype = {
|
|||
this._closedWindows.splice(spliceTo);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset state to prepare for a new session state to be restored.
|
||||
*/
|
||||
_resetRestoringState: function sss__initRestoringState() {
|
||||
//
|
||||
this._tasToRestore = { visible: [], hidden: [] };
|
||||
this._tabsRestoringCount = 0;
|
||||
},
|
||||
|
||||
/* ........ Storage API .............. */
|
||||
|
||||
/**
|
||||
|
@ -3429,6 +3616,25 @@ let XPathHelper = {
|
|||
}
|
||||
};
|
||||
|
||||
// This is used to help meter the number of restoring tabs. This is the control
|
||||
// point for telling the next tab to restore. It gets attached to each gBrowser
|
||||
// via gBrowser.addTabsProgressListener
|
||||
let gRestoreTabsProgressListener = {
|
||||
ss: null,
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
// Ignore state changes on browsers that we've already restored
|
||||
if (!aBrowser.__SS_restoring)
|
||||
return;
|
||||
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
delete aBrowser.__SS_restoring;
|
||||
this.ss.restoreNextTab(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// see nsPrivateBrowsingService.js
|
||||
String.prototype.hasRootDomain = function hasRootDomain(aDomain)
|
||||
{
|
||||
|
|
|
@ -117,6 +117,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_579879.js \
|
||||
browser_580512.js \
|
||||
browser_586147.js \
|
||||
browser_586068-cascaded_restore.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
/* ***** 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 sessionstore test code.
|
||||
*
|
||||
* 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):
|
||||
* Paul O’Shannessy <paul@oshannessy.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 ***** */
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
|
||||
let stateBackup = ss.getBrowserState();
|
||||
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 586068 - Cascade page loads when restoring **/
|
||||
waitForExplicitFinish();
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
let tests = [test_cascade, test_select];
|
||||
function runNextTest() {
|
||||
if (tests.length) {
|
||||
ss.setWindowState(window,
|
||||
JSON.stringify({ windows: [{ tabs: [{ url: 'about:blank' }], }] }),
|
||||
true);
|
||||
executeSoon(tests.shift());
|
||||
}
|
||||
else {
|
||||
ss.setBrowserState(stateBackup);
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function test_cascade() {
|
||||
// Set the pref to 1 so we know exactly how many tabs should be restoring at any given time
|
||||
Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 1);
|
||||
|
||||
// We have our own progress listener for this test, which we'll attach before our state is set
|
||||
let progressListener = {
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
||||
test_cascade_progressCallback();
|
||||
}
|
||||
}
|
||||
|
||||
let state = { windows: [{ tabs: [
|
||||
{ entries: [{ url: "http://example.com" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.com" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.com" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.com" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.com" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.com" }], extData: { "uniq": r() } }
|
||||
] }] };
|
||||
|
||||
let loadCount = 0;
|
||||
// Since our progress listener is fired before the one in sessionstore, our
|
||||
// expected counts look a little weird. This is because we inspect the state
|
||||
// before sessionstore has marked the tab as finished restoring and before it
|
||||
// starts restoring the next tab
|
||||
let expectedCounts = [
|
||||
[5, 1, 0],
|
||||
[4, 1, 1],
|
||||
[3, 1, 2],
|
||||
[2, 1, 3],
|
||||
[1, 1, 4],
|
||||
[0, 1, 5]
|
||||
];
|
||||
|
||||
function test_cascade_progressCallback() {
|
||||
loadCount++;
|
||||
// We'll get the first <length of windows[0].tabs> load events here, even
|
||||
// though they are ignored by sessionstore. Those are due to explicit
|
||||
// "stop" events before any restoring action takes place. We can safely
|
||||
// ignore these events.
|
||||
if (loadCount <= state.windows[0].tabs.length)
|
||||
return;
|
||||
|
||||
let counts = countTabs();
|
||||
let expected = expectedCounts[loadCount - state.windows[0].tabs.length - 1];
|
||||
|
||||
is(counts[0], expected[0], "test_cascade: load " + loadCount + " - # tabs that need to be restored");
|
||||
is(counts[1], expected[1], "test_cascade: load " + loadCount + " - # tabs that are restoring");
|
||||
is(counts[2], expected[2], "test_cascade: load " + loadCount + " - # tabs that has been restored");
|
||||
|
||||
if (loadCount == state.windows[0].tabs.length * 2) {
|
||||
window.gBrowser.removeTabsProgressListener(progressListener);
|
||||
// Reset the pref
|
||||
try {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs");
|
||||
} catch (e) {}
|
||||
runNextTest();
|
||||
}
|
||||
}
|
||||
|
||||
// This progress listener will get attached before the listener in session store.
|
||||
window.gBrowser.addTabsProgressListener(progressListener);
|
||||
ss.setBrowserState(JSON.stringify(state));
|
||||
}
|
||||
|
||||
|
||||
function test_select() {
|
||||
// Set the pref to 0 so we know exactly how many tabs should be restoring at
|
||||
// any given time. This guarantees that a finishing load won't start another.
|
||||
Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 0);
|
||||
|
||||
// We have our own progress listener for this test, which we'll attach before our state is set
|
||||
let progressListener = {
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
||||
test_select_progressCallback(aBrowser);
|
||||
}
|
||||
}
|
||||
|
||||
let state = { windows: [{ tabs: [
|
||||
{ entries: [{ url: "http://example.org" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.org" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.org" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.org" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.org" }], extData: { "uniq": r() } },
|
||||
{ entries: [{ url: "http://example.org" }], extData: { "uniq": r() } }
|
||||
], selectedIndex: 1 }] };
|
||||
|
||||
let loadCount = 0;
|
||||
// expectedCounts looks a little wierd for the test case, but it works. See
|
||||
// comment in test_cascade for an explanation
|
||||
let expectedCounts = [
|
||||
[5, 1, 0],
|
||||
[4, 1, 1],
|
||||
[3, 1, 2],
|
||||
[2, 1, 3],
|
||||
[1, 1, 4],
|
||||
[0, 1, 5]
|
||||
];
|
||||
let tabOrder = [0, 5, 1, 4, 3, 2];
|
||||
|
||||
function test_select_progressCallback(aBrowser) {
|
||||
loadCount++;
|
||||
// We'll get the first <length of windows[0].tabs> load events here, even
|
||||
// though they are ignored by sessionstore. Those are due to explicit
|
||||
// "stop" events before any restoring action takes place. We can safely
|
||||
// ignore these events.
|
||||
if (loadCount <= state.windows[0].tabs.length)
|
||||
return;
|
||||
|
||||
let loadIndex = loadCount - state.windows[0].tabs.length - 1;
|
||||
let counts = countTabs();
|
||||
let expected = expectedCounts[loadIndex];
|
||||
|
||||
is(counts[0], expected[0], "test_select: load " + loadCount + " - # tabs that need to be restored");
|
||||
is(counts[1], expected[1], "test_select: load " + loadCount + " - # tabs that are restoring");
|
||||
is(counts[2], expected[2], "test_select: load " + loadCount + " - # tabs that has been restored");
|
||||
|
||||
if (loadCount == state.windows[0].tabs.length * 2) {
|
||||
window.gBrowser.removeTabsProgressListener(progressListener);
|
||||
// Reset the pref
|
||||
try {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs");
|
||||
} catch (e) {}
|
||||
runNextTest();
|
||||
}
|
||||
else {
|
||||
// double check that this tab was the right one
|
||||
let expectedData = state.windows[0].tabs[tabOrder[loadIndex]].extData.uniq;
|
||||
let tab;
|
||||
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||
if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
|
||||
tab = window.gBrowser.tabs[i];
|
||||
}
|
||||
is(ss.getTabValue(tab, "uniq"), expectedData, "test_select: load " + loadCount + " - correct tab was restored");
|
||||
|
||||
// select the next tab
|
||||
window.gBrowser.selectTabAtIndex(tabOrder[loadIndex + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
window.gBrowser.addTabsProgressListener(progressListener);
|
||||
ss.setBrowserState(JSON.stringify(state));
|
||||
}
|
||||
|
||||
|
||||
function countTabs() {
|
||||
let needsRestore = 0,
|
||||
isRestoring = 0,
|
||||
wasRestored = 0;
|
||||
|
||||
let windowsEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
|
||||
while (windowsEnum.hasMoreElements()) {
|
||||
let window = windowsEnum.getNext();
|
||||
if (window.closed)
|
||||
continue;
|
||||
|
||||
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||
let browser = window.gBrowser.tabs[i].linkedBrowser;
|
||||
if (browser.__SS_restoring)
|
||||
isRestoring++;
|
||||
else if (browser.__SS_needsRestore)
|
||||
needsRestore++;
|
||||
else
|
||||
wasRestored++;
|
||||
}
|
||||
}
|
||||
return [needsRestore, isRestoring, wasRestored];
|
||||
}
|
||||
|
||||
function r() {
|
||||
return "" + Date.now() + Math.random();
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
4.0b6pre
|
||||
4.0b7pre
|
||||
|
|
|
@ -458,7 +458,7 @@ Section "-InstallEndCleanup"
|
|||
${EndUnless}
|
||||
|
||||
; Win7 taskbar and start menu link maintenance
|
||||
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}"
|
||||
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}" $0
|
||||
|
||||
; Refresh desktop icons
|
||||
System::Call "shell32::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)"
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
${SetUninstallKeys}
|
||||
|
||||
; Win7 taskbar and start menu link maintenance
|
||||
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}"
|
||||
${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}" $0
|
||||
|
||||
; Remove files that may be left behind by the application in the
|
||||
; VirtualStore directory.
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
<!ENTITY aboutDialog.title "About &brandFullName;">
|
||||
<!ENTITY copyright "Credits">
|
||||
<!ENTITY copyright.accesskey "C">
|
||||
<!ENTITY copyrightGNOME.accesskey "r">
|
||||
<!ENTITY aboutLink "< About &brandFullName;">
|
||||
<!ENTITY aboutLink.accesskey "A">
|
||||
<!ENTITY aboutVersion "version">
|
||||
<!ENTITY closeCmdGNOME.label "Close">
|
||||
<!ENTITY closeCmdGNOME.accesskey "C">
|
||||
<!ENTITY licenseLinkText "Licensing information">
|
||||
<!ENTITY licenseLinkSuffix ".">
|
||||
|
||||
<!ENTITY community.start2 "&brandShortName; is designed by ">
|
||||
<!-- LOCALIZATION NOTE (community.mozillaLink): This is a link title that links to http://www.mozilla.org/. -->
|
||||
<!ENTITY community.mozillaLink "&vendorShortName;">
|
||||
<!ENTITY community.middle2 ", a ">
|
||||
<!-- LOCALIZATION NOTE (community.creditsLink): This is a link title that links to about:credits. -->
|
||||
<!ENTITY community.creditsLink "global community">
|
||||
<!ENTITY community.end2 " working together to make the Internet better. We believe that the Internet should be open, public, and accessible to everyone without any restrictions.">
|
||||
|
||||
<!ENTITY contribute.start "Sound interesting? ">
|
||||
<!-- LOCALIZATION NOTE (contribute.getInvolvedLink): This is a link title that links to http://www.mozilla.org/contribute/. -->
|
||||
<!ENTITY contribute.getInvolvedLink "Get involved!">
|
||||
<!ENTITY contribute.end "">
|
||||
|
||||
<!-- LOCALIZATION NOTE (bottomLinks.license): This is a link title that links to about:license. -->
|
||||
<!ENTITY bottomLinks.license "Licensing Information">
|
||||
|
||||
<!-- LOCALIZATION NOTE (bottomLinks.rights): This is a link title that links to about:rights. -->
|
||||
<!ENTITY bottomLinks.rights "End User Rights">
|
||||
|
||||
<!-- LOCALIZATION NOTE (bottomLinks.privacy): This is a link title that links to http://www.mozilla.com/legal/privacy/. -->
|
||||
<!ENTITY bottomLinks.privacy "Privacy Policy">
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
<!ENTITY privatebrowsingpage.startPrivateBrowsing.label "Start Private Browsing">
|
||||
<!ENTITY privatebrowsingpage.startPrivateBrowsing.accesskey "P">
|
||||
|
||||
<!ENTITY privatebrowsingpage.howToStop "To stop Private Browsing, select &toolsMenu.label; > &privateBrowsingCmd.stop.label;, or close &brandShortName;.">
|
||||
<!ENTITY privatebrowsingpage.howToStart "To start Private Browsing, you can also select &toolsMenu.label; > &privateBrowsingCmd.start.label;.">
|
||||
<!-- LOCALIZATION NOTE (privatebrowsingpage.howToStop2): please leave &basePBMenu.label; intact in the translation -->
|
||||
<!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart2): please leave &basePBMenu.label; intact in the translation -->
|
||||
<!ENTITY privatebrowsingpage.howToStop2 "To stop Private Browsing, select &basePBMenu.label; > &privateBrowsingCmd.stop.label;, or close &brandShortName;.">
|
||||
<!ENTITY privatebrowsingpage.howToStart2 "To start Private Browsing, you can also select &basePBMenu.label; > &privateBrowsingCmd.start.label;.">
|
||||
|
||||
<!ENTITY privatebrowsingpage.moreInfo "While this computer won't have a record of your browsing history, your internet service provider or employer can still track the pages you visit.">
|
||||
<!ENTITY privatebrowsingpage.learnMore "Learn More">
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
<!ENTITY reloadAllTabs.accesskey "A">
|
||||
<!ENTITY closeOtherTabs.label "Close Other Tabs">
|
||||
<!ENTITY closeOtherTabs.accesskey "o">
|
||||
<!ENTITY openTabInNewWindow.label "Open in a New Window">
|
||||
<!ENTITY openTabInNewWindow.accesskey "W">
|
||||
|
||||
<!-- LOCALIZATION NOTE (pinAppTab.label, unpinAppTab.label): "Pin" is being
|
||||
used as a metaphor for expressing the fact that these tabs are "pinned" to the
|
||||
|
@ -33,6 +31,8 @@ can reach it easily. -->
|
|||
<!ENTITY moveToGroup.label "Move to Group">
|
||||
<!ENTITY moveToGroup.accesskey "M">
|
||||
<!ENTITY moveToNewGroup.label "New Group">
|
||||
<!ENTITY moveToNewWindow.label "Move to New Window">
|
||||
<!ENTITY moveToNewWindow.accesskey "W">
|
||||
<!ENTITY bookmarkAllTabs.label "Bookmark All Tabs…">
|
||||
<!ENTITY bookmarkAllTabs.accesskey "T">
|
||||
<!ENTITY undoCloseTab.label "Undo Close Tab">
|
||||
|
@ -133,9 +133,11 @@ can reach it easily. -->
|
|||
<!ENTITY bookmarksItem.title "Bookmarks">
|
||||
|
||||
<!-- Toolbar items -->
|
||||
<!ENTITY homeButton.label "Home">
|
||||
<!ENTITY tabViewButton2.label "Tab Groups">
|
||||
<!ENTITY tabViewButton2.tooltip "Group Your Tabs">
|
||||
<!ENTITY appMenuButton.label "Menu">
|
||||
<!ENTITY homeButton.label "Home">
|
||||
|
||||
<!ENTITY tabGroupsButton.label "Tab Groups">
|
||||
<!ENTITY tabGroupsButton.tooltip "Group your tabs">
|
||||
|
||||
<!ENTITY bookmarksButton.label "Bookmarks">
|
||||
<!ENTITY bookmarksButton.tooltip "Display your bookmarks">
|
||||
|
@ -249,8 +251,8 @@ can reach it easily. -->
|
|||
|
||||
<!ENTITY viewMenu.label "View">
|
||||
<!ENTITY viewMenu.accesskey "V">
|
||||
<!ENTITY showTabView2.label "Group Your Tabs…">
|
||||
<!ENTITY showTabView2.accesskey "G">
|
||||
<!ENTITY viewTabGroups.label "Tab Groups">
|
||||
<!ENTITY viewTabGroups.accesskey "G">
|
||||
<!ENTITY viewToolbarsMenu.label "Toolbars">
|
||||
<!ENTITY viewToolbarsMenu.accesskey "T">
|
||||
<!ENTITY viewSidebarMenu.label "Sidebar">
|
||||
|
@ -489,7 +491,7 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
<!ENTITY dontShowMessage.accesskey "D">
|
||||
|
||||
<!ENTITY bidiSwitchPageDirectionItem.label "Switch Page Direction">
|
||||
<!ENTITY bidiSwitchPageDirectionItem.accesskey "g">
|
||||
<!ENTITY bidiSwitchPageDirectionItem.accesskey "D">
|
||||
<!ENTITY bidiSwitchTextDirectionItem.label "Switch Text Direction">
|
||||
<!ENTITY bidiSwitchTextDirectionItem.accesskey "w">
|
||||
<!ENTITY bidiSwitchTextDirectionItem.commandkey "X">
|
||||
|
@ -540,17 +542,10 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
<!-- LOCALIZATION NOTE (syncTabsMenu.label): This appears in the history menu -->
|
||||
<!ENTITY syncTabsMenu.label "Tabs From Other Computers">
|
||||
|
||||
<!ENTITY syncBrand.shortName.label "Sync">
|
||||
<!ENTITY syncBrand.shortName.label "Sync">
|
||||
|
||||
<!ENTITY syncMenu.label "&syncBrand.shortName.label;">
|
||||
<!-- LOCALIZATION NOTE (sync.menu.accesskey): This is part of the tools menu, so
|
||||
don't use a conflicting access key -->
|
||||
<!ENTITY syncMenu.accesskey "Y">
|
||||
<!ENTITY syncSetup.label "Set Up &syncBrand.shortName.label;…">
|
||||
<!ENTITY syncSetup.accesskey "Y">
|
||||
<!ENTITY syncLogInItem.label "Connect">
|
||||
<!ENTITY syncLogInItem.accesskey "C">
|
||||
<!ENTITY syncLogOutItem.label "Disconnect">
|
||||
<!ENTITY syncLogOutItem.accesskey "D">
|
||||
<!ENTITY syncSyncNowItem.label "Sync Now">
|
||||
<!ENTITY syncSyncNowItem.accesskey "S">
|
||||
<!ENTITY syncToolbarButton.label "Sync">
|
||||
|
|
|
@ -141,6 +141,33 @@ updatesItem_pending=Apply Downloaded Update Now…
|
|||
updatesItem_pendingFallback=Apply Downloaded Update Now…
|
||||
updatesItem_pending.accesskey=D
|
||||
|
||||
# Check for Updates in the About Dialog - button labels and accesskeys
|
||||
# LOCALIZATION NOTE - all of the following update buttons and labels will only
|
||||
# be displayed one at a time. So, if a button is displayed no other buttons or
|
||||
# labels will be displayed and if a label is displayed no other buttons or
|
||||
# labels will be displayed. They will be placed directly under the Firefox
|
||||
# version in the about dialog.
|
||||
update.checkButton.label=Check for Updates…
|
||||
update.checkButton.accesskey=C
|
||||
update.resumeButton.label=Resume Downloading %S…
|
||||
update.resumeButton.accesskey=D
|
||||
update.openUpdateUI.applyButton.label=Apply Update…
|
||||
update.openUpdateUI.applyButton.accesskey=A
|
||||
update.restart.applyButton.label=Apply Update
|
||||
update.restart.applyButton.accesskey=A
|
||||
update.openUpdateUI.upgradeButton.label=Upgrade Now…
|
||||
update.openUpdateUI.upgradeButton.accesskey=U
|
||||
update.restart.upgradeButton.label=Upgrade Now
|
||||
update.restart.upgradeButton.accesskey=U
|
||||
# Check for Updates in the About Dialog - status labels
|
||||
update.checkingForUpdate.label=Checking for updates…
|
||||
update.checkingAddonCompat.label=Checking add-on compatibility…
|
||||
update.noUpdateFound.label=This is the latest available version
|
||||
# LOCALIZATION NOTE (update.downloading) — is the "em dash" (long dash)
|
||||
# %S is the amount download
|
||||
# examples: Downloading update — 111 KB of 13 MB
|
||||
update.downloading=Downloading update — %S
|
||||
|
||||
# RSS Pretty Print
|
||||
feedShowFeedNew=Subscribe to '%S'…
|
||||
|
||||
|
@ -162,6 +189,9 @@ tabHistory.current=Stay on this page
|
|||
tabHistory.goBack=Go back to this page
|
||||
tabHistory.goForward=Go forward to this page
|
||||
|
||||
# URL Bar
|
||||
pasteAndGo.label=Paste & Go
|
||||
|
||||
# Block autorefresh
|
||||
refreshBlocked.goButton=Allow
|
||||
refreshBlocked.goButton.accesskey=A
|
||||
|
@ -288,3 +318,8 @@ tabView2.title=%S - Group Your Tabs
|
|||
|
||||
extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name=Default
|
||||
extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description=The default theme.
|
||||
|
||||
# About Firefox Dialog
|
||||
# LOCALIZATION NOTE (aboutdialog.released): %1$S = year, %2$S = month,
|
||||
# %3$S = day. These are just numbers, and the month/day values are zero-padded.
|
||||
aboutdialog.released=(released %2$S-%3$S-%1$S)
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<!ENTITY brandMotto "Rediscover the Web">
|
||||
<!ENTITY credit.thanks "Special Thanks To">
|
||||
|
||||
<!ENTITY credit.thanks2 "Many thanks to our">
|
||||
<!ENTITY credit.contributors2 "contributors">
|
||||
|
||||
<!-- localization credits look like this: -->
|
||||
<!--
|
||||
<!ENTITY credit.translation
|
||||
"<h3>Translators</h3><ul><li>Name Here</li></ul>">
|
||||
-->
|
||||
<!ENTITY credit.translation "">
|
||||
|
||||
<!ENTITY credit.memory "In Fond Memory Of">
|
||||
<!ENTITY credit.poweredByGeckoReg "Powered by Gecko®">
|
|
@ -51,6 +51,8 @@
|
|||
<!ENTITY useCacheAfter.label "MB of space for the cache">
|
||||
<!ENTITY clearCacheNow.label "Clear Now">
|
||||
<!ENTITY clearCacheNow.accesskey "C">
|
||||
<!ENTITY smartSizeCache.label "Let &brandShortName; manage the size of my cache">
|
||||
<!ENTITY smartSizeCache.accesskey "L">
|
||||
|
||||
<!ENTITY updateTab.label "Update">
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
<!ENTITY startupHomePage.label "Show my home page">
|
||||
<!ENTITY startupBlankPage.label "Show a blank page">
|
||||
<!ENTITY startupLastSession.label "Show my windows and tabs from last time">
|
||||
<!ENTITY location.label "Home Page:">
|
||||
<!ENTITY location.accesskey "H">
|
||||
<!ENTITY homepage.label "Home Page:">
|
||||
<!ENTITY homepage.accesskey "P">
|
||||
<!ENTITY useCurrentPage.label "Use Current Page">
|
||||
<!ENTITY useCurrentPage.accesskey "C">
|
||||
<!ENTITY useMultiple.label "Use Current Pages">
|
||||
|
|
|
@ -104,11 +104,17 @@ offlineAppUsage=%1$S %2$S
|
|||
offlinepermissionstext=The following websites are not allowed to store data for offline use:
|
||||
offlinepermissionstitle=Offline Data
|
||||
|
||||
####Preferences::Advanced::Network
|
||||
#LOCALIZATION NOTE: The next string is for the disk usage of the http cache.
|
||||
# e.g., "Your cache is currently using 200 MB"
|
||||
# %1$S = size
|
||||
# %2$S = unit (MB, KB, etc.)
|
||||
actualCacheSize=Your cache is currently using %1$S %2$S of disk space
|
||||
|
||||
#### Syncing
|
||||
connect.label=Connect
|
||||
disconnect.label=Disconnect
|
||||
|
||||
differentAccount.title=Use a Different Account?
|
||||
stopUsingAccount.title=Do you want to stop using this account?
|
||||
differentAccount.label=This will reset all of your Sync account information and preferences.
|
||||
differentAccountConfirm.label=Reset All Information
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<!-- The page shown when logged in... -->
|
||||
<!ENTITY accountGroupboxCaption.label "&syncBrand.fullName.label; Account">
|
||||
<!ENTITY currentUser.label "Current User:">
|
||||
<!ENTITY currentAccount.label "Current Account:">
|
||||
|
||||
<!-- Login error feedback -->
|
||||
<!ENTITY updatePass.label "Update">
|
||||
|
@ -14,10 +14,11 @@
|
|||
<!-- Manage Account -->
|
||||
<!ENTITY manageAccount.label "Manage Account">
|
||||
<!ENTITY manageAccount.accesskey "A">
|
||||
<!ENTITY viewQuota.label "View Quota">
|
||||
<!ENTITY changePassword.label "Change Password">
|
||||
<!ENTITY mySyncKey.label "My Sync Key">
|
||||
<!ENTITY resetSync.label "Reset Sync">
|
||||
<!ENTITY differentAccount.label "Use a Different Account">
|
||||
<!ENTITY stopUsingAccount.label "Stop Using This Account">
|
||||
|
||||
<!-- Sync Settings -->
|
||||
<!ENTITY syncPrefsCaption.label "Browser Sync">
|
||||
|
|