зеркало из https://github.com/mozilla/pjs.git
Bug 454647 - fix test_bug368835.xul tests so that TreeInvalidation returns consistent values for event data, r=marcoz, davidb
--HG-- rename : accessible/tests/mochitest/test_bug368835.xul => accessible/tests/mochitest/test_events_tree.xul
This commit is contained in:
Родитель
cd7ae31dc7
Коммит
d8177b09b1
|
@ -65,11 +65,11 @@ _TEST_FILES =\
|
|||
test_aria_role_article.html \
|
||||
test_aria_role_equation.html \
|
||||
test_aria_token_attrs.html \
|
||||
$(warning test_bug368835.xul temporarily disabled) \
|
||||
test_bug420863.html \
|
||||
test_cssattrs.html \
|
||||
test_events_caretmove.html \
|
||||
test_events_mutation.html \
|
||||
test_events_tree.xul \
|
||||
test_groupattrs.xul \
|
||||
test_groupattrs.html \
|
||||
test_name_markup.html \
|
||||
|
@ -111,6 +111,7 @@ _TEST_FILES =\
|
|||
test_textboxes.html \
|
||||
test_textboxes.xul \
|
||||
testTextboxes.js \
|
||||
treeview.js \
|
||||
test_bug429285.html \
|
||||
test_bug434464.html \
|
||||
z_states_frame.html \
|
||||
|
|
|
@ -37,6 +37,8 @@ const nsIAccessibleValue = Components.interfaces.nsIAccessibleValue;
|
|||
const nsIObserverService = Components.interfaces.nsIObserverService;
|
||||
|
||||
const nsIDOMDocument = Components.interfaces.nsIDOMDocument;
|
||||
const nsIDOMEvent = Components.interfaces.nsIDOMEvent;
|
||||
const nsIDOMHTMLDocument = Components.interfaces.nsIDOMHTMLDocument;
|
||||
const nsIDOMNode = Components.interfaces.nsIDOMNode;
|
||||
const nsIDOMWindow = Components.interfaces.nsIDOMWindow;
|
||||
|
||||
|
@ -163,6 +165,17 @@ function getNode(aNodeOrID)
|
|||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants indicates getAccessible doesn't fail if there is no accessible.
|
||||
*/
|
||||
const DONOTFAIL_IF_NO_ACC = 1;
|
||||
|
||||
/**
|
||||
* Constants indicates getAccessible won't fail if accessible doesn't implement
|
||||
* the requested interfaces.
|
||||
*/
|
||||
const DONOTFAIL_IF_NO_INTERFACE = 2;
|
||||
|
||||
/**
|
||||
* Return accessible for the given identifier (may be ID attribute or DOM
|
||||
* element or accessible object).
|
||||
|
@ -173,10 +186,10 @@ function getNode(aNodeOrID)
|
|||
* to query it/them from obtained accessible
|
||||
* @param aElmObj [out, optional] object to store DOM element which
|
||||
* accessible is obtained for
|
||||
* @param aDoNotFailIfNoAcc [in, optional] no error if the given identifier is
|
||||
* not accessible
|
||||
* @param aDoNotFailIf [in, optional] no error for special cases (see
|
||||
* constants above)
|
||||
*/
|
||||
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
|
||||
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf)
|
||||
{
|
||||
if (!aAccOrElmOrID)
|
||||
return;
|
||||
|
@ -209,7 +222,7 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
|
|||
}
|
||||
|
||||
if (!acc) {
|
||||
if (!aDoNotFailIfNoAcc)
|
||||
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC))
|
||||
ok(false, "Can't get accessible for " + aAccOrElmOrID);
|
||||
|
||||
return null;
|
||||
|
@ -224,7 +237,9 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
|
|||
try {
|
||||
acc.QueryInterface(aInterfaces[index]);
|
||||
} catch (e) {
|
||||
ok(false, "Can't query " + aInterfaces[index] + " for " + aID);
|
||||
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE))
|
||||
ok(false, "Can't query " + aInterfaces[index] + " for " + aID);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +261,8 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
|
|||
*/
|
||||
function isAccessible(aAccOrElmOrID)
|
||||
{
|
||||
return getAccessible(aAccOrElmOrID, null, null, true) ? true : false;
|
||||
return getAccessible(aAccOrElmOrID, null, null, DONOTFAIL_IF_NO_ACC) ?
|
||||
true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -315,7 +331,8 @@ function prettyName(aIdentifier)
|
|||
{
|
||||
if (aIdentifier instanceof nsIAccessible) {
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessNode]);
|
||||
return getNodePrettyName(acc.DOMNode);
|
||||
return getNodePrettyName(acc.DOMNode) + ", role: " +
|
||||
roleToString(acc.finalRole);
|
||||
}
|
||||
|
||||
if (aIdentifier instanceof nsIDOMNode)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
|
||||
const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
|
||||
const EVENT_DOM_DESTROY = nsIAccessibleEvent.EVENT_DOM_DESTROY;
|
||||
const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
|
||||
const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// General
|
||||
|
@ -91,24 +92,35 @@ function unregisterA11yEventListener(aEventType, aEventHandler)
|
|||
* // Generates accessible event or event sequence.
|
||||
* invoke: function(){},
|
||||
*
|
||||
* // Invoker's check of handled event for correctness [optional].
|
||||
* // [optional] Invoker's check of handled event for correctness.
|
||||
* check: function(aEvent){},
|
||||
*
|
||||
* // Is called when event of registered type is handled.
|
||||
* // [optional] Is called when event of registered type is handled.
|
||||
* debugCheck: function(aEvent){},
|
||||
*
|
||||
* // DOM node event is generated for (the case when invoker generates
|
||||
* // single event, see 'eventSeq' property).
|
||||
* DOMNode getter() {},
|
||||
* // [ignored if 'eventSeq' is defined] DOM node event is generated for
|
||||
* // (used in the case when invoker expects single event).
|
||||
* DOMNode getter: function() {},
|
||||
*
|
||||
* // Array of items defining events expected (or not expected, see
|
||||
* // 'doNotExpectEvents' property) on invoker's action. Every item is array
|
||||
* // with two elements, first element is event type, second element is
|
||||
* // event target (DOM node).
|
||||
* // 'doNotExpectEvents' property) on invoker's action.
|
||||
* //
|
||||
* // Every array item should be either
|
||||
* // 1) an array consisted from two elements, the first element is DOM or
|
||||
* // a11y event type, second element is event target (DOM node or
|
||||
* // accessible).
|
||||
* //
|
||||
* // 2) object (invoker's checker object) like
|
||||
* // var checker = {
|
||||
* // type getter: function() {}, // DOM or a11y event type
|
||||
* // target getter: function() {}, // DOM node or accessible
|
||||
* // check: function(aEvent) {},
|
||||
* // getID: function() {}
|
||||
* // };
|
||||
* eventSeq getter() {},
|
||||
*
|
||||
* // Boolean indicates if events specified by 'eventSeq' property shouldn't
|
||||
* // be triggerd by invoker.
|
||||
* // [optional, used together with 'eventSeq'] Boolean indicates if events
|
||||
* // specified by 'eventSeq' property shouldn't be triggerd by invoker.
|
||||
* doNotExpectEvents getter() {},
|
||||
*
|
||||
* // The ID of invoker.
|
||||
|
@ -156,17 +168,16 @@ function eventQueue(aEventType)
|
|||
|
||||
var invoker = this.getInvoker();
|
||||
if (invoker) {
|
||||
var id = invoker.getID();
|
||||
|
||||
if (invoker.wasCaught) {
|
||||
for (var jdx = 0; jdx < invoker.wasCaught.length; jdx++) {
|
||||
var seq = this.mEventSeq;
|
||||
var type = seq[jdx][0];
|
||||
var typeStr = gAccRetrieval.getStringEventType(type);
|
||||
for (var idx = 0; idx < invoker.wasCaught.length; idx++) {
|
||||
var id = this.getEventID(idx);
|
||||
var type = this.getEventType(idx);
|
||||
var typeStr = (typeof type == "string") ?
|
||||
type : gAccRetrieval.getStringEventType(type);
|
||||
|
||||
var msg = "test with ID = '" + id + "' failed. ";
|
||||
if (invoker.doNotExpectEvents) {
|
||||
var wasCaught = invoker.wasCaught[jdx];
|
||||
var wasCaught = invoker.wasCaught[idx];
|
||||
if (!testFailed)
|
||||
testFailed = wasCaught;
|
||||
|
||||
|
@ -174,7 +185,7 @@ function eventQueue(aEventType)
|
|||
msg + "There is unexpected " + typeStr + " event.");
|
||||
|
||||
} else {
|
||||
var wasCaught = invoker.wasCaught[jdx];
|
||||
var wasCaught = invoker.wasCaught[idx];
|
||||
if (!testFailed)
|
||||
testFailed = !wasCaught;
|
||||
|
||||
|
@ -184,8 +195,11 @@ function eventQueue(aEventType)
|
|||
}
|
||||
} else {
|
||||
testFailed = true;
|
||||
ok(false,
|
||||
"test with ID = '" + id + "' failed. No events were registered.");
|
||||
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||
var id = this.getEventID(idx);
|
||||
ok(false,
|
||||
"test with ID = '" + id + "' failed. No events were registered.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,35 +251,28 @@ function eventQueue(aEventType)
|
|||
// Search through event sequence to ensure it doesn't contain handled
|
||||
// event.
|
||||
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||
if (aEvent.eventType == this.mEventSeq[idx][0] &&
|
||||
aEvent.DOMNode == this.mEventSeq[idx][1]) {
|
||||
if (this.compareEvents(idx, aEvent))
|
||||
invoker.wasCaught[idx] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We wait for events in order specified by eventSeq variable.
|
||||
var idx = this.mEventSeqIdx + 1;
|
||||
|
||||
if (gA11yEventDumpID) { // debug stuff
|
||||
var eventType = this.mEventSeq[idx][0];
|
||||
var target = this.mEventSeq[idx][1];
|
||||
|
||||
var info = "Event queue processing. Event type: ";
|
||||
info += gAccRetrieval.getStringEventType(eventType) + ". Target: ";
|
||||
info += (target.localName ? target.localName : target);
|
||||
if (target.nodeType == nsIDOMNode.ELEMENT_NODE &&
|
||||
target.hasAttribute("id"))
|
||||
info += " '" + target.getAttribute("id") + "'";
|
||||
var currType = this.getEventType(idx);
|
||||
var currTarget = this.getEventTarget(idx);
|
||||
|
||||
var info = "Event queue processing. Expected event type: ";
|
||||
info += (typeof currType == "string") ?
|
||||
currType : eventTypeToString(currType);
|
||||
info += ". Target: " + prettyName(currTarget);
|
||||
|
||||
dumpInfoToDOM(info);
|
||||
}
|
||||
|
||||
if (aEvent.eventType == this.mEventSeq[idx][0] &&
|
||||
aEvent.DOMNode == this.mEventSeq[idx][1]) {
|
||||
|
||||
if ("check" in invoker)
|
||||
invoker.check(aEvent);
|
||||
|
||||
if (this.compareEvents(idx, aEvent)) {
|
||||
this.checkEvent(idx, aEvent);
|
||||
invoker.wasCaught[idx] = true;
|
||||
|
||||
if (idx == this.mEventSeq.length - 1) {
|
||||
|
@ -300,21 +307,93 @@ function eventQueue(aEventType)
|
|||
if (this.mEventSeq) {
|
||||
aInvoker.wasCaught = new Array(this.mEventSeq.length);
|
||||
|
||||
for (var idx = 0; idx < this.mEventSeq.length; idx++)
|
||||
addA11yEventListener(this.mEventSeq[idx][0], this);
|
||||
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||
var eventType = this.getEventType(idx);
|
||||
if (typeof eventType == "string") // DOM event
|
||||
document.addEventListener(eventType, this, true);
|
||||
else // A11y event
|
||||
addA11yEventListener(eventType, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.clearEventHandler = function eventQueue_clearEventHandler()
|
||||
{
|
||||
if (this.mEventSeq) {
|
||||
for (var idx = 0; idx < this.mEventSeq.length; idx++)
|
||||
removeA11yEventListener(this.mEventSeq[idx][0], this);
|
||||
|
||||
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||
var eventType = this.getEventType(idx);
|
||||
if (typeof eventType == "string") // DOM event
|
||||
document.removeEventListener(eventType, this, true);
|
||||
else // A11y event
|
||||
removeA11yEventListener(eventType, this);
|
||||
}
|
||||
|
||||
this.mEventSeq = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.getEventType = function eventQueue_getEventType(aIdx)
|
||||
{
|
||||
var eventItem = this.mEventSeq[aIdx];
|
||||
if ("type" in eventItem)
|
||||
return eventItem.type;
|
||||
|
||||
return eventItem[0];
|
||||
}
|
||||
|
||||
this.getEventTarget = function eventQueue_getEventTarget(aIdx)
|
||||
{
|
||||
var eventItem = this.mEventSeq[aIdx];
|
||||
if ("target" in eventItem)
|
||||
return eventItem.target;
|
||||
|
||||
return eventItem[1];
|
||||
}
|
||||
|
||||
this.compareEvents = function eventQueue_compareEvents(aIdx, aEvent)
|
||||
{
|
||||
var eventType1 = this.getEventType(aIdx);
|
||||
|
||||
var eventType2 = (aEvent instanceof nsIDOMEvent) ?
|
||||
aEvent.type : aEvent.eventType;
|
||||
|
||||
if (eventType1 != eventType2)
|
||||
return false;
|
||||
|
||||
var target1 = this.getEventTarget(aIdx);
|
||||
if (target1 instanceof nsIAccessible) {
|
||||
var target2 = (aEvent instanceof nsIDOMEvent) ?
|
||||
getAccessible(aEvent.target) : aEvent.accessible;
|
||||
|
||||
return target1 == target2;
|
||||
}
|
||||
|
||||
var target2 = (aEvent instanceof nsIDOMEvent) ?
|
||||
aEvent.target : aEvent.DOMNode;
|
||||
return target1 == target2;
|
||||
}
|
||||
|
||||
this.checkEvent = function eventQueue_checkEvent(aIdx, aEvent)
|
||||
{
|
||||
var eventItem = this.mEventSeq[aIdx];
|
||||
if ("check" in eventItem)
|
||||
eventItem.check(aEvent);
|
||||
|
||||
var invoker = this.getInvoker();
|
||||
if ("check" in invoker)
|
||||
invoker.check(aEvent);
|
||||
}
|
||||
|
||||
this.getEventID = function eventQueue_getEventID(aIdx)
|
||||
{
|
||||
var eventItem = this.mEventSeq[aIdx];
|
||||
if ("getID" in eventItem)
|
||||
return eventItem.getID();
|
||||
|
||||
var invoker = this.getInvoker();
|
||||
return invoker.getID();
|
||||
}
|
||||
|
||||
this.mDefEventType = aEventType;
|
||||
|
||||
this.mInvokers = new Array();
|
||||
|
@ -356,13 +435,9 @@ var gA11yEventObserver =
|
|||
parent = parent.parentNode;
|
||||
|
||||
if (parent != dumpElm) {
|
||||
var type = gAccRetrieval.getStringEventType(event.eventType);
|
||||
var info = "Event type: " + type + ". Target: ";
|
||||
info += (target.localName ? target.localName : target);
|
||||
|
||||
if (target.nodeType == nsIDOMNode.ELEMENT_NODE &&
|
||||
target.hasAttribute("id"))
|
||||
info += " '" + target.getAttribute("id") + "'";
|
||||
var type = eventTypeToString(event.eventType);
|
||||
var info = "Event type: " + type;
|
||||
info += ". Target: " + prettyName(event.accessible);
|
||||
|
||||
if (listenersArray)
|
||||
info += ". Listeners count: " + listenersArray.length;
|
||||
|
@ -428,7 +503,11 @@ function dumpInfoToDOM(aInfo)
|
|||
return;
|
||||
|
||||
var dumpElm = document.getElementById(gA11yEventDumpID);
|
||||
var div = document.createElement("div");
|
||||
div.textContent = aInfo;
|
||||
dumpElm.appendChild(div);
|
||||
|
||||
var containerTagName = document instanceof nsIDOMHTMLDocument ?
|
||||
"div" : "description";
|
||||
var container = document.createElement(containerTagName);
|
||||
|
||||
container.textContent = aInfo;
|
||||
dumpElm.appendChild(container);
|
||||
}
|
||||
|
|
|
@ -1,325 +0,0 @@
|
|||
<?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"?>
|
||||
|
||||
<!--
|
||||
Bug 368835 - fire TreeViewChanged/TreeRowCountChanged events.
|
||||
Bug 308564 - no accessibility events when data in a tree row changes.
|
||||
-->
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Mozilla Bug 368835">
|
||||
|
||||
<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[
|
||||
function inTreeView() { }
|
||||
|
||||
inTreeView.prototype =
|
||||
{
|
||||
mRowCount: 0,
|
||||
mTree: null,
|
||||
mData: {},
|
||||
|
||||
get rowCount() { return this.mRowCount; },
|
||||
setTree: function(aTree) { this.mTree = aTree; },
|
||||
getCellText: function(aRow, aCol)
|
||||
{
|
||||
var key = String(aRow) + aCol.id;
|
||||
if (key in this.mData)
|
||||
return this.mData[key];
|
||||
|
||||
return "hello";
|
||||
},
|
||||
getRowProperties: function(aIndex, aProperties) {},
|
||||
getCellProperties: function(aIndex, aCol, aProperties) {},
|
||||
getColumnProperties: function(aCol, aProperties) {},
|
||||
getParentIndex: function(aRowIndex) { },
|
||||
hasNextSibling: function(aRowIndex, aAfterIndex) { },
|
||||
getLevel: function(aIndex) {},
|
||||
getImageSrc: function(aRow, aCol) {},
|
||||
getProgressMode: function(aRow, aCol) {},
|
||||
getCellValue: function(aRow, aCol) {},
|
||||
isContainer: function(aIndex) {},
|
||||
isContainerOpen: function(aIndex) {},
|
||||
isContainerEmpty: function(aIndex) {},
|
||||
isSeparator: function(aIndex) {},
|
||||
isSorted: function() {},
|
||||
toggleOpenState: function(aIndex) {},
|
||||
selectionChanged: function() {},
|
||||
cycleHeader: function(aCol) {},
|
||||
cycleCell: function(aRow, aCol) {},
|
||||
isEditable: function(aRow, aCol) {},
|
||||
isSelectable: function(aRow, aCol) {},
|
||||
setCellValue: function(aRow, aCol, aValue) {},
|
||||
setCellText: function(aRow, aCol, aValue) { },
|
||||
performAction: function(aAction) {},
|
||||
performActionOnRow: function(aAction, aRow) {},
|
||||
performActionOnCell: function(aAction, aRow, aCol) {}
|
||||
};
|
||||
|
||||
var gTreeViewChangedCount = 0;
|
||||
var gTreeViewChanged = false;
|
||||
function TreeViewChangedHandler(aEvent)
|
||||
{
|
||||
gTreeViewChangedCount++;
|
||||
|
||||
// We get two systems 'treeViewChanged' event when tree is initialized
|
||||
// The third one is our when we change the tree view by
|
||||
// nsITreeBoxObject::setTree.
|
||||
if (gTreeViewChangedCount == 3) {
|
||||
gTreeViewChanged = true;
|
||||
|
||||
// Tree view has been setted. We can continue tests for the tree.
|
||||
window.setTimeout(doTest2, 500);
|
||||
}
|
||||
}
|
||||
|
||||
var gTreeRowCountChanged = false;
|
||||
function TreeRowCountChangedHandler(aEvent)
|
||||
{
|
||||
gTreeRowCountChanged = true;
|
||||
|
||||
var index = aEvent.getData("index");
|
||||
is(index, 0, "Wrong 'index' data of 'treeRowCountChanged' event.");
|
||||
|
||||
var count = aEvent.getData("count");
|
||||
is(count, 1, "Wrong 'count' data of 'treeRowCountChanged' event.");
|
||||
}
|
||||
|
||||
var gTreeColumnInvalidated = false;
|
||||
var gTreeRowInvalidated = false;
|
||||
|
||||
var gTreeInvalidatedCount = 0;
|
||||
function TreeInvalidatedHandler(aEvent)
|
||||
{
|
||||
gTreeInvalidatedCount++;
|
||||
|
||||
switch (gTreeInvalidatedCount) {
|
||||
case 1:
|
||||
TreeInvalidatedHandlerHelper(aEvent, 0, 5, null, null,
|
||||
"nsITreeBoxObject::rowCountChanged");
|
||||
break;
|
||||
case 2:
|
||||
// XXX see bug 454647 TreeInvalidatedHandlerHelper(aEvent, null, null, 0, 0,
|
||||
// "nsITreeBoxObject::invalidateColumn");
|
||||
gTreeColumnInvalidated = true;
|
||||
break;
|
||||
case 3:
|
||||
// XXX see bug 454647 TreeInvalidatedHandlerHelper(aEvent, 1, 1, null, null,
|
||||
// "nsITreeBoxObject::invalidateRow");
|
||||
gTreeRowInvalidated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function TreeInvalidatedHandlerHelper(aEvent, aStartRow, aEndRow,
|
||||
aStartCol, aEndCol, aCauseMsg)
|
||||
{
|
||||
var startRow = aEvent.getData("startrow");
|
||||
is(startRow, aStartRow,
|
||||
"Wrong 'startrow' of 'treeInvalidated' event on " + aCauseMsg);
|
||||
|
||||
var endRow = aEvent.getData("endrow");
|
||||
is(endRow, aEndRow,
|
||||
"Wrong 'endrow' of 'treeInvalidated' event on " + aCauseMsg);
|
||||
|
||||
var startCol = aEvent.getData("startcolumn");
|
||||
is(startCol, aStartCol,
|
||||
"Wrong 'startcolumn' of 'treeInvalidated' event on " + aCauseMsg);
|
||||
|
||||
var endCol = aEvent.getData("endcolumn");
|
||||
is(endCol, aEndCol,
|
||||
"Wrong 'endcolumn' of 'treeInvalidated' event on " + aCauseMsg);
|
||||
}
|
||||
|
||||
var gNameChangedOnTreeRowInvalidated = false;
|
||||
var gNameChangedOnTreeColumnInvalidated = false;
|
||||
|
||||
var gA11yEventObserver = {
|
||||
observe: function observe(aSubject, aTopic, aData)
|
||||
{
|
||||
if (aTopic != "accessible-event")
|
||||
return;
|
||||
|
||||
const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
|
||||
var event = aSubject.QueryInterface(nsIAccessibleEvent);
|
||||
|
||||
if (event.eventType != nsIAccessibleEvent.EVENT_NAME_CHANGE)
|
||||
return;
|
||||
|
||||
++this.mCount;
|
||||
|
||||
// We should get first six 'name changed' events on
|
||||
// nsITreeBoxObject::invalidateColumn when we update 0th column
|
||||
// containing six rows.
|
||||
if (this.mCount == 6) {
|
||||
gNameChangedOnTreeColumnInvalidated = true;
|
||||
|
||||
// Make sure 'name change' events have been fired on
|
||||
// InvalidateColumn() before continue the test.
|
||||
window.setTimeout(doTest3, 0);
|
||||
}
|
||||
else if (this.mCount == 7)
|
||||
gNameChangedOnTreeRowInvalidated = true;
|
||||
},
|
||||
|
||||
mCount: 0
|
||||
};
|
||||
|
||||
function CheckEvents()
|
||||
{
|
||||
// If these fail then it doesn't mean actually events are not fired,
|
||||
// possibly setTimeout was executed earlier than events have been fired.
|
||||
|
||||
// nsITreeBoxObject::view
|
||||
ok(gTreeViewChanged,
|
||||
"TreeViewChanged event should have been fired.");
|
||||
|
||||
// nsITreeBoxObject::rowCountChanged
|
||||
ok(gTreeRowCountChanged,
|
||||
"TreeRowCountChanged event should have been fired.");
|
||||
|
||||
// nsITreeBoxObject::invalidateColumn
|
||||
ok(gTreeColumnInvalidated,
|
||||
"TreeInvalidated event should have been fired for InvalidateColumn().");
|
||||
ok(gNameChangedOnTreeColumnInvalidated,
|
||||
"Wrong NameChanged events number on tree column invalidation.");
|
||||
|
||||
// nsITreeBoxObject::invalidateRow
|
||||
ok(gTreeRowInvalidated,
|
||||
"TreeInvalidated event should have been fired for InvalidateRow().");
|
||||
ok(gNameChangedOnTreeRowInvalidated,
|
||||
"Wrong NameChanged events number on tree row invalidation.");
|
||||
|
||||
// Remove DOM event listeners
|
||||
document.removeEventListener("TreeViewChanged",
|
||||
TreeViewChangedHandler, true);
|
||||
|
||||
document.removeEventListener("TreeRowCountChanged",
|
||||
TreeRowCountChangedHandler, true);
|
||||
|
||||
document.removeEventListener("TreeInvalidated",
|
||||
TreeInvalidatedHandler, true);
|
||||
|
||||
// Remove a11y events listener
|
||||
gObserverService.removeObserver(gA11yEventObserver, "accessible-event");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
var gAccService = null;
|
||||
var gObserverService = null;
|
||||
|
||||
var gTree = null;
|
||||
var gTreeBox = null;
|
||||
var gTreeView = null;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
// Activate accessibility, otherwise events aren't fired.
|
||||
gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(Components.interfaces.nsIAccessibleRetrieval);
|
||||
|
||||
// Add accessibility event listeners
|
||||
gObserverService = Components.classes["@mozilla.org/observer-service;1"].
|
||||
getService(Components.interfaces.nsIObserverService);
|
||||
gObserverService.addObserver(gA11yEventObserver, "accessible-event",
|
||||
false);
|
||||
// Add DOM event listeners
|
||||
document.addEventListener("TreeViewChanged",
|
||||
TreeViewChangedHandler, true);
|
||||
document.addEventListener("TreeRowCountChanged",
|
||||
TreeRowCountChangedHandler, true);
|
||||
document.addEventListener("TreeInvalidated",
|
||||
TreeInvalidatedHandler, true);
|
||||
|
||||
// Initialize the tree
|
||||
gTree = document.getElementById("tree");
|
||||
gTreeBox = gTree.treeBoxObject;
|
||||
|
||||
gView = new inTreeView();
|
||||
gView.mRowCount = 5;
|
||||
|
||||
// Fire 'TreeViewChanged' event
|
||||
gTreeBox.view = gView;
|
||||
|
||||
// Fire 'TreeRowCountChanged' changed
|
||||
++gView.mRowCount;
|
||||
gTreeBox.rowCountChanged(0, 1);
|
||||
|
||||
// Wait for events.
|
||||
window.setTimeout(CheckEvents, 1000);
|
||||
}
|
||||
|
||||
function doTest2()
|
||||
{
|
||||
// Make sure accessibles for the tree is created because it makes
|
||||
// sure accessible events will be fired.
|
||||
var treeAcc = gAccService.getAccessibleFor(gTree);
|
||||
|
||||
// Makes sure tree children accessibles are created otherwise they won't
|
||||
// be a couse of name changed events.
|
||||
var children = treeAcc.children;
|
||||
|
||||
// Fire 'TreeInvalidated' event by InvalidateColumn()
|
||||
var firstCol = gTree.columns.getFirstColumn();
|
||||
for (var i = 0; i < gView.mRowCount; i++) {
|
||||
var key = String(i) + firstCol.id;
|
||||
gView.mData[key] = key + "_col";
|
||||
}
|
||||
|
||||
gTreeBox.invalidateColumn(firstCol);
|
||||
}
|
||||
|
||||
function doTest3()
|
||||
{
|
||||
// Fire 'TreeInvalidated' event by InvalidateRow()
|
||||
var colCount = gTree.columns.count;
|
||||
for (var i = 0; i < colCount; i++) {
|
||||
var key = "1" + gTree.columns.getColumnAt(i).id;
|
||||
gView.mData[key] = key + "_row";
|
||||
}
|
||||
|
||||
gTreeBox.invalidateRow(1);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox flex="1" style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=368835"
|
||||
title="Fire TreeViewChanged/TreeRowCountChanged events.">
|
||||
Mozilla Bug 368835
|
||||
</a><br/>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=308564"
|
||||
title="No accessibility events when data in a tree row changes.">
|
||||
Mozilla Bug 308564
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<tree id="tree" flex="1">
|
||||
<treecols>
|
||||
<treecol id="col" flex="1" primary="true" label="column"/>
|
||||
<treecol id="scol" flex="1" label="column 2"/>
|
||||
</treecols>
|
||||
<treechildren id="treechildren"/>
|
||||
</tree>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
<?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"?>
|
||||
|
||||
<!--
|
||||
Bug 368835 - fire TreeViewChanged/TreeRowCountChanged events.
|
||||
Bug 308564 - no accessibility events when data in a tree row changes.
|
||||
-->
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="DOM TreeViewChanged/TreeRowCountChanged and a11y name change events.">
|
||||
|
||||
<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/a11y/accessible/treeview.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/common.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/events.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Invoker's checkers
|
||||
|
||||
/**
|
||||
* Check TreeRowCountChanged event.
|
||||
*/
|
||||
function rowCountChangedChecker(aMsg, aIdx, aCount)
|
||||
{
|
||||
this.type = "TreeRowCountChanged";
|
||||
this.target = gTree;
|
||||
this.check = function check(aEvent)
|
||||
{
|
||||
var index = aEvent.getData("index");
|
||||
is(index, aIdx, "Wrong 'index' data of 'treeRowCountChanged' event.");
|
||||
|
||||
var count = aEvent.getData("count");
|
||||
is(count, aCount, "Wrong 'count' data of 'treeRowCountChanged' event.");
|
||||
}
|
||||
this.getID = function getID()
|
||||
{
|
||||
return aMsg + "TreeRowCountChanged";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check TreeInvalidated event.
|
||||
*/
|
||||
function treeInvalidatedChecker(aMsg, aStartRow, aEndRow, aStartCol, aEndCol)
|
||||
{
|
||||
this.type = "TreeInvalidated";
|
||||
this.target = gTree;
|
||||
this.check = function check(aEvent)
|
||||
{
|
||||
var startRow = aEvent.getData("startrow");
|
||||
is(startRow, aStartRow,
|
||||
"Wrong 'startrow' of 'treeInvalidated' event on " + aMsg);
|
||||
|
||||
var endRow = aEvent.getData("endrow");
|
||||
is(endRow, aEndRow,
|
||||
"Wrong 'endrow' of 'treeInvalidated' event on " + aMsg);
|
||||
|
||||
var startCol = aEvent.getData("startcolumn");
|
||||
is(startCol, aStartCol,
|
||||
"Wrong 'startcolumn' of 'treeInvalidated' event on " + aMsg);
|
||||
|
||||
var endCol = aEvent.getData("endcolumn");
|
||||
is(endCol, aEndCol,
|
||||
"Wrong 'endcolumn' of 'treeInvalidated' event on " + aMsg);
|
||||
}
|
||||
this.getID = function getID()
|
||||
{
|
||||
return "TreeInvalidated on " + aMsg;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check name changed a11y event.
|
||||
*/
|
||||
function nameChangeChecker(aMsg, aRow, aCol)
|
||||
{
|
||||
this.type = EVENT_NAME_CHANGE;
|
||||
|
||||
this.target getter = function()
|
||||
{
|
||||
var acc = getAccessible(gTree);
|
||||
|
||||
var tableAcc = getAccessible(acc, [nsIAccessibleTable], null,
|
||||
DONOTFAIL_IF_NO_INTERFACE);
|
||||
|
||||
if (tableAcc)
|
||||
return tableAcc.cellRefAt(aRow, aCol);
|
||||
|
||||
return acc.getChildAt(aRow + 1);
|
||||
}
|
||||
this.getID = function getID()
|
||||
{
|
||||
return aMsg + "name changed";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Invokers
|
||||
|
||||
/**
|
||||
* Set tree view and process TreeViewChanged handler.
|
||||
*/
|
||||
function setTreeView()
|
||||
{
|
||||
this.invoke = function setTreeView_invoke()
|
||||
{
|
||||
gTreeBox.view = gView;
|
||||
}
|
||||
|
||||
this.getID = function setTreeView_getID() { return "TreeViewChanged"; }
|
||||
|
||||
this.eventSeq = [["TreeViewChanged", gTree]];
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert row at 0 index and checks TreeRowCountChanged and TreeInvalidated
|
||||
* event.
|
||||
*/
|
||||
function insertRow()
|
||||
{
|
||||
this.invoke = function insertRow_invoke()
|
||||
{
|
||||
++gView.mRowCount;
|
||||
gTreeBox.rowCountChanged(0, 1);
|
||||
}
|
||||
|
||||
this.eventSeq =
|
||||
[
|
||||
new rowCountChangedChecker("insertRow: ", 0, 1),
|
||||
new treeInvalidatedChecker("insertRow", 0, 5, null, null)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates first column and checks six name changed events for each
|
||||
* treeitem plus TreeInvalidated event.
|
||||
*/
|
||||
function invalidateColumn()
|
||||
{
|
||||
this.invoke = function()
|
||||
{
|
||||
// Make sure accessibles for the tree is created because it makes
|
||||
// sure accessible events will be fired.
|
||||
var treeAcc = getAccessible(gTree);
|
||||
|
||||
// Makes sure tree children accessibles are created otherwise they won't
|
||||
// be a cause of name changed events.
|
||||
var children = treeAcc.children;
|
||||
|
||||
// Fire 'TreeInvalidated' event by InvalidateColumn()
|
||||
var firstCol = gTree.columns.getFirstColumn();
|
||||
for (var i = 0; i < gView.mRowCount; i++) {
|
||||
var key = String(i) + firstCol.id;
|
||||
gView.mData[key] = key + "_col";
|
||||
}
|
||||
|
||||
gTreeBox.invalidateColumn(firstCol);
|
||||
}
|
||||
|
||||
this.eventSeq =
|
||||
[
|
||||
new nameChangeChecker("invalidateColumn: ", 0, 0),
|
||||
new nameChangeChecker("invalidateColumn: ", 1, 0),
|
||||
new nameChangeChecker("invalidateColumn: ", 2, 0),
|
||||
new nameChangeChecker("invalidateColumn: ", 3, 0),
|
||||
new nameChangeChecker("invalidateColumn: ", 4, 0),
|
||||
new nameChangeChecker("invalidateColumn: ", 5, 0),
|
||||
new treeInvalidatedChecker("invalidateColumn", null, null, 0, 0)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates second row and checks name changed event for first treeitem
|
||||
* (note, there are two name changed events on linux due to different
|
||||
* accessible tree for xul:tree element) plus TreeInvalidated event.
|
||||
*/
|
||||
function invalidateRow()
|
||||
{
|
||||
this.invoke = function()
|
||||
{
|
||||
// Fire 'TreeInvalidated' event by InvalidateRow()
|
||||
var colCount = gTree.columns.count;
|
||||
for (var i = 0; i < colCount; i++) {
|
||||
var key = "1" + gTree.columns.getColumnAt(i).id;
|
||||
gView.mData[key] = key + "_row";
|
||||
}
|
||||
|
||||
gTreeBox.invalidateRow(1);
|
||||
}
|
||||
|
||||
this.eventSeq =
|
||||
[
|
||||
new nameChangeChecker("invalidateColumn: ", 1, 0),
|
||||
new treeInvalidatedChecker("invalidateColumn", 1, 1, null, null)
|
||||
];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Test
|
||||
|
||||
var gTree = null;
|
||||
var gTreeBox = null;
|
||||
var gTreeView = null;
|
||||
var gQueue = null;
|
||||
|
||||
// gA11yEventDumpID = "debug";
|
||||
|
||||
function doTest()
|
||||
{
|
||||
// Initialize the tree
|
||||
gTree = document.getElementById("tree");
|
||||
gTreeBox = gTree.treeBoxObject;
|
||||
|
||||
gView = new inTreeView();
|
||||
gView.mRowCount = 5;
|
||||
|
||||
// Perform actions
|
||||
gQueue = new eventQueue();
|
||||
|
||||
gQueue.push(new setTreeView());
|
||||
gQueue.push(new insertRow());
|
||||
gQueue.push(new invalidateColumn());
|
||||
gQueue.push(new invalidateRow());
|
||||
|
||||
gQueue.invoke();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox flex="1" style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=368835"
|
||||
title="Fire TreeViewChanged/TreeRowCountChanged events.">
|
||||
Mozilla Bug 368835
|
||||
</a><br/>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=308564"
|
||||
title="No accessibility events when data in a tree row changes.">
|
||||
Mozilla Bug 308564
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox id="debug"/>
|
||||
<tree id="tree" flex="1">
|
||||
<treecols>
|
||||
<treecol id="col" flex="1" primary="true" label="column"/>
|
||||
<treecol id="scol" flex="1" label="column 2"/>
|
||||
</treecols>
|
||||
<treechildren id="treechildren"/>
|
||||
</tree>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
function inTreeView() { }
|
||||
|
||||
inTreeView.prototype =
|
||||
{
|
||||
mRowCount: 0,
|
||||
mTree: null,
|
||||
mData: {},
|
||||
|
||||
get rowCount()
|
||||
{
|
||||
return this.mRowCount;
|
||||
},
|
||||
setTree: function setTree(aTree)
|
||||
{
|
||||
this.mTree = aTree;
|
||||
},
|
||||
getCellText: function getCellText(aRow, aCol)
|
||||
{
|
||||
var key = String(aRow) + aCol.id;
|
||||
if (key in this.mData)
|
||||
return this.mData[key];
|
||||
|
||||
return "hello";
|
||||
},
|
||||
getRowProperties: function getRowProperties(aIndex, aProperties) {},
|
||||
getCellProperties: function getCellProperties(aIndex, aCol, aProperties) {},
|
||||
getColumnProperties: function getColumnProperties(aCol, aProperties) {},
|
||||
getParentIndex: function getParentIndex(aRowIndex) { },
|
||||
hasNextSibling: function hasNextSibling(aRowIndex, aAfterIndex) { },
|
||||
getLevel: function getLevel(aIndex) {},
|
||||
getImageSrc: function getImageSrc(aRow, aCol) {},
|
||||
getProgressMode: function getProgressMode(aRow, aCol) {},
|
||||
getCellValue: function getCellValue(aRow, aCol) {},
|
||||
isContainer: function isContainer(aIndex) {},
|
||||
isContainerOpen: function isContainerOpen(aIndex) {},
|
||||
isContainerEmpty: function isContainerEmpty(aIndex) {},
|
||||
isSeparator: function isSeparator(aIndex) {},
|
||||
isSorted: function isSorted() {},
|
||||
toggleOpenState: function toggleOpenState(aIndex) {},
|
||||
selectionChanged: function selectionChanged() {},
|
||||
cycleHeader: function cycleHeader(aCol) {},
|
||||
cycleCell: function cycleCell(aRow, aCol) {},
|
||||
isEditable: function isEditable(aRow, aCol) {},
|
||||
isSelectable: function isSelectable(aRow, aCol) {},
|
||||
setCellValue: function setCellValue(aRow, aCol, aValue) {},
|
||||
setCellText: function setCellText(aRow, aCol, aValue) { },
|
||||
performAction: function performAction(aAction) {},
|
||||
performActionOnRow: function performActionOnRow(aAction, aRow) {},
|
||||
performActionOnCell: function performActionOnCell(aAction, aRow, aCol) {}
|
||||
};
|
Загрузка…
Ссылка в новой задаче