зеркало из https://github.com/mozilla/gecko-dev.git
Mergi mc to kiwifox, lots of conflicts so may not build
This commit is contained in:
Коммит
e0bcc5a6d2
|
@ -23,7 +23,7 @@ ID
|
||||||
security/manager/.nss.checkout
|
security/manager/.nss.checkout
|
||||||
|
|
||||||
# Build directories
|
# Build directories
|
||||||
obj*/
|
/obj*/
|
||||||
|
|
||||||
# Build directories for js shell
|
# Build directories for js shell
|
||||||
*/_DBG.OBJ/
|
*/_DBG.OBJ/
|
||||||
|
|
1
.hgtags
1
.hgtags
|
@ -72,3 +72,4 @@ c0983049bcaa9551e5f276d5a77ce154c151e0b0 AURORA_BASE_20110927
|
||||||
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R15
|
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R15
|
||||||
54bfd8bf682e295ffd7f22fa921ca343957b6c1c AURORA_BASE_20111108
|
54bfd8bf682e295ffd7f22fa921ca343957b6c1c AURORA_BASE_20111108
|
||||||
a8506ab2c65480cf2f85f54e203ea746522c62bb AURORA_BASE_20111220
|
a8506ab2c65480cf2f85f54e203ea746522c62bb AURORA_BASE_20111220
|
||||||
|
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R16
|
||||||
|
|
|
@ -49,6 +49,9 @@ namespace statistics {
|
||||||
inline void A11yInitialized()
|
inline void A11yInitialized()
|
||||||
{ Telemetry::Accumulate(Telemetry::A11Y_INSTANTIATED, true); }
|
{ Telemetry::Accumulate(Telemetry::A11Y_INSTANTIATED, true); }
|
||||||
|
|
||||||
|
inline void A11yConsumers(PRUint32 aConsumer)
|
||||||
|
{ Telemetry::Accumulate(Telemetry::A11Y_CONSUMERS, aConsumer); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report that ISimpleDOM* has been used.
|
* Report that ISimpleDOM* has been used.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -195,12 +195,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool IsPrimaryForNode() const;
|
virtual bool IsPrimaryForNode() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the string bundle
|
|
||||||
*/
|
|
||||||
static nsIStringBundle* GetStringBundle()
|
|
||||||
{ return gStringBundle; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsPresContext* GetPresContext();
|
nsPresContext* GetPresContext();
|
||||||
|
|
||||||
|
|
|
@ -395,7 +395,7 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
|
||||||
nsCString plugId;
|
nsCString plugId;
|
||||||
nsresult rv = pluginInstance->GetValueFromPlugin(
|
nsresult rv = pluginInstance->GetValueFromPlugin(
|
||||||
NPPVpluginNativeAccessibleAtkPlugId, &plugId);
|
NPPVpluginNativeAccessibleAtkPlugId, &plugId);
|
||||||
if (NS_SUCCEEDED(rv) && !plugId.IsVoid()) {
|
if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
|
||||||
AtkSocketAccessible* socketAccessible =
|
AtkSocketAccessible* socketAccessible =
|
||||||
new AtkSocketAccessible(aContent, weakShell, plugId);
|
new AtkSocketAccessible(aContent, weakShell, plugId);
|
||||||
|
|
||||||
|
@ -909,19 +909,8 @@ static bool HasRelatedContent(nsIContent *aContent)
|
||||||
|
|
||||||
// If the given ID is referred by relation attribute then create an accessible
|
// If the given ID is referred by relation attribute then create an accessible
|
||||||
// for it. Take care of HTML elements only for now.
|
// for it. Take care of HTML elements only for now.
|
||||||
if (aContent->IsHTML() &&
|
return aContent->IsHTML() &&
|
||||||
nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id))
|
nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id);
|
||||||
return true;
|
|
||||||
|
|
||||||
nsIContent *ancestorContent = aContent;
|
|
||||||
while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
|
|
||||||
if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
|
|
||||||
// ancestor has activedescendant property, this content could be active
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAccessible*
|
nsAccessible*
|
||||||
|
|
|
@ -579,16 +579,13 @@ nsAccessible::GetIndexInParent(PRInt32 *aIndexInParent)
|
||||||
return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE;
|
return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsAccessible::GetTranslatedString(const nsAString& aKey, nsAString& aStringOut)
|
void
|
||||||
|
nsAccessible::TranslateString(const nsAString& aKey, nsAString& aStringOut)
|
||||||
{
|
{
|
||||||
nsXPIDLString xsValue;
|
nsXPIDLString xsValue;
|
||||||
|
|
||||||
if (!gStringBundle ||
|
gStringBundle->GetStringFromName(PromiseFlatString(aKey).get(), getter_Copies(xsValue));
|
||||||
NS_FAILED(gStringBundle->GetStringFromName(PromiseFlatString(aKey).get(), getter_Copies(xsValue))))
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
aStringOut.Assign(xsValue);
|
aStringOut.Assign(xsValue);
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PRUint64
|
PRUint64
|
||||||
|
@ -616,6 +613,9 @@ nsAccessible::VisibilityState()
|
||||||
} while (accessible = accessible->Parent());
|
} while (accessible = accessible->Parent());
|
||||||
|
|
||||||
nsIFrame* frame = GetFrame();
|
nsIFrame* frame = GetFrame();
|
||||||
|
if (!frame)
|
||||||
|
return vstates;
|
||||||
|
|
||||||
const nsCOMPtr<nsIPresShell> shell(GetPresShell());
|
const nsCOMPtr<nsIPresShell> shell(GetPresShell());
|
||||||
|
|
||||||
// We need to know if at least a kMinPixels around the object is visible,
|
// We need to know if at least a kMinPixels around the object is visible,
|
||||||
|
@ -1473,23 +1473,34 @@ nsAccessible::State()
|
||||||
// Apply ARIA states to be sure accessible states will be overridden.
|
// Apply ARIA states to be sure accessible states will be overridden.
|
||||||
ApplyARIAState(&state);
|
ApplyARIAState(&state);
|
||||||
|
|
||||||
if (mRoleMapEntry && mRoleMapEntry->role == roles::PAGETAB &&
|
// If this is an ARIA item of the selectable widget and if it's focused and
|
||||||
!(state & states::SELECTED) &&
|
// not marked unselected explicitly (i.e. aria-selected="false") then expose
|
||||||
|
// it as selected to make ARIA widget authors life easier.
|
||||||
|
if (mRoleMapEntry && !(state & states::SELECTED) &&
|
||||||
!mContent->AttrValueIs(kNameSpaceID_None,
|
!mContent->AttrValueIs(kNameSpaceID_None,
|
||||||
nsGkAtoms::aria_selected,
|
nsGkAtoms::aria_selected,
|
||||||
nsGkAtoms::_false, eCaseMatters)) {
|
nsGkAtoms::_false, eCaseMatters)) {
|
||||||
// Special case: for tabs, focused implies selected, unless explicitly
|
// Special case for tabs: focused tab or focus inside related tab panel
|
||||||
// false, i.e. aria-selected="false".
|
// implies selected state.
|
||||||
if (state & states::FOCUSED) {
|
if (mRoleMapEntry->role == roles::PAGETAB) {
|
||||||
state |= states::SELECTED;
|
if (state & states::FOCUSED) {
|
||||||
} else {
|
state |= states::SELECTED;
|
||||||
// If focus is in a child of the tab panel surely the tab is selected!
|
} else {
|
||||||
Relation rel = RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
|
// If focus is in a child of the tab panel surely the tab is selected!
|
||||||
nsAccessible* relTarget = nsnull;
|
Relation rel = RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
|
||||||
while ((relTarget = rel.Next())) {
|
nsAccessible* relTarget = nsnull;
|
||||||
if (relTarget->Role() == roles::PROPERTYPAGE &&
|
while ((relTarget = rel.Next())) {
|
||||||
FocusMgr()->IsFocusWithin(relTarget))
|
if (relTarget->Role() == roles::PROPERTYPAGE &&
|
||||||
state |= states::SELECTED;
|
FocusMgr()->IsFocusWithin(relTarget))
|
||||||
|
state |= states::SELECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (state & states::FOCUSED) {
|
||||||
|
nsAccessible* container = nsAccUtils::GetSelectableContainer(this, state);
|
||||||
|
if (container &&
|
||||||
|
!nsAccUtils::HasDefinedARIAToken(container->GetContent(),
|
||||||
|
nsGkAtoms::aria_multiselectable)) {
|
||||||
|
state |= states::SELECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1882,7 +1893,8 @@ nsAccessible::GetActionDescription(PRUint8 aIndex, nsAString& aDescription)
|
||||||
nsresult rv = GetActionName(aIndex, name);
|
nsresult rv = GetActionName(aIndex, name);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return GetTranslatedString(name, aDescription);
|
TranslateString(name, aDescription);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void doAction(in PRUint8 index)
|
// void doAction(in PRUint8 index)
|
||||||
|
@ -2914,21 +2926,18 @@ nsAccessible::SetCurrentItem(nsAccessible* aItem)
|
||||||
nsAccessible*
|
nsAccessible*
|
||||||
nsAccessible::ContainerWidget() const
|
nsAccessible::ContainerWidget() const
|
||||||
{
|
{
|
||||||
nsIAtom* idAttribute = mContent->GetIDAttributeName();
|
if (HasARIARole() && mContent->HasID()) {
|
||||||
if (idAttribute) {
|
for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
|
||||||
if (mContent->HasAttr(kNameSpaceID_None, idAttribute)) {
|
nsIContent* parentContent = parent->GetContent();
|
||||||
for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
|
if (parentContent &&
|
||||||
nsIContent* parentContent = parent->GetContent();
|
parentContent->HasAttr(kNameSpaceID_None,
|
||||||
if (parentContent &&
|
nsGkAtoms::aria_activedescendant)) {
|
||||||
parentContent->HasAttr(kNameSpaceID_None,
|
return parent;
|
||||||
nsGkAtoms::aria_activedescendant)) {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't cross DOM document boundaries.
|
|
||||||
if (parent->IsDocumentNode())
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't cross DOM document boundaries.
|
||||||
|
if (parent->IsDocumentNode())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
|
|
@ -166,6 +166,14 @@ public:
|
||||||
return ARIARoleInternal();
|
return ARIARoleInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if ARIA role is specified on the element.
|
||||||
|
*/
|
||||||
|
inline bool HasARIARole() const
|
||||||
|
{
|
||||||
|
return mRoleMapEntry;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return accessible role specified by ARIA (see constants in
|
* Return accessible role specified by ARIA (see constants in
|
||||||
* roles).
|
* roles).
|
||||||
|
@ -603,6 +611,11 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual nsAccessible* ContainerWidget() const;
|
virtual nsAccessible* ContainerWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the localized string for the given key.
|
||||||
|
*/
|
||||||
|
static void TranslateString(const nsAString& aKey, nsAString& aStringOut);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -695,7 +708,6 @@ protected:
|
||||||
|
|
||||||
// helper method to verify frames
|
// helper method to verify frames
|
||||||
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
|
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
|
||||||
static nsresult GetTranslatedString(const nsAString& aKey, nsAString& aStringOut);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an accessible for the given DOM node, or if that node isn't
|
* Return an accessible for the given DOM node, or if that node isn't
|
||||||
|
|
|
@ -1345,7 +1345,7 @@ nsHTMLTableAccessible::HasDescendant(const nsAString& aTagName,
|
||||||
if (foundItemContent->GetChildCount() > 1)
|
if (foundItemContent->GetChildCount() > 1)
|
||||||
return true; // Treat multiple child nodes as non-empty
|
return true; // Treat multiple child nodes as non-empty
|
||||||
|
|
||||||
nsIContent *innerItemContent = foundItemContent->GetChildAt(0);
|
nsIContent *innerItemContent = foundItemContent->GetFirstChild();
|
||||||
if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
|
if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
/* ***** BEGIN LICENSE BLOCK *****
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
*
|
*
|
||||||
|
@ -15,11 +16,12 @@
|
||||||
* The Original Code is mozilla.org code.
|
* The Original Code is mozilla.org code.
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is
|
* The Initial Developer of the Original Code is
|
||||||
* Netscape Communications Corporation.
|
* Mozilla Foundation.
|
||||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
|
* Original Author: Hubert Figuiere <hub@mozilla.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -35,25 +37,24 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#ifndef nsDocumentCharsetInfo_h__
|
#ifndef _MacUtils_H_
|
||||||
#define nsDocumentCharsetInfo_h__
|
#define _MacUtils_H_
|
||||||
|
|
||||||
#include "nsIFactory.h"
|
@class NSString;
|
||||||
#include "nsIDocumentCharsetInfo.h"
|
class nsString;
|
||||||
|
|
||||||
class nsDocumentCharsetInfo : public nsIDocumentCharsetInfo
|
namespace mozilla {
|
||||||
{
|
namespace a11y {
|
||||||
public:
|
namespace utils {
|
||||||
nsDocumentCharsetInfo ();
|
|
||||||
virtual ~nsDocumentCharsetInfo ();
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
/**
|
||||||
NS_DECL_NSIDOCUMENTCHARSETINFO
|
* Get a localized string from the string bundle.
|
||||||
|
* Return nil if not found.
|
||||||
|
*/
|
||||||
|
NSString* LocalizedString(const nsString& aString);
|
||||||
|
|
||||||
private:
|
}
|
||||||
nsCOMPtr<nsIAtom> mForcedCharset;
|
}
|
||||||
nsCOMPtr<nsIAtom> mParentCharset;
|
}
|
||||||
PRInt32 mParentCharsetSource;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // nsDocumentCharsetInfo_h__
|
#endif
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* ***** 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 mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Original Author: Hubert Figuiere <hub@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of 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 ***** */
|
||||||
|
|
||||||
|
#import "MacUtils.h"
|
||||||
|
|
||||||
|
#include "nsAccessible.h"
|
||||||
|
|
||||||
|
#include "nsCocoaUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a localized string from the a11y string bundle.
|
||||||
|
* Return nil if not found.
|
||||||
|
*/
|
||||||
|
NSString*
|
||||||
|
LocalizedString(const nsString& aString)
|
||||||
|
{
|
||||||
|
nsString text;
|
||||||
|
|
||||||
|
nsAccessible::TranslateString(aString, text);
|
||||||
|
|
||||||
|
return text.IsEmpty() ? nil : nsCocoaUtils::ToNSString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,8 +56,10 @@ CMMSRCS = nsAccessNodeWrap.mm \
|
||||||
mozDocAccessible.mm \
|
mozDocAccessible.mm \
|
||||||
mozActionElements.mm \
|
mozActionElements.mm \
|
||||||
mozTextAccessible.mm \
|
mozTextAccessible.mm \
|
||||||
|
mozHTMLAccessible.mm \
|
||||||
|
MacUtils.mm \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|
||||||
EXPORTS = \
|
EXPORTS = \
|
||||||
nsAccessNodeWrap.h \
|
nsAccessNodeWrap.h \
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
#import "mozAccessible.h"
|
#import "mozAccessible.h"
|
||||||
|
|
||||||
// to get the mozView formal protocol, that all gecko's ChildViews implement.
|
#import "MacUtils.h"
|
||||||
#import "mozView.h"
|
#import "mozView.h"
|
||||||
#import "nsRoleMap.h"
|
#import "nsRoleMap.h"
|
||||||
|
|
||||||
|
@ -127,24 +127,6 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a localized string from the string bundle.
|
|
||||||
* Return nil is not found.
|
|
||||||
*/
|
|
||||||
static NSString*
|
|
||||||
GetLocalizedString(const nsString& aString)
|
|
||||||
{
|
|
||||||
if (!nsAccessNode::GetStringBundle())
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
nsXPIDLString text;
|
|
||||||
nsresult rv = nsAccessNode::GetStringBundle()->GetStringFromName(aString.get(),
|
|
||||||
getter_Copies(text));
|
|
||||||
NS_ENSURE_SUCCESS(rv, nil);
|
|
||||||
|
|
||||||
return !text.IsEmpty() ? nsCocoaUtils::ToNSString(text) : nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
@implementation mozAccessible
|
@implementation mozAccessible
|
||||||
|
@ -219,6 +201,9 @@ GetLocalizedString(const nsString& aString)
|
||||||
NSAccessibilityTitleUIElementAttribute,
|
NSAccessibilityTitleUIElementAttribute,
|
||||||
NSAccessibilityTopLevelUIElementAttribute,
|
NSAccessibilityTopLevelUIElementAttribute,
|
||||||
NSAccessibilityDescriptionAttribute,
|
NSAccessibilityDescriptionAttribute,
|
||||||
|
#if DEBUG
|
||||||
|
@"AXMozDescription",
|
||||||
|
#endif
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +218,11 @@ GetLocalizedString(const nsString& aString)
|
||||||
|
|
||||||
if (mIsExpired)
|
if (mIsExpired)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if ([attribute isEqualToString:@"AXMozDescription"])
|
||||||
|
return [NSString stringWithFormat:@"role = %u native = %@", mRole, [self class]];
|
||||||
|
#endif
|
||||||
|
|
||||||
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
|
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
|
||||||
return [self children];
|
return [self children];
|
||||||
|
@ -254,8 +244,8 @@ GetLocalizedString(const nsString& aString)
|
||||||
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
|
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
|
||||||
return [self value];
|
return [self value];
|
||||||
if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
|
if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
|
||||||
if (mRole == roles::INTERNAL_FRAME || mRole == roles::DOCUMENT_FRAME)
|
if (mRole == roles::DOCUMENT)
|
||||||
return GetLocalizedString(NS_LITERAL_STRING("htmlContent")) ? : @"HTML Content";
|
return utils::LocalizedString(NS_LITERAL_STRING("htmlContent"));
|
||||||
|
|
||||||
return NSAccessibilityRoleDescription([self role], nil);
|
return NSAccessibilityRoleDescription([self role], nil);
|
||||||
}
|
}
|
||||||
|
@ -348,7 +338,9 @@ GetLocalizedString(const nsString& aString)
|
||||||
|
|
||||||
- (NSString*)accessibilityActionDescription:(NSString*)action
|
- (NSString*)accessibilityActionDescription:(NSString*)action
|
||||||
{
|
{
|
||||||
return nil;
|
// by default we return whatever the MacOS API know about.
|
||||||
|
// if you have custom actions, override.
|
||||||
|
return NSAccessibilityActionDescription(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)accessibilityPerformAction:(NSString*)action
|
- (void)accessibilityPerformAction:(NSString*)action
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
@interface mozButtonAccessible : mozAccessible
|
@interface mozButtonAccessible : mozAccessible
|
||||||
- (void)click;
|
- (void)click;
|
||||||
|
- (BOOL)isTab;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface mozCheckboxAccessible : mozButtonAccessible
|
@interface mozCheckboxAccessible : mozButtonAccessible
|
||||||
|
@ -53,3 +54,11 @@
|
||||||
/* Used for buttons that may pop up a menu. */
|
/* Used for buttons that may pop up a menu. */
|
||||||
@interface mozPopupButtonAccessible : mozButtonAccessible
|
@interface mozPopupButtonAccessible : mozButtonAccessible
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
/* Class for tabs - not individual tabs */
|
||||||
|
@interface mozTabsAccessible : mozAccessible
|
||||||
|
{
|
||||||
|
NSMutableArray* mTabs;
|
||||||
|
}
|
||||||
|
-(id)tabs;
|
||||||
|
@end
|
||||||
|
|
|
@ -37,7 +37,11 @@
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#import "mozActionElements.h"
|
#import "mozActionElements.h"
|
||||||
|
|
||||||
|
#import "MacUtils.h"
|
||||||
|
|
||||||
#import "nsIAccessible.h"
|
#import "nsIAccessible.h"
|
||||||
|
#import "nsXULTabAccessible.h"
|
||||||
|
|
||||||
#include "nsObjCExceptions.h"
|
#include "nsObjCExceptions.h"
|
||||||
|
|
||||||
|
@ -60,6 +64,7 @@ enum CheckboxValue {
|
||||||
if (!attributes) {
|
if (!attributes) {
|
||||||
attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required
|
attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required
|
||||||
NSAccessibilityRoleAttribute, // required
|
NSAccessibilityRoleAttribute, // required
|
||||||
|
NSAccessibilityRoleDescriptionAttribute,
|
||||||
NSAccessibilityPositionAttribute, // required
|
NSAccessibilityPositionAttribute, // required
|
||||||
NSAccessibilitySizeAttribute, // required
|
NSAccessibilitySizeAttribute, // required
|
||||||
NSAccessibilityWindowAttribute, // required
|
NSAccessibilityWindowAttribute, // required
|
||||||
|
@ -70,6 +75,9 @@ enum CheckboxValue {
|
||||||
NSAccessibilityFocusedAttribute, // required
|
NSAccessibilityFocusedAttribute, // required
|
||||||
NSAccessibilityTitleAttribute, // required
|
NSAccessibilityTitleAttribute, // required
|
||||||
NSAccessibilityDescriptionAttribute,
|
NSAccessibilityDescriptionAttribute,
|
||||||
|
#if DEBUG
|
||||||
|
@"AXMozDescription",
|
||||||
|
#endif
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
return attributes;
|
return attributes;
|
||||||
|
@ -83,6 +91,13 @@ enum CheckboxValue {
|
||||||
|
|
||||||
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
|
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
|
||||||
return nil;
|
return nil;
|
||||||
|
if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
|
||||||
|
if ([self isTab])
|
||||||
|
return utils::LocalizedString(NS_LITERAL_STRING("tab"));
|
||||||
|
|
||||||
|
return NSAccessibilityRoleDescription([self role], nil);
|
||||||
|
}
|
||||||
|
|
||||||
return [super accessibilityAttributeValue:attribute];
|
return [super accessibilityAttributeValue:attribute];
|
||||||
|
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||||
|
@ -109,9 +124,13 @@ enum CheckboxValue {
|
||||||
{
|
{
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||||
|
|
||||||
if ([action isEqualToString:NSAccessibilityPressAction])
|
if ([action isEqualToString:NSAccessibilityPressAction]) {
|
||||||
|
if ([self isTab])
|
||||||
|
return utils::LocalizedString(NS_LITERAL_STRING("switch"));
|
||||||
|
|
||||||
return @"press button"; // XXX: localize this later?
|
return @"press button"; // XXX: localize this later?
|
||||||
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||||
|
@ -134,6 +153,11 @@ enum CheckboxValue {
|
||||||
mGeckoAccessible->DoAction(0);
|
mGeckoAccessible->DoAction(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isTab
|
||||||
|
{
|
||||||
|
return (mGeckoAccessible && (mGeckoAccessible->Role() == roles::PAGETAB));
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation mozCheckboxAccessible
|
@implementation mozCheckboxAccessible
|
||||||
|
@ -198,6 +222,9 @@ enum CheckboxValue {
|
||||||
NSAccessibilityTitleAttribute, // required for popupmenus, and for menubuttons with a title
|
NSAccessibilityTitleAttribute, // required for popupmenus, and for menubuttons with a title
|
||||||
NSAccessibilityChildrenAttribute, // required
|
NSAccessibilityChildrenAttribute, // required
|
||||||
NSAccessibilityDescriptionAttribute, // required if it has no title attr
|
NSAccessibilityDescriptionAttribute, // required if it has no title attr
|
||||||
|
#if DEBUG
|
||||||
|
@"AXMozDescription",
|
||||||
|
#endif
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
return attributes;
|
return attributes;
|
||||||
|
@ -258,3 +285,85 @@ enum CheckboxValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation mozTabsAccessible
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[mTabs release];
|
||||||
|
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray*)accessibilityAttributeNames
|
||||||
|
{
|
||||||
|
// standard attributes that are shared and supported by root accessible (AXMain) elements.
|
||||||
|
static NSMutableArray* attributes = nil;
|
||||||
|
|
||||||
|
if (!attributes) {
|
||||||
|
attributes = [[super accessibilityAttributeNames] mutableCopy];
|
||||||
|
[attributes addObject:NSAccessibilityContentsAttribute];
|
||||||
|
[attributes addObject:NSAccessibilityTabsAttribute];
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)accessibilityAttributeValue:(NSString *)attribute
|
||||||
|
{
|
||||||
|
if ([attribute isEqualToString:NSAccessibilityContentsAttribute])
|
||||||
|
return [super children];
|
||||||
|
if ([attribute isEqualToString:NSAccessibilityTabsAttribute])
|
||||||
|
return [self tabs];
|
||||||
|
|
||||||
|
return [super accessibilityAttributeValue:attribute];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the selected tab (the mozAccessible)
|
||||||
|
*/
|
||||||
|
- (id)value
|
||||||
|
{
|
||||||
|
if (!mGeckoAccessible)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
nsAccessible* accessible = mGeckoAccessible->GetSelectedItem(0);
|
||||||
|
if (!accessible)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
mozAccessible* nativeAcc = nil;
|
||||||
|
nsresult rv = accessible->GetNativeInterface((void**)&nativeAcc);
|
||||||
|
NS_ENSURE_SUCCESS(rv, nil);
|
||||||
|
|
||||||
|
return nativeAcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mozAccessibles that are the tabs.
|
||||||
|
*/
|
||||||
|
- (id)tabs
|
||||||
|
{
|
||||||
|
if (mTabs)
|
||||||
|
return mTabs;
|
||||||
|
|
||||||
|
NSArray* children = [self children];
|
||||||
|
NSEnumerator* enumerator = [children objectEnumerator];
|
||||||
|
mTabs = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
id obj;
|
||||||
|
while ((obj = [enumerator nextObject]))
|
||||||
|
if ([obj isTab])
|
||||||
|
[mTabs addObject:obj];
|
||||||
|
|
||||||
|
return mTabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)invalidateChildren
|
||||||
|
{
|
||||||
|
[super invalidateChildren];
|
||||||
|
|
||||||
|
[mTabs release];
|
||||||
|
mTabs = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||||
|
*/
|
||||||
/* ***** BEGIN LICENSE BLOCK *****
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
*
|
*
|
||||||
|
@ -15,11 +17,12 @@
|
||||||
* The Original Code is mozilla.org code.
|
* The Original Code is mozilla.org code.
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is
|
* The Initial Developer of the Original Code is
|
||||||
* Netscape Communications Corporation.
|
* Mozilla Foundation.
|
||||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
|
* Original Author: Hub Figuière <hub@mozilla.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -35,16 +38,12 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#ifndef nsXMLEncodingCID_h__
|
#import "mozAccessible.h"
|
||||||
#define nsXMLEncodingCID_h__
|
|
||||||
|
|
||||||
#include "nscore.h"
|
@interface mozHeadingAccessible : mozAccessible
|
||||||
|
|
||||||
#define NS_XML_ENCODING_CONTRACTID "@mozilla.org/intl/xmlencoding;1"
|
@end
|
||||||
|
|
||||||
// {12BB8F16-2389-11d3-B3BF-00805F8A6670}
|
@interface mozLinkAccessible : mozAccessible
|
||||||
#define NS_XML_ENCODING_CID \
|
|
||||||
{ 0x12bb8f16, 0x2389, 0x11d3, { 0xb3, 0xbf, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 } }
|
|
||||||
|
|
||||||
|
@end
|
||||||
#endif // nsXMLEncodingCID_h__
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=2:tabstop=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 mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Original Author: Hub Figuière <hub@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of 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 ***** */
|
||||||
|
|
||||||
|
#import "mozHTMLAccessible.h"
|
||||||
|
|
||||||
|
#import "nsHyperTextAccessible.h"
|
||||||
|
|
||||||
|
#import "nsCocoaUtils.h"
|
||||||
|
|
||||||
|
@implementation mozHeadingAccessible
|
||||||
|
|
||||||
|
- (id)value
|
||||||
|
{
|
||||||
|
if (!mGeckoAccessible || !mGeckoAccessible->IsHyperText())
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
PRUint32 level = mGeckoAccessible->AsHyperText()->GetLevelInternal();
|
||||||
|
return [NSNumber numberWithInt:level];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface mozLinkAccessible ()
|
||||||
|
-(NSURL*)url;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation mozLinkAccessible
|
||||||
|
|
||||||
|
- (NSArray*)accessibilityAttributeNames
|
||||||
|
{
|
||||||
|
// if we're expired, we don't support any attributes.
|
||||||
|
if (mIsExpired)
|
||||||
|
return [NSArray array];
|
||||||
|
|
||||||
|
static NSMutableArray* attributes = nil;
|
||||||
|
|
||||||
|
if (!attributes) {
|
||||||
|
attributes = [[super accessibilityAttributeNames] mutableCopy];
|
||||||
|
[attributes addObject:NSAccessibilityURLAttribute];
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)accessibilityAttributeValue:(NSString *)attribute
|
||||||
|
{
|
||||||
|
if ([attribute isEqualToString:NSAccessibilityURLAttribute])
|
||||||
|
return [self url];
|
||||||
|
|
||||||
|
return [super accessibilityAttributeValue:attribute];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray*)accessibilityActionNames
|
||||||
|
{
|
||||||
|
// if we're expired, we don't support any attributes.
|
||||||
|
if (mIsExpired)
|
||||||
|
return [NSArray array];
|
||||||
|
|
||||||
|
static NSArray* actionNames = nil;
|
||||||
|
|
||||||
|
if (!actionNames) {
|
||||||
|
actionNames = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction,
|
||||||
|
nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)accessibilityPerformAction:(NSString*)action
|
||||||
|
{
|
||||||
|
if (!mGeckoAccessible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([action isEqualToString:NSAccessibilityPressAction])
|
||||||
|
mGeckoAccessible->DoAction(0);
|
||||||
|
else
|
||||||
|
[super accessibilityPerformAction:action];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSURL*)url
|
||||||
|
{
|
||||||
|
if (!mGeckoAccessible)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
nsAutoString value;
|
||||||
|
nsresult rv = mGeckoAccessible->GetValue(value);
|
||||||
|
NS_ENSURE_SUCCESS(rv, nil);
|
||||||
|
|
||||||
|
NSString* urlString = value.IsEmpty() ? nil : nsCocoaUtils::ToNSString(value);
|
||||||
|
if (!urlString)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [NSURL URLWithString:urlString];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -1,4 +1,6 @@
|
||||||
#include "nsAccessibleWrap.h"
|
#include "nsAccessibleWrap.h"
|
||||||
|
|
||||||
|
#include "nsCocoaUtils.h"
|
||||||
#include "nsObjCExceptions.h"
|
#include "nsObjCExceptions.h"
|
||||||
|
|
||||||
#import "mozTextAccessible.h"
|
#import "mozTextAccessible.h"
|
||||||
|
@ -12,6 +14,7 @@ using namespace mozilla::a11y;
|
||||||
- (long)textLength;
|
- (long)textLength;
|
||||||
- (BOOL)isReadOnly;
|
- (BOOL)isReadOnly;
|
||||||
- (void)setText:(NSString*)newText;
|
- (void)setText:(NSString*)newText;
|
||||||
|
- (NSString*)text;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation mozTextAccessible
|
@implementation mozTextAccessible
|
||||||
|
@ -60,6 +63,9 @@ using namespace mozilla::a11y;
|
||||||
NSAccessibilityNumberOfCharactersAttribute, // required
|
NSAccessibilityNumberOfCharactersAttribute, // required
|
||||||
// TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
|
// TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
|
||||||
// TODO: NSAccessibilityInsertionPointLineNumberAttribute
|
// TODO: NSAccessibilityInsertionPointLineNumberAttribute
|
||||||
|
#if DEBUG
|
||||||
|
@"AXMozDescription",
|
||||||
|
#endif
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
return supportedAttributes;
|
return supportedAttributes;
|
||||||
|
@ -79,8 +85,9 @@ using namespace mozilla::a11y;
|
||||||
return [self selectedText];
|
return [self selectedText];
|
||||||
// Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText
|
// Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText
|
||||||
// object's AXSelectedText attribute. See bug 674612.
|
// object's AXSelectedText attribute. See bug 674612.
|
||||||
|
// Also if there is no selected text, we return the full text.See bug 369710
|
||||||
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
|
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
|
||||||
return [self selectedText];
|
return [self selectedText] ? : [self text];
|
||||||
|
|
||||||
// let mozAccessible handle all other attributes
|
// let mozAccessible handle all other attributes
|
||||||
return [super accessibilityAttributeValue:attribute];
|
return [super accessibilityAttributeValue:attribute];
|
||||||
|
@ -158,6 +165,20 @@ using namespace mozilla::a11y;
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString*)text
|
||||||
|
{
|
||||||
|
if (!mGeckoTextAccessible)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
nsAutoString text;
|
||||||
|
nsresult rv =
|
||||||
|
mGeckoTextAccessible->GetText(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT,
|
||||||
|
text);
|
||||||
|
NS_ENSURE_SUCCESS(rv, nil);
|
||||||
|
|
||||||
|
return text.IsEmpty() ? nil : nsCocoaUtils::ToNSString(text);
|
||||||
|
}
|
||||||
|
|
||||||
- (long)textLength
|
- (long)textLength
|
||||||
{
|
{
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||||
|
@ -261,6 +282,9 @@ using namespace mozilla::a11y;
|
||||||
NSAccessibilityNumberOfCharactersAttribute, // required
|
NSAccessibilityNumberOfCharactersAttribute, // required
|
||||||
// TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
|
// TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
|
||||||
// TODO: NSAccessibilityInsertionPointLineNumberAttribute
|
// TODO: NSAccessibilityInsertionPointLineNumberAttribute
|
||||||
|
#if DEBUG
|
||||||
|
@"AXMozDescription",
|
||||||
|
#endif
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
return supportedAttributes;
|
return supportedAttributes;
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#import "mozAccessible.h"
|
#import "mozAccessible.h"
|
||||||
#import "mozActionElements.h"
|
#import "mozActionElements.h"
|
||||||
|
#import "mozHTMLAccessible.h"
|
||||||
#import "mozTextAccessible.h"
|
#import "mozTextAccessible.h"
|
||||||
|
|
||||||
using namespace mozilla::a11y;
|
using namespace mozilla::a11y;
|
||||||
|
@ -103,22 +104,33 @@ nsAccessibleWrap::GetNativeType ()
|
||||||
[mozButtonAccessible class];
|
[mozButtonAccessible class];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case roles::PAGETAB:
|
||||||
|
return [mozButtonAccessible class];
|
||||||
|
|
||||||
case roles::CHECKBUTTON:
|
case roles::CHECKBUTTON:
|
||||||
return [mozCheckboxAccessible class];
|
return [mozCheckboxAccessible class];
|
||||||
|
|
||||||
case roles::AUTOCOMPLETE:
|
case roles::AUTOCOMPLETE:
|
||||||
return [mozComboboxAccessible class];
|
return [mozComboboxAccessible class];
|
||||||
|
|
||||||
|
case roles::HEADING:
|
||||||
|
return [mozHeadingAccessible class];
|
||||||
|
|
||||||
|
case roles::PAGETABLIST:
|
||||||
|
return [mozTabsAccessible class];
|
||||||
|
|
||||||
case roles::ENTRY:
|
case roles::ENTRY:
|
||||||
case roles::STATICTEXT:
|
case roles::STATICTEXT:
|
||||||
case roles::HEADING:
|
|
||||||
case roles::LABEL:
|
case roles::LABEL:
|
||||||
case roles::CAPTION:
|
case roles::CAPTION:
|
||||||
case roles::ACCEL_LABEL:
|
case roles::ACCEL_LABEL:
|
||||||
case roles::TEXT_LEAF:
|
case roles::TEXT_LEAF:
|
||||||
// normal textfield (static or editable)
|
// normal textfield (static or editable)
|
||||||
return [mozTextAccessible class];
|
return [mozTextAccessible class];
|
||||||
|
|
||||||
|
case roles::LINK:
|
||||||
|
return [mozLinkAccessible class];
|
||||||
|
|
||||||
case roles::COMBOBOX:
|
case roles::COMBOBOX:
|
||||||
return [mozPopupButtonAccessible class];
|
return [mozPopupButtonAccessible class];
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,12 @@ static const NSString* AXRoles [] = {
|
||||||
NSAccessibilityUnknownRole, // ROLE_CARET. unused on OS X
|
NSAccessibilityUnknownRole, // ROLE_CARET. unused on OS X
|
||||||
NSAccessibilityWindowRole, // ROLE_ALERT
|
NSAccessibilityWindowRole, // ROLE_ALERT
|
||||||
NSAccessibilityWindowRole, // ROLE_WINDOW. irrelevant on OS X; all window a11y is handled by the system.
|
NSAccessibilityWindowRole, // ROLE_WINDOW. irrelevant on OS X; all window a11y is handled by the system.
|
||||||
@"AXWebArea", // ROLE_INTERNAL_FRAME
|
NSAccessibilityScrollAreaRole, // ROLE_INTERNAL_FRAME
|
||||||
NSAccessibilityMenuRole, // ROLE_MENUPOPUP. the parent of menuitems
|
NSAccessibilityMenuRole, // ROLE_MENUPOPUP. the parent of menuitems
|
||||||
NSAccessibilityMenuItemRole, // ROLE_MENUITEM.
|
NSAccessibilityMenuItemRole, // ROLE_MENUITEM.
|
||||||
@"AXHelpTag", // ROLE_TOOLTIP. 10.4+ only, so we re-define the constant.
|
@"AXHelpTag", // ROLE_TOOLTIP. 10.4+ only, so we re-define the constant.
|
||||||
NSAccessibilityGroupRole, // ROLE_APPLICATION. unused on OS X. the system will take care of this.
|
NSAccessibilityGroupRole, // ROLE_APPLICATION. unused on OS X. the system will take care of this.
|
||||||
NSAccessibilityGroupRole, // ROLE_DOCUMENT
|
@"AXWebArea", // ROLE_DOCUMENT
|
||||||
NSAccessibilityGroupRole, // ROLE_PANE
|
NSAccessibilityGroupRole, // ROLE_PANE
|
||||||
NSAccessibilityUnknownRole, // ROLE_CHART
|
NSAccessibilityUnknownRole, // ROLE_CHART
|
||||||
NSAccessibilityWindowRole, // ROLE_DIALOG. there's a dialog subrole.
|
NSAccessibilityWindowRole, // ROLE_DIALOG. there's a dialog subrole.
|
||||||
|
@ -74,12 +74,12 @@ static const NSString* AXRoles [] = {
|
||||||
NSAccessibilityGroupRole, // ROLE_CELL
|
NSAccessibilityGroupRole, // ROLE_CELL
|
||||||
@"AXLink", // ROLE_LINK. 10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
|
@"AXLink", // ROLE_LINK. 10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
|
||||||
@"AXHelpTag", // ROLE_HELPBALLOON
|
@"AXHelpTag", // ROLE_HELPBALLOON
|
||||||
NSAccessibilityUnknownRole, // ROLE_CHARACTER. unusued on OS X
|
NSAccessibilityUnknownRole, // ROLE_CHARACTER. unused on OS X
|
||||||
NSAccessibilityListRole, // ROLE_LIST
|
NSAccessibilityListRole, // ROLE_LIST
|
||||||
NSAccessibilityRowRole, // ROLE_LISTITEM
|
NSAccessibilityRowRole, // ROLE_LISTITEM
|
||||||
NSAccessibilityOutlineRole, // ROLE_OUTLINE
|
NSAccessibilityOutlineRole, // ROLE_OUTLINE
|
||||||
NSAccessibilityRowRole, // ROLE_OUTLINEITEM. XXX: use OutlineRow as subrole.
|
NSAccessibilityRowRole, // ROLE_OUTLINEITEM. XXX: use OutlineRow as subrole.
|
||||||
NSAccessibilityGroupRole, // ROLE_PAGETAB
|
NSAccessibilityRadioButtonRole, // ROLE_PAGETAB
|
||||||
NSAccessibilityGroupRole, // ROLE_PROPERTYPAGE
|
NSAccessibilityGroupRole, // ROLE_PROPERTYPAGE
|
||||||
NSAccessibilityUnknownRole, // ROLE_INDICATOR
|
NSAccessibilityUnknownRole, // ROLE_INDICATOR
|
||||||
NSAccessibilityImageRole, // ROLE_GRAPHIC
|
NSAccessibilityImageRole, // ROLE_GRAPHIC
|
||||||
|
@ -102,7 +102,7 @@ static const NSString* AXRoles [] = {
|
||||||
NSAccessibilityMenuButtonRole, // ROLE_BUTTONMENU
|
NSAccessibilityMenuButtonRole, // ROLE_BUTTONMENU
|
||||||
NSAccessibilityGroupRole, // ROLE_BUTTONDROPDOWNGRID
|
NSAccessibilityGroupRole, // ROLE_BUTTONDROPDOWNGRID
|
||||||
NSAccessibilityUnknownRole, // ROLE_WHITESPACE
|
NSAccessibilityUnknownRole, // ROLE_WHITESPACE
|
||||||
NSAccessibilityGroupRole, // ROLE_PAGETABLIST
|
NSAccessibilityTabGroupRole, // ROLE_PAGETABLIST
|
||||||
NSAccessibilityUnknownRole, // ROLE_CLOCK. unused on OS X
|
NSAccessibilityUnknownRole, // ROLE_CLOCK. unused on OS X
|
||||||
NSAccessibilityButtonRole, // ROLE_SPLITBUTTON
|
NSAccessibilityButtonRole, // ROLE_SPLITBUTTON
|
||||||
NSAccessibilityUnknownRole, // ROLE_IPADDRESS
|
NSAccessibilityUnknownRole, // ROLE_IPADDRESS
|
||||||
|
@ -146,9 +146,9 @@ static const NSString* AXRoles [] = {
|
||||||
NSAccessibilityTextFieldRole, // ROLE_EDITBAR
|
NSAccessibilityTextFieldRole, // ROLE_EDITBAR
|
||||||
NSAccessibilityTextFieldRole, // ROLE_ENTRY
|
NSAccessibilityTextFieldRole, // ROLE_ENTRY
|
||||||
NSAccessibilityStaticTextRole, // ROLE_CAPTION
|
NSAccessibilityStaticTextRole, // ROLE_CAPTION
|
||||||
@"AXWebArea", // ROLE_DOCUMENT_FRAME
|
NSAccessibilityScrollAreaRole, // ROLE_DOCUMENT_FRAME
|
||||||
NSAccessibilityStaticTextRole, // ROLE_HEADING
|
@"AXHeading", // ROLE_HEADING
|
||||||
NSAccessibilityGroupRole, // ROLE_PAGE
|
NSAccessibilityGroupRole, // ROLE_PAG
|
||||||
NSAccessibilityGroupRole, // ROLE_SECTION
|
NSAccessibilityGroupRole, // ROLE_SECTION
|
||||||
NSAccessibilityUnknownRole, // ROLE_REDUNDANT_OBJECT
|
NSAccessibilityUnknownRole, // ROLE_REDUNDANT_OBJECT
|
||||||
NSAccessibilityGroupRole, // ROLE_FORM
|
NSAccessibilityGroupRole, // ROLE_FORM
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "Compatibility.h"
|
#include "Compatibility.h"
|
||||||
|
|
||||||
#include "nsWinUtils.h"
|
#include "nsWinUtils.h"
|
||||||
|
#include "Statistics.h"
|
||||||
|
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
|
||||||
|
@ -84,18 +85,37 @@ PRUint32 Compatibility::sMode = Compatibility::NoCompatibilityMode;
|
||||||
void
|
void
|
||||||
Compatibility::Init()
|
Compatibility::Init()
|
||||||
{
|
{
|
||||||
|
// Note we collect some AT statistics/telemetry here for convenience.
|
||||||
|
|
||||||
HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
|
HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
|
||||||
if (jawsHandle) {
|
if (jawsHandle) {
|
||||||
sMode |= JAWSMode;
|
sMode |= JAWSMode;
|
||||||
// IA2 off mode for JAWS versions below 8.0.2173.
|
// IA2 off mode for JAWS versions below 8.0.2173.
|
||||||
if (IsModuleVersionLessThan(jawsHandle, 8, 2173))
|
if (IsModuleVersionLessThan(jawsHandle, 8, 2173)) {
|
||||||
sMode |= IA2OffMode;
|
sMode |= IA2OffMode;
|
||||||
|
statistics::A11yConsumers(OLDJAWS);
|
||||||
|
} else {
|
||||||
|
statistics::A11yConsumers(JAWS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::GetModuleHandleW(L"gwm32inc"))
|
if (::GetModuleHandleW(L"gwm32inc")) {
|
||||||
sMode |= WEMode;
|
sMode |= WEMode;
|
||||||
if (::GetModuleHandleW(L"dolwinhk"))
|
statistics::A11yConsumers(WE);
|
||||||
|
}
|
||||||
|
if (::GetModuleHandleW(L"dolwinhk")) {
|
||||||
sMode |= DolphinMode;
|
sMode |= DolphinMode;
|
||||||
|
statistics::A11yConsumers(DOLPHIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::GetModuleHandleW(L"STSA32"))
|
||||||
|
statistics::A11yConsumers(SEROTEK);
|
||||||
|
|
||||||
|
if (::GetModuleHandleW(L"nvdaHelperRemote"))
|
||||||
|
statistics::A11yConsumers(NVDA);
|
||||||
|
|
||||||
|
if (::GetModuleHandleW(L"OsmHooks"))
|
||||||
|
statistics::A11yConsumers(COBRA);
|
||||||
|
|
||||||
// Turn off new tab switching for Jaws and WE.
|
// Turn off new tab switching for Jaws and WE.
|
||||||
if (sMode & JAWSMode || sMode & WEMode) {
|
if (sMode & JAWSMode || sMode & WEMode) {
|
||||||
|
|
|
@ -97,6 +97,19 @@ private:
|
||||||
IA2OffMode = 1 << 3
|
IA2OffMode = 1 << 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of detected consumers of a11y (used for statistics/telemetry)
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
NVDA = 0,
|
||||||
|
JAWS = 1,
|
||||||
|
OLDJAWS = 2,
|
||||||
|
WE = 3,
|
||||||
|
DOLPHIN = 4,
|
||||||
|
SEROTEK = 5,
|
||||||
|
COBRA = 6
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static PRUint32 sMode;
|
static PRUint32 sMode;
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,6 +75,7 @@ _TEST_FILES =\
|
||||||
actions.js \
|
actions.js \
|
||||||
attributes.js \
|
attributes.js \
|
||||||
autocomplete.js \
|
autocomplete.js \
|
||||||
|
browser.js \
|
||||||
common.js \
|
common.js \
|
||||||
events.js \
|
events.js \
|
||||||
grid.js \
|
grid.js \
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
* Load the browser with the given url and then invokes the given function.
|
||||||
|
*/
|
||||||
|
function openBrowserWindow(aFunc, aURL)
|
||||||
|
{
|
||||||
|
gBrowserContext.testFunc = aFunc;
|
||||||
|
gBrowserContext.startURL = aURL;
|
||||||
|
|
||||||
|
addLoadEvent(openBrowserWindowIntl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the browser window.
|
||||||
|
*/
|
||||||
|
function closeBrowserWindow()
|
||||||
|
{
|
||||||
|
gBrowserContext.browserWnd.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the browser window object.
|
||||||
|
*/
|
||||||
|
function browserWindow()
|
||||||
|
{
|
||||||
|
return gBrowserContext.browserWnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return tab browser object.
|
||||||
|
*/
|
||||||
|
function tabBrowser()
|
||||||
|
{
|
||||||
|
return browserWindow().gBrowser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return browser element of the current tab.
|
||||||
|
*/
|
||||||
|
function currentBrowser()
|
||||||
|
{
|
||||||
|
return tabBrowser().selectedBrowser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return DOM document of the current tab.
|
||||||
|
*/
|
||||||
|
function currentTabDocument()
|
||||||
|
{
|
||||||
|
return currentBrowser().contentDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return input element of address bar.
|
||||||
|
*/
|
||||||
|
function urlbarInput()
|
||||||
|
{
|
||||||
|
return browserWindow().document.getElementById("urlbar").inputField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return reload button.
|
||||||
|
*/
|
||||||
|
function reloadButton()
|
||||||
|
{
|
||||||
|
return browserWindow().document.getElementById("urlbar-reload-button");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private section
|
||||||
|
|
||||||
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
var gBrowserContext =
|
||||||
|
{
|
||||||
|
browserWnd: null,
|
||||||
|
testFunc: null,
|
||||||
|
startURL: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
function openBrowserWindowIntl()
|
||||||
|
{
|
||||||
|
gBrowserContext.browserWnd =
|
||||||
|
window.openDialog(Services.prefs.getCharPref("browser.chromeURL"),
|
||||||
|
"_blank", "chrome,all,dialog=no",
|
||||||
|
gBrowserContext.startURL);
|
||||||
|
|
||||||
|
addA11yLoadEvent(startBrowserTests, browserWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
function startBrowserTests()
|
||||||
|
{
|
||||||
|
if (gBrowserContext.startURL) // wait for load
|
||||||
|
addA11yLoadEvent(gBrowserContext.testFunc, currentBrowser().contentWindow);
|
||||||
|
else
|
||||||
|
gBrowserContext.testFunc();
|
||||||
|
}
|
|
@ -31,6 +31,8 @@ const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// General
|
// General
|
||||||
|
|
||||||
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up this variable to dump events into DOM.
|
* Set up this variable to dump events into DOM.
|
||||||
*/
|
*/
|
||||||
|
@ -172,7 +174,7 @@ const DO_NOT_FINISH_TEST = 1;
|
||||||
* // phase getter: function() {},
|
* // phase getter: function() {},
|
||||||
* //
|
* //
|
||||||
* // * Callback, called to match handled event. *
|
* // * Callback, called to match handled event. *
|
||||||
* // match : function() {},
|
* // match : function(aEvent) {},
|
||||||
* //
|
* //
|
||||||
* // * Callback, called when event is handled
|
* // * Callback, called when event is handled
|
||||||
* // check: function(aEvent) {},
|
* // check: function(aEvent) {},
|
||||||
|
@ -1338,10 +1340,10 @@ function caretMoveChecker(aCaretOffset, aTargetOrFunc, aTargetFuncArg)
|
||||||
* State change checker.
|
* State change checker.
|
||||||
*/
|
*/
|
||||||
function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
||||||
aTargetOrFunc, aTargetFuncArg)
|
aTargetOrFunc, aTargetFuncArg, aIsAsync)
|
||||||
{
|
{
|
||||||
this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
|
this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
|
||||||
aTargetFuncArg);
|
aTargetFuncArg, aIsAsync);
|
||||||
|
|
||||||
this.check = function stateChangeChecker_check(aEvent)
|
this.check = function stateChangeChecker_check(aEvent)
|
||||||
{
|
{
|
||||||
|
@ -1368,6 +1370,22 @@ function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
||||||
var unxpdExtraState = aIsEnabled ? 0 : (aIsExtraState ? aState : 0);
|
var unxpdExtraState = aIsEnabled ? 0 : (aIsExtraState ? aState : 0);
|
||||||
testStates(event.accessible, state, extraState, unxpdState, unxpdExtraState);
|
testStates(event.accessible, state, extraState, unxpdState, unxpdExtraState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.match = function stateChangeChecker_match(aEvent)
|
||||||
|
{
|
||||||
|
if (aEvent instanceof nsIAccessibleStateChangeEvent) {
|
||||||
|
var scEvent = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
|
||||||
|
return aEvent.accessible = this.target && scEvent.state == aState;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function asyncStateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
||||||
|
aTargetOrFunc, aTargetFuncArg)
|
||||||
|
{
|
||||||
|
this.__proto__ = new stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
||||||
|
aTargetOrFunc, aTargetFuncArg, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1414,12 +1432,6 @@ var gA11yEventApplicantsCount = 0;
|
||||||
|
|
||||||
var gA11yEventObserver =
|
var gA11yEventObserver =
|
||||||
{
|
{
|
||||||
// The service reference needs to live in the observer, instead of as a global var,
|
|
||||||
// to be available in observe() catch case too.
|
|
||||||
observerService :
|
|
||||||
Components.classes["@mozilla.org/observer-service;1"]
|
|
||||||
.getService(nsIObserverService),
|
|
||||||
|
|
||||||
observe: function observe(aSubject, aTopic, aData)
|
observe: function observe(aSubject, aTopic, aData)
|
||||||
{
|
{
|
||||||
if (aTopic != "accessible-event")
|
if (aTopic != "accessible-event")
|
||||||
|
@ -1431,7 +1443,7 @@ var gA11yEventObserver =
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// After a test is aborted (i.e. timed out by the harness), this exception is soon triggered.
|
// After a test is aborted (i.e. timed out by the harness), this exception is soon triggered.
|
||||||
// Remove the leftover observer, otherwise it "leaks" to all the following tests.
|
// Remove the leftover observer, otherwise it "leaks" to all the following tests.
|
||||||
this.observerService.removeObserver(this, "accessible-event");
|
Services.obs.removeObserver(this, "accessible-event");
|
||||||
// Forward the exception, with added explanation.
|
// Forward the exception, with added explanation.
|
||||||
throw "[accessible/events.js, gA11yEventObserver.observe] This is expected if a previous test has been aborted... Initial exception was: [ " + ex + " ]";
|
throw "[accessible/events.js, gA11yEventObserver.observe] This is expected if a previous test has been aborted... Initial exception was: [ " + ex + " ]";
|
||||||
}
|
}
|
||||||
|
@ -1485,14 +1497,12 @@ function listenA11yEvents(aStartToListen)
|
||||||
if (aStartToListen) {
|
if (aStartToListen) {
|
||||||
// Add observer when adding the first applicant only.
|
// Add observer when adding the first applicant only.
|
||||||
if (!(gA11yEventApplicantsCount++))
|
if (!(gA11yEventApplicantsCount++))
|
||||||
gA11yEventObserver.observerService
|
Services.obs.addObserver(gA11yEventObserver, "accessible-event", false);
|
||||||
.addObserver(gA11yEventObserver, "accessible-event", false);
|
|
||||||
} else {
|
} else {
|
||||||
// Remove observer when there are no more applicants only.
|
// Remove observer when there are no more applicants only.
|
||||||
// '< 0' case should not happen, but just in case: removeObserver() will throw.
|
// '< 0' case should not happen, but just in case: removeObserver() will throw.
|
||||||
if (--gA11yEventApplicantsCount <= 0)
|
if (--gA11yEventApplicantsCount <= 0)
|
||||||
gA11yEventObserver.observerService
|
Services.obs.removeObserver(gA11yEventObserver, "accessible-event");
|
||||||
.removeObserver(gA11yEventObserver, "accessible-event");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1609,11 +1619,8 @@ var gLogger =
|
||||||
logToAppConsole: function logger_logToAppConsole(aMsg)
|
logToAppConsole: function logger_logToAppConsole(aMsg)
|
||||||
{
|
{
|
||||||
if (gA11yEventDumpToAppConsole)
|
if (gA11yEventDumpToAppConsole)
|
||||||
consoleService.logStringMessage("events: " + aMsg);
|
Services.console.logStringMessage("events: " + aMsg);
|
||||||
},
|
}
|
||||||
|
|
||||||
consoleService: Components.classes["@mozilla.org/consoleservice;1"].
|
|
||||||
getService(Components.interfaces.nsIConsoleService)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ relativesrcdir = accessible/events
|
||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
# test_docload.xul, docload_wnd.xul, test_scroll.xul disabled for misusing <tabbrowser> (bug 715857)
|
# test_scroll.xul disabled for misusing <tabbrowser> (bug 715857)
|
||||||
|
|
||||||
_TEST_FILES =\
|
_TEST_FILES =\
|
||||||
docload_wnd.html \
|
docload_wnd.html \
|
||||||
|
@ -61,6 +61,7 @@ _TEST_FILES =\
|
||||||
test_coalescence.html \
|
test_coalescence.html \
|
||||||
test_contextmenu.html \
|
test_contextmenu.html \
|
||||||
test_docload.html \
|
test_docload.html \
|
||||||
|
test_docload.xul \
|
||||||
test_dragndrop.html \
|
test_dragndrop.html \
|
||||||
test_flush.html \
|
test_flush.html \
|
||||||
test_focus_aria_activedescendant.html \
|
test_focus_aria_activedescendant.html \
|
||||||
|
|
|
@ -1,275 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
|
||||||
|
|
||||||
<!-- Firefox tabbrowser -->
|
|
||||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
|
||||||
type="text/css"?>
|
|
||||||
<!-- SeaMonkey tabbrowser -->
|
|
||||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
|
||||||
type="text/css"?>
|
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
||||||
|
|
||||||
<script type="application/javascript"
|
|
||||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
|
||||||
|
|
||||||
<script type="application/javascript">
|
|
||||||
<![CDATA[
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// SimpleTest stuffs
|
|
||||||
|
|
||||||
var gOpenerWnd = window.opener.wrappedJSObject;
|
|
||||||
|
|
||||||
function ok(aCond, aMsg) {
|
|
||||||
gOpenerWnd.SimpleTest.ok(aCond, aMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function is(aExpected, aActual, aMsg) {
|
|
||||||
gOpenerWnd.SimpleTest.is(aExpected, aActual, aMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
|
|
||||||
aAbsentExtraState)
|
|
||||||
{
|
|
||||||
gOpenerWnd.testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
|
|
||||||
aAbsentExtraState);
|
|
||||||
}
|
|
||||||
|
|
||||||
var invokerChecker = gOpenerWnd.invokerChecker;
|
|
||||||
var asyncInvokerChecker = gOpenerWnd.asyncInvokerChecker;
|
|
||||||
|
|
||||||
const STATE_BUSY = gOpenerWnd.STATE_BUSY;
|
|
||||||
const EVENT_DOCUMENT_LOAD_COMPLETE =
|
|
||||||
gOpenerWnd.EVENT_DOCUMENT_LOAD_COMPLETE;
|
|
||||||
const EVENT_DOCUMENT_RELOAD = gOpenerWnd.EVENT_DOCUMENT_RELOAD;
|
|
||||||
const EVENT_DOCUMENT_LOAD_STOPPED =
|
|
||||||
gOpenerWnd.EVENT_DOCUMENT_LOAD_STOPPED;
|
|
||||||
const EVENT_REORDER = gOpenerWnd.EVENT_REORDER;
|
|
||||||
const EVENT_STATE_CHANGE = gOpenerWnd.EVENT_STATE_CHANGE;
|
|
||||||
const nsIAccessibleStateChangeEvent =
|
|
||||||
gOpenerWnd.nsIAccessibleStateChangeEvent;
|
|
||||||
|
|
||||||
//gOpenerWnd.gA11yEventDumpToConsole = true; // debug
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Hacks to make xul:tabbrowser work.
|
|
||||||
|
|
||||||
var handleDroppedLink = null; // needed for tabbrowser usage
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
var XULBrowserWindow = {
|
|
||||||
isBusy: false,
|
|
||||||
setOverLink: function (link, b) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
gFindBarInitialized = false;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Helpers.
|
|
||||||
|
|
||||||
function getContainer()
|
|
||||||
{
|
|
||||||
var idx = gTabBrowser.tabContainer.selectedIndex;
|
|
||||||
return gTabBrowser.getBrowserAtIndex(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDocument()
|
|
||||||
{
|
|
||||||
return getContainer().contentDocument;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Invoker checkers.
|
|
||||||
function stateBusyChecker(aIsEnabled)
|
|
||||||
{
|
|
||||||
this.type = EVENT_STATE_CHANGE;
|
|
||||||
this.__defineGetter__("target", getDocument);
|
|
||||||
|
|
||||||
this.check = function stateBusyChecker_check(aEvent)
|
|
||||||
{
|
|
||||||
var event = null;
|
|
||||||
try {
|
|
||||||
var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
|
|
||||||
} catch (e) {
|
|
||||||
ok(false, "State change event was expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!event)
|
|
||||||
return;
|
|
||||||
|
|
||||||
is(event.state, STATE_BUSY, "Wrong state of statechange event.");
|
|
||||||
is(event.isEnabled(), aIsEnabled,
|
|
||||||
"Wrong value of state of statechange event");
|
|
||||||
|
|
||||||
testStates(event.accessible, (aIsEnabled ? STATE_BUSY : 0), 0,
|
|
||||||
(aIsEnabled ? 0 : STATE_BUSY), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function documentReloadChecker(aIsFromUserInput)
|
|
||||||
{
|
|
||||||
this.type = EVENT_DOCUMENT_RELOAD;
|
|
||||||
this.__defineGetter__("target", getDocument);
|
|
||||||
|
|
||||||
this.check = function documentReloadChecker_check(aEvent)
|
|
||||||
{
|
|
||||||
is(aEvent.isFromUserInput, aIsFromUserInput,
|
|
||||||
"Wrong value of isFromUserInput");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Invokers.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load URI.
|
|
||||||
*/
|
|
||||||
function loadURIInvoker(aURI)
|
|
||||||
{
|
|
||||||
this.invoke = function loadURIInvoker_invoke()
|
|
||||||
{
|
|
||||||
gTabBrowser.loadURI(aURI);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.eventSeq = [
|
|
||||||
// We don't expect state change event for busy true since things happen
|
|
||||||
// quickly and it's coalesced.
|
|
||||||
new asyncInvokerChecker(EVENT_REORDER, getContainer),
|
|
||||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
|
|
||||||
new stateBusyChecker(false)
|
|
||||||
];
|
|
||||||
|
|
||||||
this.getID = function loadURIInvoker_getID()
|
|
||||||
{
|
|
||||||
return "load uri " + aURI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Click reload page button.
|
|
||||||
*/
|
|
||||||
function clickReloadBtnInvoker()
|
|
||||||
{
|
|
||||||
this.invoke = function clickReloadBtnInvoker_invoke()
|
|
||||||
{
|
|
||||||
synthesizeMouse(document.getElementById("reloadbtn"), 5, 5, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.eventSeq = [
|
|
||||||
new documentReloadChecker(true),
|
|
||||||
new asyncInvokerChecker(EVENT_REORDER, getContainer),
|
|
||||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
|
|
||||||
new stateBusyChecker(false)
|
|
||||||
];
|
|
||||||
|
|
||||||
this.getID = function reloadInvoker_getID()
|
|
||||||
{
|
|
||||||
return "click reload page button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reload the page.
|
|
||||||
*/
|
|
||||||
function reloadInvoker()
|
|
||||||
{
|
|
||||||
this.invoke = function reloadInvoker_invoke()
|
|
||||||
{
|
|
||||||
gTabBrowser.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.eventSeq = [
|
|
||||||
new documentReloadChecker(false),
|
|
||||||
new asyncInvokerChecker(EVENT_REORDER, getContainer),
|
|
||||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
|
|
||||||
new stateBusyChecker(false)
|
|
||||||
];
|
|
||||||
|
|
||||||
this.getID = function reloadInvoker_getID()
|
|
||||||
{
|
|
||||||
return "reload page";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load wrong URI what results in error page loading.
|
|
||||||
*/
|
|
||||||
function loadErrorPageInvoker(aURL, aURLDescr)
|
|
||||||
{
|
|
||||||
this.invoke = function loadErrorPageInvoker_invoke()
|
|
||||||
{
|
|
||||||
gTabBrowser.loadURI(aURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.eventSeq = [
|
|
||||||
// We don't expect state change for busy true, load stopped events since
|
|
||||||
// things happen quickly and it's coalesced.
|
|
||||||
new asyncInvokerChecker(EVENT_REORDER, getContainer),
|
|
||||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
|
|
||||||
new stateBusyChecker(false)
|
|
||||||
];
|
|
||||||
|
|
||||||
this.getID = function loadErrorPageInvoker_getID()
|
|
||||||
{
|
|
||||||
return "load error page: '" + aURLDescr + "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Tests
|
|
||||||
|
|
||||||
var gQueue = null;
|
|
||||||
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
|
|
||||||
var gTabBrowser = null;
|
|
||||||
function doTest()
|
|
||||||
{
|
|
||||||
gTabBrowser = document.getElementById("content");
|
|
||||||
|
|
||||||
gQueue = new gOpenerWnd.eventQueue();
|
|
||||||
gQueue.push(new loadURIInvoker("about:"));
|
|
||||||
gQueue.push(new clickReloadBtnInvoker());
|
|
||||||
gQueue.push(new loadURIInvoker("about:mozilla"));
|
|
||||||
gQueue.push(new reloadInvoker());
|
|
||||||
gQueue.push(new loadErrorPageInvoker("www.wronguri.wronguri",
|
|
||||||
"Server not found"));
|
|
||||||
gQueue.push(new loadErrorPageInvoker("https://nocert.example.com:443",
|
|
||||||
"Untrusted Connection"));
|
|
||||||
|
|
||||||
gQueue.onFinish = function() { window.close(); }
|
|
||||||
gQueue.invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
gOpenerWnd.addA11yLoadEvent(doTest);
|
|
||||||
]]>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Hack to make xul:tabbrowser work -->
|
|
||||||
<menubar>
|
|
||||||
<menu label="menu">
|
|
||||||
<menupopup>
|
|
||||||
<menuitem label="close window hook" id="menu_closeWindow"/>
|
|
||||||
<menuitem label="close hook" id="menu_close"/>
|
|
||||||
</menupopup>
|
|
||||||
</menu>
|
|
||||||
</menubar>
|
|
||||||
|
|
||||||
<button id="reloadbtn" label="reload page"
|
|
||||||
oncommand="gTabBrowser.reload();"/>
|
|
||||||
|
|
||||||
<toolbar>
|
|
||||||
<tabs id="tabbrowser-tabs" class="tabbrowser-tabs"
|
|
||||||
tabbrowser="content"
|
|
||||||
flex="1"
|
|
||||||
setfocus="false">
|
|
||||||
<tab class="tabbrowser-tab" selected="true"/>
|
|
||||||
</tabs>
|
|
||||||
</toolbar>
|
|
||||||
<tabbrowser id="content"
|
|
||||||
type="content-primary"
|
|
||||||
tabcontainer="tabbrowser-tabs"
|
|
||||||
flex="1"/>
|
|
||||||
|
|
||||||
</window>
|
|
|
@ -19,20 +19,172 @@
|
||||||
src="../states.js"></script>
|
src="../states.js"></script>
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../events.js"></script>
|
src="../events.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../browser.js"></script>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
// var gA11yEventDumpID = "eventdump"; // debug stuff
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Invoker checkers.
|
||||||
function doTest()
|
function stateBusyChecker(aIsEnabled)
|
||||||
{
|
{
|
||||||
var w = window.openDialog("../events/docload_wnd.xul",
|
this.type = EVENT_STATE_CHANGE;
|
||||||
"docload_test",
|
this.__defineGetter__("target", currentTabDocument);
|
||||||
"chrome,width=600,height=600");
|
|
||||||
|
this.check = function stateBusyChecker_check(aEvent)
|
||||||
|
{
|
||||||
|
var event = null;
|
||||||
|
try {
|
||||||
|
var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
|
||||||
|
} catch (e) {
|
||||||
|
ok(false, "State change event was expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event)
|
||||||
|
return;
|
||||||
|
|
||||||
|
is(event.state, STATE_BUSY, "Wrong state of statechange event.");
|
||||||
|
is(event.isEnabled(), aIsEnabled,
|
||||||
|
"Wrong value of state of statechange event");
|
||||||
|
|
||||||
|
testStates(event.accessible, (aIsEnabled ? STATE_BUSY : 0), 0,
|
||||||
|
(aIsEnabled ? 0 : STATE_BUSY), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function documentReloadChecker(aIsFromUserInput)
|
||||||
|
{
|
||||||
|
this.type = EVENT_DOCUMENT_RELOAD;
|
||||||
|
this.__defineGetter__("target", currentTabDocument);
|
||||||
|
|
||||||
|
this.check = function documentReloadChecker_check(aEvent)
|
||||||
|
{
|
||||||
|
is(aEvent.isFromUserInput, aIsFromUserInput,
|
||||||
|
"Wrong value of isFromUserInput");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Invokers.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load URI.
|
||||||
|
*/
|
||||||
|
function loadURIInvoker(aURI)
|
||||||
|
{
|
||||||
|
this.invoke = function loadURIInvoker_invoke()
|
||||||
|
{
|
||||||
|
tabBrowser().loadURI(aURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventSeq = [
|
||||||
|
// We don't expect state change event for busy true since things happen
|
||||||
|
// quickly and it's coalesced.
|
||||||
|
new asyncInvokerChecker(EVENT_REORDER, currentBrowser),
|
||||||
|
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument),
|
||||||
|
new stateBusyChecker(false)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.getID = function loadURIInvoker_getID()
|
||||||
|
{
|
||||||
|
return "load uri " + aURI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload the page by F5 (isFromUserInput flag is true).
|
||||||
|
*/
|
||||||
|
function userReloadInvoker()
|
||||||
|
{
|
||||||
|
this.invoke = function userReloadInvoker_invoke()
|
||||||
|
{
|
||||||
|
synthesizeKey("VK_F5", {}, browserWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventSeq = [
|
||||||
|
new documentReloadChecker(true),
|
||||||
|
new asyncInvokerChecker(EVENT_REORDER, currentBrowser),
|
||||||
|
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument),
|
||||||
|
new stateBusyChecker(false)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.getID = function userReloadInvoker_getID()
|
||||||
|
{
|
||||||
|
return "user reload page";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload the page (isFromUserInput flag is false).
|
||||||
|
*/
|
||||||
|
function reloadInvoker()
|
||||||
|
{
|
||||||
|
this.invoke = function reloadInvoker_invoke()
|
||||||
|
{
|
||||||
|
tabBrowser().reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventSeq = [
|
||||||
|
new documentReloadChecker(false),
|
||||||
|
new asyncInvokerChecker(EVENT_REORDER, currentBrowser),
|
||||||
|
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument),
|
||||||
|
new stateBusyChecker(false)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.getID = function reloadInvoker_getID()
|
||||||
|
{
|
||||||
|
return "reload page";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load wrong URI what results in error page loading.
|
||||||
|
*/
|
||||||
|
function loadErrorPageInvoker(aURL, aURLDescr)
|
||||||
|
{
|
||||||
|
this.invoke = function loadErrorPageInvoker_invoke()
|
||||||
|
{
|
||||||
|
tabBrowser().loadURI(aURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventSeq = [
|
||||||
|
// We don't expect state change for busy true, load stopped events since
|
||||||
|
// things happen quickly and it's coalesced.
|
||||||
|
new asyncInvokerChecker(EVENT_REORDER, currentBrowser),
|
||||||
|
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument),
|
||||||
|
new stateBusyChecker(false)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.getID = function loadErrorPageInvoker_getID()
|
||||||
|
{
|
||||||
|
return "load error page: '" + aURLDescr + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tests
|
||||||
|
|
||||||
|
gA11yEventDumpToConsole = true; // debug
|
||||||
|
|
||||||
|
var gQueue = null;
|
||||||
|
function doTests()
|
||||||
|
{
|
||||||
|
gQueue = new eventQueue();
|
||||||
|
gQueue.push(new loadURIInvoker("about:"));
|
||||||
|
gQueue.push(new userReloadInvoker());
|
||||||
|
gQueue.push(new loadURIInvoker("about:mozilla"));
|
||||||
|
gQueue.push(new reloadInvoker());
|
||||||
|
gQueue.push(new loadErrorPageInvoker("www.wronguri.wronguri",
|
||||||
|
"Server not found"));
|
||||||
|
gQueue.push(new loadErrorPageInvoker("https://nocert.example.com:443",
|
||||||
|
"Untrusted Connection"));
|
||||||
|
|
||||||
|
gQueue.onFinish = function() { closeBrowserWindow(); }
|
||||||
|
gQueue.invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
addLoadEvent(doTest);
|
openBrowserWindow(doTests);
|
||||||
]]>
|
]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,12 @@
|
||||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||||
type="text/css"?>
|
type="text/css"?>
|
||||||
|
|
||||||
|
<!-- Firefox searchbar -->
|
||||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||||
type="text/css"?>
|
type="text/css"?>
|
||||||
|
<!-- SeaMonkey searchbar -->
|
||||||
|
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||||
|
type="text/css"?>
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
title="Accessible focus event testing">
|
title="Accessible focus event testing">
|
||||||
|
|
|
@ -19,40 +19,20 @@
|
||||||
src="../states.js"></script>
|
src="../states.js"></script>
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../events.js"></script>
|
src="../events.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../browser.js"></script>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
function tabBrowser()
|
|
||||||
{
|
|
||||||
return gBrowserWnd.gBrowser;
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentBrowser()
|
|
||||||
{
|
|
||||||
return tabBrowser().selectedBrowser;
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentTabDocument()
|
|
||||||
{
|
|
||||||
return currentBrowser().contentDocument;
|
|
||||||
}
|
|
||||||
|
|
||||||
function inputInDocument()
|
function inputInDocument()
|
||||||
{
|
{
|
||||||
var tabdoc = currentTabDocument();
|
var tabdoc = currentTabDocument();
|
||||||
return tabdoc.getElementById("input");
|
return tabdoc.getElementById("input");
|
||||||
}
|
}
|
||||||
|
|
||||||
function urlbarInput()
|
|
||||||
{
|
|
||||||
return gBrowserWnd.document.getElementById("urlbar").inputField;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Invokers
|
// Invokers
|
||||||
|
|
||||||
|
@ -96,22 +76,6 @@
|
||||||
var gInputDocURI = "data:text/html,<html><input id='input'></html>";
|
var gInputDocURI = "data:text/html,<html><input id='input'></html>";
|
||||||
var gButtonDocURI = "data:text/html,<html><input id='input' type='button' value='button'></html>";
|
var gButtonDocURI = "data:text/html,<html><input id='input' type='button' value='button'></html>";
|
||||||
|
|
||||||
var gBrowserWnd = null;
|
|
||||||
function loadBrowser()
|
|
||||||
{
|
|
||||||
gBrowserWnd = window.openDialog(Services.prefs.getCharPref("browser.chromeURL"),
|
|
||||||
"_blank", "chrome,all,dialog=no", gInputDocURI);
|
|
||||||
|
|
||||||
addA11yLoadEvent(startTests, gBrowserWnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
function startTests()
|
|
||||||
{
|
|
||||||
// Wait for tab load.
|
|
||||||
var browser = gBrowserWnd.gBrowser.selectedBrowser;
|
|
||||||
addA11yLoadEvent(doTests, browser.contentWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
//gA11yEventDumpToConsole = true; // debug
|
//gA11yEventDumpToConsole = true; // debug
|
||||||
|
|
||||||
var gQueue = null;
|
var gQueue = null;
|
||||||
|
@ -123,7 +87,8 @@
|
||||||
var input = inputInDocument();
|
var input = inputInDocument();
|
||||||
|
|
||||||
// move focus to input inside tab document
|
// move focus to input inside tab document
|
||||||
gQueue.push(new synthTab(tabDocument, new focusChecker(input), gBrowserWnd));
|
gQueue.push(new synthTab(tabDocument, new focusChecker(input),
|
||||||
|
browserWindow()));
|
||||||
|
|
||||||
// open new url, focus moves to new document
|
// open new url, focus moves to new document
|
||||||
gQueue.push(new loadURI(gButtonDocURI));
|
gQueue.push(new loadURI(gButtonDocURI));
|
||||||
|
@ -132,22 +97,22 @@
|
||||||
gQueue.push(new goBack());
|
gQueue.push(new goBack());
|
||||||
|
|
||||||
// open new tab, focus moves to urlbar
|
// open new tab, focus moves to urlbar
|
||||||
gQueue.push(new synthKey(tabDocument, "t", { ctrlKey: true, window: gBrowserWnd },
|
gQueue.push(new synthKey(tabDocument, "t", { ctrlKey: true, window: browserWindow() },
|
||||||
new focusChecker(urlbarInput)));
|
new focusChecker(urlbarInput)));
|
||||||
|
|
||||||
// close open tab, focus goes on input of tab document
|
// close open tab, focus goes on input of tab document
|
||||||
gQueue.push(new synthKey(tabDocument, "w", { ctrlKey: true, window: gBrowserWnd },
|
gQueue.push(new synthKey(tabDocument, "w", { ctrlKey: true, window: browserWindow() },
|
||||||
new focusChecker(inputInDocument)));
|
new focusChecker(inputInDocument)));
|
||||||
|
|
||||||
gQueue.onFinish = function()
|
gQueue.onFinish = function()
|
||||||
{
|
{
|
||||||
gBrowserWnd.close();
|
closeBrowserWindow();
|
||||||
}
|
}
|
||||||
gQueue.invoke();
|
gQueue.invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
addLoadEvent(loadBrowser);
|
openBrowserWindow(doTests, gInputDocURI);
|
||||||
]]>
|
]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://browser/content/utilityOverlay.js"/>
|
||||||
|
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../common.js" />
|
src="../common.js" />
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||||
type="text/css"?>
|
type="text/css"?>
|
||||||
|
|
||||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
|
||||||
type="text/css"?>
|
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
title="Accessible focus testing">
|
title="Accessible focus testing">
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,18 @@
|
||||||
<rule attr="title" type="string"/>
|
<rule attr="title" type="string"/>
|
||||||
</ruleset>
|
</ruleset>
|
||||||
|
|
||||||
|
<ruleset id="htmlimage">
|
||||||
|
<ruleset ref="aria"/>
|
||||||
|
<rule attr="alt" type="string"/>
|
||||||
|
<ruleset ref="htmlelm_end"/>
|
||||||
|
</ruleset>
|
||||||
|
|
||||||
|
<ruleset id="htmlimageemptyalt">
|
||||||
|
<ruleset ref="aria"/>
|
||||||
|
<ruleset ref="htmlelm_end"/>
|
||||||
|
<rule attr="alt" type="string"/>
|
||||||
|
</ruleset>
|
||||||
|
|
||||||
<ruleset id="htmltable">
|
<ruleset id="htmltable">
|
||||||
<ruleset ref="htmlelm_start"/>
|
<ruleset ref="htmlelm_start"/>
|
||||||
<rule elm="caption"/>
|
<rule elm="caption"/>
|
||||||
|
@ -190,6 +202,28 @@
|
||||||
</html:select>
|
</html:select>
|
||||||
</markup>
|
</markup>
|
||||||
|
|
||||||
|
<markup ref="html:img" ruleset="htmlimage">
|
||||||
|
<html:span id="l1" a11yname="test2">test2</html:span>
|
||||||
|
<html:span id="l2" a11yname="test3">test3</html:span>
|
||||||
|
<html:img id="img"
|
||||||
|
aria-label="Logo of Mozilla"
|
||||||
|
aria-labelledby="l1 l2"
|
||||||
|
alt="Mozilla logo"
|
||||||
|
title="This is a logo"
|
||||||
|
src="moz.png"/>
|
||||||
|
</markup>
|
||||||
|
|
||||||
|
<markup ref="html:img" ruleset="htmlimageemptyalt">
|
||||||
|
<html:span id="l1" a11yname="test2">test2</html:span>
|
||||||
|
<html:span id="l2" a11yname="test3">test3</html:span>
|
||||||
|
<html:img id="img"
|
||||||
|
aria-label="Logo of Mozilla"
|
||||||
|
aria-labelledby="l1 l2"
|
||||||
|
title="This is a logo"
|
||||||
|
alt=""
|
||||||
|
src="moz.png"/>
|
||||||
|
</markup>
|
||||||
|
|
||||||
<markup ref="html:table/html:tr/html:td" ruleset="htmlelm"
|
<markup ref="html:table/html:tr/html:td" ruleset="htmlelm"
|
||||||
id="markup4test">
|
id="markup4test">
|
||||||
<html:span id="l1" a11yname="test2">test2</html:span>
|
<html:span id="l1" a11yname="test2">test2</html:span>
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://browser/content/utilityOverlay.js"/>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
var gOpenerWnd = window.opener.wrappedJSObject;
|
var gOpenerWnd = window.opener.wrappedJSObject;
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://browser/content/utilityOverlay.js"/>
|
||||||
|
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../common.js" />
|
src="../common.js" />
|
||||||
|
|
|
@ -37,9 +37,11 @@ const STATE_UNAVAILABLE = nsIAccessibleStates.STATE_UNAVAILABLE;
|
||||||
const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
|
const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
|
||||||
const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
|
const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
|
||||||
const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE;
|
const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE;
|
||||||
|
const EXT_STATE_ENABLED = nsIAccessibleStates.EXT_STATE_ENABLED;
|
||||||
const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE;
|
const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE;
|
||||||
const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
|
const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
|
||||||
const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE;
|
const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE;
|
||||||
|
const EXT_STATE_SENSITIVE = nsIAccessibleStates.EXT_STATE_SENSITIVE;
|
||||||
const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE;
|
const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE;
|
||||||
const EXT_STATE_STALE = nsIAccessibleStates.EXT_STATE_STALE;
|
const EXT_STATE_STALE = nsIAccessibleStates.EXT_STATE_STALE;
|
||||||
const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
|
const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
|
||||||
|
|
|
@ -48,7 +48,7 @@ include $(topsrcdir)/config/rules.mk
|
||||||
_TEST_FILES =\
|
_TEST_FILES =\
|
||||||
test_aria.html \
|
test_aria.html \
|
||||||
test_aria_imgmap.html \
|
test_aria_imgmap.html \
|
||||||
test_aria_tabs.html \
|
test_aria_widgetitems.html \
|
||||||
test_buttons.html \
|
test_buttons.html \
|
||||||
test_doc.html \
|
test_doc.html \
|
||||||
test_docarticle.html \
|
test_docarticle.html \
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>Test ARIA tab accessible selected state</title>
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css"
|
|
||||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
|
||||||
|
|
||||||
<script type="application/javascript"
|
|
||||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
|
|
||||||
<script type="application/javascript"
|
|
||||||
src="../common.js"></script>
|
|
||||||
<script type="application/javascript"
|
|
||||||
src="../states.js"></script>
|
|
||||||
<script type="application/javascript"
|
|
||||||
src="../events.js"></script>
|
|
||||||
|
|
||||||
<script type="application/javascript">
|
|
||||||
function focusARIATab(aID, aIsSelected)
|
|
||||||
{
|
|
||||||
this.DOMNode = getNode(aID);
|
|
||||||
|
|
||||||
this.invoke = function focusARIATab_invoke()
|
|
||||||
{
|
|
||||||
this.DOMNode.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.check = function focusARIATab_check(aEvent)
|
|
||||||
{
|
|
||||||
testStates(this.DOMNode, aIsSelected ? STATE_SELECTED : 0, 0,
|
|
||||||
aIsSelected ? 0 : STATE_SELECTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getID = function focusARIATab_getID()
|
|
||||||
{
|
|
||||||
return "Focused ARIA Tab with aria-selected=" +
|
|
||||||
(aIsSelected ? "true, should" : "false, shouldn't") +
|
|
||||||
" have selected state on " + prettyName(aID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function focusActiveDescendantTab(aTabID, aTabListID, aIsSelected)
|
|
||||||
{
|
|
||||||
this.DOMNode = getNode(aTabID);
|
|
||||||
this.tabListDOMNode = getNode(aTabListID);
|
|
||||||
|
|
||||||
this.invoke = function focusActiveDescendantTab_invoke()
|
|
||||||
{
|
|
||||||
this.tabListDOMNode.setAttribute("aria-activedescendant", aTabID);
|
|
||||||
this.tabListDOMNode.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.check = function focusActiveDescendantTab_check(aEvent)
|
|
||||||
{
|
|
||||||
testStates(this.DOMNode, aIsSelected ? STATE_SELECTED : 0, 0,
|
|
||||||
aIsSelected ? 0 : STATE_SELECTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getID = function tabActiveDescendant_getID()
|
|
||||||
{
|
|
||||||
return "ARIA Tab with activedescendant " +
|
|
||||||
(aIsSelected ? "should" : "shouldn't") +
|
|
||||||
" have the selected state on " + prettyName(aTabID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Test
|
|
||||||
|
|
||||||
//gA11yEventDumpID = "eventdump"; // debug stuff
|
|
||||||
//gA11yEventDumpToConsole = true;
|
|
||||||
|
|
||||||
var gQueue = null;
|
|
||||||
|
|
||||||
function doTest()
|
|
||||||
{
|
|
||||||
// simple tabs
|
|
||||||
testStates("aria_tab1", 0, 0, STATE_SELECTED);
|
|
||||||
testStates("aria_tab2", STATE_SELECTED);
|
|
||||||
|
|
||||||
// To make sure our focus != selected is truly under test, we need to
|
|
||||||
// make sure our cache of what currently has focus is correct, which
|
|
||||||
// we update asyncronously.
|
|
||||||
gQueue = new eventQueue(EVENT_FOCUS);
|
|
||||||
|
|
||||||
gQueue.push(new focusARIATab("aria_tab1", true));
|
|
||||||
gQueue.push(new focusARIATab("aria_tab3", false));
|
|
||||||
gQueue.push(new focusARIATab("aria_tab2", true));
|
|
||||||
|
|
||||||
// selection through aria-activedescendant
|
|
||||||
// Make sure initially setting it selects the tab.
|
|
||||||
gQueue.push(new focusActiveDescendantTab("aria_tab5", "aria_tablist2", true));
|
|
||||||
|
|
||||||
// Now, make sure if one is selected selection gets transferred properly.
|
|
||||||
gQueue.push(new focusActiveDescendantTab("aria_tab6", "aria_tablist2", true));
|
|
||||||
|
|
||||||
// Now, make sure the focused but explicitly unselected one behaves.
|
|
||||||
gQueue.push(new focusActiveDescendantTab("aria_tab4", "aria_tablist2", false));
|
|
||||||
|
|
||||||
gQueue.invoke(); // SimpleTest.finish() will be called in the end
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
addA11yLoadEvent(doTest);
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<a target="_blank"
|
|
||||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=653601"
|
|
||||||
title="aria-selected ignored for ARIA tabs">
|
|
||||||
Mozilla Bug 653601
|
|
||||||
</a>
|
|
||||||
<p id="display"></p>
|
|
||||||
<div id="content" style="display: none"></div>
|
|
||||||
<pre id="test">
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<!-- tab -->
|
|
||||||
<div id="aria_tablist" role="tablist">
|
|
||||||
<div id="aria_tab1" role="tab" tabindex="0">unselected tab</div>
|
|
||||||
<div id="aria_tab2" role="tab" tabindex="0" aria-selected="true">selected tab</div>
|
|
||||||
<div id="aria_tab3" role="tab" tabindex="0" aria-selected="false">focused explicitly unselected tab</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- test activeDescendant -->
|
|
||||||
<div id="aria_tablist2" role="tablist" tabindex="0">
|
|
||||||
<div id="aria_tab4" role="tab" aria-selected="false">focused explicitly unselected tab</div>
|
|
||||||
<div id="aria_tab5" role="tab">initially selected tab</div>
|
|
||||||
<div id="aria_tab6" role="tab">later selected tab</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Test ARIA tab accessible selected state</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../states.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../events.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
function focusARIAItem(aID, aIsSelected)
|
||||||
|
{
|
||||||
|
this.DOMNode = getNode(aID);
|
||||||
|
|
||||||
|
this.invoke = function focusARIAItem_invoke()
|
||||||
|
{
|
||||||
|
this.DOMNode.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.check = function focusARIAItem_check(aEvent)
|
||||||
|
{
|
||||||
|
testStates(this.DOMNode, aIsSelected ? STATE_SELECTED : 0, 0,
|
||||||
|
aIsSelected ? 0 : STATE_SELECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getID = function focusARIAItem_getID()
|
||||||
|
{
|
||||||
|
return "Focused ARIA widget item with aria-selected='" +
|
||||||
|
(aIsSelected ? "true', should" : "false', shouldn't") +
|
||||||
|
" have selected state on " + prettyName(aID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusActiveDescendantItem(aItemID, aWidgetID, aIsSelected)
|
||||||
|
{
|
||||||
|
this.DOMNode = getNode(aItemID);
|
||||||
|
this.widgetDOMNode = getNode(aWidgetID);
|
||||||
|
|
||||||
|
this.invoke = function focusActiveDescendantItem_invoke()
|
||||||
|
{
|
||||||
|
this.widgetDOMNode.setAttribute("aria-activedescendant", aItemID);
|
||||||
|
this.widgetDOMNode.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.check = function focusActiveDescendantItem_check(aEvent)
|
||||||
|
{
|
||||||
|
testStates(this.DOMNode, aIsSelected ? STATE_SELECTED : 0, 0,
|
||||||
|
aIsSelected ? 0 : STATE_SELECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getID = function tabActiveDescendant_getID()
|
||||||
|
{
|
||||||
|
return "ARIA widget item managed by activedescendant " +
|
||||||
|
(aIsSelected ? "should" : "shouldn't") +
|
||||||
|
" have the selected state on " + prettyName(aItemID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Test
|
||||||
|
|
||||||
|
//gA11yEventDumpID = "eventdump"; // debug stuff
|
||||||
|
//gA11yEventDumpToConsole = true;
|
||||||
|
|
||||||
|
var gQueue = null;
|
||||||
|
|
||||||
|
function doTest()
|
||||||
|
{
|
||||||
|
// aria-selected
|
||||||
|
testStates("aria_tab1", 0, 0, STATE_SELECTED);
|
||||||
|
testStates("aria_tab2", STATE_SELECTED);
|
||||||
|
testStates("aria_tab3", 0, 0, STATE_SELECTED);
|
||||||
|
testStates("aria_option1", 0, 0, STATE_SELECTED);
|
||||||
|
testStates("aria_option2", STATE_SELECTED);
|
||||||
|
testStates("aria_option3", 0, 0, STATE_SELECTED);
|
||||||
|
testStates("aria_treeitem1", 0, 0, STATE_SELECTED);
|
||||||
|
testStates("aria_treeitem2", STATE_SELECTED);
|
||||||
|
testStates("aria_treeitem3", 0, 0, STATE_SELECTED);
|
||||||
|
|
||||||
|
// selected state when widget item is focused
|
||||||
|
gQueue = new eventQueue(EVENT_FOCUS);
|
||||||
|
|
||||||
|
gQueue.push(new focusARIAItem("aria_tab1", true));
|
||||||
|
gQueue.push(new focusARIAItem("aria_tab2", true));
|
||||||
|
gQueue.push(new focusARIAItem("aria_tab3", false));
|
||||||
|
gQueue.push(new focusARIAItem("aria_option1", true));
|
||||||
|
gQueue.push(new focusARIAItem("aria_option2", true));
|
||||||
|
gQueue.push(new focusARIAItem("aria_option3", false));
|
||||||
|
gQueue.push(new focusARIAItem("aria_treeitem1", true));
|
||||||
|
gQueue.push(new focusARIAItem("aria_treeitem2", true));
|
||||||
|
gQueue.push(new focusARIAItem("aria_treeitem3", false));
|
||||||
|
|
||||||
|
// selected state when widget item is focused (by aria-activedescendant)
|
||||||
|
gQueue.push(new focusActiveDescendantItem("aria_tab5", "aria_tablist2", true));
|
||||||
|
gQueue.push(new focusActiveDescendantItem("aria_tab6", "aria_tablist2", true));
|
||||||
|
gQueue.push(new focusActiveDescendantItem("aria_tab4", "aria_tablist2", false));
|
||||||
|
|
||||||
|
gQueue.invoke(); // SimpleTest.finish() will be called in the end
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTest);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=653601"
|
||||||
|
title="aria-selected ignored for ARIA tabs">
|
||||||
|
Mozilla Bug 653601
|
||||||
|
</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=526703"
|
||||||
|
title="Focused widget item should expose selected state by default">
|
||||||
|
Mozilla Bug 526703
|
||||||
|
</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!-- tab -->
|
||||||
|
<div id="aria_tablist" role="tablist">
|
||||||
|
<div id="aria_tab1" role="tab" tabindex="0">unselected tab</div>
|
||||||
|
<div id="aria_tab2" role="tab" tabindex="0" aria-selected="true">selected tab</div>
|
||||||
|
<div id="aria_tab3" role="tab" tabindex="0" aria-selected="false">focused explicitly unselected tab</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- listbox -->
|
||||||
|
<div id="aria_listbox" role="listbox">
|
||||||
|
<div id="aria_option1" role="option" tabindex="0">unselected option</div>
|
||||||
|
<div id="aria_option2" role="option" tabindex="0" aria-selected="true">selected option</div>
|
||||||
|
<div id="aria_option3" role="option" tabindex="0" aria-selected="false">focused explicitly unselected option</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- tree -->
|
||||||
|
<div id="aria_tree" role="tree">
|
||||||
|
<div id="aria_treeitem1" role="treeitem" tabindex="0">unselected treeitem</div>
|
||||||
|
<div id="aria_treeitem2" role="treeitem" tabindex="0" aria-selected="true">selected treeitem</div>
|
||||||
|
<div id="aria_treeitem3" role="treeitem" tabindex="0" aria-selected="false">focused explicitly unselected treeitem</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- tab managed by active-descendant -->
|
||||||
|
<div id="aria_tablist2" role="tablist" tabindex="0">
|
||||||
|
<div id="aria_tab4" role="tab" aria-selected="false">focused explicitly unselected tab</div>
|
||||||
|
<div id="aria_tab5" role="tab">initially selected tab</div>
|
||||||
|
<div id="aria_tab6" role="tab">later selected tab</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -2,8 +2,13 @@
|
||||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||||
type="text/css"?>
|
type="text/css"?>
|
||||||
|
|
||||||
|
<!-- Firefox searchbar -->
|
||||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||||
type="text/css"?>
|
type="text/css"?>
|
||||||
|
<!-- SeaMonkey searchbar -->
|
||||||
|
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||||
|
type="text/css"?>
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
title="Expanded state change events tests for comboboxes and autocompletes.">
|
title="Expanded state change events tests for comboboxes and autocompletes.">
|
||||||
|
|
|
@ -76,15 +76,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
|
||||||
is(height.value, aHeight, "wrong height for " + aID + "!");
|
is(height.value, aHeight, "wrong height for " + aID + "!");
|
||||||
}
|
}
|
||||||
|
|
||||||
function testThis(aID, aName, aSRC, aWidth, aHeight,
|
function testThis(aID, aSRC, aWidth, aHeight,
|
||||||
aNumActions, aActionNames)
|
aNumActions, aActionNames)
|
||||||
{
|
{
|
||||||
var acc = getAccessible(aID, [nsIAccessibleImage]);
|
var acc = getAccessible(aID, [nsIAccessibleImage]);
|
||||||
if (!acc)
|
if (!acc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
is(acc.name, aName, "wrong name for " + aID + "!");
|
|
||||||
|
|
||||||
// Test role
|
// Test role
|
||||||
testRole(aID, ROLE_GRAPHIC);
|
testRole(aID, ROLE_GRAPHIC);
|
||||||
|
|
||||||
|
@ -108,50 +106,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
|
||||||
function doTest()
|
function doTest()
|
||||||
{
|
{
|
||||||
// Test non-linked image
|
// Test non-linked image
|
||||||
testThis("nonLinkedImage", null, "moz.png", 89, 38);
|
testThis("nonLinkedImage", "moz.png", 89, 38);
|
||||||
|
|
||||||
// Test linked image
|
// Test linked image
|
||||||
testThis("linkedImage", null, "moz.png", 89, 38);
|
testThis("linkedImage", "moz.png", 89, 38);
|
||||||
|
|
||||||
// Test non-linked image with alt attribute
|
|
||||||
testThis("nonLinkedImageWithAlt", "MoFo", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test linked image with alt attribute
|
|
||||||
testThis("linkedImageWithAlt", "MoFo link", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test non-linked image with title attribute
|
|
||||||
testThis("nonLinkedImageWithTitle", "MoFo logo", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test linked image with title attribute
|
|
||||||
testThis("linkedImageWithTitle", "Link to MoFo", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test simple image with empty alt attribute
|
|
||||||
testThis("nonLinkedImageEmptyAlt", "", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test linked image with empty alt attribute
|
|
||||||
testThis("linkedImageEmptyAlt", "", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test simple image with empty alt attribute and title
|
|
||||||
testThis("nonLinkedImageEmptyAltAndTitle", "MozillaFoundation", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Test linked image with empty alt attribute and title
|
|
||||||
testThis("linkedImageEmptyAltAndTitle", "Link to Mozilla Foundation", "moz.png", 89, 38);
|
|
||||||
|
|
||||||
// Image with long desc
|
// Image with long desc
|
||||||
var actionNamesArray = new Array("showlongdesc");
|
var actionNamesArray = new Array("showlongdesc");
|
||||||
testThis("longdesc", "Image of Mozilla logo", "moz.png", 89, 38, 1,
|
testThis("longdesc", "moz.png", 89, 38, 1,
|
||||||
actionNamesArray);
|
actionNamesArray);
|
||||||
|
|
||||||
// Image with click and long desc
|
// Image with click and long desc
|
||||||
actionNamesArray = null;
|
actionNamesArray = null;
|
||||||
actionNamesArray = new Array("click", "showlongdesc");
|
actionNamesArray = new Array("click", "showlongdesc");
|
||||||
testThis("clickAndLongdesc", "Another image of Mozilla logo", "moz.png",
|
testThis("clickAndLongdesc", "moz.png",
|
||||||
89, 38, 2, actionNamesArray);
|
89, 38, 2, actionNamesArray);
|
||||||
|
|
||||||
// Image with click
|
// Image with click
|
||||||
actionNamesArray = null;
|
actionNamesArray = null;
|
||||||
actionNamesArray = new Array("click");
|
actionNamesArray = new Array("click");
|
||||||
testThis("click", "A third image of Mozilla logo", "moz.png",
|
testThis("click", "moz.png",
|
||||||
89, 38, 1, actionNamesArray);
|
89, 38, 1, actionNamesArray);
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
@ -172,23 +146,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
|
||||||
<img id="nonLinkedImage" src="moz.png"/>
|
<img id="nonLinkedImage" src="moz.png"/>
|
||||||
<br>Linked image:<br>
|
<br>Linked image:<br>
|
||||||
<a href="http://www.mozilla.org"><img id="linkedImage" src="moz.png"></a>
|
<a href="http://www.mozilla.org"><img id="linkedImage" src="moz.png"></a>
|
||||||
<br>Simple image with alt:<br>
|
|
||||||
<img id="nonLinkedImageWithAlt" src="moz.png" alt="MoFo"/>
|
|
||||||
<br>Linked image with alt:<br>
|
|
||||||
<a href="http://www.mozilla.org"><img id="linkedImageWithAlt" src="moz.png" alt="MoFo link"/></a>
|
|
||||||
<br>Simple image with title:<br>
|
|
||||||
<img id="nonLinkedImageWithTitle" src="moz.png" title="MoFo logo"/>
|
|
||||||
<br>Linked image with title:<br>
|
|
||||||
<a href="http://www.mozilla.org"><img id="linkedImageWithTitle" src="moz.png" title="Link to MoFo"/></a>
|
|
||||||
<br>Simple image with empty alt:<br>
|
|
||||||
<img id="nonLinkedImageEmptyAlt" src="moz.png" alt=""/>
|
|
||||||
<br>Linked image with empty alt:<br>
|
|
||||||
<a href="http://www.mozilla.org"><img id="linkedImageEmptyAlt" src="moz.png" alt=""/></a>
|
|
||||||
<br>Simple image with empty alt and title:<br>
|
|
||||||
<img id="nonLinkedImageEmptyAltAndTitle" src="moz.png" alt="" title="MozillaFoundation"/>
|
|
||||||
<br>Linked image with empty alt and title:<br>
|
|
||||||
<a href="http://www.mozilla.org"><img id="linkedImageEmptyAltAndTitle" src="moz.png" alt=""
|
|
||||||
title="Link to Mozilla Foundation"/></a>
|
|
||||||
<br>Image with longdesc:<br>
|
<br>Image with longdesc:<br>
|
||||||
<img id="longdesc" src="moz.png" longdesc="longdesc_src.html"
|
<img id="longdesc" src="moz.png" longdesc="longdesc_src.html"
|
||||||
alt="Image of Mozilla logo"/>
|
alt="Image of Mozilla logo"/>
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://browser/content/utilityOverlay.js"/>
|
||||||
|
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../common.js" />
|
src="../common.js" />
|
||||||
|
|
|
@ -394,6 +394,10 @@ pref("layers.acceleration.force-enabled", true);
|
||||||
pref("dom.screenEnabledProperty.enabled", true);
|
pref("dom.screenEnabledProperty.enabled", true);
|
||||||
pref("dom.screenBrightnessProperty.enabled", true);
|
pref("dom.screenBrightnessProperty.enabled", true);
|
||||||
|
|
||||||
|
// Enable browser frame
|
||||||
|
pref("dom.mozBrowserFramesEnabled", true);
|
||||||
|
pref("dom.mozBrowserFramesWhitelist", "http://localhost:6666");
|
||||||
|
|
||||||
// Temporary permission hack for WebSMS
|
// Temporary permission hack for WebSMS
|
||||||
pref("dom.sms.enabled", true);
|
pref("dom.sms.enabled", true);
|
||||||
pref("dom.sms.whitelist", "file://,http://localhost:6666");
|
pref("dom.sms.whitelist", "file://,http://localhost:6666");
|
||||||
|
|
|
@ -201,6 +201,11 @@ var shell = {
|
||||||
break;
|
break;
|
||||||
case evt.DOM_VK_SLEEP:
|
case evt.DOM_VK_SLEEP:
|
||||||
this.toggleScreen();
|
this.toggleScreen();
|
||||||
|
|
||||||
|
let details = {
|
||||||
|
'enabled': screen.mozEnabled
|
||||||
|
};
|
||||||
|
this.sendEvent(this.home.contentWindow, 'sleep', details);
|
||||||
break;
|
break;
|
||||||
case evt.DOM_VK_ESCAPE:
|
case evt.DOM_VK_ESCAPE:
|
||||||
if (evt.defaultPrevented)
|
if (evt.defaultPrevented)
|
||||||
|
|
|
@ -395,10 +395,8 @@
|
||||||
@BINPATH@/components/nsFilePicker.js
|
@BINPATH@/components/nsFilePicker.js
|
||||||
@BINPATH@/components/nsFilePicker.manifest
|
@BINPATH@/components/nsFilePicker.manifest
|
||||||
#ifdef MOZ_B2G_RIL
|
#ifdef MOZ_B2G_RIL
|
||||||
@BINPATH@/components/nsTelephonyWorker.manifest
|
@BINPATH@/components/RadioInterfaceLayer.manifest
|
||||||
@BINPATH@/components/nsTelephonyWorker.js
|
@BINPATH@/components/RadioInterfaceLayer.js
|
||||||
@BINPATH@/components/Telephony.manifest
|
|
||||||
@BINPATH@/components/Telephony.js
|
|
||||||
@BINPATH@/components/nsWifiWorker.js
|
@BINPATH@/components/nsWifiWorker.js
|
||||||
@BINPATH@/components/nsWifiWorker.manifest
|
@BINPATH@/components/nsWifiWorker.manifest
|
||||||
#endif
|
#endif
|
||||||
|
@ -602,3 +600,5 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
||||||
@BINPATH@/chrome/icons/
|
@BINPATH@/chrome/icons/
|
||||||
@BINPATH@/chrome/chrome@JAREXT@
|
@BINPATH@/chrome/chrome@JAREXT@
|
||||||
@BINPATH@/chrome/chrome.manifest
|
@BINPATH@/chrome/chrome.manifest
|
||||||
|
@BINPATH@/components/B2GComponents.manifest
|
||||||
|
@BINPATH@/components/B2GComponents.xpt
|
||||||
|
|
|
@ -83,6 +83,10 @@ LIBS += \
|
||||||
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
ifdef MOZ_LINKER
|
||||||
|
LIBS += $(ZLIB_LIBS)
|
||||||
|
endif
|
||||||
|
|
||||||
ifndef MOZ_WINCONSOLE
|
ifndef MOZ_WINCONSOLE
|
||||||
ifdef MOZ_DEBUG
|
ifdef MOZ_DEBUG
|
||||||
MOZ_WINCONSOLE = 1
|
MOZ_WINCONSOLE = 1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1325894427000">
|
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1327685994000">
|
||||||
<emItems>
|
<emItems>
|
||||||
<emItem blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
|
<emItem blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
|
||||||
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
|
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
|
||||||
|
@ -27,6 +27,10 @@
|
||||||
<versionRange minVersion="1.1b1" maxVersion="1.1b1">
|
<versionRange minVersion="1.1b1" maxVersion="1.1b1">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i54" id="applebeegifts@mozilla.doslash.org">
|
||||||
|
<versionRange minVersion="0" maxVersion="*">
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
|
<emItem blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
|
||||||
<versionRange minVersion="1.0" maxVersion="1.0">
|
<versionRange minVersion="1.0" maxVersion="1.0">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
|
@ -39,6 +43,10 @@
|
||||||
<versionRange minVersion="0.1" maxVersion="14.4.0" severity="1">
|
<versionRange minVersion="0.1" maxVersion="14.4.0" severity="1">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i53" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
|
||||||
|
<versionRange minVersion="2.0.3" maxVersion="2.0.3">
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
|
<emItem blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
|
||||||
</emItem>
|
</emItem>
|
||||||
<emItem blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
|
<emItem blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
|
||||||
|
@ -66,10 +74,21 @@
|
||||||
</targetApplication>
|
</targetApplication>
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i50" id="firebug@software.joehewitt.com">
|
||||||
|
<versionRange minVersion="0" maxVersion="0">
|
||||||
|
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||||
|
<versionRange minVersion="9.0a1" maxVersion="9.*" />
|
||||||
|
</targetApplication>
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
|
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
|
||||||
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
|
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i51" id="admin@youtubeplayer.com">
|
||||||
|
<versionRange minVersion="0" maxVersion="*">
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
|
<emItem blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
|
||||||
<versionRange minVersion="0.1" maxVersion="*">
|
<versionRange minVersion="0.1" maxVersion="*">
|
||||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||||
|
@ -84,13 +103,12 @@
|
||||||
</targetApplication>
|
</targetApplication>
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
<emItem blockID="i11" id="yslow@yahoo-inc.com">
|
<emItem blockID="i55" id="youtube@youtube7.com">
|
||||||
<versionRange minVersion="2.0.5" maxVersion="2.0.5">
|
<versionRange minVersion="0" maxVersion="*">
|
||||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
|
||||||
<versionRange minVersion="3.5.7" maxVersion="*" />
|
|
||||||
</targetApplication>
|
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i47" id="youtube@youtube2.com">
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i22" id="ShopperReports@ShopperReports.com">
|
<emItem blockID="i22" id="ShopperReports@ShopperReports.com">
|
||||||
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
|
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
|
@ -122,8 +140,13 @@
|
||||||
<versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
|
<versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
<emItem blockID="i47" id="youtube@youtube2.com">
|
<emItem blockID="i11" id="yslow@yahoo-inc.com">
|
||||||
</emItem>
|
<versionRange minVersion="2.0.5" maxVersion="2.0.5">
|
||||||
|
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||||
|
<versionRange minVersion="3.5.7" maxVersion="*" />
|
||||||
|
</targetApplication>
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
|
<emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
|
||||||
<versionRange minVersion="2.2" maxVersion="2.2">
|
<versionRange minVersion="2.2" maxVersion="2.2">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
|
@ -139,10 +162,12 @@
|
||||||
<versionRange minVersion="2.0" maxVersion="2.0">
|
<versionRange minVersion="2.0" maxVersion="2.0">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
<emItem blockID="i49" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE63}">
|
|
||||||
</emItem>
|
|
||||||
<emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
|
<emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i52" id="ff-ext@youtube">
|
||||||
|
<versionRange minVersion="0" maxVersion="*">
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
|
<emItem blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
|
||||||
<versionRange minVersion="0.1" maxVersion="1.3.328.4" severity="1">
|
<versionRange minVersion="0.1" maxVersion="1.3.328.4" severity="1">
|
||||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||||
|
|
|
@ -244,8 +244,7 @@ pref("general.autoScroll", false);
|
||||||
pref("general.autoScroll", true);
|
pref("general.autoScroll", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Whether or not the application should check at startup each time if it
|
// At startup, check if we're the default browser and prompt user if not.
|
||||||
// is the default browser.
|
|
||||||
pref("browser.shell.checkDefaultBrowser", true);
|
pref("browser.shell.checkDefaultBrowser", true);
|
||||||
|
|
||||||
// 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
|
// 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
|
||||||
|
@ -281,7 +280,7 @@ pref("browser.urlbar.doubleClickSelectsAll", true);
|
||||||
#else
|
#else
|
||||||
pref("browser.urlbar.doubleClickSelectsAll", false);
|
pref("browser.urlbar.doubleClickSelectsAll", false);
|
||||||
#endif
|
#endif
|
||||||
pref("browser.urlbar.autoFill", false);
|
pref("browser.urlbar.autoFill", true);
|
||||||
// 0: Match anywhere (e.g., middle of words)
|
// 0: Match anywhere (e.g., middle of words)
|
||||||
// 1: Match on word boundaries and then try matching anywhere
|
// 1: Match on word boundaries and then try matching anywhere
|
||||||
// 2: Match only on word boundaries (e.g., after / or .)
|
// 2: Match only on word boundaries (e.g., after / or .)
|
||||||
|
@ -294,7 +293,7 @@ pref("browser.urlbar.maxRichResults", 12);
|
||||||
// The amount of time (ms) to wait after the user has stopped typing
|
// The amount of time (ms) to wait after the user has stopped typing
|
||||||
// before starting to perform autocomplete. 50 is the default set in
|
// before starting to perform autocomplete. 50 is the default set in
|
||||||
// autocomplete.xml.
|
// autocomplete.xml.
|
||||||
pref("browser.urlbar.delay", 50);
|
pref("browser.urlbar.delay", 0);
|
||||||
|
|
||||||
// The special characters below can be typed into the urlbar to either restrict
|
// The special characters below can be typed into the urlbar to either restrict
|
||||||
// the search to visited history, bookmarked, tagged pages; or force a match on
|
// the search to visited history, bookmarked, tagged pages; or force a match on
|
||||||
|
@ -804,6 +803,10 @@ pref("browser.sessionstore.max_resumed_crashes", 1);
|
||||||
pref("browser.sessionstore.restore_on_demand", false);
|
pref("browser.sessionstore.restore_on_demand", false);
|
||||||
// Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
|
// Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
|
||||||
pref("browser.sessionstore.restore_hidden_tabs", false);
|
pref("browser.sessionstore.restore_hidden_tabs", false);
|
||||||
|
// If restore_on_demand is set, pinned tabs are restored on startup by default.
|
||||||
|
// When set to true, this pref overrides that behavior, and pinned tabs will only
|
||||||
|
// be restored when they are focused.
|
||||||
|
pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
|
||||||
|
|
||||||
// allow META refresh by default
|
// allow META refresh by default
|
||||||
pref("accessibility.blockautorefresh", false);
|
pref("accessibility.blockautorefresh", false);
|
||||||
|
@ -1032,6 +1035,8 @@ pref("devtools.styleinspector.enabled", true);
|
||||||
|
|
||||||
// Enable the Tilt inspector
|
// Enable the Tilt inspector
|
||||||
pref("devtools.tilt.enabled", true);
|
pref("devtools.tilt.enabled", true);
|
||||||
|
pref("devtools.tilt.intro_transition", true);
|
||||||
|
pref("devtools.tilt.outro_transition", true);
|
||||||
|
|
||||||
// Enable the rules view
|
// Enable the rules view
|
||||||
pref("devtools.ruleview.enabled", true);
|
pref("devtools.ruleview.enabled", true);
|
||||||
|
@ -1041,12 +1046,13 @@ pref("devtools.scratchpad.enabled", true);
|
||||||
|
|
||||||
// Enable the Style Editor.
|
// Enable the Style Editor.
|
||||||
pref("devtools.styleeditor.enabled", true);
|
pref("devtools.styleeditor.enabled", true);
|
||||||
|
pref("devtools.styleeditor.transitions", true);
|
||||||
|
|
||||||
// Enable tools for Chrome development.
|
// Enable tools for Chrome development.
|
||||||
pref("devtools.chrome.enabled", false);
|
pref("devtools.chrome.enabled", false);
|
||||||
|
|
||||||
// Disable the GCLI enhanced command line.
|
// Disable the GCLI enhanced command line.
|
||||||
pref("devtools.gcli.enable", true);
|
pref("devtools.gcli.enable", false);
|
||||||
|
|
||||||
// The last Web Console height. This is initially 0 which means that the Web
|
// The last Web Console height. This is initially 0 which means that the Web
|
||||||
// Console will use the default height next time it shows.
|
// Console will use the default height next time it shows.
|
||||||
|
@ -1104,5 +1110,11 @@ pref("prompts.tab_modal.enabled", true);
|
||||||
// Whether the Panorama should animate going in/out of tabs
|
// Whether the Panorama should animate going in/out of tabs
|
||||||
pref("browser.panorama.animate_zoom", true);
|
pref("browser.panorama.animate_zoom", true);
|
||||||
|
|
||||||
|
// Defines the url to be used for new tabs.
|
||||||
|
pref("browser.newtab.url", "about:blank");
|
||||||
|
|
||||||
|
// Toggles the content of 'about:newtab'. Shows the grid when enabled.
|
||||||
|
pref("browser.newtabpage.enabled", false);
|
||||||
|
|
||||||
// Enable the DOM full-screen API.
|
// Enable the DOM full-screen API.
|
||||||
pref("full-screen-api.enabled", true);
|
pref("full-screen-api.enabled", true);
|
||||||
|
|
|
@ -57,7 +57,6 @@
|
||||||
list-style-image: url("chrome://global/skin/icons/loading_16.png");
|
list-style-image: url("chrome://global/skin/icons/loading_16.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
.trademark-label,
|
|
||||||
.text-link,
|
.text-link,
|
||||||
.text-link:focus {
|
.text-link:focus {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
|
|
@ -77,17 +77,6 @@ function init(aEvent)
|
||||||
document.getElementById("communityDesc").hidden = true;
|
document.getElementById("communityDesc").hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_OFFICIAL_BRANDING
|
|
||||||
// Hide the Charlton trademark attribution for non-en-US/en-GB
|
|
||||||
// DO NOT REMOVE without consulting people involved with bug 616193
|
|
||||||
let chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"].
|
|
||||||
getService(Components.interfaces.nsIXULChromeRegistry);
|
|
||||||
let currentLocale = chromeRegistry.getSelectedLocale("global");
|
|
||||||
if (currentLocale != "en-US" && currentLocale != "en-GB") {
|
|
||||||
document.getElementById("extra-trademark").hidden = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_UPDATER
|
#ifdef MOZ_UPDATER
|
||||||
gAppUpdater = new appUpdater();
|
gAppUpdater = new appUpdater();
|
||||||
|
|
||||||
|
|
|
@ -146,13 +146,7 @@
|
||||||
<label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</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>
|
<label class="text-link bottom-link" href="http://www.mozilla.com/legal/privacy/">&bottomLinks.privacy;</label>
|
||||||
</hbox>
|
</hbox>
|
||||||
<description id="trademark">
|
<description id="trademark">&trademarkInfo.part1;</description>
|
||||||
<label class="trademark-label">&trademarkInfo.part1;</label>
|
|
||||||
#ifdef MOZ_OFFICIAL_BRANDING
|
|
||||||
<!-- DO NOT REMOVE without consulting people involved with bug 616193 -->
|
|
||||||
<label id="extra-trademark" class="trademark-label">Some of the trademarks used under license from The Charlton Company.</label>
|
|
||||||
#endif
|
|
||||||
</description>
|
|
||||||
</vbox>
|
</vbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,8 @@
|
||||||
<menuseparator class="appmenu-menuseparator"/>
|
<menuseparator class="appmenu-menuseparator"/>
|
||||||
<menu id="appmenu_webDeveloper"
|
<menu id="appmenu_webDeveloper"
|
||||||
label="&appMenuWebDeveloper.label;">
|
label="&appMenuWebDeveloper.label;">
|
||||||
<menupopup id="appmenu_webDeveloper_popup">
|
<menupopup id="appmenu_webDeveloper_popup"
|
||||||
|
onpopupshowing="onWebDeveloperMenuShowing();">
|
||||||
<menuitem id="appmenu_webConsole"
|
<menuitem id="appmenu_webConsole"
|
||||||
label="&webConsoleCmd.label;"
|
label="&webConsoleCmd.label;"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
|
@ -225,13 +225,19 @@ var FullZoom = {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Avoid the cps roundtrip and apply the default/global pref.
|
// Avoid the cps roundtrip and apply the default/global pref.
|
||||||
if (aURI.spec == "about:blank") {
|
if (isBlankPageURL(aURI.spec)) {
|
||||||
this._applyPrefToSetting(undefined, aBrowser);
|
this._applyPrefToSetting(undefined, aBrowser);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let browser = aBrowser || gBrowser.selectedBrowser;
|
let browser = aBrowser || gBrowser.selectedBrowser;
|
||||||
|
|
||||||
|
// Media documents should always start at 1, and are not affected by prefs.
|
||||||
|
if (!aIsTabSwitch && browser.contentDocument.mozSyntheticDocument) {
|
||||||
|
ZoomManager.setZoomForBrowser(browser, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Services.contentPrefs.hasCachedPref(aURI, this.name)) {
|
if (Services.contentPrefs.hasCachedPref(aURI, this.name)) {
|
||||||
let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
|
let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
|
||||||
this._applyPrefToSetting(zoomValue, browser);
|
this._applyPrefToSetting(zoomValue, browser);
|
||||||
|
@ -303,9 +309,10 @@ var FullZoom = {
|
||||||
|
|
||||||
var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser);
|
var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser);
|
||||||
try {
|
try {
|
||||||
if (browser.contentDocument instanceof Ci.nsIImageDocument)
|
if (browser.contentDocument.mozSyntheticDocument)
|
||||||
ZoomManager.setZoomForBrowser(browser, 1);
|
return;
|
||||||
else if (typeof aValue != "undefined")
|
|
||||||
|
if (typeof aValue != "undefined")
|
||||||
ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue));
|
ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue));
|
||||||
else if (typeof this.globalValue != "undefined")
|
else if (typeof this.globalValue != "undefined")
|
||||||
ZoomManager.setZoomForBrowser(browser, this.globalValue);
|
ZoomManager.setZoomForBrowser(browser, this.globalValue);
|
||||||
|
@ -317,7 +324,7 @@ var FullZoom = {
|
||||||
|
|
||||||
_applySettingToPref: function FullZoom__applySettingToPref() {
|
_applySettingToPref: function FullZoom__applySettingToPref() {
|
||||||
if (!this.siteSpecific || gInPrintPreviewMode ||
|
if (!this.siteSpecific || gInPrintPreviewMode ||
|
||||||
content.document instanceof Ci.nsIImageDocument)
|
content.document.mozSyntheticDocument)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var zoomLevel = ZoomManager.zoom;
|
var zoomLevel = ZoomManager.zoom;
|
||||||
|
@ -325,7 +332,7 @@ var FullZoom = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_removePref: function FullZoom__removePref() {
|
_removePref: function FullZoom__removePref() {
|
||||||
if (!(content.document instanceof Ci.nsIImageDocument))
|
if (!(content.document.mozSyntheticDocument))
|
||||||
Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
|
Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -531,7 +531,8 @@
|
||||||
<menu id="webDeveloperMenu"
|
<menu id="webDeveloperMenu"
|
||||||
label="&webDeveloperMenu.label;"
|
label="&webDeveloperMenu.label;"
|
||||||
accesskey="&webDeveloperMenu.accesskey;">
|
accesskey="&webDeveloperMenu.accesskey;">
|
||||||
<menupopup id="menuWebDeveloperPopup">
|
<menupopup id="menuWebDeveloperPopup"
|
||||||
|
onpopupshowing="onWebDeveloperMenuShowing();">
|
||||||
<menuitem id="webConsole"
|
<menuitem id="webConsole"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
label="&webConsoleCmd.label;"
|
label="&webConsoleCmd.label;"
|
||||||
|
|
|
@ -1012,7 +1012,7 @@ var PlacesStarButton = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can load about:blank before the actual page, but there is no point in handling that page.
|
// We can load about:blank before the actual page, but there is no point in handling that page.
|
||||||
if (this._uri.spec == "about:blank") {
|
if (isBlankPageURL(this._uri.spec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps thumbnails of open web pages up-to-date.
|
||||||
|
*/
|
||||||
|
let gBrowserThumbnails = {
|
||||||
|
_captureDelayMS: 2000,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of capture() timeouts assigned to their browsers.
|
||||||
|
*/
|
||||||
|
_timeouts: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache for the PageThumbs module.
|
||||||
|
*/
|
||||||
|
_pageThumbs: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of tab events we want to listen for.
|
||||||
|
*/
|
||||||
|
_tabEvents: ["TabClose", "TabSelect"],
|
||||||
|
|
||||||
|
init: function Thumbnails_init() {
|
||||||
|
gBrowser.addTabsProgressListener(this);
|
||||||
|
|
||||||
|
this._tabEvents.forEach(function (aEvent) {
|
||||||
|
gBrowser.tabContainer.addEventListener(aEvent, this, false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this._timeouts = new WeakMap();
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "_pageThumbs",
|
||||||
|
"resource:///modules/PageThumbs.jsm", "PageThumbs");
|
||||||
|
},
|
||||||
|
|
||||||
|
uninit: function Thumbnails_uninit() {
|
||||||
|
gBrowser.removeTabsProgressListener(this);
|
||||||
|
|
||||||
|
this._tabEvents.forEach(function (aEvent) {
|
||||||
|
gBrowser.tabContainer.removeEventListener(aEvent, this, false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this._timeouts = null;
|
||||||
|
this._pageThumbs = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEvent: function Thumbnails_handleEvent(aEvent) {
|
||||||
|
switch (aEvent.type) {
|
||||||
|
case "scroll":
|
||||||
|
let browser = aEvent.currentTarget;
|
||||||
|
if (this._timeouts.has(browser))
|
||||||
|
this._delayedCapture(browser);
|
||||||
|
break;
|
||||||
|
case "TabSelect":
|
||||||
|
this._delayedCapture(aEvent.target.linkedBrowser);
|
||||||
|
break;
|
||||||
|
case "TabClose": {
|
||||||
|
this._clearTimeout(aEvent.target.linkedBrowser);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State change progress listener for all tabs.
|
||||||
|
*/
|
||||||
|
onStateChange: function Thumbnails_onStateChange(aBrowser, aWebProgress,
|
||||||
|
aRequest, aStateFlags, aStatus) {
|
||||||
|
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||||
|
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
|
||||||
|
this._delayedCapture(aBrowser);
|
||||||
|
},
|
||||||
|
|
||||||
|
_capture: function Thumbnails_capture(aBrowser) {
|
||||||
|
if (this._shouldCapture(aBrowser)) {
|
||||||
|
let canvas = this._pageThumbs.capture(aBrowser.contentWindow);
|
||||||
|
this._pageThumbs.store(aBrowser.currentURI.spec, canvas);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
|
||||||
|
if (this._timeouts.has(aBrowser))
|
||||||
|
clearTimeout(this._timeouts.get(aBrowser));
|
||||||
|
else
|
||||||
|
aBrowser.addEventListener("scroll", this, true);
|
||||||
|
|
||||||
|
let timeout = setTimeout(function () {
|
||||||
|
this._clearTimeout(aBrowser);
|
||||||
|
this._capture(aBrowser);
|
||||||
|
}.bind(this), this._captureDelayMS);
|
||||||
|
|
||||||
|
this._timeouts.set(aBrowser, timeout);
|
||||||
|
},
|
||||||
|
|
||||||
|
_shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
|
||||||
|
let doc = aBrowser.contentDocument;
|
||||||
|
|
||||||
|
// FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as
|
||||||
|
// that currently regresses Talos SVG tests.
|
||||||
|
if (doc instanceof SVGDocument || doc instanceof XMLDocument)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// There's no point in taking screenshot of loading pages.
|
||||||
|
if (aBrowser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Don't take screenshots of about: pages.
|
||||||
|
if (aBrowser.currentURI.schemeIs("about"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let channel = aBrowser.docShell.currentDocumentChannel;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// If the channel is a nsIHttpChannel get its http status code.
|
||||||
|
let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
|
||||||
|
// Continue only if we have a 2xx status code.
|
||||||
|
return Math.floor(httpChannel.responseStatus / 100) == 2;
|
||||||
|
} catch (e) {
|
||||||
|
// Not a http channel, we just assume a success status code.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_clearTimeout: function Thumbnails_clearTimeout(aBrowser) {
|
||||||
|
if (this._timeouts.has(aBrowser)) {
|
||||||
|
aBrowser.removeEventListener("scroll", this, false);
|
||||||
|
clearTimeout(this._timeouts.get(aBrowser));
|
||||||
|
this._timeouts.delete(aBrowser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -188,6 +188,7 @@ XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
|
||||||
|
|
||||||
let gInitialPages = [
|
let gInitialPages = [
|
||||||
"about:blank",
|
"about:blank",
|
||||||
|
"about:newtab",
|
||||||
"about:privatebrowsing",
|
"about:privatebrowsing",
|
||||||
"about:sessionrestore"
|
"about:sessionrestore"
|
||||||
];
|
];
|
||||||
|
@ -196,6 +197,7 @@ let gInitialPages = [
|
||||||
#include browser-places.js
|
#include browser-places.js
|
||||||
#include browser-tabPreviews.js
|
#include browser-tabPreviews.js
|
||||||
#include browser-tabview.js
|
#include browser-tabview.js
|
||||||
|
#include browser-thumbnails.js
|
||||||
|
|
||||||
#ifdef MOZ_SERVICES_SYNC
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
#include browser-syncui.js
|
#include browser-syncui.js
|
||||||
|
@ -1501,6 +1503,8 @@ function prepareForStartup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||||
|
Cu.import("resource:///modules/TelemetryTimestamps.jsm");
|
||||||
|
TelemetryTimestamps.add("delayedStartupStarted");
|
||||||
gDelayedStartupTimeoutId = null;
|
gDelayedStartupTimeoutId = null;
|
||||||
|
|
||||||
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
||||||
|
@ -1554,7 +1558,11 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||||
// Perform default browser checking (after window opens).
|
// Perform default browser checking (after window opens).
|
||||||
var shell = getShellService();
|
var shell = getShellService();
|
||||||
if (shell) {
|
if (shell) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
var shouldCheck = false;
|
||||||
|
#else
|
||||||
var shouldCheck = shell.shouldCheckDefaultBrowser;
|
var shouldCheck = shell.shouldCheckDefaultBrowser;
|
||||||
|
#endif
|
||||||
var willRecoverSession = false;
|
var willRecoverSession = false;
|
||||||
try {
|
try {
|
||||||
var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
||||||
|
@ -1699,6 +1707,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||||
gSyncUI.init();
|
gSyncUI.init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
gBrowserThumbnails.init();
|
||||||
TabView.init();
|
TabView.init();
|
||||||
|
|
||||||
setUrlAndSearchBarWidthForConditionalForwardButton();
|
setUrlAndSearchBarWidthForConditionalForwardButton();
|
||||||
|
@ -1761,6 +1770,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||||
window.addEventListener("dragover", MousePosTracker, false);
|
window.addEventListener("dragover", MousePosTracker, false);
|
||||||
|
|
||||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
|
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
|
||||||
|
TelemetryTimestamps.add("delayedStartupFinished");
|
||||||
}
|
}
|
||||||
|
|
||||||
function BrowserShutdown() {
|
function BrowserShutdown() {
|
||||||
|
@ -1820,6 +1830,7 @@ function BrowserShutdown() {
|
||||||
gPrefService.removeObserver(allTabs.prefName, allTabs);
|
gPrefService.removeObserver(allTabs.prefName, allTabs);
|
||||||
ctrlTab.uninit();
|
ctrlTab.uninit();
|
||||||
TabView.uninit();
|
TabView.uninit();
|
||||||
|
gBrowserThumbnails.uninit();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FullZoom.destroy();
|
FullZoom.destroy();
|
||||||
|
@ -2194,7 +2205,7 @@ function openLocation() {
|
||||||
else {
|
else {
|
||||||
// If there are no open browser windows, open a new one
|
// If there are no open browser windows, open a new one
|
||||||
win = window.openDialog("chrome://browser/content/", "_blank",
|
win = window.openDialog("chrome://browser/content/", "_blank",
|
||||||
"chrome,all,dialog=no", "about:blank");
|
"chrome,all,dialog=no", BROWSER_NEW_TAB_URL);
|
||||||
win.addEventListener("load", openLocationCallback, false);
|
win.addEventListener("load", openLocationCallback, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -2212,7 +2223,7 @@ function openLocationCallback()
|
||||||
|
|
||||||
function BrowserOpenTab()
|
function BrowserOpenTab()
|
||||||
{
|
{
|
||||||
openUILinkIn("about:blank", "tab");
|
openUILinkIn(BROWSER_NEW_TAB_URL, "tab");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from the openLocation dialog. This allows that dialog to instruct
|
/* Called from the openLocation dialog. This allows that dialog to instruct
|
||||||
|
@ -2547,7 +2558,7 @@ function URLBarSetURI(aURI) {
|
||||||
else
|
else
|
||||||
value = losslessDecodeURI(uri);
|
value = losslessDecodeURI(uri);
|
||||||
|
|
||||||
valid = (uri.spec != "about:blank");
|
valid = !isBlankPageURL(uri.spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
gURLBar.value = value;
|
gURLBar.value = value;
|
||||||
|
@ -2864,7 +2875,7 @@ function getMeOutOfHere() {
|
||||||
// Get the start page from the *default* pref branch, not the user's
|
// Get the start page from the *default* pref branch, not the user's
|
||||||
var prefs = Cc["@mozilla.org/preferences-service;1"]
|
var prefs = Cc["@mozilla.org/preferences-service;1"]
|
||||||
.getService(Ci.nsIPrefService).getDefaultBranch(null);
|
.getService(Ci.nsIPrefService).getDefaultBranch(null);
|
||||||
var url = "about:blank";
|
var url = BROWSER_NEW_TAB_URL;
|
||||||
try {
|
try {
|
||||||
url = prefs.getComplexValue("browser.startup.homepage",
|
url = prefs.getComplexValue("browser.startup.homepage",
|
||||||
Ci.nsIPrefLocalizedString).data;
|
Ci.nsIPrefLocalizedString).data;
|
||||||
|
@ -3040,7 +3051,7 @@ function FillInHTMLTooltip(tipElement)
|
||||||
// Don't show the tooltip if the tooltip node is a XUL element, a document or is disconnected.
|
// Don't show the tooltip if the tooltip node is a XUL element, a document or is disconnected.
|
||||||
if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ||
|
if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ||
|
||||||
!tipElement.ownerDocument ||
|
!tipElement.ownerDocument ||
|
||||||
tipElement.ownerDocument.compareDocumentPosition(tipElement) == document.DOCUMENT_POSITION_DISCONNECTED)
|
(tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED))
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
||||||
const XLinkNS = "http://www.w3.org/1999/xlink";
|
const XLinkNS = "http://www.w3.org/1999/xlink";
|
||||||
|
@ -3105,20 +3116,13 @@ function FillInHTMLTooltip(tipElement)
|
||||||
|
|
||||||
[titleText, XLinkTitleText, SVGTitleText].forEach(function (t) {
|
[titleText, XLinkTitleText, SVGTitleText].forEach(function (t) {
|
||||||
if (t && /\S/.test(t)) {
|
if (t && /\S/.test(t)) {
|
||||||
|
// Make CRLF and CR render one line break each.
|
||||||
// Per HTML 4.01 6.2 (CDATA section), literal CRs and tabs should be
|
t = t.replace(/\r\n?/g, '\n');
|
||||||
// replaced with spaces, and LFs should be removed entirely.
|
|
||||||
// XXX Bug 322270: We don't preserve the result of entities like ,
|
|
||||||
// which should result in a line break in the tooltip, because we can't
|
|
||||||
// distinguish that from a literal character in the source by this point.
|
|
||||||
t = t.replace(/[\r\t]/g, ' ');
|
|
||||||
t = t.replace(/\n/g, '');
|
|
||||||
|
|
||||||
tipNode.setAttribute("label", t);
|
tipNode.setAttribute("label", t);
|
||||||
retVal = true;
|
retVal = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4785,6 +4789,7 @@ var XULBrowserWindow = {
|
||||||
},
|
},
|
||||||
|
|
||||||
hideChromeForLocation: function(aLocation) {
|
hideChromeForLocation: function(aLocation) {
|
||||||
|
aLocation = aLocation.toLowerCase();
|
||||||
return this.inContentWhitelist.some(function(aSpec) {
|
return this.inContentWhitelist.some(function(aSpec) {
|
||||||
return aSpec == aLocation;
|
return aSpec == aLocation;
|
||||||
});
|
});
|
||||||
|
@ -5188,7 +5193,7 @@ nsBrowserAccess.prototype = {
|
||||||
case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
|
case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
|
||||||
// FIXME: Bug 408379. So how come this doesn't send the
|
// FIXME: Bug 408379. So how come this doesn't send the
|
||||||
// referrer like the other loads do?
|
// referrer like the other loads do?
|
||||||
var url = aURI ? aURI.spec : "about:blank";
|
var url = aURI ? aURI.spec : BROWSER_NEW_TAB_URL;
|
||||||
// Pass all params to openDialog to ensure that "url" isn't passed through
|
// Pass all params to openDialog to ensure that "url" isn't passed through
|
||||||
// loadOneOrMoreURIs, which splits based on "|"
|
// loadOneOrMoreURIs, which splits based on "|"
|
||||||
newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null);
|
newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null);
|
||||||
|
@ -5197,7 +5202,7 @@ nsBrowserAccess.prototype = {
|
||||||
let win, needToFocusWin;
|
let win, needToFocusWin;
|
||||||
|
|
||||||
// try the current window. if we're in a popup, fall back on the most recent browser window
|
// try the current window. if we're in a popup, fall back on the most recent browser window
|
||||||
if (!window.document.documentElement.getAttribute("chromehidden"))
|
if (window.toolbar.visible)
|
||||||
win = window;
|
win = window;
|
||||||
else {
|
else {
|
||||||
win = Cc["@mozilla.org/browser/browserglue;1"]
|
win = Cc["@mozilla.org/browser/browserglue;1"]
|
||||||
|
@ -5221,7 +5226,7 @@ nsBrowserAccess.prototype = {
|
||||||
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
|
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
|
||||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||||
|
|
||||||
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
|
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : BROWSER_NEW_TAB_URL, {
|
||||||
referrerURI: referrer,
|
referrerURI: referrer,
|
||||||
fromExternal: isExternal,
|
fromExternal: isExternal,
|
||||||
inBackground: loadInBackground});
|
inBackground: loadInBackground});
|
||||||
|
@ -5969,12 +5974,12 @@ function MultiplexHandler(event)
|
||||||
var name = node.getAttribute('name');
|
var name = node.getAttribute('name');
|
||||||
|
|
||||||
if (name == 'detectorGroup') {
|
if (name == 'detectorGroup') {
|
||||||
SetForcedDetector(true);
|
BrowserCharsetReload();
|
||||||
SelectDetector(event, false);
|
SelectDetector(event, false);
|
||||||
} else if (name == 'charsetGroup') {
|
} else if (name == 'charsetGroup') {
|
||||||
var charset = node.getAttribute('id');
|
var charset = node.getAttribute('id');
|
||||||
charset = charset.substring('charset.'.length, charset.length)
|
charset = charset.substring('charset.'.length, charset.length)
|
||||||
SetForcedCharset(charset);
|
BrowserSetForcedCharacterSet(charset);
|
||||||
} else if (name == 'charsetCustomize') {
|
} else if (name == 'charsetCustomize') {
|
||||||
//do nothing - please remove this else statement, once the charset prefs moves to the pref window
|
//do nothing - please remove this else statement, once the charset prefs moves to the pref window
|
||||||
} else {
|
} else {
|
||||||
|
@ -6005,30 +6010,17 @@ function SelectDetector(event, doReload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetForcedDetector(doReload)
|
|
||||||
{
|
|
||||||
BrowserSetForcedDetector(doReload);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SetForcedCharset(charset)
|
|
||||||
{
|
|
||||||
BrowserSetForcedCharacterSet(charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
function BrowserSetForcedCharacterSet(aCharset)
|
function BrowserSetForcedCharacterSet(aCharset)
|
||||||
{
|
{
|
||||||
var docCharset = gBrowser.docShell.QueryInterface(Ci.nsIDocCharset);
|
gBrowser.docShell.charset = aCharset;
|
||||||
docCharset.charset = aCharset;
|
|
||||||
// Save the forced character-set
|
// Save the forced character-set
|
||||||
PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, aCharset);
|
PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, aCharset);
|
||||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
BrowserCharsetReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
function BrowserSetForcedDetector(doReload)
|
function BrowserCharsetReload()
|
||||||
{
|
{
|
||||||
gBrowser.documentCharsetInfo.forcedDetector = true;
|
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||||
if (doReload)
|
|
||||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function charsetMenuGetElement(parent, id) {
|
function charsetMenuGetElement(parent, id) {
|
||||||
|
@ -7783,9 +7775,11 @@ function undoCloseWindow(aIndex) {
|
||||||
*/
|
*/
|
||||||
function isTabEmpty(aTab) {
|
function isTabEmpty(aTab) {
|
||||||
let browser = aTab.linkedBrowser;
|
let browser = aTab.linkedBrowser;
|
||||||
|
let uri = browser.currentURI.spec;
|
||||||
|
let body = browser.contentDocument.body;
|
||||||
return browser.sessionHistory.count < 2 &&
|
return browser.sessionHistory.count < 2 &&
|
||||||
browser.currentURI.spec == "about:blank" &&
|
isBlankPageURL(uri) &&
|
||||||
!browser.contentDocument.body.hasChildNodes() &&
|
(!body || !body.hasChildNodes()) &&
|
||||||
!aTab.hasAttribute("busy");
|
!aTab.hasAttribute("busy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8872,8 +8866,8 @@ function restoreLastSession() {
|
||||||
var TabContextMenu = {
|
var TabContextMenu = {
|
||||||
contextTab: null,
|
contextTab: null,
|
||||||
updateContextMenu: function updateContextMenu(aPopupMenu) {
|
updateContextMenu: function updateContextMenu(aPopupMenu) {
|
||||||
this.contextTab = document.popupNode.localName == "tab" ?
|
this.contextTab = aPopupMenu.triggerNode.localName == "tab" ?
|
||||||
document.popupNode : gBrowser.selectedTab;
|
aPopupMenu.triggerNode : gBrowser.selectedTab;
|
||||||
let disabled = gBrowser.tabs.length == 1;
|
let disabled = gBrowser.tabs.length == 1;
|
||||||
|
|
||||||
// Enable the "Close Tab" menuitem when the window doesn't close with the last tab.
|
// Enable the "Close Tab" menuitem when the window doesn't close with the last tab.
|
||||||
|
@ -8918,9 +8912,10 @@ var TabContextMenu = {
|
||||||
};
|
};
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
|
XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
|
||||||
Cu.import("resource:///modules/HUDService.jsm");
|
let tempScope = {};
|
||||||
|
Cu.import("resource:///modules/HUDService.jsm", tempScope);
|
||||||
try {
|
try {
|
||||||
return HUDService.consoleUI;
|
return tempScope.HUDService.consoleUI;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
Components.utils.reportError(ex);
|
Components.utils.reportError(ex);
|
||||||
|
@ -9072,6 +9067,11 @@ var StyleEditor = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function onWebDeveloperMenuShowing() {
|
||||||
|
document.getElementById("Tools:WebConsole").setAttribute("checked", HUDConsoleUI.getOpenHUD() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
|
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
// Only show resizers on Windows 2000 and XP
|
// Only show resizers on Windows 2000 and XP
|
||||||
|
@ -9146,6 +9146,7 @@ var MousePosTracker = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function focusNextFrame(event) {
|
function focusNextFrame(event) {
|
||||||
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||||
let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
|
let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
<panel id="customizeToolbarSheetPopup"
|
<panel id="customizeToolbarSheetPopup"
|
||||||
noautohide="true">
|
noautohide="true">
|
||||||
<iframe id="customizeToolbarSheetIFrame"
|
<iframe id="customizeToolbarSheetIFrame"
|
||||||
style="&dialog.style;"
|
style="&dialog.dimensions;"
|
||||||
hidden="true"/>
|
hidden="true"/>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
||||||
|
@ -502,7 +502,7 @@
|
||||||
<textbox id="urlbar" flex="1"
|
<textbox id="urlbar" flex="1"
|
||||||
placeholder="&urlbar.placeholder;"
|
placeholder="&urlbar.placeholder;"
|
||||||
type="autocomplete"
|
type="autocomplete"
|
||||||
autocompletesearch="history"
|
autocompletesearch="urlinline history"
|
||||||
autocompletesearchparam="enable-actions"
|
autocompletesearchparam="enable-actions"
|
||||||
autocompletepopup="PopupAutoCompleteRichResult"
|
autocompletepopup="PopupAutoCompleteRichResult"
|
||||||
completeselectedindex="true"
|
completeselectedindex="true"
|
||||||
|
@ -534,12 +534,12 @@
|
||||||
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
|
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
|
||||||
ondragstart="gIdentityHandler.onDragStart(event);">
|
ondragstart="gIdentityHandler.onDragStart(event);">
|
||||||
<hbox id="identity-box-inner" align="center">
|
<hbox id="identity-box-inner" align="center">
|
||||||
<stack id="page-proxy-stack"
|
<hbox id="page-proxy-stack"
|
||||||
onclick="PageProxyClickHandler(event);">
|
onclick="PageProxyClickHandler(event);">
|
||||||
<image id="page-proxy-favicon" validate="never"
|
<image id="page-proxy-favicon" validate="never"
|
||||||
pageproxystate="invalid"
|
pageproxystate="invalid"
|
||||||
onerror="this.removeAttribute('src');"/>
|
onerror="this.removeAttribute('src');"/>
|
||||||
</stack>
|
</hbox>
|
||||||
<hbox id="identity-icon-labels">
|
<hbox id="identity-icon-labels">
|
||||||
<label id="identity-icon-label" class="plain" flex="1"/>
|
<label id="identity-icon-label" class="plain" flex="1"/>
|
||||||
<label id="identity-icon-country-label" class="plain"/>
|
<label id="identity-icon-country-label" class="plain"/>
|
||||||
|
@ -993,7 +993,6 @@
|
||||||
hidden="true">
|
hidden="true">
|
||||||
<vbox flex="1">
|
<vbox flex="1">
|
||||||
<resizer id="inspector-top-resizer" flex="1"
|
<resizer id="inspector-top-resizer" flex="1"
|
||||||
class="inspector-resizer"
|
|
||||||
dir="top" disabled="true"
|
dir="top" disabled="true"
|
||||||
element="inspector-tree-box"/>
|
element="inspector-tree-box"/>
|
||||||
<hbox>
|
<hbox>
|
||||||
|
@ -1029,10 +1028,6 @@
|
||||||
oncommand="InspectorUI.closeInspectorUI(false);"
|
oncommand="InspectorUI.closeInspectorUI(false);"
|
||||||
tooltiptext="&inspectCloseButton.tooltiptext;"/>
|
tooltiptext="&inspectCloseButton.tooltiptext;"/>
|
||||||
#endif
|
#endif
|
||||||
<resizer id="inspector-end-resizer"
|
|
||||||
class="inspector-resizer"
|
|
||||||
dir="top" disabled="true"
|
|
||||||
element="inspector-tree-box"/>
|
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
</toolbar>
|
</toolbar>
|
||||||
|
|
|
@ -34,12 +34,11 @@
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspector-resizer {
|
#inspector-top-resizer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer,
|
#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer {
|
||||||
#inspector-toolbar[treepanel-open] > vbox > hbox > #inspector-end-resizer {
|
|
||||||
display: -moz-box;
|
display: -moz-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class makes it easy to wait until a batch of callbacks has finished.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* let batch = new Batch(function () alert("finished"));
|
||||||
|
* let pop = batch.pop.bind(batch);
|
||||||
|
*
|
||||||
|
* for (let i = 0; i < 5; i++) {
|
||||||
|
* batch.push();
|
||||||
|
* setTimeout(pop, i * 1000);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* batch.close();
|
||||||
|
*/
|
||||||
|
function Batch(aCallback) {
|
||||||
|
this._callback = aCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
Batch.prototype = {
|
||||||
|
/**
|
||||||
|
* The number of batch entries.
|
||||||
|
*/
|
||||||
|
_count: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this batch is closed.
|
||||||
|
*/
|
||||||
|
_closed: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the number of batch entries by one.
|
||||||
|
*/
|
||||||
|
push: function Batch_push() {
|
||||||
|
if (!this._closed)
|
||||||
|
this._count++;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decreases the number of batch entries by one.
|
||||||
|
*/
|
||||||
|
pop: function Batch_pop() {
|
||||||
|
if (this._count)
|
||||||
|
this._count--;
|
||||||
|
|
||||||
|
if (this._closed)
|
||||||
|
this._check();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the batch so that no new entries can be added.
|
||||||
|
*/
|
||||||
|
close: function Batch_close() {
|
||||||
|
if (this._closed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._closed = true;
|
||||||
|
this._check();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the batch has finished.
|
||||||
|
*/
|
||||||
|
_check: function Batch_check() {
|
||||||
|
if (this._count == 0 && this._callback) {
|
||||||
|
this._callback();
|
||||||
|
this._callback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,137 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages a cell's DOM node (not the actually cell content, a site).
|
||||||
|
* It's mostly read-only, i.e. all manipulation of both position and content
|
||||||
|
* aren't handled here.
|
||||||
|
*/
|
||||||
|
function Cell(aGrid, aNode) {
|
||||||
|
this._grid = aGrid;
|
||||||
|
this._node = aNode;
|
||||||
|
this._node._newtabCell = this;
|
||||||
|
|
||||||
|
// Register drag-and-drop event handlers.
|
||||||
|
["DragEnter", "DragOver", "DragExit", "Drop"].forEach(function (aType) {
|
||||||
|
let method = "on" + aType;
|
||||||
|
this[method] = this[method].bind(this);
|
||||||
|
this._node.addEventListener(aType.toLowerCase(), this[method], false);
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell.prototype = {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
_grid: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cell's DOM node.
|
||||||
|
*/
|
||||||
|
get node() this._node,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cell's offset in the grid.
|
||||||
|
*/
|
||||||
|
get index() {
|
||||||
|
let index = this._grid.cells.indexOf(this);
|
||||||
|
|
||||||
|
// Cache this value, overwrite the getter.
|
||||||
|
Object.defineProperty(this, "index", {value: index, enumerable: true});
|
||||||
|
|
||||||
|
return index;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The previous cell in the grid.
|
||||||
|
*/
|
||||||
|
get previousSibling() {
|
||||||
|
let prev = this.node.previousElementSibling;
|
||||||
|
prev = prev && prev._newtabCell;
|
||||||
|
|
||||||
|
// Cache this value, overwrite the getter.
|
||||||
|
Object.defineProperty(this, "previousSibling", {value: prev, enumerable: true});
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next cell in the grid.
|
||||||
|
*/
|
||||||
|
get nextSibling() {
|
||||||
|
let next = this.node.nextElementSibling;
|
||||||
|
next = next && next._newtabCell;
|
||||||
|
|
||||||
|
// Cache this value, overwrite the getter.
|
||||||
|
Object.defineProperty(this, "nextSibling", {value: next, enumerable: true});
|
||||||
|
|
||||||
|
return next;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The site contained in the cell, if any.
|
||||||
|
*/
|
||||||
|
get site() {
|
||||||
|
let firstChild = this.node.firstElementChild;
|
||||||
|
return firstChild && firstChild._newtabSite;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the cell contains a pinned site.
|
||||||
|
* @return Whether the cell contains a pinned site.
|
||||||
|
*/
|
||||||
|
containsPinnedSite: function Cell_containsPinnedSite() {
|
||||||
|
let site = this.site;
|
||||||
|
return site && site.isPinned();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the cell contains a site (is empty).
|
||||||
|
* @return Whether the cell is empty.
|
||||||
|
*/
|
||||||
|
isEmpty: function Cell_isEmpty() {
|
||||||
|
return !this.site;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'dragenter' event.
|
||||||
|
* @param aEvent The dragenter event.
|
||||||
|
*/
|
||||||
|
onDragEnter: function Cell_onDragEnter(aEvent) {
|
||||||
|
if (gDrag.isValid(aEvent)) {
|
||||||
|
aEvent.preventDefault();
|
||||||
|
gDrop.enter(this, aEvent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'dragover' event.
|
||||||
|
* @param aEvent The dragover event.
|
||||||
|
*/
|
||||||
|
onDragOver: function Cell_onDragOver(aEvent) {
|
||||||
|
if (gDrag.isValid(aEvent))
|
||||||
|
aEvent.preventDefault();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'dragexit' event.
|
||||||
|
* @param aEvent The dragexit event.
|
||||||
|
*/
|
||||||
|
onDragExit: function Cell_onDragExit(aEvent) {
|
||||||
|
gDrop.exit(this, aEvent);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'drop' event.
|
||||||
|
* @param aEvent The drop event.
|
||||||
|
*/
|
||||||
|
onDrop: function Cell_onDrop(aEvent) {
|
||||||
|
if (gDrag.isValid(aEvent)) {
|
||||||
|
aEvent.preventDefault();
|
||||||
|
gDrop.drop(this, aEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,140 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton implements site dragging functionality.
|
||||||
|
*/
|
||||||
|
let gDrag = {
|
||||||
|
/**
|
||||||
|
* The site offset to the drag start point.
|
||||||
|
*/
|
||||||
|
_offsetX: null,
|
||||||
|
_offsetY: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The site that is dragged.
|
||||||
|
*/
|
||||||
|
_draggedSite: null,
|
||||||
|
get draggedSite() this._draggedSite,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cell width/height at the point the drag started.
|
||||||
|
*/
|
||||||
|
_cellWidth: null,
|
||||||
|
_cellHeight: null,
|
||||||
|
get cellWidth() this._cellWidth,
|
||||||
|
get cellHeight() this._cellHeight,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new drag operation.
|
||||||
|
* @param aSite The site that's being dragged.
|
||||||
|
* @param aEvent The 'dragstart' event.
|
||||||
|
*/
|
||||||
|
start: function Drag_start(aSite, aEvent) {
|
||||||
|
this._draggedSite = aSite;
|
||||||
|
|
||||||
|
// Prevent moz-transform for left, top.
|
||||||
|
aSite.node.setAttribute("dragged", "true");
|
||||||
|
|
||||||
|
// Make sure the dragged site is floating above the grid.
|
||||||
|
aSite.node.setAttribute("ontop", "true");
|
||||||
|
|
||||||
|
this._setDragData(aSite, aEvent);
|
||||||
|
|
||||||
|
// Store the cursor offset.
|
||||||
|
let node = aSite.node;
|
||||||
|
let rect = node.getBoundingClientRect();
|
||||||
|
this._offsetX = aEvent.clientX - rect.left;
|
||||||
|
this._offsetY = aEvent.clientY - rect.top;
|
||||||
|
|
||||||
|
// Store the cell dimensions.
|
||||||
|
let cellNode = aSite.cell.node;
|
||||||
|
this._cellWidth = cellNode.offsetWidth;
|
||||||
|
this._cellHeight = cellNode.offsetHeight;
|
||||||
|
|
||||||
|
gTransformation.freezeSitePosition(aSite);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'drag' event.
|
||||||
|
* @param aSite The site that's being dragged.
|
||||||
|
* @param aEvent The 'drag' event.
|
||||||
|
*/
|
||||||
|
drag: function Drag_drag(aSite, aEvent) {
|
||||||
|
// Get the viewport size.
|
||||||
|
let {clientWidth, clientHeight} = document.documentElement;
|
||||||
|
|
||||||
|
// We'll want a padding of 5px.
|
||||||
|
let border = 5;
|
||||||
|
|
||||||
|
// Enforce minimum constraints to keep the drag image inside the window.
|
||||||
|
let left = Math.max(scrollX + aEvent.clientX - this._offsetX, border);
|
||||||
|
let top = Math.max(scrollY + aEvent.clientY - this._offsetY, border);
|
||||||
|
|
||||||
|
// Enforce maximum constraints to keep the drag image inside the window.
|
||||||
|
left = Math.min(left, scrollX + clientWidth - this.cellWidth - border);
|
||||||
|
top = Math.min(top, scrollY + clientHeight - this.cellHeight - border);
|
||||||
|
|
||||||
|
// Update the drag image's position.
|
||||||
|
gTransformation.setSitePosition(aSite, {left: left, top: top});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the current drag operation.
|
||||||
|
* @param aSite The site that's being dragged.
|
||||||
|
* @param aEvent The 'dragend' event.
|
||||||
|
*/
|
||||||
|
end: function Drag_end(aSite, aEvent) {
|
||||||
|
aSite.node.removeAttribute("dragged");
|
||||||
|
|
||||||
|
// Slide the dragged site back into its cell (may be the old or the new cell).
|
||||||
|
gTransformation.slideSiteTo(aSite, aSite.cell, {
|
||||||
|
unfreeze: true,
|
||||||
|
callback: function () aSite.node.removeAttribute("ontop")
|
||||||
|
});
|
||||||
|
|
||||||
|
this._draggedSite = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether we're responsible for a given drag event.
|
||||||
|
* @param aEvent The drag event to check.
|
||||||
|
* @return Whether we should handle this drag and drop operation.
|
||||||
|
*/
|
||||||
|
isValid: function Drag_isValid(aEvent) {
|
||||||
|
let dt = aEvent.dataTransfer;
|
||||||
|
return dt && dt.types.contains("text/x-moz-url");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the drag data for the current drag operation.
|
||||||
|
* @param aSite The site that's being dragged.
|
||||||
|
* @param aEvent The 'dragstart' event.
|
||||||
|
*/
|
||||||
|
_setDragData: function Drag_setDragData(aSite, aEvent) {
|
||||||
|
let {url, title} = aSite;
|
||||||
|
|
||||||
|
let dt = aEvent.dataTransfer;
|
||||||
|
dt.mozCursor = "default";
|
||||||
|
dt.effectAllowed = "move";
|
||||||
|
dt.setData("text/plain", url);
|
||||||
|
dt.setData("text/uri-list", url);
|
||||||
|
dt.setData("text/x-moz-url", url + "\n" + title);
|
||||||
|
dt.setData("text/html", "<a href=\"" + url + "\">" + url + "</a>");
|
||||||
|
|
||||||
|
// Create and use an empty drag element. We don't want to use the default
|
||||||
|
// drag image with its default opacity.
|
||||||
|
let dragElement = document.createElementNS(HTML_NAMESPACE, "div");
|
||||||
|
dragElement.classList.add("drag-element");
|
||||||
|
let body = document.getElementById("body");
|
||||||
|
body.appendChild(dragElement);
|
||||||
|
dt.setDragImage(dragElement, 0, 0);
|
||||||
|
|
||||||
|
// After the 'dragstart' event has been processed we can remove the
|
||||||
|
// temporary drag element from the DOM.
|
||||||
|
setTimeout(function () body.removeChild(dragElement), 0);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,147 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// A little delay that prevents the grid from being too sensitive when dragging
|
||||||
|
// sites around.
|
||||||
|
const DELAY_REARRANGE_MS = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton implements site dropping functionality.
|
||||||
|
*/
|
||||||
|
let gDrop = {
|
||||||
|
/**
|
||||||
|
* The last drop target.
|
||||||
|
*/
|
||||||
|
_lastDropTarget: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'dragenter' event.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
enter: function Drop_enter(aCell) {
|
||||||
|
this._delayedRearrange(aCell);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'dragexit' event.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @param aEvent The 'dragexit' event.
|
||||||
|
*/
|
||||||
|
exit: function Drop_exit(aCell, aEvent) {
|
||||||
|
if (aEvent.dataTransfer && !aEvent.dataTransfer.mozUserCancelled) {
|
||||||
|
this._delayedRearrange();
|
||||||
|
} else {
|
||||||
|
// The drag operation has been cancelled.
|
||||||
|
this._cancelDelayedArrange();
|
||||||
|
this._rearrange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'drop' event.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @param aEvent The 'dragexit' event.
|
||||||
|
* @param aCallback The callback to call when the drop is finished.
|
||||||
|
*/
|
||||||
|
drop: function Drop_drop(aCell, aEvent, aCallback) {
|
||||||
|
// The cell that is the drop target could contain a pinned site. We need
|
||||||
|
// to find out where that site has gone and re-pin it there.
|
||||||
|
if (aCell.containsPinnedSite())
|
||||||
|
this._repinSitesAfterDrop(aCell);
|
||||||
|
|
||||||
|
// Pin the dragged or insert the new site.
|
||||||
|
this._pinDraggedSite(aCell, aEvent);
|
||||||
|
|
||||||
|
this._cancelDelayedArrange();
|
||||||
|
|
||||||
|
// Update the grid and move all sites to their new places.
|
||||||
|
gUpdater.updateGrid(aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-pins all pinned sites in their (new) positions.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
_repinSitesAfterDrop: function Drop_repinSitesAfterDrop(aCell) {
|
||||||
|
let sites = gDropPreview.rearrange(aCell);
|
||||||
|
|
||||||
|
// Filter out pinned sites.
|
||||||
|
let pinnedSites = sites.filter(function (aSite) {
|
||||||
|
return aSite && aSite.isPinned();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-pin all shifted pinned cells.
|
||||||
|
pinnedSites.forEach(function (aSite) aSite.pin(sites.indexOf(aSite)), this);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pins the dragged site in its new place.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @param aEvent The 'dragexit' event.
|
||||||
|
*/
|
||||||
|
_pinDraggedSite: function Drop_pinDraggedSite(aCell, aEvent) {
|
||||||
|
let index = aCell.index;
|
||||||
|
let draggedSite = gDrag.draggedSite;
|
||||||
|
|
||||||
|
if (draggedSite) {
|
||||||
|
// Pin the dragged site at its new place.
|
||||||
|
if (aCell != draggedSite.cell)
|
||||||
|
draggedSite.pin(index);
|
||||||
|
} else {
|
||||||
|
// A new link was dragged onto the grid. Create it by pinning its URL.
|
||||||
|
let dt = aEvent.dataTransfer;
|
||||||
|
let [url, title] = dt.getData("text/x-moz-url").split(/[\r\n]+/);
|
||||||
|
gPinnedLinks.pin({url: url, title: title}, index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time a rearrange with a little delay.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
_delayedRearrange: function Drop_delayedRearrange(aCell) {
|
||||||
|
// The last drop target didn't change so there's no need to re-arrange.
|
||||||
|
if (this._lastDropTarget == aCell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
function callback() {
|
||||||
|
self._rearrangeTimeout = null;
|
||||||
|
self._rearrange(aCell);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cancelDelayedArrange();
|
||||||
|
this._rearrangeTimeout = setTimeout(callback, DELAY_REARRANGE_MS);
|
||||||
|
|
||||||
|
// Store the last drop target.
|
||||||
|
this._lastDropTarget = aCell;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a timed rearrange, if any.
|
||||||
|
*/
|
||||||
|
_cancelDelayedArrange: function Drop_cancelDelayedArrange() {
|
||||||
|
if (this._rearrangeTimeout) {
|
||||||
|
clearTimeout(this._rearrangeTimeout);
|
||||||
|
this._rearrangeTimeout = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rearrange all sites in the grid depending on the current drop target.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
_rearrange: function Drop_rearrange(aCell) {
|
||||||
|
let sites = gGrid.sites;
|
||||||
|
|
||||||
|
// We need to rearrange the grid only if there's a current drop target.
|
||||||
|
if (aCell)
|
||||||
|
sites = gDropPreview.rearrange(aCell);
|
||||||
|
|
||||||
|
gTransformation.rearrangeSites(sites, {unfreeze: !aCell});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,222 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton provides the ability to re-arrange the current grid to
|
||||||
|
* indicate the transformation that results from dropping a cell at a certain
|
||||||
|
* position.
|
||||||
|
*/
|
||||||
|
let gDropPreview = {
|
||||||
|
/**
|
||||||
|
* Rearranges the sites currently contained in the grid when a site would be
|
||||||
|
* dropped onto the given cell.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @return The re-arranged array of sites.
|
||||||
|
*/
|
||||||
|
rearrange: function DropPreview_rearrange(aCell) {
|
||||||
|
let sites = gGrid.sites;
|
||||||
|
|
||||||
|
// Insert the dragged site into the current grid.
|
||||||
|
this._insertDraggedSite(sites, aCell);
|
||||||
|
|
||||||
|
// After the new site has been inserted we need to correct the positions
|
||||||
|
// of all pinned tabs that have been moved around.
|
||||||
|
this._repositionPinnedSites(sites, aCell);
|
||||||
|
|
||||||
|
return sites;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the currently dragged site into the given array of sites.
|
||||||
|
* @param aSites The array of sites to insert into.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
_insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) {
|
||||||
|
let dropIndex = aCell.index;
|
||||||
|
let draggedSite = gDrag.draggedSite;
|
||||||
|
|
||||||
|
// We're currently dragging a site.
|
||||||
|
if (draggedSite) {
|
||||||
|
let dragCell = draggedSite.cell;
|
||||||
|
let dragIndex = dragCell.index;
|
||||||
|
|
||||||
|
// Move the dragged site into its new position.
|
||||||
|
if (dragIndex != dropIndex) {
|
||||||
|
aSites.splice(dragIndex, 1);
|
||||||
|
aSites.splice(dropIndex, 0, draggedSite);
|
||||||
|
}
|
||||||
|
// We're handling an external drag item.
|
||||||
|
} else {
|
||||||
|
aSites.splice(dropIndex, 0, null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the position of all pinned sites that might have been moved to
|
||||||
|
* different positions after the dragged site has been inserted.
|
||||||
|
* @param aSites The array of sites containing the dragged site.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
_repositionPinnedSites:
|
||||||
|
function DropPreview_repositionPinnedSites(aSites, aCell) {
|
||||||
|
|
||||||
|
// Collect all pinned sites.
|
||||||
|
let pinnedSites = this._filterPinnedSites(aSites, aCell);
|
||||||
|
|
||||||
|
// Correct pinned site positions.
|
||||||
|
pinnedSites.forEach(function (aSite) {
|
||||||
|
aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index];
|
||||||
|
aSites[aSite.cell.index] = aSite;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// There might be a pinned cell that got pushed out of the grid, try to
|
||||||
|
// sneak it in by removing a lower-priority cell.
|
||||||
|
if (this._hasOverflowedPinnedSite(aSites, aCell))
|
||||||
|
this._repositionOverflowedPinnedSite(aSites, aCell);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter pinned sites out of the grid that are still on their old positions
|
||||||
|
* and have not moved.
|
||||||
|
* @param aSites The array of sites to filter.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @return The filtered array of sites.
|
||||||
|
*/
|
||||||
|
_filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) {
|
||||||
|
let draggedSite = gDrag.draggedSite;
|
||||||
|
|
||||||
|
// When dropping on a cell that contains a pinned site make sure that all
|
||||||
|
// pinned cells surrounding the drop target are moved as well.
|
||||||
|
let range = this._getPinnedRange(aCell);
|
||||||
|
|
||||||
|
return aSites.filter(function (aSite, aIndex) {
|
||||||
|
// The site must be valid, pinned and not the dragged site.
|
||||||
|
if (!aSite || aSite == draggedSite || !aSite.isPinned())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let index = aSite.cell.index;
|
||||||
|
|
||||||
|
// If it's not in the 'pinned range' it's a valid pinned site.
|
||||||
|
return (index > range.end || index < range.start);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the range of pinned sites surrounding the drop target cell.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @return The range of pinned cells.
|
||||||
|
*/
|
||||||
|
_getPinnedRange: function DropPreview_getPinnedRange(aCell) {
|
||||||
|
let dropIndex = aCell.index;
|
||||||
|
let range = {start: dropIndex, end: dropIndex};
|
||||||
|
|
||||||
|
// We need a pinned range only when dropping on a pinned site.
|
||||||
|
if (aCell.containsPinnedSite()) {
|
||||||
|
let links = gPinnedLinks.links;
|
||||||
|
|
||||||
|
// Find all previous siblings of the drop target that are pinned as well.
|
||||||
|
while (range.start && links[range.start - 1])
|
||||||
|
range.start--;
|
||||||
|
|
||||||
|
let maxEnd = links.length - 1;
|
||||||
|
|
||||||
|
// Find all next siblings of the drop target that are pinned as well.
|
||||||
|
while (range.end < maxEnd && links[range.end + 1])
|
||||||
|
range.end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return range;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given array of sites contains a pinned site that has
|
||||||
|
* been pushed out of the grid.
|
||||||
|
* @param aSites The array of sites to check.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @return Whether there is an overflowed pinned cell.
|
||||||
|
*/
|
||||||
|
_hasOverflowedPinnedSite:
|
||||||
|
function DropPreview_hasOverflowedPinnedSite(aSites, aCell) {
|
||||||
|
|
||||||
|
// If the drop target isn't pinned there's no way a pinned site has been
|
||||||
|
// pushed out of the grid so we can just exit here.
|
||||||
|
if (!aCell.containsPinnedSite())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let cells = gGrid.cells;
|
||||||
|
|
||||||
|
// No cells have been pushed out of the grid, nothing to do here.
|
||||||
|
if (aSites.length <= cells.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let overflowedSite = aSites[cells.length];
|
||||||
|
|
||||||
|
// Nothing to do if the site that got pushed out of the grid is not pinned.
|
||||||
|
return (overflowedSite && overflowedSite.isPinned());
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have a overflowed pinned site that we need to re-position so that it's
|
||||||
|
* visible again. We try to find a lower-priority cell (empty or containing
|
||||||
|
* an unpinned site) that we can move it to.
|
||||||
|
* @param aSites The array of sites.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
*/
|
||||||
|
_repositionOverflowedPinnedSite:
|
||||||
|
function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) {
|
||||||
|
|
||||||
|
// Try to find a lower-priority cell (empty or containing an unpinned site).
|
||||||
|
let index = this._indexOfLowerPrioritySite(aSites, aCell);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
let cells = gGrid.cells;
|
||||||
|
let dropIndex = aCell.index;
|
||||||
|
|
||||||
|
// Move all pinned cells to their new positions to let the overflowed
|
||||||
|
// site fit into the grid.
|
||||||
|
for (let i = index + 1, lastPosition = index; i < aSites.length; i++) {
|
||||||
|
if (i != dropIndex) {
|
||||||
|
aSites[lastPosition] = aSites[i];
|
||||||
|
lastPosition = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, remove the overflowed site from its previous position.
|
||||||
|
aSites.splice(cells.length, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index of the last cell that is empty or contains an unpinned
|
||||||
|
* site. These are considered to be of a lower priority.
|
||||||
|
* @param aSites The array of sites.
|
||||||
|
* @param aCell The drop target cell.
|
||||||
|
* @return The cell's index.
|
||||||
|
*/
|
||||||
|
_indexOfLowerPrioritySite:
|
||||||
|
function DropPreview_indexOfLowerPrioritySite(aSites, aCell) {
|
||||||
|
|
||||||
|
let cells = gGrid.cells;
|
||||||
|
let dropIndex = aCell.index;
|
||||||
|
|
||||||
|
// Search (beginning with the last site in the grid) for a site that is
|
||||||
|
// empty or unpinned (an thus lower-priority) and can be pushed out of the
|
||||||
|
// grid instead of the pinned site.
|
||||||
|
for (let i = cells.length - 1; i >= 0; i--) {
|
||||||
|
// The cell that is our drop target is not a good choice.
|
||||||
|
if (i == dropIndex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let site = aSites[i];
|
||||||
|
|
||||||
|
// We can use the cell only if it's empty or the site is un-pinned.
|
||||||
|
if (!site || !site.isPinned())
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,178 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton provides a custom drop target detection. We need this because
|
||||||
|
* the default DnD target detection relies on the cursor's position. We want
|
||||||
|
* to pick a drop target based on the dragged site's position.
|
||||||
|
*/
|
||||||
|
let gDropTargetShim = {
|
||||||
|
/**
|
||||||
|
* Cache for the position of all cells, cleaned after drag finished.
|
||||||
|
*/
|
||||||
|
_cellPositions: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last drop target that was hovered.
|
||||||
|
*/
|
||||||
|
_lastDropTarget: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the drop target shim.
|
||||||
|
*/
|
||||||
|
init: function DropTargetShim_init() {
|
||||||
|
let node = gGrid.node;
|
||||||
|
|
||||||
|
this._dragover = this._dragover.bind(this);
|
||||||
|
|
||||||
|
// Add drag event handlers.
|
||||||
|
node.addEventListener("dragstart", this._start.bind(this), true);
|
||||||
|
// XXX bug 505521 - Don't listen for drag, it's useless at the moment.
|
||||||
|
//node.addEventListener("drag", this._drag.bind(this), false);
|
||||||
|
node.addEventListener("dragend", this._end.bind(this), true);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'dragstart' event.
|
||||||
|
* @param aEvent The 'dragstart' event.
|
||||||
|
*/
|
||||||
|
_start: function DropTargetShim_start(aEvent) {
|
||||||
|
gGrid.lock();
|
||||||
|
|
||||||
|
// XXX bug 505521 - Listen for dragover on the document.
|
||||||
|
document.documentElement.addEventListener("dragover", this._dragover, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'drag' event and determines the current drop target.
|
||||||
|
* @param aEvent The 'drag' event.
|
||||||
|
*/
|
||||||
|
_drag: function DropTargetShim_drag(aEvent) {
|
||||||
|
// Let's see if we find a drop target.
|
||||||
|
let target = this._findDropTarget(aEvent);
|
||||||
|
|
||||||
|
if (target == this._lastDropTarget) {
|
||||||
|
// XXX bug 505521 - Don't fire dragover for now (causes recursion).
|
||||||
|
/*if (target)
|
||||||
|
// The last drop target is valid and didn't change.
|
||||||
|
this._dispatchEvent(aEvent, "dragover", target);*/
|
||||||
|
} else {
|
||||||
|
if (this._lastDropTarget)
|
||||||
|
// We left the last drop target.
|
||||||
|
this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
// We're now hovering a (new) drop target.
|
||||||
|
this._dispatchEvent(aEvent, "dragenter", target);
|
||||||
|
|
||||||
|
if (this._lastDropTarget)
|
||||||
|
// We left the last drop target.
|
||||||
|
this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget);
|
||||||
|
|
||||||
|
this._lastDropTarget = target;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'dragover' event as long as bug 505521 isn't fixed to get
|
||||||
|
* current mouse cursor coordinates while dragging.
|
||||||
|
* @param aEvent The 'dragover' event.
|
||||||
|
*/
|
||||||
|
_dragover: function DropTargetShim_dragover(aEvent) {
|
||||||
|
let sourceNode = aEvent.dataTransfer.mozSourceNode;
|
||||||
|
gDrag.drag(sourceNode._newtabSite, aEvent);
|
||||||
|
|
||||||
|
this._drag(aEvent);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'dragend' event.
|
||||||
|
* @param aEvent The 'dragend' event.
|
||||||
|
*/
|
||||||
|
_end: function DropTargetShim_end(aEvent) {
|
||||||
|
// Make sure to determine the current drop target in case the dragenter
|
||||||
|
// event hasn't been fired.
|
||||||
|
this._drag(aEvent);
|
||||||
|
|
||||||
|
if (this._lastDropTarget) {
|
||||||
|
if (aEvent.dataTransfer.mozUserCancelled) {
|
||||||
|
// The drag operation was cancelled.
|
||||||
|
this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
|
||||||
|
this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget);
|
||||||
|
} else {
|
||||||
|
// A site was successfully dropped.
|
||||||
|
this._dispatchEvent(aEvent, "drop", this._lastDropTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
this._lastDropTarget = null;
|
||||||
|
this._cellPositions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
gGrid.unlock();
|
||||||
|
|
||||||
|
// XXX bug 505521 - Remove the document's dragover listener.
|
||||||
|
document.documentElement.removeEventListener("dragover", this._dragover, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the current drop target by matching the dragged site's position
|
||||||
|
* against all cells in the grid.
|
||||||
|
* @return The currently hovered drop target or null.
|
||||||
|
*/
|
||||||
|
_findDropTarget: function DropTargetShim_findDropTarget() {
|
||||||
|
// These are the minimum intersection values - we want to use the cell if
|
||||||
|
// the site is >= 50% hovering its position.
|
||||||
|
let minWidth = gDrag.cellWidth / 2;
|
||||||
|
let minHeight = gDrag.cellHeight / 2;
|
||||||
|
|
||||||
|
let cellPositions = this._getCellPositions();
|
||||||
|
let rect = gTransformation.getNodePosition(gDrag.draggedSite.node);
|
||||||
|
|
||||||
|
// Compare each cell's position to the dragged site's position.
|
||||||
|
for (let i = 0; i < cellPositions.length; i++) {
|
||||||
|
let inter = rect.intersect(cellPositions[i].rect);
|
||||||
|
|
||||||
|
// If the intersection is big enough we found a drop target.
|
||||||
|
if (inter.width >= minWidth && inter.height >= minHeight)
|
||||||
|
return cellPositions[i].cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No drop target found.
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the positions of all cell nodes.
|
||||||
|
* @return The (cached) cell positions.
|
||||||
|
*/
|
||||||
|
_getCellPositions: function DropTargetShim_getCellPositions() {
|
||||||
|
if (this._cellPositions)
|
||||||
|
return this._cellPositions;
|
||||||
|
|
||||||
|
return this._cellPositions = gGrid.cells.map(function (cell) {
|
||||||
|
return {cell: cell, rect: gTransformation.getNodePosition(cell.node)};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches a custom DragEvent on the given target node.
|
||||||
|
* @param aEvent The source event.
|
||||||
|
* @param aType The event type.
|
||||||
|
* @param aTarget The target node that receives the event.
|
||||||
|
*/
|
||||||
|
_dispatchEvent:
|
||||||
|
function DropTargetShim_dispatchEvent(aEvent, aType, aTarget) {
|
||||||
|
|
||||||
|
let node = aTarget.node;
|
||||||
|
let event = document.createEvent("DragEvents");
|
||||||
|
|
||||||
|
event.initDragEvent(aType, true, true, window, 0, 0, 0, 0, 0, false, false,
|
||||||
|
false, false, 0, node, aEvent.dataTransfer);
|
||||||
|
|
||||||
|
node.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,132 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton represents the grid that contains all sites.
|
||||||
|
*/
|
||||||
|
let gGrid = {
|
||||||
|
/**
|
||||||
|
* The DOM node of the grid.
|
||||||
|
*/
|
||||||
|
_node: null,
|
||||||
|
get node() this._node,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cached DOM fragment for sites.
|
||||||
|
*/
|
||||||
|
_siteFragment: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All cells contained in the grid.
|
||||||
|
*/
|
||||||
|
get cells() {
|
||||||
|
let children = this.node.querySelectorAll("li");
|
||||||
|
let cells = [new Cell(this, child) for each (child in children)];
|
||||||
|
|
||||||
|
// Replace the getter with our cached value.
|
||||||
|
Object.defineProperty(this, "cells", {value: cells, enumerable: true});
|
||||||
|
|
||||||
|
return cells;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All sites contained in the grid's cells. Sites may be empty.
|
||||||
|
*/
|
||||||
|
get sites() [cell.site for each (cell in this.cells)],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the grid.
|
||||||
|
* @param aSelector The query selector of the grid.
|
||||||
|
*/
|
||||||
|
init: function Grid_init(aSelector) {
|
||||||
|
this._node = document.querySelector(aSelector);
|
||||||
|
this._createSiteFragment();
|
||||||
|
this._draw();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new site in the grid.
|
||||||
|
* @param aLink The new site's link.
|
||||||
|
* @param aCell The cell that will contain the new site.
|
||||||
|
* @return The newly created site.
|
||||||
|
*/
|
||||||
|
createSite: function Grid_createSite(aLink, aCell) {
|
||||||
|
let node = aCell.node;
|
||||||
|
node.appendChild(this._siteFragment.cloneNode(true));
|
||||||
|
return new Site(node.firstElementChild, aLink);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the grid and re-creates all sites.
|
||||||
|
*/
|
||||||
|
refresh: function Grid_refresh() {
|
||||||
|
// Remove all sites.
|
||||||
|
this.cells.forEach(function (cell) {
|
||||||
|
let node = cell.node;
|
||||||
|
let child = node.firstElementChild;
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
node.removeChild(child);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Draw the grid again.
|
||||||
|
this._draw();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the grid to block all pointer events.
|
||||||
|
*/
|
||||||
|
lock: function Grid_lock() {
|
||||||
|
this.node.setAttribute("locked", "true");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks the grid to allow all pointer events.
|
||||||
|
*/
|
||||||
|
unlock: function Grid_unlock() {
|
||||||
|
this.node.removeAttribute("locked");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the DOM fragment that is re-used when creating sites.
|
||||||
|
*/
|
||||||
|
_createSiteFragment: function Grid_createSiteFragment() {
|
||||||
|
let site = document.createElementNS(HTML_NAMESPACE, "a");
|
||||||
|
site.classList.add("site");
|
||||||
|
site.setAttribute("draggable", "true");
|
||||||
|
|
||||||
|
// Create the site's inner HTML code.
|
||||||
|
site.innerHTML =
|
||||||
|
'<img class="site-img" width="' + THUMB_WIDTH +'" ' +
|
||||||
|
' height="' + THUMB_HEIGHT + '" alt=""/>' +
|
||||||
|
'<span class="site-title"/>' +
|
||||||
|
'<span class="site-strip">' +
|
||||||
|
' <input class="button strip-button strip-button-pin" type="button"' +
|
||||||
|
' tabindex="-1" title="' + newTabString("pin") + '"/>' +
|
||||||
|
' <input class="button strip-button strip-button-block" type="button"' +
|
||||||
|
' tabindex="-1" title="' + newTabString("block") + '"/>' +
|
||||||
|
'</span>';
|
||||||
|
|
||||||
|
this._siteFragment = document.createDocumentFragment();
|
||||||
|
this._siteFragment.appendChild(site);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the grid, creates all sites and puts them into their cells.
|
||||||
|
*/
|
||||||
|
_draw: function Grid_draw() {
|
||||||
|
let cells = this.cells;
|
||||||
|
|
||||||
|
// Put sites into the cells.
|
||||||
|
let links = gLinks.getLinks();
|
||||||
|
let length = Math.min(links.length, cells.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
if (links[i])
|
||||||
|
this.createSite(links[i], cells[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,173 @@
|
||||||
|
:root {
|
||||||
|
-moz-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scrollbox:not([page-disabled]) {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#body {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
min-width: 675px;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOOLBAR */
|
||||||
|
#toolbar {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar[page-disabled] {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar:-moz-locale-dir(rtl) {
|
||||||
|
left: 8px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-button {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
-moz-transition: opacity 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar-button-show,
|
||||||
|
#toolbar-button-reset {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar-button-reset[modified],
|
||||||
|
#toolbar-button-show[page-disabled] {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar-button-hide[page-disabled],
|
||||||
|
#toolbar-button-reset[page-disabled] {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GRID */
|
||||||
|
#grid {
|
||||||
|
width: 637px;
|
||||||
|
height: 411px;
|
||||||
|
overflow: hidden;
|
||||||
|
list-style-type: none;
|
||||||
|
-moz-transition: opacity 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid[page-disabled] {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid[page-disabled],
|
||||||
|
#grid[locked] {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CELLS */
|
||||||
|
.cell {
|
||||||
|
float: left;
|
||||||
|
width: 201px;
|
||||||
|
height: 127px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
-moz-margin-end: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell:-moz-locale-dir(rtl) {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell:nth-child(3n+3) {
|
||||||
|
-moz-margin-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SITES */
|
||||||
|
.site {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 201px;
|
||||||
|
height: 127px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site[frozen] {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site[ontop] {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SITE IMAGE */
|
||||||
|
.site-img {
|
||||||
|
display: block;
|
||||||
|
opacity: 0.75;
|
||||||
|
-moz-transition: opacity 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site:hover > .site-img,
|
||||||
|
.site[ontop] > .site-img,
|
||||||
|
.site:-moz-focusring > .site-img {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-img[loading] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SITE TITLE */
|
||||||
|
.site-title {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SITE STRIP */
|
||||||
|
.site-strip {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 195px;
|
||||||
|
height: 17px;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
-moz-transition: opacity 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site:hover:not([frozen]) > .site-strip {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.strip-button-pin,
|
||||||
|
.strip-button-block:-moz-locale-dir(rtl) {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.strip-button-block,
|
||||||
|
.strip-button-pin:-moz-locale-dir(rtl) {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DRAG & DROP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is just a temporary drag element used for dataTransfer.setDragImage()
|
||||||
|
* so that we can use custom drag images and elements. It needs an opacity of
|
||||||
|
* 0.01 so that the core code detects that it's in fact a visible element.
|
||||||
|
*/
|
||||||
|
.drag-element {
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #fff;
|
||||||
|
opacity: 0.01;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let Cu = Components.utils;
|
||||||
|
let Ci = Components.interfaces;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource:///modules/PageThumbs.jsm");
|
||||||
|
Cu.import("resource:///modules/NewTabUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Rect",
|
||||||
|
"resource://gre/modules/Geometry.jsm");
|
||||||
|
|
||||||
|
let {
|
||||||
|
links: gLinks,
|
||||||
|
allPages: gAllPages,
|
||||||
|
pinnedLinks: gPinnedLinks,
|
||||||
|
blockedLinks: gBlockedLinks
|
||||||
|
} = NewTabUtils;
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
|
||||||
|
return Services.strings.
|
||||||
|
createBundle("chrome://browser/locale/newTab.properties");
|
||||||
|
});
|
||||||
|
|
||||||
|
function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
|
||||||
|
|
||||||
|
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||||
|
const THUMB_WIDTH = 201;
|
||||||
|
const THUMB_HEIGHT = 127;
|
||||||
|
|
||||||
|
#include batch.js
|
||||||
|
#include transformations.js
|
||||||
|
#include page.js
|
||||||
|
#include toolbar.js
|
||||||
|
#include grid.js
|
||||||
|
#include cells.js
|
||||||
|
#include sites.js
|
||||||
|
#include drag.js
|
||||||
|
#include drop.js
|
||||||
|
#include dropTargetShim.js
|
||||||
|
#include dropPreview.js
|
||||||
|
#include updater.js
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||||
|
<?xml-stylesheet href="chrome://browser/content/newtab/newTab.css" type="text/css"?>
|
||||||
|
<?xml-stylesheet href="chrome://browser/skin/newtab/newTab.css" type="text/css"?>
|
||||||
|
|
||||||
|
<!DOCTYPE window [
|
||||||
|
<!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
|
||||||
|
%newTabDTD;
|
||||||
|
]>
|
||||||
|
|
||||||
|
<xul:window xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
disablefastfind="true" title="&newtab.pageTitle;">
|
||||||
|
<xul:vbox id="scrollbox" flex="1" title=" ">
|
||||||
|
<body id="body">
|
||||||
|
<div id="toolbar">
|
||||||
|
<input class="button toolbar-button" id="toolbar-button-show"
|
||||||
|
type="button" title="&newtab.show;"/>
|
||||||
|
<input class="button toolbar-button" id="toolbar-button-hide"
|
||||||
|
type="button" title="&newtab.hide;"/>
|
||||||
|
<input class="button toolbar-button" id="toolbar-button-reset"
|
||||||
|
type="button" title="&newtab.reset;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul id="grid">
|
||||||
|
<li class="cell"/><li class="cell"/><li class="cell"/>
|
||||||
|
<li class="cell"/><li class="cell"/><li class="cell"/>
|
||||||
|
<li class="cell"/><li class="cell"/><li class="cell"/>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<xul:script type="text/javascript;version=1.8" src="chrome://browser/content/newtab/newTab.js"/>
|
||||||
|
<xul:script type="text/javascript;version=1.8">
|
||||||
|
gPage.init("#toolbar", "#grid");
|
||||||
|
</xul:script>
|
||||||
|
</body>
|
||||||
|
</xul:vbox>
|
||||||
|
</xul:window>
|
|
@ -0,0 +1,173 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton represents the whole 'New Tab Page' and takes care of
|
||||||
|
* initializing all its components.
|
||||||
|
*/
|
||||||
|
let gPage = {
|
||||||
|
/**
|
||||||
|
* Initializes the page.
|
||||||
|
* @param aToolbarSelector The query selector for the page toolbar.
|
||||||
|
* @param aGridSelector The query selector for the grid.
|
||||||
|
*/
|
||||||
|
init: function Page_init(aToolbarSelector, aGridSelector) {
|
||||||
|
gToolbar.init(aToolbarSelector);
|
||||||
|
this._gridSelector = aGridSelector;
|
||||||
|
|
||||||
|
// Add ourselves to the list of pages to receive notifications.
|
||||||
|
gAllPages.register(this);
|
||||||
|
|
||||||
|
// Listen for 'unload' to unregister this page.
|
||||||
|
function unload() gAllPages.unregister(self);
|
||||||
|
addEventListener("unload", unload, false);
|
||||||
|
|
||||||
|
// Check if the new tab feature is enabled.
|
||||||
|
if (gAllPages.enabled)
|
||||||
|
this._init();
|
||||||
|
else
|
||||||
|
this._updateAttributes(false);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for notifications specific to this page.
|
||||||
|
*/
|
||||||
|
observe: function Page_observe() {
|
||||||
|
let enabled = gAllPages.enabled;
|
||||||
|
this._updateAttributes(enabled);
|
||||||
|
|
||||||
|
// Initialize the whole page if we haven't done that, yet.
|
||||||
|
if (enabled)
|
||||||
|
this._init();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the whole page and the grid when the storage has changed.
|
||||||
|
*/
|
||||||
|
update: function Page_update() {
|
||||||
|
this.updateModifiedFlag();
|
||||||
|
gGrid.refresh();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the page is modified and sets the CSS class accordingly
|
||||||
|
*/
|
||||||
|
updateModifiedFlag: function Page_updateModifiedFlag() {
|
||||||
|
let node = document.getElementById("toolbar-button-reset");
|
||||||
|
let modified = this._isModified();
|
||||||
|
|
||||||
|
if (modified)
|
||||||
|
node.setAttribute("modified", "true");
|
||||||
|
else
|
||||||
|
node.removeAttribute("modified");
|
||||||
|
|
||||||
|
this._updateTabIndices(gAllPages.enabled, modified);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internally initializes the page. This runs only when/if the feature
|
||||||
|
* is/gets enabled.
|
||||||
|
*/
|
||||||
|
_init: function Page_init() {
|
||||||
|
if (this._initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._initialized = true;
|
||||||
|
|
||||||
|
gLinks.populateCache(function () {
|
||||||
|
// Check if the grid is modified.
|
||||||
|
this.updateModifiedFlag();
|
||||||
|
|
||||||
|
// Initialize and render the grid.
|
||||||
|
gGrid.init(this._gridSelector);
|
||||||
|
|
||||||
|
// Initialize the drop target shim.
|
||||||
|
gDropTargetShim.init();
|
||||||
|
|
||||||
|
// Workaround to prevent a delay on MacOSX due to a slow drop animation.
|
||||||
|
let doc = document.documentElement;
|
||||||
|
doc.addEventListener("dragover", this.onDragOver, false);
|
||||||
|
doc.addEventListener("drop", this.onDrop, false);
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the 'page-disabled' attributes of the respective DOM nodes.
|
||||||
|
* @param aValue Whether to set or remove attributes.
|
||||||
|
*/
|
||||||
|
_updateAttributes: function Page_updateAttributes(aValue) {
|
||||||
|
let nodes = document.querySelectorAll("#grid, #scrollbox, #toolbar, .toolbar-button");
|
||||||
|
|
||||||
|
// Set the nodes' states.
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
let node = nodes[i];
|
||||||
|
if (aValue)
|
||||||
|
node.removeAttribute("page-disabled");
|
||||||
|
else
|
||||||
|
node.setAttribute("page-disabled", "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateTabIndices(aValue, this._isModified());
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the page is modified.
|
||||||
|
* @return Whether the page is modified or not.
|
||||||
|
*/
|
||||||
|
_isModified: function Page_isModified() {
|
||||||
|
// The page is considered modified only if sites have been removed.
|
||||||
|
return !gBlockedLinks.isEmpty();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the tab indices of focusable elements.
|
||||||
|
* @param aEnabled Whether the page is currently enabled.
|
||||||
|
* @param aModified Whether the page is currently modified.
|
||||||
|
*/
|
||||||
|
_updateTabIndices: function Page_updateTabIndices(aEnabled, aModified) {
|
||||||
|
function setFocusable(aNode, aFocusable) {
|
||||||
|
if (aFocusable)
|
||||||
|
aNode.removeAttribute("tabindex");
|
||||||
|
else
|
||||||
|
aNode.setAttribute("tabindex", "-1");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sites and the 'hide' button are always focusable when the grid is shown.
|
||||||
|
let nodes = document.querySelectorAll(".site, #toolbar-button-hide");
|
||||||
|
for (let i = 0; i < nodes.length; i++)
|
||||||
|
setFocusable(nodes[i], aEnabled);
|
||||||
|
|
||||||
|
// The 'show' button is focusable when the grid is hidden.
|
||||||
|
let btnShow = document.getElementById("toolbar-button-show");
|
||||||
|
setFocusable(btnShow, !aEnabled);
|
||||||
|
|
||||||
|
// The 'reset' button is focusable when the grid is shown and modified.
|
||||||
|
let btnReset = document.getElementById("toolbar-button-reset");
|
||||||
|
setFocusable(btnReset, aEnabled && aModified);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'dragover' event. Workaround to prevent a delay on MacOSX
|
||||||
|
* due to a slow drop animation.
|
||||||
|
* @param aEvent The 'dragover' event.
|
||||||
|
*/
|
||||||
|
onDragOver: function Page_onDragOver(aEvent) {
|
||||||
|
if (gDrag.isValid(aEvent))
|
||||||
|
aEvent.preventDefault();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the 'drop' event. Workaround to prevent a delay on MacOSX due to
|
||||||
|
* a slow drop animation.
|
||||||
|
* @param aEvent The 'drop' event.
|
||||||
|
*/
|
||||||
|
onDrop: function Page_onDrop(aEvent) {
|
||||||
|
if (gDrag.isValid(aEvent)) {
|
||||||
|
aEvent.preventDefault();
|
||||||
|
aEvent.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,209 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a site that is contained in a cell and can be pinned,
|
||||||
|
* moved around or deleted.
|
||||||
|
*/
|
||||||
|
function Site(aNode, aLink) {
|
||||||
|
this._node = aNode;
|
||||||
|
this._node._newtabSite = this;
|
||||||
|
|
||||||
|
this._link = aLink;
|
||||||
|
|
||||||
|
this._render();
|
||||||
|
this._addEventHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
Site.prototype = {
|
||||||
|
/**
|
||||||
|
* The site's DOM node.
|
||||||
|
*/
|
||||||
|
get node() this._node,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The site's link.
|
||||||
|
*/
|
||||||
|
get link() this._link,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The url of the site's link.
|
||||||
|
*/
|
||||||
|
get url() this.link.url,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The title of the site's link.
|
||||||
|
*/
|
||||||
|
get title() this.link.title,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The site's parent cell.
|
||||||
|
*/
|
||||||
|
get cell() {
|
||||||
|
let parentNode = this.node.parentNode;
|
||||||
|
return parentNode && parentNode._newtabCell;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pins the site on its current or a given index.
|
||||||
|
* @param aIndex The pinned index (optional).
|
||||||
|
*/
|
||||||
|
pin: function Site_pin(aIndex) {
|
||||||
|
if (typeof aIndex == "undefined")
|
||||||
|
aIndex = this.cell.index;
|
||||||
|
|
||||||
|
this._updateAttributes(true);
|
||||||
|
gPinnedLinks.pin(this._link, aIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpins the site and calls the given callback when done.
|
||||||
|
* @param aCallback The callback to be called when finished.
|
||||||
|
*/
|
||||||
|
unpin: function Site_unpin(aCallback) {
|
||||||
|
if (this.isPinned()) {
|
||||||
|
this._updateAttributes(false);
|
||||||
|
gPinnedLinks.unpin(this._link);
|
||||||
|
gUpdater.updateGrid(aCallback);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this site is pinned.
|
||||||
|
* @return Whether this site is pinned.
|
||||||
|
*/
|
||||||
|
isPinned: function Site_isPinned() {
|
||||||
|
return gPinnedLinks.isPinned(this._link);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the site (removes it from the grid) and calls the given callback
|
||||||
|
* when done.
|
||||||
|
* @param aCallback The callback to be called when finished.
|
||||||
|
*/
|
||||||
|
block: function Site_block(aCallback) {
|
||||||
|
gBlockedLinks.block(this._link);
|
||||||
|
gUpdater.updateGrid(aCallback);
|
||||||
|
gPage.updateModifiedFlag();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the DOM node specified by the given query selector.
|
||||||
|
* @param aSelector The query selector.
|
||||||
|
* @return The DOM node we found.
|
||||||
|
*/
|
||||||
|
_querySelector: function Site_querySelector(aSelector) {
|
||||||
|
return this.node.querySelector(aSelector);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates attributes for all nodes which status depends on this site being
|
||||||
|
* pinned or unpinned.
|
||||||
|
* @param aPinned Whether this site is now pinned or unpinned.
|
||||||
|
*/
|
||||||
|
_updateAttributes: function (aPinned) {
|
||||||
|
let buttonPin = this._querySelector(".strip-button-pin");
|
||||||
|
|
||||||
|
if (aPinned) {
|
||||||
|
this.node.setAttribute("pinned", true);
|
||||||
|
buttonPin.setAttribute("title", newTabString("unpin"));
|
||||||
|
} else {
|
||||||
|
this.node.removeAttribute("pinned");
|
||||||
|
buttonPin.setAttribute("title", newTabString("pin"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the site's data (fills the HTML fragment).
|
||||||
|
*/
|
||||||
|
_render: function Site_render() {
|
||||||
|
let title = this.title || this.url;
|
||||||
|
this.node.setAttribute("title", title);
|
||||||
|
this.node.setAttribute("href", this.url);
|
||||||
|
this._querySelector(".site-title").textContent = title;
|
||||||
|
|
||||||
|
if (this.isPinned())
|
||||||
|
this._updateAttributes(true);
|
||||||
|
|
||||||
|
this._renderThumbnail();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the site's thumbnail.
|
||||||
|
*/
|
||||||
|
_renderThumbnail: function Site_renderThumbnail() {
|
||||||
|
let img = this._querySelector(".site-img")
|
||||||
|
img.setAttribute("alt", this.title || this.url);
|
||||||
|
img.setAttribute("loading", "true");
|
||||||
|
|
||||||
|
// Wait until the image has loaded.
|
||||||
|
img.addEventListener("load", function onLoad() {
|
||||||
|
img.removeEventListener("load", onLoad, false);
|
||||||
|
img.removeAttribute("loading");
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// Set the thumbnail url.
|
||||||
|
img.setAttribute("src", PageThumbs.getThumbnailURL(this.url));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event handlers for the site and its buttons.
|
||||||
|
*/
|
||||||
|
_addEventHandlers: function Site_addEventHandlers() {
|
||||||
|
// Register drag-and-drop event handlers.
|
||||||
|
["DragStart", /*"Drag",*/ "DragEnd"].forEach(function (aType) {
|
||||||
|
let method = "_on" + aType;
|
||||||
|
this[method] = this[method].bind(this);
|
||||||
|
this._node.addEventListener(aType.toLowerCase(), this[method], false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
function pin(aEvent) {
|
||||||
|
if (aEvent)
|
||||||
|
aEvent.preventDefault();
|
||||||
|
|
||||||
|
if (self.isPinned())
|
||||||
|
self.unpin();
|
||||||
|
else
|
||||||
|
self.pin();
|
||||||
|
}
|
||||||
|
|
||||||
|
function block(aEvent) {
|
||||||
|
if (aEvent)
|
||||||
|
aEvent.preventDefault();
|
||||||
|
|
||||||
|
self.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._querySelector(".strip-button-pin").addEventListener("click", pin, false);
|
||||||
|
this._querySelector(".strip-button-block").addEventListener("click", block, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'dragstart' event.
|
||||||
|
* @param aEvent The drag event.
|
||||||
|
*/
|
||||||
|
_onDragStart: function Site_onDragStart(aEvent) {
|
||||||
|
gDrag.start(this, aEvent);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'drag' event.
|
||||||
|
* @param aEvent The drag event.
|
||||||
|
*/
|
||||||
|
_onDrag: function Site_onDrag(aEvent) {
|
||||||
|
gDrag.drag(this, aEvent);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'dragend' event.
|
||||||
|
* @param aEvent The drag event.
|
||||||
|
*/
|
||||||
|
_onDragEnd: function Site_onDragEnd(aEvent) {
|
||||||
|
gDrag.end(this, aEvent);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton represents the page's toolbar that allows to enable/disable
|
||||||
|
* the 'New Tab Page' feature and to reset the whole page.
|
||||||
|
*/
|
||||||
|
let gToolbar = {
|
||||||
|
/**
|
||||||
|
* Initializes the toolbar.
|
||||||
|
* @param aSelector The query selector of the toolbar.
|
||||||
|
*/
|
||||||
|
init: function Toolbar_init(aSelector) {
|
||||||
|
this._node = document.querySelector(aSelector);
|
||||||
|
let buttons = this._node.querySelectorAll("input");
|
||||||
|
|
||||||
|
// Listen for 'click' events on the toolbar buttons.
|
||||||
|
["show", "hide", "reset"].forEach(function (aType, aIndex) {
|
||||||
|
let self = this;
|
||||||
|
let button = buttons[aIndex];
|
||||||
|
let handler = function () self[aType]();
|
||||||
|
|
||||||
|
button.addEventListener("click", handler, false);
|
||||||
|
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
// Per default buttons lose focus after being clicked on Mac OS X.
|
||||||
|
// So when the URL bar has focus and a toolbar button is clicked the
|
||||||
|
// URL bar regains focus and the history pops up. We need to prevent
|
||||||
|
// that by explicitly removing its focus.
|
||||||
|
button.addEventListener("mousedown", function () {
|
||||||
|
window.focus();
|
||||||
|
}, false);
|
||||||
|
#endif
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the 'New Tab Page' feature.
|
||||||
|
*/
|
||||||
|
show: function Toolbar_show() {
|
||||||
|
this._passButtonFocus("show", "hide");
|
||||||
|
gAllPages.enabled = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the 'New Tab Page' feature.
|
||||||
|
*/
|
||||||
|
hide: function Toolbar_hide() {
|
||||||
|
this._passButtonFocus("hide", "show");
|
||||||
|
gAllPages.enabled = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the whole page and forces it to re-render its content.
|
||||||
|
* @param aCallback The callback to call when the page has been reset.
|
||||||
|
*/
|
||||||
|
reset: function Toolbar_reset(aCallback) {
|
||||||
|
this._passButtonFocus("reset", "hide");
|
||||||
|
let node = gGrid.node;
|
||||||
|
|
||||||
|
// animate the page reset
|
||||||
|
gTransformation.fadeNodeOut(node, function () {
|
||||||
|
NewTabUtils.reset();
|
||||||
|
|
||||||
|
gLinks.populateCache(function () {
|
||||||
|
gAllPages.update();
|
||||||
|
|
||||||
|
// Without the setTimeout() we have a strange flicker.
|
||||||
|
setTimeout(function () gTransformation.fadeNodeIn(node, aCallback));
|
||||||
|
}, true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Passes the focus from the current button to the next.
|
||||||
|
* @param aCurrent The button that currently has focus.
|
||||||
|
* @param aNext The button that is focused next.
|
||||||
|
*/
|
||||||
|
_passButtonFocus: function Toolbar_passButtonFocus(aCurrent, aNext) {
|
||||||
|
if (document.querySelector("#toolbar-button-" + aCurrent + ":-moz-focusring"))
|
||||||
|
document.getElementById("toolbar-button-" + aNext).focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton allows to transform the grid by repositioning a site's node
|
||||||
|
* in the DOM and by showing or hiding the node. It additionally provides
|
||||||
|
* convenience methods to work with a site's DOM node.
|
||||||
|
*/
|
||||||
|
let gTransformation = {
|
||||||
|
/**
|
||||||
|
* Gets a DOM node's position.
|
||||||
|
* @param aNode The DOM node.
|
||||||
|
* @return A Rect instance with the position.
|
||||||
|
*/
|
||||||
|
getNodePosition: function Transformation_getNodePosition(aNode) {
|
||||||
|
let {left, top, width, height} = aNode.getBoundingClientRect();
|
||||||
|
return new Rect(left + scrollX, top + scrollY, width, height);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades a given node from zero to full opacity.
|
||||||
|
* @param aNode The node to fade.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
fadeNodeIn: function Transformation_fadeNodeIn(aNode, aCallback) {
|
||||||
|
this._setNodeOpacity(aNode, 1, function () {
|
||||||
|
// Clear the style property.
|
||||||
|
aNode.style.opacity = "";
|
||||||
|
|
||||||
|
if (aCallback)
|
||||||
|
aCallback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades a given node from full to zero opacity.
|
||||||
|
* @param aNode The node to fade.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
fadeNodeOut: function Transformation_fadeNodeOut(aNode, aCallback) {
|
||||||
|
this._setNodeOpacity(aNode, 0, aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades a given site from zero to full opacity.
|
||||||
|
* @param aSite The site to fade.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
showSite: function Transformation_showSite(aSite, aCallback) {
|
||||||
|
this.fadeNodeIn(aSite.node, aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades a given site from full to zero opacity.
|
||||||
|
* @param aSite The site to fade.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
hideSite: function Transformation_hideSite(aSite, aCallback) {
|
||||||
|
this.fadeNodeOut(aSite.node, aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to set a site's position.
|
||||||
|
* @param aSite The site to re-position.
|
||||||
|
* @param aPosition The desired position for the given site.
|
||||||
|
*/
|
||||||
|
setSitePosition: function Transformation_setSitePosition(aSite, aPosition) {
|
||||||
|
let style = aSite.node.style;
|
||||||
|
let {top, left} = aPosition;
|
||||||
|
|
||||||
|
style.top = top + "px";
|
||||||
|
style.left = left + "px";
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freezes a site in its current position by positioning it absolute.
|
||||||
|
* @param aSite The site to freeze.
|
||||||
|
*/
|
||||||
|
freezeSitePosition: function Transformation_freezeSitePosition(aSite) {
|
||||||
|
aSite.node.setAttribute("frozen", "true");
|
||||||
|
this.setSitePosition(aSite, this.getNodePosition(aSite.node));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unfreezes a site by removing its absolute positioning.
|
||||||
|
* @param aSite The site to unfreeze.
|
||||||
|
*/
|
||||||
|
unfreezeSitePosition: function Transformation_unfreezeSitePosition(aSite) {
|
||||||
|
let style = aSite.node.style;
|
||||||
|
style.left = style.top = "";
|
||||||
|
aSite.node.removeAttribute("frozen");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slides the given site to the target node's position.
|
||||||
|
* @param aSite The site to move.
|
||||||
|
* @param aTarget The slide target.
|
||||||
|
* @param aOptions Set of options (see below).
|
||||||
|
* unfreeze - unfreeze the site after sliding
|
||||||
|
* callback - the callback to call when finished
|
||||||
|
*/
|
||||||
|
slideSiteTo: function Transformation_slideSiteTo(aSite, aTarget, aOptions) {
|
||||||
|
let currentPosition = this.getNodePosition(aSite.node);
|
||||||
|
let targetPosition = this.getNodePosition(aTarget.node)
|
||||||
|
let callback = aOptions && aOptions.callback;
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
function finish() {
|
||||||
|
if (aOptions && aOptions.unfreeze)
|
||||||
|
self.unfreezeSitePosition(aSite);
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to do here if the positions already match.
|
||||||
|
if (currentPosition.equals(targetPosition)) {
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
this.setSitePosition(aSite, targetPosition);
|
||||||
|
this._whenTransitionEnded(aSite.node, finish);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rearranges a given array of sites and moves them to their new positions or
|
||||||
|
* fades in/out new/removed sites.
|
||||||
|
* @param aSites An array of sites to rearrange.
|
||||||
|
* @param aOptions Set of options (see below).
|
||||||
|
* unfreeze - unfreeze the site after rearranging
|
||||||
|
* callback - the callback to call when finished
|
||||||
|
*/
|
||||||
|
rearrangeSites: function Transformation_rearrangeSites(aSites, aOptions) {
|
||||||
|
let batch;
|
||||||
|
let cells = gGrid.cells;
|
||||||
|
let callback = aOptions && aOptions.callback;
|
||||||
|
let unfreeze = aOptions && aOptions.unfreeze;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
batch = new Batch(callback);
|
||||||
|
callback = function () batch.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
aSites.forEach(function (aSite, aIndex) {
|
||||||
|
// Do not re-arrange empty cells or the dragged site.
|
||||||
|
if (!aSite || aSite == gDrag.draggedSite)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (batch)
|
||||||
|
batch.push();
|
||||||
|
|
||||||
|
if (!cells[aIndex])
|
||||||
|
// The site disappeared from the grid, hide it.
|
||||||
|
this.hideSite(aSite, callback);
|
||||||
|
else if (this._getNodeOpacity(aSite.node) != 1)
|
||||||
|
// The site disappeared before but is now back, show it.
|
||||||
|
this.showSite(aSite, callback);
|
||||||
|
else
|
||||||
|
// The site's position has changed, move it around.
|
||||||
|
this._moveSite(aSite, aIndex, {unfreeze: unfreeze, callback: callback});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
if (batch)
|
||||||
|
batch.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for the 'transitionend' event on a given node and calls the given
|
||||||
|
* callback.
|
||||||
|
* @param aNode The node that is transitioned.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
_whenTransitionEnded:
|
||||||
|
function Transformation_whenTransitionEnded(aNode, aCallback) {
|
||||||
|
|
||||||
|
aNode.addEventListener("transitionend", function onEnd() {
|
||||||
|
aNode.removeEventListener("transitionend", onEnd, false);
|
||||||
|
aCallback();
|
||||||
|
}, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a given node's opacity value.
|
||||||
|
* @param aNode The node to get the opacity value from.
|
||||||
|
* @return The node's opacity value.
|
||||||
|
*/
|
||||||
|
_getNodeOpacity: function Transformation_getNodeOpacity(aNode) {
|
||||||
|
let cstyle = window.getComputedStyle(aNode, null);
|
||||||
|
return cstyle.getPropertyValue("opacity");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a given node's opacity.
|
||||||
|
* @param aNode The node to set the opacity value for.
|
||||||
|
* @param aOpacity The opacity value to set.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
_setNodeOpacity:
|
||||||
|
function Transformation_setNodeOpacity(aNode, aOpacity, aCallback) {
|
||||||
|
|
||||||
|
if (this._getNodeOpacity(aNode) == aOpacity) {
|
||||||
|
if (aCallback)
|
||||||
|
aCallback();
|
||||||
|
} else {
|
||||||
|
if (aCallback)
|
||||||
|
this._whenTransitionEnded(aNode, aCallback);
|
||||||
|
|
||||||
|
aNode.style.opacity = aOpacity;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a site to the cell with the given index.
|
||||||
|
* @param aSite The site to move.
|
||||||
|
* @param aIndex The target cell's index.
|
||||||
|
* @param aOptions Options that are directly passed to slideSiteTo().
|
||||||
|
*/
|
||||||
|
_moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) {
|
||||||
|
this.freezeSitePosition(aSite);
|
||||||
|
this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,182 @@
|
||||||
|
#ifdef 0
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This singleton provides functionality to update the current grid to a new
|
||||||
|
* set of pinned and blocked sites. It adds, moves and removes sites.
|
||||||
|
*/
|
||||||
|
let gUpdater = {
|
||||||
|
/**
|
||||||
|
* Updates the current grid according to its pinned and blocked sites.
|
||||||
|
* This removes old, moves existing and creates new sites to fill gaps.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
updateGrid: function Updater_updateGrid(aCallback) {
|
||||||
|
let links = gLinks.getLinks().slice(0, gGrid.cells.length);
|
||||||
|
|
||||||
|
// Find all sites that remain in the grid.
|
||||||
|
let sites = this._findRemainingSites(links);
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
// Remove sites that are no longer in the grid.
|
||||||
|
this._removeLegacySites(sites, function () {
|
||||||
|
// Freeze all site positions so that we can move their DOM nodes around
|
||||||
|
// without any visual impact.
|
||||||
|
self._freezeSitePositions(sites);
|
||||||
|
|
||||||
|
// Move the sites' DOM nodes to their new position in the DOM. This will
|
||||||
|
// have no visual effect as all the sites have been frozen and will
|
||||||
|
// remain in their current position.
|
||||||
|
self._moveSiteNodes(sites);
|
||||||
|
|
||||||
|
// Now it's time to animate the sites actually moving to their new
|
||||||
|
// positions.
|
||||||
|
self._rearrangeSites(sites, function () {
|
||||||
|
// Try to fill empty cells and finish.
|
||||||
|
self._fillEmptyCells(links, aCallback);
|
||||||
|
|
||||||
|
// Update other pages that might be open to keep them synced.
|
||||||
|
gAllPages.update(gPage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an array of links and tries to correlate them to sites contained in
|
||||||
|
* the current grid. If no corresponding site can be found (i.e. the link is
|
||||||
|
* new and a site will be created) then just set it to null.
|
||||||
|
* @param aLinks The array of links to find sites for.
|
||||||
|
* @return Array of sites mapped to the given links (can contain null values).
|
||||||
|
*/
|
||||||
|
_findRemainingSites: function Updater_findRemainingSites(aLinks) {
|
||||||
|
let map = {};
|
||||||
|
|
||||||
|
// Create a map to easily retrieve the site for a given URL.
|
||||||
|
gGrid.sites.forEach(function (aSite) {
|
||||||
|
if (aSite)
|
||||||
|
map[aSite.url] = aSite;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Map each link to its corresponding site, if any.
|
||||||
|
return aLinks.map(function (aLink) {
|
||||||
|
return aLink && (aLink.url in map) && map[aLink.url];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freezes the given sites' positions.
|
||||||
|
* @param aSites The array of sites to freeze.
|
||||||
|
*/
|
||||||
|
_freezeSitePositions: function Updater_freezeSitePositions(aSites) {
|
||||||
|
aSites.forEach(function (aSite) {
|
||||||
|
if (aSite)
|
||||||
|
gTransformation.freezeSitePosition(aSite);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the given sites' DOM nodes to their new positions.
|
||||||
|
* @param aSites The array of sites to move.
|
||||||
|
*/
|
||||||
|
_moveSiteNodes: function Updater_moveSiteNodes(aSites) {
|
||||||
|
let cells = gGrid.cells;
|
||||||
|
|
||||||
|
// Truncate the given array of sites to not have more sites than cells.
|
||||||
|
// This can happen when the user drags a bookmark (or any other new kind
|
||||||
|
// of link) onto the grid.
|
||||||
|
let sites = aSites.slice(0, cells.length);
|
||||||
|
|
||||||
|
sites.forEach(function (aSite, aIndex) {
|
||||||
|
let cell = cells[aIndex];
|
||||||
|
let cellSite = cell.site;
|
||||||
|
|
||||||
|
// The site's position didn't change.
|
||||||
|
if (!aSite || cellSite != aSite) {
|
||||||
|
let cellNode = cell.node;
|
||||||
|
|
||||||
|
// Empty the cell if necessary.
|
||||||
|
if (cellSite)
|
||||||
|
cellNode.removeChild(cellSite.node);
|
||||||
|
|
||||||
|
// Put the new site in place, if any.
|
||||||
|
if (aSite)
|
||||||
|
cellNode.appendChild(aSite.node);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rearranges the given sites and slides them to their new positions.
|
||||||
|
* @param aSites The array of sites to re-arrange.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
_rearrangeSites: function Updater_rearrangeSites(aSites, aCallback) {
|
||||||
|
let options = {callback: aCallback, unfreeze: true};
|
||||||
|
gTransformation.rearrangeSites(aSites, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all sites from the grid that are not in the given links array or
|
||||||
|
* exceed the grid.
|
||||||
|
* @param aSites The array of sites remaining in the grid.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
_removeLegacySites: function Updater_removeLegacySites(aSites, aCallback) {
|
||||||
|
let batch = new Batch(aCallback);
|
||||||
|
|
||||||
|
// Delete sites that were removed from the grid.
|
||||||
|
gGrid.sites.forEach(function (aSite) {
|
||||||
|
// The site must be valid and not in the current grid.
|
||||||
|
if (!aSite || aSites.indexOf(aSite) != -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
batch.push();
|
||||||
|
|
||||||
|
// Fade out the to-be-removed site.
|
||||||
|
gTransformation.hideSite(aSite, function () {
|
||||||
|
let node = aSite.node;
|
||||||
|
|
||||||
|
// Remove the site from the DOM.
|
||||||
|
node.parentNode.removeChild(node);
|
||||||
|
batch.pop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
batch.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to fill empty cells with new links if available.
|
||||||
|
* @param aLinks The array of links.
|
||||||
|
* @param aCallback The callback to call when finished.
|
||||||
|
*/
|
||||||
|
_fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) {
|
||||||
|
let {cells, sites} = gGrid;
|
||||||
|
let batch = new Batch(aCallback);
|
||||||
|
|
||||||
|
// Find empty cells and fill them.
|
||||||
|
sites.forEach(function (aSite, aIndex) {
|
||||||
|
if (aSite || !aLinks[aIndex])
|
||||||
|
return;
|
||||||
|
|
||||||
|
batch.push();
|
||||||
|
|
||||||
|
// Create the new site and fade it in.
|
||||||
|
let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]);
|
||||||
|
|
||||||
|
// Set the site's initial opacity to zero.
|
||||||
|
site.node.style.opacity = 0;
|
||||||
|
|
||||||
|
// Without the setTimeout() the node would just appear instead of fade in.
|
||||||
|
setTimeout(function () {
|
||||||
|
gTransformation.showSite(site, function () batch.pop());
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
batch.close();
|
||||||
|
}
|
||||||
|
};
|
|
@ -69,7 +69,7 @@
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
<textbox id="dialog.input" flex="1" type="autocomplete"
|
<textbox id="dialog.input" flex="1" type="autocomplete"
|
||||||
completeselectedindex="true"
|
completeselectedindex="true"
|
||||||
autocompletesearch="history"
|
autocompletesearch="urlinline history"
|
||||||
enablehistory="true"
|
enablehistory="true"
|
||||||
class="uri-element"
|
class="uri-element"
|
||||||
oninput="doEnabling();"/>
|
oninput="doEnabling();"/>
|
||||||
|
|
|
@ -42,17 +42,18 @@
|
||||||
# ***** END LICENSE BLOCK *****
|
# ***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
//******** define a js object to implement nsITreeView
|
//******** define a js object to implement nsITreeView
|
||||||
function pageInfoTreeView(copycol)
|
function pageInfoTreeView(treeid, copycol)
|
||||||
{
|
{
|
||||||
// copycol is the index number for the column that we want to add to
|
// copycol is the index number for the column that we want to add to
|
||||||
// the copy-n-paste buffer when the user hits accel-c
|
// the copy-n-paste buffer when the user hits accel-c
|
||||||
|
this.treeid = treeid;
|
||||||
this.copycol = copycol;
|
this.copycol = copycol;
|
||||||
this.rows = 0;
|
this.rows = 0;
|
||||||
this.tree = null;
|
this.tree = null;
|
||||||
this.data = [ ];
|
this.data = [ ];
|
||||||
this.selection = null;
|
this.selection = null;
|
||||||
this.sortcol = null;
|
this.sortcol = -1;
|
||||||
this.sortdir = 0;
|
this.sortdir = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInfoTreeView.prototype = {
|
pageInfoTreeView.prototype = {
|
||||||
|
@ -121,6 +122,25 @@ pageInfoTreeView.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onPageMediaSort : function(columnname)
|
||||||
|
{
|
||||||
|
var tree = document.getElementById(this.treeid);
|
||||||
|
var treecol = tree.columns.getNamedColumn(columnname);
|
||||||
|
|
||||||
|
this.sortdir =
|
||||||
|
gTreeUtils.sort(
|
||||||
|
tree,
|
||||||
|
this,
|
||||||
|
this.data,
|
||||||
|
treecol.index,
|
||||||
|
function textComparator(a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); },
|
||||||
|
this.sortcol,
|
||||||
|
this.sortdir
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sortcol = treecol.index;
|
||||||
|
},
|
||||||
|
|
||||||
getRowProperties: function(row, prop) { },
|
getRowProperties: function(row, prop) { },
|
||||||
getCellProperties: function(row, column, prop) { },
|
getCellProperties: function(row, column, prop) { },
|
||||||
getColumnProperties: function(column, prop) { },
|
getColumnProperties: function(column, prop) { },
|
||||||
|
@ -166,9 +186,8 @@ const COPYCOL_META_CONTENT = 1;
|
||||||
const COPYCOL_IMAGE = COL_IMAGE_ADDRESS;
|
const COPYCOL_IMAGE = COL_IMAGE_ADDRESS;
|
||||||
|
|
||||||
// one nsITreeView for each tree in the window
|
// one nsITreeView for each tree in the window
|
||||||
var gMetaView = new pageInfoTreeView(COPYCOL_META_CONTENT);
|
var gMetaView = new pageInfoTreeView('metatree', COPYCOL_META_CONTENT);
|
||||||
var gImageView = new pageInfoTreeView(COPYCOL_IMAGE);
|
var gImageView = new pageInfoTreeView('imagetree', COPYCOL_IMAGE);
|
||||||
|
|
||||||
|
|
||||||
var atomSvc = Components.classes["@mozilla.org/atom-service;1"]
|
var atomSvc = Components.classes["@mozilla.org/atom-service;1"]
|
||||||
.getService(Components.interfaces.nsIAtomService);
|
.getService(Components.interfaces.nsIAtomService);
|
||||||
|
@ -187,6 +206,44 @@ gImageView.getCellProperties = function(row, col, props) {
|
||||||
props.AppendElement(this._ltrAtom);
|
props.AppendElement(this._ltrAtom);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
gImageView.getCellText = function(row, column) {
|
||||||
|
var value = this.data[row][column.index];
|
||||||
|
if (column.index == COL_IMAGE_SIZE) {
|
||||||
|
if (value == -1) {
|
||||||
|
return gStrings.unknown;
|
||||||
|
} else {
|
||||||
|
var kbSize = Number(Math.round(value / 1024 * 100) / 100);
|
||||||
|
return gBundle.getFormattedString("mediaFileSize", [kbSize]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value || "";
|
||||||
|
};
|
||||||
|
|
||||||
|
gImageView.onPageMediaSort = function(columnname) {
|
||||||
|
var tree = document.getElementById(this.treeid);
|
||||||
|
var treecol = tree.columns.getNamedColumn(columnname);
|
||||||
|
|
||||||
|
var comparator;
|
||||||
|
if (treecol.index == COL_IMAGE_SIZE) {
|
||||||
|
comparator = function numComparator(a, b) { return a - b; };
|
||||||
|
} else {
|
||||||
|
comparator = function textComparator(a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); };
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sortdir =
|
||||||
|
gTreeUtils.sort(
|
||||||
|
tree,
|
||||||
|
this,
|
||||||
|
this.data,
|
||||||
|
treecol.index,
|
||||||
|
comparator,
|
||||||
|
this.sortcol,
|
||||||
|
this.sortdir
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sortcol = treecol.index;
|
||||||
|
};
|
||||||
|
|
||||||
var gImageHash = { };
|
var gImageHash = { };
|
||||||
|
|
||||||
// localized strings (will be filled in when the document is loaded)
|
// localized strings (will be filled in when the document is loaded)
|
||||||
|
@ -585,15 +642,8 @@ function addImage(url, type, alt, elem, isBg)
|
||||||
catch(ex2) { }
|
catch(ex2) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
var sizeText;
|
var dataSize = (cacheEntryDescriptor) ? cacheEntryDescriptor.dataSize : -1;
|
||||||
if (cacheEntryDescriptor) {
|
gImageView.addRow([url, type, dataSize, alt, 1, elem, isBg]);
|
||||||
var pageSize = cacheEntryDescriptor.dataSize;
|
|
||||||
var kbSize = formatNumber(Math.round(pageSize / 1024 * 100) / 100);
|
|
||||||
sizeText = gBundle.getFormattedString("mediaFileSize", [kbSize]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sizeText = gStrings.unknown;
|
|
||||||
gImageView.addRow([url, type, sizeText, alt, 1, elem, isBg]);
|
|
||||||
|
|
||||||
// Add the observer, only once.
|
// Add the observer, only once.
|
||||||
if (gImageView.data.length == 1) {
|
if (gImageView.data.length == 1) {
|
||||||
|
@ -700,7 +750,10 @@ function getSelectedImage(tree)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Only works if only one item is selected
|
// Only works if only one item is selected
|
||||||
var clickedRow = tree.currentIndex;
|
var clickedRow = tree.view.selection.currentIndex;
|
||||||
|
if (clickedRow == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
// image-node
|
// image-node
|
||||||
return gImageView.data[clickedRow][COL_IMAGE_NODE];
|
return gImageView.data[clickedRow][COL_IMAGE_NODE];
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
|
|
||||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||||
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
|
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
|
||||||
|
<script type="application/javascript" src="chrome://global/content/treeUtils.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/pageinfo/pageInfo.js"/>
|
<script type="application/javascript" src="chrome://browser/content/pageinfo/pageInfo.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/pageinfo/feeds.js"/>
|
<script type="application/javascript" src="chrome://browser/content/pageinfo/feeds.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/pageinfo/permissions.js"/>
|
<script type="application/javascript" src="chrome://browser/content/pageinfo/permissions.js"/>
|
||||||
|
@ -192,10 +193,12 @@
|
||||||
<tree id="metatree" flex="1" hidecolumnpicker="true" contextmenu="picontext">
|
<tree id="metatree" flex="1" hidecolumnpicker="true" contextmenu="picontext">
|
||||||
<treecols>
|
<treecols>
|
||||||
<treecol id="meta-name" label="&generalMetaName;"
|
<treecol id="meta-name" label="&generalMetaName;"
|
||||||
persist="width" flex="1"/>
|
persist="width" flex="1"
|
||||||
|
onclick="gMetaView.onPageMediaSort('meta-name');"/>
|
||||||
<splitter class="tree-splitter"/>
|
<splitter class="tree-splitter"/>
|
||||||
<treecol id="meta-content" label="&generalMetaContent;"
|
<treecol id="meta-content" label="&generalMetaContent;"
|
||||||
persist="width" flex="4"/>
|
persist="width" flex="4"
|
||||||
|
onclick="gMetaView.onPageMediaSort('meta-content');"/>
|
||||||
</treecols>
|
</treecols>
|
||||||
<treechildren flex="1"/>
|
<treechildren flex="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
@ -218,19 +221,24 @@
|
||||||
ondragstart="onBeginLinkDrag(event,'image-address','image-alt')">
|
ondragstart="onBeginLinkDrag(event,'image-address','image-alt')">
|
||||||
<treecols>
|
<treecols>
|
||||||
<treecol sortSeparators="true" primary="true" persist="width" flex="10"
|
<treecol sortSeparators="true" primary="true" persist="width" flex="10"
|
||||||
width="10" id="image-address" label="&mediaAddress;"/>
|
width="10" id="image-address" label="&mediaAddress;"
|
||||||
|
onclick="gImageView.onPageMediaSort('image-address');"/>
|
||||||
<splitter class="tree-splitter"/>
|
<splitter class="tree-splitter"/>
|
||||||
<treecol sortSeparators="true" persist="hidden width" flex="2"
|
<treecol sortSeparators="true" persist="hidden width" flex="2"
|
||||||
width="2" id="image-type" label="&mediaType;"/>
|
width="2" id="image-type" label="&mediaType;"
|
||||||
|
onclick="gImageView.onPageMediaSort('image-type');"/>
|
||||||
<splitter class="tree-splitter"/>
|
<splitter class="tree-splitter"/>
|
||||||
<treecol sortSeparators="true" hidden="true" persist="hidden width" flex="2"
|
<treecol sortSeparators="true" hidden="true" persist="hidden width" flex="2"
|
||||||
width="2" id="image-size" label="&mediaSize;"/>
|
width="2" id="image-size" label="&mediaSize;" value="size"
|
||||||
|
onclick="gImageView.onPageMediaSort('image-size');"/>
|
||||||
<splitter class="tree-splitter"/>
|
<splitter class="tree-splitter"/>
|
||||||
<treecol sortSeparators="true" hidden="true" persist="hidden width" flex="4"
|
<treecol sortSeparators="true" hidden="true" persist="hidden width" flex="4"
|
||||||
width="4" id="image-alt" label="&mediaAltHeader;"/>
|
width="4" id="image-alt" label="&mediaAltHeader;"
|
||||||
|
onclick="gImageView.onPageMediaSort('image-alt');"/>
|
||||||
<splitter class="tree-splitter"/>
|
<splitter class="tree-splitter"/>
|
||||||
<treecol sortSeparators="true" hidden="true" persist="hidden width" flex="1"
|
<treecol sortSeparators="true" hidden="true" persist="hidden width" flex="1"
|
||||||
width="1" id="image-count" label="&mediaCount;"/>
|
width="1" id="image-count" label="&mediaCount;"
|
||||||
|
onclick="gImageView.onPageMediaSort('image-count');"/>
|
||||||
</treecols>
|
</treecols>
|
||||||
<treechildren flex="1"/>
|
<treechildren flex="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
|
|
@ -260,23 +260,24 @@
|
||||||
value="&addDevice.showMeHow.label;"
|
value="&addDevice.showMeHow.label;"
|
||||||
href="https://services.mozilla.com/sync/help/easy-setup"/>
|
href="https://services.mozilla.com/sync/help/easy-setup"/>
|
||||||
</description>
|
</description>
|
||||||
<description>&addDevice.setup.enterCode.label;</description>
|
<label value="&addDevice.setup.enterCode.label;"
|
||||||
|
control="easySetupPIN1"/>
|
||||||
<spacer flex="1"/>
|
<spacer flex="1"/>
|
||||||
<vbox align="center" flex="1">
|
<vbox align="center" flex="1">
|
||||||
<textbox id="easySetupPIN1"
|
<textbox id="easySetupPIN1"
|
||||||
class="pin"
|
class="pin"
|
||||||
value=""
|
value=""
|
||||||
disabled="true"
|
readonly="true"
|
||||||
/>
|
/>
|
||||||
<textbox id="easySetupPIN2"
|
<textbox id="easySetupPIN2"
|
||||||
class="pin"
|
class="pin"
|
||||||
value=""
|
value=""
|
||||||
disabled="true"
|
readonly="true"
|
||||||
/>
|
/>
|
||||||
<textbox id="easySetupPIN3"
|
<textbox id="easySetupPIN3"
|
||||||
class="pin"
|
class="pin"
|
||||||
value=""
|
value=""
|
||||||
disabled="true"
|
readonly="true"
|
||||||
/>
|
/>
|
||||||
</vbox>
|
</vbox>
|
||||||
<spacer flex="3"/>
|
<spacer flex="3"/>
|
||||||
|
|
|
@ -632,7 +632,7 @@
|
||||||
autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
|
autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
|
||||||
delete this.mBrowser.registeredOpenURI;
|
delete this.mBrowser.registeredOpenURI;
|
||||||
}
|
}
|
||||||
if (aLocation.spec != "about:blank") {
|
if (!isBlankPageURL(aLocation.spec)) {
|
||||||
autocomplete.registerOpenPage(aLocation);
|
autocomplete.registerOpenPage(aLocation);
|
||||||
this.mBrowser.registeredOpenURI = aLocation;
|
this.mBrowser.registeredOpenURI = aLocation;
|
||||||
}
|
}
|
||||||
|
@ -1065,7 +1065,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title && title != "about:blank") {
|
if (title && !isBlankPageURL(title)) {
|
||||||
// At this point, we now have a URI.
|
// At this point, we now have a URI.
|
||||||
// Let's try to unescape it using a character set
|
// Let's try to unescape it using a character set
|
||||||
// in case the URI is not ASCII.
|
// in case the URI is not ASCII.
|
||||||
|
@ -1589,7 +1589,7 @@
|
||||||
aTab.closing = true;
|
aTab.closing = true;
|
||||||
this._removingTabs.push(aTab);
|
this._removingTabs.push(aTab);
|
||||||
if (newTab)
|
if (newTab)
|
||||||
this.addTab("about:blank", {skipAnimation: true});
|
this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
|
||||||
else
|
else
|
||||||
this.tabContainer.updateVisibility();
|
this.tabContainer.updateVisibility();
|
||||||
|
|
||||||
|
@ -2375,10 +2375,6 @@
|
||||||
onget="return this.mCurrentBrowser.contentViewerFile;"
|
onget="return this.mCurrentBrowser.contentViewerFile;"
|
||||||
readonly="true"/>
|
readonly="true"/>
|
||||||
|
|
||||||
<property name="documentCharsetInfo"
|
|
||||||
onget="return this.mCurrentBrowser.documentCharsetInfo;"
|
|
||||||
readonly="true"/>
|
|
||||||
|
|
||||||
<property name="contentDocument"
|
<property name="contentDocument"
|
||||||
onget="return this.mCurrentBrowser.contentDocument;"
|
onget="return this.mCurrentBrowser.contentDocument;"
|
||||||
readonly="true"/>
|
readonly="true"/>
|
||||||
|
@ -3811,49 +3807,34 @@
|
||||||
<binding id="tabbrowser-alltabs-popup"
|
<binding id="tabbrowser-alltabs-popup"
|
||||||
extends="chrome://global/content/bindings/popup.xml#popup">
|
extends="chrome://global/content/bindings/popup.xml#popup">
|
||||||
<implementation implements="nsIDOMEventListener">
|
<implementation implements="nsIDOMEventListener">
|
||||||
<method name="_menuItemOnCommand">
|
|
||||||
<parameter name="aEvent"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
gBrowser.selectedTab = aEvent.target.tab;
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_tabOnAttrModified">
|
<method name="_tabOnAttrModified">
|
||||||
<parameter name="aEvent"/>
|
<parameter name="aEvent"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
var tab = aEvent.target;
|
var tab = aEvent.target;
|
||||||
this._setMenuitemAttributes(tab.mCorrespondingMenuitem, tab);
|
if (tab.mCorrespondingMenuitem)
|
||||||
|
this._setMenuitemAttributes(tab.mCorrespondingMenuitem, tab);
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="_tabOnTabClose">
|
<method name="_tabOnTabClose">
|
||||||
<parameter name="aEvent"/>
|
<parameter name="aEvent"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
var menuItem = aEvent.target.mCorrespondingMenuitem;
|
var tab = aEvent.target;
|
||||||
if (menuItem)
|
if (tab.mCorrespondingMenuitem)
|
||||||
this.removeChild(menuItem);
|
this.removeChild(tab.mCorrespondingMenuitem);
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="handleEvent">
|
<method name="handleEvent">
|
||||||
<parameter name="aEvent"/>
|
<parameter name="aEvent"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
if (!aEvent.isTrusted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (aEvent.type) {
|
switch (aEvent.type) {
|
||||||
case "command":
|
|
||||||
this._menuItemOnCommand(aEvent);
|
|
||||||
break;
|
|
||||||
case "TabAttrModified":
|
case "TabAttrModified":
|
||||||
this._tabOnAttrModified(aEvent);
|
this._tabOnAttrModified(aEvent);
|
||||||
break;
|
break;
|
||||||
case "TabClose":
|
case "TabClose":
|
||||||
this._tabOnTabClose(aEvent);
|
this._tabOnTabClose(aEvent);
|
||||||
break;
|
break;
|
||||||
case "TabOpen":
|
|
||||||
this._createTabMenuItem(aEvent.originalTarget);
|
|
||||||
break;
|
|
||||||
case "scroll":
|
case "scroll":
|
||||||
this._updateTabsVisibilityStatus();
|
this._updateTabsVisibilityStatus();
|
||||||
break;
|
break;
|
||||||
|
@ -3874,8 +3855,6 @@
|
||||||
if (!curTab) // "Tab Groups" menuitem and its menuseparator
|
if (!curTab) // "Tab Groups" menuitem and its menuseparator
|
||||||
continue;
|
continue;
|
||||||
let curTabBO = curTab.boxObject;
|
let curTabBO = curTab.boxObject;
|
||||||
if (!curTabBO) // "Tabs From Other Computers" menuitem
|
|
||||||
continue;
|
|
||||||
if (curTabBO.screenX >= tabstripBO.screenX &&
|
if (curTabBO.screenX >= tabstripBO.screenX &&
|
||||||
curTabBO.screenX + curTabBO.width <= tabstripBO.screenX + tabstripBO.width)
|
curTabBO.screenX + curTabBO.width <= tabstripBO.screenX + tabstripBO.width)
|
||||||
this.childNodes[i].setAttribute("tabIsVisible", "true");
|
this.childNodes[i].setAttribute("tabIsVisible", "true");
|
||||||
|
@ -3896,14 +3875,10 @@
|
||||||
|
|
||||||
this._setMenuitemAttributes(menuItem, aTab);
|
this._setMenuitemAttributes(menuItem, aTab);
|
||||||
|
|
||||||
// Keep some attributes of the menuitem in sync with its
|
|
||||||
// corresponding tab (e.g. the tab label)
|
|
||||||
aTab.mCorrespondingMenuitem = menuItem;
|
aTab.mCorrespondingMenuitem = menuItem;
|
||||||
menuItem.tab = aTab;
|
menuItem.tab = aTab;
|
||||||
menuItem.addEventListener("command", this, false);
|
|
||||||
|
|
||||||
this.appendChild(menuItem);
|
this.appendChild(menuItem);
|
||||||
return menuItem;
|
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
@ -3938,18 +3913,17 @@
|
||||||
<handlers>
|
<handlers>
|
||||||
<handler event="popupshowing">
|
<handler event="popupshowing">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
// set up the menu popup
|
|
||||||
var tabcontainer = gBrowser.tabContainer;
|
var tabcontainer = gBrowser.tabContainer;
|
||||||
let tabs = gBrowser.visibleTabs;
|
|
||||||
|
|
||||||
// Listen for changes in the tab bar.
|
// Listen for changes in the tab bar.
|
||||||
tabcontainer.addEventListener("TabOpen", this, false);
|
|
||||||
tabcontainer.addEventListener("TabAttrModified", this, false);
|
tabcontainer.addEventListener("TabAttrModified", this, false);
|
||||||
tabcontainer.addEventListener("TabClose", this, false);
|
tabcontainer.addEventListener("TabClose", this, false);
|
||||||
tabcontainer.mTabstrip.addEventListener("scroll", this, false);
|
tabcontainer.mTabstrip.addEventListener("scroll", this, false);
|
||||||
|
|
||||||
|
let tabs = gBrowser.visibleTabs;
|
||||||
for (var i = 0; i < tabs.length; i++) {
|
for (var i = 0; i < tabs.length; i++) {
|
||||||
this._createTabMenuItem(tabs[i]);
|
if (!tabs[i].pinned)
|
||||||
|
this._createTabMenuItem(tabs[i]);
|
||||||
}
|
}
|
||||||
this._updateTabsVisibilityStatus();
|
this._updateTabsVisibilityStatus();
|
||||||
]]></handler>
|
]]></handler>
|
||||||
|
@ -3960,14 +3934,12 @@
|
||||||
for (let i = this.childNodes.length - 1; i > 0; i--) {
|
for (let i = this.childNodes.length - 1; i > 0; i--) {
|
||||||
let menuItem = this.childNodes[i];
|
let menuItem = this.childNodes[i];
|
||||||
if (menuItem.tab) {
|
if (menuItem.tab) {
|
||||||
menuItem.removeEventListener("command", this, false);
|
|
||||||
menuItem.tab.mCorrespondingMenuitem = null;
|
menuItem.tab.mCorrespondingMenuitem = null;
|
||||||
this.removeChild(menuItem);
|
this.removeChild(menuItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var tabcontainer = gBrowser.tabContainer;
|
var tabcontainer = gBrowser.tabContainer;
|
||||||
tabcontainer.mTabstrip.removeEventListener("scroll", this, false);
|
tabcontainer.mTabstrip.removeEventListener("scroll", this, false);
|
||||||
tabcontainer.removeEventListener("TabOpen", this, false);
|
|
||||||
tabcontainer.removeEventListener("TabAttrModified", this, false);
|
tabcontainer.removeEventListener("TabAttrModified", this, false);
|
||||||
tabcontainer.removeEventListener("TabClose", this, false);
|
tabcontainer.removeEventListener("TabClose", this, false);
|
||||||
]]></handler>
|
]]></handler>
|
||||||
|
@ -3988,6 +3960,11 @@
|
||||||
XULBrowserWindow.setOverLink("", null);
|
XULBrowserWindow.setOverLink("", null);
|
||||||
]]></handler>
|
]]></handler>
|
||||||
|
|
||||||
|
<handler event="command"><![CDATA[
|
||||||
|
if (event.target.tab)
|
||||||
|
gBrowser.selectedTab = event.target.tab;
|
||||||
|
]]></handler>
|
||||||
|
|
||||||
</handlers>
|
</handlers>
|
||||||
</binding>
|
</binding>
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,10 @@ srcdir = @srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
relativesrcdir = browser/base/content/test
|
relativesrcdir = browser/base/content/test
|
||||||
|
|
||||||
|
DIRS += \
|
||||||
|
newtab \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
|
@ -83,7 +87,7 @@ endif
|
||||||
# browser_sanitize-download-history.js is bug 432425
|
# browser_sanitize-download-history.js is bug 432425
|
||||||
#
|
#
|
||||||
# browser_sanitizeDialog_treeView.js is disabled until the tree view is added
|
# browser_sanitizeDialog_treeView.js is disabled until the tree view is added
|
||||||
# back to the clear recent history dialog (santize.xul), if it ever is (bug
|
# back to the clear recent history dialog (sanitize.xul), if it ever is (bug
|
||||||
# 480169)
|
# 480169)
|
||||||
|
|
||||||
# browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
|
# browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
|
||||||
|
@ -91,6 +95,7 @@ endif
|
||||||
# browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
|
# browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
|
||||||
|
|
||||||
_BROWSER_FILES = \
|
_BROWSER_FILES = \
|
||||||
|
head.js \
|
||||||
browser_typeAheadFind.js \
|
browser_typeAheadFind.js \
|
||||||
browser_keywordSearch.js \
|
browser_keywordSearch.js \
|
||||||
browser_allTabsPanel.js \
|
browser_allTabsPanel.js \
|
||||||
|
@ -145,6 +150,7 @@ _BROWSER_FILES = \
|
||||||
browser_bug567306.js \
|
browser_bug567306.js \
|
||||||
browser_zbug569342.js \
|
browser_zbug569342.js \
|
||||||
browser_bug575561.js \
|
browser_bug575561.js \
|
||||||
|
browser_bug575830.js \
|
||||||
browser_bug577121.js \
|
browser_bug577121.js \
|
||||||
browser_bug578534.js \
|
browser_bug578534.js \
|
||||||
browser_bug579872.js \
|
browser_bug579872.js \
|
||||||
|
@ -172,6 +178,7 @@ _BROWSER_FILES = \
|
||||||
browser_bug655584.js \
|
browser_bug655584.js \
|
||||||
browser_bug664672.js \
|
browser_bug664672.js \
|
||||||
browser_bug710878.js \
|
browser_bug710878.js \
|
||||||
|
browser_bug719271.js \
|
||||||
browser_canonizeURL.js \
|
browser_canonizeURL.js \
|
||||||
browser_findbarClose.js \
|
browser_findbarClose.js \
|
||||||
browser_keywordBookmarklets.js \
|
browser_keywordBookmarklets.js \
|
||||||
|
@ -213,6 +220,7 @@ _BROWSER_FILES = \
|
||||||
browser_tabfocus.js \
|
browser_tabfocus.js \
|
||||||
browser_tabs_isActive.js \
|
browser_tabs_isActive.js \
|
||||||
browser_tabs_owner.js \
|
browser_tabs_owner.js \
|
||||||
|
browser_urlbarAutoFillTrimURLs.js \
|
||||||
browser_urlbarCopying.js \
|
browser_urlbarCopying.js \
|
||||||
browser_urlbarEnter.js \
|
browser_urlbarEnter.js \
|
||||||
browser_urlbarTrimURLs.js \
|
browser_urlbarTrimURLs.js \
|
||||||
|
@ -228,6 +236,7 @@ _BROWSER_FILES = \
|
||||||
discovery.html \
|
discovery.html \
|
||||||
domplate_test.js \
|
domplate_test.js \
|
||||||
moz.png \
|
moz.png \
|
||||||
|
video.ogg \
|
||||||
test_bug435035.html \
|
test_bug435035.html \
|
||||||
test_bug462673.html \
|
test_bug462673.html \
|
||||||
page_style_sample.html \
|
page_style_sample.html \
|
||||||
|
|
|
@ -11,16 +11,16 @@ function test () {
|
||||||
is(tooltip.getAttribute("label"), "This is a non-root SVG element title");
|
is(tooltip.getAttribute("label"), "This is a non-root SVG element title");
|
||||||
|
|
||||||
ok(FillInHTMLTooltip(doc.getElementById("text1"), "should get title"));
|
ok(FillInHTMLTooltip(doc.getElementById("text1"), "should get title"));
|
||||||
is(tooltip.getAttribute("label"), " This is a title ");
|
is(tooltip.getAttribute("label"), "\n\n\n This is a title\n\n ");
|
||||||
|
|
||||||
ok(!FillInHTMLTooltip(doc.getElementById("text2"), "should not get title"));
|
ok(!FillInHTMLTooltip(doc.getElementById("text2"), "should not get title"));
|
||||||
|
|
||||||
ok(!FillInHTMLTooltip(doc.getElementById("text3"), "should not get title"));
|
ok(!FillInHTMLTooltip(doc.getElementById("text3"), "should not get title"));
|
||||||
|
|
||||||
ok(FillInHTMLTooltip(doc.getElementById("link1"), "should get title"));
|
ok(FillInHTMLTooltip(doc.getElementById("link1"), "should get title"));
|
||||||
is(tooltip.getAttribute("label"), " This is a title ");
|
is(tooltip.getAttribute("label"), "\n This is a title\n ");
|
||||||
ok(FillInHTMLTooltip(doc.getElementById("text4"), "should get title"));
|
ok(FillInHTMLTooltip(doc.getElementById("text4"), "should get title"));
|
||||||
is(tooltip.getAttribute("label"), " This is a title ");
|
is(tooltip.getAttribute("label"), "\n This is a title\n ");
|
||||||
|
|
||||||
ok(!FillInHTMLTooltip(doc.getElementById("link2"), "should not get title"));
|
ok(!FillInHTMLTooltip(doc.getElementById("link2"), "should not get title"));
|
||||||
|
|
||||||
|
|
|
@ -54,12 +54,10 @@ function thirdPageLoaded() {
|
||||||
|
|
||||||
function imageLoaded() {
|
function imageLoaded() {
|
||||||
zoomTest(gTab1, 1, "Zoom should be 1 when image was loaded in the background");
|
zoomTest(gTab1, 1, "Zoom should be 1 when image was loaded in the background");
|
||||||
afterZoom(function() {
|
|
||||||
zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected");
|
|
||||||
|
|
||||||
executeSoon(imageZoomSwitch);
|
|
||||||
});
|
|
||||||
gBrowser.selectedTab = gTab1;
|
gBrowser.selectedTab = gTab1;
|
||||||
|
zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected");
|
||||||
|
|
||||||
|
executeSoon(imageZoomSwitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
function imageZoomSwitch() {
|
function imageZoomSwitch() {
|
||||||
|
@ -136,12 +134,10 @@ function navigate(direction, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterZoom(cb) {
|
function afterZoom(cb) {
|
||||||
let oldAPTS = FullZoom._applyPrefToSetting;
|
let oldSZFB = ZoomManager.setZoomForBrowser;
|
||||||
FullZoom._applyPrefToSetting = function(value, browser) {
|
ZoomManager.setZoomForBrowser = function(browser, value) {
|
||||||
if (!value)
|
oldSZFB.call(ZoomManager, browser, value);
|
||||||
value = undefined;
|
ZoomManager.setZoomForBrowser = oldSZFB;
|
||||||
oldAPTS.call(FullZoom, value, browser);
|
|
||||||
FullZoom._applyPrefToSetting = oldAPTS;
|
|
||||||
executeSoon(cb);
|
executeSoon(cb);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,19 +43,18 @@ function test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterZoomAndLoad(cb) {
|
function afterZoomAndLoad(cb) {
|
||||||
let didLoad = didZoom = false;
|
let didLoad = false;
|
||||||
|
let didZoom = false;
|
||||||
tabElm.linkedBrowser.addEventListener("load", function() {
|
tabElm.linkedBrowser.addEventListener("load", function() {
|
||||||
tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||||
didLoad = true;
|
didLoad = true;
|
||||||
if (didZoom)
|
if (didZoom)
|
||||||
executeSoon(cb);
|
executeSoon(cb);
|
||||||
}, true);
|
}, true);
|
||||||
let oldAPTS = FullZoom._applyPrefToSetting;
|
let oldSZFB = ZoomManager.setZoomForBrowser;
|
||||||
FullZoom._applyPrefToSetting = function(value, browser) {
|
ZoomManager.setZoomForBrowser = function(browser, value) {
|
||||||
if (!value)
|
oldSZFB.call(ZoomManager, browser, value);
|
||||||
value = undefined;
|
ZoomManager.setZoomForBrowser = oldSZFB;
|
||||||
oldAPTS.call(FullZoom, value, browser);
|
|
||||||
FullZoom._applyPrefToSetting = oldAPTS;
|
|
||||||
didZoom = true;
|
didZoom = true;
|
||||||
if (didLoad)
|
if (didLoad)
|
||||||
executeSoon(cb);
|
executeSoon(cb);
|
||||||
|
|
|
@ -37,7 +37,8 @@ const TEST_PAGE = "/browser/browser/base/content/test/dummy_page.html";
|
||||||
var gTestTab, gBgTab, gTestZoom;
|
var gTestTab, gBgTab, gTestZoom;
|
||||||
|
|
||||||
function afterZoomAndLoad(aCallback, aTab) {
|
function afterZoomAndLoad(aCallback, aTab) {
|
||||||
let didLoad = didZoom = false;
|
let didLoad = false;
|
||||||
|
let didZoom = false;
|
||||||
aTab.linkedBrowser.addEventListener("load", function() {
|
aTab.linkedBrowser.addEventListener("load", function() {
|
||||||
aTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
aTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||||
didLoad = true;
|
didLoad = true;
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
let tab1, tab2;
|
||||||
|
const TEST_IMAGE = "http://example.org/browser/browser/base/content/test/moz.png";
|
||||||
|
|
||||||
|
waitForExplicitFinish();
|
||||||
|
registerCleanupFunction(function cleanup() {
|
||||||
|
gBrowser.removeTab(tab1);
|
||||||
|
gBrowser.removeTab(tab2);
|
||||||
|
});
|
||||||
|
|
||||||
|
tab1 = gBrowser.addTab(TEST_IMAGE);
|
||||||
|
tab2 = gBrowser.addTab();
|
||||||
|
gBrowser.selectedTab = tab1;
|
||||||
|
|
||||||
|
tab1.linkedBrowser.addEventListener("load", function onload() {
|
||||||
|
tab1.linkedBrowser.removeEventListener("load", onload, true);
|
||||||
|
is(ZoomManager.zoom, 1, "initial zoom level for first should be 1");
|
||||||
|
|
||||||
|
FullZoom.enlarge();
|
||||||
|
let zoom = ZoomManager.zoom;
|
||||||
|
isnot(zoom, 1, "zoom level should have changed");
|
||||||
|
|
||||||
|
gBrowser.selectedTab = tab2;
|
||||||
|
is(ZoomManager.zoom, 1, "initial zoom level for second tab should be 1");
|
||||||
|
|
||||||
|
gBrowser.selectedTab = tab1;
|
||||||
|
is(ZoomManager.zoom, zoom, "zoom level for first tab should not have changed");
|
||||||
|
|
||||||
|
finish();
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ function numClosedTabs()
|
||||||
getClosedTabCount(window);
|
getClosedTabCount(window);
|
||||||
|
|
||||||
function isUndoCloseEnabled() {
|
function isUndoCloseEnabled() {
|
||||||
document.popupNode = gBrowser.tabs[0];
|
updateTabContextMenu();
|
||||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
|
||||||
TabContextMenu.contextTab = null;
|
|
||||||
return !document.getElementById("context_undoCloseTab").disabled;
|
return !document.getElementById("context_undoCloseTab").disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm");
|
var tempScope = {};
|
||||||
|
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
|
||||||
|
var LightweightThemeManager = tempScope.LightweightThemeManager;
|
||||||
|
|
||||||
function wait_for_notification(aCallback) {
|
function wait_for_notification(aCallback) {
|
||||||
PopupNotifications.panel.addEventListener("popupshown", function() {
|
PopupNotifications.panel.addEventListener("popupshown", function() {
|
||||||
|
|
|
@ -43,6 +43,8 @@ https://example.com/browser/browser/base/content/test/redirect_bug623155.sjs#FG
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var gNewTab;
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const TEST_PAGE = "http://example.org/browser/browser/base/content/test/zoom_test.html";
|
||||||
|
const TEST_VIDEO = "http://example.org/browser/browser/base/content/test/video.ogg";
|
||||||
|
|
||||||
|
var gTab1, gTab2, gLevel1, gLevel2;
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
gTab1 = gBrowser.addTab();
|
||||||
|
gTab2 = gBrowser.addTab();
|
||||||
|
gBrowser.selectedTab = gTab1;
|
||||||
|
|
||||||
|
load(gTab1, TEST_PAGE, function() {
|
||||||
|
load(gTab2, TEST_VIDEO, zoomTab1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomTab1() {
|
||||||
|
is(gBrowser.selectedTab, gTab1, "Tab 1 is selected");
|
||||||
|
zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1");
|
||||||
|
zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1");
|
||||||
|
|
||||||
|
FullZoom.enlarge();
|
||||||
|
gLevel1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1));
|
||||||
|
|
||||||
|
ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1");
|
||||||
|
zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2");
|
||||||
|
|
||||||
|
gBrowser.selectedTab = gTab2;
|
||||||
|
zoomTest(gTab2, 1, "Tab 2 is still unzoomed after it is selected");
|
||||||
|
zoomTest(gTab1, gLevel1, "Tab 1 is still zoomed");
|
||||||
|
|
||||||
|
zoomTab2();
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomTab2() {
|
||||||
|
is(gBrowser.selectedTab, gTab2, "Tab 2 is selected");
|
||||||
|
|
||||||
|
FullZoom.reduce();
|
||||||
|
let gLevel2 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab2));
|
||||||
|
|
||||||
|
ok(gLevel2 < 1, "New zoom for tab 2 should be less than 1");
|
||||||
|
zoomTest(gTab1, gLevel1, "Zooming tab 2 should not affect tab 1");
|
||||||
|
|
||||||
|
afterZoom(function() {
|
||||||
|
zoomTest(gTab1, gLevel1, "Tab 1 should have the same zoom after it's selected");
|
||||||
|
|
||||||
|
testNavigation();
|
||||||
|
});
|
||||||
|
gBrowser.selectedTab = gTab1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testNavigation() {
|
||||||
|
load(gTab1, TEST_VIDEO, function() {
|
||||||
|
zoomTest(gTab1, 1, "Zoom should be 1 when a video was loaded");
|
||||||
|
navigate(BACK, function() {
|
||||||
|
zoomTest(gTab1, gLevel1, "Zoom should be restored when a page is loaded");
|
||||||
|
navigate(FORWARD, function() {
|
||||||
|
zoomTest(gTab1, 1, "Zoom should be 1 again when navigating back to a video");
|
||||||
|
finishTest();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var finishTestStarted = false;
|
||||||
|
function finishTest() {
|
||||||
|
ok(!finishTestStarted, "finishTest called more than once");
|
||||||
|
finishTestStarted = true;
|
||||||
|
|
||||||
|
gBrowser.selectedTab = gTab1;
|
||||||
|
FullZoom.reset();
|
||||||
|
gBrowser.removeTab(gTab1);
|
||||||
|
|
||||||
|
gBrowser.selectedTab = gTab2;
|
||||||
|
FullZoom.reset();
|
||||||
|
gBrowser.removeTab(gTab2);
|
||||||
|
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomTest(tab, val, msg) {
|
||||||
|
is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(tab, url, cb) {
|
||||||
|
let didLoad = false;
|
||||||
|
let didZoom = false;
|
||||||
|
tab.linkedBrowser.addEventListener("load", function onload(event) {
|
||||||
|
event.currentTarget.removeEventListener("load", onload, true);
|
||||||
|
didLoad = true;
|
||||||
|
if (didZoom)
|
||||||
|
executeSoon(cb);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
afterZoom(function() {
|
||||||
|
didZoom = true;
|
||||||
|
if (didLoad)
|
||||||
|
executeSoon(cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
tab.linkedBrowser.loadURI(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BACK = 0;
|
||||||
|
const FORWARD = 1;
|
||||||
|
function navigate(direction, cb) {
|
||||||
|
let didPs = false;
|
||||||
|
let didZoom = false;
|
||||||
|
gBrowser.addEventListener("pageshow", function onpageshow(event) {
|
||||||
|
gBrowser.removeEventListener("pageshow", onpageshow, true);
|
||||||
|
didPs = true;
|
||||||
|
if (didZoom)
|
||||||
|
executeSoon(cb);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
afterZoom(function() {
|
||||||
|
didZoom = true;
|
||||||
|
if (didPs)
|
||||||
|
executeSoon(cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (direction == BACK)
|
||||||
|
gBrowser.goBack();
|
||||||
|
else if (direction == FORWARD)
|
||||||
|
gBrowser.goForward();
|
||||||
|
}
|
||||||
|
|
||||||
|
function afterZoom(cb) {
|
||||||
|
let oldSZFB = ZoomManager.setZoomForBrowser;
|
||||||
|
ZoomManager.setZoomForBrowser = function(browser, value) {
|
||||||
|
oldSZFB.call(ZoomManager, browser, value);
|
||||||
|
ZoomManager.setZoomForBrowser = oldSZFB;
|
||||||
|
executeSoon(cb);
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,8 +7,10 @@
|
||||||
const testURL1 = "http://mochi.test:8888/browser/browser/base/content/test/browser_clearplugindata.html";
|
const testURL1 = "http://mochi.test:8888/browser/browser/base/content/test/browser_clearplugindata.html";
|
||||||
const testURL2 = "http://mochi.test:8888/browser/browser/base/content/test/browser_clearplugindata_noage.html";
|
const testURL2 = "http://mochi.test:8888/browser/browser/base/content/test/browser_clearplugindata_noage.html";
|
||||||
|
|
||||||
|
let tempScope = {};
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("chrome://browser/content/sanitize.js");
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
const pluginHostIface = Ci.nsIPluginHost;
|
const pluginHostIface = Ci.nsIPluginHost;
|
||||||
var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||||
|
|
|
@ -104,7 +104,6 @@ function end_test() {
|
||||||
|
|
||||||
function test_url(aURL, aCanHide, aNextTest) {
|
function test_url(aURL, aCanHide, aNextTest) {
|
||||||
is_chrome_visible();
|
is_chrome_visible();
|
||||||
|
|
||||||
info("Page load");
|
info("Page load");
|
||||||
load_page(aURL, aCanHide, function() {
|
load_page(aURL, aCanHide, function() {
|
||||||
info("Switch away");
|
info("Switch away");
|
||||||
|
@ -163,5 +162,30 @@ function run_http_test_2() {
|
||||||
// Should not hide the chrome
|
// Should not hide the chrome
|
||||||
function run_chrome_about_test_2() {
|
function run_chrome_about_test_2() {
|
||||||
info("Chrome about: tests");
|
info("Chrome about: tests");
|
||||||
test_url("about:addons", true, end_test);
|
test_url("about:addons", true, run_http_test3);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_http_test3() {
|
||||||
|
info("HTTP tests");
|
||||||
|
test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not hide the chrome
|
||||||
|
function run_chrome_about_test_3() {
|
||||||
|
info("Chrome about: tests");
|
||||||
|
test_url("about:Addons", true, function(){
|
||||||
|
info("Tabs on top");
|
||||||
|
TabsOnTop.enabled = true;
|
||||||
|
run_http_test4();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_http_test4() {
|
||||||
|
info("HTTP tests");
|
||||||
|
test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_chrome_about_test_4() {
|
||||||
|
info("Chrome about: tests");
|
||||||
|
test_url("about:Addons", true, end_test);
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,7 +383,7 @@ function test_latchedGesture(gesture, inc, dec, eventPrefix)
|
||||||
|
|
||||||
// Restore the gesture to its original configuration.
|
// Restore the gesture to its original configuration.
|
||||||
gPrefService.setBoolPref(branch + "latched", oldLatchedValue);
|
gPrefService.setBoolPref(branch + "latched", oldLatchedValue);
|
||||||
for (dir in cmd)
|
for (let dir in cmd)
|
||||||
test_removeCommand(cmd[dir]);
|
test_removeCommand(cmd[dir]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ var tests = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
let gCurrentTest, gCurrentTestIndex = -1;
|
let gCurrentTest, gCurrentTestIndex = -1, gTestDesc;
|
||||||
// Go through the tests in both directions, to add additional coverage for
|
// Go through the tests in both directions, to add additional coverage for
|
||||||
// transitions between different states.
|
// transitions between different states.
|
||||||
let gForward = true;
|
let gForward = true;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
// Bug 474792 - Clear "Never remember passwords for this site" when
|
// Bug 474792 - Clear "Never remember passwords for this site" when
|
||||||
// clearing site-specific settings in Clear Recent History dialog
|
// clearing site-specific settings in Clear Recent History dialog
|
||||||
|
|
||||||
|
let tempScope = {};
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("chrome://browser/content/sanitize.js");
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// Bug 380852 - Delete permission manager entries in Clear Recent History
|
// Bug 380852 - Delete permission manager entries in Clear Recent History
|
||||||
|
|
||||||
|
let tempScope = {};
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("chrome://browser/content/sanitize.js");
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,10 @@ const dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManage
|
||||||
const bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory);
|
const bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory);
|
||||||
const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
|
const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
|
||||||
|
|
||||||
|
let tempScope = {};
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("chrome://browser/content/sanitize.js");
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,10 @@
|
||||||
* browser/base/content/test/browser_sanitize-timespans.js.
|
* browser/base/content/test/browser_sanitize-timespans.js.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
let tempScope = {};
|
||||||
getService(Ci.mozIJSSubScriptLoader).
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
loadSubScript("chrome://browser/content/sanitize.js");
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
const dm = Cc["@mozilla.org/download-manager;1"].
|
const dm = Cc["@mozilla.org/download-manager;1"].
|
||||||
getService(Ci.nsIDownloadManager);
|
getService(Ci.nsIDownloadManager);
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* This Source Code is subject to the terms of the Mozilla Public License
|
||||||
|
* version 2.0 (the "License"). You can obtain a copy of the License at
|
||||||
|
* http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// This test ensures that autoFilled values are not trimmed, unless the user
|
||||||
|
// selects from the autocomplete popup.
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
const PREF_TRIMURL = "browser.urlbar.trimURLs";
|
||||||
|
const PREF_AUTOFILL = "browser.urlbar.autoFill";
|
||||||
|
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
Services.prefs.clearUserPref(PREF_TRIMURL);
|
||||||
|
Services.prefs.clearUserPref(PREF_AUTOFILL);
|
||||||
|
URLBarSetURI();
|
||||||
|
});
|
||||||
|
Services.prefs.setBoolPref(PREF_TRIMURL, true);
|
||||||
|
Services.prefs.setBoolPref(PREF_AUTOFILL, true);
|
||||||
|
|
||||||
|
// Adding a tab would hit switch-to-tab, so it's safer to just add a visit.
|
||||||
|
let callback = {
|
||||||
|
handleError: function () {},
|
||||||
|
handleResult: function () {},
|
||||||
|
handleCompletion: continue_test
|
||||||
|
};
|
||||||
|
let history = Cc["@mozilla.org/browser/history;1"]
|
||||||
|
.getService(Ci.mozIAsyncHistory);
|
||||||
|
history.updatePlaces({ uri: NetUtil.newURI("http://www.autofilltrimurl.com/")
|
||||||
|
, visits: [ { transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED
|
||||||
|
, visitDate: Date.now() * 1000
|
||||||
|
} ]
|
||||||
|
}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function continue_test() {
|
||||||
|
function test_autoFill(aTyped, aExpected, aCallback) {
|
||||||
|
gURLBar.inputField.value = aTyped.substr(0, aTyped.length - 1);
|
||||||
|
gURLBar.focus();
|
||||||
|
gURLBar.selectionStart = aTyped.length - 1;
|
||||||
|
gURLBar.selectionEnd = aTyped.length - 1;
|
||||||
|
|
||||||
|
EventUtils.synthesizeKey(aTyped.substr(-1), {});
|
||||||
|
is(gURLBar.value, aExpected, "trim was applied correctly");
|
||||||
|
|
||||||
|
aCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
test_autoFill("http://", "http://", function () {
|
||||||
|
test_autoFill("http://a", "http://autofilltrimurl.com/", function () {
|
||||||
|
test_autoFill("http://www.autofilltrimurl.com", "http://www.autofilltrimurl.com/", function () {
|
||||||
|
// Now ensure selecting from the popup correctly trims.
|
||||||
|
waitForSearchComplete(function () {
|
||||||
|
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||||
|
is(gURLBar.value, "www.autofilltrimurl.com", "trim was applied correctly");
|
||||||
|
gURLBar.closePopup();
|
||||||
|
waitForClearHistory(finish);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForClearHistory(aCallback) {
|
||||||
|
Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
|
||||||
|
Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
|
||||||
|
aCallback();
|
||||||
|
}, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
|
||||||
|
PlacesUtils.bhistory.removeAllPages();
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForSearchComplete(aCallback) {
|
||||||
|
info("Waiting for onSearchComplete");
|
||||||
|
let onSearchComplete = gURLBar.onSearchComplete;
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
gURLBar.onSearchComplete = onSearchComplete;
|
||||||
|
});
|
||||||
|
gURLBar.onSearchComplete = function () {
|
||||||
|
ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
|
||||||
|
is(gURLBar.controller.matchCount, 1, "Found the expected number of matches")
|
||||||
|
onSearchComplete.apply(gURLBar);
|
||||||
|
aCallback();
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,15 +89,11 @@ function test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Disabled() {
|
function Disabled() {
|
||||||
document.popupNode = gBrowser.selectedTab;
|
updateTabContextMenu();
|
||||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
|
||||||
TabContextMenu.contextTab = null;
|
|
||||||
return document.getElementById("Browser:BookmarkAllTabs").getAttribute("disabled") == "true";
|
return document.getElementById("Browser:BookmarkAllTabs").getAttribute("disabled") == "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
function Hidden() {
|
function Hidden() {
|
||||||
document.popupNode = gBrowser.selectedTab;
|
updateTabContextMenu();
|
||||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
|
||||||
TabContextMenu.contextTab = null;
|
|
||||||
return document.getElementById("context_bookmarkAllTabs").hidden;
|
return document.getElementById("context_bookmarkAllTabs").hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ function test() {
|
||||||
is(gBrowser.visibleTabs.length, 2, "there are now two visible tabs");
|
is(gBrowser.visibleTabs.length, 2, "there are now two visible tabs");
|
||||||
|
|
||||||
// Check the context menu with two tabs
|
// Check the context menu with two tabs
|
||||||
popup(origTab);
|
updateTabContextMenu(origTab);
|
||||||
is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled");
|
is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled");
|
||||||
is(document.getElementById("context_reloadAllTabs").disabled, false, "Reload All Tabs is enabled");
|
is(document.getElementById("context_reloadAllTabs").disabled, false, "Reload All Tabs is enabled");
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ function test() {
|
||||||
is(gBrowser.visibleTabs.length, 1, "now there is only one visible tab");
|
is(gBrowser.visibleTabs.length, 1, "now there is only one visible tab");
|
||||||
|
|
||||||
// Check the context menu with one tab.
|
// Check the context menu with one tab.
|
||||||
popup(testTab);
|
updateTabContextMenu(testTab);
|
||||||
is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled when more than one tab exists");
|
is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled when more than one tab exists");
|
||||||
is(document.getElementById("context_reloadAllTabs").disabled, true, "Reload All Tabs is disabled");
|
is(document.getElementById("context_reloadAllTabs").disabled, true, "Reload All Tabs is disabled");
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ function test() {
|
||||||
is(gBrowser.visibleTabs.length, 2, "now there are two visible tabs");
|
is(gBrowser.visibleTabs.length, 2, "now there are two visible tabs");
|
||||||
|
|
||||||
// Check the context menu on the unpinned visible tab
|
// Check the context menu on the unpinned visible tab
|
||||||
popup(testTab);
|
updateTabContextMenu(testTab);
|
||||||
is(document.getElementById("context_closeOtherTabs").disabled, true, "Close Other Tabs is disabled");
|
is(document.getElementById("context_closeOtherTabs").disabled, true, "Close Other Tabs is disabled");
|
||||||
|
|
||||||
// Show all tabs
|
// Show all tabs
|
||||||
|
@ -72,16 +72,9 @@ function test() {
|
||||||
gBrowser.showOnlyTheseTabs(allTabs);
|
gBrowser.showOnlyTheseTabs(allTabs);
|
||||||
|
|
||||||
// Check the context menu now
|
// Check the context menu now
|
||||||
popup(testTab);
|
updateTabContextMenu(testTab);
|
||||||
is(document.getElementById("context_closeOtherTabs").disabled, false, "Close Other Tabs is enabled");
|
is(document.getElementById("context_closeOtherTabs").disabled, false, "Close Other Tabs is enabled");
|
||||||
|
|
||||||
gBrowser.removeTab(testTab);
|
gBrowser.removeTab(testTab);
|
||||||
gBrowser.removeTab(pinned);
|
gBrowser.removeTab(pinned);
|
||||||
}
|
}
|
||||||
|
|
||||||
function popup(tab) {
|
|
||||||
document.popupNode = tab;
|
|
||||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
|
||||||
is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
|
|
||||||
TabContextMenu.contextTab = null;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
function updateTabContextMenu(tab) {
|
||||||
|
let menu = document.getElementById("tabContextMenu");
|
||||||
|
if (!tab)
|
||||||
|
tab = gBrowser.selectedTab;
|
||||||
|
menu.openPopup(tab, "end_after", 0, 0, true, false, {target: tab});
|
||||||
|
is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
|
||||||
|
menu.hidePopup();
|
||||||
|
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче