зеркало из https://github.com/mozilla/gecko-dev.git
Merge commit for bug 210197
This commit is contained in:
Коммит
8c80506f1c
|
@ -19,8 +19,7 @@
|
|||
^security/manager/\.nss\.checkout$
|
||||
|
||||
# Build directories
|
||||
^obj-
|
||||
^objdir-
|
||||
^obj
|
||||
|
||||
# Build directories for js shell
|
||||
_DBG\.OBJ/
|
||||
|
|
6
.hgtags
6
.hgtags
|
@ -2,3 +2,9 @@ df7a3c8ffeeaba229067efee5a20e21dae0dd877 MOZILLA_1_9_a4_BASE
|
|||
4209e16b58411750ac73f761023e46b76b793e2c MOZILLA_1_9_a6_BASE
|
||||
66a5c7bce7ee86a820d3c0d54fa07cb719be751c MOZILLA_1_9_a7_BASE
|
||||
caeba7562e495a9f604984df0b48b6f99bec3e2e FENNEC_M4
|
||||
9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_RELEASE
|
||||
9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_BUILD1
|
||||
c1d7e318a27574c995631fec166ad42672475702 FIREFOX_3_1a1_BUILD2
|
||||
c1d7e318a27574c995631fec166ad42672475702 FIREFOX_3_1a1_RELEASE
|
||||
afc4ee509d9ca3bb4031015c3c22963dcb4b7e7f FIREFOX_3_1a1_RELEASE
|
||||
afc4ee509d9ca3bb4031015c3c22963dcb4b7e7f FIREFOX_3_1a1_BUILD2
|
||||
|
|
|
@ -66,6 +66,11 @@ ifdef MOZ_MEMORY
|
|||
tier_base_dirs += memory/jemalloc
|
||||
endif
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
# Additional makefile targets to call automated test suites
|
||||
include $(topsrcdir)/testing/testsuite-targets.mk
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
|
||||
|
||||
TIERS += testharness
|
||||
|
|
|
@ -94,7 +94,10 @@ EXTRA_DSO_LDOPTS += $(MOZ_GTK2_LIBS)
|
|||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
OS_LIBS += oleaut32.lib
|
||||
OS_LIBS += \
|
||||
oleaut32.lib \
|
||||
version.lib \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -92,35 +92,27 @@ cpp_quote("")
|
|||
|
||||
import "objidl.idl";
|
||||
import "oaidl.idl";
|
||||
|
||||
|
||||
const long DISPID_DOC_URL = -5904;
|
||||
const long DISPID_DOC_TITLE = -5905;
|
||||
const long DISPID_DOC_MIMETYPE = -5906;
|
||||
const long DISPID_DOC_DOCTYPE = -5907;
|
||||
const long DISPID_DOC_NAMESPACE = -5908;
|
||||
const long DISPID_DOC_MEDIATYPES = -5909;
|
||||
|
||||
[object, uuid(0D68D6D0-D93D-4d08-A30D-F00DD1F45B24)]
|
||||
interface ISimpleDOMDocument : IUnknown
|
||||
{
|
||||
[propget, id(DISPID_DOC_URL)] HRESULT URL(
|
||||
[propget] HRESULT URL(
|
||||
[out, retval] BSTR * url
|
||||
);
|
||||
[propget, id(DISPID_DOC_TITLE)] HRESULT title(
|
||||
[propget] HRESULT title(
|
||||
[out, retval] BSTR * title
|
||||
);
|
||||
[propget, id(DISPID_DOC_MIMETYPE)] HRESULT mimeType(
|
||||
[propget] HRESULT mimeType(
|
||||
[out, retval] BSTR * mimeType
|
||||
);
|
||||
[propget, id(DISPID_DOC_DOCTYPE)] HRESULT docType(
|
||||
[propget] HRESULT docType(
|
||||
[out, retval] BSTR * docType
|
||||
);
|
||||
[propget, id(DISPID_DOC_NAMESPACE)] HRESULT nameSpaceURIForID(
|
||||
[propget] HRESULT nameSpaceURIForID(
|
||||
[in] short nameSpaceID,
|
||||
[out, retval] BSTR * nameSpaceURI
|
||||
);
|
||||
[propput, id(DISPID_DOC_MEDIATYPES)] HRESULT alternateViewMediaTypes(
|
||||
[propput] HRESULT alternateViewMediaTypes(
|
||||
[in] BSTR * commaSeparatedMediaTypes
|
||||
);
|
||||
}
|
||||
|
|
|
@ -133,13 +133,9 @@ cpp_quote("")
|
|||
|
||||
import "objidl.idl";
|
||||
import "oaidl.idl";
|
||||
|
||||
const long DISPID_NODE_NODEINFO = -5900;
|
||||
const long DISPID_NODE_ATTRIBUTES = -5901;
|
||||
const long DISPID_NODE_ATTRIBUTESFORNAMES = -5902;
|
||||
const long DISPID_NODE_COMPSTYLE = -5903;
|
||||
const long DISPID_NODE_COMPSTYLEFORPROPS = -5904;
|
||||
const long DISPID_NODE_LANGUAGE = -5905;
|
||||
|
||||
import "ISimpleDOMText.idl";
|
||||
import "ISimpleDOMDocument.idl";
|
||||
|
||||
[object, uuid(1814ceeb-49e2-407f-af99-fa755a7d2607)]
|
||||
interface ISimpleDOMNode : IUnknown
|
||||
|
@ -157,7 +153,7 @@ interface ISimpleDOMNode : IUnknown
|
|||
const unsigned short NODETYPE_DOCUMENT_FRAGMENT = 11;
|
||||
const unsigned short NODETYPE_NOTATION = 12;
|
||||
|
||||
[propget, id(DISPID_NODE_NODEINFO)] HRESULT nodeInfo(
|
||||
[propget] HRESULT nodeInfo(
|
||||
[out] BSTR *nodeName, // for performance returns NULL for text nodes (true nodeName would be "#text")
|
||||
[out] short *nameSpaceID,
|
||||
[out] BSTR *nodeValue,
|
||||
|
@ -166,7 +162,7 @@ interface ISimpleDOMNode : IUnknown
|
|||
[out, retval] unsigned short *nodeType
|
||||
);
|
||||
|
||||
[propget, id(DISPID_NODE_ATTRIBUTES)] HRESULT attributes(
|
||||
[propget] HRESULT attributes(
|
||||
[in] unsigned short maxAttribs,
|
||||
[out, size_is(maxAttribs), length_is(*numAttribs)] BSTR *attribNames,
|
||||
[out, size_is(maxAttribs), length_is(*numAttribs)] short *nameSpaceID,
|
||||
|
@ -174,14 +170,14 @@ interface ISimpleDOMNode : IUnknown
|
|||
[out, retval] unsigned short *numAttribs
|
||||
);
|
||||
|
||||
[propget, id(DISPID_NODE_ATTRIBUTESFORNAMES)] HRESULT attributesForNames(
|
||||
[propget] HRESULT attributesForNames(
|
||||
[in] unsigned short numAttribs,
|
||||
[in, size_is(numAttribs), length_is(numAttribs)] BSTR *attribNames,
|
||||
[in, size_is(numAttribs), length_is(numAttribs)] short *nameSpaceID,
|
||||
[out, retval, size_is(numAttribs), length_is(numAttribs)] BSTR *attribValues
|
||||
);
|
||||
|
||||
[propget, id(DISPID_NODE_COMPSTYLE)] HRESULT computedStyle(
|
||||
[propget] HRESULT computedStyle(
|
||||
[in] unsigned short maxStyleProperties,
|
||||
[in] boolean useAlternateView, // If TRUE, returns properites for media as set in nsIDOMDocument::set_alternateViewMediaTypes
|
||||
[out, size_is(maxStyleProperties), length_is(*numStyleProperties)] BSTR *styleProperties,
|
||||
|
@ -189,7 +185,7 @@ interface ISimpleDOMNode : IUnknown
|
|||
[out, retval] unsigned short *numStyleProperties
|
||||
);
|
||||
|
||||
[propget, id(DISPID_NODE_COMPSTYLEFORPROPS)] HRESULT computedStyleForProperties(
|
||||
[propget] HRESULT computedStyleForProperties(
|
||||
[in] unsigned short numStyleProperties,
|
||||
[in] boolean useAlternateView, // If TRUE, returns properites for media as set in nsIDOMDocument::set_alternateViewMediaTypes
|
||||
[in, size_is(numStyleProperties), length_is(numStyleProperties)] BSTR *styleProperties,
|
||||
|
@ -210,7 +206,18 @@ interface ISimpleDOMNode : IUnknown
|
|||
|
||||
[propget, local] HRESULT localInterface([out][retval] void **localInterface);
|
||||
|
||||
[propget, id(DISPID_NODE_LANGUAGE)] HRESULT language([out, retval] BSTR *language);
|
||||
[propget] HRESULT language([out, retval] BSTR *language);
|
||||
}
|
||||
|
||||
|
||||
[
|
||||
uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea),
|
||||
helpstring("ISimpleDOM Type Library")
|
||||
]
|
||||
library ISimpleDOM
|
||||
{
|
||||
interface ISimpleDOMNode;
|
||||
interface ISimpleDOMText;
|
||||
interface ISimpleDOMDocument;
|
||||
};
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ done_gen: ISimpleDOMNode.idl \
|
|||
ISimpleDOMDocument.idl \
|
||||
ISimpleDOMText.idl
|
||||
|
||||
$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMNode.idl
|
||||
$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/ISimpleDOMNode.idl
|
||||
$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMDocument.idl
|
||||
$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMText.idl
|
||||
touch $@
|
||||
|
|
|
@ -44,8 +44,9 @@
|
|||
typedef long nsAccessibleTextBoundary;
|
||||
|
||||
interface nsIAccessible;
|
||||
interface nsIPersistentProperties;
|
||||
|
||||
[scriptable, uuid(caa4f543-070e-4705-8428-2e53575c41bb)]
|
||||
[scriptable, uuid(0f4633b1-550c-4b50-8c04-0eb1005eef2f)]
|
||||
interface nsIAccessibleText : nsISupports
|
||||
{
|
||||
// In parameters for character offsets:
|
||||
|
@ -102,13 +103,24 @@ interface nsIAccessibleText : nsISupports
|
|||
wchar getCharacterAtOffset (in long offset);
|
||||
|
||||
/**
|
||||
* Get the accessible and start/end offsets around the given offset.
|
||||
* This accessible get return the DOM node and layout frame
|
||||
* with the uniform attributes for this range of text
|
||||
* Get the accessible start/end offsets around the given offset,
|
||||
* return the text attributes for this range of text.
|
||||
*
|
||||
* @param includeDefAttrs [in] points whether text attributes applied to
|
||||
* the entire accessible should be included or not.
|
||||
* @param offset [in] text offset
|
||||
* @param rangeStartOffset [out] start offset of the range of text
|
||||
* @param rangeEndOffset [out] end offset of the range of text
|
||||
*/
|
||||
nsIAccessible getAttributeRange (in long offset,
|
||||
out long rangeStartOffset,
|
||||
out long rangeEndOffset);
|
||||
nsIPersistentProperties getTextAttributes(in boolean includeDefAttrs,
|
||||
in long offset,
|
||||
out long rangeStartOffset,
|
||||
out long rangeEndOffset);
|
||||
|
||||
/**
|
||||
* Return the text attributes that apply to the entire accessible.
|
||||
*/
|
||||
readonly attribute nsIPersistentProperties defaultTextAttributes;
|
||||
|
||||
/**
|
||||
* Returns the bounding box of the specified position.
|
||||
|
@ -223,11 +235,6 @@ interface nsIAccessibleText : nsISupports
|
|||
(since not every text component will allow every operation):
|
||||
setSelectionBounds, addSelection, removeSelection, setCaretOffset.
|
||||
|
||||
getRangeAttributes defined to return an nsISupports
|
||||
interface instead of a pango specific data structure.
|
||||
It may be that some other return type is more appropriate
|
||||
for mozilla text attributes.
|
||||
|
||||
we assume that all text components support the idea of
|
||||
a caret offset, whether visible or "virtual". If this
|
||||
isn't the case, caretOffset can be made readonly and
|
||||
|
|
|
@ -786,13 +786,50 @@ getRoleCB(AtkObject *aAtkObj)
|
|||
return aAtkObj->role;
|
||||
}
|
||||
|
||||
AtkAttributeSet*
|
||||
ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes)
|
||||
{
|
||||
if (!aAttributes)
|
||||
return nsnull;
|
||||
|
||||
AtkAttributeSet *objAttributeSet = nsnull;
|
||||
nsCOMPtr<nsISimpleEnumerator> propEnum;
|
||||
nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
PRBool hasMore;
|
||||
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> sup;
|
||||
rv = propEnum->GetNext(getter_AddRefs(sup));
|
||||
NS_ENSURE_SUCCESS(rv, objAttributeSet);
|
||||
|
||||
nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
|
||||
NS_ENSURE_TRUE(propElem, objAttributeSet);
|
||||
|
||||
nsCAutoString name;
|
||||
rv = propElem->GetKey(name);
|
||||
NS_ENSURE_SUCCESS(rv, objAttributeSet);
|
||||
|
||||
nsAutoString value;
|
||||
rv = propElem->GetValue(value);
|
||||
NS_ENSURE_SUCCESS(rv, objAttributeSet);
|
||||
|
||||
AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
|
||||
objAttr->name = g_strdup(name.get());
|
||||
objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
|
||||
objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
|
||||
}
|
||||
|
||||
//libspi will free it
|
||||
return objAttributeSet;
|
||||
}
|
||||
|
||||
AtkAttributeSet *
|
||||
GetAttributeSet(nsIAccessible* aAccessible)
|
||||
{
|
||||
AtkAttributeSet *objAttributeSet = nsnull;
|
||||
nsCOMPtr<nsIPersistentProperties> attributes;
|
||||
aAccessible->GetAttributes(getter_AddRefs(attributes));
|
||||
|
||||
|
||||
if (attributes) {
|
||||
// Deal with attributes that we only need to expose in ATK
|
||||
PRUint32 state;
|
||||
|
@ -804,33 +841,10 @@ GetAttributeSet(nsIAccessible* aAccessible)
|
|||
oldValueUnused);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> propEnum;
|
||||
nsresult rv = attributes->Enumerate(getter_AddRefs(propEnum));
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
PRBool hasMore;
|
||||
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> sup;
|
||||
rv = propEnum->GetNext(getter_AddRefs(sup));
|
||||
nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
|
||||
NS_ENSURE_TRUE(propElem, nsnull);
|
||||
|
||||
nsCAutoString name;
|
||||
rv = propElem->GetKey(name);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
nsAutoString value;
|
||||
rv = propElem->GetValue(value);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
AtkAttribute *objAttribute = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
|
||||
objAttribute->name = g_strdup(name.get());
|
||||
objAttribute->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
|
||||
objAttributeSet = g_slist_prepend(objAttributeSet, objAttribute);
|
||||
}
|
||||
return ConvertToAtkAttributeSet(attributes);
|
||||
}
|
||||
|
||||
return objAttributeSet;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
AtkAttributeSet *
|
||||
|
@ -855,8 +869,9 @@ getParentCB(AtkObject *aAtkObj)
|
|||
if (NS_FAILED(rv) || !accParent)
|
||||
return nsnull;
|
||||
|
||||
atk_object_set_parent(aAtkObj,
|
||||
nsAccessibleWrap::GetAtkObject(accParent));
|
||||
AtkObject *parent = nsAccessibleWrap::GetAtkObject(accParent);
|
||||
if (parent)
|
||||
atk_object_set_parent(aAtkObj, parent);
|
||||
}
|
||||
return aAtkObj->accessible_parent;
|
||||
}
|
||||
|
@ -1197,6 +1212,13 @@ nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
|
|||
caretOffset);
|
||||
} break;
|
||||
|
||||
case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
|
||||
MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_ATTRIBUTE_CHANGED\n"));
|
||||
|
||||
g_signal_emit_by_name(atkObj,
|
||||
"text-attributes-changed");
|
||||
break;
|
||||
|
||||
case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
|
||||
MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_MODEL_CHANGED\n"));
|
||||
g_signal_emit_by_name(atkObj, "model_changed");
|
||||
|
|
|
@ -41,8 +41,9 @@
|
|||
|
||||
#include "nsMaiInterfaceText.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIPersistentProperties2.h"
|
||||
|
||||
AtkAttributeSet * GetAttributeSet(nsIAccessible* aAccessible);
|
||||
AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
|
||||
|
||||
void
|
||||
textInterfaceInitCB(AtkTextIface *aIface)
|
||||
|
@ -245,6 +246,9 @@ getRunAttributesCB(AtkText *aText, gint aOffset,
|
|||
gint *aStartOffset,
|
||||
gint *aEndOffset)
|
||||
{
|
||||
*aStartOffset = -1;
|
||||
*aEndOffset = -1;
|
||||
|
||||
nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (!accWrap)
|
||||
return nsnull;
|
||||
|
@ -254,24 +258,37 @@ getRunAttributesCB(AtkText *aText, gint aOffset,
|
|||
getter_AddRefs(accText));
|
||||
NS_ENSURE_TRUE(accText, nsnull);
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessibleWithAttrs;
|
||||
nsCOMPtr<nsIPersistentProperties> attributes;
|
||||
PRInt32 startOffset = 0, endOffset = 0;
|
||||
nsresult rv =
|
||||
accText->GetAttributeRange(aOffset, &startOffset, &endOffset,
|
||||
getter_AddRefs(accessibleWithAttrs));
|
||||
nsresult rv = accText->GetTextAttributes(PR_FALSE, aOffset,
|
||||
&startOffset, &endOffset,
|
||||
getter_AddRefs(attributes));
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
*aStartOffset = startOffset;
|
||||
*aEndOffset = endOffset;
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
return GetAttributeSet(accessibleWithAttrs);
|
||||
return ConvertToAtkAttributeSet(attributes);
|
||||
}
|
||||
|
||||
AtkAttributeSet *
|
||||
getDefaultAttributesCB(AtkText *aText)
|
||||
{
|
||||
/* not supported ??? */
|
||||
return nsnull;
|
||||
nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (!accWrap)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIAccessibleText> accText;
|
||||
accWrap->QueryInterface(NS_GET_IID(nsIAccessibleText),
|
||||
getter_AddRefs(accText));
|
||||
NS_ENSURE_TRUE(accText, nsnull);
|
||||
|
||||
nsCOMPtr<nsIPersistentProperties> attributes;
|
||||
nsresult rv = accText->GetDefaultTextAttributes(getter_AddRefs(attributes));
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
return ConvertToAtkAttributeSet(attributes);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -90,6 +90,7 @@ CPPSRCS = \
|
|||
nsApplicationAccessible.cpp \
|
||||
nsCaretAccessible.cpp \
|
||||
nsTextAccessible.cpp \
|
||||
nsTextUtils.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
|
|
|
@ -112,12 +112,23 @@ nsIAccessibilityService *nsAccessNode::GetAccService()
|
|||
* Class nsAccessNode
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------
|
||||
// construction
|
||||
//-----------------------------------------------------
|
||||
NS_IMPL_QUERY_INTERFACE2(nsAccessNode, nsIAccessNode, nsPIAccessNode)
|
||||
NS_IMPL_ADDREF(nsAccessNode)
|
||||
NS_IMPL_RELEASE_WITH_DESTROY(nsAccessNode, LastRelease())
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccessible. nsISupports
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_0(nsAccessNode)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccessNode)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAccessNode)
|
||||
NS_INTERFACE_MAP_ENTRY(nsPIAccessNode)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessNode)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsAccessNode, nsIAccessNode)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsAccessNode, nsIAccessNode,
|
||||
LastRelease())
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccessible. Constructor
|
||||
|
||||
nsAccessNode::nsAccessNode(nsIDOMNode *aNode, nsIWeakReference* aShell):
|
||||
mDOMNode(aNode), mWeakShell(aShell)
|
||||
|
@ -191,8 +202,7 @@ NS_IMETHODIMP nsAccessNode::Init()
|
|||
// so that nsDocAccessible::RefreshNodes() can find the anonymous subtree to release when
|
||||
// the root node goes away
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
|
||||
if (content && (content->IsNativeAnonymous() ||
|
||||
content->GetBindingParent())) {
|
||||
if (content && content->IsInAnonymousSubtree()) {
|
||||
// Specific examples of where this is used: <input type="file"> and <xul:findbar>
|
||||
nsCOMPtr<nsIAccessible> parentAccessible;
|
||||
docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, getter_AddRefs(parentAccessible));
|
||||
|
@ -876,10 +886,7 @@ nsAccessNode::GetLanguage(nsAString& aLanguage)
|
|||
}
|
||||
}
|
||||
|
||||
nsIContent *walkUp = content;
|
||||
while (walkUp && !walkUp->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::lang, aLanguage)) {
|
||||
walkUp = walkUp->GetParent();
|
||||
}
|
||||
nsAccUtils::GetLanguageFor(content, nsnull, aLanguage);
|
||||
|
||||
if (aLanguage.IsEmpty()) { // Nothing found, so use document's language
|
||||
nsIDocument *doc = content->GetOwnerDoc();
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAccessibilityAtoms.h"
|
||||
#include "nsAccessibilityUtils.h"
|
||||
|
||||
#include "nsIAccessibleTypes.h"
|
||||
#include "nsIAccessNode.h"
|
||||
#include "nsIContent.h"
|
||||
|
@ -72,13 +74,16 @@ class nsIDocShellTreeItem;
|
|||
typedef nsInterfaceHashtable<nsVoidPtrHashKey, nsIAccessNode>
|
||||
nsAccessNodeHashtable;
|
||||
|
||||
class nsAccessNode: public nsIAccessNode, public nsPIAccessNode
|
||||
class nsAccessNode: public nsIAccessNode,
|
||||
public nsPIAccessNode
|
||||
{
|
||||
public: // construction, destruction
|
||||
nsAccessNode(nsIDOMNode *, nsIWeakReference* aShell);
|
||||
virtual ~nsAccessNode();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsAccessNode, nsIAccessNode)
|
||||
|
||||
NS_DECL_NSIACCESSNODE
|
||||
NS_DECL_NSPIACCESSNODE
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ ACCESSIBILITY_ATOM(tooltip, "tooltip") // XUL
|
|||
ACCESSIBILITY_ATOM(tr, "tr")
|
||||
ACCESSIBILITY_ATOM(ul, "ul")
|
||||
|
||||
// Alphabetical list of attributes
|
||||
// Alphabetical list of attributes (DOM)
|
||||
ACCESSIBILITY_ATOM(acceltext, "acceltext")
|
||||
ACCESSIBILITY_ATOM(accesskey, "accesskey")
|
||||
ACCESSIBILITY_ATOM(alt, "alt")
|
||||
|
@ -186,6 +186,10 @@ ACCESSIBILITY_ATOM(tooltiptext, "tooltiptext")
|
|||
ACCESSIBILITY_ATOM(type, "type")
|
||||
ACCESSIBILITY_ATOM(value, "value")
|
||||
|
||||
// Alphabetical list of text attributes (AT API)
|
||||
ACCESSIBILITY_ATOM(invalid, "invalid")
|
||||
ACCESSIBILITY_ATOM(language, "language")
|
||||
|
||||
// ARIA (DHTML accessibility) attributes
|
||||
// Also add to nsARIAMap.cpp and nsARIAMap.h
|
||||
// ARIA role attribute
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "nsIEventStateManager.h"
|
||||
#include "nsISelection2.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsGUIEvent.h"
|
||||
|
||||
#include "nsContentCID.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
@ -291,6 +292,48 @@ nsAccUtils::HasListener(nsIContent *aContent, const nsAString& aEventType)
|
|||
return listenerManager && listenerManager->HasListenersFor(aEventType);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsAccUtils::DispatchMouseEvent(PRUint32 aEventType,
|
||||
nsIPresShell *aPresShell,
|
||||
nsIContent *aContent)
|
||||
{
|
||||
nsIFrame *frame = aPresShell->GetPrimaryFrameFor(aContent);
|
||||
if (!frame)
|
||||
return PR_FALSE;
|
||||
|
||||
nsIFrame* rootFrame = aPresShell->GetRootFrame();
|
||||
if (!rootFrame)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIWidget> rootWidget = rootFrame->GetWindow();
|
||||
if (!rootWidget)
|
||||
return PR_FALSE;
|
||||
|
||||
// Compute x and y coordinates.
|
||||
nsPoint point = frame->GetOffsetToExternal(rootFrame);
|
||||
nsSize size = frame->GetSize();
|
||||
|
||||
nsPresContext* presContext = aPresShell->GetPresContext();
|
||||
|
||||
PRInt32 x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
|
||||
PRInt32 y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
|
||||
|
||||
// Fire mouse event.
|
||||
nsMouseEvent event(PR_TRUE, aEventType, rootWidget,
|
||||
nsMouseEvent::eReal, nsMouseEvent::eNormal);
|
||||
|
||||
event.refPoint = nsIntPoint(x, y);
|
||||
|
||||
event.clickCount = 1;
|
||||
event.button = nsMouseEvent::eLeftButton;
|
||||
event.time = PR_IntervalNow();
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
aPresShell->HandleEventWithTarget(&event, frame, aContent, &status);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsAccUtils::GetAccessKeyFor(nsIContent *aContent)
|
||||
{
|
||||
|
@ -340,6 +383,24 @@ nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
|
|||
return pAccessible->FireAccessibleEvent(event);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMElement>
|
||||
nsAccUtils::GetDOMElementFor(nsIDOMNode *aNode)
|
||||
{
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
|
||||
|
||||
nsIDOMElement *element = nsnull;
|
||||
if (node->IsNodeOfType(nsINode::eELEMENT))
|
||||
CallQueryInterface(node, &element);
|
||||
else if (node->IsNodeOfType(nsINode::eTEXT))
|
||||
CallQueryInterface(node->GetNodeParent(), &element);
|
||||
else if (node->IsNodeOfType(nsINode::eDOCUMENT)) {
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(node));
|
||||
domDoc->GetDocumentElement(&element);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
|
||||
nsIDOMNode *aPossibleDescendantNode)
|
||||
|
@ -774,11 +835,9 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode,
|
|||
nsIAtom *aTagName,
|
||||
PRUint32 aAncestorLevelsToSearch)
|
||||
{
|
||||
nsCOMPtr<nsIContent> binding;
|
||||
nsAutoString controlID;
|
||||
if (!nsAccUtils::GetID(aForNode, controlID)) {
|
||||
binding = aForNode->GetBindingParent();
|
||||
if (binding == aForNode)
|
||||
if (!aForNode->IsInAnonymousSubtree())
|
||||
return nsnull;
|
||||
|
||||
aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
|
||||
|
@ -787,6 +846,7 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode,
|
|||
}
|
||||
|
||||
// Look for label in subtrees of nearby ancestors
|
||||
nsCOMPtr<nsIContent> binding(aForNode->GetBindingParent());
|
||||
PRUint32 count = 0;
|
||||
nsIContent *labelContent = nsnull;
|
||||
nsIContent *prevSearched = nsnull;
|
||||
|
@ -921,6 +981,19 @@ nsAccUtils::FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsAccUtils::GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent,
|
||||
nsAString& aLanguage)
|
||||
{
|
||||
aLanguage.Truncate();
|
||||
|
||||
nsIContent *walkUp = aContent;
|
||||
while (walkUp && walkUp != aRootContent &&
|
||||
!walkUp->GetAttr(kNameSpaceID_None,
|
||||
nsAccessibilityAtoms::lang, aLanguage))
|
||||
walkUp = walkUp->GetParent();
|
||||
}
|
||||
|
||||
nsRoleMapEntry*
|
||||
nsAccUtils::GetRoleMapEntry(nsIDOMNode *aNode)
|
||||
{
|
||||
|
|
|
@ -124,6 +124,17 @@ public:
|
|||
*/
|
||||
static PRBool HasListener(nsIContent *aContent, const nsAString& aEventType);
|
||||
|
||||
/**
|
||||
* Send mouse events to the given element.
|
||||
*
|
||||
* @param aEventType an event type (see nsGUIEvent.h for constants)
|
||||
* @param aPresShell the presshell for the given element
|
||||
* @param aContent the element element
|
||||
*/
|
||||
static PRBool DispatchMouseEvent(PRUint32 aEventType,
|
||||
nsIPresShell *aPresShell,
|
||||
nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* Return an accesskey registered on the given element by
|
||||
* nsIEventStateManager or 0 if there is no registered accesskey.
|
||||
|
@ -138,6 +149,16 @@ public:
|
|||
static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
|
||||
PRBool aIsAsynch = PR_FALSE);
|
||||
|
||||
/**
|
||||
* Return DOM element related with the given node, i.e.
|
||||
* a) itself if it is DOM element
|
||||
* b) parent element if it is text node
|
||||
* c) document element if it is document node.
|
||||
*
|
||||
* @param aNode [in] the given DOM node
|
||||
*/
|
||||
static already_AddRefed<nsIDOMElement> GetDOMElementFor(nsIDOMNode *aNode);
|
||||
|
||||
/**
|
||||
* Is the first passed in node an ancestor of the second?
|
||||
* Note: A node is not considered to be the ancestor of itself.
|
||||
|
@ -302,6 +323,16 @@ public:
|
|||
*/
|
||||
static PRBool IsXLink(nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* Returns language for the given node.
|
||||
*
|
||||
* @param aContent [in] the given node
|
||||
* @param aRootContent [in] container of the given node
|
||||
* @param aLanguage [out] language
|
||||
*/
|
||||
static void GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent,
|
||||
nsAString& aLanguage);
|
||||
|
||||
/**
|
||||
* Get the role map entry for a given DOM node. This will use the first
|
||||
* ARIA role if the role attribute provides a space delimited list of roles.
|
||||
|
|
|
@ -140,9 +140,23 @@ nsAccessibleDOMStringList::Contains(const nsAString& aString, PRBool *aResult)
|
|||
* Class nsAccessible
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------
|
||||
// construction
|
||||
//-----------------------------------------------------
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccessible. nsISupports
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccessible)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsAccessible, nsAccessNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNextSibling)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsAccessible, nsAccessNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNextSibling)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsAccessible, nsAccessNode)
|
||||
NS_IMPL_RELEASE_INHERITED(nsAccessible, nsAccessNode)
|
||||
|
||||
|
@ -188,7 +202,12 @@ nsresult nsAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
// Custom-built QueryInterface() knows when we support nsIAccessibleSelectable
|
||||
// based on role attribute and aria-multiselectable
|
||||
*aInstancePtr = nsnull;
|
||||
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
|
||||
*aInstancePtr = &NS_CYCLE_COLLECTION_NAME(nsAccessible);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIAccessible))) {
|
||||
*aInstancePtr = static_cast<nsIAccessible*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
|
@ -483,7 +502,7 @@ NS_IMETHODIMP nsAccessible::SetFirstChild(nsIAccessible *aFirstChild)
|
|||
|
||||
NS_IMETHODIMP nsAccessible::SetNextSibling(nsIAccessible *aNextSibling)
|
||||
{
|
||||
mNextSibling = aNextSibling? aNextSibling: DEAD_END_ACCESSIBLE;
|
||||
mNextSibling = aNextSibling;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -538,15 +557,13 @@ NS_IMETHODIMP nsAccessible::InvalidateChildren()
|
|||
// CacheChildren() is called.
|
||||
// Note: we don't want to start creating accessibles at this point,
|
||||
// so don't use GetNextSibling() here. (bug 387252)
|
||||
nsAccessible* child = static_cast<nsAccessible*>(mFirstChild);
|
||||
nsAccessible* child = static_cast<nsAccessible*>(mFirstChild.get());
|
||||
while (child) {
|
||||
child->mParent = nsnull;
|
||||
if (child->mNextSibling == DEAD_END_ACCESSIBLE) {
|
||||
break;
|
||||
}
|
||||
nsIAccessible *next = child->mNextSibling;
|
||||
|
||||
nsCOMPtr<nsIAccessible> next = child->mNextSibling;
|
||||
child->mNextSibling = nsnull;
|
||||
child = static_cast<nsAccessible*>(next);
|
||||
child = static_cast<nsAccessible*>(next.get());
|
||||
}
|
||||
|
||||
mAccChildCount = eChildCountUninitialized;
|
||||
|
@ -608,9 +625,8 @@ NS_IMETHODIMP nsAccessible::GetNextSibling(nsIAccessible * *aNextSibling)
|
|||
if (mNextSibling || !mParent) {
|
||||
// If no parent, don't try to calculate a new sibling
|
||||
// It either means we're at the root or shutting down the parent
|
||||
if (mNextSibling != DEAD_END_ACCESSIBLE) {
|
||||
NS_IF_ADDREF(*aNextSibling = mNextSibling);
|
||||
}
|
||||
NS_IF_ADDREF(*aNextSibling = mNextSibling);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1593,15 +1609,6 @@ nsresult nsAccessible::AppendFlatStringFromContentNode(nsIContent *aContent, nsA
|
|||
nsAutoString textEquivalent;
|
||||
if (!aContent->IsNodeOfType(nsINode::eHTML)) {
|
||||
if (aContent->IsNodeOfType(nsINode::eXUL)) {
|
||||
nsCOMPtr<nsIPresShell> shell = GetPresShell();
|
||||
if (!shell) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
|
||||
if (!frame || !frame->GetStyleVisibility()->IsVisible()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(aContent));
|
||||
if (labeledEl) {
|
||||
labeledEl->GetLabel(textEquivalent);
|
||||
|
@ -1661,8 +1668,17 @@ nsresult nsAccessible::AppendFlatStringFromSubtree(nsIContent *aContent, nsAStri
|
|||
if (isAlreadyHere) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
isAlreadyHere = PR_TRUE;
|
||||
nsresult rv = AppendFlatStringFromSubtreeRecurse(aContent, aFlatString);
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = GetPresShell();
|
||||
NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
|
||||
|
||||
nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
|
||||
PRBool isHidden = (!frame || !frame->GetStyleVisibility()->IsVisible());
|
||||
nsresult rv = AppendFlatStringFromSubtreeRecurse(aContent, aFlatString,
|
||||
isHidden);
|
||||
|
||||
isAlreadyHere = PR_FALSE;
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !aFlatString->IsEmpty()) {
|
||||
|
@ -1681,7 +1697,10 @@ nsresult nsAccessible::AppendFlatStringFromSubtree(nsIContent *aContent, nsAStri
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent, nsAString *aFlatString)
|
||||
nsresult
|
||||
nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
|
||||
nsAString *aFlatString,
|
||||
PRBool aIsRootHidden)
|
||||
{
|
||||
// Depth first search for all text nodes that are decendants of content node.
|
||||
// Append all the text into one flat string
|
||||
|
@ -1698,10 +1717,25 @@ nsresult nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
|
|||
}
|
||||
|
||||
// There are relevant children: use them to get the text.
|
||||
nsCOMPtr<nsIPresShell> shell = GetPresShell();
|
||||
NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
|
||||
|
||||
PRUint32 index;
|
||||
for (index = 0; index < numChildren; index++) {
|
||||
AppendFlatStringFromSubtreeRecurse(aContent->GetChildAt(index), aFlatString);
|
||||
nsCOMPtr<nsIContent> childContent = aContent->GetChildAt(index);
|
||||
|
||||
// Walk into hidden subtree if the the root parent is also hidden. This
|
||||
// happens when the author explictly uses a hidden label or description.
|
||||
if (!aIsRootHidden) {
|
||||
nsIFrame *childFrame = shell->GetPrimaryFrameFor(childContent);
|
||||
if (!childFrame || !childFrame->GetStyleVisibility()->IsVisible())
|
||||
continue;
|
||||
}
|
||||
|
||||
AppendFlatStringFromSubtreeRecurse(childContent, aFlatString,
|
||||
aIsRootHidden);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3119,40 +3153,30 @@ NS_IMETHODIMP nsAccessible::GetNativeInterface(void **aOutAccessible)
|
|||
|
||||
void nsAccessible::DoCommandCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
NS_ASSERTION(gDoCommandTimer, "How did we get here if there was no gDoCommandTimer?");
|
||||
NS_ASSERTION(gDoCommandTimer,
|
||||
"How did we get here if there was no gDoCommandTimer?");
|
||||
NS_RELEASE(gDoCommandTimer);
|
||||
|
||||
nsIContent *content = reinterpret_cast<nsIContent*>(aClosure);
|
||||
nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(content));
|
||||
if (xulElement) {
|
||||
xulElement->Click();
|
||||
}
|
||||
else {
|
||||
nsIDocument *doc = content->GetDocument();
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
|
||||
nsPIDOMWindow *outerWindow = doc->GetWindow();
|
||||
if (presShell && outerWindow) {
|
||||
nsAutoPopupStatePusher popupStatePusher(outerWindow, openAllowed);
|
||||
nsCOMPtr<nsIContent> content =
|
||||
reinterpret_cast<nsIContent*>(aClosure);
|
||||
|
||||
nsMouseEvent downEvent(PR_TRUE, NS_MOUSE_BUTTON_DOWN, nsnull,
|
||||
nsMouseEvent::eSynthesized);
|
||||
nsMouseEvent upEvent(PR_TRUE, NS_MOUSE_BUTTON_UP, nsnull,
|
||||
nsMouseEvent::eSynthesized);
|
||||
nsMouseEvent clickEvent(PR_TRUE, NS_MOUSE_CLICK, nsnull,
|
||||
nsMouseEvent::eSynthesized);
|
||||
nsIDocument *doc = content->GetDocument();
|
||||
if (!doc)
|
||||
return;
|
||||
|
||||
nsEventStatus eventStatus = nsEventStatus_eIgnore;
|
||||
content->DispatchDOMEvent(&downEvent, nsnull,
|
||||
presShell->GetPresContext(), &eventStatus);
|
||||
content->DispatchDOMEvent(&upEvent, nsnull,
|
||||
presShell->GetPresContext(), &eventStatus);
|
||||
content->DispatchDOMEvent(&clickEvent, nsnull,
|
||||
presShell->GetPresContext(), &eventStatus);
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
|
||||
|
||||
// Scroll into view.
|
||||
presShell->ScrollContentIntoView(content, NS_PRESSHELL_SCROLL_ANYWHERE,
|
||||
NS_PRESSHELL_SCROLL_ANYWHERE);
|
||||
|
||||
// Fire mouse down and mouse up events.
|
||||
PRBool res = nsAccUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, presShell,
|
||||
content);
|
||||
if (!res)
|
||||
return;
|
||||
|
||||
nsAccUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, presShell, content);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#define _nsAccessible_H_
|
||||
|
||||
#include "nsAccessNodeWrap.h"
|
||||
#include "nsAccessibilityUtils.h"
|
||||
|
||||
#include "nsIAccessible.h"
|
||||
#include "nsPIAccessible.h"
|
||||
|
@ -70,9 +69,6 @@ class nsIView;
|
|||
#define NS_OK_NO_ARIA_VALUE \
|
||||
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x21)
|
||||
|
||||
// When mNextSibling is set to this, it indicates there ar eno more siblings
|
||||
#define DEAD_END_ACCESSIBLE static_cast<nsIAccessible*>((void*)1)
|
||||
|
||||
// Saves a data member -- if child count equals this value we haven't
|
||||
// cached children or child count yet
|
||||
enum { eChildCountUninitialized = -1 };
|
||||
|
@ -107,6 +103,8 @@ public:
|
|||
virtual ~nsAccessible();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsAccessible, nsAccessNode)
|
||||
|
||||
NS_DECL_NSIACCESSIBLE
|
||||
NS_DECL_NSPIACCESSIBLE
|
||||
NS_DECL_NSIACCESSIBLEHYPERLINK
|
||||
|
@ -197,7 +195,22 @@ 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);
|
||||
nsresult AppendFlatStringFromSubtreeRecurse(nsIContent *aContent, nsAString *aFlatString);
|
||||
|
||||
/**
|
||||
* Walk into subtree and calculate the string which is used as the accessible
|
||||
* name or description.
|
||||
*
|
||||
* @param aContent [in] traversed content
|
||||
* @param aFlatString [in, out] result string
|
||||
* @param aIsRootHidden [in] specifies whether root content (we started to
|
||||
* traverse from) is hidden, in this case the result
|
||||
* string is calculated from hidden children
|
||||
* (this is used when hidden root content is explicitly
|
||||
* specified as label or description by author)
|
||||
*/
|
||||
nsresult AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
|
||||
nsAString *aFlatString,
|
||||
PRBool aIsRootHidden);
|
||||
|
||||
// Helpers for dealing with children
|
||||
virtual void CacheChildren();
|
||||
|
@ -258,7 +271,9 @@ protected:
|
|||
|
||||
// Data Members
|
||||
nsCOMPtr<nsIAccessible> mParent;
|
||||
nsIAccessible *mFirstChild, *mNextSibling;
|
||||
nsCOMPtr<nsIAccessible> mFirstChild;
|
||||
nsCOMPtr<nsIAccessible> mNextSibling;
|
||||
|
||||
nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
|
||||
PRInt32 mAccChildCount;
|
||||
};
|
||||
|
|
|
@ -57,7 +57,22 @@
|
|||
PRBool nsAccEvent::gLastEventFromUserInput = PR_FALSE;
|
||||
nsIDOMNode* nsAccEvent::gLastEventNodeWeak = 0;
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsAccEvent, nsAccEvent, nsIAccessibleEvent)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEvent. nsISupports
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_2(nsAccEvent, mAccessible, mDocAccessible)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAccessibleEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsAccEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccEvent)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEvent)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEvent. Constructors
|
||||
|
||||
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
|
||||
PRBool aIsAsynch, EEventRule aEventRule):
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsIPresShell;
|
||||
|
||||
|
@ -93,7 +94,9 @@ public:
|
|||
EEventRule aEventRule = eRemoveDupes);
|
||||
virtual ~nsAccEvent() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsAccEvent)
|
||||
|
||||
NS_DECL_NSIACCESSIBLEEVENT
|
||||
|
||||
static void GetLastEventAttributes(nsIDOMNode *aNode,
|
||||
|
@ -105,13 +108,13 @@ protected:
|
|||
void CaptureIsFromUserInput(PRBool aIsAsynch);
|
||||
PRBool mIsFromUserInput;
|
||||
|
||||
private:
|
||||
PRUint32 mEventType;
|
||||
EEventRule mEventRule;
|
||||
nsCOMPtr<nsIAccessible> mAccessible;
|
||||
nsCOMPtr<nsIDOMNode> mDOMNode;
|
||||
nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
|
||||
|
||||
private:
|
||||
static PRBool gLastEventFromUserInput;
|
||||
static nsIDOMNode* gLastEventNodeWeak;
|
||||
|
||||
|
|
|
@ -50,11 +50,48 @@ nsApplicationAccessible::nsApplicationAccessible():
|
|||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISupports
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsApplicationAccessible,
|
||||
nsAccessible)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsApplicationAccessible)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsApplicationAccessible,
|
||||
nsAccessible)
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
||||
tmp->mChildren->Enumerate(getter_AddRefs(enumerator));
|
||||
|
||||
nsCOMPtr<nsIWeakReference> childWeakRef;
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
|
||||
PRBool hasMoreElements;
|
||||
while(NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements))
|
||||
&& hasMoreElements) {
|
||||
|
||||
enumerator->GetNext(getter_AddRefs(childWeakRef));
|
||||
accessible = do_QueryReferent(childWeakRef);
|
||||
if (accessible) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, accessible);
|
||||
cb.NoteXPCOMChild(accessible);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsApplicationAccessible,
|
||||
nsAccessible)
|
||||
tmp->mChildren->Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsApplicationAccessible)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsAccessible)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsApplicationAccessible, nsAccessible)
|
||||
NS_IMPL_RELEASE_INHERITED(nsApplicationAccessible, nsAccessible)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIAccessNode
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsApplicationAccessible::Init()
|
||||
{
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsApplicationAccessible,
|
||||
nsAccessible)
|
||||
|
||||
// nsPIAccessNode
|
||||
NS_IMETHOD Init();
|
||||
|
|
|
@ -188,11 +188,14 @@ nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
|
|||
NS_IMETHODIMP
|
||||
nsLinkableAccessible::DoAction(PRUint8 aIndex)
|
||||
{
|
||||
if (aIndex != eAction_Jump)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
|
||||
if (actionAcc)
|
||||
return actionAcc->DoAction(aIndex);
|
||||
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
return nsHyperTextAccessibleWrap::DoAction(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "nsAccessibilityService.h"
|
||||
#include "nsCaretAccessible.h"
|
||||
#include "nsIAccessibleEvent.h"
|
||||
#include "nsICaret.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
|
@ -47,8 +47,8 @@
|
|||
#include "nsIFrame.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsISelection2.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsIWidget.h"
|
||||
|
@ -78,13 +78,31 @@ void nsCaretAccessible::Shutdown()
|
|||
|
||||
nsresult nsCaretAccessible::ClearControlSelectionListener()
|
||||
{
|
||||
mCurrentControl = nsnull;
|
||||
mCurrentControlSelection = nsnull;
|
||||
nsCOMPtr<nsISelectionController> controller =
|
||||
GetSelectionControllerForNode(mCurrentControl);
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryReferent(mCurrentControlSelection));
|
||||
if (!selPrivate) {
|
||||
mCurrentControl = nsnull;
|
||||
|
||||
if (!controller)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Remove 'this' registered as selection listener for the normal selection.
|
||||
nsCOMPtr<nsISelection> normalSel;
|
||||
controller->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(normalSel));
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(normalSel));
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = selPrivate->RemoveSelectionListener(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Remove 'this' registered as selection listener for the spellcheck
|
||||
// selection.
|
||||
nsCOMPtr<nsISelection> spellcheckSel;
|
||||
controller->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
|
||||
getter_AddRefs(spellcheckSel));
|
||||
selPrivate = do_QueryInterface(spellcheckSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
return selPrivate->RemoveSelectionListener(this);
|
||||
}
|
||||
|
@ -99,39 +117,29 @@ nsresult nsCaretAccessible::SetControlSelectionListener(nsIDOMNode *aCurrentNode
|
|||
mLastTextAccessible = nsnull;
|
||||
|
||||
// When focus moves such that the caret is part of a new frame selection
|
||||
// this removes the old selection listener and attaches a new one for the current focus
|
||||
nsCOMPtr<nsIPresShell> presShell =
|
||||
mRootAccessible->GetPresShellFor(aCurrentNode);
|
||||
if (!presShell)
|
||||
return NS_ERROR_FAILURE;
|
||||
// this removes the old selection listener and attaches a new one for
|
||||
// the current focus.
|
||||
nsCOMPtr<nsISelectionController> controller =
|
||||
GetSelectionControllerForNode(mCurrentControl);
|
||||
NS_ENSURE_TRUE(controller, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aCurrentNode));
|
||||
// The control selection listener is only for form controls, not for the document
|
||||
// When there is no document, the content will be null
|
||||
if (!content) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
nsPresContext *presContext = presShell->GetPresContext();
|
||||
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
frame->GetSelectionController(presContext, getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(domSel));
|
||||
// Register 'this' as selection listener for the normal selection.
|
||||
nsCOMPtr<nsISelection> normalSel;
|
||||
controller->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(normalSel));
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(normalSel));
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
mCurrentControlSelection = do_GetWeakReference(domSel);
|
||||
nsresult rv = selPrivate->AddSelectionListener(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Register 'this' as selection listener for the spellcheck selection.
|
||||
nsCOMPtr<nsISelection> spellcheckSel;
|
||||
controller->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
|
||||
getter_AddRefs(spellcheckSel));
|
||||
selPrivate = do_QueryInterface(spellcheckSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
return selPrivate->AddSelectionListener(this);
|
||||
}
|
||||
|
||||
|
@ -148,6 +156,15 @@ nsCaretAccessible::AddDocSelectionListener(nsIPresShell *aShell)
|
|||
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = selPrivate->AddSelectionListener(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelection> spellcheckSel;
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
|
||||
getter_AddRefs(spellcheckSel));
|
||||
selPrivate = do_QueryInterface(spellcheckSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
return selPrivate->AddSelectionListener(this);
|
||||
}
|
||||
|
||||
|
@ -162,10 +179,39 @@ nsCaretAccessible::RemoveDocSelectionListener(nsIPresShell *aShell)
|
|||
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
selPrivate->RemoveSelectionListener(this);
|
||||
|
||||
nsCOMPtr<nsISelection> spellcheckSel;
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
|
||||
getter_AddRefs(spellcheckSel));
|
||||
selPrivate = do_QueryInterface(spellcheckSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
return selPrivate->RemoveSelectionListener(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel, PRInt16 aReason)
|
||||
NS_IMETHODIMP
|
||||
nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc,
|
||||
nsISelection *aSel,
|
||||
PRInt16 aReason)
|
||||
{
|
||||
nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSel));
|
||||
|
||||
PRInt16 type = 0;
|
||||
sel2->GetType(&type);
|
||||
|
||||
if (type == nsISelectionController::SELECTION_NORMAL)
|
||||
return NormalSelectionChanged(aDoc, aSel);
|
||||
|
||||
if (type == nsISelectionController::SELECTION_SPELLCHECK)
|
||||
return SpellcheckSelectionChanged(aDoc, aSel);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCaretAccessible::NormalSelectionChanged(nsIDOMDocument *aDoc,
|
||||
nsISelection *aSel)
|
||||
{
|
||||
NS_ENSURE_TRUE(mRootAccessible, NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -247,6 +293,38 @@ NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, ns
|
|||
return mRootAccessible->FireDelayedAccessibleEvent(event);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCaretAccessible::SpellcheckSelectionChanged(nsIDOMDocument *aDoc,
|
||||
nsISelection *aSel)
|
||||
{
|
||||
// XXX: fire an event for accessible of focus node of the selection. If
|
||||
// spellchecking is enabled then we will fire the number of events for
|
||||
// the same accessible for newly appended range of the selection (for every
|
||||
// misspelled word). If spellchecking is disabled (for example,
|
||||
// @spellcheck="false" on html:body) then we won't fire any event.
|
||||
nsCOMPtr<nsIDOMNode> targetNode;
|
||||
aSel->GetFocusNode(getter_AddRefs(targetNode));
|
||||
if (!targetNode)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIAccessibleDocument> docAccessible =
|
||||
nsAccessNode::GetDocAccessibleFor(targetNode);
|
||||
NS_ENSURE_STATE(docAccessible);
|
||||
|
||||
nsCOMPtr<nsIAccessible> containerAccessible;
|
||||
nsresult rv =
|
||||
docAccessible->GetAccessibleInParentChain(targetNode, PR_TRUE,
|
||||
getter_AddRefs(containerAccessible));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
new nsAccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
|
||||
containerAccessible, nsnull);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return mRootAccessible->FireAccessibleEvent(event);
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
|
||||
{
|
||||
|
@ -269,7 +347,7 @@ nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
|
|||
nsCOMPtr<nsIPresShell> presShell = mRootAccessible->GetPresShellFor(lastNodeWithCaret);
|
||||
NS_ENSURE_TRUE(presShell, caretRect);
|
||||
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
nsRefPtr<nsCaret> caret;
|
||||
presShell->GetCaret(getter_AddRefs(caret));
|
||||
NS_ENSURE_TRUE(caret, caretRect);
|
||||
|
||||
|
@ -278,7 +356,7 @@ nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
|
|||
nsCOMPtr<nsISelection> caretSelection(do_QueryReferent(mLastUsedSelection));
|
||||
NS_ENSURE_TRUE(caretSelection, caretRect);
|
||||
|
||||
caret->GetCaretCoordinates(nsICaret::eRenderingViewCoordinates, caretSelection,
|
||||
caret->GetCaretCoordinates(nsCaret::eRenderingViewCoordinates, caretSelection,
|
||||
&caretRect, &isCollapsed, &view);
|
||||
if (!view || caretRect.IsEmpty()) {
|
||||
return nsRect(); // Return empty rect
|
||||
|
@ -317,3 +395,35 @@ nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
|
|||
return caretRect;
|
||||
}
|
||||
|
||||
already_AddRefed<nsISelectionController>
|
||||
nsCaretAccessible::GetSelectionControllerForNode(nsIDOMNode *aNode)
|
||||
{
|
||||
if (!aNode)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = mRootAccessible->GetPresShellFor(aNode);
|
||||
if (!presShell)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
|
||||
if (!doc)
|
||||
return nsnull;
|
||||
|
||||
// Get selection controller only for form controls, not for the document.
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
|
||||
if (!content)
|
||||
return nsnull;
|
||||
|
||||
nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
|
||||
if (!frame)
|
||||
return nsnull;
|
||||
|
||||
nsPresContext *presContext = presShell->GetPresContext();
|
||||
if (!presContext)
|
||||
return nsnull;
|
||||
|
||||
nsISelectionController *controller = nsnull;
|
||||
frame->GetSelectionController(presContext, &controller);
|
||||
return controller;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,13 +40,15 @@
|
|||
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsIAccessibleText.h"
|
||||
#include "nsICaret.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
class nsRootAccessible;
|
||||
class nsIView;
|
||||
class nsIPresShell;
|
||||
class nsIWidget;
|
||||
|
||||
/*
|
||||
* This special accessibility class is for the caret, which is really the currently focused selection.
|
||||
|
@ -119,17 +121,23 @@ public:
|
|||
|
||||
nsRect GetCaretRect(nsIWidget **aOutWidget);
|
||||
|
||||
protected:
|
||||
nsresult NormalSelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel);
|
||||
nsresult SpellcheckSelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel);
|
||||
|
||||
already_AddRefed<nsISelectionController>
|
||||
GetSelectionControllerForNode(nsIDOMNode *aNode);
|
||||
|
||||
private:
|
||||
// The currently focused control -- never a document.
|
||||
// We listen to selection for one control at a time (the focused one)
|
||||
// Document selection is handled separately via additional listeners on all active documents
|
||||
// The current control is set via SetControlSelectionListener()
|
||||
nsCOMPtr<nsIDOMNode> mCurrentControl; // Selection controller for the currently focused control
|
||||
nsCOMPtr<nsIWeakReference> mCurrentControlSelection;
|
||||
|
||||
// Info for the the last selection event
|
||||
// If it was on a control, then mLastUsedSelection == mCurrentControlSelection
|
||||
// Otherwise, it's for a document where the selection changed
|
||||
// Info for the the last selection event.
|
||||
// If it was on a control, then it's control's selection. Otherwise, it's for
|
||||
// a document where the selection changed.
|
||||
nsCOMPtr<nsIWeakReference> mLastUsedSelection; // Weak ref to nsISelection
|
||||
nsCOMPtr<nsIAccessibleText> mLastTextAccessible;
|
||||
PRInt32 mLastCaretOffset;
|
||||
|
|
|
@ -135,7 +135,34 @@ nsDocAccessible::~nsDocAccessible()
|
|||
{
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDocAccessible)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsDocAccessible. nsISupports
|
||||
|
||||
PR_STATIC_CALLBACK(PLDHashOperator)
|
||||
ElementTraverser(const void *aKey, nsIAccessNode *aAccessNode,
|
||||
void *aUserArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aAccessNode);
|
||||
cb->NoteXPCOMChild(aAccessNode);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mEventsToFire)
|
||||
tmp->mAccessNodeCache.EnumerateRead(ElementTraverser, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mEventsToFire)
|
||||
tmp->ClearCache(tmp->mAccessNodeCache);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDocAccessible)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
|
||||
NS_INTERFACE_MAP_ENTRY(nsPIAccessibleDocument)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
|
||||
|
@ -1760,9 +1787,8 @@ void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode)
|
|||
getter_AddRefs(childAccessNode));
|
||||
childAccessNode->GetDOMNode(getter_AddRefs(possibleAnonNode));
|
||||
nsCOMPtr<nsIContent> iterContent = do_QueryInterface(possibleAnonNode);
|
||||
if (iterContent && (iterContent->IsNativeAnonymous() ||
|
||||
iterContent->GetBindingParent())) {
|
||||
// GetBindingParent() check is a perf win -- make sure we don't
|
||||
if (iterContent && iterContent->IsInAnonymousSubtree()) {
|
||||
// IsInAnonymousSubtree() check is a perf win -- make sure we don't
|
||||
// shut down the same subtree twice since we'll reach non-anon content via
|
||||
// DOM traversal later in this method
|
||||
RefreshNodes(possibleAnonNode);
|
||||
|
|
|
@ -65,6 +65,8 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
|
|||
public nsSupportsWeakReference
|
||||
{
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDocAccessible, nsAccessible)
|
||||
|
||||
NS_DECL_NSIACCESSIBLEDOCUMENT
|
||||
NS_DECL_NSPIACCESSIBLEDOCUMENT
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include "nsAccessibleEventData.h"
|
||||
#include "nsHTMLSelectAccessible.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsICaret.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocShellTreeNode.h"
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsTextUtils.h"
|
||||
|
||||
#include "nsAccessNode.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsLangTextAttr
|
||||
|
||||
PRBool
|
||||
nsLangTextAttr::equal(nsIDOMElement *aElm)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aElm));
|
||||
if (!content)
|
||||
return PR_FALSE;
|
||||
|
||||
nsAutoString lang;
|
||||
nsAccUtils::GetLanguageFor(content, mRootContent, lang);
|
||||
|
||||
return lang == mLang;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsCSSTextAttr
|
||||
|
||||
/**
|
||||
* Item of the gCSSTextAttrsMap map.
|
||||
*/
|
||||
struct nsCSSTextAttrMapItem
|
||||
{
|
||||
const char* mCSSName;
|
||||
const char* mCSSValue;
|
||||
const char* mAttrName;
|
||||
const char* mAttrValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* The map of CSS properties to text attributes.
|
||||
*/
|
||||
|
||||
const char* const kAnyValue = nsnull;
|
||||
const char* const kCopyName = nsnull;
|
||||
const char* const kCopyValue = nsnull;
|
||||
|
||||
static nsCSSTextAttrMapItem gCSSTextAttrsMap[] = {
|
||||
// CSS name CSS value Attribute name Attribute name
|
||||
{ "background-color", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "color", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "font-family", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "font-size", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "font-style", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "font-weight", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "text-decoration", "line-through", "text-line-through-style", "solid" },
|
||||
{ "text-decoration", "underline", "text-underline-style", "solid" },
|
||||
{ "text-align", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "text-indent", kAnyValue, kCopyName, kCopyValue },
|
||||
{ "vertical-align", kAnyValue, "text-position", kCopyValue }
|
||||
};
|
||||
|
||||
nsCSSTextAttr::nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
|
||||
nsIDOMElement *aRootElm) :
|
||||
mIndex(-1), mIncludeDefAttrValue(aIncludeDefAttrValue)
|
||||
{
|
||||
nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aElm,
|
||||
getter_AddRefs(mStyleDecl));
|
||||
|
||||
if (!mIncludeDefAttrValue)
|
||||
nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aRootElm,
|
||||
getter_AddRefs(mDefStyleDecl));
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCSSTextAttr::equal(nsIDOMElement *aElm)
|
||||
{
|
||||
if (!aElm || !mStyleDecl)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
|
||||
nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aElm,
|
||||
getter_AddRefs(currStyleDecl));
|
||||
if (!currStyleDecl)
|
||||
return PR_FALSE;
|
||||
|
||||
NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
|
||||
|
||||
nsAutoString currValue;
|
||||
nsresult rv = currStyleDecl->GetPropertyValue(cssName, currValue);
|
||||
if (NS_FAILED(rv))
|
||||
return PR_FALSE;
|
||||
|
||||
nsAutoString value;
|
||||
rv = mStyleDecl->GetPropertyValue(cssName, value);
|
||||
return NS_SUCCEEDED(rv) && value == currValue;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCSSTextAttr::iterate()
|
||||
{
|
||||
return ++mIndex < static_cast<PRInt32>(NS_ARRAY_LENGTH(gCSSTextAttrsMap));
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCSSTextAttr::get(nsACString& aName, nsAString& aValue)
|
||||
{
|
||||
if (!mStyleDecl)
|
||||
return PR_FALSE;
|
||||
|
||||
NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
|
||||
nsresult rv = mStyleDecl->GetPropertyValue(cssName, aValue);
|
||||
if (NS_FAILED(rv))
|
||||
return PR_FALSE;
|
||||
|
||||
// Don't expose text attribute if corresponding CSS value on the element
|
||||
// equals to CSS value on the root element and we don't want to include
|
||||
// default values.
|
||||
if (!mIncludeDefAttrValue) {
|
||||
if (!mDefStyleDecl)
|
||||
return PR_FALSE;
|
||||
|
||||
nsAutoString defValue;
|
||||
mDefStyleDecl->GetPropertyValue(cssName, defValue);
|
||||
if (defValue == aValue)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Don't expose text attribute if its required specific CSS value isn't
|
||||
// matched with the CSS value we got.
|
||||
const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
|
||||
if (cssValue != kAnyValue && !aValue.EqualsASCII(cssValue))
|
||||
return PR_FALSE;
|
||||
|
||||
// Get the name of text attribute.
|
||||
if (gCSSTextAttrsMap[mIndex].mAttrName != kCopyName)
|
||||
aName = gCSSTextAttrsMap[mIndex].mAttrName;
|
||||
else
|
||||
aName = gCSSTextAttrsMap[mIndex].mCSSName;
|
||||
|
||||
// Get the value of text attribute.
|
||||
const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
|
||||
if (attrValue != kCopyValue)
|
||||
AppendASCIItoUTF16(attrValue, aValue);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef nsTextUtils_h_
|
||||
#define nsTextUtils_h_
|
||||
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMCSSStyleDeclaration.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
/**
|
||||
* Base class to work with text attributes. See derived classes below.
|
||||
*/
|
||||
class nsTextAttr
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Return true if the text attribute for the given element equals with
|
||||
* predefined attribute.
|
||||
*/
|
||||
virtual PRBool equal(nsIDOMElement *aElm) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class is used for the work with 'lang' text attributes. Used in
|
||||
* nsHyperTextAccessible.
|
||||
*/
|
||||
class nsLangTextAttr : public nsTextAttr
|
||||
{
|
||||
public:
|
||||
nsLangTextAttr(nsAString& aLang, nsIContent *aRootContent) :
|
||||
mLang(aLang), mRootContent(aRootContent) { }
|
||||
|
||||
virtual PRBool equal(nsIDOMElement *aElm);
|
||||
|
||||
private:
|
||||
nsString mLang;
|
||||
nsCOMPtr<nsIContent> mRootContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class is used for the work with CSS based text attributes. Used in
|
||||
* nsHyperTextAccessible.
|
||||
*/
|
||||
class nsCSSTextAttr : public nsTextAttr
|
||||
{
|
||||
public:
|
||||
nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
|
||||
nsIDOMElement *aRootElm);
|
||||
|
||||
// nsTextAttr
|
||||
virtual PRBool equal(nsIDOMElement *aElm);
|
||||
|
||||
// nsCSSTextAttr
|
||||
/**
|
||||
* Interates through attributes.
|
||||
*/
|
||||
PRBool iterate();
|
||||
|
||||
/**
|
||||
* Get name and value of attribute.
|
||||
*/
|
||||
PRBool get(nsACString& aName, nsAString& aValue);
|
||||
|
||||
private:
|
||||
PRInt32 mIndex;
|
||||
PRBool mIncludeDefAttrValue;
|
||||
|
||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> mStyleDecl;
|
||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> mDefStyleDecl;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -41,6 +41,8 @@
|
|||
#include "nsAccessibilityAtoms.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsAccessibleTreeWalker.h"
|
||||
#include "nsTextUtils.h"
|
||||
|
||||
#include "nsPIAccessNode.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsContentCID.h"
|
||||
|
@ -50,6 +52,7 @@
|
|||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIDOMDocumentView.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIDOMNSRange.h"
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsIDOMXULDocument.h"
|
||||
#include "nsIEditingSession.h"
|
||||
|
@ -637,7 +640,9 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
|
|||
if (findContent->IsNodeOfType(nsINode::eHTML) &&
|
||||
findContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
|
||||
nsIContent *parent = findContent->GetParent();
|
||||
if (parent && parent->IsNativeAnonymous() && parent->GetChildCount() == 1) {
|
||||
if (parent &&
|
||||
parent->IsRootOfNativeAnonymousSubtree() &&
|
||||
parent->GetChildCount() == 1) {
|
||||
// This <br> is the only node in a text control, therefore it is the hacky
|
||||
// "bogus node" used when there is no text in a control
|
||||
*aHyperTextOffset = 0;
|
||||
|
@ -671,7 +676,7 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
|
|||
// Start offset, inclusive
|
||||
// Make sure the offset lands on the embedded object character in order to indicate
|
||||
// the true inner offset is inside the subtree for that link
|
||||
addTextOffset = (TextLength(descendantAccessible) == addTextOffset) ? 1 : 0;
|
||||
addTextOffset = (TextLength(descendantAccessible) == static_cast<PRInt32>(addTextOffset)) ? 1 : 0;
|
||||
}
|
||||
descendantAccessible = parentAccessible;
|
||||
}
|
||||
|
@ -698,6 +703,18 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHyperTextAccessible::HypertextOffsetToDOMPoint(PRInt32 aHTOffset,
|
||||
nsIDOMNode **aNode,
|
||||
PRInt32 *aOffset)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
PRInt32 endOffset;
|
||||
|
||||
return HypertextOffsetsToDOMRange(aHTOffset, aHTOffset, aNode, aOffset,
|
||||
getter_AddRefs(endNode), &endOffset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
|
||||
PRInt32 aEndHTOffset,
|
||||
|
@ -869,6 +886,9 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe
|
|||
nsAString &aText)
|
||||
{
|
||||
aText.Truncate();
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aStartOffset);
|
||||
NS_ENSURE_ARG_POINTER(aEndOffset);
|
||||
*aStartOffset = *aEndOffset = 0;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
|
@ -888,11 +908,15 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe
|
|||
// otherwise screen readers will announce the wrong line as the user presses up or down arrow and land
|
||||
// at the end of a line.
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, getter_AddRefs(domSel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSel));
|
||||
nsCOMPtr<nsFrameSelection> frameSelection;
|
||||
rv = privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (frameSelection->GetHint() == nsFrameSelection::HINTLEFT) {
|
||||
-- aOffset; // We are at the start of a line
|
||||
}
|
||||
|
@ -902,6 +926,52 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsSelectionAmount amount;
|
||||
PRBool needsStart = PR_FALSE;
|
||||
switch (aBoundaryType) {
|
||||
case BOUNDARY_CHAR:
|
||||
amount = eSelectCharacter;
|
||||
if (aType == eGetAt)
|
||||
aType = eGetAfter; // Avoid returning 2 characters
|
||||
break;
|
||||
|
||||
case BOUNDARY_WORD_START:
|
||||
needsStart = PR_TRUE;
|
||||
amount = eSelectWord;
|
||||
break;
|
||||
|
||||
case BOUNDARY_WORD_END:
|
||||
amount = eSelectWord;
|
||||
break;
|
||||
|
||||
case BOUNDARY_LINE_START:
|
||||
// Newlines are considered at the end of a line. Since getting
|
||||
// the BOUNDARY_LINE_START gets the text from the line-start to the next
|
||||
// line-start, the newline is included at the end of the string.
|
||||
needsStart = PR_TRUE;
|
||||
amount = eSelectLine;
|
||||
break;
|
||||
|
||||
case BOUNDARY_LINE_END:
|
||||
// Newlines are considered at the end of a line. Since getting
|
||||
// the BOUNDARY_END_START gets the text from the line-end to the next
|
||||
//line-end, the newline is included at the beginning of the string.
|
||||
amount = eSelectLine;
|
||||
break;
|
||||
|
||||
case BOUNDARY_ATTRIBUTE_RANGE:
|
||||
{
|
||||
nsresult rv = GetTextAttributes(PR_FALSE, aOffset,
|
||||
aStartOffset, aEndOffset, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return GetText(*aStartOffset, *aEndOffset, aText);
|
||||
}
|
||||
|
||||
default: // Note, sentence support is deprecated and falls through to here
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PRInt32 startOffset = aOffset + (aBoundaryType == BOUNDARY_LINE_END); // Avoid getting the previous line
|
||||
PRInt32 endOffset = startOffset;
|
||||
|
||||
|
@ -929,60 +999,6 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe
|
|||
}
|
||||
}
|
||||
|
||||
nsSelectionAmount amount;
|
||||
PRBool needsStart = PR_FALSE;
|
||||
switch (aBoundaryType)
|
||||
{
|
||||
case BOUNDARY_CHAR:
|
||||
amount = eSelectCharacter;
|
||||
if (aType == eGetAt) {
|
||||
aType = eGetAfter; // Avoid returning 2 characters
|
||||
}
|
||||
break;
|
||||
case BOUNDARY_WORD_START:
|
||||
needsStart = PR_TRUE;
|
||||
amount = eSelectWord;
|
||||
break;
|
||||
case BOUNDARY_WORD_END:
|
||||
amount = eSelectWord;
|
||||
break;
|
||||
case BOUNDARY_LINE_START:
|
||||
// Newlines are considered at the end of a line,
|
||||
// Since getting the BOUNDARY_LINE_START gets the text from the line-start
|
||||
// to the next line-start, the newline is included at the end of the string
|
||||
needsStart = PR_TRUE;
|
||||
amount = eSelectLine;
|
||||
break;
|
||||
case BOUNDARY_LINE_END:
|
||||
// Newlines are considered at the end of a line,
|
||||
// Since getting the BOUNDARY_END_START gets the text from the line-end
|
||||
// to the next line-end, the newline is included at the beginning of the string
|
||||
amount = eSelectLine;
|
||||
break;
|
||||
case BOUNDARY_ATTRIBUTE_RANGE:
|
||||
{
|
||||
// XXX We should merge identically formatted frames
|
||||
// XXX deal with static text case
|
||||
// XXX deal with boundary type
|
||||
nsIContent *textContent = startFrame->GetContent();
|
||||
// If not text, then it's represented by an embedded object char
|
||||
// (length of 1)
|
||||
// XXX did this mean to check for eTEXT?
|
||||
// XXX This is completely wrong, needs to be reimplemented
|
||||
PRInt32 textLength = textContent ? textContent->TextLength() : 1;
|
||||
if (textLength < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aStartOffset = aOffset - startOffset;
|
||||
*aEndOffset = *aStartOffset + textLength;
|
||||
startOffset = *aStartOffset;
|
||||
endOffset = *aEndOffset;
|
||||
return GetText(startOffset, endOffset, aText);
|
||||
}
|
||||
default: // Note, sentence support is deprecated and falls through to here
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PRInt32 finalStartOffset, finalEndOffset;
|
||||
|
||||
// If aType == eGetAt we'll change both the start and end offset from
|
||||
|
@ -1071,31 +1087,106 @@ NS_IMETHODIMP nsHyperTextAccessible::GetTextAfterOffset(PRInt32 aOffset, nsAcces
|
|||
return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHyperTextAccessible::GetAttributeRange(PRInt32 aOffset, PRInt32 *aRangeStartOffset,
|
||||
PRInt32 *aRangeEndOffset, nsIAccessible **aAccessibleWithAttrs)
|
||||
// nsIPersistentProperties
|
||||
// nsIAccessibleText::getTextAttributes(in boolean includeDefAttrs,
|
||||
// in long offset,
|
||||
// out long rangeStartOffset,
|
||||
// out long rangeEndOffset);
|
||||
NS_IMETHODIMP
|
||||
nsHyperTextAccessible::GetTextAttributes(PRBool aIncludeDefAttrs,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 *aStartOffset,
|
||||
PRInt32 *aEndOffset,
|
||||
nsIPersistentProperties **aAttributes)
|
||||
{
|
||||
// Return the range of text with common attributes around aOffset
|
||||
*aRangeStartOffset = *aRangeEndOffset = 0;
|
||||
*aAccessibleWithAttrs = nsnull;
|
||||
// 1. First we get spell check, then language, then the set of CSS-based
|
||||
// attributes.
|
||||
// 2. As we get each new attribute, we pass the current start and end offsets
|
||||
// as in/out parameters. In other words, as attributes are collected,
|
||||
// the attribute range itself can only stay the same or get smaller.
|
||||
//
|
||||
// Example:
|
||||
// Current: range 5-10
|
||||
// Adding: range 7-12
|
||||
// Result: range 7-10
|
||||
|
||||
if (!mDOMNode) {
|
||||
NS_ENSURE_ARG_POINTER(aStartOffset);
|
||||
*aStartOffset = 0;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aEndOffset);
|
||||
nsresult rv = GetCharacterCount(aEndOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aAttributes) {
|
||||
*aAttributes = nsnull;
|
||||
|
||||
nsCOMPtr<nsIPersistentProperties> attributes =
|
||||
do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
|
||||
NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_ADDREF(*aAttributes = attributes);
|
||||
}
|
||||
|
||||
if (!mDOMNode)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
|
||||
while (NextChild(accessible)) {
|
||||
PRInt32 length = TextLength(accessible);
|
||||
NS_ENSURE_TRUE(length >= 0, NS_ERROR_FAILURE);
|
||||
if (*aRangeStartOffset + length > aOffset) {
|
||||
*aRangeEndOffset = *aRangeStartOffset + length;
|
||||
NS_ADDREF(*aAccessibleWithAttrs = accessible);
|
||||
return NS_OK;
|
||||
}
|
||||
*aRangeStartOffset += length;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
PRInt32 nodeOffset = 0;
|
||||
rv = HypertextOffsetToDOMPoint(aOffset, getter_AddRefs(node), &nodeOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
// Set 'misspelled' text attribute.
|
||||
rv = GetSpellTextAttribute(node, nodeOffset, aStartOffset, aEndOffset,
|
||||
aAttributes ? *aAttributes : nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(node));
|
||||
if (content && content->IsNodeOfType(nsINode::eELEMENT))
|
||||
node = do_QueryInterface(content->GetChildAt(nodeOffset));
|
||||
|
||||
if (!node)
|
||||
return NS_OK;
|
||||
|
||||
// Set 'lang' text attribute.
|
||||
rv = GetLangTextAttributes(aIncludeDefAttrs, node,
|
||||
aStartOffset, aEndOffset,
|
||||
aAttributes ? *aAttributes : nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set CSS based text attributes.
|
||||
rv = GetCSSTextAttributes(aIncludeDefAttrs, node,
|
||||
aStartOffset, aEndOffset,
|
||||
aAttributes ? *aAttributes : nsnull);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// nsIPersistentProperties
|
||||
// nsIAccessibleText::defaultTextAttributes
|
||||
NS_IMETHODIMP
|
||||
nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttributes)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aAttributes);
|
||||
*aAttributes = nsnull;
|
||||
|
||||
nsCOMPtr<nsIPersistentProperties> attributes =
|
||||
do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
|
||||
NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_ADDREF(*aAttributes = attributes);
|
||||
|
||||
if (!mDOMNode)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> element = nsAccUtils::GetDOMElementFor(mDOMNode);
|
||||
|
||||
nsCSSTextAttr textAttr(PR_TRUE, element, nsnull);
|
||||
while (textAttr.iterate()) {
|
||||
nsCAutoString name;
|
||||
nsAutoString value, oldValue;
|
||||
if (textAttr.get(name, value))
|
||||
attributes->SetStringProperty(name, value, oldValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1474,7 +1565,8 @@ nsresult nsHyperTextAccessible::SetSelectionRange(PRInt32 aStartPos, PRInt32 aEn
|
|||
// ranges remaining from previous selection
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
GetSelections(getter_AddRefs(selCon), getter_AddRefs(domSel));
|
||||
GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(selCon), getter_AddRefs(domSel));
|
||||
if (domSel) {
|
||||
PRInt32 numRanges;
|
||||
domSel->GetRangeCount(&numRanges);
|
||||
|
@ -1509,7 +1601,8 @@ NS_IMETHODIMP nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
|
|||
*aCaretOffset = 0;
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, getter_AddRefs(domSel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> caretNode;
|
||||
|
@ -1527,7 +1620,8 @@ PRInt32 nsHyperTextAccessible::GetCaretLineNumber()
|
|||
// Provide the line number for the caret, relative to the
|
||||
// currently focused node. Use a 1-based index
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
GetSelections(nsnull, getter_AddRefs(domSel));
|
||||
GetSelections(nsISelectionController::SELECTION_NORMAL, nsnull,
|
||||
getter_AddRefs(domSel));
|
||||
nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSel));
|
||||
NS_ENSURE_TRUE(privateSelection, -1);
|
||||
nsCOMPtr<nsFrameSelection> frameSelection;
|
||||
|
@ -1590,9 +1684,11 @@ PRInt32 nsHyperTextAccessible::GetCaretLineNumber()
|
|||
return lineNumber;
|
||||
}
|
||||
|
||||
nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon,
|
||||
nsISelection **aDomSel,
|
||||
nsCOMArray<nsIDOMRange>* aRanges)
|
||||
nsresult
|
||||
nsHyperTextAccessible::GetSelections(PRInt16 aType,
|
||||
nsISelectionController **aSelCon,
|
||||
nsISelection **aDomSel,
|
||||
nsCOMArray<nsIDOMRange>* aRanges)
|
||||
{
|
||||
if (!mDOMNode) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1610,7 +1706,6 @@ nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon,
|
|||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startNode;
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
GetAssociatedEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
|
||||
|
@ -1619,18 +1714,7 @@ nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon,
|
|||
// This is for form controls which have their own
|
||||
// selection controller separate from the document, for example
|
||||
// HTML:input, HTML:textarea, XUL:textbox, etc.
|
||||
if (aSelCon) {
|
||||
editor->GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(*aSelCon, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
editor->GetSelection(getter_AddRefs(domSel));
|
||||
NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> editorRoot;
|
||||
editor->GetRootElement(getter_AddRefs(editorRoot));
|
||||
startNode = do_QueryInterface(editorRoot);
|
||||
NS_ENSURE_STATE(startNode);
|
||||
editor->GetSelectionController(getter_AddRefs(selCon));
|
||||
}
|
||||
else {
|
||||
// Case 2: rich content subtree (can be rich editor)
|
||||
|
@ -1641,13 +1725,11 @@ nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon,
|
|||
// Get the selection and selection controller
|
||||
frame->GetSelectionController(GetPresContext(),
|
||||
getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(domSel));
|
||||
NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE);
|
||||
|
||||
startNode = mDOMNode;
|
||||
}
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
selCon->GetSelection(aType, getter_AddRefs(domSel));
|
||||
NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE);
|
||||
|
||||
if (aSelCon) {
|
||||
NS_ADDREF(*aSelCon = selCon);
|
||||
|
@ -1655,10 +1737,19 @@ nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon,
|
|||
if (aDomSel) {
|
||||
NS_ADDREF(*aDomSel = domSel);
|
||||
}
|
||||
|
||||
if (aRanges) {
|
||||
nsCOMPtr<nsISelection2> selection2(do_QueryInterface(domSel));
|
||||
NS_ENSURE_TRUE(selection2, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startNode(mDOMNode);
|
||||
if (peditor) {
|
||||
nsCOMPtr<nsIDOMElement> editorRoot;
|
||||
editor->GetRootElement(getter_AddRefs(editorRoot));
|
||||
startNode = do_QueryInterface(editorRoot);
|
||||
}
|
||||
NS_ENSURE_STATE(startNode);
|
||||
|
||||
nsCOMPtr<nsIDOMNodeList> childNodes;
|
||||
nsresult rv = startNode->GetChildNodes(getter_AddRefs(childNodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1692,7 +1783,8 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
|
|||
{
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMArray<nsIDOMRange> ranges;
|
||||
nsresult rv = GetSelections(nsnull, nsnull, &ranges);
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, nsnull, &ranges);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aSelectionCount = ranges.Count();
|
||||
|
@ -1709,7 +1801,8 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, P
|
|||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMArray<nsIDOMRange> ranges;
|
||||
nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel), &ranges);
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, getter_AddRefs(domSel), &ranges);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 rangeCount = ranges.Count();
|
||||
|
@ -1762,7 +1855,8 @@ nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum,
|
|||
PRInt32 aEndOffset)
|
||||
{
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, getter_AddRefs(domSel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Caret is a collapsed selection
|
||||
|
@ -1810,7 +1904,8 @@ nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum,
|
|||
NS_IMETHODIMP nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset)
|
||||
{
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, getter_AddRefs(domSel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 rangeCount;
|
||||
|
@ -1825,7 +1920,8 @@ NS_IMETHODIMP nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32
|
|||
NS_IMETHODIMP nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum)
|
||||
{
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
|
||||
nsnull, getter_AddRefs(domSel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 rangeCount;
|
||||
|
@ -2037,3 +2133,356 @@ nsHyperTextAccessible::GetDOMPointByFrameOffset(nsIFrame *aFrame,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsHyperTextAccessible
|
||||
nsresult
|
||||
nsHyperTextAccessible::DOMRangeBoundToHypertextOffset(nsIDOMRange *aRange,
|
||||
PRBool aIsStartBound,
|
||||
PRBool aIsStartHTOffset,
|
||||
PRInt32 *aHTOffset)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
PRInt32 nodeOffset = 0;
|
||||
|
||||
nsresult rv;
|
||||
if (aIsStartBound) {
|
||||
rv = aRange->GetStartContainer(getter_AddRefs(node));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aRange->GetStartOffset(&nodeOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
rv = aRange->GetEndContainer(getter_AddRefs(node));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aRange->GetEndOffset(&nodeOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAccessible> startAcc;
|
||||
rv = DOMPointToHypertextOffset(node, nodeOffset, aHTOffset,
|
||||
getter_AddRefs(startAcc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aIsStartHTOffset && !startAcc)
|
||||
*aHTOffset = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsHyperTextAccessible
|
||||
nsresult
|
||||
nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode,
|
||||
PRInt32 aNodeOffset,
|
||||
PRInt32 *aHTStartOffset,
|
||||
PRInt32 *aHTEndOffset,
|
||||
nsIPersistentProperties *aAttributes)
|
||||
{
|
||||
nsCOMArray<nsIDOMRange> ranges;
|
||||
nsresult rv = GetSelections(nsISelectionController::SELECTION_SPELLCHECK,
|
||||
nsnull, nsnull, &ranges);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 rangeCount = ranges.Count();
|
||||
if (!rangeCount)
|
||||
return NS_OK;
|
||||
|
||||
for (PRInt32 index = 0; index < rangeCount; index++) {
|
||||
nsCOMPtr<nsIDOMRange> range = ranges[index];
|
||||
nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
|
||||
NS_ENSURE_STATE(nsrange);
|
||||
|
||||
PRInt16 result;
|
||||
rv = nsrange->ComparePoint(aNode, aNodeOffset, &result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (result == 1) { // range is before point
|
||||
PRInt32 startHTOffset = 0;
|
||||
rv = DOMRangeBoundToHypertextOffset(range, PR_FALSE, PR_TRUE,
|
||||
&startHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (startHTOffset > *aHTStartOffset)
|
||||
*aHTStartOffset = startHTOffset;
|
||||
|
||||
} else if (result == -1) { // range is after point
|
||||
PRInt32 endHTOffset = 0;
|
||||
rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_FALSE,
|
||||
&endHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (endHTOffset < *aHTEndOffset)
|
||||
*aHTEndOffset = endHTOffset;
|
||||
|
||||
} else { // point is in range
|
||||
PRInt32 startHTOffset = 0;
|
||||
rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_TRUE,
|
||||
&startHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 endHTOffset = 0;
|
||||
rv = DOMRangeBoundToHypertextOffset(range, PR_FALSE, PR_FALSE,
|
||||
&endHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (startHTOffset > *aHTStartOffset)
|
||||
*aHTStartOffset = startHTOffset;
|
||||
if (endHTOffset < *aHTEndOffset)
|
||||
*aHTEndOffset = endHTOffset;
|
||||
|
||||
if (aAttributes) {
|
||||
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::invalid,
|
||||
NS_LITERAL_STRING("spelling"));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsHyperTextAccessible
|
||||
nsresult
|
||||
nsHyperTextAccessible::GetLangTextAttributes(PRBool aIncludeDefAttrs,
|
||||
nsIDOMNode *aSourceNode,
|
||||
PRInt32 *aStartHTOffset,
|
||||
PRInt32 *aEndHTOffset,
|
||||
nsIPersistentProperties *aAttributes)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> sourceElm(nsAccUtils::GetDOMElementFor(aSourceNode));
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(sourceElm));
|
||||
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(mDOMNode));
|
||||
|
||||
nsAutoString lang;
|
||||
nsAccUtils::GetLanguageFor(content, rootContent, lang);
|
||||
|
||||
nsAutoString rootLang;
|
||||
nsresult rv = GetLanguage(rootLang);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aAttributes) {
|
||||
// Expose 'language' text attribute if the DOM 'lang' attribute is
|
||||
// presented and it's different from the 'lang' attribute on the root
|
||||
// element or we should include default values of text attribute.
|
||||
const nsAString& resultLang = lang.IsEmpty() ? rootLang : lang;
|
||||
if (!resultLang.IsEmpty() && (aIncludeDefAttrs || lang != rootLang))
|
||||
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::language,
|
||||
resultLang);
|
||||
}
|
||||
|
||||
nsLangTextAttr textAttr(lang, rootContent);
|
||||
return GetRangeForTextAttr(aSourceNode, &textAttr,
|
||||
aStartHTOffset, aEndHTOffset);
|
||||
}
|
||||
|
||||
// nsHyperTextAccessible
|
||||
nsresult
|
||||
nsHyperTextAccessible::GetCSSTextAttributes(PRBool aIncludeDefAttrs,
|
||||
nsIDOMNode *aSourceNode,
|
||||
PRInt32 *aStartHTOffset,
|
||||
PRInt32 *aEndHTOffset,
|
||||
nsIPersistentProperties *aAttributes)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> sourceElm(nsAccUtils::GetDOMElementFor(aSourceNode));
|
||||
nsCOMPtr<nsIDOMElement> rootElm(nsAccUtils::GetDOMElementFor(mDOMNode));
|
||||
|
||||
nsCSSTextAttr textAttr(aIncludeDefAttrs, sourceElm, rootElm);
|
||||
while (textAttr.iterate()) {
|
||||
nsCAutoString name;
|
||||
nsAutoString value, oldValue;
|
||||
if (aAttributes && textAttr.get(name, value))
|
||||
aAttributes->SetStringProperty(name, value, oldValue);
|
||||
|
||||
nsresult rv = GetRangeForTextAttr(aSourceNode, &textAttr,
|
||||
aStartHTOffset, aEndHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsHyperTextAccessible
|
||||
nsresult
|
||||
nsHyperTextAccessible::GetRangeForTextAttr(nsIDOMNode *aNode,
|
||||
nsTextAttr *aComparer,
|
||||
PRInt32 *aStartHTOffset,
|
||||
PRInt32 *aEndHTOffset)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> rootElm(nsAccUtils::GetDOMElementFor(mDOMNode));
|
||||
NS_ENSURE_STATE(rootElm);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> tmpNode(aNode);
|
||||
nsCOMPtr<nsIDOMNode> currNode(aNode);
|
||||
|
||||
// Navigate backwards and forwards from current node to the root node to
|
||||
// calculate range bounds for the text attribute. Navigation sequence is the
|
||||
// following:
|
||||
// 1. Navigate through the siblings.
|
||||
// 2. If the traversed sibling has children then navigate from its leaf child
|
||||
// to it through whole tree of the traversed sibling.
|
||||
// 3. Get the parent and cycle algorithm until the root node.
|
||||
|
||||
// Navigate backwards (find the start offset).
|
||||
while (currNode && currNode != rootElm) {
|
||||
nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(currNode));
|
||||
NS_ENSURE_STATE(currElm);
|
||||
|
||||
if (currNode != aNode && !aComparer->equal(currElm)) {
|
||||
PRInt32 startHTOffset = 0;
|
||||
nsCOMPtr<nsIAccessible> startAcc;
|
||||
nsresult rv = DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
|
||||
getter_AddRefs(startAcc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!startAcc)
|
||||
startHTOffset = 0;
|
||||
|
||||
if (startHTOffset > *aStartHTOffset)
|
||||
*aStartHTOffset = startHTOffset;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
|
||||
if (tmpNode) {
|
||||
// Navigate through the subtree of traversed children to calculate
|
||||
// left bound of the range.
|
||||
FindStartOffsetInSubtree(tmpNode, currNode, aComparer, aStartHTOffset);
|
||||
}
|
||||
|
||||
currNode->GetParentNode(getter_AddRefs(tmpNode));
|
||||
currNode.swap(tmpNode);
|
||||
}
|
||||
|
||||
// Navigate forwards (find the end offset).
|
||||
PRBool moveIntoSubtree = PR_TRUE;
|
||||
currNode = aNode;
|
||||
while (currNode && currNode != rootElm) {
|
||||
nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(currNode));
|
||||
NS_ENSURE_STATE(currElm);
|
||||
|
||||
// Stop new end offset searching if the given text attribute changes its
|
||||
// value.
|
||||
if (!aComparer->equal(currElm)) {
|
||||
PRInt32 endHTOffset = 0;
|
||||
nsresult rv = DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (endHTOffset < *aEndHTOffset)
|
||||
*aEndHTOffset = endHTOffset;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (moveIntoSubtree) {
|
||||
// Navigate through subtree of traversed node. We use 'moveIntoSubtree'
|
||||
// flag to avoid traversing the same subtree twice.
|
||||
currNode->GetFirstChild(getter_AddRefs(tmpNode));
|
||||
if (tmpNode)
|
||||
FindEndOffsetInSubtree(tmpNode, aComparer, aEndHTOffset);
|
||||
}
|
||||
|
||||
currNode->GetNextSibling(getter_AddRefs(tmpNode));
|
||||
moveIntoSubtree = PR_TRUE;
|
||||
if (!tmpNode) {
|
||||
currNode->GetParentNode(getter_AddRefs(tmpNode));
|
||||
moveIntoSubtree = PR_FALSE;
|
||||
}
|
||||
|
||||
currNode.swap(tmpNode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsHyperTextAccessible::FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
|
||||
nsTextAttr *aComparer,
|
||||
PRInt32 *aHTOffset)
|
||||
{
|
||||
if (!aCurrNode)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(aCurrNode));
|
||||
NS_ENSURE_STATE(currElm);
|
||||
|
||||
// If the given text attribute (pointed by nsTextAttr object) changes its
|
||||
// value on the traversed element then fit the end of range.
|
||||
if (!aComparer->equal(currElm)) {
|
||||
PRInt32 endHTOffset = 0;
|
||||
nsresult rv = DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (endHTOffset < *aHTOffset)
|
||||
*aHTOffset = endHTOffset;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Deeply traverse into the tree to fit the end of range.
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
PRBool res = FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
if (FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHyperTextAccessible::FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
|
||||
nsIDOMNode *aPrevNode,
|
||||
nsTextAttr *aComparer,
|
||||
PRInt32 *aHTOffset)
|
||||
{
|
||||
if (!aCurrNode)
|
||||
return PR_FALSE;
|
||||
|
||||
// Find the closest element back to the traversed element.
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
aCurrNode->GetLastChild(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
if (FindStartOffsetInSubtree(nextNode, aPrevNode, aComparer, aHTOffset))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(aCurrNode));
|
||||
NS_ENSURE_STATE(currElm);
|
||||
|
||||
// If the given text attribute (pointed by nsTextAttr object) changes its
|
||||
// value on the traversed element then fit the start of range.
|
||||
if (!aComparer->equal(currElm)) {
|
||||
PRInt32 startHTOffset = 0;
|
||||
nsCOMPtr<nsIAccessible> startAcc;
|
||||
nsresult rv = DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
|
||||
getter_AddRefs(startAcc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!startAcc)
|
||||
startHTOffset = 0;
|
||||
|
||||
if (startHTOffset > *aHTOffset)
|
||||
*aHTOffset = startHTOffset;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Moving backwards to find the start of range.
|
||||
aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
if (FindStartOffsetInSubtree(nextNode, aCurrNode, aComparer, aHTOffset))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include "nsIAccessibleHyperText.h"
|
||||
#include "nsIAccessibleEditableText.h"
|
||||
#include "nsAccessibleEventData.h"
|
||||
#include "nsTextUtils.h"
|
||||
|
||||
#include "nsFrameSelection.h"
|
||||
#include "nsISelectionController.h"
|
||||
|
||||
|
@ -64,7 +66,6 @@ const PRUnichar kForcedNewLineChar = '\n';
|
|||
{ 0xa9, 0x2e, 0x95, 0x23, 0x97, 0x05, 0xf3, 0x0b } \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Special Accessible that knows how contain both text and embedded objects
|
||||
*/
|
||||
|
@ -81,8 +82,11 @@ public:
|
|||
NS_DECL_NSIACCESSIBLEEDITABLETEXT
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_HYPERTEXTACCESSIBLE_IMPL_CID)
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetRole(PRUint32 *aRole);
|
||||
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
|
||||
|
||||
// nsAccessible
|
||||
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
|
||||
void CacheChildren();
|
||||
|
||||
|
@ -124,6 +128,17 @@ public:
|
|||
nsIAccessible **aFinalAccessible = nsnull,
|
||||
PRBool aIsEndOffset = PR_FALSE);
|
||||
|
||||
/**
|
||||
* Turn a hypertext offsets into DOM point.
|
||||
*
|
||||
* @param aHTOffset [in] the given start hypertext offset
|
||||
* @param aNode [out] start node
|
||||
* @param aOffset [out] offset inside the start node
|
||||
*/
|
||||
nsresult HypertextOffsetToDOMPoint(PRInt32 aHTOffset,
|
||||
nsIDOMNode **aNode,
|
||||
PRInt32 *aOffset);
|
||||
|
||||
/**
|
||||
* Turn a start and end hypertext offsets into DOM range.
|
||||
*
|
||||
|
@ -211,15 +226,23 @@ protected:
|
|||
|
||||
// Selection helpers
|
||||
|
||||
/**
|
||||
* Get the relevant selection interfaces and ranges for the current hyper text
|
||||
* @param aSelCon The selection controller for the current hyper text, or nsnull if not needed
|
||||
* @param aDomSel The selection interface for the current hyper text, or nsnull if not needed
|
||||
* @param aRanges The selected ranges within the current subtree, or nsnull if not needed
|
||||
/**
|
||||
* Get the relevant selection interfaces and ranges for the current hyper
|
||||
* text.
|
||||
*
|
||||
* @param aType [in] the selection type
|
||||
* @param aSelCon [out, optional] the selection controller for the current
|
||||
* hyper text
|
||||
* @param aDomSel [out, optional] the selection interface for the current
|
||||
* hyper text
|
||||
* @param aRanges [out, optional] the selected ranges within the current
|
||||
* subtree
|
||||
*/
|
||||
nsresult GetSelections(nsISelectionController **aSelCon,
|
||||
nsresult GetSelections(PRInt16 aType,
|
||||
nsISelectionController **aSelCon,
|
||||
nsISelection **aDomSel = nsnull,
|
||||
nsCOMArray<nsIDOMRange>* aRanges = nsnull);
|
||||
|
||||
nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos);
|
||||
|
||||
/**
|
||||
|
@ -233,6 +256,125 @@ protected:
|
|||
nsresult GetDOMPointByFrameOffset(nsIFrame *aFrame, PRInt32 aOffset,
|
||||
nsIAccessible *aAccessible,
|
||||
nsIDOMNode **aNode, PRInt32 *aNodeOffset);
|
||||
|
||||
|
||||
/**
|
||||
* Return hyper text offset for the specified bound of the given DOM range.
|
||||
* If the bound is outside of the hyper text then offset value is either
|
||||
* 0 or number of characters of hyper text, it depends on type of requested
|
||||
* offset. The method is a wrapper for DOMPointToHypertextOffset.
|
||||
*
|
||||
* @param aRange [in] the given range
|
||||
* @param aIsStartBound [in] specifies whether the required range bound is
|
||||
* start bound
|
||||
* @param aIsStartOffset [in] the offset type, used when the range bound is
|
||||
* outside of hyper text
|
||||
* @param aHTOffset [out] the result offset
|
||||
*/
|
||||
nsresult DOMRangeBoundToHypertextOffset(nsIDOMRange *aRange,
|
||||
PRBool aIsStartBound,
|
||||
PRBool aIsStartOffset,
|
||||
PRInt32 *aHTOffset);
|
||||
|
||||
/**
|
||||
* Set 'misspelled' text attribute and return range offsets where the
|
||||
* attibute is stretched. If the text is not misspelled at the given offset
|
||||
* then we expose only range offsets where text is not misspelled. The method
|
||||
* is used by GetTextAttributes() method.
|
||||
*
|
||||
* @param aIncludeDefAttrs [in] points whether text attributes having default
|
||||
* values of attributes should be included
|
||||
* @param aSourceNode [in] the node we start to traverse from
|
||||
* @param aStartOffset [in, out] the start offset
|
||||
* @param aEndOffset [in, out] the end offset
|
||||
* @param aAttributes [out, optional] result attributes
|
||||
*/
|
||||
nsresult GetSpellTextAttribute(nsIDOMNode *aNode, PRInt32 aNodeOffset,
|
||||
PRInt32 *aStartOffset,
|
||||
PRInt32 *aEndOffset,
|
||||
nsIPersistentProperties *aAttributes);
|
||||
|
||||
/**
|
||||
* Set 'lang' text attribute and return range offsets where attibute is
|
||||
* stretched. The method is used by GetTextAttributes() method.
|
||||
*
|
||||
* @param aIncludeDefAttrs [in] points whether text attributes having default
|
||||
* values of attributes should be included
|
||||
* @param aSourceNode [in] the node we start to traverse from
|
||||
* @param aStartOffset [in, out] the start offset
|
||||
* @param aEndOffset [in, out] the end offset
|
||||
* @param aAttributes [out, optional] result attributes
|
||||
*/
|
||||
nsresult GetLangTextAttributes(PRBool aIncludeDefAttrs,
|
||||
nsIDOMNode *aSourceNode,
|
||||
PRInt32 *aStartOffset,
|
||||
PRInt32 *aEndOffset,
|
||||
nsIPersistentProperties *aAttributes);
|
||||
|
||||
/**
|
||||
* Set CSS based text attribute and return range offsets where attibutes are
|
||||
* stretched. The method is used by GetTextAttributes() method.
|
||||
*
|
||||
* @param aIncludeDefAttrs [in] points whether text attributes having default
|
||||
* values of attributes should be included
|
||||
* @param aSourceNode [in] the node we start to traverse from
|
||||
* @param aStartOffset [in, out] the start offset
|
||||
* @param aEndOffset [in, out] the end offset
|
||||
* @param aAttributes [out, optional] result attributes
|
||||
*/
|
||||
nsresult GetCSSTextAttributes(PRBool aIncludeDefAttrs,
|
||||
nsIDOMNode *aSourceNode,
|
||||
PRInt32 *aStartOffset,
|
||||
PRInt32 *aEndOffset,
|
||||
nsIPersistentProperties *aAttributes);
|
||||
|
||||
/**
|
||||
* Calculates range (start and end offsets) of text where the text attribute
|
||||
* (pointed by nsTextAttr object) is stretched. New offsets may be smaller if
|
||||
* the given text attribute changes its value before or after the given
|
||||
* offsets.
|
||||
*
|
||||
* @param aNode [in] the node we start to traverse from
|
||||
* @param aComparer [in] object used to describe the text attribute
|
||||
* @param aStartHTOffset [in, out] the start offset
|
||||
* @param aEndHTOffset [in, out] the end offset
|
||||
*/
|
||||
nsresult GetRangeForTextAttr(nsIDOMNode *aNode,
|
||||
nsTextAttr *aComparer,
|
||||
PRInt32 *aStartHTOffset,
|
||||
PRInt32 *aEndHTOffset);
|
||||
|
||||
/**
|
||||
* Find new end offset for text attributes navigating through the tree. New
|
||||
* end offset may be smaller if the given text attribute (pointed by
|
||||
* nsTextAttr object) changes its value before the given end offset.
|
||||
*
|
||||
* @param aCurrNode [in] the first node of the tree
|
||||
* @param aComparer [in] object used to describe the text attribute
|
||||
* @param aHTOffset [in, out] the end offset
|
||||
* @return true if the end offset has been changed
|
||||
*/
|
||||
PRBool FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
|
||||
nsTextAttr *aComparer,
|
||||
PRInt32 *aHTOffset);
|
||||
|
||||
/**
|
||||
* Find the start offset for text attributes navigating through the tree. New
|
||||
* start offset may be bigger if the given text attribute (pointed by
|
||||
* nsTextAttr object) changes its value after the given start offset.
|
||||
*
|
||||
* @param aCurrNode [in] the node navigating through thee thee is started
|
||||
* from
|
||||
* @param aPrevNode [in] the previous node placed before the start node
|
||||
* @param aComparer [in] object used to describe the text attribute
|
||||
* @param aHTOffset [in, out] the start offset
|
||||
* @return true if the start offset has been changed
|
||||
*/
|
||||
PRBool FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
|
||||
nsIDOMNode *aPrevNode,
|
||||
nsTextAttr *aComparer,
|
||||
PRInt32 *aHTOffset);
|
||||
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsIAccessibleTypes.h"
|
||||
#include "nsIWinAccessNode.h"
|
||||
#include "nsAccessNodeWrap.h"
|
||||
#include "nsAccessibleWrap.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
@ -108,32 +109,26 @@ __try {
|
|||
|
||||
GET_NSIACCESSIBLETEXT
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
PRInt32 startOffset = 0, endOffset = 0;
|
||||
textAcc->GetAttributeRange(aOffset, &startOffset, &endOffset,
|
||||
getter_AddRefs(accessible));
|
||||
if (!accessible)
|
||||
return E_FAIL;
|
||||
|
||||
nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(accessible));
|
||||
if (!winAccessNode)
|
||||
return E_FAIL;
|
||||
|
||||
void *instancePtr = 0;
|
||||
winAccessNode->QueryNativeInterface(IID_IAccessible2, &instancePtr);
|
||||
if (!instancePtr)
|
||||
return E_FAIL;
|
||||
|
||||
IAccessible2 *pAccessible2 = static_cast<IAccessible2*>(instancePtr);
|
||||
HRESULT hr = pAccessible2->get_attributes(aTextAttributes);
|
||||
pAccessible2->Release();
|
||||
nsCOMPtr<nsIPersistentProperties> attributes;
|
||||
nsresult rv = textAcc->GetTextAttributes(PR_TRUE, aOffset,
|
||||
&startOffset, &endOffset,
|
||||
getter_AddRefs(attributes));
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
HRESULT hr = nsAccessibleWrap::ConvertToIA2Attributes(attributes,
|
||||
aTextAttributes);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
*aStartOffset = startOffset;
|
||||
*aEndOffset = endOffset;
|
||||
return hr;
|
||||
|
||||
return S_OK;
|
||||
|
||||
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
|
||||
return E_NOTIMPL;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsAccessNodeWrap.h"
|
||||
#include <tchar.h>
|
||||
#include "ISimpleDOMNode_i.c"
|
||||
#include "nsAccessibilityAtoms.h"
|
||||
#include "nsIAccessibilityService.h"
|
||||
|
@ -66,6 +67,8 @@ LPFNNOTIFYWINEVENT nsAccessNodeWrap::gmNotifyWinEvent = nsnull;
|
|||
LPFNGETGUITHREADINFO nsAccessNodeWrap::gmGetGUIThreadInfo = nsnull;
|
||||
|
||||
PRBool nsAccessNodeWrap::gIsEnumVariantSupportDisabled = 0;
|
||||
// Used to determine whether an IAccessible2 compatible screen reader is loaded.
|
||||
PRBool nsAccessNodeWrap::gIsIA2Disabled = PR_FALSE;
|
||||
|
||||
nsIAccessibleTextChangeEvent *nsAccessNodeWrap::gTextEvent = nsnull;
|
||||
|
||||
|
@ -599,6 +602,8 @@ void nsAccessNodeWrap::InitAccessibility()
|
|||
gmGetGUIThreadInfo = (LPFNGETGUITHREADINFO)GetProcAddress(gmUserLib,"GetGUIThreadInfo");
|
||||
}
|
||||
|
||||
DoATSpecificProcessing();
|
||||
|
||||
nsAccessNode::InitXPAccessibility();
|
||||
}
|
||||
|
||||
|
@ -655,3 +660,40 @@ GetHRESULT(nsresult aResult)
|
|||
}
|
||||
}
|
||||
|
||||
PRBool nsAccessNodeWrap::IsOnlyMsaaCompatibleJawsPresent()
|
||||
{
|
||||
HMODULE jhookhandle = ::GetModuleHandleW(NS_LITERAL_STRING("jhook").get());
|
||||
if (!jhookhandle)
|
||||
return PR_FALSE; // No JAWS, or some other screen reader, use IA2
|
||||
|
||||
PRUnichar fileName[MAX_PATH];
|
||||
::GetModuleFileNameW(jhookhandle, fileName, MAX_PATH);
|
||||
|
||||
DWORD dummy;
|
||||
DWORD length = ::GetFileVersionInfoSizeW(fileName, &dummy);
|
||||
|
||||
LPBYTE versionInfo = new BYTE[length];
|
||||
::GetFileVersionInfoW(fileName, 0, length, versionInfo);
|
||||
|
||||
UINT uLen;
|
||||
VS_FIXEDFILEINFO *fixedFileInfo;
|
||||
::VerQueryValueW(versionInfo, L"\\", (LPVOID*)&fixedFileInfo, &uLen);
|
||||
DWORD dwFileVersionMS = fixedFileInfo->dwFileVersionMS;
|
||||
DWORD dwFileVersionLS = fixedFileInfo->dwFileVersionLS;
|
||||
delete [] versionInfo;
|
||||
|
||||
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
|
||||
// DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
|
||||
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
|
||||
// DWORD dwRightMost = LOWORD(dwFileVersionLS);
|
||||
|
||||
return (dwLeftMost < 8
|
||||
|| (dwLeftMost == 8 && dwSecondRight < 2173));
|
||||
}
|
||||
|
||||
void nsAccessNodeWrap::DoATSpecificProcessing()
|
||||
{
|
||||
if (IsOnlyMsaaCompatibleJawsPresent())
|
||||
// All versions below 8.0.2173 are not compatible
|
||||
gIsIA2Disabled = PR_TRUE;
|
||||
}
|
||||
|
|
|
@ -158,12 +158,20 @@ class nsAccessNodeWrap : public nsAccessNode,
|
|||
|
||||
static int FilterA11yExceptions(unsigned int aCode, EXCEPTION_POINTERS *aExceptionInfo);
|
||||
|
||||
static PRBool IsOnlyMsaaCompatibleJawsPresent();
|
||||
static void DoATSpecificProcessing();
|
||||
protected:
|
||||
void GetAccessibleFor(nsIDOMNode *node, nsIAccessible **newAcc);
|
||||
ISimpleDOMNode* MakeAccessNode(nsIDOMNode *node);
|
||||
|
||||
static PRBool gIsEnumVariantSupportDisabled;
|
||||
|
||||
/**
|
||||
* Used to determine whether an IAccessible2 compatible screen reader is
|
||||
* loaded. Currently used for JAWS versions older than 8.0.2173.
|
||||
*/
|
||||
static PRBool gIsIA2Disabled;
|
||||
|
||||
/**
|
||||
* It is used in nsHyperTextAccessibleWrap for IA2::newText/oldText
|
||||
* implementation.
|
||||
|
|
|
@ -117,7 +117,7 @@ __try {
|
|||
*ppv = static_cast<IEnumVARIANT*>(this);
|
||||
} else if (IID_IServiceProvider == iid)
|
||||
*ppv = static_cast<IServiceProvider*>(this);
|
||||
else if (IID_IAccessible2 == iid)
|
||||
else if (IID_IAccessible2 == iid && !gIsIA2Disabled)
|
||||
*ppv = static_cast<IAccessible2*>(this);
|
||||
|
||||
if (NULL == *ppv) {
|
||||
|
@ -1584,60 +1584,7 @@ __try {
|
|||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
if (!attributes)
|
||||
return S_FALSE;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> propEnum;
|
||||
attributes->Enumerate(getter_AddRefs(propEnum));
|
||||
if (!propEnum)
|
||||
return E_FAIL;
|
||||
|
||||
nsAutoString strAttrs;
|
||||
|
||||
const char kCharsToEscape[] = ":;=,\\";
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> propSupports;
|
||||
propEnum->GetNext(getter_AddRefs(propSupports));
|
||||
|
||||
nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
|
||||
if (!propElem)
|
||||
return E_FAIL;
|
||||
|
||||
nsCAutoString name;
|
||||
rv = propElem->GetKey(name);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
PRUint32 offset = 0;
|
||||
while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
||||
name.Insert('\\', offset);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
nsAutoString value;
|
||||
rv = propElem->GetValue(value);
|
||||
if (NS_FAILED(rv))
|
||||
return E_FAIL;
|
||||
|
||||
offset = 0;
|
||||
while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
||||
value.Insert('\\', offset);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
AppendUTF8toUTF16(name, strAttrs);
|
||||
strAttrs.Append(':');
|
||||
strAttrs.Append(value);
|
||||
strAttrs.Append(';');
|
||||
}
|
||||
|
||||
if (strAttrs.IsEmpty())
|
||||
return S_FALSE;
|
||||
|
||||
*aAttributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
|
||||
return *aAttributes ? S_OK : E_OUTOFMEMORY;
|
||||
return ConvertToIA2Attributes(attributes, aAttributes);
|
||||
|
||||
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
|
||||
return E_FAIL;
|
||||
|
@ -1829,6 +1776,69 @@ nsAccessibleWrap::GetHWNDFor(nsIAccessible *aAccessible)
|
|||
return hWnd;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
nsAccessibleWrap::ConvertToIA2Attributes(nsIPersistentProperties *aAttributes,
|
||||
BSTR *aIA2Attributes)
|
||||
{
|
||||
*aIA2Attributes = NULL;
|
||||
|
||||
// The format is name:value;name:value; with \ for escaping these
|
||||
// characters ":;=,\".
|
||||
|
||||
if (!aAttributes)
|
||||
return S_FALSE;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> propEnum;
|
||||
aAttributes->Enumerate(getter_AddRefs(propEnum));
|
||||
if (!propEnum)
|
||||
return E_FAIL;
|
||||
|
||||
nsAutoString strAttrs;
|
||||
|
||||
const char kCharsToEscape[] = ":;=,\\";
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> propSupports;
|
||||
propEnum->GetNext(getter_AddRefs(propSupports));
|
||||
|
||||
nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
|
||||
if (!propElem)
|
||||
return E_FAIL;
|
||||
|
||||
nsCAutoString name;
|
||||
if (NS_FAILED(propElem->GetKey(name)))
|
||||
return E_FAIL;
|
||||
|
||||
PRUint32 offset = 0;
|
||||
while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
||||
name.Insert('\\', offset);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
nsAutoString value;
|
||||
if (NS_FAILED(propElem->GetValue(value)))
|
||||
return E_FAIL;
|
||||
|
||||
offset = 0;
|
||||
while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
|
||||
value.Insert('\\', offset);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
AppendUTF8toUTF16(name, strAttrs);
|
||||
strAttrs.Append(':');
|
||||
strAttrs.Append(value);
|
||||
strAttrs.Append(';');
|
||||
}
|
||||
|
||||
if (strAttrs.IsEmpty())
|
||||
return S_FALSE;
|
||||
|
||||
*aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
|
||||
return *aIA2Attributes ? S_OK : E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
IDispatch *nsAccessibleWrap::NativeAccessible(nsIAccessible *aXPAccessible)
|
||||
{
|
||||
if (!aXPAccessible) {
|
||||
|
|
|
@ -296,6 +296,8 @@ class nsAccessibleWrap : public nsAccessible,
|
|||
// Helper methods
|
||||
static PRInt32 GetChildIDFor(nsIAccessible* aAccessible);
|
||||
static HWND GetHWNDFor(nsIAccessible *aAccessible);
|
||||
static HRESULT ConvertToIA2Attributes(nsIPersistentProperties *aAttributes,
|
||||
BSTR *aIA2Attributes);
|
||||
|
||||
/**
|
||||
* System caret support: update the Windows caret position.
|
||||
|
|
|
@ -47,13 +47,20 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_TEST_FILES =\
|
||||
moz.png \
|
||||
nsIAccessible_actions.js \
|
||||
nsIAccessible_name.css \
|
||||
nsIAccessible_name.xbl \
|
||||
test_aria_activedescendant.html \
|
||||
test_aria_role_article.html \
|
||||
test_bug368835.xul \
|
||||
test_bug420863.html \
|
||||
test_cssattrs.html \
|
||||
test_groupattrs.xul \
|
||||
test_table_indexes.html \
|
||||
$(warning test_table_indexes.html temporarily disabled) \
|
||||
test_nsIAccessible_actions.html \
|
||||
test_nsIAccessible_actions.xul \
|
||||
test_nsIAccessible_name.html \
|
||||
test_nsIAccessible_name.xul \
|
||||
test_nsIAccessibleTable_1.html \
|
||||
test_nsIAccessibleTable_2.html \
|
||||
test_nsIAccessibleTable_3.html \
|
||||
|
@ -65,6 +72,7 @@ _TEST_FILES =\
|
|||
test_nsIAccessibleHyperText.html \
|
||||
test_nsIAccessibleImage.html \
|
||||
test_nsOuterDocAccessible.html \
|
||||
test_textattrs.html \
|
||||
test_textboxes.html \
|
||||
test_textboxes.xul \
|
||||
testTextboxes.js \
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// General
|
||||
|
||||
const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
|
||||
const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
|
||||
|
||||
var gAccRetrieval = null;
|
||||
|
||||
function initialize()
|
||||
{
|
||||
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(nsIAccessibleRetrieval);
|
||||
}
|
||||
|
||||
addLoadEvent(initialize);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Event constants
|
||||
|
||||
const MOUSEDOWN_EVENT = 1;
|
||||
const MOUSEUP_EVENT = 2;
|
||||
const CLICK_EVENT = 4;
|
||||
const COMMAND_EVENT = 8;
|
||||
|
||||
const CLICK_EVENTS = MOUSEDOWN_EVENT | MOUSEUP_EVENT | CLICK_EVENT;
|
||||
const ALL_EVENTS = CLICK_EVENTS | COMMAND_EVENT;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public functions
|
||||
|
||||
function testActions(aArray, aIndex)
|
||||
{
|
||||
if (!aIndex)
|
||||
aIndex = 0;
|
||||
|
||||
if (aIndex == aArray.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var ID = aArray[aIndex].ID;
|
||||
var actionName = aArray[aIndex].actionName;
|
||||
var events = aArray[aIndex].events;
|
||||
|
||||
var elm = document.getElementById(ID);
|
||||
if (!elm) {
|
||||
ok(false, "There is no element with ID " + ID);
|
||||
SimpleTest.finish();
|
||||
return null;
|
||||
}
|
||||
|
||||
var acc = null;
|
||||
try {
|
||||
acc = gAccRetrieval.getAccessibleFor(elm);
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (!acc) {
|
||||
ok(false, "There is no accessible for " + ID);
|
||||
SimpleTest.finish();
|
||||
return null;
|
||||
}
|
||||
|
||||
is(acc.getActionName(0), actionName,
|
||||
"Wrong action name of the accessible for " + ID);
|
||||
|
||||
gEventHandler.initialize(ID, elm, events);
|
||||
|
||||
acc.doAction(0);
|
||||
|
||||
window.setTimeout(
|
||||
function()
|
||||
{
|
||||
gEventHandler.checkEvents();
|
||||
testActions(aArray, aIndex + 1);
|
||||
},
|
||||
200
|
||||
);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
|
||||
var gEventHandler =
|
||||
{
|
||||
initialize: function(aID, aElm, aExpectedEvents)
|
||||
{
|
||||
this.ID = aID,
|
||||
this.element = aElm;
|
||||
this.mExpectedEvents = aExpectedEvents;
|
||||
this.mFiredEvents = 0;
|
||||
|
||||
if (this.mExpectedEvents & MOUSEDOWN_EVENT)
|
||||
aElm.addEventListener("mousedown", this, false);
|
||||
|
||||
if (this.mExpectedEvents & MOUSEUP_EVENT)
|
||||
aElm.addEventListener("mouseup", this, false);
|
||||
|
||||
if (this.mExpectedEvents & CLICK_EVENT)
|
||||
aElm.addEventListener("click", this, false);
|
||||
|
||||
if (this.mExpectedEvents & COMMAND_EVENT)
|
||||
aElm.addEventListener("command", this, false);
|
||||
},
|
||||
|
||||
checkEvents: function()
|
||||
{
|
||||
if (this.mExpectedEvents & MOUSEDOWN_EVENT) {
|
||||
ok(this.mFiredEvents & MOUSEDOWN_EVENT,
|
||||
"mousedown hasn't been fired for " + this.ID);
|
||||
this.element.removeEventListener("mousedown", this, false);
|
||||
}
|
||||
|
||||
if (this.mExpectedEvents & MOUSEUP_EVENT) {
|
||||
ok(this.mFiredEvents & MOUSEUP_EVENT,
|
||||
"mouseup hasn't been fired for " + this.ID);
|
||||
this.element.removeEventListener("mouseup", this, false);
|
||||
}
|
||||
|
||||
if (this.mExpectedEvents & CLICK_EVENT) {
|
||||
ok(this.mFiredEvents & CLICK_EVENT,
|
||||
"click hasn't been fired for " + this.ID);
|
||||
this.element.removeEventListener("click", this, false);
|
||||
}
|
||||
|
||||
if (this.mExpectedEvents & COMMAND_EVENT) {
|
||||
ok(this.mFiredEvents & COMMAND_EVENT,
|
||||
"command hasn't been fired for " + this.ID);
|
||||
this.element.removeEventListener("command", this, false);
|
||||
}
|
||||
},
|
||||
|
||||
ID: "",
|
||||
element: null,
|
||||
|
||||
handleEvent : function(aEvent)
|
||||
{
|
||||
if (aEvent.type == "mousedown")
|
||||
this.mFiredEvents |= MOUSEDOWN_EVENT;
|
||||
else if(aEvent.type == "mouseup")
|
||||
this.mFiredEvents |= MOUSEUP_EVENT;
|
||||
else if(aEvent.type == "click")
|
||||
this.mFiredEvents |= CLICK_EVENT;
|
||||
else if(aEvent.type == "command")
|
||||
this.mFiredEvents |= COMMAND_EVENT;
|
||||
},
|
||||
|
||||
mExpectedEvents: 0,
|
||||
mFiredEvents: 0
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
box.first {
|
||||
-moz-binding: url('chrome://mochikit/content/a11y/accessible/nsIAccessible_name.xbl#first');
|
||||
}
|
||||
|
||||
.second {
|
||||
-moz-binding: url('chrome://mochikit/content/a11y/accessible/nsIAccessible_name.xbl#second');
|
||||
}
|
||||
|
||||
.third {
|
||||
-moz-binding: url('chrome://mochikit/content/a11y/accessible/nsIAccessible_name.xbl#third');
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<bindings xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="first">
|
||||
<content>
|
||||
<xul:textbox anonid="labeled" class="bottom"/>
|
||||
<xul:label control="labeled" value="Label"/>
|
||||
<children/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="second">
|
||||
<content>
|
||||
<xul:box class="first">
|
||||
<xul:label control="toplabeled" value="Top textbox"/>
|
||||
<xul:textbox anonid="toplabeled" class="top"/>
|
||||
</xul:box>
|
||||
<children/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
|
@ -0,0 +1,49 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>nsIAccessible actions testing</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/nsIAccessible_actions.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
var actionsArray = [
|
||||
{
|
||||
ID: "clickable",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
}
|
||||
];
|
||||
testActions(actionsArray);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=410765"
|
||||
title="nsIAccessible actions testing">
|
||||
Mozilla Bug 410765
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="clickable" onclick="">Clickable text</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="nsIAccessible actions testing">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/nsIAccessible_actions.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function doTest()
|
||||
{
|
||||
var actionsArray = [
|
||||
{
|
||||
ID: "menu",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "submenu",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "menuitem",
|
||||
actionName: "click",
|
||||
events: ALL_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "button",
|
||||
actionName: "press",
|
||||
events: ALL_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "buttonmenu",
|
||||
actionName: "press",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "buttonmenu_item",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
}
|
||||
];
|
||||
testActions(actionsArray);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=410765"
|
||||
title="nsIAccessible actions testing">
|
||||
Mozilla Bug 410765
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<menubar>
|
||||
<menu label="menu" id="menu">
|
||||
<menupopup>
|
||||
<menuitem label="menu item" id="menuitem"/>
|
||||
<menu label="submenu" id="submenu">
|
||||
<menupopup>
|
||||
<menuitem label="menu item"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menubar>
|
||||
|
||||
<button label="button" id="button"/>
|
||||
|
||||
<button type="menu" id="buttonmenu" label="button">
|
||||
<menupopup>
|
||||
<menuitem label="item1" id="buttonmenu_item"/>
|
||||
<menuitem label="item1"/>
|
||||
</menupopup>
|
||||
</button>
|
||||
</window>
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>nsIAccessible::name calculation</title>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
|
||||
const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
|
||||
|
||||
var gAccRetrieval = null;
|
||||
|
||||
function testName(aID, aName)
|
||||
{
|
||||
var elm = document.getElementById(aID);
|
||||
if (!elm) {
|
||||
ok(false, "There is no element with ID " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
var acc = null;
|
||||
try {
|
||||
acc = gAccRetrieval.getAccessibleFor(elm);
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (!acc) {
|
||||
ok(false, "There is no accessible for " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
is(acc.name, aName, "Wrong name of the accessible for " + aID);
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(nsIAccessibleRetrieval);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// aria-labelledby
|
||||
|
||||
// Single relation. The value of 'aria-labelledby' contains the ID of
|
||||
// an element. Gets the name from text node of that element.
|
||||
testName("btn_labelledby_text", "text");
|
||||
|
||||
// Multiple relations. The value of 'aria-labelledby' contains the IDs
|
||||
// of elements. Gets the name from text nodes of those elements.
|
||||
testName("btn_labelledby_texts", "text1 text2");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name from subtree (single relation labelled_by).
|
||||
|
||||
// Gets the name from text nodes contained by nested elements
|
||||
testName("btn_labelledby_mixed", "nomore text");
|
||||
|
||||
// Gets the name from text nodes contained by nested elements, ignores
|
||||
// hidden elements (bug 443081).
|
||||
testName("btn_labelledby_mixed_hidden_child", "nomore text2");
|
||||
|
||||
// Gets the name from hidden text nodes contained by nested elements,
|
||||
// (label element is hidden entirely), (bug 443081).
|
||||
testName("btn_labelledby_mixed_hidden", "lala more hidden text");
|
||||
|
||||
// Gets the name from text nodes contained by nested elements having block
|
||||
// representation (every text node value in the name should be devided by
|
||||
// spaces)
|
||||
testName("btn_labelledby_mixed_block", "text more text");
|
||||
|
||||
// Gets the name from text nodes contained by html:td (every text node
|
||||
// value in the name should be devided by spaces).
|
||||
// XXX: this case is rather a feature than strong wanted behaviour.
|
||||
testName("btn_labelledby_mixed_table", "text space text");
|
||||
|
||||
// Gets the name from image accessible.
|
||||
testName("btn_labelledby_mixed_img", "text image");
|
||||
|
||||
// Gets the name from input accessibles
|
||||
// Note: if input have label elements then the name isn't calculated
|
||||
// from them.
|
||||
testName("btn_labelledby_mixed_input",
|
||||
"input button Submit Query Reset input image");
|
||||
|
||||
// Gets the name from the title of object element.
|
||||
testName("btn_labelledby_mixed_object", "object");
|
||||
|
||||
// Gets the name from text nodes. Element br adds space between them.
|
||||
testName("btn_labelledby_mixed_br", "text text");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// label element
|
||||
|
||||
// The label element contains the button. The name is calculated from
|
||||
// this button.
|
||||
// Note: the name contains the content of the button.
|
||||
testName("btn_label_inside", "text10text");
|
||||
|
||||
// The label element and the button are placed in the same form. Gets
|
||||
// the name from the label subtree.
|
||||
testName("btn_label_inform", "in form");
|
||||
|
||||
// The label element is placed outside of form where the button is.
|
||||
// Do not take into account the label.
|
||||
testName("btn_label_outform", "12");
|
||||
|
||||
// The label element and the button are in the same document. Gets the
|
||||
// name from the label subtree.
|
||||
testName("btn_label_indocument", "in document");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// name from children
|
||||
|
||||
// ARIA role button is presented allowing the name calculation from
|
||||
// children.
|
||||
testName("btn_children", "14");
|
||||
|
||||
// ARIA role option is presented allowing the name calculation from
|
||||
// visible children (bug 443081).
|
||||
testName("lb_opt1_children_hidden", "i am visible");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// title attribute
|
||||
|
||||
// If nothing is left. Let's try title attribute.
|
||||
testName("btn_title", "title");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=444279"
|
||||
title="mochitest for accessible name calculating">
|
||||
Mozilla Bug 444279
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<!-- aria-labelledby, single relation -->
|
||||
<span id="labelledby_text">text</span>
|
||||
<button id="btn_labelledby_text"
|
||||
aria-labelledby="labelledby_text">1</button>
|
||||
<br/>
|
||||
|
||||
<!-- aria-labelledby, multiple relations -->
|
||||
<span id="labelledby_text1">text1</span>
|
||||
<span id="labelledby_text2">text2</span>
|
||||
<button id="btn_labelledby_texts"
|
||||
aria-labelledby="labelledby_text1 labelledby_text2">2</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, mixed content -->
|
||||
<span id="labelledby_mixed">no<span>more text</span></span>
|
||||
<button id="btn_labelledby_mixed"
|
||||
aria-labelledby="labelledby_mixed">3</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, mixed/hidden content -->
|
||||
<span id="labelledby_mixed_hidden_child">
|
||||
no<span>more
|
||||
<span style="display: none;">hidden</span>
|
||||
text2
|
||||
<span style="visibility: hidden">hidden2</span>
|
||||
</span>
|
||||
</span>
|
||||
<button id="btn_labelledby_mixed_hidden_child"
|
||||
aria-labelledby="labelledby_mixed_hidden_child">3.1</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, mixed/completely hidden content -->
|
||||
<span id="labelledby_mixed_hidden"
|
||||
style="display: none;">lala <span>more hidden </span>text</span></span>
|
||||
<button id="btn_labelledby_mixed_hidden"
|
||||
aria-labelledby="labelledby_mixed_hidden">3.2</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, mixed content, block structure -->
|
||||
<div id="labelledby_mixed_block"><div>text</div>more text</div></div>
|
||||
<button id="btn_labelledby_mixed_block"
|
||||
aria-labelledby="labelledby_mixed_block">4</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, mixed content, table structure -->
|
||||
<table><tr>
|
||||
<td id="labelledby_mixed_table">text<span>space</span>text</td>
|
||||
</tr></table>
|
||||
<button id="btn_labelledby_mixed_table"
|
||||
aria-labelledby="labelledby_mixed_table">5</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, child img -->
|
||||
<span id="labelledby_mixed_img">text<img alt="image"/></span>
|
||||
<button id="btn_labelledby_mixed_img"
|
||||
aria-labelledby="labelledby_mixed_img">6</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, child inputs -->
|
||||
<span id="labelledby_mixed_input">
|
||||
<input type="button" id="input_button" title="input button"/>
|
||||
<input type="submit" id="input_submit"/>
|
||||
<input type="reset" id="input_reset"/>
|
||||
<input type="image" id="input_image" title="input image"/>
|
||||
</span>
|
||||
<button id="btn_labelledby_mixed_input"
|
||||
aria-labelledby="labelledby_mixed_input">7</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, child object -->
|
||||
<span id="labelledby_mixed_object">
|
||||
<object data="about:blank" title="object"></object>
|
||||
</span>
|
||||
<button id="btn_labelledby_mixed_object"
|
||||
aria-labelledby="labelledby_mixed_object">8</button>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, child br -->
|
||||
<span id="labelledby_mixed_br">text<br/>text</span>
|
||||
<button id="btn_labelledby_mixed_br"
|
||||
aria-labelledby="labelledby_mixed_br">9</button>
|
||||
<br/>
|
||||
|
||||
<!-- label element, label contains the button -->
|
||||
<label>text<button id="btn_label_inside">10</button>text</label>
|
||||
<br/>
|
||||
|
||||
<!-- label element, label and the button are in the same form -->
|
||||
<form>
|
||||
<label for="btn_label_inform">in form</label>
|
||||
<button id="btn_label_inform">11</button>
|
||||
</form>
|
||||
|
||||
<!-- label element, label is outside of the form of the button -->
|
||||
<label for="btn_label_outform">out form</label>
|
||||
<form>
|
||||
<button id="btn_label_outform">12</button>
|
||||
</form>
|
||||
|
||||
<!-- label element, label and the button are in the same document -->
|
||||
<label for="btn_label_indocument">in document</label>
|
||||
<button id="btn_label_indocument">13</button>
|
||||
|
||||
<!-- name from children -->
|
||||
<span id="btn_children" role="button">14</span>
|
||||
|
||||
<!-- name from children, hidden children -->
|
||||
<div role="listbox" tabindex="0">
|
||||
<div id="lb_opt1_children_hidden" role="option" tabindex="0">
|
||||
<span>i am visible</span>
|
||||
<span style="display:none">i am hidden</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- name from title attribute -->
|
||||
<span id="btn_title" role="group" title="title">15</span>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,318 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Accessibility Name Calculating Test.">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
|
||||
const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
|
||||
|
||||
var gAccRetrieval = null;
|
||||
|
||||
function testName(aID, aName)
|
||||
{
|
||||
var elm = document.getElementById(aID);
|
||||
if (!elm) {
|
||||
ok(false, "There is no element with ID " + aID);
|
||||
return null;
|
||||
}
|
||||
|
||||
var acc = null;
|
||||
try {
|
||||
acc = gAccRetrieval.getAccessibleFor(elm);
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (!acc) {
|
||||
ok(false, "There is no accessible for " + aID);
|
||||
return null;
|
||||
}
|
||||
|
||||
is(acc.name, aName, "Wrong name of the accessible for " + aID);
|
||||
return acc;
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(nsIAccessibleRetrieval);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// aria-labelledby
|
||||
|
||||
// Single relation. The value of 'aria-labelledby' contains the ID of
|
||||
// an element. Gets the name from text node of that element.
|
||||
testName("btn_labelledby_text", "text");
|
||||
|
||||
// Multiple relations. The value of 'aria-labelledby' contains the IDs
|
||||
// of elements. Gets the name from text nodes of those elements.
|
||||
testName("btn_labelledby_texts", "text1 text2");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name from subtree (single relation labelled_by).
|
||||
|
||||
// Gets the name from text nodes contained by nested elements.
|
||||
testName("btn_labelledby_mixed", "nomore text");
|
||||
|
||||
// Gets the name from text nodes and selected item of menulist
|
||||
// (other items are ignored).
|
||||
testName("btn_labelledby_mixed_menulist",
|
||||
"nomore text selected item more text");
|
||||
|
||||
// Gets the name from text nodes contained by nested elements, ignores
|
||||
// hidden elements (bug 443081).
|
||||
testName("btn_labelledby_mixed_hidden_child", "nomore text2");
|
||||
|
||||
// Gets the name from hidden text nodes contained by nested elements,
|
||||
// (label element is hidden entirely), (bug 443081)
|
||||
testName("btn_labelledby_mixed_hidden", "lala more hidden text");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name for nsIDOMXULLabeledControlElement.
|
||||
|
||||
// Gets the name from @label attribute.
|
||||
testName("btn_nsIDOMXULLabeledControlElement", "labeled element");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name for nsIDOMXULSelectControlItemElement.
|
||||
|
||||
// Gets the name from @label attribute.
|
||||
testName("li_nsIDOMXULSelectControlItemElement", "select control item");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name if the XUL element doesn't implement nsIDOMXULSelectControlElement
|
||||
// and has @label attribute.
|
||||
|
||||
testName("box_not_nsIDOMXULSelectControlElement", "box");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name from the label element.
|
||||
|
||||
// The label and button are placed on 2nd level relative common parent.
|
||||
testName("btn_label_1", "label1");
|
||||
|
||||
// The label is on 1st, the button is on 5th level relative common parent.
|
||||
testName("btn_label_2", "label2");
|
||||
|
||||
// The label and button are siblings.
|
||||
testName("btn_label_3", "label3");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name from the label element in anonymous content (see bug 362365).
|
||||
|
||||
// Get the name from anonymous label element for anonymous textbox
|
||||
// (@anonid is used).
|
||||
var ID = "box_label_anon1";
|
||||
var box1Acc = testName(ID, "");
|
||||
if (box1Acc) {
|
||||
var textboxAcc = box1Acc.firstChild;
|
||||
is(textboxAcc.name, "Label",
|
||||
"Wrong label for anonymous textbox of " + ID);
|
||||
}
|
||||
|
||||
// Get the name from anonymous label element for anonymous textbox
|
||||
// (@anonid is used). Nested bindings.
|
||||
ID = "box_label_anon2";
|
||||
var box2Acc = testName(ID, "");
|
||||
if (box2Acc) {
|
||||
var textboxAcc = box2Acc.firstChild;
|
||||
is(textboxAcc.name, "Label",
|
||||
"Wrong label for anonymous textbox of " + ID);
|
||||
|
||||
var topTextboxAcc = box2Acc.lastChild;
|
||||
is(topTextboxAcc.name, "Top textbox",
|
||||
"Wrong label for anonymous textbox of " + ID);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// tooltiptext (if nothing above isn't presented then tooltiptext is used)
|
||||
testName("box_tooltiptext", "tooltiptext label");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name from the @title attribute of <toolbaritem/> (original bug 237249).
|
||||
|
||||
// Direct child of toolbaritem.
|
||||
var textboxAcc = testName("toolbaritem_textbox", "ooospspss");
|
||||
|
||||
// Element from anonymous content of direct child of toolbaritem.
|
||||
var dropmarkerAcc = textboxAcc.lastChild;
|
||||
is(dropmarkerAcc.finalRole, nsIAccessibleRole.ROLE_PUSHBUTTON,
|
||||
"The last child of autocomplete textbox 'toolbaritem_textbox' should be dropmarker.");
|
||||
is(dropmarkerAcc.name, "ooospspss",
|
||||
"Wrong name for dropmarker of autocomplete textbox 'toolbaritem_textbox'.");
|
||||
|
||||
// Child from subtree of toolbaritem.
|
||||
testName("toolbaritem_hboxbutton", "ooospspss");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Name from children
|
||||
|
||||
// ARIA role button is presented allowing the name calculation from
|
||||
// children.
|
||||
testName("box_children", "14");
|
||||
|
||||
// ARIA role option is presented allowing the name calculation from
|
||||
// the visible children (bug 443081)
|
||||
testName("lb_opt1_children_hidden", "i am visible");
|
||||
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=444279"
|
||||
title="mochitest for accessible name calculating">
|
||||
Mozilla Bug 444279
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<!-- aria-labelledby, single relation -->
|
||||
<description id="labelledby_text">text</description>
|
||||
<button id="btn_labelledby_text"
|
||||
aria-labelledby="labelledby_text"/>
|
||||
|
||||
<!-- aria-labelledby, multiple relations -->
|
||||
<description id="labelledby_text1">text1</description>
|
||||
<description id="labelledby_text2">text2</description>
|
||||
<button id="btn_labelledby_texts"
|
||||
aria-labelledby="labelledby_text1 labelledby_text2"/>
|
||||
|
||||
<!-- the name from subtree, mixed content -->
|
||||
<description id="labelledby_mixed">
|
||||
no<description>more text</description>
|
||||
</description>
|
||||
<button id="btn_labelledby_mixed"
|
||||
aria-labelledby="labelledby_mixed"/>
|
||||
|
||||
<!-- the name from subtree, mixed/hidden content -->
|
||||
<description id="labelledby_mixed_hidden_child">no<description>more <description hidden="true">hidden</description>text2</description></description>
|
||||
<button id="btn_labelledby_mixed_hidden_child"
|
||||
aria-labelledby="labelledby_mixed_hidden_child"/>
|
||||
|
||||
<!-- the name from subtree, mixed/completely hidden content -->
|
||||
<description id="labelledby_mixed_hidden"
|
||||
hidden="true">lala <description>more hidden </description>text</description>
|
||||
<button id="btn_labelledby_mixed_hidden"
|
||||
aria-labelledby="labelledby_mixed_hidden"/>
|
||||
<br/>
|
||||
|
||||
<!-- the name from subtree, mixed content, ignore items of menulist -->
|
||||
<description id="labelledby_mixed_menulist">
|
||||
no<description>more text</description>
|
||||
<menulist>
|
||||
<menupopup>
|
||||
<menuitem label="selected item"/>
|
||||
<menuitem label="item"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
more text
|
||||
</description>
|
||||
<button id="btn_labelledby_mixed_menulist"
|
||||
aria-labelledby="labelledby_mixed_menulist"/>
|
||||
|
||||
<!-- nsIDOMXULLabeledControlElement -->
|
||||
<button id="btn_nsIDOMXULLabeledControlElement"
|
||||
label="labeled element"/>
|
||||
|
||||
<!-- nsIDOMXULSelectControlItemElement -->
|
||||
<listbox>
|
||||
<listitem id="li_nsIDOMXULSelectControlItemElement"
|
||||
label="select control item"/>
|
||||
</listbox>
|
||||
|
||||
<!-- not nsIDOMXULSelectControlElement -->
|
||||
<box id="box_not_nsIDOMXULSelectControlElement" role="group" label="box"/>
|
||||
|
||||
<!-- label element -->
|
||||
<hbox>
|
||||
<box>
|
||||
<label control="btn_label_1">label1</label>
|
||||
</box>
|
||||
<label control="btn_label_2">label2</label>
|
||||
<box>
|
||||
<button id="btn_label_1"/>
|
||||
<box>
|
||||
<box>
|
||||
<box>
|
||||
<button id="btn_label_2"/>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
<label control="btn_label_3">label3</label>
|
||||
<button id="btn_label_3"/>
|
||||
</hbox>
|
||||
|
||||
<!-- label element, anonymous content -->
|
||||
<box id="box_label_anon1"
|
||||
class="first"
|
||||
role="group"/>
|
||||
|
||||
<box id="box_label_anon2"
|
||||
class="second"
|
||||
role="group"/>
|
||||
|
||||
<!-- tooltiptext -->
|
||||
<box id="box_tooltiptext"
|
||||
role="group"
|
||||
tooltiptext="tooltiptext label"/>
|
||||
|
||||
<!-- the name from @title of toolbaritem -->
|
||||
<toolbar>
|
||||
<toolbaritem title="ooospspss">
|
||||
<textbox id="toolbaritem_textbox"
|
||||
flex="1"
|
||||
type="autocomplete"
|
||||
enablehistory="true">
|
||||
<hbox role="button" id="toolbaritem_hboxbutton">
|
||||
<description value="button"/>
|
||||
</hbox>
|
||||
</textbox>
|
||||
</toolbaritem>
|
||||
</toolbar>
|
||||
|
||||
<!-- name from children -->
|
||||
<box id="box_children" role="button">14</box>
|
||||
|
||||
<!-- name from children, hidden children -->
|
||||
<vbox role="listbox" tabindex="0">
|
||||
<hbox id="lb_opt1_children_hidden" role="option" tabindex="0">
|
||||
<description>i am visible</description>
|
||||
<description style="display:none">i am hidden</description>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
</window>
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>Text attributes tests</title>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
|
||||
const nsIAccessibleText = Components.interfaces.nsIAccessibleText;
|
||||
const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
|
||||
|
||||
const nsIDOMNSEditableElement =
|
||||
Components.interfaces.nsIDOMNSEditableElement;
|
||||
const nsIObserverService = Components.interfaces.nsIObserverService;
|
||||
|
||||
var gAccRetrieval = null;
|
||||
|
||||
/**
|
||||
* Test text attributes.
|
||||
*
|
||||
* @param aID the ID of DOM element having text accessible
|
||||
* @param aOffset the offset inside text accessible to fetch
|
||||
* text attributes
|
||||
* @param aAttrs the map of text attributes (name/value pairs)
|
||||
* @param aStartOffset the start offset where text attributes are
|
||||
* applied
|
||||
* @param aEndOffset the end offset where text attribute are applied
|
||||
* @param aDefAttrs the list of default text attributes (name/value
|
||||
* pairs)
|
||||
*/
|
||||
function testTextAttrs(aID, aOffset,
|
||||
aAttrs, aStartOffset, aEndOffset, aDefAttrs)
|
||||
{
|
||||
var node = document.getElementById(aID);
|
||||
if (!node) {
|
||||
ok(false, "Can't get the element with ID " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
var accessible = null;
|
||||
try {
|
||||
accessible = gAccRetrieval.getAccessibleFor(node);
|
||||
accessible.QueryInterface(nsIAccessibleText);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (!accessible) {
|
||||
ok(false, "Can't query nsIAccessibleText interface for " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
var startOffset = { value: -1 };
|
||||
var endOffset = { value: -1 };
|
||||
var attrs = null;
|
||||
try {
|
||||
attrs = accessible.getTextAttributes(false,
|
||||
aOffset,
|
||||
startOffset, endOffset);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (!attrs) {
|
||||
ok(false, "Can't get text attributes for " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
var errorMsg = " for " + aID + "at offset " + aOffset;
|
||||
is(startOffset.value, aStartOffset,
|
||||
"Wrong start offset" + errorMsg);
|
||||
is(endOffset.value, aEndOffset,
|
||||
"Wrong end offset" + errorMsg);
|
||||
|
||||
compareTextAttrs(errorMsg, attrs, aAttrs);
|
||||
|
||||
var defAttrs = null;
|
||||
try{
|
||||
defAttrs = accessible.defaultTextAttributes;
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (!defAttrs) {
|
||||
ok(false, "Can't get default attributes for " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
compareTextAttrs(errorMsg, defAttrs, aDefAttrs);
|
||||
}
|
||||
|
||||
function compareTextAttrs(aErrorMsg, aAttrs, aExpectedAttrs)
|
||||
{
|
||||
var enumerate = aAttrs.enumerate();
|
||||
while (enumerate.hasMoreElements()) {
|
||||
var prop = enumerate.getNext().
|
||||
QueryInterface(Components.interfaces.nsIPropertyElement);
|
||||
|
||||
if (!(prop.key in aExpectedAttrs))
|
||||
ok(false,
|
||||
"Unexpected attribute '" + prop.key + "'" + aErrorMsg);
|
||||
else
|
||||
is(prop.value, aExpectedAttrs[prop.key],
|
||||
"Attribute '" + prop.key + "' has wrong value" + aErrorMsg);
|
||||
}
|
||||
|
||||
for (var name in aExpectedAttrs) {
|
||||
var value = "";
|
||||
try {
|
||||
value = aAttrs.getStringProperty(name);
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (!value)
|
||||
ok(false,
|
||||
"There is no expected attribute '" + name + "'" + aErrorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
var gObserverService = null;
|
||||
var gA11yEventObserver = null;
|
||||
|
||||
function testSpellTextAttrs()
|
||||
{
|
||||
gA11yEventObserver = {
|
||||
observe: function observe(aSubject, aTopic, aData)
|
||||
{
|
||||
if (aTopic != "accessible-event")
|
||||
return;
|
||||
|
||||
|
||||
var event = aSubject.QueryInterface(nsIAccessibleEvent);
|
||||
|
||||
if (event.eventType == nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHANGED)
|
||||
this.mTextAttrChangedEventCounter++;
|
||||
},
|
||||
|
||||
mTextAttrChangedEventCounter: 0
|
||||
};
|
||||
|
||||
// Add accessibility event listeners
|
||||
var gObserverService = Components.classes["@mozilla.org/observer-service;1"].
|
||||
getService(nsIObserverService);
|
||||
|
||||
gObserverService.addObserver(gA11yEventObserver, "accessible-event",
|
||||
false);
|
||||
|
||||
ID = "area8";
|
||||
|
||||
var node = document.getElementById(ID);
|
||||
node.focus();
|
||||
|
||||
var editor = node.QueryInterface(nsIDOMNSEditableElement).editor;
|
||||
var spellchecker = editor.getInlineSpellChecker(true);
|
||||
spellchecker.enableRealTimeSpell = true;
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
var defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "11px",
|
||||
"background-color": "rgb(255, 255, 255)",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "Lucida Grande",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
var attrs = { "background-color": "transparent" };
|
||||
var misspelledAttrs = {
|
||||
"background-color": "transparent",
|
||||
"invalid": "spelling"
|
||||
};
|
||||
|
||||
testTextAttrs(ID, 0, attrs, 0, 11, defAttrs);
|
||||
testTextAttrs(ID, 11, misspelledAttrs, 11, 17, defAttrs);
|
||||
testTextAttrs(ID, 18, misspelledAttrs, 18, 22, defAttrs);
|
||||
|
||||
is(gA11yEventObserver.mTextAttrChangedEventCounter, 2,
|
||||
"Wrong count of 'text attribute changed' events for " + ID);
|
||||
|
||||
// Remove a11y events listener
|
||||
gObserverService.removeObserver(gA11yEventObserver,
|
||||
"accessible-event");
|
||||
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(nsIAccessibleRetrieval);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area1
|
||||
var ID = "area1";
|
||||
var defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
var attrs = {};
|
||||
testTextAttrs(ID, 0, attrs, 0, 7, defAttrs);
|
||||
|
||||
attrs = {"font-weight": "401"};
|
||||
testTextAttrs(ID, 7, attrs, 7, 11, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 12, attrs, 11, 18, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area2
|
||||
ID = "area2";
|
||||
defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 0, attrs, 0, 7, defAttrs);
|
||||
|
||||
attrs = {"font-weight": "401"};
|
||||
testTextAttrs(ID, 7, attrs, 7, 12, defAttrs);
|
||||
|
||||
attrs = {"font-style": "italic", "font-weight": "401"};
|
||||
testTextAttrs(ID, 13, attrs, 12, 19, defAttrs);
|
||||
|
||||
attrs = {"font-weight": "401"};
|
||||
testTextAttrs(ID, 20, attrs, 19, 23, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 24, attrs, 23, 30, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area3
|
||||
ID = "area3";
|
||||
defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
attrs = {"color": "rgb(0, 128, 0)"};
|
||||
testTextAttrs(ID, 0, attrs, 0, 6, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(255, 0, 0)"};
|
||||
testTextAttrs(ID, 6, attrs, 6, 26, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(0, 128, 0)"};
|
||||
testTextAttrs(ID, 26, attrs, 26, 50, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area4
|
||||
ID = "area4";
|
||||
defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
attrs = {"color": "rgb(0, 128, 0)"};
|
||||
testTextAttrs(ID, 0, attrs, 0, 16, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(255, 0, 0)"};
|
||||
testTextAttrs(ID, 16, attrs, 16, 33, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(0, 128, 0)"};
|
||||
testTextAttrs(ID, 34, attrs, 33, 46, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area5
|
||||
ID = "area5";
|
||||
defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
attrs = {"color": "rgb(0, 128, 0)"};
|
||||
testTextAttrs(ID, 0, attrs, 0, 5, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 7, attrs, 5, 8, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(255, 0, 0)"};
|
||||
testTextAttrs(ID, 9, attrs, 8, 11, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 11, attrs, 11, 18, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area6 (CSS vertical-align property, bug 445938)
|
||||
ID = "area6";
|
||||
defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 0, attrs, 0, 5, defAttrs);
|
||||
|
||||
attrs = {"text-position": "super", "font-size": "13px" };
|
||||
testTextAttrs(ID, 5, attrs, 5, 13, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 13, attrs, 13, 27, defAttrs);
|
||||
|
||||
attrs = {"text-position": "super" };
|
||||
testTextAttrs(ID, 27, attrs, 27, 35, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 35, attrs, 35, 39, defAttrs);
|
||||
|
||||
attrs = {"text-position": "sub", "font-size": "13px" };
|
||||
testTextAttrs(ID, 39, attrs, 39, 50, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 50, attrs, 50, 55, defAttrs);
|
||||
|
||||
attrs = {"text-position": "sub" };
|
||||
testTextAttrs(ID, 55, attrs, 55, 64, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area7
|
||||
ID = "area7";
|
||||
defAttrs = {
|
||||
"font-style": "normal",
|
||||
"text-align": "start",
|
||||
"font-size": "16px",
|
||||
"background-color": "transparent",
|
||||
"font-weight": "400",
|
||||
"text-indent": "0px",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"font-family": "serif",
|
||||
"text-position": "baseline"
|
||||
};
|
||||
|
||||
attrs = {"language": "ru"};
|
||||
testTextAttrs(ID, 0, attrs, 0, 12, defAttrs);
|
||||
|
||||
attrs = {"language": "en"};
|
||||
testTextAttrs(ID, 12, attrs, 12, 13, defAttrs);
|
||||
|
||||
attrs = {"language" :"en", "background-color": "rgb(0, 0, 255)"};
|
||||
testTextAttrs(ID, 13, attrs, 13, 26, defAttrs);
|
||||
|
||||
attrs = {"language": "en" };
|
||||
testTextAttrs(ID, 26, attrs, 26, 27, defAttrs);
|
||||
|
||||
attrs = {"language": "de"};
|
||||
testTextAttrs(ID, 27, attrs, 27, 42, defAttrs);
|
||||
|
||||
attrs = {"language": "en"};
|
||||
testTextAttrs(ID, 42, attrs, 42, 43, defAttrs);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 43, attrs, 43, 50, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(255, 0, 255)"};
|
||||
testTextAttrs(ID, 50, attrs, 50, 57, defAttrs);
|
||||
|
||||
attrs = {"font-weight": "401", "color": "rgb(255, 0, 255)" };
|
||||
testTextAttrs(ID, 57, attrs, 57, 61, defAttrs);
|
||||
|
||||
attrs = {"color": "rgb(255, 0, 255)"};
|
||||
testTextAttrs(ID, 61, attrs, 61, 68, defAttrs);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// test spelling text attributes
|
||||
testSpellTextAttrs(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=345759"
|
||||
title="Implement text attributes">
|
||||
Mozilla Bug 345759
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<p id="area1">Normal <b>Bold</b> Normal</p>
|
||||
<p id="area2">Normal <b>Bold <i>Italic </i>Bold</b> Normal</p>
|
||||
<p id="area3">
|
||||
<span style="color: green">
|
||||
Green
|
||||
<span style="color: red">but children are red</span>
|
||||
</span><span style="color: green">
|
||||
Another green section.
|
||||
</span>
|
||||
</p>
|
||||
<p id="area4">
|
||||
<span style="color: green">
|
||||
Green
|
||||
</span><span style="color: green">
|
||||
Green too
|
||||
<span style="color: red">with red children</span>
|
||||
Green again
|
||||
</span>
|
||||
</p>
|
||||
<p id="area5">
|
||||
<span style="color: green">Green</span>
|
||||
<img src="moz.png" alt="image"/>
|
||||
<span style="color: red">Red</span>Normal
|
||||
</p>
|
||||
<p id="area6">
|
||||
This <sup>sentence</sup> has the word
|
||||
<span style="vertical-align:super;">sentence</span> in
|
||||
<sub>superscript</sub> and
|
||||
<span style="vertical-align:sub;">subscript</span>
|
||||
</p>
|
||||
|
||||
<p lang="en" id="area7">
|
||||
<span lang="ru">Привет</span>
|
||||
<span style="background-color: blue">Blue BG color</span>
|
||||
<span lang="de">Ich bin/Du bist</span>
|
||||
<span lang="en">
|
||||
Normal
|
||||
<span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<input id="area8" value="valid text inalid tixt"/>
|
||||
|
||||
<p id="output"/>
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +1,7 @@
|
|||
WIN32_MODULE_COMPANYNAME=Mozilla Corporation
|
||||
WIN32_MODULE_COPYRIGHT=©Firefox and Mozilla Developers, according to the MPL 1.1/GPL 2.0/LGPL 2.1 licenses, as applicable.
|
||||
WIN32_MODULE_PRODUCTVERSION=3,1,0,0
|
||||
WIN32_MODULE_PRODUCTVERSION_STRING=3.1a1pre
|
||||
WIN32_MODULE_PRODUCTVERSION_STRING=3.1a2pre
|
||||
WIN32_MODULE_TRADEMARKS=Firefox is a Trademark of The Mozilla Foundation.
|
||||
WIN32_MODULE_DESCRIPTION=Firefox
|
||||
WIN32_MODULE_PRODUCTNAME=Firefox
|
||||
|
|
|
@ -227,6 +227,15 @@ pref("browser.urlbar.maxRichResults", 12);
|
|||
pref("browser.urlbar.search.chunkSize", 1000);
|
||||
pref("browser.urlbar.search.timeout", 100);
|
||||
|
||||
// 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
|
||||
// just the title text or url.
|
||||
pref("browser.urlbar.restrict.history", "^");
|
||||
pref("browser.urlbar.restrict.bookmark", "*");
|
||||
pref("browser.urlbar.restrict.tag", "+");
|
||||
pref("browser.urlbar.match.title", "#");
|
||||
pref("browser.urlbar.match.url", "@");
|
||||
|
||||
// Number of milliseconds to wait for the http headers (and thus
|
||||
// the Content-Disposition filename) before giving up and falling back to
|
||||
// picking a filename without that info in hand so that the user sees some
|
||||
|
@ -327,6 +336,9 @@ pref("browser.tabs.closeButtons", 1);
|
|||
// false return to the adjacent tab (old default)
|
||||
pref("browser.tabs.selectOwnerOnClose", true);
|
||||
|
||||
pref("browser.ctrlTab.mostRecentlyUsed", true);
|
||||
pref("browser.ctrlTab.smoothScroll", true);
|
||||
|
||||
// Default bookmark sorting
|
||||
pref("browser.bookmarks.sort.direction", "descending");
|
||||
pref("browser.bookmarks.sort.resource", "rdf:http://home.netscape.com/NC-rdf#Name");
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 7.7 KiB |
|
@ -29,6 +29,7 @@
|
|||
# Jeff Walden <jwalden+code@mit.edu>
|
||||
# Johnathan Nightingale <johnath@mozilla.com>
|
||||
# Justin Dolske <dolske@mozilla.com>
|
||||
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -80,13 +81,32 @@
|
|||
}
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<style type="text/css"><![CDATA[
|
||||
#errorPageContainer {
|
||||
background: url('chrome://browser/content/aboutRobots-icon.png') left 0 no-repeat -moz-Field;
|
||||
-moz-background-origin: content;
|
||||
}
|
||||
|
||||
#errorTrailerDescText {
|
||||
float: right;
|
||||
}
|
||||
|
||||
body[dir=rtl] #errorPageContainer {
|
||||
background-image: url('chrome://browser/content/aboutRobots-icon-rtl.png');
|
||||
background-position: right 0;
|
||||
}
|
||||
|
||||
body[dir=rtl] #errorTrailerDescText {
|
||||
float: left;
|
||||
}
|
||||
]]></style>
|
||||
</head>
|
||||
|
||||
<body dir="&locale.dir;">
|
||||
|
||||
<!-- PAGE CONTAINER (for styling purposes only) -->
|
||||
<div id="errorPageContainer"
|
||||
style="background: url('chrome://browser/content/aboutRobots-icon.png') left 0 no-repeat -moz-Field; -moz-background-origin: content;">
|
||||
<div id="errorPageContainer">
|
||||
|
||||
<!-- Error Title -->
|
||||
<div id="errorTitle">
|
||||
|
@ -113,7 +133,7 @@
|
|||
|
||||
<!-- Short Description -->
|
||||
<div id="errorTrailerDesc">
|
||||
<p id="errorTrailerDescText" style="float: right;">&robots.errorTrailerDescText;</p>
|
||||
<p id="errorTrailerDescText">&robots.errorTrailerDescText;</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -179,7 +179,6 @@
|
|||
accesskey="&keywordfield.accesskey;"
|
||||
oncommand="AddKeywordForSearchField();"/>
|
||||
<menuitem id="context-searchselect"
|
||||
accesskey="&search.accesskey;"
|
||||
oncommand="BrowserSearch.loadSearch(getBrowserSelection(), true);"/>
|
||||
<menuseparator id="frame-sep"/>
|
||||
<menu id="frame" label="&thisFrameMenu.label;" accesskey="&thisFrameMenu.accesskey;">
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
# Annie Sullivan <annie.sullivan@gmail.com>
|
||||
# Joe Hughes <joe@retrovirus.com>
|
||||
# Asaf Romano <mano@mozilla.com>
|
||||
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
|
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
#ifdef 0
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Tab Previews.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dão Gottwald <dao@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
#endif
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tab previews utility, produces thumbnails
|
||||
*/
|
||||
var tabPreviews = {
|
||||
aspectRatio: 0.6875, // 16:11
|
||||
init: function () {
|
||||
this.width = Math.ceil(screen.availWidth / 7.5);
|
||||
this.height = Math.round(this.width * this.aspectRatio);
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
|
||||
gBrowser.tabContainer.addEventListener("SSTabRestored", this, false);
|
||||
},
|
||||
uninit: function () {
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
|
||||
gBrowser.tabContainer.removeEventListener("SSTabRestored", this, false);
|
||||
this._selectedTab = null;
|
||||
},
|
||||
get: function (aTab) {
|
||||
return aTab.__thumbnail || this.capture(aTab, !aTab.hasAttribute("busy"));
|
||||
},
|
||||
capture: function (aTab, aStore) {
|
||||
var win = aTab.linkedBrowser.contentWindow;
|
||||
var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
thumbnail.mozOpaque = true;
|
||||
thumbnail.height = this.height;
|
||||
thumbnail.width = this.width;
|
||||
var ctx = thumbnail.getContext("2d");
|
||||
var widthScale = this.width / win.innerWidth;
|
||||
ctx.scale(widthScale, widthScale);
|
||||
ctx.drawWindow(win, win.scrollX, win.scrollY,
|
||||
win.innerWidth, win.innerWidth * this.aspectRatio, "rgb(255,255,255)");
|
||||
var data = thumbnail.toDataURL("image/jpeg", "quality=60");
|
||||
if (aStore)
|
||||
aTab.__thumbnail = data;
|
||||
return data;
|
||||
},
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "TabSelect":
|
||||
if (this._selectedTab &&
|
||||
this._selectedTab.parentNode &&
|
||||
!this._pendingUpdate) {
|
||||
// Generate a thumbnail for the tab that was selected.
|
||||
// The timeout keeps the UI snappy and prevents us from generating thumbnails
|
||||
// for tabs that will be closed. During that timeout, don't generate other
|
||||
// thumbnails in case multiple TabSelect events occur fast in succession.
|
||||
this._pendingUpdate = true;
|
||||
setTimeout(function (self, aTab) {
|
||||
self._pendingUpdate = false;
|
||||
if (aTab.parentNode && !aTab.hasAttribute("busy"))
|
||||
self.capture(aTab, true);
|
||||
}, 2000, this, this._selectedTab);
|
||||
}
|
||||
this._selectedTab = event.target;
|
||||
break;
|
||||
case "SSTabRestored":
|
||||
this.capture(event.target, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ctrl-Tab panel
|
||||
*/
|
||||
var ctrlTab = {
|
||||
tabs: null,
|
||||
visibleCount: 3,
|
||||
_uniqid: 0,
|
||||
get panel () {
|
||||
delete this.panel;
|
||||
return this.panel = document.getElementById("ctrlTab-panel");
|
||||
},
|
||||
get label () {
|
||||
delete this.label;
|
||||
return this.label = document.getElementById("ctrlTab-label");
|
||||
},
|
||||
get svgRoot () {
|
||||
delete this.svgRoot;
|
||||
|
||||
let (groundFade = document.getElementById("ctrlTab-groundFade")) {
|
||||
groundFade.setAttribute("height", Math.ceil(tabPreviews.height * .25) + 1);
|
||||
groundFade.setAttribute("y", tabPreviews.height + 1);
|
||||
}
|
||||
|
||||
this.svgRoot = document.getElementById("ctrlTab-svgRoot");
|
||||
this.svgRoot.setAttribute("height", tabPreviews.height * 1.25 + 2);
|
||||
return this.svgRoot;
|
||||
},
|
||||
get container () {
|
||||
delete this.container;
|
||||
return this.container = document.getElementById("ctrlTab-container");
|
||||
},
|
||||
get rtl () {
|
||||
delete this.rtl;
|
||||
return this.rtl = getComputedStyle(this.panel, "").direction == "rtl";
|
||||
},
|
||||
get iconSize () {
|
||||
delete this.iconSize;
|
||||
return this.iconSize = Math.round(tabPreviews.height / 4);
|
||||
},
|
||||
get closeCharCode () {
|
||||
delete this.closeCharCode;
|
||||
return this.closeCharCode = document.getElementById("key_close")
|
||||
.getAttribute("key")
|
||||
.toLowerCase().charCodeAt(0);
|
||||
},
|
||||
get smoothScroll () {
|
||||
delete this.smoothScroll;
|
||||
return this.smoothScroll = gPrefService.getBoolPref("browser.ctrlTab.smoothScroll");
|
||||
},
|
||||
get offscreenStart () {
|
||||
return Array.indexOf(this.container.childNodes, this.selected) - 1;
|
||||
},
|
||||
get offscreenEnd () {
|
||||
return this.container.childNodes.length - this.visibleCount - this.offscreenStart;
|
||||
},
|
||||
get offsetX () {
|
||||
return - tabPreviews.width * (this.rtl ? this.offscreenEnd : this.offscreenStart);
|
||||
},
|
||||
get isOpen () {
|
||||
return this.panel.state == "open" || this.panel.state == "showing";
|
||||
},
|
||||
init: function () {
|
||||
if (this.tabs)
|
||||
return;
|
||||
|
||||
var tabContainer = gBrowser.tabContainer;
|
||||
|
||||
this.tabs = [];
|
||||
Array.forEach(tabContainer.childNodes, function (tab) {
|
||||
this.attachTab(tab, tab == gBrowser.selectedTab);
|
||||
}, this);
|
||||
|
||||
tabContainer.addEventListener("TabOpen", this, false);
|
||||
tabContainer.addEventListener("TabSelect", this, false);
|
||||
tabContainer.addEventListener("TabClose", this, false);
|
||||
|
||||
gBrowser.mTabBox.handleCtrlTab = false;
|
||||
window.addEventListener("keydown", this, true);
|
||||
},
|
||||
uninit: function () {
|
||||
this.tabs = null;
|
||||
|
||||
var tabContainer = gBrowser.tabContainer;
|
||||
tabContainer.removeEventListener("TabOpen", this, false);
|
||||
tabContainer.removeEventListener("TabSelect", this, false);
|
||||
tabContainer.removeEventListener("TabClose", this, false);
|
||||
|
||||
this.panel.removeEventListener("popuphiding", this, false);
|
||||
window.removeEventListener("keydown", this, true);
|
||||
},
|
||||
addBox: function (aAtStart) {
|
||||
const SVGNS = "http://www.w3.org/2000/svg";
|
||||
|
||||
var thumbnail = document.createElementNS(SVGNS, "image");
|
||||
thumbnail.setAttribute("class", "ctrlTab-thumbnail");
|
||||
thumbnail.setAttribute("height", tabPreviews.height);
|
||||
thumbnail.setAttribute("width", tabPreviews.width);
|
||||
|
||||
var thumbnail_border = document.createElementNS(SVGNS, "rect");
|
||||
thumbnail_border.setAttribute("class", "ctrlTab-thumbnailborder");
|
||||
thumbnail_border.setAttribute("height", tabPreviews.height);
|
||||
thumbnail_border.setAttribute("width", tabPreviews.width);
|
||||
|
||||
var icon = document.createElementNS(SVGNS, "image");
|
||||
icon.setAttribute("class", "ctrlTab-icon");
|
||||
icon.setAttribute("height", this.iconSize);
|
||||
icon.setAttribute("width", this.iconSize);
|
||||
icon.setAttribute("transform", "skewY(10)");
|
||||
icon.setAttribute("x", - this.iconSize / 3);
|
||||
icon.setAttribute("y", tabPreviews.height * .9 - this.iconSize);
|
||||
|
||||
var thumbnail_and_icon = document.createElementNS(SVGNS, "g");
|
||||
thumbnail_and_icon.appendChild(thumbnail);
|
||||
thumbnail_and_icon.appendChild(thumbnail_border);
|
||||
thumbnail_and_icon.appendChild(icon);
|
||||
|
||||
var reflection = document.createElementNS(SVGNS, "use");
|
||||
reflection.setAttribute("class", "ctrlTab-reflection");
|
||||
var ref_scale = .5;
|
||||
reflection.setAttribute("transform", "scale(1,-" + ref_scale + ")");
|
||||
reflection.setAttribute("y", - ((1 / ref_scale + 1) * tabPreviews.height +
|
||||
(1 / ref_scale) * 2));
|
||||
|
||||
var box = document.createElementNS(SVGNS, "g");
|
||||
box.setAttribute("class", "ctrlTab-box");
|
||||
box.appendChild(thumbnail_and_icon);
|
||||
box.appendChild(reflection);
|
||||
|
||||
if (aAtStart)
|
||||
this.container.insertBefore(box, this.container.firstChild);
|
||||
else
|
||||
this.container.appendChild(box);
|
||||
return box;
|
||||
},
|
||||
removeBox: function (aBox) {
|
||||
this.container.removeChild(aBox);
|
||||
if (!Array.some(this.container.childNodes, function (box) box._tab == aBox._tab))
|
||||
aBox._tab.removeEventListener("DOMAttrModified", this, false);
|
||||
aBox._tab = null;
|
||||
},
|
||||
addPreview: function (aBox, aTab) {
|
||||
const XLinkNS = "http://www.w3.org/1999/xlink";
|
||||
|
||||
aBox._tab = aTab;
|
||||
let (thumbnail = aBox.firstChild.firstChild)
|
||||
thumbnail.setAttributeNS(XLinkNS, "href", tabPreviews.get(aTab));
|
||||
this.updateIcon(aBox);
|
||||
|
||||
aTab.addEventListener("DOMAttrModified", this, false);
|
||||
|
||||
if (!aBox.firstChild.hasAttribute("id")) {
|
||||
// set up reflection
|
||||
this._uniqid++;
|
||||
aBox.firstChild.setAttribute("id", "ctrlTab-preview-" + this._uniqid);
|
||||
aBox.lastChild.setAttributeNS(XLinkNS, "href", "#ctrlTab-preview-" + this._uniqid);
|
||||
}
|
||||
},
|
||||
updateIcon: function (aBox) {
|
||||
const XLinkNS = "http://www.w3.org/1999/xlink";
|
||||
var url = aBox._tab.hasAttribute("busy") ?
|
||||
"chrome://global/skin/icons/loading_16.png" :
|
||||
aBox._tab.getAttribute("image");
|
||||
var icon = aBox.firstChild.lastChild;
|
||||
if (url)
|
||||
icon.setAttributeNS(XLinkNS, "href", url);
|
||||
else
|
||||
icon.removeAttributeNS(XLinkNS, "href");
|
||||
},
|
||||
tabAttrModified: function (aTab, aAttrName) {
|
||||
switch (aAttrName) {
|
||||
case "busy":
|
||||
case "image":
|
||||
Array.forEach(this.container.childNodes, function (box) {
|
||||
if (box._tab == aTab) {
|
||||
if (aAttrName == "busy")
|
||||
this.addPreview(box, aTab);
|
||||
else
|
||||
this.updateIcon(box);
|
||||
}
|
||||
}, this);
|
||||
break;
|
||||
case "label":
|
||||
case "crop":
|
||||
if (!this._scrollTimer) {
|
||||
let boxes = this.container.childNodes;
|
||||
for (let i = boxes.length - 1; i >= 0; i--) {
|
||||
if (boxes[i]._tab == aTab && boxes[i] == this.selected) {
|
||||
this.label[aAttrName == "label" ? "value" : aAttrName] =
|
||||
aTab.getAttribute(aAttrName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
scroll: function () {
|
||||
if (!this.smoothScroll) {
|
||||
this.advanceSelected();
|
||||
this.arrangeBoxes();
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopScroll();
|
||||
let (next = this.invertDirection ? this.selected.previousSibling : this.selected.nextSibling) {
|
||||
this.setStatusbarValue(next);
|
||||
this.label.value = next._tab.label;
|
||||
this.label.crop = next._tab.crop;
|
||||
}
|
||||
|
||||
const FRAME_LENGTH = 40;
|
||||
var x = this.offsetX;
|
||||
var scrollAmounts = let (tenth = tabPreviews.width / (this.invertDirection == this.rtl ? -10 : 10))
|
||||
[3 * tenth, 4 * tenth, 2 * tenth, tenth];
|
||||
|
||||
function processFrame(self, lateness) {
|
||||
lateness += FRAME_LENGTH / 2;
|
||||
do {
|
||||
x += scrollAmounts.shift();
|
||||
lateness -= FRAME_LENGTH;
|
||||
} while (lateness > 0 && scrollAmounts.length);
|
||||
self.container.setAttribute("transform", "translate("+ x +",0)");
|
||||
self.svgRoot.forceRedraw();
|
||||
if (!scrollAmounts.length)
|
||||
self.stopScroll();
|
||||
}
|
||||
|
||||
this._scrollTimer = setInterval(processFrame, FRAME_LENGTH, this);
|
||||
processFrame(this, 0);
|
||||
},
|
||||
stopScroll: function () {
|
||||
if (this._scrollTimer) {
|
||||
clearInterval(this._scrollTimer);
|
||||
this._scrollTimer = 0;
|
||||
this.advanceSelected();
|
||||
this.arrangeBoxes();
|
||||
}
|
||||
},
|
||||
advanceSelected: function () {
|
||||
// regardless of visibleCount, the new highlighted tab will be
|
||||
// the first or third-visible tab, depending on whether Shift is pressed
|
||||
var index = ((this.invertDirection ? 0 : 2) + this.offscreenStart + this.tabs.length)
|
||||
% this.tabs.length;
|
||||
if (index < 2)
|
||||
index += this.tabs.length;
|
||||
if (index > this.container.childNodes.length - this.visibleCount + 1)
|
||||
index -= this.tabs.length;
|
||||
this.selected = this.container.childNodes[index];
|
||||
},
|
||||
arrangeBoxes: function () {
|
||||
this.addOffscreenBox(this.invertDirection);
|
||||
this.addOffscreenBox(!this.invertDirection);
|
||||
|
||||
// having lots of off-screen boxes reduce the scrolling speed, remove some
|
||||
for (let i = this.offscreenStart; i > 1; i--)
|
||||
this.removeBox(this.container.firstChild);
|
||||
for (let i = this.offscreenEnd; i > 1; i--)
|
||||
this.removeBox(this.container.lastChild);
|
||||
|
||||
this.container.setAttribute("transform", "translate("+ this.offsetX +", 0)");
|
||||
|
||||
for (let i = 0, l = this.container.childNodes.length; i < l; i++)
|
||||
this.arrange(i);
|
||||
},
|
||||
addOffscreenBox: function (aAtStart) {
|
||||
if (this.container.childNodes.length < this.tabs.length + this.visibleCount + 1 &&
|
||||
!(aAtStart ? this.offscreenStart : this.offscreenEnd)) {
|
||||
let i = aAtStart ?
|
||||
this.tabs.indexOf(this.container.firstChild._tab) - 1:
|
||||
this.tabs.indexOf(this.container.lastChild._tab) + 1;
|
||||
i = (i + this.tabs.length) % this.tabs.length;
|
||||
this.addPreview(this.addBox(aAtStart), this.tabs[i]);
|
||||
}
|
||||
},
|
||||
arrange: function (aIndex) {
|
||||
var box = this.container.childNodes[aIndex];
|
||||
var selected = box == this.selected;
|
||||
if (selected) {
|
||||
box.setAttribute("selected", "true");
|
||||
this.setStatusbarValue(box);
|
||||
this.label.value = box._tab.label;
|
||||
this.label.crop = box._tab.crop;
|
||||
} else {
|
||||
box.removeAttribute("selected");
|
||||
}
|
||||
var scale = selected ? 1 : .75;
|
||||
var pos = this.rtl ? this.container.childNodes.length - 1 - aIndex : aIndex;
|
||||
var trans_x = tabPreviews.width * (pos + (1 - scale) / 2) / scale;
|
||||
var trans_y = (tabPreviews.height + 1) * (1 / scale - 1);
|
||||
box.setAttribute("transform", "scale(" + scale + "," + scale + ") " +
|
||||
"translate("+ trans_x + "," + trans_y + ")");
|
||||
},
|
||||
setStatusbarValue: function (aBox) {
|
||||
var value = "";
|
||||
if (aBox) {
|
||||
value = aBox._tab.linkedBrowser.currentURI.spec;
|
||||
if (value == "about:blank") {
|
||||
// XXXhack: Passing a space here (and not "")
|
||||
// to make sure the browser implementation would
|
||||
// still consider it a hovered link.
|
||||
value = " ";
|
||||
} else {
|
||||
try {
|
||||
value = decodeURI(value);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
XULBrowserWindow.setOverLink(value, null);
|
||||
},
|
||||
attachTab: function (aTab, aSelected) {
|
||||
if (aSelected)
|
||||
this.tabs.unshift(aTab);
|
||||
else
|
||||
this.tabs.push(aTab);
|
||||
},
|
||||
detachTab: function (aTab) {
|
||||
var i = this.tabs.indexOf(aTab);
|
||||
if (i >= 0)
|
||||
this.tabs.splice(i, 1);
|
||||
},
|
||||
open: function () {
|
||||
this._deferOnTabSelect = [];
|
||||
|
||||
window.addEventListener("keyup", this, true);
|
||||
window.addEventListener("keypress", this, true);
|
||||
this.panel.addEventListener("popuphiding", this, false);
|
||||
this.panel.hidden = false;
|
||||
this.panel.width = tabPreviews.width * this.visibleCount;
|
||||
this.panel.openPopupAtScreen(screen.availLeft + (screen.availWidth - this.panel.width) / 2,
|
||||
screen.availTop + (screen.availHeight - this.svgRoot.getAttribute("height")) / 2,
|
||||
false);
|
||||
|
||||
// display $visibleCount tabs, starting with the first or
|
||||
// the second to the last tab, depending on whether Shift is pressed
|
||||
for (let index = this.invertDirection ? this.tabs.length - 2 : 0,
|
||||
i = this.visibleCount; i > 0; i--)
|
||||
this.addPreview(this.addBox(), this.tabs[index++ % this.tabs.length]);
|
||||
|
||||
// regardless of visibleCount, highlight the second-visible tab
|
||||
this.selected = this.container.childNodes[1];
|
||||
this.arrangeBoxes();
|
||||
},
|
||||
onKeyDown: function (event) {
|
||||
var isOpen = this.isOpen;
|
||||
var propagate = !isOpen;
|
||||
switch (event.keyCode) {
|
||||
case event.DOM_VK_TAB:
|
||||
if (event.ctrlKey && !event.altKey && !event.metaKey && this.tabs.length > 1) {
|
||||
propagate = false;
|
||||
this.invertDirection = event.shiftKey;
|
||||
if (isOpen)
|
||||
this.scroll();
|
||||
else if (this.tabs.length == 2)
|
||||
gBrowser.selectedTab = this.tabs[1];
|
||||
else
|
||||
this.open();
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_ESCAPE:
|
||||
if (isOpen)
|
||||
this.panel.hidePopup();
|
||||
break;
|
||||
}
|
||||
if (!propagate) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
onKeyUp: function (event) {
|
||||
if (event.keyCode == event.DOM_VK_CONTROL) {
|
||||
this.stopScroll();
|
||||
let selectedTab = this.selected._tab;
|
||||
this.panel.hidePopup();
|
||||
gBrowser.selectedTab = selectedTab;
|
||||
}
|
||||
},
|
||||
onPopupHiding: function () {
|
||||
this.stopScroll();
|
||||
window.removeEventListener("keyup", this, true);
|
||||
window.removeEventListener("keypress", this, true);
|
||||
while (this.container.childNodes.length)
|
||||
this.removeBox(this.container.lastChild);
|
||||
this.selected = null;
|
||||
this.invertDirection = false;
|
||||
this._uniqid = 0;
|
||||
this.label.value = "";
|
||||
this.setStatusbarValue();
|
||||
this.container.removeAttribute("transform");
|
||||
this.svgRoot.forceRedraw();
|
||||
|
||||
this._deferOnTabSelect.forEach(this.onTabSelect, this);
|
||||
this._deferOnTabSelect = null;
|
||||
},
|
||||
onTabSelect: function (aTab) {
|
||||
if (aTab.parentNode) {
|
||||
this.detachTab(aTab);
|
||||
this.attachTab(aTab, true);
|
||||
}
|
||||
},
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "DOMAttrModified":
|
||||
this.tabAttrModified(event.target, event.attrName);
|
||||
break;
|
||||
case "TabSelect":
|
||||
if (this.isOpen)
|
||||
// don't change the tab order while the panel is open
|
||||
this._deferOnTabSelect.push(event.target);
|
||||
else
|
||||
this.onTabSelect(event.target);
|
||||
break;
|
||||
case "TabOpen":
|
||||
this.attachTab(event.target);
|
||||
break;
|
||||
case "TabClose":
|
||||
if (this.isOpen) {
|
||||
if (this.tabs.length == 2) {
|
||||
// we have two tabs, one is being closed, so the panel isn't needed anymore
|
||||
this.panel.hidePopup();
|
||||
} else {
|
||||
if (event.target == this.selected._tab)
|
||||
this.advanceSelected();
|
||||
this.detachTab(event.target);
|
||||
Array.slice(this.container.childNodes).forEach(function (box) {
|
||||
if (box._tab == event.target) {
|
||||
this.removeBox(box);
|
||||
this.arrangeBoxes();
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
this.detachTab(event.target);
|
||||
break;
|
||||
case "keydown":
|
||||
this.onKeyDown(event);
|
||||
break;
|
||||
case "keypress":
|
||||
// the panel is open; don't propagate any key events
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if (event.charCode == this.closeCharCode) {
|
||||
this.stopScroll();
|
||||
gBrowser.removeTab(this.selected._tab);
|
||||
}
|
||||
break;
|
||||
case "keyup":
|
||||
// the panel is open; don't propagate any key events
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.onKeyUp(event);
|
||||
break;
|
||||
case "popuphiding":
|
||||
this.onPopupHiding();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,3 +1,7 @@
|
|||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
@namespace xlink url("http://www.w3.org/1999/xlink");
|
||||
|
||||
searchbar {
|
||||
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
|
||||
}
|
||||
|
@ -82,3 +86,17 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
|||
#navigator-toolbox[inFullscreen="true"] #fullscr-toggler {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
/* Tab Previews */
|
||||
svg|*.ctrlTab-icon:not([xlink|href]) ,
|
||||
svg|*.ctrlTab-thumbnail:not([xlink|href]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
fill: transparent;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-icon {
|
||||
filter: url(chrome://browser/content/browser.xul#ctrlTab-iconShadow);
|
||||
}
|
||||
|
|
|
@ -73,19 +73,12 @@ var gURIFixup = null;
|
|||
var gCharsetMenu = null;
|
||||
var gLastBrowserCharset = null;
|
||||
var gPrevCharset = null;
|
||||
var gURLBar = null;
|
||||
var gFindBar = null;
|
||||
var gProxyFavIcon = null;
|
||||
var gNavigatorBundle = null;
|
||||
var gIsLoadingBlank = false;
|
||||
var gLastValidURLStr = "";
|
||||
var gMustLoadSidebar = false;
|
||||
var gProgressMeterPanel = null;
|
||||
var gProgressCollapseTimer = null;
|
||||
var gPrefService = null;
|
||||
var appCore = null;
|
||||
var gBrowser = null;
|
||||
var gNavToolbox = null;
|
||||
var gSidebarCommand = "";
|
||||
var gInPrintPreviewMode = false;
|
||||
let gDownloadMgr = null;
|
||||
|
@ -108,6 +101,34 @@ var gClickAndHoldTimer = null;
|
|||
var gEditUIVisible = true;
|
||||
#endif
|
||||
|
||||
[
|
||||
["gBrowser", "content"],
|
||||
["gNavToolbox", "navigator-toolbox"],
|
||||
["gURLBar", "urlbar"],
|
||||
["gNavigatorBundle", "bundle_browser"],
|
||||
["gProgressMeterPanel", "statusbar-progresspanel"],
|
||||
["gFindBar", "FindToolbar"]
|
||||
].forEach(function (elementGlobal) {
|
||||
var [name, id] = elementGlobal;
|
||||
window.__defineGetter__(name, function () {
|
||||
var element = document.getElementById(id);
|
||||
if (!element)
|
||||
return null;
|
||||
delete window[name];
|
||||
return window[name] = element;
|
||||
});
|
||||
window.__defineSetter__(name, function (val) {
|
||||
delete window[name];
|
||||
return window[name] = val;
|
||||
});
|
||||
});
|
||||
|
||||
__defineGetter__("gPrefService", function() {
|
||||
delete this.gPrefService;
|
||||
return this.gPrefService = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch2);
|
||||
});
|
||||
|
||||
/**
|
||||
* We can avoid adding multiple load event listeners and save some time by adding
|
||||
* one listener that calls all real handlers.
|
||||
|
@ -253,9 +274,9 @@ function SetClickAndHoldHandlers()
|
|||
|
||||
function BookmarkThisTab()
|
||||
{
|
||||
var tab = getBrowser().mContextTab;
|
||||
var tab = gBrowser.mContextTab;
|
||||
if (tab.localName != "tab")
|
||||
tab = getBrowser().mCurrentTab;
|
||||
tab = gBrowser.mCurrentTab;
|
||||
|
||||
PlacesCommandHook.bookmarkPage(tab.linkedBrowser,
|
||||
PlacesUtils.bookmarksMenuFolderId, true);
|
||||
|
@ -334,9 +355,6 @@ const gPopupBlockerObserver = {
|
|||
// notifications are per-browser, we don't need to worry about re-adding
|
||||
// it.
|
||||
if (!gBrowser.pageReport.reported) {
|
||||
if (!gPrefService)
|
||||
gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
if (gPrefService.getBoolPref("privacy.popups.showBrowserMessage")) {
|
||||
var bundle_browser = document.getElementById("bundle_browser");
|
||||
var brandBundle = document.getElementById("bundle_brand");
|
||||
|
@ -577,9 +595,8 @@ const gXPInstallObserver = {
|
|||
|
||||
_getBrowser: function (aDocShell)
|
||||
{
|
||||
var tabbrowser = getBrowser();
|
||||
for (var i = 0; i < tabbrowser.browsers.length; ++i) {
|
||||
var browser = tabbrowser.getBrowserAtIndex(i);
|
||||
for (var i = 0; i < gBrowser.browsers.length; ++i) {
|
||||
var browser = gBrowser.getBrowserAtIndex(i);
|
||||
if (this._findChildShell(browser.docShell, aDocShell))
|
||||
return browser;
|
||||
}
|
||||
|
@ -656,8 +673,6 @@ const gXPInstallObserver = {
|
|||
|
||||
function BrowserStartup()
|
||||
{
|
||||
gBrowser = document.getElementById("content");
|
||||
|
||||
var uriToLoad = null;
|
||||
|
||||
// window.arguments[0]: URI to load (string), or an nsISupportsArray of
|
||||
|
@ -826,10 +841,6 @@ function HandleAppCommandEvent(evt)
|
|||
|
||||
function prepareForStartup()
|
||||
{
|
||||
gURLBar = document.getElementById("urlbar");
|
||||
gNavigatorBundle = document.getElementById("bundle_browser");
|
||||
gProgressMeterPanel = document.getElementById("statusbar-progresspanel");
|
||||
gFindBar = document.getElementById("FindToolbar");
|
||||
gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver.onUpdatePageReport, false);
|
||||
// Note: we need to listen to untrusted events, because the pluginfinder XBL
|
||||
// binding can't fire trusted ones (runs with page privileges).
|
||||
|
@ -912,9 +923,6 @@ function delayedStartup()
|
|||
os.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
||||
os.addObserver(gXPInstallObserver, "xpinstall-install-blocked", false);
|
||||
|
||||
if (!gPrefService)
|
||||
gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
|
||||
|
@ -946,9 +954,8 @@ function delayedStartup()
|
|||
else
|
||||
focusElement(content);
|
||||
|
||||
var navToolbox = getNavToolbox();
|
||||
navToolbox.customizeDone = BrowserToolboxCustomizeDone;
|
||||
navToolbox.customizeChange = BrowserToolboxCustomizeChange;
|
||||
gNavToolbox.customizeDone = BrowserToolboxCustomizeDone;
|
||||
gNavToolbox.customizeChange = BrowserToolboxCustomizeChange;
|
||||
|
||||
// Set up Sanitize Item
|
||||
gSanitizeListener = new SanitizeListener();
|
||||
|
@ -1074,6 +1081,10 @@ function delayedStartup()
|
|||
// themselves.
|
||||
gBrowser.addEventListener("command", BrowserOnCommand, false);
|
||||
|
||||
tabPreviews.init();
|
||||
if (gPrefService.getBoolPref("browser.ctrlTab.mostRecentlyUsed"))
|
||||
ctrlTab.init();
|
||||
|
||||
// Delayed initialization of the livemarks update timer.
|
||||
// Livemark updates don't need to start until after bookmark UI
|
||||
// such as the toolbar has initialized. Starting 5 seconds after
|
||||
|
@ -1104,6 +1115,9 @@ function delayedStartup()
|
|||
|
||||
function BrowserShutdown()
|
||||
{
|
||||
tabPreviews.uninit();
|
||||
ctrlTab.uninit();
|
||||
|
||||
try {
|
||||
FullZoom.destroy();
|
||||
}
|
||||
|
@ -1202,17 +1216,12 @@ function nonBrowserWindowStartup()
|
|||
element.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
gNavigatorBundle = document.getElementById("bundle_browser");
|
||||
|
||||
setTimeout(nonBrowserWindowDelayedStartup, 0);
|
||||
}
|
||||
|
||||
function nonBrowserWindowDelayedStartup()
|
||||
{
|
||||
// init global pref service
|
||||
gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
|
||||
// initialise the offline listener
|
||||
BrowserOffline.init();
|
||||
|
||||
|
@ -1330,7 +1339,7 @@ function gotoHistoryIndex(aEvent)
|
|||
// Normal click. Go there in the current tab and update session history.
|
||||
|
||||
try {
|
||||
getBrowser().gotoIndex(index);
|
||||
gBrowser.gotoIndex(index);
|
||||
}
|
||||
catch(ex) {
|
||||
return false;
|
||||
|
@ -1355,7 +1364,7 @@ function BrowserForward(aEvent, aIgnoreAlt)
|
|||
|
||||
if (where == "current") {
|
||||
try {
|
||||
getBrowser().goForward();
|
||||
gBrowser.goForward();
|
||||
}
|
||||
catch(ex) {
|
||||
}
|
||||
|
@ -1375,7 +1384,7 @@ function BrowserBack(aEvent, aIgnoreAlt)
|
|||
|
||||
if (where == "current") {
|
||||
try {
|
||||
getBrowser().goBack();
|
||||
gBrowser.goBack();
|
||||
}
|
||||
catch(ex) {
|
||||
}
|
||||
|
@ -1646,7 +1655,7 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup)
|
|||
if (allowThirdPartyFixup) {
|
||||
flags = nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
}
|
||||
getBrowser().loadURIWithFlags(uri, flags, referrer, null, postData);
|
||||
gBrowser.loadURIWithFlags(uri, flags, referrer, null, postData);
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
@ -1927,7 +1936,7 @@ function checkForDirectoryListing()
|
|||
}
|
||||
|
||||
function URLBarSetURI(aURI) {
|
||||
var value = getBrowser().userTypedValue;
|
||||
var value = gBrowser.userTypedValue;
|
||||
var state = "invalid";
|
||||
|
||||
if (!value) {
|
||||
|
@ -2392,7 +2401,7 @@ function toggleAffectedChrome(aHide)
|
|||
// (*) find bar
|
||||
// (*) statusbar
|
||||
|
||||
getNavToolbox().hidden = aHide;
|
||||
gNavToolbox.hidden = aHide;
|
||||
if (aHide)
|
||||
{
|
||||
gChromeState = {};
|
||||
|
@ -2453,7 +2462,7 @@ function onExitPrintPreview()
|
|||
|
||||
function getPPBrowser()
|
||||
{
|
||||
return getBrowser();
|
||||
return gBrowser;
|
||||
}
|
||||
|
||||
function getMarkupDocumentViewer()
|
||||
|
@ -2992,8 +3001,8 @@ const BrowserSearch = {
|
|||
return;
|
||||
|
||||
if (useNewTab) {
|
||||
getBrowser().loadOneTab(submission.uri.spec, null, null,
|
||||
submission.postData, null, false);
|
||||
gBrowser.loadOneTab(submission.uri.spec, null, null,
|
||||
submission.postData, null, false);
|
||||
} else
|
||||
loadURI(submission.uri.spec, null, submission.postData, false);
|
||||
},
|
||||
|
@ -3199,12 +3208,12 @@ function BrowserCustomizeToolbar()
|
|||
// hidden
|
||||
var sheetWidth = sheetFrame.style.width.match(/([0-9]+)px/)[1];
|
||||
document.getElementById("customizeToolbarSheetPopup")
|
||||
.openPopup(getNavToolbox(), "after_start", (window.innerWidth - sheetWidth) / 2, 0);
|
||||
.openPopup(gNavToolbox, "after_start", (window.innerWidth - sheetWidth) / 2, 0);
|
||||
#else
|
||||
window.openDialog(customizeURL,
|
||||
"CustomizeToolbar",
|
||||
"chrome,all,dependent",
|
||||
getNavToolbox());
|
||||
gNavToolbox);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -3398,7 +3407,7 @@ var FullScreen =
|
|||
// The user may quit fullscreen during an animation
|
||||
clearInterval(this._animationInterval);
|
||||
clearTimeout(this._animationTimeout);
|
||||
getNavToolbox().style.marginTop = "0px";
|
||||
gNavToolbox.style.marginTop = "0px";
|
||||
if (this._isChromeCollapsed)
|
||||
this.mouseoverToggle(true);
|
||||
this._isAnimating = false;
|
||||
|
@ -3509,21 +3518,20 @@ var FullScreen =
|
|||
return;
|
||||
}
|
||||
|
||||
var navToolbox = getNavToolbox();
|
||||
var animateFrameAmount = 2;
|
||||
function animateUpFrame() {
|
||||
animateFrameAmount *= 2;
|
||||
if (animateFrameAmount >=
|
||||
(navToolbox.boxObject.height + gBrowser.mStrip.boxObject.height)) {
|
||||
(gNavToolbox.boxObject.height + gBrowser.mStrip.boxObject.height)) {
|
||||
// We've animated enough
|
||||
clearInterval(FullScreen._animationInterval);
|
||||
navToolbox.style.marginTop = "0px";
|
||||
gNavToolbox.style.marginTop = "0px";
|
||||
FullScreen._isAnimating = false;
|
||||
FullScreen._shouldAnimate = false; // Just to make sure
|
||||
FullScreen.mouseoverToggle(false);
|
||||
return;
|
||||
}
|
||||
navToolbox.style.marginTop = (animateFrameAmount * -1) + "px";
|
||||
gNavToolbox.style.marginTop = (animateFrameAmount * -1) + "px";
|
||||
}
|
||||
|
||||
FullScreen._animationInterval = setInterval(animateUpFrame, 70);
|
||||
|
@ -3631,11 +3639,10 @@ var FullScreen =
|
|||
}
|
||||
}
|
||||
|
||||
var toolbox = getNavToolbox();
|
||||
if (aShow)
|
||||
toolbox.removeAttribute("inFullscreen");
|
||||
gNavToolbox.removeAttribute("inFullscreen");
|
||||
else
|
||||
toolbox.setAttribute("inFullscreen", true);
|
||||
gNavToolbox.setAttribute("inFullscreen", true);
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
var controls = document.getElementsByAttribute("fullscreencontrol", "true");
|
||||
|
@ -3707,7 +3714,7 @@ nsBrowserStatusHandler.prototype =
|
|||
|
||||
// Initialize the security button's state and tooltip text. Remember to reset
|
||||
// _hostChanged, otherwise onSecurityChange will short circuit.
|
||||
var securityUI = getBrowser().securityUI;
|
||||
var securityUI = gBrowser.securityUI;
|
||||
this._hostChanged = true;
|
||||
this.onSecurityChange(null, null, securityUI.state);
|
||||
},
|
||||
|
@ -3853,7 +3860,7 @@ nsBrowserStatusHandler.prototype =
|
|||
|
||||
// For keyword URIs clear the user typed value since they will be changed into real URIs
|
||||
if (location.scheme == "keyword" && aWebProgress.DOMWindow == content)
|
||||
getBrowser().userTypedValue = null;
|
||||
gBrowser.userTypedValue = null;
|
||||
|
||||
if (location.spec != "about:blank") {
|
||||
const kErrorBindingAborted = 0x804B0002;
|
||||
|
@ -3930,7 +3937,7 @@ nsBrowserStatusHandler.prototype =
|
|||
// <a href="#" onclick="return install();">Install Foo</a>
|
||||
//
|
||||
// - which fires a onLocationChange message to uri + '#'...
|
||||
var selectedBrowser = getBrowser().selectedBrowser;
|
||||
var selectedBrowser = gBrowser.selectedBrowser;
|
||||
if (selectedBrowser.lastURI) {
|
||||
var oldSpec = selectedBrowser.lastURI.spec;
|
||||
var oldIndexOfHash = oldSpec.indexOf("#");
|
||||
|
@ -3962,7 +3969,7 @@ nsBrowserStatusHandler.prototype =
|
|||
// Update urlbar only if a new page was loaded on the primary content area
|
||||
// Do not update urlbar if there was a subframe navigation
|
||||
|
||||
var browser = getBrowser().selectedBrowser;
|
||||
var browser = gBrowser.selectedBrowser;
|
||||
if (aWebProgress.DOMWindow == content) {
|
||||
|
||||
if ((location == "about:blank" && !content.opener) ||
|
||||
|
@ -4264,10 +4271,6 @@ nsBrowserAccess.prototype =
|
|||
return null;
|
||||
}
|
||||
|
||||
if (!gPrefService)
|
||||
gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
|
||||
var loadflags = isExternal ?
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
|
@ -4424,9 +4427,8 @@ function onViewToolbarsPopupShowing(aEvent)
|
|||
|
||||
var firstMenuItem = popup.firstChild;
|
||||
|
||||
var toolbox = getNavToolbox();
|
||||
for (i = 0; i < toolbox.childNodes.length; ++i) {
|
||||
var toolbar = toolbox.childNodes[i];
|
||||
for (i = 0; i < gNavToolbox.childNodes.length; ++i) {
|
||||
var toolbar = gNavToolbox.childNodes[i];
|
||||
var toolbarName = toolbar.getAttribute("toolbarname");
|
||||
var type = toolbar.getAttribute("type");
|
||||
if (toolbarName && type != "menubar") {
|
||||
|
@ -4446,9 +4448,8 @@ function onViewToolbarsPopupShowing(aEvent)
|
|||
|
||||
function onViewToolbarCommand(aEvent)
|
||||
{
|
||||
var toolbox = getNavToolbox();
|
||||
var index = aEvent.originalTarget.getAttribute("toolbarindex");
|
||||
var toolbar = toolbox.childNodes[index];
|
||||
var toolbar = gNavToolbox.childNodes[index];
|
||||
|
||||
toolbar.collapsed = aEvent.originalTarget.getAttribute("checked") != "true";
|
||||
document.persist(toolbar.id, "collapsed");
|
||||
|
@ -4953,20 +4954,6 @@ var contentAreaDNDObserver = {
|
|||
|
||||
};
|
||||
|
||||
function getBrowser()
|
||||
{
|
||||
if (!gBrowser)
|
||||
gBrowser = document.getElementById("content");
|
||||
return gBrowser;
|
||||
}
|
||||
|
||||
function getNavToolbox()
|
||||
{
|
||||
if (!gNavToolbox)
|
||||
gNavToolbox = document.getElementById("navigator-toolbox");
|
||||
return gNavToolbox;
|
||||
}
|
||||
|
||||
function MultiplexHandler(event)
|
||||
{ try {
|
||||
var node = event.target;
|
||||
|
@ -5023,8 +5010,7 @@ function SetForcedCharset(charset)
|
|||
|
||||
function BrowserSetForcedCharacterSet(aCharset)
|
||||
{
|
||||
var docCharset = getBrowser().docShell.QueryInterface(
|
||||
Components.interfaces.nsIDocCharset);
|
||||
var docCharset = gBrowser.docShell.QueryInterface(Ci.nsIDocCharset);
|
||||
docCharset.charset = aCharset;
|
||||
// Save the forced character-set
|
||||
PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, aCharset);
|
||||
|
@ -5033,7 +5019,7 @@ function BrowserSetForcedCharacterSet(aCharset)
|
|||
|
||||
function BrowserSetForcedDetector(doReload)
|
||||
{
|
||||
getBrowser().documentCharsetInfo.forcedDetector = true;
|
||||
gBrowser.documentCharsetInfo.forcedDetector = true;
|
||||
if (doReload)
|
||||
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||
}
|
||||
|
@ -5399,7 +5385,7 @@ var OfflineApps = {
|
|||
return gBrowser.mCurrentBrowser;
|
||||
}
|
||||
|
||||
var browsers = getBrowser().browsers;
|
||||
var browsers = gBrowser.browsers;
|
||||
for (var i = 0; i < browsers.length; ++i) {
|
||||
uri = this._getManifestURI(browsers[i].contentWindow);
|
||||
if (uri && uri.equals(aCacheUpdate.manifestURI)) {
|
||||
|
@ -5608,13 +5594,12 @@ var OfflineApps = {
|
|||
|
||||
function WindowIsClosing()
|
||||
{
|
||||
var browser = getBrowser();
|
||||
var cn = browser.tabContainer.childNodes;
|
||||
var cn = gBrowser.tabContainer.childNodes;
|
||||
var numtabs = cn.length;
|
||||
var reallyClose = true;
|
||||
|
||||
for (var i = 0; reallyClose && i < numtabs; ++i) {
|
||||
var ds = browser.getBrowserForTab(cn[i]).docShell;
|
||||
var ds = gBrowser.getBrowserForTab(cn[i]).docShell;
|
||||
|
||||
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
||||
reallyClose = false;
|
||||
|
@ -5628,7 +5613,7 @@ function WindowIsClosing()
|
|||
// up another dialog so we don't need to.)
|
||||
return closeWindow(false,
|
||||
function () {
|
||||
return browser.warnAboutClosingTabs(true);
|
||||
return gBrowser.warnAboutClosingTabs(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5797,7 +5782,6 @@ function getPluginInfo(pluginElement)
|
|||
}
|
||||
|
||||
missingPluginInstaller.prototype.installSinglePlugin = function(aEvent){
|
||||
var tabbrowser = getBrowser();
|
||||
var missingPluginsArray = {};
|
||||
|
||||
var pluginInfo = getPluginInfo(aEvent.target);
|
||||
|
@ -5806,7 +5790,7 @@ missingPluginInstaller.prototype.installSinglePlugin = function(aEvent){
|
|||
if (missingPluginsArray) {
|
||||
window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
|
||||
"PFSWindow", "chrome,centerscreen,resizable=yes",
|
||||
{plugins: missingPluginsArray, browser: tabbrowser.selectedBrowser});
|
||||
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
|
||||
}
|
||||
|
||||
aEvent.preventDefault();
|
||||
|
@ -5835,18 +5819,17 @@ missingPluginInstaller.prototype.newMissingPlugin = function(aEvent){
|
|||
return;
|
||||
} catch (ex) {} // if the pref is missing, treat it as false, which shows the infobar
|
||||
|
||||
var tabbrowser = getBrowser();
|
||||
const browsers = tabbrowser.mPanelContainer.childNodes;
|
||||
const browsers = gBrowser.mPanelContainer.childNodes;
|
||||
|
||||
var contentWindow = aEvent.target.ownerDocument.defaultView.top;
|
||||
|
||||
var i = 0;
|
||||
for (; i < browsers.length; i++) {
|
||||
if (tabbrowser.getBrowserAtIndex(i).contentWindow == contentWindow)
|
||||
if (gBrowser.getBrowserAtIndex(i).contentWindow == contentWindow)
|
||||
break;
|
||||
}
|
||||
|
||||
var browser = tabbrowser.getBrowserAtIndex(i);
|
||||
var browser = gBrowser.getBrowserAtIndex(i);
|
||||
if (!browser.missingPlugins)
|
||||
browser.missingPlugins = {};
|
||||
|
||||
|
@ -5928,12 +5911,11 @@ function blocklistInfo()
|
|||
function pluginsMissing()
|
||||
{
|
||||
// get the urls of missing plugins
|
||||
var tabbrowser = getBrowser();
|
||||
var missingPluginsArray = tabbrowser.selectedBrowser.missingPlugins;
|
||||
var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
|
||||
if (missingPluginsArray) {
|
||||
window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
|
||||
"PFSWindow", "chrome,centerscreen,resizable=yes",
|
||||
{plugins: missingPluginsArray, browser: tabbrowser.selectedBrowser});
|
||||
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6139,6 +6121,8 @@ var FeedHandler = {
|
|||
|
||||
#include browser-textZoom.js
|
||||
|
||||
#include browser-tabPreviews.js
|
||||
|
||||
HistoryMenu.toggleRecentlyClosedTabs = function PHM_toggleRecentlyClosedTabs() {
|
||||
// enable/disable the Recently Closed Tabs sub menu
|
||||
var undoPopup = document.getElementById("historyUndoPopup");
|
||||
|
@ -6214,7 +6198,7 @@ function undoCloseMiddleClick(aEvent) {
|
|||
return;
|
||||
|
||||
undoCloseTab(aEvent.originalTarget.value);
|
||||
getBrowser().moveTabToEnd();
|
||||
gBrowser.moveTabToEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6224,15 +6208,14 @@ function undoCloseMiddleClick(aEvent) {
|
|||
*/
|
||||
function undoCloseTab(aIndex) {
|
||||
// wallpaper patch to prevent an unnecessary blank tab (bug 343895)
|
||||
var tabbrowser = getBrowser();
|
||||
var blankTabToRemove = null;
|
||||
if (tabbrowser.tabContainer.childNodes.length == 1 &&
|
||||
if (gBrowser.tabContainer.childNodes.length == 1 &&
|
||||
!gPrefService.getBoolPref("browser.tabs.autoHide") &&
|
||||
tabbrowser.selectedBrowser.sessionHistory.count < 2 &&
|
||||
tabbrowser.selectedBrowser.currentURI.spec == "about:blank" &&
|
||||
!tabbrowser.selectedBrowser.contentDocument.body.hasChildNodes() &&
|
||||
!tabbrowser.selectedTab.hasAttribute("busy"))
|
||||
blankTabToRemove = tabbrowser.selectedTab;
|
||||
gBrowser.selectedBrowser.sessionHistory.count < 2 &&
|
||||
gBrowser.selectedBrowser.currentURI.spec == "about:blank" &&
|
||||
!gBrowser.selectedBrowser.contentDocument.body.hasChildNodes() &&
|
||||
!gBrowser.selectedTab.hasAttribute("busy"))
|
||||
blankTabToRemove = gBrowser.selectedTab;
|
||||
|
||||
var ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
|
@ -6241,7 +6224,7 @@ function undoCloseTab(aIndex) {
|
|||
ss.undoCloseTab(window, aIndex || 0);
|
||||
|
||||
if (blankTabToRemove)
|
||||
tabbrowser.removeTab(blankTabToRemove);
|
||||
gBrowser.removeTab(blankTabToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6753,3 +6736,7 @@ let DownloadMonitorPanel = {
|
|||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener]),
|
||||
};
|
||||
|
||||
/* DEPRECATED */
|
||||
function getBrowser() gBrowser;
|
||||
function getNavToolbox() gNavToolbox;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
# Pierre Chanial <chanial@noos.fr>
|
||||
# Dean Tessman <dean_tessman@hotmail.com>
|
||||
# Johnathan Nightingale <johnath@mozilla.com>
|
||||
# Dão Gottwald <dao@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -61,6 +62,7 @@
|
|||
|
||||
<window id="main-window"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="BrowserStartup()" onunload="BrowserShutdown()" onclose="return WindowIsClosing();"
|
||||
contenttitlesetting="true"
|
||||
|
@ -102,10 +104,14 @@
|
|||
<!-- for url bar autocomplete -->
|
||||
<panel type="autocomplete-richlistbox" chromedir="&locale.dir;" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
|
||||
|
||||
<!-- XXX panel element that has one or more text fields should not be
|
||||
top-most panel, for IME users. See bug 433340 comment 100. -->
|
||||
<panel id="editBookmarkPanel"
|
||||
orient="vertical"
|
||||
ignorekeys="true"
|
||||
hidden="true"
|
||||
noautohide="true"
|
||||
onpopupshowing="this.removeAttribute('noautohide');"
|
||||
onpopupshown="StarUI.panelShown(event);"
|
||||
aria-labelledby="editBookmarkPanelTitle">
|
||||
<hbox flex="1" align="top">
|
||||
|
@ -227,6 +233,29 @@
|
|||
<tooltip id="urlTooltip">
|
||||
<label crop="center" flex="1"/>
|
||||
</tooltip>
|
||||
|
||||
<panel id="ctrlTab-panel" class="KUI-panel" hidden="true">
|
||||
<label id="ctrlTab-label" flex="1"/>
|
||||
<svg:svg id="ctrlTab-svgRoot">
|
||||
<svg:defs>
|
||||
<svg:linearGradient id="ctrlTab-fadeGradient" x1="1" y1="1" x2="1" y2="0">
|
||||
<svg:stop id="ctrlTab-fadeGradientBottom" offset="0"/>
|
||||
<svg:stop id="ctrlTab-fadeGradientTop" offset="1"/>
|
||||
</svg:linearGradient>
|
||||
<svg:filter id="ctrlTab-iconShadow">
|
||||
<svg:feOffset result="shadow" in="SourceAlpha" dx="2" dy="-1"/>
|
||||
<svg:feColorMatrix result="transparent-shadow" in="shadow"
|
||||
values="1 0 0 0 0
|
||||
0 1 0 0 0
|
||||
0 0 1 0 0
|
||||
0 0 0 0.5 0"/>
|
||||
<svg:feBlend in="SourceGraphic" in2="transparent-shadow"/>
|
||||
</svg:filter>
|
||||
</svg:defs>
|
||||
<svg:g id="ctrlTab-container"/>
|
||||
<svg:rect id="ctrlTab-groundFade" fill="url(#ctrlTab-fadeGradient)" width="100%"/>
|
||||
</svg:svg>
|
||||
</panel>
|
||||
</popupset>
|
||||
|
||||
<!-- bookmarks toolbar tooltip -->
|
||||
|
|
|
@ -1189,6 +1189,8 @@ nsContextMenu.prototype = {
|
|||
[engineName,
|
||||
selectedText]);
|
||||
document.getElementById("context-searchselect").label = menuLabel;
|
||||
document.getElementById("context-searchselect").accessKey =
|
||||
gNavigatorBundle.getString("contextMenuSearchText.accesskey");
|
||||
|
||||
return true;
|
||||
},
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<xul:label xbl:inherits="value=type"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox>
|
||||
<xul:label xbl:inherits="value=feedURL" class="text-link" flex="1"
|
||||
<xul:label xbl:inherits="value=feedURL,tooltiptext=feedURL" class="text-link" flex="1"
|
||||
onclick="openUILink(this.value, event);" crop="end"/>
|
||||
<xul:spacer flex="10000"/>
|
||||
</xul:hbox>
|
||||
|
|
|
@ -70,11 +70,11 @@
|
|||
<script type="application/x-javascript" src="chrome://browser/content/pageinfo/feeds.js"/>
|
||||
<script type="application/x-javascript" src="chrome://browser/content/pageinfo/permissions.js"/>
|
||||
<script type="application/x-javascript" src="chrome://browser/content/pageinfo/security.js"/>
|
||||
<script type="application/x-javascript" src="chrome://global/content/strres.js"/>
|
||||
<script type="application/x-javascript" src="chrome://browser/content/utilityOverlay.js"/>
|
||||
|
||||
<stringbundleset id="pageinfobundleset">
|
||||
<stringbundle id="pageinfobundle" src="chrome://browser/locale/pageInfo.properties"/>
|
||||
<stringbundle id="pkiBundle" src="chrome://pippki/locale/pippki.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<commandset id="pageInfoCommandSet">
|
||||
|
|
|
@ -186,9 +186,6 @@ var security = {
|
|||
};
|
||||
|
||||
function securityOnLoad() {
|
||||
var bundle = srGetStrBundle("chrome://pippki/locale/pippki.properties");
|
||||
var pageInfoBundle = document.getElementById("pageinfobundle");
|
||||
|
||||
var info = security._getSecurityInfo();
|
||||
if (!info) {
|
||||
document.getElementById("securityTab").hidden = true;
|
||||
|
@ -200,6 +197,8 @@ function securityOnLoad() {
|
|||
document.getElementById("securityBox").collapsed = false;
|
||||
}
|
||||
|
||||
const pageInfoBundle = document.getElementById("pageinfobundle");
|
||||
|
||||
/* Set Identity section text */
|
||||
setText("security-identity-domain-value", info.hostName);
|
||||
|
||||
|
@ -273,35 +272,36 @@ function securityOnLoad() {
|
|||
}
|
||||
|
||||
/* Set the Technical Detail section messages */
|
||||
const pkiBundle = document.getElementById("pkiBundle");
|
||||
var hdr;
|
||||
var msg1;
|
||||
var msg2;
|
||||
|
||||
if (info.isBroken) {
|
||||
hdr = bundle.GetStringFromName("pageInfo_MixedContent");
|
||||
msg1 = bundle.GetStringFromName("pageInfo_Privacy_Mixed1");
|
||||
msg2 = bundle.GetStringFromName("pageInfo_Privacy_None2");
|
||||
hdr = pkiBundle.getString("pageInfo_MixedContent");
|
||||
msg1 = pkiBundle.getString("pageInfo_Privacy_Mixed1");
|
||||
msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
|
||||
}
|
||||
else if (info.encryptionStrength >= 90) {
|
||||
hdr = bundle.formatStringFromName("pageInfo_StrongEncryption",
|
||||
[ info.encryptionAlgorithm, info.encryptionStrength + "" ], 2);
|
||||
msg1 = bundle.GetStringFromName("pageInfo_Privacy_Strong1");
|
||||
msg2 = bundle.GetStringFromName("pageInfo_Privacy_Strong2");
|
||||
hdr = pkiBundle.getFormattedString("pageInfo_StrongEncryption",
|
||||
[info.encryptionAlgorithm, info.encryptionStrength + ""]);
|
||||
msg1 = pkiBundle.getString("pageInfo_Privacy_Strong1");
|
||||
msg2 = pkiBundle.getString("pageInfo_Privacy_Strong2");
|
||||
security._cert = info.cert;
|
||||
}
|
||||
else if (info.encryptionStrength > 0) {
|
||||
hdr = bundle.formatStringFromName("pageInfo_WeakEncryption",
|
||||
[ info.encryptionAlgorithm, info.encryptionStrength + "" ], 2);
|
||||
msg1 = bundle.formatStringFromName("pageInfo_Privacy_Weak1", [ info.hostName ], 1);
|
||||
msg2 = bundle.GetStringFromName("pageInfo_Privacy_Weak2");
|
||||
hdr = pkiBundle.getFormattedString("pageInfo_WeakEncryption",
|
||||
[info.encryptionAlgorithm, info.encryptionStrength + ""]);
|
||||
msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_Weak1", [info.hostName]);
|
||||
msg2 = pkiBundle.getString("pageInfo_Privacy_Weak2");
|
||||
}
|
||||
else {
|
||||
hdr = bundle.GetStringFromName("pageInfo_NoEncryption");
|
||||
hdr = pkiBundle.getString("pageInfo_NoEncryption");
|
||||
if (info.hostName != null)
|
||||
msg1 = bundle.formatStringFromName("pageInfo_Privacy_None1", [ info.hostName ], 1);
|
||||
msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
|
||||
else
|
||||
msg1 = bundle.GetStringFromName("pageInfo_Privacy_None3");
|
||||
msg2 = bundle.GetStringFromName("pageInfo_Privacy_None2");
|
||||
msg1 = pkiBundle.getString("pageInfo_Privacy_None3");
|
||||
msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
|
||||
}
|
||||
setText("security-technical-shortform", hdr);
|
||||
setText("security-technical-longform1", msg1);
|
||||
|
|
|
@ -278,7 +278,6 @@
|
|||
mTab: aTab,
|
||||
mBrowser: aBrowser,
|
||||
mBlank: aStartsBlank,
|
||||
mLastURI: null,
|
||||
|
||||
// cache flags for correct status bar update after tab switching
|
||||
mStateFlags: 0,
|
||||
|
@ -1389,6 +1388,18 @@
|
|||
|
||||
<method name="removeTab">
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._endRemoveTab(this._beginRemoveTab(aTab, true));
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<!-- Returns the tab being removed. This might not be the same as aTab,
|
||||
in cases when aTab is not actually a tab -->
|
||||
<method name="_beginRemoveTab">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aFireBeforeUnload"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._browsers = null; // invalidate cache
|
||||
|
@ -1403,9 +1414,11 @@
|
|||
return;
|
||||
}
|
||||
|
||||
var ds = this.getBrowserForTab(aTab).docShell;
|
||||
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
||||
return;
|
||||
if (aFireBeforeUnload) {
|
||||
var ds = this.getBrowserForTab(aTab).docShell;
|
||||
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
||||
return;
|
||||
}
|
||||
|
||||
// see notes in addTab
|
||||
var _delayedUpdate = function(aTabContainer) {
|
||||
|
@ -1435,15 +1448,7 @@
|
|||
evt.initEvent("TabClose", true, false);
|
||||
aTab.dispatchEvent(evt);
|
||||
|
||||
var index = -1;
|
||||
if (this.mCurrentTab == aTab)
|
||||
index = this.mTabContainer.selectedIndex;
|
||||
else {
|
||||
// Find and locate the tab in our list.
|
||||
for (var i = 0; i < l; i++)
|
||||
if (this.mTabContainer.childNodes[i] == aTab)
|
||||
index = i;
|
||||
}
|
||||
var index = aTab._tPos;
|
||||
|
||||
// Remove the tab's filter and progress listener.
|
||||
const filter = this.mTabFilters[index];
|
||||
|
@ -1459,22 +1464,34 @@
|
|||
// We are no longer the primary content area.
|
||||
oldBrowser.setAttribute("type", "content-targetable");
|
||||
|
||||
// Get the index of the tab we're removing before unselecting it
|
||||
var currentIndex = this.mTabContainer.selectedIndex;
|
||||
|
||||
var oldTab = aTab;
|
||||
|
||||
// clean up the before/afterselected attributes before removing the tab
|
||||
oldTab._selected = false;
|
||||
|
||||
// Remove this tab as the owner of any other tabs, since it's going away.
|
||||
for (i = 0; i < this.mTabContainer.childNodes.length; ++i) {
|
||||
for (var i = 0; i < this.mTabs.length; ++i) {
|
||||
var tab = this.mTabContainer.childNodes[i];
|
||||
if ("owner" in tab && tab.owner == oldTab)
|
||||
if ("owner" in tab && tab.owner == aTab)
|
||||
// |tab| is a child of the tab we're removing, make it an orphan
|
||||
tab.owner = null;
|
||||
}
|
||||
|
||||
return aTab;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_endRemoveTab">
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var browser = this.getBrowserForTab(aTab);
|
||||
var length = this.mTabs.length;
|
||||
|
||||
// Get the index of the tab we're removing before unselecting it
|
||||
var currentIndex = this.mTabContainer.selectedIndex;
|
||||
var index = aTab._tPos;
|
||||
|
||||
// clean up the before/afterselected attributes before removing the
|
||||
// tab. But make sure this happens after we grab currentIndex.
|
||||
aTab._selected = false;
|
||||
|
||||
// Because of the way XBL works (fields just set JS
|
||||
// properties on the element) and the code we have in place
|
||||
// to preserve the JS objects for any elements that have
|
||||
|
@ -1485,16 +1502,18 @@
|
|||
// XBL implementation of nsIObserver still works. But
|
||||
// clearing focusedWindow happens below because it gets
|
||||
// reset by updateCurrentBrowser.
|
||||
oldBrowser.destroy();
|
||||
browser.destroy();
|
||||
|
||||
if (oldBrowser == this.mCurrentBrowser)
|
||||
if (browser == this.mCurrentBrowser)
|
||||
this.mCurrentBrowser = null;
|
||||
|
||||
// Remove the tab
|
||||
this.mTabContainer.removeChild(oldTab);
|
||||
this.mTabContainer.removeChild(aTab);
|
||||
// Update our length
|
||||
--length;
|
||||
// invalidate cache, because mTabContainer is about to change
|
||||
this._browsers = null;
|
||||
this.mPanelContainer.removeChild(oldBrowser.parentNode);
|
||||
this.mPanelContainer.removeChild(browser.parentNode);
|
||||
|
||||
try {
|
||||
// if we're at the right side (and not the logical end,
|
||||
|
@ -1523,24 +1542,24 @@
|
|||
else if (currentIndex < index)
|
||||
newIndex = currentIndex;
|
||||
else {
|
||||
if ("owner" in oldTab && oldTab.owner &&
|
||||
if ("owner" in aTab && aTab.owner &&
|
||||
this.mPrefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
|
||||
for (i = 0; i < this.mTabContainer.childNodes.length; ++i) {
|
||||
for (var i = 0; i < length; ++i) {
|
||||
tab = this.mTabContainer.childNodes[i];
|
||||
if (tab == oldTab.owner) {
|
||||
if (tab == aTab.owner) {
|
||||
newIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newIndex == -1)
|
||||
newIndex = (index == l - 1) ? index - 1 : index;
|
||||
newIndex = (index == length) ? index - 1 : index;
|
||||
}
|
||||
|
||||
// Select the new tab
|
||||
this.selectedTab = this.mTabContainer.childNodes[newIndex];
|
||||
this.selectedTab = this.mTabs[newIndex];
|
||||
|
||||
for (i = oldTab._tPos; i < this.mTabContainer.childNodes.length; i++) {
|
||||
for (i = aTab._tPos; i < length; i++) {
|
||||
this.mTabContainer.childNodes[i]._tPos = i;
|
||||
}
|
||||
this.mTabBox.selectedPanel = this.getBrowserForTab(this.mCurrentTab).parentNode;
|
||||
|
@ -1549,8 +1568,53 @@
|
|||
this.updateCurrentBrowser();
|
||||
|
||||
// see comment above destroy above
|
||||
oldBrowser.focusedWindow = null;
|
||||
oldBrowser.focusedElement = null;
|
||||
browser.focusedWindow = null;
|
||||
browser.focusedElement = null;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="swapBrowsersAndCloseOther">
|
||||
<parameter name="aOurTab"/>
|
||||
<parameter name="aOtherTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var remoteBrowser =
|
||||
aOtherTab.ownerDocument.defaultView.getBrowser();
|
||||
var tabCount = remoteBrowser.mTabs.length;
|
||||
|
||||
// First, start teardown of the other browser. Make sure to not
|
||||
// fire the beforeunload event in the process.
|
||||
var tabToRemove = remoteBrowser._beginRemoveTab(aOtherTab, false);
|
||||
|
||||
// Unhook our progress listener
|
||||
var ourIndex = aOurTab._tPos;
|
||||
const filter = this.mTabFilters[ourIndex];
|
||||
var tabListener = this.mTabListeners[ourIndex];
|
||||
var ourBrowser = this.getBrowserForTab(aOurTab);
|
||||
ourBrowser.webProgress.removeProgressListener(filter);
|
||||
filter.removeProgressListener(tabListener);
|
||||
var tabListenerBlank = tabListener.mBlank;
|
||||
|
||||
// Swap the docshells
|
||||
ourBrowser.swapDocShells(remoteBrowser.getBrowserForTab(aOtherTab));
|
||||
|
||||
// Finish tearing down the tab that's going away.
|
||||
remoteBrowser._endRemoveTab(tabToRemove);
|
||||
|
||||
// Restore the progress listener
|
||||
tabListener = this.mTabProgressListener(aOurTab, ourBrowser,
|
||||
tabListenerBlank);
|
||||
this.mTabListeners[ourIndex] = tabListener;
|
||||
filter.addProgressListener(tabListener,
|
||||
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
|
||||
ourBrowser.webProgress.addProgressListener(filter,
|
||||
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
|
||||
// close the other window if this was its last tab
|
||||
if (tabCount == 1)
|
||||
aOtherTab.ownerDocument.defaultView.close();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -1879,19 +1943,26 @@
|
|||
}
|
||||
}
|
||||
else if (draggedTab) {
|
||||
// copy the dropped tab and remove it from the other window
|
||||
// (making it seem to have moved between windows)
|
||||
// swap the dropped tab with a new one we create and then close
|
||||
// it in the other window (making it seem to have moved between
|
||||
// windows)
|
||||
newIndex = this.getNewIndex(aEvent);
|
||||
newTab = this.duplicateTab(draggedTab);
|
||||
this.moveTabTo(newTab, newIndex);
|
||||
this.selectedTab = newTab;
|
||||
newTab = this.addTab("about:blank");
|
||||
var newBrowser = this.getBrowserForTab(newTab);
|
||||
// Stop the about:blank load
|
||||
newBrowser.stop();
|
||||
// make sure it has a docshell
|
||||
newBrowser.docShell;
|
||||
|
||||
var remoteBrowser = draggedTab.ownerDocument.defaultView.getBrowser();
|
||||
var tabCount = remoteBrowser.tabContainer.childNodes.length;
|
||||
remoteBrowser.removeTab(draggedTab);
|
||||
// close the other window if this was its last tab
|
||||
if (tabCount == 1)
|
||||
draggedTab.ownerDocument.defaultView.close();
|
||||
this.moveTabTo(newTab, newIndex);
|
||||
|
||||
this.swapBrowsersAndCloseOther(newTab, draggedTab);
|
||||
|
||||
// We need to set selectedTab after we've done
|
||||
// swapBrowsersAndCloseOther, so that the updateCurrentBrowser
|
||||
// it triggers will correctly update our URL bar.
|
||||
this.selectedTab = newTab;
|
||||
this.setTabTitle(newTab);
|
||||
}
|
||||
else {
|
||||
var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
|
||||
|
|
|
@ -59,6 +59,8 @@ _BROWSER_FILES = browser_bug321000.js \
|
|||
autodiscovery.html \
|
||||
moz.png \
|
||||
browser_getshortcutoruri.js \
|
||||
browser_page_style_menu.js \
|
||||
page_style_sample.html \
|
||||
$(NULL)
|
||||
|
||||
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
|
|
|
@ -8,6 +8,7 @@ function test() {
|
|||
}
|
||||
|
||||
function delayedOpenUrl() {
|
||||
ok(true, "Ran delayedOpenUrl");
|
||||
setTimeout(openPanelUrl, 100);
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,7 @@ function openPanelUrl(event) {
|
|||
}
|
||||
|
||||
function delayedRunTest() {
|
||||
ok(true, "Ran delayedRunTest");
|
||||
setTimeout(runTest, 100);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
finish();
|
||||
return;
|
||||
|
||||
var tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.linkedBrowser.addEventListener("load", checkPageStyleMenu, true);
|
||||
content.location =
|
||||
"chrome://mochikit/content/browser/browser/base/content/test/page_style_sample.html";
|
||||
}
|
||||
|
||||
function checkPageStyleMenu() {
|
||||
var menupopup = document.getElementById("pageStyleMenu")
|
||||
.getElementsByTagName("menupopup")[0];
|
||||
stylesheetFillPopup(menupopup);
|
||||
|
||||
var items = [];
|
||||
var current = menupopup.getElementsByTagName("menuseparator")[0];
|
||||
while (current.nextSibling) {
|
||||
current = current.nextSibling;
|
||||
items.push(current);
|
||||
}
|
||||
|
||||
var validLinks = 0;
|
||||
Array.forEach(content.document.getElementsByTagName("link"), function (link) {
|
||||
var title = link.getAttribute("title");
|
||||
var rel = link.getAttribute("rel");
|
||||
var media = link.getAttribute("media");
|
||||
var idstring = "link " + (title ? title : "without title and") +
|
||||
" with rel=\"" + rel + "\"" +
|
||||
(media ? " and media=\"" + media + "\"" : "");
|
||||
|
||||
var item = items.filter(function (item) item.label == title);
|
||||
var found = item.length == 1;
|
||||
var checked = found && (item[0].getAttribute("checked") == "true");
|
||||
|
||||
switch (link.getAttribute("data-state")) {
|
||||
case "0":
|
||||
ok(!found, idstring + " does not show up in page style menu");
|
||||
break;
|
||||
case "0-todo":
|
||||
validLinks++;
|
||||
todo(!found, idstring + " should not show up in page style menu");
|
||||
ok(!checked, idstring + " is not selected");
|
||||
break;
|
||||
case "1":
|
||||
validLinks++;
|
||||
ok(found, idstring + " shows up in page style menu");
|
||||
ok(!checked, idstring + " is not selected");
|
||||
break;
|
||||
case "2":
|
||||
validLinks++;
|
||||
ok(found, idstring + " shows up in page style menu");
|
||||
ok(checked, idstring + " is selected");
|
||||
break;
|
||||
default:
|
||||
throw "data-state attribute is missing or has invalid value";
|
||||
}
|
||||
});
|
||||
|
||||
is(validLinks, items.length, "all valid links found");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Test for page style menu</title>
|
||||
<!-- data-state values:
|
||||
0: should not appear in the page style menu
|
||||
0-todo: should not appear in the page style menu, but does
|
||||
1: should appear in the page style menu
|
||||
2: should appear in the page style menu as the selected stylesheet -->
|
||||
<link data-state="1" href="404.css" title="1" rel="alternate stylesheet">
|
||||
<link data-state="0" title="2" rel="alternate stylesheet">
|
||||
<link data-state="0" href="404.css" rel="alternate stylesheet">
|
||||
<link data-state="0" href="404.css" title="" rel="alternate stylesheet">
|
||||
<link data-state="1" href="404.css" title="3" rel="stylesheet alternate">
|
||||
<link data-state="1" href="404.css" title="4" rel=" alternate stylesheet ">
|
||||
<link data-state="1" href="404.css" title="5" rel="alternate stylesheet">
|
||||
<link data-state="2" href="404.css" title="6" rel="stylesheet">
|
||||
<link data-state="1" href="404.css" title="7" rel="foo stylesheet">
|
||||
<link data-state="0" href="404.css" title="8" rel="alternate">
|
||||
<link data-state="1" href="404.css" title="9" rel="alternate STYLEsheet">
|
||||
<link data-state="1" href="404.css" title="10" rel="alternate stylesheet" media="">
|
||||
<link data-state="1" href="404.css" title="11" rel="alternate stylesheet" media="all">
|
||||
<link data-state="1" href="404.css" title="12" rel="alternate stylesheet" media="ALL ">
|
||||
<link data-state="1" href="404.css" title="13" rel="alternate stylesheet" media="screen">
|
||||
<link data-state="1" href="404.css" title="14" rel="alternate stylesheet" media=" Screen">
|
||||
<link data-state="1" href="404.css" title="15" rel="alternate stylesheet" media="screen foo">
|
||||
<link data-state="1" href="404.css" title="16" rel="alternate stylesheet" media="all screen">
|
||||
<link data-state="0-todo" href="404.css" title="17" rel="alternate stylesheet" media="allscreen">
|
||||
<link data-state="0-todo" href="404.css" title="18" rel="alternate stylesheet" media="_all">
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
|
@ -42,7 +42,6 @@
|
|||
* for shared application glue for the Communicator suite of applications
|
||||
**/
|
||||
|
||||
var goPrefWindow = 0;
|
||||
var gBidiUI = false;
|
||||
|
||||
function getBrowserURL()
|
||||
|
|
|
@ -115,7 +115,6 @@ function load()
|
|||
null, null);
|
||||
}
|
||||
|
||||
gNavigatorBundle = document.getElementById("bundle_browser");
|
||||
gLoadFired = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ browser.jar:
|
|||
content/browser/aboutDialog.css (content/aboutDialog.css)
|
||||
* content/browser/aboutRobots.xhtml (content/aboutRobots.xhtml)
|
||||
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
|
||||
content/browser/aboutRobots-icon-rtl.png (content/aboutRobots-icon-rtl.png)
|
||||
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
|
||||
content/browser/aboutRobots-widget-right.png (content/aboutRobots-widget-right.png)
|
||||
* content/browser/browser.css (content/browser.css)
|
||||
|
|
|
@ -37,17 +37,17 @@
|
|||
# NSIS branding defines for unofficial builds.
|
||||
# The official release build branding.nsi is located in other-license/branding/firefox/
|
||||
# The nightly build branding.nsi is located in browser/installer/windows/nsis/
|
||||
!define BrandShortName "Gran Paradiso"
|
||||
!define BrandShortName "Shiretoko"
|
||||
# BrandFullNameInternal is used for some registry and file system values
|
||||
# instead of BrandFullName and typically should not be modified.
|
||||
!define BrandFullNameInternal "Gran Paradiso"
|
||||
!define BrandFullNameInternal "Shiretoko"
|
||||
!define CompanyName "mozilla.org"
|
||||
!define URLInfoAbout "http://www.mozilla.org"
|
||||
!define URLUpdateInfo "http://www.mozilla.org/projects/firefox"
|
||||
!define SurveyURL "https://survey.mozilla.com/1/Mozilla%20Firefox/${AppVersion}/${AB_CD}/exit.html"
|
||||
|
||||
# Everything below this line may be modified for Alpha / Beta releases.
|
||||
!define BrandFullName "Gran Paradiso"
|
||||
!define BrandFullName "Shiretoko"
|
||||
|
||||
# Add !define NO_INSTDIR_FROM_REG to prevent finding a non-default installation
|
||||
# directory in the registry and using that as the default. This prevents
|
||||
|
|
|
@ -1 +1 @@
|
|||
MOZ_APP_DISPLAYNAME="GranParadiso"
|
||||
MOZ_APP_DISPLAYNAME="Shiretoko"
|
||||
|
|
|
@ -28,7 +28,7 @@ resource 'STR#' (5000, "English") {
|
|||
"Save AsÉ",
|
||||
// Descriptive text, curly quotes are 0xD2 and 0xD3
|
||||
"You are about to install\n"
|
||||
"Gran Paradiso.\n"
|
||||
"Shiretoko.\n"
|
||||
"\n"
|
||||
"Please read the license agreement. If you agree to its terms and accept, click ÒAcceptÓ to access the software. Otherwise, click ÒDeclineÓ to cancel."
|
||||
};
|
||||
|
@ -41,7 +41,7 @@ resource 'STR#' (5000, "English") {
|
|||
// 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly
|
||||
// single quotes ('), 0xD5 is also the apostrophe.
|
||||
data 'TEXT' (5000, "English") {
|
||||
"GRAN PARADISO END-USER SOFTWARE LICENSE AGREEMENT\n"
|
||||
"SHIRETOKO END-USER SOFTWARE LICENSE AGREEMENT\n"
|
||||
"Version 3.0, May 2008\n"
|
||||
"\n"
|
||||
"A SOURCE CODE VERSION OF CERTAIN FIREFOX BROWSER FUNCTIONALITY THAT YOU MAY USE, MODIFY AND DISTRIBUTE IS AVAILABLE TO YOU FREE-OF-CHARGE FROM WWW.MOZILLA.ORG UNDER THE MOZILLA PUBLIC LICENSE and other open source software licenses.\n"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Do NOT localize or otherwise change these values
|
||||
browser.startup.homepage=http://www.mozilla.org/projects/granparadiso/
|
||||
browser.startup.homepage=http://www.mozilla.org/projects/shiretoko/
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!ENTITY brandShortName "Gran Paradiso">
|
||||
<!ENTITY brandFullName "Gran Paradiso">
|
||||
<!ENTITY brandShortName "Shiretoko">
|
||||
<!ENTITY brandFullName "Shiretoko">
|
||||
<!ENTITY vendorShortName "mozilla.org">
|
||||
|
||||
<!-- LOCALIZATION NOTE (releaseBaseURL): The about: page appends __MOZ_APP_VERSION__.html, e.g. 2.0.html -->
|
||||
<!ENTITY releaseBaseURL "http://www.mozilla.org/projects/granparadiso/releases/">
|
||||
<!ENTITY releaseBaseURL "http://www.mozilla.org/projects/shiretoko/releases/">
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
brandShortName=Gran Paradiso
|
||||
brandFullName=Gran Paradiso
|
||||
brandShortName=Shiretoko
|
||||
brandFullName=Shiretoko
|
||||
vendorShortName=mozilla.org
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
@AB_CD@.jar:
|
||||
% locale branding @AB_CD@ %locale/branding/
|
||||
# Gran Paradiso branding only exists in en-US
|
||||
# Unofficial branding only exists in en-US
|
||||
locale/branding/brand.dtd (en-US/brand.dtd)
|
||||
* locale/branding/brand.properties (en-US/brand.properties)
|
||||
|
|
|
@ -59,3 +59,14 @@ package:
|
|||
|
||||
install::
|
||||
@$(MAKE) -C browser/installer install
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
# Implemented in testing/testsuite-targets.mk
|
||||
mochitest-browser-chrome:
|
||||
$(RUN_MOCHITEST) --browser-chrome
|
||||
$(CHECK_TEST_ERROR)
|
||||
|
||||
mochitest:: mochitest-browser-chrome
|
||||
|
||||
.PHONY: mochitest-browser-chrome
|
||||
endif
|
||||
|
|
|
@ -226,7 +226,7 @@ DistributionCustomizer.prototype = {
|
|||
|
||||
if (!bmProcessed) {
|
||||
if (sections["BookmarksMenu"])
|
||||
this._parseBookmarksSection(this._bmSvc.bookmarksRoot,
|
||||
this._parseBookmarksSection(this._bmSvc.bookmarksMenuFolder,
|
||||
"BookmarksMenu");
|
||||
if (sections["BookmarksToolbar"])
|
||||
this._parseBookmarksSection(this._bmSvc.toolbarFolder,
|
||||
|
|
|
@ -564,13 +564,29 @@ BrowserGlue.prototype = {
|
|||
this._dataSource = this._rdf.GetDataSource("rdf:local-store");
|
||||
this._dirty = false;
|
||||
|
||||
var currentSet = this._rdf.GetResource("currentset");
|
||||
|
||||
// get an nsIRDFResource for the nav-bar item
|
||||
var navBar = this._rdf.GetResource("chrome://browser/content/browser.xul#nav-bar");
|
||||
var target = this._getPersist(navBar, currentSet);
|
||||
if (target && !/(?:^|,)unified-back-forward-button(?:$|,)/.test(target))
|
||||
this._setPersist(navBar, currentSet, "unified-back-forward-button," + target);
|
||||
let currentsetResource = this._rdf.GetResource("currentset");
|
||||
let toolbars = ["nav-bar", "toolbar-menubar", "PersonalToolbar"];
|
||||
for (let i = 0; i < toolbars.length; i++) {
|
||||
let toolbar = this._rdf.GetResource("chrome://browser/content/browser.xul#" + toolbars[i]);
|
||||
let currentset = this._getPersist(toolbar, currentsetResource);
|
||||
if (!currentset) {
|
||||
// toolbar isn't customized
|
||||
if (i == 0)
|
||||
// new button is in the defaultset, nothing to migrate
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (/(?:^|,)unified-back-forward-button(?:$|,)/.test(currentset))
|
||||
// new button is already there, nothing to migrate
|
||||
break;
|
||||
if (/(?:^|,)back-button(?:$|,)/.test(currentset)) {
|
||||
let newset = currentset.replace(/(^|,)back-button($|,)/,
|
||||
"$1unified-back-forward-button,back-button$2")
|
||||
this._setPersist(toolbar, currentsetResource, newset);
|
||||
// done migrating
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// force the RDF to be saved
|
||||
if (this._dirty)
|
||||
|
|
|
@ -63,8 +63,7 @@
|
|||
|
||||
<hbox align="center">
|
||||
<label value="&search.label;" accesskey="&search.accesskey;" control="search-box"/>
|
||||
<textbox id="search-box" flex="1"
|
||||
type="timed" timeout="500"
|
||||
<textbox id="search-box" flex="1" type="search"
|
||||
oncommand="searchBookmarks(this.value);"/>
|
||||
</hbox>
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
<hbox align="center">
|
||||
<label value="&find.label;" accesskey="&find.accesskey;"
|
||||
control="search-box"/>
|
||||
<textbox id="search-box" flex="1" type="timed" timeout="500"
|
||||
<textbox id="search-box" flex="1" type="search"
|
||||
oncommand="searchHistory(this.value);"/>
|
||||
<button id="viewButton" style="min-width:0px !important;" type="menu"
|
||||
label="&view.label;" accesskey="&view.accesskey;" selectedsort="day"
|
||||
|
|
|
@ -902,12 +902,12 @@
|
|||
<getter><![CDATA[
|
||||
// By default, the insertion point is at the top level, at the end.
|
||||
var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
|
||||
var folderId = 0;
|
||||
var container = null;
|
||||
var orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
var isTag = false;
|
||||
|
||||
if (PlacesUtils.nodeIsFolder(this._resultNode)) {
|
||||
folderId = PlacesUtils.getConcreteItemId(this._resultNode);
|
||||
container = this._resultNode;
|
||||
isTag = PlacesUtils.nodeIsTagQuery(this._resultNode);
|
||||
}
|
||||
|
||||
|
@ -917,20 +917,37 @@
|
|||
if (!popupNode.node) {
|
||||
// If a static menuitem is selected the insertion point
|
||||
// is inside the folder, at the end.
|
||||
folderId = PlacesUtils.getConcreteItemId(selectedNode);
|
||||
container = selectedNode;
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
}
|
||||
else {
|
||||
// In all other cases the insertion point is before that node.
|
||||
folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
|
||||
container = selectedNode.parent;
|
||||
index = PlacesUtils.getIndexOfNode(selectedNode);
|
||||
isTag = PlacesUtils.nodeIsTagQuery(selectedNode.parent);
|
||||
}
|
||||
}
|
||||
return new InsertionPoint(folderId, index, orientation, isTag);
|
||||
|
||||
if (this._disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
index, orientation, isTag);
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="_disallowInsertion">
|
||||
<parameter name="aContainer"/>
|
||||
<body><![CDATA[
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<method name="selectAll">
|
||||
<body/>
|
||||
|
|
|
@ -853,6 +853,10 @@ var PlacesSearchBox = {
|
|||
//scopeBtn.label = PlacesOrganizer._places.selectedNode.title;
|
||||
break;
|
||||
case "bookmarks":
|
||||
// Make sure we're getting uri results.
|
||||
// We do not yet support searching into grouped queries or into
|
||||
// tag containers, so we must fall to the default case.
|
||||
currentOptions.resultType = currentOptions.RESULT_TYPE_URI;
|
||||
content.applyFilter(filterString,
|
||||
[PlacesUtils.bookmarksMenuFolderId,
|
||||
PlacesUtils.toolbarFolderId,
|
||||
|
|
|
@ -385,7 +385,7 @@
|
|||
<getter><![CDATA[
|
||||
// By default, the insertion point is at the top level, at the end.
|
||||
var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
|
||||
var folderId = PlacesUtils.getConcreteItemId(this._result.root);
|
||||
var container = this._result.root;
|
||||
var orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
var isTag = false;
|
||||
|
||||
|
@ -395,20 +395,37 @@
|
|||
if (!popupNode.node) {
|
||||
// If a static menuitem is selected the insertion point
|
||||
// is inside the folder, at the end.
|
||||
folderId = PlacesUtils.getConcreteItemId(selectedNode);
|
||||
container = selectedNode;
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
}
|
||||
else {
|
||||
// In all other cases the insertion point is before that node.
|
||||
folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
|
||||
container = selectedNode.parent;
|
||||
index = PlacesUtils.getIndexOfNode(selectedNode);
|
||||
isTag = PlacesUtils.nodeIsTagQuery(selectedNode.parent);
|
||||
}
|
||||
}
|
||||
return new InsertionPoint(folderId, index, orientation, isTag);
|
||||
|
||||
if (this._disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
index, orientation, isTag);
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="_disallowInsertion">
|
||||
<parameter name="aContainer"/>
|
||||
<body><![CDATA[
|
||||
// allow dropping into Tag containers
|
||||
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||
return false;
|
||||
// Disallow insertion of items under readonly folders
|
||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<method name="selectAll">
|
||||
<body><![CDATA[
|
||||
|
|
|
@ -487,7 +487,7 @@
|
|||
return this._cachedInsertionPoint;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
|
||||
<method name="_disallowInsertion">
|
||||
<parameter name="aContainer"/>
|
||||
<body><![CDATA[
|
||||
|
|
|
@ -939,6 +939,11 @@ PlacesTreeView.prototype = {
|
|||
if (!node.parent)
|
||||
return true;
|
||||
|
||||
// Flat-lists may ignore expandQueries and other query options when
|
||||
// they are asked to open a container.
|
||||
if (this._flatList)
|
||||
return true;
|
||||
|
||||
// treat non-expandable childless queries as non-containers
|
||||
if (PlacesUtils.nodeIsQuery(node)) {
|
||||
var parent = node.parent;
|
||||
|
|
|
@ -897,14 +897,26 @@ placesSortFolderByNameTransactions.prototype = {
|
|||
newOrder = newOrder.concat(preSep);
|
||||
}
|
||||
|
||||
// set the nex indexs
|
||||
for (var i = 0; i < count; ++i)
|
||||
PlacesUtils.bookmarks.setItemIndex(newOrder[i].itemId, i);
|
||||
// set the nex indexes
|
||||
var callback = {
|
||||
runBatched: function() {
|
||||
for (var i = 0; i < newOrder.length; ++i) {
|
||||
PlacesUtils.bookmarks.setItemIndex(newOrder[i].itemId, i);
|
||||
}
|
||||
}
|
||||
};
|
||||
PlacesUtils.bookmarks.runInBatchMode(callback, null);
|
||||
},
|
||||
|
||||
undoTransaction: function PSSFBN_undoTransaction() {
|
||||
for (item in this._oldOrder)
|
||||
PlacesUtils.bookmarks.setItemIndex(item, this._oldOrder[item]);
|
||||
var callback = {
|
||||
_self: this,
|
||||
runBatched: function() {
|
||||
for (item in this._self._oldOrder)
|
||||
PlacesUtils.bookmarks.setItemIndex(item, this._self._oldOrder[item]);
|
||||
}
|
||||
};
|
||||
PlacesUtils.bookmarks.runInBatchMode(callback, null);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ XPCSHELL_TESTS = unit
|
|||
|
||||
ifdef MOZ_MOCHITEST
|
||||
DIRS += browser
|
||||
DIRS += perf
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
|
@ -15,11 +14,12 @@
|
|||
# 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) 2007
|
||||
# Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Shawn Wilsher <me@shawnwilsher.com> (Original Author)
|
||||
#
|
||||
# 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,28 +35,18 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = dom/tests/mochitest/ajax/jquery/src
|
||||
DEPTH = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = browser/components/places/tests/perf
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = \
|
||||
ajax \
|
||||
event \
|
||||
fx \
|
||||
jquery \
|
||||
selector \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
intro.js \
|
||||
outro.js \
|
||||
$(NULL)
|
||||
_CHROME_FILES = \
|
||||
perf_large_delete.xul \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
|
||||
libs:: $(_CHROME_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
|
|
@ -0,0 +1,169 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* This tests that the performance of deleting a large number of bookmarks. See
|
||||
* bug 432706 for more details.
|
||||
*
|
||||
* To run this test, run it like you would a standard chrome test, with the test
|
||||
* path being:
|
||||
* ../chrome/browser/components/places/tests/perf/perf_large_delete.xul
|
||||
*/
|
||||
-->
|
||||
|
||||
<window title="Places Library Performance Test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
function test()
|
||||
{
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
// First, add 250 bookmarks
|
||||
let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
bs.runInBatchMode({
|
||||
runBatched: function(aUserData)
|
||||
{
|
||||
for (let i = 0; i < 250; i++) {
|
||||
let uri = ios.newURI("http://example.com/" + i, null, null);
|
||||
bs.insertBookmark(bs.unfiledBookmarksFolder, uri, bs.DEFAULT_INDEX,
|
||||
"bookmark " + i);
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
|
||||
// Close the window if it's already open
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
let win = wm.getMostRecentWindow("Places:Orgainzier");
|
||||
if (win)
|
||||
win.close();
|
||||
|
||||
|
||||
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Ci.nsIWindowWatcher);
|
||||
ww.registerNotification({
|
||||
observe: function(aSubject, aTopic, aData)
|
||||
{
|
||||
if (aTopic != "domwindowopened")
|
||||
return;
|
||||
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
|
||||
|
||||
// We need to run after the window is loaded, and has run its startup code
|
||||
win.addEventListener("DOMContentLoaded", function() {
|
||||
let tm = Cc["@mozilla.org/thread-manager;1"].
|
||||
getService(Ci.nsIThreadManager);
|
||||
tm.mainThread.dispatch({
|
||||
run: function() doTest(win.QueryInterface(Ci.nsIDOMWindow))
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}, false);
|
||||
|
||||
// and now to unregister ourself as a listener
|
||||
ww.unregisterNotification(this);
|
||||
}
|
||||
});
|
||||
|
||||
function doTest(aWin)
|
||||
{
|
||||
// Select all the bookmarks
|
||||
synthesizeKey("a", {accelKey:true}, aWin);
|
||||
|
||||
// If we can, start shark
|
||||
try {
|
||||
connectShark();
|
||||
startShark();
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
// Delete the bookmarks
|
||||
let start = Date.now();
|
||||
synthesizeKey("VK_BACK_SPACE", {}, aWin);
|
||||
let end = Date.now();
|
||||
|
||||
// Stop shark, if we can
|
||||
try {
|
||||
stopShark();
|
||||
disconnectionShark();
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
// Close the window, and write the results out
|
||||
aWin.close();
|
||||
document.getElementById("test-result").value =
|
||||
"Duration was " + String(end - start) + "ms";
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// And open the window
|
||||
wm.getMostRecentWindow("navigator:browser")
|
||||
.openDialog("chrome://browser/content/places/places.xul",
|
||||
"", "chrome,toolbar=yes,dialog=no,resizable",
|
||||
"UnfiledBookmarks");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
|
@ -50,6 +50,8 @@
|
|||
style="&appManager.style;"
|
||||
persist="screenX screenY">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/applicationManager.js"/>
|
||||
<script type="application/javascript"
|
||||
|
|
|
@ -982,6 +982,10 @@ var gApplicationsPane = {
|
|||
self._rebuildVisibleTypes();
|
||||
self._sortVisibleTypes();
|
||||
self._rebuildView();
|
||||
|
||||
// Notify observers that the UI is now ready
|
||||
Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).
|
||||
notifyObservers(window, "app-handler-pane-loaded", null);
|
||||
}
|
||||
setTimeout(_delayedPaneLoad, 0, this);
|
||||
},
|
||||
|
@ -1598,36 +1602,7 @@ var gApplicationsPane = {
|
|||
* Filter the list when the user enters a filter term into the filter field.
|
||||
*/
|
||||
filter: function() {
|
||||
if (this._filter.value == "") {
|
||||
this.clearFilter();
|
||||
return;
|
||||
}
|
||||
|
||||
this._rebuildView();
|
||||
|
||||
document.getElementById("clearFilter").disabled = false;
|
||||
},
|
||||
|
||||
_filterTimeout: null,
|
||||
|
||||
onFilterInput: function() {
|
||||
if (this._filterTimeout)
|
||||
clearTimeout(this._filterTimeout);
|
||||
|
||||
this._filterTimeout = setTimeout("gApplicationsPane.filter()", 500);
|
||||
},
|
||||
|
||||
onFilterKeyPress: function(aEvent) {
|
||||
if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE)
|
||||
this.clearFilter();
|
||||
},
|
||||
|
||||
clearFilter: function() {
|
||||
this._filter.value = "";
|
||||
this._rebuildView();
|
||||
|
||||
this._filter.focus();
|
||||
document.getElementById("clearFilter").disabled = true;
|
||||
},
|
||||
|
||||
focusFilterBox: function() {
|
||||
|
|
|
@ -110,12 +110,11 @@
|
|||
<key key="&focusSearch2.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
|
||||
</keyset>
|
||||
|
||||
<hbox align="center">
|
||||
<label accesskey="&filter.accesskey;" control="filter">&filter.label;</label>
|
||||
<textbox id="filter" flex="1" oninput="gApplicationsPane.onFilterInput();"
|
||||
onkeypress="gApplicationsPane.onFilterKeyPress(event);"/>
|
||||
<button id="clearFilter" icon="clear" label="&clear.label;" accesskey="&clear.accesskey;"
|
||||
oncommand="gApplicationsPane.clearFilter();" disabled="true"/>
|
||||
<hbox>
|
||||
<textbox id="filter" flex="1"
|
||||
type="search"
|
||||
emptytext="&filter.emptytext;"
|
||||
oncommand="gApplicationsPane.filter();"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
|
|
@ -163,6 +163,7 @@
|
|||
<filefield id="downloadFolder" flex="1"
|
||||
preference="browser.download.folderList"
|
||||
preference-editable="true"
|
||||
aria-labelledby="saveTo"
|
||||
onsyncfrompreference="return gMainPane.displayDownloadDirPref();"
|
||||
onsynctopreference="return gMainPane.getFolderListPref()"/>
|
||||
<button id="chooseFolder" oncommand="gMainPane.chooseFolder();"
|
||||
|
|
|
@ -16,28 +16,40 @@ function test() {
|
|||
getService(Ci.nsIHandlerService);
|
||||
hserv.store(info);
|
||||
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
||||
var observer = {
|
||||
observe: function(win, topic, data) {
|
||||
if (topic != "app-handler-pane-loaded")
|
||||
return;
|
||||
runTest(win);
|
||||
obs.removeObserver(observer, "app-handler-pane-loaded");
|
||||
}
|
||||
};
|
||||
obs.addObserver(observer, "app-handler-pane-loaded", false);
|
||||
|
||||
openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
|
||||
"chrome,titlebar,toolbar,centerscreen,dialog=no", "paneApplications");
|
||||
setTimeout(runTest, 1000);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("Browser:Preferences");
|
||||
ok(win, "Pref window opened");
|
||||
function runTest(win) {
|
||||
var sel = win.document.documentElement.getAttribute("lastSelected");
|
||||
ok(sel == "paneApplications", "Specified pane was opened");
|
||||
|
||||
if (win) {
|
||||
var sel = win.document.documentElement.getAttribute("lastSelected");
|
||||
ok(sel == "paneApplications", "Specified pane was opened");
|
||||
var rbox = win.document.getElementById("handlersView");
|
||||
ok(rbox, "handlersView is present");
|
||||
|
||||
var rbox = win.document.getElementById("handlersView");
|
||||
ok(rbox, "handlersView is present");
|
||||
var items = rbox && rbox.getElementsByTagName("richlistitem");
|
||||
ok(items && items.length > 0, "App handler list populated");
|
||||
|
||||
var items = rbox && rbox.getElementsByTagName("richlistitem");
|
||||
ok(items && items.length > 0, "App handler list populated");
|
||||
|
||||
win.close();
|
||||
var handlerAdded = false;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type == "apppanetest")
|
||||
handlerAdded = true;
|
||||
}
|
||||
ok(handlerAdded, "apppanetest protocol handler was successfully added");
|
||||
|
||||
win.close();
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -228,10 +228,7 @@ SessionStoreService.prototype = {
|
|||
this._initialState.session && this._initialState.session.state &&
|
||||
this._initialState.session.state == STATE_RUNNING_STR;
|
||||
|
||||
// restore the features of the first window from localstore.rdf
|
||||
WINDOW_ATTRIBUTES.forEach(function(aAttr) {
|
||||
delete this._initialState.windows[0][aAttr];
|
||||
}, this);
|
||||
// make sure that at least the first window doesn't have anything hidden
|
||||
delete this._initialState.windows[0].hidden;
|
||||
}
|
||||
catch (ex) { debug("The session file is invalid: " + ex); }
|
||||
|
|
|
@ -222,7 +222,7 @@ static SETTING gSettings[] = {
|
|||
};
|
||||
|
||||
PRBool
|
||||
nsWindowsShellService::IsDefaultBrowserVista(PRBool aStartupCheck, PRBool* aIsDefaultBrowser)
|
||||
nsWindowsShellService::IsDefaultBrowserVista(PRBool* aIsDefaultBrowser)
|
||||
{
|
||||
#if !defined(MOZ_DISABLE_VISTA_SDK_REQUIREMENTS)
|
||||
IApplicationAssociationRegistration* pAAR;
|
||||
|
@ -232,18 +232,12 @@ nsWindowsShellService::IsDefaultBrowserVista(PRBool aStartupCheck, PRBool* aIsDe
|
|||
CLSCTX_INPROC,
|
||||
IID_IApplicationAssociationRegistration,
|
||||
(void**)&pAAR);
|
||||
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
|
||||
APP_REG_NAME,
|
||||
aIsDefaultBrowser);
|
||||
|
||||
// If this is the first browser window, maintain internal state that we've
|
||||
// checked this session (so that subsequent window opens don't show the
|
||||
// default browser dialog).
|
||||
if (aStartupCheck)
|
||||
mCheckedThisSession = PR_TRUE;
|
||||
|
||||
|
||||
pAAR->Release();
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -316,26 +310,29 @@ nsWindowsShellService::IsDefaultBrowser(PRBool aStartupCheck,
|
|||
::ZeroMemory(currValue, sizeof(currValue));
|
||||
HKEY theKey;
|
||||
rv = OpenKeyForReading(HKEY_CLASSES_ROOT, key, &theKey);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DWORD len = sizeof currValue;
|
||||
DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(value).get(),
|
||||
NULL, NULL, (LPBYTE)currValue, &len);
|
||||
// Close the key we opened.
|
||||
::RegCloseKey(theKey);
|
||||
if (REG_FAILED(res) ||
|
||||
!dataLongPath.Equals(currValue, CaseInsensitiveCompare) &&
|
||||
!dataShortPath.Equals(currValue, CaseInsensitiveCompare)) {
|
||||
// Key wasn't set, or was set to something else (something else became the default browser)
|
||||
*aIsDefaultBrowser = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
*aIsDefaultBrowser = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DWORD len = sizeof currValue;
|
||||
DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(value).get(),
|
||||
NULL, NULL, (LPBYTE)currValue, &len);
|
||||
// Close the key we opened.
|
||||
::RegCloseKey(theKey);
|
||||
if (REG_FAILED(res) ||
|
||||
!dataLongPath.Equals(currValue, CaseInsensitiveCompare) &&
|
||||
!dataShortPath.Equals(currValue, CaseInsensitiveCompare)) {
|
||||
// Key wasn't set, or was set to something other than our registry entry
|
||||
*aIsDefaultBrowser = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Only check if Firefox is the default browser on Vista if the previous
|
||||
// checks show that Firefox is the default browser.
|
||||
if (aIsDefaultBrowser)
|
||||
IsDefaultBrowserVista(aStartupCheck, aIsDefaultBrowser);
|
||||
if (*aIsDefaultBrowser)
|
||||
IsDefaultBrowserVista(aIsDefaultBrowser);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -358,8 +355,8 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs
|
|||
rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCAutoString appHelperPath;
|
||||
rv = appHelper->GetNativePath(appHelperPath);
|
||||
nsAutoString appHelperPath;
|
||||
rv = appHelper->GetPath(appHelperPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aForAllUsers) {
|
||||
|
@ -368,11 +365,11 @@ nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUs
|
|||
appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
|
||||
}
|
||||
|
||||
STARTUPINFO si = {sizeof(si), 0};
|
||||
STARTUPINFOW si = {sizeof(si), 0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
BOOL ok = CreateProcess(NULL, (LPSTR)appHelperPath.get(), NULL, NULL,
|
||||
FALSE, 0, NULL, NULL, &si, &pi);
|
||||
BOOL ok = CreateProcessW(NULL, (LPWSTR)appHelperPath.get(), NULL, NULL,
|
||||
FALSE, 0, NULL, NULL, &si, &pi);
|
||||
|
||||
if (!ok)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -766,8 +763,8 @@ nsWindowsShellService::GetUnreadMailCount(PRUint32* aCount)
|
|||
if (REG_SUCCEEDED(res))
|
||||
*aCount = unreadCount;
|
||||
|
||||
// Close the key we opened.
|
||||
::RegCloseKey(accountKey);
|
||||
// Close the key we opened.
|
||||
::RegCloseKey(accountKey);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -57,16 +57,9 @@ public:
|
|||
NS_DECL_NSIWINDOWSSHELLSERVICE
|
||||
|
||||
protected:
|
||||
PRBool IsDefaultBrowserVista(PRBool aStartupCheck, PRBool* aIsDefaultBrowser);
|
||||
PRBool IsDefaultBrowserVista(PRBool* aIsDefaultBrowser);
|
||||
|
||||
PRBool GetMailAccountKey(HKEY* aResult);
|
||||
void SetRegKey(const nsString& aKeyName,
|
||||
const nsString& aValueName,
|
||||
const nsString& aValue, PRBool aHKLMOnly);
|
||||
|
||||
DWORD DeleteRegKey(HKEY baseKey, const nsString& keyName);
|
||||
DWORD DeleteRegKeyDefaultValue(HKEY baseKey,
|
||||
const nsString& keyName);
|
||||
|
||||
private:
|
||||
PRBool mCheckedThisSession;
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.1a1pre
|
||||
3.1a2pre
|
||||
|
|
|
@ -34,11 +34,14 @@ bin/libmozjs.so
|
|||
bin/libplc4.so
|
||||
bin/libplds4.so
|
||||
bin/libxpcom.so
|
||||
bin/libxpcom_core.so
|
||||
bin/libnspr4.so
|
||||
#ifdef MOZ_ENABLE_LIBXUL
|
||||
bin/libxul.so
|
||||
#else
|
||||
bin/libxpcom_core.so
|
||||
bin/components/libxpinstall.so
|
||||
bin/components/libjar50.so
|
||||
#endif
|
||||
|
||||
[browser]
|
||||
; [Base Browser Files]
|
||||
|
@ -111,14 +114,14 @@ bin/components/filepicker.xpt
|
|||
bin/components/find.xpt
|
||||
bin/components/fuel.xpt
|
||||
bin/components/gfx.xpt
|
||||
bin/components/helperAppDlg.xpt
|
||||
bin/components/htmlparser.xpt
|
||||
bin/components/imglib2.xpt
|
||||
; bin/components/imgicon.xpt
|
||||
bin/components/intl.xpt
|
||||
bin/components/jar.xpt
|
||||
bin/components/jsconsole.xpt
|
||||
#ifndef MOZ_ENABLE_LIBXUL
|
||||
bin/components/libjsd.so
|
||||
#endif
|
||||
bin/components/libimgicon.so
|
||||
bin/components/jsdservice.xpt
|
||||
bin/components/layout_base.xpt
|
||||
|
@ -140,7 +143,6 @@ bin/components/necko_dns.xpt
|
|||
bin/components/necko_file.xpt
|
||||
bin/components/necko_ftp.xpt
|
||||
bin/components/necko_http.xpt
|
||||
bin/components/necko_jar.xpt
|
||||
bin/components/necko_res.xpt
|
||||
bin/components/necko_socket.xpt
|
||||
bin/components/necko_strconv.xpt
|
||||
|
@ -152,13 +154,11 @@ bin/components/places.xpt
|
|||
bin/components/plugin.xpt
|
||||
bin/components/prefetch.xpt
|
||||
bin/components/pref.xpt
|
||||
bin/components/progressDlg.xpt
|
||||
bin/components/proxyObjInst.xpt
|
||||
bin/components/toolkitremote.xpt
|
||||
bin/components/rdf.xpt
|
||||
bin/components/satchel.xpt
|
||||
bin/components/saxparser.xpt
|
||||
bin/components/search.xpt
|
||||
bin/components/shistory.xpt
|
||||
bin/components/spellchecker.xpt
|
||||
bin/components/storage.xpt
|
||||
|
@ -172,7 +172,6 @@ bin/components/uriloader.xpt
|
|||
bin/components/webBrowser_core.xpt
|
||||
bin/components/webbrowserpersist.xpt
|
||||
bin/components/webshell_idls.xpt
|
||||
bin/components/websrvcs.xpt
|
||||
bin/components/widget.xpt
|
||||
bin/components/windowds.xpt
|
||||
bin/components/windowwatcher.xpt
|
||||
|
@ -185,7 +184,6 @@ bin/components/xpcom_threads.xpt
|
|||
bin/components/xpcom_xpti.xpt
|
||||
bin/components/xpconnect.xpt
|
||||
bin/components/xpinstall.xpt
|
||||
bin/components/xremoteservice.xpt
|
||||
bin/components/xulapp.xpt
|
||||
bin/components/xuldoc.xpt
|
||||
bin/components/xultmpl.xpt
|
||||
|
@ -211,14 +209,10 @@ bin/components/nsLoginManagerPrompter.js
|
|||
bin/components/storage-Legacy.js
|
||||
bin/components/jsconsole-clhandler.js
|
||||
bin/components/nsTryToClose.js
|
||||
bin/components/nsDictionary.js
|
||||
bin/components/nsFilePicker.js
|
||||
bin/components/nsHelperAppDlg.js
|
||||
bin/components/nsDownloadManagerUI.js
|
||||
bin/components/nsInterfaceInfoToIDL.js
|
||||
; bin/components/nsProgressDialog.js not needed for firefox
|
||||
bin/components/nsProxyAutoConfig.js
|
||||
; bin/components/nsResetPref.js not needed for firefox
|
||||
bin/components/nsSidebar.js
|
||||
bin/components/nsExtensionManager.js
|
||||
bin/components/nsBlocklistService.js
|
||||
|
@ -253,12 +247,8 @@ bin/components/nsUrlClassifierListManager.js
|
|||
bin/components/nsUrlClassifierLib.js
|
||||
bin/components/url-classifier.xpt
|
||||
|
||||
; Kerberos NegotiateAuth
|
||||
bin/components/libauth.so
|
||||
|
||||
; GNOME hooks
|
||||
bin/components/libmozgnome.so
|
||||
bin/components/mozgnome.xpt
|
||||
|
||||
; [Browser Chrome Files]
|
||||
bin/chrome/browser.jar
|
||||
|
@ -299,7 +289,6 @@ bin/res/ua.css
|
|||
bin/res/html.css
|
||||
bin/res/quirk.css
|
||||
bin/res/forms.css
|
||||
bin/res/platform-forms.css
|
||||
bin/res/EditorOverride.css
|
||||
bin/res/contenteditable.css
|
||||
bin/res/designmode.css
|
||||
|
@ -357,7 +346,6 @@ bin/libfreebl3.chk
|
|||
bin/libfreebl3.so
|
||||
bin/libssl3.so
|
||||
bin/libnssdbm3.so
|
||||
bin/chrome/pipnss.jar
|
||||
bin/chrome/pippki.jar
|
||||
bin/chrome/pippki.manifest
|
||||
|
||||
|
@ -383,14 +371,3 @@ bin/Throbber-small.gif
|
|||
; [Extensions]
|
||||
;
|
||||
bin/components/libnkgnomevfs.so
|
||||
bin/components/libauth.so
|
||||
|
||||
; [Additional Developer Tools]
|
||||
[adt]
|
||||
bin/extensions/inspector@mozilla.org/install.rdf
|
||||
bin/extensions/inspector@mozilla.org/components/inspector-cmdline.js
|
||||
bin/extensions/inspector@mozilla.org/chrome.manifest
|
||||
bin/extensions/inspector@mozilla.org/chrome/inspector.jar
|
||||
bin/extensions/inspector@mozilla.org/defaults/preferences/inspector.js
|
||||
bin/extensions/inspector@mozilla.org/platform/Linux/chrome/icons/default/winInspectorMain.xpm
|
||||
bin/extensions/inspector@mozilla.org/platform/Linux/chrome/icons/default/winInspectorMain16.xpm
|
||||
|
|
|
@ -48,6 +48,8 @@ SetDatablockOptimize on
|
|||
SetCompress off
|
||||
CRCCheck on
|
||||
|
||||
RequestExecutionLevel user
|
||||
|
||||
!addplugindir ./
|
||||
|
||||
; empty files - except for the comment line - for generating custom pages.
|
||||
|
@ -70,21 +72,11 @@ Var AddDesktopSC
|
|||
; The following includes are provided by NSIS.
|
||||
!include FileFunc.nsh
|
||||
!include LogicLib.nsh
|
||||
!include MUI.nsh
|
||||
!include TextFunc.nsh
|
||||
!include WinMessages.nsh
|
||||
!include WinVer.nsh
|
||||
!include WordFunc.nsh
|
||||
!include MUI.nsh
|
||||
|
||||
; WinVer.nsh was added in the same release that RequestExecutionLevel so check
|
||||
; if ___WINVER__NSH___ is defined to determine if RequestExecutionLevel is
|
||||
; available.
|
||||
!include /NONFATAL WinVer.nsh
|
||||
!ifdef ___WINVER__NSH___
|
||||
RequestExecutionLevel user
|
||||
!else
|
||||
!warning "Installer will be created without Vista compatibility.$\n \
|
||||
Upgrade your NSIS installation to at least version 2.22 to resolve."
|
||||
!endif
|
||||
|
||||
!insertmacro GetOptions
|
||||
!insertmacro GetParameters
|
||||
|
@ -105,6 +97,7 @@ Var AddDesktopSC
|
|||
!include version.nsh
|
||||
|
||||
VIAddVersionKey "FileDescription" "${BrandShortName} Installer"
|
||||
VIAddVersionKey "OriginalFilename" "setup.exe"
|
||||
|
||||
; Must be inserted before other macros that use logging
|
||||
!insertmacro _LoggingCommon
|
||||
|
@ -356,6 +349,7 @@ Section "-Application" APP_IDX
|
|||
SetShellVarContext current ; Set SHCTX to HKCU
|
||||
${RegCleanMain} "Software\Mozilla"
|
||||
${RegCleanUninstall}
|
||||
${UpdateProtocolHandlers}
|
||||
|
||||
ClearErrors
|
||||
WriteRegStr HKLM "Software\Mozilla\InstallerTest" "InstallerTest" "Test"
|
||||
|
@ -367,6 +361,7 @@ Section "-Application" APP_IDX
|
|||
StrCpy $TmpVal "HKLM" ; used primarily for logging
|
||||
${RegCleanMain} "Software\Mozilla"
|
||||
${RegCleanUninstall}
|
||||
${UpdateProtocolHandlers}
|
||||
|
||||
ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
|
||||
${If} "$0" != "${GREVersion}"
|
||||
|
@ -392,7 +387,6 @@ Section "-Application" APP_IDX
|
|||
${WriteRegDWORD2} $TmpVal "$0" "Create Start Menu Shortcut" $AddStartMenuSC 0
|
||||
|
||||
${FixClassKeys}
|
||||
${UpdateProtocolHandlers}
|
||||
|
||||
; On install always add the FirefoxHTML and FirefoxURL keys.
|
||||
; An empty string is used for the 5th param because FirefoxHTML is not a
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче