зеркало из 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
|
||||
|
||||
# Build directories
|
||||
obj*/
|
||||
/obj*/
|
||||
|
||||
# Build directories for js shell
|
||||
*/_DBG.OBJ/
|
||||
|
|
1
.hgtags
1
.hgtags
|
@ -72,3 +72,4 @@ c0983049bcaa9551e5f276d5a77ce154c151e0b0 AURORA_BASE_20110927
|
|||
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R15
|
||||
54bfd8bf682e295ffd7f22fa921ca343957b6c1c AURORA_BASE_20111108
|
||||
a8506ab2c65480cf2f85f54e203ea746522c62bb AURORA_BASE_20111220
|
||||
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R16
|
||||
|
|
|
@ -49,6 +49,9 @@ namespace statistics {
|
|||
inline void A11yInitialized()
|
||||
{ Telemetry::Accumulate(Telemetry::A11Y_INSTANTIATED, true); }
|
||||
|
||||
inline void A11yConsumers(PRUint32 aConsumer)
|
||||
{ Telemetry::Accumulate(Telemetry::A11Y_CONSUMERS, aConsumer); }
|
||||
|
||||
/**
|
||||
* Report that ISimpleDOM* has been used.
|
||||
*/
|
||||
|
|
|
@ -195,12 +195,6 @@ public:
|
|||
*/
|
||||
virtual bool IsPrimaryForNode() const;
|
||||
|
||||
/**
|
||||
* Return the string bundle
|
||||
*/
|
||||
static nsIStringBundle* GetStringBundle()
|
||||
{ return gStringBundle; }
|
||||
|
||||
protected:
|
||||
nsPresContext* GetPresContext();
|
||||
|
||||
|
|
|
@ -395,7 +395,7 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
|
|||
nsCString plugId;
|
||||
nsresult rv = pluginInstance->GetValueFromPlugin(
|
||||
NPPVpluginNativeAccessibleAtkPlugId, &plugId);
|
||||
if (NS_SUCCEEDED(rv) && !plugId.IsVoid()) {
|
||||
if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
|
||||
AtkSocketAccessible* socketAccessible =
|
||||
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
|
||||
// for it. Take care of HTML elements only for now.
|
||||
if (aContent->IsHTML() &&
|
||||
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;
|
||||
return aContent->IsHTML() &&
|
||||
nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id);
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
|
|
|
@ -579,16 +579,13 @@ nsAccessible::GetIndexInParent(PRInt32 *aIndexInParent)
|
|||
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;
|
||||
|
||||
if (!gStringBundle ||
|
||||
NS_FAILED(gStringBundle->GetStringFromName(PromiseFlatString(aKey).get(), getter_Copies(xsValue))))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
gStringBundle->GetStringFromName(PromiseFlatString(aKey).get(), getter_Copies(xsValue));
|
||||
aStringOut.Assign(xsValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint64
|
||||
|
@ -616,6 +613,9 @@ nsAccessible::VisibilityState()
|
|||
} while (accessible = accessible->Parent());
|
||||
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (!frame)
|
||||
return vstates;
|
||||
|
||||
const nsCOMPtr<nsIPresShell> shell(GetPresShell());
|
||||
|
||||
// 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.
|
||||
ApplyARIAState(&state);
|
||||
|
||||
if (mRoleMapEntry && mRoleMapEntry->role == roles::PAGETAB &&
|
||||
!(state & states::SELECTED) &&
|
||||
// If this is an ARIA item of the selectable widget and if it's focused and
|
||||
// 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,
|
||||
nsGkAtoms::aria_selected,
|
||||
nsGkAtoms::_false, eCaseMatters)) {
|
||||
// Special case: for tabs, focused implies selected, unless explicitly
|
||||
// false, i.e. aria-selected="false".
|
||||
if (state & states::FOCUSED) {
|
||||
state |= states::SELECTED;
|
||||
} else {
|
||||
// If focus is in a child of the tab panel surely the tab is selected!
|
||||
Relation rel = RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
|
||||
nsAccessible* relTarget = nsnull;
|
||||
while ((relTarget = rel.Next())) {
|
||||
if (relTarget->Role() == roles::PROPERTYPAGE &&
|
||||
FocusMgr()->IsFocusWithin(relTarget))
|
||||
state |= states::SELECTED;
|
||||
// Special case for tabs: focused tab or focus inside related tab panel
|
||||
// implies selected state.
|
||||
if (mRoleMapEntry->role == roles::PAGETAB) {
|
||||
if (state & states::FOCUSED) {
|
||||
state |= states::SELECTED;
|
||||
} else {
|
||||
// If focus is in a child of the tab panel surely the tab is selected!
|
||||
Relation rel = RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
|
||||
nsAccessible* relTarget = nsnull;
|
||||
while ((relTarget = rel.Next())) {
|
||||
if (relTarget->Role() == roles::PROPERTYPAGE &&
|
||||
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);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return GetTranslatedString(name, aDescription);
|
||||
TranslateString(name, aDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// void doAction(in PRUint8 index)
|
||||
|
@ -2914,21 +2926,18 @@ nsAccessible::SetCurrentItem(nsAccessible* aItem)
|
|||
nsAccessible*
|
||||
nsAccessible::ContainerWidget() const
|
||||
{
|
||||
nsIAtom* idAttribute = mContent->GetIDAttributeName();
|
||||
if (idAttribute) {
|
||||
if (mContent->HasAttr(kNameSpaceID_None, idAttribute)) {
|
||||
for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
|
||||
nsIContent* parentContent = parent->GetContent();
|
||||
if (parentContent &&
|
||||
parentContent->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::aria_activedescendant)) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
// Don't cross DOM document boundaries.
|
||||
if (parent->IsDocumentNode())
|
||||
break;
|
||||
if (HasARIARole() && mContent->HasID()) {
|
||||
for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
|
||||
nsIContent* parentContent = parent->GetContent();
|
||||
if (parentContent &&
|
||||
parentContent->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::aria_activedescendant)) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
// Don't cross DOM document boundaries.
|
||||
if (parent->IsDocumentNode())
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
|
|
|
@ -166,6 +166,14 @@ public:
|
|||
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
|
||||
* roles).
|
||||
|
@ -603,6 +611,11 @@ public:
|
|||
*/
|
||||
virtual nsAccessible* ContainerWidget() const;
|
||||
|
||||
/**
|
||||
* Return the localized string for the given key.
|
||||
*/
|
||||
static void TranslateString(const nsAString& aKey, nsAString& aStringOut);
|
||||
|
||||
protected:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -695,7 +708,6 @@ protected:
|
|||
|
||||
// helper method to verify frames
|
||||
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
|
||||
|
|
|
@ -1345,7 +1345,7 @@ nsHTMLTableAccessible::HasDescendant(const nsAString& aTagName,
|
|||
if (foundItemContent->GetChildCount() > 1)
|
||||
return true; // Treat multiple child nodes as non-empty
|
||||
|
||||
nsIContent *innerItemContent = foundItemContent->GetChildAt(0);
|
||||
nsIContent *innerItemContent = foundItemContent->GetFirstChild();
|
||||
if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
|
||||
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 *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -15,11 +16,12 @@
|
|||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* 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"),
|
||||
|
@ -35,25 +37,24 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsDocumentCharsetInfo_h__
|
||||
#define nsDocumentCharsetInfo_h__
|
||||
#ifndef _MacUtils_H_
|
||||
#define _MacUtils_H_
|
||||
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIDocumentCharsetInfo.h"
|
||||
@class NSString;
|
||||
class nsString;
|
||||
|
||||
class nsDocumentCharsetInfo : public nsIDocumentCharsetInfo
|
||||
{
|
||||
public:
|
||||
nsDocumentCharsetInfo ();
|
||||
virtual ~nsDocumentCharsetInfo ();
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
namespace utils {
|
||||
|
||||
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 \
|
||||
mozActionElements.mm \
|
||||
mozTextAccessible.mm \
|
||||
mozHTMLAccessible.mm \
|
||||
MacUtils.mm \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
EXPORTS = \
|
||||
nsAccessNodeWrap.h \
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#import "mozAccessible.h"
|
||||
|
||||
// to get the mozView formal protocol, that all gecko's ChildViews implement.
|
||||
#import "MacUtils.h"
|
||||
#import "mozView.h"
|
||||
#import "nsRoleMap.h"
|
||||
|
||||
|
@ -127,24 +127,6 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
|
|||
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 -
|
||||
|
||||
@implementation mozAccessible
|
||||
|
@ -219,6 +201,9 @@ GetLocalizedString(const nsString& aString)
|
|||
NSAccessibilityTitleUIElementAttribute,
|
||||
NSAccessibilityTopLevelUIElementAttribute,
|
||||
NSAccessibilityDescriptionAttribute,
|
||||
#if DEBUG
|
||||
@"AXMozDescription",
|
||||
#endif
|
||||
nil];
|
||||
}
|
||||
|
||||
|
@ -233,6 +218,11 @@ GetLocalizedString(const nsString& aString)
|
|||
|
||||
if (mIsExpired)
|
||||
return nil;
|
||||
|
||||
#if DEBUG
|
||||
if ([attribute isEqualToString:@"AXMozDescription"])
|
||||
return [NSString stringWithFormat:@"role = %u native = %@", mRole, [self class]];
|
||||
#endif
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
|
||||
return [self children];
|
||||
|
@ -254,8 +244,8 @@ GetLocalizedString(const nsString& aString)
|
|||
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
|
||||
return [self value];
|
||||
if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
|
||||
if (mRole == roles::INTERNAL_FRAME || mRole == roles::DOCUMENT_FRAME)
|
||||
return GetLocalizedString(NS_LITERAL_STRING("htmlContent")) ? : @"HTML Content";
|
||||
if (mRole == roles::DOCUMENT)
|
||||
return utils::LocalizedString(NS_LITERAL_STRING("htmlContent"));
|
||||
|
||||
return NSAccessibilityRoleDescription([self role], nil);
|
||||
}
|
||||
|
@ -348,7 +338,9 @@ GetLocalizedString(const nsString& aString)
|
|||
|
||||
- (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
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
@interface mozButtonAccessible : mozAccessible
|
||||
- (void)click;
|
||||
- (BOOL)isTab;
|
||||
@end
|
||||
|
||||
@interface mozCheckboxAccessible : mozButtonAccessible
|
||||
|
@ -53,3 +54,11 @@
|
|||
/* Used for buttons that may pop up a menu. */
|
||||
@interface mozPopupButtonAccessible : mozButtonAccessible
|
||||
@end
|
||||
|
||||
/* Class for tabs - not individual tabs */
|
||||
@interface mozTabsAccessible : mozAccessible
|
||||
{
|
||||
NSMutableArray* mTabs;
|
||||
}
|
||||
-(id)tabs;
|
||||
@end
|
||||
|
|
|
@ -37,7 +37,11 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#import "mozActionElements.h"
|
||||
|
||||
#import "MacUtils.h"
|
||||
|
||||
#import "nsIAccessible.h"
|
||||
#import "nsXULTabAccessible.h"
|
||||
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
|
@ -60,6 +64,7 @@ enum CheckboxValue {
|
|||
if (!attributes) {
|
||||
attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required
|
||||
NSAccessibilityRoleAttribute, // required
|
||||
NSAccessibilityRoleDescriptionAttribute,
|
||||
NSAccessibilityPositionAttribute, // required
|
||||
NSAccessibilitySizeAttribute, // required
|
||||
NSAccessibilityWindowAttribute, // required
|
||||
|
@ -70,6 +75,9 @@ enum CheckboxValue {
|
|||
NSAccessibilityFocusedAttribute, // required
|
||||
NSAccessibilityTitleAttribute, // required
|
||||
NSAccessibilityDescriptionAttribute,
|
||||
#if DEBUG
|
||||
@"AXMozDescription",
|
||||
#endif
|
||||
nil];
|
||||
}
|
||||
return attributes;
|
||||
|
@ -83,6 +91,13 @@ enum CheckboxValue {
|
|||
|
||||
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
|
||||
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];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
|
@ -109,9 +124,13 @@ enum CheckboxValue {
|
|||
{
|
||||
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 nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
|
@ -134,6 +153,11 @@ enum CheckboxValue {
|
|||
mGeckoAccessible->DoAction(0);
|
||||
}
|
||||
|
||||
- (BOOL)isTab
|
||||
{
|
||||
return (mGeckoAccessible && (mGeckoAccessible->Role() == roles::PAGETAB));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation mozCheckboxAccessible
|
||||
|
@ -198,6 +222,9 @@ enum CheckboxValue {
|
|||
NSAccessibilityTitleAttribute, // required for popupmenus, and for menubuttons with a title
|
||||
NSAccessibilityChildrenAttribute, // required
|
||||
NSAccessibilityDescriptionAttribute, // required if it has no title attr
|
||||
#if DEBUG
|
||||
@"AXMozDescription",
|
||||
#endif
|
||||
nil];
|
||||
}
|
||||
return attributes;
|
||||
|
@ -258,3 +285,85 @@ enum CheckboxValue {
|
|||
}
|
||||
|
||||
@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 *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -15,11 +17,12 @@
|
|||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* 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"),
|
||||
|
@ -35,16 +38,12 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsXMLEncodingCID_h__
|
||||
#define nsXMLEncodingCID_h__
|
||||
#import "mozAccessible.h"
|
||||
|
||||
#include "nscore.h"
|
||||
@interface mozHeadingAccessible : mozAccessible
|
||||
|
||||
#define NS_XML_ENCODING_CONTRACTID "@mozilla.org/intl/xmlencoding;1"
|
||||
@end
|
||||
|
||||
// {12BB8F16-2389-11d3-B3BF-00805F8A6670}
|
||||
#define NS_XML_ENCODING_CID \
|
||||
{ 0x12bb8f16, 0x2389, 0x11d3, { 0xb3, 0xbf, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 } }
|
||||
@interface mozLinkAccessible : mozAccessible
|
||||
|
||||
|
||||
#endif // nsXMLEncodingCID_h__
|
||||
@end
|
|
@ -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 "nsCocoaUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
#import "mozTextAccessible.h"
|
||||
|
@ -12,6 +14,7 @@ using namespace mozilla::a11y;
|
|||
- (long)textLength;
|
||||
- (BOOL)isReadOnly;
|
||||
- (void)setText:(NSString*)newText;
|
||||
- (NSString*)text;
|
||||
@end
|
||||
|
||||
@implementation mozTextAccessible
|
||||
|
@ -60,6 +63,9 @@ using namespace mozilla::a11y;
|
|||
NSAccessibilityNumberOfCharactersAttribute, // required
|
||||
// TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
|
||||
// TODO: NSAccessibilityInsertionPointLineNumberAttribute
|
||||
#if DEBUG
|
||||
@"AXMozDescription",
|
||||
#endif
|
||||
nil];
|
||||
}
|
||||
return supportedAttributes;
|
||||
|
@ -79,8 +85,9 @@ using namespace mozilla::a11y;
|
|||
return [self selectedText];
|
||||
// Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText
|
||||
// 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])
|
||||
return [self selectedText];
|
||||
return [self selectedText] ? : [self text];
|
||||
|
||||
// let mozAccessible handle all other attributes
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
|
@ -158,6 +165,20 @@ using namespace mozilla::a11y;
|
|||
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
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
@ -261,6 +282,9 @@ using namespace mozilla::a11y;
|
|||
NSAccessibilityNumberOfCharactersAttribute, // required
|
||||
// TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
|
||||
// TODO: NSAccessibilityInsertionPointLineNumberAttribute
|
||||
#if DEBUG
|
||||
@"AXMozDescription",
|
||||
#endif
|
||||
nil];
|
||||
}
|
||||
return supportedAttributes;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#import "mozAccessible.h"
|
||||
#import "mozActionElements.h"
|
||||
#import "mozHTMLAccessible.h"
|
||||
#import "mozTextAccessible.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
@ -103,22 +104,33 @@ nsAccessibleWrap::GetNativeType ()
|
|||
[mozButtonAccessible class];
|
||||
}
|
||||
|
||||
case roles::PAGETAB:
|
||||
return [mozButtonAccessible class];
|
||||
|
||||
case roles::CHECKBUTTON:
|
||||
return [mozCheckboxAccessible class];
|
||||
|
||||
case roles::AUTOCOMPLETE:
|
||||
return [mozComboboxAccessible class];
|
||||
|
||||
case roles::HEADING:
|
||||
return [mozHeadingAccessible class];
|
||||
|
||||
case roles::PAGETABLIST:
|
||||
return [mozTabsAccessible class];
|
||||
|
||||
case roles::ENTRY:
|
||||
case roles::STATICTEXT:
|
||||
case roles::HEADING:
|
||||
case roles::LABEL:
|
||||
case roles::CAPTION:
|
||||
case roles::ACCEL_LABEL:
|
||||
case roles::TEXT_LEAF:
|
||||
// normal textfield (static or editable)
|
||||
return [mozTextAccessible class];
|
||||
|
||||
|
||||
case roles::LINK:
|
||||
return [mozLinkAccessible class];
|
||||
|
||||
case roles::COMBOBOX:
|
||||
return [mozPopupButtonAccessible class];
|
||||
|
||||
|
|
|
@ -52,12 +52,12 @@ static const NSString* AXRoles [] = {
|
|||
NSAccessibilityUnknownRole, // ROLE_CARET. unused on OS X
|
||||
NSAccessibilityWindowRole, // ROLE_ALERT
|
||||
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
|
||||
NSAccessibilityMenuItemRole, // ROLE_MENUITEM.
|
||||
@"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_DOCUMENT
|
||||
@"AXWebArea", // ROLE_DOCUMENT
|
||||
NSAccessibilityGroupRole, // ROLE_PANE
|
||||
NSAccessibilityUnknownRole, // ROLE_CHART
|
||||
NSAccessibilityWindowRole, // ROLE_DIALOG. there's a dialog subrole.
|
||||
|
@ -74,12 +74,12 @@ static const NSString* AXRoles [] = {
|
|||
NSAccessibilityGroupRole, // ROLE_CELL
|
||||
@"AXLink", // ROLE_LINK. 10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
|
||||
@"AXHelpTag", // ROLE_HELPBALLOON
|
||||
NSAccessibilityUnknownRole, // ROLE_CHARACTER. unusued on OS X
|
||||
NSAccessibilityUnknownRole, // ROLE_CHARACTER. unused on OS X
|
||||
NSAccessibilityListRole, // ROLE_LIST
|
||||
NSAccessibilityRowRole, // ROLE_LISTITEM
|
||||
NSAccessibilityOutlineRole, // ROLE_OUTLINE
|
||||
NSAccessibilityRowRole, // ROLE_OUTLINEITEM. XXX: use OutlineRow as subrole.
|
||||
NSAccessibilityGroupRole, // ROLE_PAGETAB
|
||||
NSAccessibilityRadioButtonRole, // ROLE_PAGETAB
|
||||
NSAccessibilityGroupRole, // ROLE_PROPERTYPAGE
|
||||
NSAccessibilityUnknownRole, // ROLE_INDICATOR
|
||||
NSAccessibilityImageRole, // ROLE_GRAPHIC
|
||||
|
@ -102,7 +102,7 @@ static const NSString* AXRoles [] = {
|
|||
NSAccessibilityMenuButtonRole, // ROLE_BUTTONMENU
|
||||
NSAccessibilityGroupRole, // ROLE_BUTTONDROPDOWNGRID
|
||||
NSAccessibilityUnknownRole, // ROLE_WHITESPACE
|
||||
NSAccessibilityGroupRole, // ROLE_PAGETABLIST
|
||||
NSAccessibilityTabGroupRole, // ROLE_PAGETABLIST
|
||||
NSAccessibilityUnknownRole, // ROLE_CLOCK. unused on OS X
|
||||
NSAccessibilityButtonRole, // ROLE_SPLITBUTTON
|
||||
NSAccessibilityUnknownRole, // ROLE_IPADDRESS
|
||||
|
@ -146,9 +146,9 @@ static const NSString* AXRoles [] = {
|
|||
NSAccessibilityTextFieldRole, // ROLE_EDITBAR
|
||||
NSAccessibilityTextFieldRole, // ROLE_ENTRY
|
||||
NSAccessibilityStaticTextRole, // ROLE_CAPTION
|
||||
@"AXWebArea", // ROLE_DOCUMENT_FRAME
|
||||
NSAccessibilityStaticTextRole, // ROLE_HEADING
|
||||
NSAccessibilityGroupRole, // ROLE_PAGE
|
||||
NSAccessibilityScrollAreaRole, // ROLE_DOCUMENT_FRAME
|
||||
@"AXHeading", // ROLE_HEADING
|
||||
NSAccessibilityGroupRole, // ROLE_PAG
|
||||
NSAccessibilityGroupRole, // ROLE_SECTION
|
||||
NSAccessibilityUnknownRole, // ROLE_REDUNDANT_OBJECT
|
||||
NSAccessibilityGroupRole, // ROLE_FORM
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "Compatibility.h"
|
||||
|
||||
#include "nsWinUtils.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
|
@ -84,18 +85,37 @@ PRUint32 Compatibility::sMode = Compatibility::NoCompatibilityMode;
|
|||
void
|
||||
Compatibility::Init()
|
||||
{
|
||||
// Note we collect some AT statistics/telemetry here for convenience.
|
||||
|
||||
HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
|
||||
if (jawsHandle) {
|
||||
sMode |= JAWSMode;
|
||||
// IA2 off mode for JAWS versions below 8.0.2173.
|
||||
if (IsModuleVersionLessThan(jawsHandle, 8, 2173))
|
||||
if (IsModuleVersionLessThan(jawsHandle, 8, 2173)) {
|
||||
sMode |= IA2OffMode;
|
||||
statistics::A11yConsumers(OLDJAWS);
|
||||
} else {
|
||||
statistics::A11yConsumers(JAWS);
|
||||
}
|
||||
}
|
||||
|
||||
if (::GetModuleHandleW(L"gwm32inc"))
|
||||
if (::GetModuleHandleW(L"gwm32inc")) {
|
||||
sMode |= WEMode;
|
||||
if (::GetModuleHandleW(L"dolwinhk"))
|
||||
statistics::A11yConsumers(WE);
|
||||
}
|
||||
if (::GetModuleHandleW(L"dolwinhk")) {
|
||||
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.
|
||||
if (sMode & JAWSMode || sMode & WEMode) {
|
||||
|
|
|
@ -97,6 +97,19 @@ private:
|
|||
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:
|
||||
static PRUint32 sMode;
|
||||
};
|
||||
|
|
|
@ -75,6 +75,7 @@ _TEST_FILES =\
|
|||
actions.js \
|
||||
attributes.js \
|
||||
autocomplete.js \
|
||||
browser.js \
|
||||
common.js \
|
||||
events.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
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Set up this variable to dump events into DOM.
|
||||
*/
|
||||
|
@ -172,7 +174,7 @@ const DO_NOT_FINISH_TEST = 1;
|
|||
* // phase getter: function() {},
|
||||
* //
|
||||
* // * Callback, called to match handled event. *
|
||||
* // match : function() {},
|
||||
* // match : function(aEvent) {},
|
||||
* //
|
||||
* // * Callback, called when event is handled
|
||||
* // check: function(aEvent) {},
|
||||
|
@ -1338,10 +1340,10 @@ function caretMoveChecker(aCaretOffset, aTargetOrFunc, aTargetFuncArg)
|
|||
* State change checker.
|
||||
*/
|
||||
function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
||||
aTargetOrFunc, aTargetFuncArg)
|
||||
aTargetOrFunc, aTargetFuncArg, aIsAsync)
|
||||
{
|
||||
this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
|
||||
aTargetFuncArg);
|
||||
aTargetFuncArg, aIsAsync);
|
||||
|
||||
this.check = function stateChangeChecker_check(aEvent)
|
||||
{
|
||||
|
@ -1368,6 +1370,22 @@ function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
|||
var unxpdExtraState = aIsEnabled ? 0 : (aIsExtraState ? aState : 0);
|
||||
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 =
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
if (aTopic != "accessible-event")
|
||||
|
@ -1431,7 +1443,7 @@ var gA11yEventObserver =
|
|||
} catch (ex) {
|
||||
// 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.
|
||||
this.observerService.removeObserver(this, "accessible-event");
|
||||
Services.obs.removeObserver(this, "accessible-event");
|
||||
// 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 + " ]";
|
||||
}
|
||||
|
@ -1485,14 +1497,12 @@ function listenA11yEvents(aStartToListen)
|
|||
if (aStartToListen) {
|
||||
// Add observer when adding the first applicant only.
|
||||
if (!(gA11yEventApplicantsCount++))
|
||||
gA11yEventObserver.observerService
|
||||
.addObserver(gA11yEventObserver, "accessible-event", false);
|
||||
Services.obs.addObserver(gA11yEventObserver, "accessible-event", false);
|
||||
} else {
|
||||
// Remove observer when there are no more applicants only.
|
||||
// '< 0' case should not happen, but just in case: removeObserver() will throw.
|
||||
if (--gA11yEventApplicantsCount <= 0)
|
||||
gA11yEventObserver.observerService
|
||||
.removeObserver(gA11yEventObserver, "accessible-event");
|
||||
Services.obs.removeObserver(gA11yEventObserver, "accessible-event");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1609,11 +1619,8 @@ var gLogger =
|
|||
logToAppConsole: function logger_logToAppConsole(aMsg)
|
||||
{
|
||||
if (gA11yEventDumpToAppConsole)
|
||||
consoleService.logStringMessage("events: " + aMsg);
|
||||
},
|
||||
|
||||
consoleService: Components.classes["@mozilla.org/consoleservice;1"].
|
||||
getService(Components.interfaces.nsIConsoleService)
|
||||
Services.console.logStringMessage("events: " + aMsg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ relativesrcdir = accessible/events
|
|||
include $(DEPTH)/config/autoconf.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 =\
|
||||
docload_wnd.html \
|
||||
|
@ -61,6 +61,7 @@ _TEST_FILES =\
|
|||
test_coalescence.html \
|
||||
test_contextmenu.html \
|
||||
test_docload.html \
|
||||
test_docload.xul \
|
||||
test_dragndrop.html \
|
||||
test_flush.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>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../browser.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
// var gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
|
||||
function doTest()
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Invoker checkers.
|
||||
function stateBusyChecker(aIsEnabled)
|
||||
{
|
||||
var w = window.openDialog("../events/docload_wnd.xul",
|
||||
"docload_test",
|
||||
"chrome,width=600,height=600");
|
||||
this.type = EVENT_STATE_CHANGE;
|
||||
this.__defineGetter__("target", currentTabDocument);
|
||||
|
||||
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();
|
||||
addLoadEvent(doTest);
|
||||
openBrowserWindow(doTests);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<!-- Firefox searchbar -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.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"
|
||||
title="Accessible focus event testing">
|
||||
|
|
|
@ -19,40 +19,20 @@
|
|||
src="../states.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../browser.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
function tabBrowser()
|
||||
{
|
||||
return gBrowserWnd.gBrowser;
|
||||
}
|
||||
|
||||
function currentBrowser()
|
||||
{
|
||||
return tabBrowser().selectedBrowser;
|
||||
}
|
||||
|
||||
function currentTabDocument()
|
||||
{
|
||||
return currentBrowser().contentDocument;
|
||||
}
|
||||
|
||||
function inputInDocument()
|
||||
{
|
||||
var tabdoc = currentTabDocument();
|
||||
return tabdoc.getElementById("input");
|
||||
}
|
||||
|
||||
function urlbarInput()
|
||||
{
|
||||
return gBrowserWnd.document.getElementById("urlbar").inputField;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Invokers
|
||||
|
||||
|
@ -96,22 +76,6 @@
|
|||
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 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
|
||||
|
||||
var gQueue = null;
|
||||
|
@ -123,7 +87,8 @@
|
|||
var input = inputInDocument();
|
||||
|
||||
// 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
|
||||
gQueue.push(new loadURI(gButtonDocURI));
|
||||
|
@ -132,22 +97,22 @@
|
|||
gQueue.push(new goBack());
|
||||
|
||||
// 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)));
|
||||
|
||||
// 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)));
|
||||
|
||||
gQueue.onFinish = function()
|
||||
{
|
||||
gBrowserWnd.close();
|
||||
closeBrowserWindow();
|
||||
}
|
||||
gQueue.invoke();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(loadBrowser);
|
||||
openBrowserWindow(doTests, gInputDocURI);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js" />
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.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"
|
||||
title="Accessible focus testing">
|
||||
|
||||
|
|
|
@ -139,6 +139,18 @@
|
|||
<rule attr="title" type="string"/>
|
||||
</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 ref="htmlelm_start"/>
|
||||
<rule elm="caption"/>
|
||||
|
@ -190,6 +202,28 @@
|
|||
</html:select>
|
||||
</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"
|
||||
id="markup4test">
|
||||
<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">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
var gOpenerWnd = window.opener.wrappedJSObject;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js" />
|
||||
|
|
|
@ -37,9 +37,11 @@ const STATE_UNAVAILABLE = nsIAccessibleStates.STATE_UNAVAILABLE;
|
|||
const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
|
||||
const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
|
||||
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_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
|
||||
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_STALE = nsIAccessibleStates.EXT_STATE_STALE;
|
||||
const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
|
||||
|
|
|
@ -48,7 +48,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
_TEST_FILES =\
|
||||
test_aria.html \
|
||||
test_aria_imgmap.html \
|
||||
test_aria_tabs.html \
|
||||
test_aria_widgetitems.html \
|
||||
test_buttons.html \
|
||||
test_doc.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://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<!-- Firefox searchbar -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.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"
|
||||
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 + "!");
|
||||
}
|
||||
|
||||
function testThis(aID, aName, aSRC, aWidth, aHeight,
|
||||
function testThis(aID, aSRC, aWidth, aHeight,
|
||||
aNumActions, aActionNames)
|
||||
{
|
||||
var acc = getAccessible(aID, [nsIAccessibleImage]);
|
||||
if (!acc)
|
||||
return;
|
||||
|
||||
is(acc.name, aName, "wrong name for " + aID + "!");
|
||||
|
||||
// Test role
|
||||
testRole(aID, ROLE_GRAPHIC);
|
||||
|
||||
|
@ -108,50 +106,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
|
|||
function doTest()
|
||||
{
|
||||
// Test non-linked image
|
||||
testThis("nonLinkedImage", null, "moz.png", 89, 38);
|
||||
testThis("nonLinkedImage", "moz.png", 89, 38);
|
||||
|
||||
// Test linked image
|
||||
testThis("linkedImage", null, "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);
|
||||
testThis("linkedImage", "moz.png", 89, 38);
|
||||
|
||||
// Image with long desc
|
||||
var actionNamesArray = new Array("showlongdesc");
|
||||
testThis("longdesc", "Image of Mozilla logo", "moz.png", 89, 38, 1,
|
||||
testThis("longdesc", "moz.png", 89, 38, 1,
|
||||
actionNamesArray);
|
||||
|
||||
// Image with click and long desc
|
||||
actionNamesArray = null;
|
||||
actionNamesArray = new Array("click", "showlongdesc");
|
||||
testThis("clickAndLongdesc", "Another image of Mozilla logo", "moz.png",
|
||||
testThis("clickAndLongdesc", "moz.png",
|
||||
89, 38, 2, actionNamesArray);
|
||||
|
||||
// Image with click
|
||||
actionNamesArray = null;
|
||||
actionNamesArray = new Array("click");
|
||||
testThis("click", "A third image of Mozilla logo", "moz.png",
|
||||
testThis("click", "moz.png",
|
||||
89, 38, 1, actionNamesArray);
|
||||
|
||||
SimpleTest.finish();
|
||||
|
@ -172,23 +146,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429659
|
|||
<img id="nonLinkedImage" src="moz.png"/>
|
||||
<br>Linked image:<br>
|
||||
<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>
|
||||
<img id="longdesc" src="moz.png" longdesc="longdesc_src.html"
|
||||
alt="Image of Mozilla logo"/>
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js" />
|
||||
|
|
|
@ -394,6 +394,10 @@ pref("layers.acceleration.force-enabled", true);
|
|||
pref("dom.screenEnabledProperty.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
|
||||
pref("dom.sms.enabled", true);
|
||||
pref("dom.sms.whitelist", "file://,http://localhost:6666");
|
||||
|
|
|
@ -201,6 +201,11 @@ var shell = {
|
|||
break;
|
||||
case evt.DOM_VK_SLEEP:
|
||||
this.toggleScreen();
|
||||
|
||||
let details = {
|
||||
'enabled': screen.mozEnabled
|
||||
};
|
||||
this.sendEvent(this.home.contentWindow, 'sleep', details);
|
||||
break;
|
||||
case evt.DOM_VK_ESCAPE:
|
||||
if (evt.defaultPrevented)
|
||||
|
|
|
@ -395,10 +395,8 @@
|
|||
@BINPATH@/components/nsFilePicker.js
|
||||
@BINPATH@/components/nsFilePicker.manifest
|
||||
#ifdef MOZ_B2G_RIL
|
||||
@BINPATH@/components/nsTelephonyWorker.manifest
|
||||
@BINPATH@/components/nsTelephonyWorker.js
|
||||
@BINPATH@/components/Telephony.manifest
|
||||
@BINPATH@/components/Telephony.js
|
||||
@BINPATH@/components/RadioInterfaceLayer.manifest
|
||||
@BINPATH@/components/RadioInterfaceLayer.js
|
||||
@BINPATH@/components/nsWifiWorker.js
|
||||
@BINPATH@/components/nsWifiWorker.manifest
|
||||
#endif
|
||||
|
@ -602,3 +600,5 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
|||
@BINPATH@/chrome/icons/
|
||||
@BINPATH@/chrome/chrome@JAREXT@
|
||||
@BINPATH@/chrome/chrome.manifest
|
||||
@BINPATH@/components/B2GComponents.manifest
|
||||
@BINPATH@/components/B2GComponents.xpt
|
||||
|
|
|
@ -83,6 +83,10 @@ LIBS += \
|
|||
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_LINKER
|
||||
LIBS += $(ZLIB_LIBS)
|
||||
endif
|
||||
|
||||
ifndef MOZ_WINCONSOLE
|
||||
ifdef MOZ_DEBUG
|
||||
MOZ_WINCONSOLE = 1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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>
|
||||
<emItem blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
|
||||
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
|
||||
|
@ -27,6 +27,10 @@
|
|||
<versionRange minVersion="1.1b1" maxVersion="1.1b1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i54" id="applebeegifts@mozilla.doslash.org">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
|
||||
<versionRange minVersion="1.0" maxVersion="1.0">
|
||||
</versionRange>
|
||||
|
@ -39,6 +43,10 @@
|
|||
<versionRange minVersion="0.1" maxVersion="14.4.0" severity="1">
|
||||
</versionRange>
|
||||
</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>
|
||||
<emItem blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
|
||||
|
@ -66,10 +74,21 @@
|
|||
</targetApplication>
|
||||
</versionRange>
|
||||
</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}">
|
||||
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i51" id="admin@youtubeplayer.com">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
|
||||
<versionRange minVersion="0.1" maxVersion="*">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
|
@ -84,13 +103,12 @@
|
|||
</targetApplication>
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i11" id="yslow@yahoo-inc.com">
|
||||
<versionRange minVersion="2.0.5" maxVersion="2.0.5">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
<versionRange minVersion="3.5.7" maxVersion="*" />
|
||||
</targetApplication>
|
||||
<emItem blockID="i55" id="youtube@youtube7.com">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i47" id="youtube@youtube2.com">
|
||||
</emItem>
|
||||
<emItem blockID="i22" id="ShopperReports@ShopperReports.com">
|
||||
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
|
||||
</versionRange>
|
||||
|
@ -122,8 +140,13 @@
|
|||
<versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i47" id="youtube@youtube2.com">
|
||||
</emItem>
|
||||
<emItem blockID="i11" id="yslow@yahoo-inc.com">
|
||||
<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}">
|
||||
<versionRange minVersion="2.2" maxVersion="2.2">
|
||||
</versionRange>
|
||||
|
@ -139,10 +162,12 @@
|
|||
<versionRange minVersion="2.0" maxVersion="2.0">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i49" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE63}">
|
||||
</emItem>
|
||||
<emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
|
||||
</emItem>
|
||||
<emItem blockID="i52" id="ff-ext@youtube">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
|
||||
<versionRange minVersion="0.1" maxVersion="1.3.328.4" severity="1">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
|
|
|
@ -244,8 +244,7 @@ pref("general.autoScroll", false);
|
|||
pref("general.autoScroll", true);
|
||||
#endif
|
||||
|
||||
// Whether or not the application should check at startup each time if it
|
||||
// is the default browser.
|
||||
// At startup, check if we're the default browser and prompt user if not.
|
||||
pref("browser.shell.checkDefaultBrowser", true);
|
||||
|
||||
// 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
|
||||
pref("browser.urlbar.doubleClickSelectsAll", false);
|
||||
#endif
|
||||
pref("browser.urlbar.autoFill", false);
|
||||
pref("browser.urlbar.autoFill", true);
|
||||
// 0: Match anywhere (e.g., middle of words)
|
||||
// 1: Match on word boundaries and then try matching anywhere
|
||||
// 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
|
||||
// before starting to perform autocomplete. 50 is the default set in
|
||||
// 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 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);
|
||||
// Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
|
||||
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
|
||||
pref("accessibility.blockautorefresh", false);
|
||||
|
@ -1032,6 +1035,8 @@ pref("devtools.styleinspector.enabled", true);
|
|||
|
||||
// Enable the Tilt inspector
|
||||
pref("devtools.tilt.enabled", true);
|
||||
pref("devtools.tilt.intro_transition", true);
|
||||
pref("devtools.tilt.outro_transition", true);
|
||||
|
||||
// Enable the rules view
|
||||
pref("devtools.ruleview.enabled", true);
|
||||
|
@ -1041,12 +1046,13 @@ pref("devtools.scratchpad.enabled", true);
|
|||
|
||||
// Enable the Style Editor.
|
||||
pref("devtools.styleeditor.enabled", true);
|
||||
pref("devtools.styleeditor.transitions", true);
|
||||
|
||||
// Enable tools for Chrome development.
|
||||
pref("devtools.chrome.enabled", false);
|
||||
|
||||
// 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
|
||||
// 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
|
||||
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.
|
||||
pref("full-screen-api.enabled", true);
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
list-style-image: url("chrome://global/skin/icons/loading_16.png");
|
||||
}
|
||||
|
||||
.trademark-label,
|
||||
.text-link,
|
||||
.text-link:focus {
|
||||
margin: 0px;
|
||||
|
|
|
@ -77,17 +77,6 @@ function init(aEvent)
|
|||
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
|
||||
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="http://www.mozilla.com/legal/privacy/">&bottomLinks.privacy;</label>
|
||||
</hbox>
|
||||
<description id="trademark">
|
||||
<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>
|
||||
<description id="trademark">&trademarkInfo.part1;</description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
|
|
|
@ -176,7 +176,8 @@
|
|||
<menuseparator class="appmenu-menuseparator"/>
|
||||
<menu id="appmenu_webDeveloper"
|
||||
label="&appMenuWebDeveloper.label;">
|
||||
<menupopup id="appmenu_webDeveloper_popup">
|
||||
<menupopup id="appmenu_webDeveloper_popup"
|
||||
onpopupshowing="onWebDeveloperMenuShowing();">
|
||||
<menuitem id="appmenu_webConsole"
|
||||
label="&webConsoleCmd.label;"
|
||||
type="checkbox"
|
||||
|
|
|
@ -225,13 +225,19 @@ var FullZoom = {
|
|||
return;
|
||||
|
||||
// Avoid the cps roundtrip and apply the default/global pref.
|
||||
if (aURI.spec == "about:blank") {
|
||||
if (isBlankPageURL(aURI.spec)) {
|
||||
this._applyPrefToSetting(undefined, aBrowser);
|
||||
return;
|
||||
}
|
||||
|
||||
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)) {
|
||||
let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
|
||||
this._applyPrefToSetting(zoomValue, browser);
|
||||
|
@ -303,9 +309,10 @@ var FullZoom = {
|
|||
|
||||
var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser);
|
||||
try {
|
||||
if (browser.contentDocument instanceof Ci.nsIImageDocument)
|
||||
ZoomManager.setZoomForBrowser(browser, 1);
|
||||
else if (typeof aValue != "undefined")
|
||||
if (browser.contentDocument.mozSyntheticDocument)
|
||||
return;
|
||||
|
||||
if (typeof aValue != "undefined")
|
||||
ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue));
|
||||
else if (typeof this.globalValue != "undefined")
|
||||
ZoomManager.setZoomForBrowser(browser, this.globalValue);
|
||||
|
@ -317,7 +324,7 @@ var FullZoom = {
|
|||
|
||||
_applySettingToPref: function FullZoom__applySettingToPref() {
|
||||
if (!this.siteSpecific || gInPrintPreviewMode ||
|
||||
content.document instanceof Ci.nsIImageDocument)
|
||||
content.document.mozSyntheticDocument)
|
||||
return;
|
||||
|
||||
var zoomLevel = ZoomManager.zoom;
|
||||
|
@ -325,7 +332,7 @@ var FullZoom = {
|
|||
},
|
||||
|
||||
_removePref: function FullZoom__removePref() {
|
||||
if (!(content.document instanceof Ci.nsIImageDocument))
|
||||
if (!(content.document.mozSyntheticDocument))
|
||||
Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
|
||||
},
|
||||
|
||||
|
|
|
@ -531,7 +531,8 @@
|
|||
<menu id="webDeveloperMenu"
|
||||
label="&webDeveloperMenu.label;"
|
||||
accesskey="&webDeveloperMenu.accesskey;">
|
||||
<menupopup id="menuWebDeveloperPopup">
|
||||
<menupopup id="menuWebDeveloperPopup"
|
||||
onpopupshowing="onWebDeveloperMenuShowing();">
|
||||
<menuitem id="webConsole"
|
||||
type="checkbox"
|
||||
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.
|
||||
if (this._uri.spec == "about:blank") {
|
||||
if (isBlankPageURL(this._uri.spec)) {
|
||||
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 = [
|
||||
"about:blank",
|
||||
"about:newtab",
|
||||
"about:privatebrowsing",
|
||||
"about:sessionrestore"
|
||||
];
|
||||
|
@ -196,6 +197,7 @@ let gInitialPages = [
|
|||
#include browser-places.js
|
||||
#include browser-tabPreviews.js
|
||||
#include browser-tabview.js
|
||||
#include browser-thumbnails.js
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
#include browser-syncui.js
|
||||
|
@ -1501,6 +1503,8 @@ function prepareForStartup() {
|
|||
}
|
||||
|
||||
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
Cu.import("resource:///modules/TelemetryTimestamps.jsm");
|
||||
TelemetryTimestamps.add("delayedStartupStarted");
|
||||
gDelayedStartupTimeoutId = null;
|
||||
|
||||
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
||||
|
@ -1554,7 +1558,11 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
// Perform default browser checking (after window opens).
|
||||
var shell = getShellService();
|
||||
if (shell) {
|
||||
#ifdef DEBUG
|
||||
var shouldCheck = false;
|
||||
#else
|
||||
var shouldCheck = shell.shouldCheckDefaultBrowser;
|
||||
#endif
|
||||
var willRecoverSession = false;
|
||||
try {
|
||||
var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
||||
|
@ -1699,6 +1707,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
gSyncUI.init();
|
||||
#endif
|
||||
|
||||
gBrowserThumbnails.init();
|
||||
TabView.init();
|
||||
|
||||
setUrlAndSearchBarWidthForConditionalForwardButton();
|
||||
|
@ -1761,6 +1770,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
window.addEventListener("dragover", MousePosTracker, false);
|
||||
|
||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
|
||||
TelemetryTimestamps.add("delayedStartupFinished");
|
||||
}
|
||||
|
||||
function BrowserShutdown() {
|
||||
|
@ -1820,6 +1830,7 @@ function BrowserShutdown() {
|
|||
gPrefService.removeObserver(allTabs.prefName, allTabs);
|
||||
ctrlTab.uninit();
|
||||
TabView.uninit();
|
||||
gBrowserThumbnails.uninit();
|
||||
|
||||
try {
|
||||
FullZoom.destroy();
|
||||
|
@ -2194,7 +2205,7 @@ function openLocation() {
|
|||
else {
|
||||
// If there are no open browser windows, open a new one
|
||||
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);
|
||||
}
|
||||
return;
|
||||
|
@ -2212,7 +2223,7 @@ function openLocationCallback()
|
|||
|
||||
function BrowserOpenTab()
|
||||
{
|
||||
openUILinkIn("about:blank", "tab");
|
||||
openUILinkIn(BROWSER_NEW_TAB_URL, "tab");
|
||||
}
|
||||
|
||||
/* Called from the openLocation dialog. This allows that dialog to instruct
|
||||
|
@ -2547,7 +2558,7 @@ function URLBarSetURI(aURI) {
|
|||
else
|
||||
value = losslessDecodeURI(uri);
|
||||
|
||||
valid = (uri.spec != "about:blank");
|
||||
valid = !isBlankPageURL(uri.spec);
|
||||
}
|
||||
|
||||
gURLBar.value = value;
|
||||
|
@ -2864,7 +2875,7 @@ function getMeOutOfHere() {
|
|||
// Get the start page from the *default* pref branch, not the user's
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefService).getDefaultBranch(null);
|
||||
var url = "about:blank";
|
||||
var url = BROWSER_NEW_TAB_URL;
|
||||
try {
|
||||
url = prefs.getComplexValue("browser.startup.homepage",
|
||||
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.
|
||||
if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ||
|
||||
!tipElement.ownerDocument ||
|
||||
tipElement.ownerDocument.compareDocumentPosition(tipElement) == document.DOCUMENT_POSITION_DISCONNECTED)
|
||||
(tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED))
|
||||
return retVal;
|
||||
|
||||
const XLinkNS = "http://www.w3.org/1999/xlink";
|
||||
|
@ -3105,20 +3116,13 @@ function FillInHTMLTooltip(tipElement)
|
|||
|
||||
[titleText, XLinkTitleText, SVGTitleText].forEach(function (t) {
|
||||
if (t && /\S/.test(t)) {
|
||||
|
||||
// Per HTML 4.01 6.2 (CDATA section), literal CRs and tabs should be
|
||||
// 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, '');
|
||||
// Make CRLF and CR render one line break each.
|
||||
t = t.replace(/\r\n?/g, '\n');
|
||||
|
||||
tipNode.setAttribute("label", t);
|
||||
retVal = true;
|
||||
}
|
||||
});
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -4785,6 +4789,7 @@ var XULBrowserWindow = {
|
|||
},
|
||||
|
||||
hideChromeForLocation: function(aLocation) {
|
||||
aLocation = aLocation.toLowerCase();
|
||||
return this.inContentWhitelist.some(function(aSpec) {
|
||||
return aSpec == aLocation;
|
||||
});
|
||||
|
@ -5188,7 +5193,7 @@ nsBrowserAccess.prototype = {
|
|||
case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
|
||||
// FIXME: Bug 408379. So how come this doesn't send the
|
||||
// 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
|
||||
// loadOneOrMoreURIs, which splits based on "|"
|
||||
newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null);
|
||||
|
@ -5197,7 +5202,7 @@ nsBrowserAccess.prototype = {
|
|||
let win, needToFocusWin;
|
||||
|
||||
// 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;
|
||||
else {
|
||||
win = Cc["@mozilla.org/browser/browserglue;1"]
|
||||
|
@ -5221,7 +5226,7 @@ nsBrowserAccess.prototype = {
|
|||
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
|
||||
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,
|
||||
fromExternal: isExternal,
|
||||
inBackground: loadInBackground});
|
||||
|
@ -5969,12 +5974,12 @@ function MultiplexHandler(event)
|
|||
var name = node.getAttribute('name');
|
||||
|
||||
if (name == 'detectorGroup') {
|
||||
SetForcedDetector(true);
|
||||
BrowserCharsetReload();
|
||||
SelectDetector(event, false);
|
||||
} else if (name == 'charsetGroup') {
|
||||
var charset = node.getAttribute('id');
|
||||
charset = charset.substring('charset.'.length, charset.length)
|
||||
SetForcedCharset(charset);
|
||||
BrowserSetForcedCharacterSet(charset);
|
||||
} else if (name == 'charsetCustomize') {
|
||||
//do nothing - please remove this else statement, once the charset prefs moves to the pref window
|
||||
} else {
|
||||
|
@ -6005,30 +6010,17 @@ function SelectDetector(event, doReload)
|
|||
}
|
||||
}
|
||||
|
||||
function SetForcedDetector(doReload)
|
||||
{
|
||||
BrowserSetForcedDetector(doReload);
|
||||
}
|
||||
|
||||
function SetForcedCharset(charset)
|
||||
{
|
||||
BrowserSetForcedCharacterSet(charset);
|
||||
}
|
||||
|
||||
function BrowserSetForcedCharacterSet(aCharset)
|
||||
{
|
||||
var docCharset = gBrowser.docShell.QueryInterface(Ci.nsIDocCharset);
|
||||
docCharset.charset = aCharset;
|
||||
gBrowser.docShell.charset = aCharset;
|
||||
// Save the forced character-set
|
||||
PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, aCharset);
|
||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||
BrowserCharsetReload();
|
||||
}
|
||||
|
||||
function BrowserSetForcedDetector(doReload)
|
||||
function BrowserCharsetReload()
|
||||
{
|
||||
gBrowser.documentCharsetInfo.forcedDetector = true;
|
||||
if (doReload)
|
||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||
}
|
||||
|
||||
function charsetMenuGetElement(parent, id) {
|
||||
|
@ -7783,9 +7775,11 @@ function undoCloseWindow(aIndex) {
|
|||
*/
|
||||
function isTabEmpty(aTab) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
let uri = browser.currentURI.spec;
|
||||
let body = browser.contentDocument.body;
|
||||
return browser.sessionHistory.count < 2 &&
|
||||
browser.currentURI.spec == "about:blank" &&
|
||||
!browser.contentDocument.body.hasChildNodes() &&
|
||||
isBlankPageURL(uri) &&
|
||||
(!body || !body.hasChildNodes()) &&
|
||||
!aTab.hasAttribute("busy");
|
||||
}
|
||||
|
||||
|
@ -8872,8 +8866,8 @@ function restoreLastSession() {
|
|||
var TabContextMenu = {
|
||||
contextTab: null,
|
||||
updateContextMenu: function updateContextMenu(aPopupMenu) {
|
||||
this.contextTab = document.popupNode.localName == "tab" ?
|
||||
document.popupNode : gBrowser.selectedTab;
|
||||
this.contextTab = aPopupMenu.triggerNode.localName == "tab" ?
|
||||
aPopupMenu.triggerNode : gBrowser.selectedTab;
|
||||
let disabled = gBrowser.tabs.length == 1;
|
||||
|
||||
// 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 () {
|
||||
Cu.import("resource:///modules/HUDService.jsm");
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/HUDService.jsm", tempScope);
|
||||
try {
|
||||
return HUDService.consoleUI;
|
||||
return tempScope.HUDService.consoleUI;
|
||||
}
|
||||
catch (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 () {
|
||||
#ifdef XP_WIN
|
||||
// Only show resizers on Windows 2000 and XP
|
||||
|
@ -9146,6 +9146,7 @@ var MousePosTracker = {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
function focusNextFrame(event) {
|
||||
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
|
||||
|
|
|
@ -391,7 +391,7 @@
|
|||
<panel id="customizeToolbarSheetPopup"
|
||||
noautohide="true">
|
||||
<iframe id="customizeToolbarSheetIFrame"
|
||||
style="&dialog.style;"
|
||||
style="&dialog.dimensions;"
|
||||
hidden="true"/>
|
||||
</panel>
|
||||
|
||||
|
@ -502,7 +502,7 @@
|
|||
<textbox id="urlbar" flex="1"
|
||||
placeholder="&urlbar.placeholder;"
|
||||
type="autocomplete"
|
||||
autocompletesearch="history"
|
||||
autocompletesearch="urlinline history"
|
||||
autocompletesearchparam="enable-actions"
|
||||
autocompletepopup="PopupAutoCompleteRichResult"
|
||||
completeselectedindex="true"
|
||||
|
@ -534,12 +534,12 @@
|
|||
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
|
||||
ondragstart="gIdentityHandler.onDragStart(event);">
|
||||
<hbox id="identity-box-inner" align="center">
|
||||
<stack id="page-proxy-stack"
|
||||
onclick="PageProxyClickHandler(event);">
|
||||
<hbox id="page-proxy-stack"
|
||||
onclick="PageProxyClickHandler(event);">
|
||||
<image id="page-proxy-favicon" validate="never"
|
||||
pageproxystate="invalid"
|
||||
onerror="this.removeAttribute('src');"/>
|
||||
</stack>
|
||||
</hbox>
|
||||
<hbox id="identity-icon-labels">
|
||||
<label id="identity-icon-label" class="plain" flex="1"/>
|
||||
<label id="identity-icon-country-label" class="plain"/>
|
||||
|
@ -993,7 +993,6 @@
|
|||
hidden="true">
|
||||
<vbox flex="1">
|
||||
<resizer id="inspector-top-resizer" flex="1"
|
||||
class="inspector-resizer"
|
||||
dir="top" disabled="true"
|
||||
element="inspector-tree-box"/>
|
||||
<hbox>
|
||||
|
@ -1029,10 +1028,6 @@
|
|||
oncommand="InspectorUI.closeInspectorUI(false);"
|
||||
tooltiptext="&inspectCloseButton.tooltiptext;"/>
|
||||
#endif
|
||||
<resizer id="inspector-end-resizer"
|
||||
class="inspector-resizer"
|
||||
dir="top" disabled="true"
|
||||
element="inspector-tree-box"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</toolbar>
|
||||
|
|
|
@ -34,12 +34,11 @@
|
|||
direction: ltr;
|
||||
}
|
||||
|
||||
.inspector-resizer {
|
||||
#inspector-top-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer,
|
||||
#inspector-toolbar[treepanel-open] > vbox > hbox > #inspector-end-resizer {
|
||||
#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer {
|
||||
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">
|
||||
<textbox id="dialog.input" flex="1" type="autocomplete"
|
||||
completeselectedindex="true"
|
||||
autocompletesearch="history"
|
||||
autocompletesearch="urlinline history"
|
||||
enablehistory="true"
|
||||
class="uri-element"
|
||||
oninput="doEnabling();"/>
|
||||
|
|
|
@ -42,17 +42,18 @@
|
|||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
//******** 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
|
||||
// the copy-n-paste buffer when the user hits accel-c
|
||||
this.treeid = treeid;
|
||||
this.copycol = copycol;
|
||||
this.rows = 0;
|
||||
this.tree = null;
|
||||
this.data = [ ];
|
||||
this.selection = null;
|
||||
this.sortcol = null;
|
||||
this.sortdir = 0;
|
||||
this.sortcol = -1;
|
||||
this.sortdir = false;
|
||||
}
|
||||
|
||||
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) { },
|
||||
getCellProperties: function(row, column, prop) { },
|
||||
getColumnProperties: function(column, prop) { },
|
||||
|
@ -166,9 +186,8 @@ const COPYCOL_META_CONTENT = 1;
|
|||
const COPYCOL_IMAGE = COL_IMAGE_ADDRESS;
|
||||
|
||||
// one nsITreeView for each tree in the window
|
||||
var gMetaView = new pageInfoTreeView(COPYCOL_META_CONTENT);
|
||||
var gImageView = new pageInfoTreeView(COPYCOL_IMAGE);
|
||||
|
||||
var gMetaView = new pageInfoTreeView('metatree', COPYCOL_META_CONTENT);
|
||||
var gImageView = new pageInfoTreeView('imagetree', COPYCOL_IMAGE);
|
||||
|
||||
var atomSvc = Components.classes["@mozilla.org/atom-service;1"]
|
||||
.getService(Components.interfaces.nsIAtomService);
|
||||
|
@ -187,6 +206,44 @@ gImageView.getCellProperties = function(row, col, props) {
|
|||
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 = { };
|
||||
|
||||
// localized strings (will be filled in when the document is loaded)
|
||||
|
@ -585,15 +642,8 @@ function addImage(url, type, alt, elem, isBg)
|
|||
catch(ex2) { }
|
||||
}
|
||||
|
||||
var sizeText;
|
||||
if (cacheEntryDescriptor) {
|
||||
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]);
|
||||
var dataSize = (cacheEntryDescriptor) ? cacheEntryDescriptor.dataSize : -1;
|
||||
gImageView.addRow([url, type, dataSize, alt, 1, elem, isBg]);
|
||||
|
||||
// Add the observer, only once.
|
||||
if (gImageView.data.length == 1) {
|
||||
|
@ -700,7 +750,10 @@ function getSelectedImage(tree)
|
|||
return null;
|
||||
|
||||
// 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
|
||||
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/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/feeds.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">
|
||||
<treecols>
|
||||
<treecol id="meta-name" label="&generalMetaName;"
|
||||
persist="width" flex="1"/>
|
||||
persist="width" flex="1"
|
||||
onclick="gMetaView.onPageMediaSort('meta-name');"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="meta-content" label="&generalMetaContent;"
|
||||
persist="width" flex="4"/>
|
||||
persist="width" flex="4"
|
||||
onclick="gMetaView.onPageMediaSort('meta-content');"/>
|
||||
</treecols>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
|
@ -218,19 +221,24 @@
|
|||
ondragstart="onBeginLinkDrag(event,'image-address','image-alt')">
|
||||
<treecols>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
|
|
|
@ -260,23 +260,24 @@
|
|||
value="&addDevice.showMeHow.label;"
|
||||
href="https://services.mozilla.com/sync/help/easy-setup"/>
|
||||
</description>
|
||||
<description>&addDevice.setup.enterCode.label;</description>
|
||||
<label value="&addDevice.setup.enterCode.label;"
|
||||
control="easySetupPIN1"/>
|
||||
<spacer flex="1"/>
|
||||
<vbox align="center" flex="1">
|
||||
<textbox id="easySetupPIN1"
|
||||
class="pin"
|
||||
value=""
|
||||
disabled="true"
|
||||
readonly="true"
|
||||
/>
|
||||
<textbox id="easySetupPIN2"
|
||||
class="pin"
|
||||
value=""
|
||||
disabled="true"
|
||||
readonly="true"
|
||||
/>
|
||||
<textbox id="easySetupPIN3"
|
||||
class="pin"
|
||||
value=""
|
||||
disabled="true"
|
||||
readonly="true"
|
||||
/>
|
||||
</vbox>
|
||||
<spacer flex="3"/>
|
||||
|
|
|
@ -632,7 +632,7 @@
|
|||
autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
|
||||
delete this.mBrowser.registeredOpenURI;
|
||||
}
|
||||
if (aLocation.spec != "about:blank") {
|
||||
if (!isBlankPageURL(aLocation.spec)) {
|
||||
autocomplete.registerOpenPage(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.
|
||||
// Let's try to unescape it using a character set
|
||||
// in case the URI is not ASCII.
|
||||
|
@ -1589,7 +1589,7 @@
|
|||
aTab.closing = true;
|
||||
this._removingTabs.push(aTab);
|
||||
if (newTab)
|
||||
this.addTab("about:blank", {skipAnimation: true});
|
||||
this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
|
||||
else
|
||||
this.tabContainer.updateVisibility();
|
||||
|
||||
|
@ -2375,10 +2375,6 @@
|
|||
onget="return this.mCurrentBrowser.contentViewerFile;"
|
||||
readonly="true"/>
|
||||
|
||||
<property name="documentCharsetInfo"
|
||||
onget="return this.mCurrentBrowser.documentCharsetInfo;"
|
||||
readonly="true"/>
|
||||
|
||||
<property name="contentDocument"
|
||||
onget="return this.mCurrentBrowser.contentDocument;"
|
||||
readonly="true"/>
|
||||
|
@ -3811,49 +3807,34 @@
|
|||
<binding id="tabbrowser-alltabs-popup"
|
||||
extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<method name="_menuItemOnCommand">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
gBrowser.selectedTab = aEvent.target.tab;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_tabOnAttrModified">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
var tab = aEvent.target;
|
||||
this._setMenuitemAttributes(tab.mCorrespondingMenuitem, tab);
|
||||
if (tab.mCorrespondingMenuitem)
|
||||
this._setMenuitemAttributes(tab.mCorrespondingMenuitem, tab);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_tabOnTabClose">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
var menuItem = aEvent.target.mCorrespondingMenuitem;
|
||||
if (menuItem)
|
||||
this.removeChild(menuItem);
|
||||
var tab = aEvent.target;
|
||||
if (tab.mCorrespondingMenuitem)
|
||||
this.removeChild(tab.mCorrespondingMenuitem);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="handleEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
if (!aEvent.isTrusted)
|
||||
return;
|
||||
|
||||
switch (aEvent.type) {
|
||||
case "command":
|
||||
this._menuItemOnCommand(aEvent);
|
||||
break;
|
||||
case "TabAttrModified":
|
||||
this._tabOnAttrModified(aEvent);
|
||||
break;
|
||||
case "TabClose":
|
||||
this._tabOnTabClose(aEvent);
|
||||
break;
|
||||
case "TabOpen":
|
||||
this._createTabMenuItem(aEvent.originalTarget);
|
||||
break;
|
||||
case "scroll":
|
||||
this._updateTabsVisibilityStatus();
|
||||
break;
|
||||
|
@ -3874,8 +3855,6 @@
|
|||
if (!curTab) // "Tab Groups" menuitem and its menuseparator
|
||||
continue;
|
||||
let curTabBO = curTab.boxObject;
|
||||
if (!curTabBO) // "Tabs From Other Computers" menuitem
|
||||
continue;
|
||||
if (curTabBO.screenX >= tabstripBO.screenX &&
|
||||
curTabBO.screenX + curTabBO.width <= tabstripBO.screenX + tabstripBO.width)
|
||||
this.childNodes[i].setAttribute("tabIsVisible", "true");
|
||||
|
@ -3896,14 +3875,10 @@
|
|||
|
||||
this._setMenuitemAttributes(menuItem, aTab);
|
||||
|
||||
// Keep some attributes of the menuitem in sync with its
|
||||
// corresponding tab (e.g. the tab label)
|
||||
aTab.mCorrespondingMenuitem = menuItem;
|
||||
menuItem.tab = aTab;
|
||||
menuItem.addEventListener("command", this, false);
|
||||
|
||||
this.appendChild(menuItem);
|
||||
return menuItem;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -3938,18 +3913,17 @@
|
|||
<handlers>
|
||||
<handler event="popupshowing">
|
||||
<![CDATA[
|
||||
// set up the menu popup
|
||||
var tabcontainer = gBrowser.tabContainer;
|
||||
let tabs = gBrowser.visibleTabs;
|
||||
|
||||
// Listen for changes in the tab bar.
|
||||
tabcontainer.addEventListener("TabOpen", this, false);
|
||||
tabcontainer.addEventListener("TabAttrModified", this, false);
|
||||
tabcontainer.addEventListener("TabClose", this, false);
|
||||
tabcontainer.mTabstrip.addEventListener("scroll", this, false);
|
||||
|
||||
let tabs = gBrowser.visibleTabs;
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
this._createTabMenuItem(tabs[i]);
|
||||
if (!tabs[i].pinned)
|
||||
this._createTabMenuItem(tabs[i]);
|
||||
}
|
||||
this._updateTabsVisibilityStatus();
|
||||
]]></handler>
|
||||
|
@ -3960,14 +3934,12 @@
|
|||
for (let i = this.childNodes.length - 1; i > 0; i--) {
|
||||
let menuItem = this.childNodes[i];
|
||||
if (menuItem.tab) {
|
||||
menuItem.removeEventListener("command", this, false);
|
||||
menuItem.tab.mCorrespondingMenuitem = null;
|
||||
this.removeChild(menuItem);
|
||||
}
|
||||
}
|
||||
var tabcontainer = gBrowser.tabContainer;
|
||||
tabcontainer.mTabstrip.removeEventListener("scroll", this, false);
|
||||
tabcontainer.removeEventListener("TabOpen", this, false);
|
||||
tabcontainer.removeEventListener("TabAttrModified", this, false);
|
||||
tabcontainer.removeEventListener("TabClose", this, false);
|
||||
]]></handler>
|
||||
|
@ -3988,6 +3960,11 @@
|
|||
XULBrowserWindow.setOverLink("", null);
|
||||
]]></handler>
|
||||
|
||||
<handler event="command"><![CDATA[
|
||||
if (event.target.tab)
|
||||
gBrowser.selectedTab = event.target.tab;
|
||||
]]></handler>
|
||||
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
|
|
|
@ -40,6 +40,10 @@ srcdir = @srcdir@
|
|||
VPATH = @srcdir@
|
||||
relativesrcdir = browser/base/content/test
|
||||
|
||||
DIRS += \
|
||||
newtab \
|
||||
$(NULL)
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -83,7 +87,7 @@ endif
|
|||
# browser_sanitize-download-history.js is bug 432425
|
||||
#
|
||||
# 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)
|
||||
|
||||
# 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_FILES = \
|
||||
head.js \
|
||||
browser_typeAheadFind.js \
|
||||
browser_keywordSearch.js \
|
||||
browser_allTabsPanel.js \
|
||||
|
@ -145,6 +150,7 @@ _BROWSER_FILES = \
|
|||
browser_bug567306.js \
|
||||
browser_zbug569342.js \
|
||||
browser_bug575561.js \
|
||||
browser_bug575830.js \
|
||||
browser_bug577121.js \
|
||||
browser_bug578534.js \
|
||||
browser_bug579872.js \
|
||||
|
@ -172,6 +178,7 @@ _BROWSER_FILES = \
|
|||
browser_bug655584.js \
|
||||
browser_bug664672.js \
|
||||
browser_bug710878.js \
|
||||
browser_bug719271.js \
|
||||
browser_canonizeURL.js \
|
||||
browser_findbarClose.js \
|
||||
browser_keywordBookmarklets.js \
|
||||
|
@ -213,6 +220,7 @@ _BROWSER_FILES = \
|
|||
browser_tabfocus.js \
|
||||
browser_tabs_isActive.js \
|
||||
browser_tabs_owner.js \
|
||||
browser_urlbarAutoFillTrimURLs.js \
|
||||
browser_urlbarCopying.js \
|
||||
browser_urlbarEnter.js \
|
||||
browser_urlbarTrimURLs.js \
|
||||
|
@ -228,6 +236,7 @@ _BROWSER_FILES = \
|
|||
discovery.html \
|
||||
domplate_test.js \
|
||||
moz.png \
|
||||
video.ogg \
|
||||
test_bug435035.html \
|
||||
test_bug462673.html \
|
||||
page_style_sample.html \
|
||||
|
|
|
@ -11,16 +11,16 @@ function test () {
|
|||
is(tooltip.getAttribute("label"), "This is a non-root SVG element 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("text3"), "should not 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"));
|
||||
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"));
|
||||
|
||||
|
|
|
@ -54,12 +54,10 @@ function thirdPageLoaded() {
|
|||
|
||||
function imageLoaded() {
|
||||
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;
|
||||
zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected");
|
||||
|
||||
executeSoon(imageZoomSwitch);
|
||||
}
|
||||
|
||||
function imageZoomSwitch() {
|
||||
|
@ -136,12 +134,10 @@ function navigate(direction, cb) {
|
|||
}
|
||||
|
||||
function afterZoom(cb) {
|
||||
let oldAPTS = FullZoom._applyPrefToSetting;
|
||||
FullZoom._applyPrefToSetting = function(value, browser) {
|
||||
if (!value)
|
||||
value = undefined;
|
||||
oldAPTS.call(FullZoom, value, browser);
|
||||
FullZoom._applyPrefToSetting = oldAPTS;
|
||||
let oldSZFB = ZoomManager.setZoomForBrowser;
|
||||
ZoomManager.setZoomForBrowser = function(browser, value) {
|
||||
oldSZFB.call(ZoomManager, browser, value);
|
||||
ZoomManager.setZoomForBrowser = oldSZFB;
|
||||
executeSoon(cb);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -43,19 +43,18 @@ function test() {
|
|||
}
|
||||
|
||||
function afterZoomAndLoad(cb) {
|
||||
let didLoad = didZoom = false;
|
||||
let didLoad = false;
|
||||
let didZoom = false;
|
||||
tabElm.linkedBrowser.addEventListener("load", function() {
|
||||
tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
didLoad = true;
|
||||
if (didZoom)
|
||||
executeSoon(cb);
|
||||
}, true);
|
||||
let oldAPTS = FullZoom._applyPrefToSetting;
|
||||
FullZoom._applyPrefToSetting = function(value, browser) {
|
||||
if (!value)
|
||||
value = undefined;
|
||||
oldAPTS.call(FullZoom, value, browser);
|
||||
FullZoom._applyPrefToSetting = oldAPTS;
|
||||
let oldSZFB = ZoomManager.setZoomForBrowser;
|
||||
ZoomManager.setZoomForBrowser = function(browser, value) {
|
||||
oldSZFB.call(ZoomManager, browser, value);
|
||||
ZoomManager.setZoomForBrowser = oldSZFB;
|
||||
didZoom = true;
|
||||
if (didLoad)
|
||||
executeSoon(cb);
|
||||
|
|
|
@ -37,7 +37,8 @@ const TEST_PAGE = "/browser/browser/base/content/test/dummy_page.html";
|
|||
var gTestTab, gBgTab, gTestZoom;
|
||||
|
||||
function afterZoomAndLoad(aCallback, aTab) {
|
||||
let didLoad = didZoom = false;
|
||||
let didLoad = false;
|
||||
let didZoom = false;
|
||||
aTab.linkedBrowser.addEventListener("load", function() {
|
||||
aTab.linkedBrowser.removeEventListener("load", arguments.callee, 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);
|
||||
|
||||
function isUndoCloseEnabled() {
|
||||
document.popupNode = gBrowser.tabs[0];
|
||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
||||
TabContextMenu.contextTab = null;
|
||||
updateTabContextMenu();
|
||||
return !document.getElementById("context_undoCloseTab").disabled;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
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) {
|
||||
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() {
|
||||
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 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)
|
||||
.loadSubScript("chrome://browser/content/sanitize.js");
|
||||
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||
let Sanitizer = tempScope.Sanitizer;
|
||||
|
||||
const pluginHostIface = 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) {
|
||||
is_chrome_visible();
|
||||
|
||||
info("Page load");
|
||||
load_page(aURL, aCanHide, function() {
|
||||
info("Switch away");
|
||||
|
@ -163,5 +162,30 @@ function run_http_test_2() {
|
|||
// Should not hide the chrome
|
||||
function run_chrome_about_test_2() {
|
||||
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.
|
||||
gPrefService.setBoolPref(branch + "latched", oldLatchedValue);
|
||||
for (dir in cmd)
|
||||
for (let dir in cmd)
|
||||
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
|
||||
// transitions between different states.
|
||||
let gForward = true;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Bug 474792 - Clear "Never remember passwords for this site" when
|
||||
// clearing site-specific settings in Clear Recent History dialog
|
||||
|
||||
let tempScope = {};
|
||||
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() {
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// Bug 380852 - Delete permission manager entries in Clear Recent History
|
||||
|
||||
let tempScope = {};
|
||||
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() {
|
||||
|
||||
|
|
|
@ -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 formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
|
||||
|
||||
let tempScope = {};
|
||||
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() {
|
||||
|
||||
|
|
|
@ -50,9 +50,10 @@
|
|||
* browser/base/content/test/browser_sanitize-timespans.js.
|
||||
*/
|
||||
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader).
|
||||
loadSubScript("chrome://browser/content/sanitize.js");
|
||||
let tempScope = {};
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||
let Sanitizer = tempScope.Sanitizer;
|
||||
|
||||
const dm = Cc["@mozilla.org/download-manager;1"].
|
||||
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() {
|
||||
document.popupNode = gBrowser.selectedTab;
|
||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
||||
TabContextMenu.contextTab = null;
|
||||
updateTabContextMenu();
|
||||
return document.getElementById("Browser:BookmarkAllTabs").getAttribute("disabled") == "true";
|
||||
}
|
||||
|
||||
function Hidden() {
|
||||
document.popupNode = gBrowser.selectedTab;
|
||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
||||
TabContextMenu.contextTab = null;
|
||||
updateTabContextMenu();
|
||||
return document.getElementById("context_bookmarkAllTabs").hidden;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ function test() {
|
|||
is(gBrowser.visibleTabs.length, 2, "there are now two visible 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_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");
|
||||
|
||||
// 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_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");
|
||||
|
||||
// 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");
|
||||
|
||||
// Show all tabs
|
||||
|
@ -72,16 +72,9 @@ function test() {
|
|||
gBrowser.showOnlyTheseTabs(allTabs);
|
||||
|
||||
// Check the context menu now
|
||||
popup(testTab);
|
||||
updateTabContextMenu(testTab);
|
||||
is(document.getElementById("context_closeOtherTabs").disabled, false, "Close Other Tabs is enabled");
|
||||
|
||||
gBrowser.removeTab(testTab);
|
||||
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();
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче