Bug 1751978 - Add multiselection keyboard controls to treeview-listbox. r=darktrojan
We also fix various related accessibility problems with the treeview-listbox. Differential Revision: https://phabricator.services.mozilla.com/D149421 --HG-- extra : amend_source : fbd3db0931320065845c193a85f1a74b0a0e3491
This commit is contained in:
Родитель
b1f9783a25
Коммит
dde93a8df6
|
@ -917,6 +917,50 @@
|
|||
this.shadowRoot.appendChild(this.filler);
|
||||
this.shadowRoot.appendChild(document.createElement("slot"));
|
||||
|
||||
this.setAttribute("aria-multiselectable", "true");
|
||||
|
||||
this.addEventListener("focus", event => {
|
||||
if (this._preventFocusHandler) {
|
||||
this._preventFocusHandler = false;
|
||||
return;
|
||||
}
|
||||
if (this.currentIndex == -1 && this._view.rowCount) {
|
||||
let selectionChanged = false;
|
||||
if (this.selectedIndex == -1) {
|
||||
this._selection.select(0);
|
||||
selectionChanged = true;
|
||||
}
|
||||
this.currentIndex = this.selectedIndex;
|
||||
if (selectionChanged) {
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.addEventListener("mousedown", event => {
|
||||
if (
|
||||
this == document.activeElement ||
|
||||
!event.target.closest(this._rowElementName)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// We prevent the focus handler because it can change the selection
|
||||
// state, which currently rebuilds the view. If this happens the mouseup
|
||||
// event will be on a different element, which means it will not receive
|
||||
// the "click" event.
|
||||
// Instead, we let the click handler change the selection state instead
|
||||
// of the focus handler.
|
||||
// Ideally, instead of this hack, we would not rebuild the view when
|
||||
// just the selection changes since it should be a light operation.
|
||||
this._preventFocusHandler = true;
|
||||
// We expect the property to be cleared in the focus handler, because
|
||||
// the default mousedown will invoke it, but we clear the property at
|
||||
// the next loop just in case.
|
||||
setTimeout(() => {
|
||||
this._preventFocusHandler = false;
|
||||
});
|
||||
});
|
||||
|
||||
this.addEventListener("click", event => {
|
||||
if (event.button !== 0) {
|
||||
return;
|
||||
|
@ -945,64 +989,73 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (event.ctrlKey && event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.ctrlKey) {
|
||||
this.currentIndex = index;
|
||||
this.toggleSelectionAtIndex(index);
|
||||
this._toggleSelected(index);
|
||||
} else if (event.shiftKey) {
|
||||
this._selection.rangedSelect(-1, index, false);
|
||||
this.scrollToIndex(index);
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
this._selectRange(index);
|
||||
} else {
|
||||
this.selectedIndex = index;
|
||||
this._selectSingle(index);
|
||||
}
|
||||
});
|
||||
|
||||
this.addEventListener("keydown", event => {
|
||||
if (event.altKey || event.ctrlKey || event.metaKey) {
|
||||
if (event.altKey || event.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newIndex = this.currentIndex;
|
||||
let currentIndex = this.currentIndex == -1 ? 0 : this.currentIndex;
|
||||
let newIndex;
|
||||
switch (event.key) {
|
||||
case "ArrowUp":
|
||||
newIndex = this.currentIndex - 1;
|
||||
newIndex = currentIndex - 1;
|
||||
break;
|
||||
case "ArrowDown":
|
||||
newIndex = this.currentIndex + 1;
|
||||
newIndex = currentIndex + 1;
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
case "ArrowRight": {
|
||||
event.preventDefault();
|
||||
if (this.currentIndex == -1) {
|
||||
return;
|
||||
}
|
||||
let isArrowRight = event.key == "ArrowRight";
|
||||
let isRTL = this.matches(":dir(rtl)");
|
||||
if (isArrowRight == isRTL) {
|
||||
// Collapse action.
|
||||
let currentLevel = this._view.getLevel(newIndex);
|
||||
if (this._view.isContainerOpen(newIndex)) {
|
||||
this.collapseRowAtIndex(newIndex);
|
||||
let currentLevel = this._view.getLevel(this.currentIndex);
|
||||
if (this._view.isContainerOpen(this.currentIndex)) {
|
||||
this.collapseRowAtIndex(this.currentIndex);
|
||||
return;
|
||||
} else if (currentLevel == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parentIndex = this._view.getParentIndex(newIndex);
|
||||
let parentIndex = this._view.getParentIndex(this.currentIndex);
|
||||
if (parentIndex != -1) {
|
||||
this.selectedIndex = parentIndex;
|
||||
newIndex = parentIndex;
|
||||
}
|
||||
} else if (this._view.isContainer(newIndex)) {
|
||||
} else if (this._view.isContainer(this.currentIndex)) {
|
||||
// Expand action.
|
||||
if (!this._view.isContainerOpen(newIndex)) {
|
||||
let addedRows = this.expandRowAtIndex(newIndex);
|
||||
if (!this._view.isContainerOpen(this.currentIndex)) {
|
||||
let addedRows = this.expandRowAtIndex(this.currentIndex);
|
||||
this.scrollToIndex(
|
||||
newIndex +
|
||||
this.currentIndex +
|
||||
Math.min(
|
||||
addedRows,
|
||||
this.clientHeight / this._rowElementClass.ROW_HEIGHT - 1
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.selectedIndex++;
|
||||
newIndex = this.currentIndex + 1;
|
||||
}
|
||||
}
|
||||
if (newIndex != undefined) {
|
||||
this._selectSingle(newIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "Home":
|
||||
|
@ -1014,35 +1067,46 @@
|
|||
case "PageUp":
|
||||
newIndex = Math.max(
|
||||
0,
|
||||
this.currentIndex -
|
||||
currentIndex -
|
||||
Math.floor(this.clientHeight / this._rowElementClass.ROW_HEIGHT)
|
||||
);
|
||||
break;
|
||||
case "PageDown":
|
||||
newIndex = Math.min(
|
||||
this._view.rowCount - 1,
|
||||
this.currentIndex +
|
||||
currentIndex +
|
||||
Math.floor(this.clientHeight / this._rowElementClass.ROW_HEIGHT)
|
||||
);
|
||||
break;
|
||||
case " ":
|
||||
if (event.originalTarget.closest("button")) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
newIndex = this._clampIndex(newIndex);
|
||||
if (event.shiftKey) {
|
||||
this._selection.rangedSelect(-1, newIndex, false);
|
||||
this.scrollToIndex(newIndex);
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
} else {
|
||||
this.selectedIndex = newIndex;
|
||||
if (newIndex != undefined) {
|
||||
newIndex = this._clampIndex(newIndex);
|
||||
if (newIndex != null && (!event.ctrlKey || !event.shiftKey)) {
|
||||
// Else, if both modifiers pressed, do nothing.
|
||||
if (event.shiftKey) {
|
||||
this._selectRange(newIndex);
|
||||
} else if (event.ctrlKey) {
|
||||
// Change focus, but not selection.
|
||||
this.currentIndex = newIndex;
|
||||
} else {
|
||||
this._selectSingle(newIndex);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key == " ") {
|
||||
if (this.currentIndex != -1 && !event.shiftKey) {
|
||||
if (event.ctrlKey) {
|
||||
this._toggleSelected(this.currentIndex);
|
||||
} else {
|
||||
this._selectSingle(this.currentIndex);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
let lastTime = 0;
|
||||
|
@ -1139,10 +1203,6 @@
|
|||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (view.rowCount && this.currentIndex == -1) {
|
||||
this.currentIndex = 0;
|
||||
}
|
||||
}
|
||||
this.invalidate();
|
||||
|
||||
|
@ -1296,6 +1356,9 @@
|
|||
* @return {integer}
|
||||
*/
|
||||
_clampIndex(index) {
|
||||
if (!this._view.rowCount) {
|
||||
return null;
|
||||
}
|
||||
if (index < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1445,6 +1508,7 @@
|
|||
this._selection.currentIndex = index;
|
||||
|
||||
if (index < 0 || index > this._view.rowCount - 1) {
|
||||
this.removeAttribute("aria-activedescendant");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1453,6 +1517,48 @@
|
|||
this.setAttribute("aria-activedescendant", `${this.id}-row${index}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select and focus the given index.
|
||||
*
|
||||
* @param {number} index - The index to select.
|
||||
*/
|
||||
_selectSingle(index) {
|
||||
let changeSelection =
|
||||
this._selection.count != 1 || !this._selection.isSelected(index);
|
||||
if (changeSelection) {
|
||||
this._selection.select(index);
|
||||
}
|
||||
this.currentIndex = index;
|
||||
if (changeSelection) {
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or extend a range selection to the given index and focus it.
|
||||
*
|
||||
* @param {number} index - The index to select.
|
||||
*/
|
||||
_selectRange(index) {
|
||||
this._selection.rangedSelect(-1, index, false);
|
||||
this.currentIndex = index;
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the selection state at the given index and focus it.
|
||||
*
|
||||
* @param {number} index - The index to toggle.
|
||||
*/
|
||||
_toggleSelected(index) {
|
||||
this._selection.toggleSelect(index);
|
||||
// We hack the internals of the JSTreeSelection to clear the
|
||||
// shiftSelectPivot.
|
||||
this._selection._shiftSelectPivot = null;
|
||||
this.currentIndex = index;
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
}
|
||||
|
||||
/**
|
||||
* In a selection, index of the most-recently-selected row.
|
||||
*
|
||||
|
@ -1469,13 +1575,7 @@
|
|||
}
|
||||
|
||||
set selectedIndex(index) {
|
||||
if (this._selection.count == 1 && this._selection.isSelected(index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._selection.select(index);
|
||||
this.currentIndex = index;
|
||||
this.dispatchEvent(new CustomEvent("select"));
|
||||
this._selectSingle(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1565,6 +1665,7 @@
|
|||
|
||||
this.list = this.parentNode;
|
||||
this.view = this.list.view;
|
||||
this.setAttribute("aria-selected", !!this.selected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1591,13 +1692,8 @@
|
|||
}
|
||||
|
||||
set selected(selected) {
|
||||
this.setAttribute("aria-selected", selected);
|
||||
this.setAttribute("aria-selected", !!selected);
|
||||
this.classList.toggle("selected", !!selected);
|
||||
|
||||
// Throw focus back to the list if something in this row had it.
|
||||
if (!selected && document.activeElement == this) {
|
||||
this.list.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define("tree-view-listrow", TreeViewListrow);
|
||||
|
|
|
@ -135,7 +135,7 @@ async function subtestKeyboardAndMouse() {
|
|||
}
|
||||
|
||||
checkCurrent(0);
|
||||
checkSelected();
|
||||
checkSelected(0);
|
||||
|
||||
// Click on some individual rows.
|
||||
|
||||
|
@ -143,7 +143,7 @@ async function subtestKeyboardAndMouse() {
|
|||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
async function clickOnRow(index, modifiers = {}) {
|
||||
async function clickOnRow(index, modifiers = {}, expectEvent = true) {
|
||||
if (modifiers.shiftKey) {
|
||||
info(`clicking on row ${index} with shift key`);
|
||||
} else if (modifiers.ctrlKey) {
|
||||
|
@ -160,12 +160,12 @@ async function subtestKeyboardAndMouse() {
|
|||
list.addEventListener("select", selectHandler, { once: true });
|
||||
EventUtils.synthesizeMouse(list, x, y, modifiers, content);
|
||||
await TestUtils.waitForCondition(
|
||||
() => selectHandler.seenEvent,
|
||||
"'select' event did not get fired"
|
||||
() => !!selectHandler.seenEvent == expectEvent,
|
||||
`'select' event should ${expectEvent ? "" : "not "}get fired`
|
||||
);
|
||||
}
|
||||
|
||||
await clickOnRow(0);
|
||||
await clickOnRow(0, {}, false);
|
||||
checkCurrent(0);
|
||||
checkSelected(0);
|
||||
|
||||
|
@ -206,15 +206,15 @@ async function subtestKeyboardAndMouse() {
|
|||
checkSelected(1, 2, 5);
|
||||
|
||||
await clickOnRow(5, { ctrlKey: true });
|
||||
checkCurrent(5); // Is this right?
|
||||
checkCurrent(5);
|
||||
checkSelected(1, 2);
|
||||
|
||||
await clickOnRow(1, { ctrlKey: true });
|
||||
checkCurrent(1); // Is this right?
|
||||
checkCurrent(1);
|
||||
checkSelected(2);
|
||||
|
||||
await clickOnRow(2, { ctrlKey: true });
|
||||
checkCurrent(2); // Is this right?
|
||||
checkCurrent(2);
|
||||
checkSelected();
|
||||
|
||||
// Move around by pressing keys.
|
||||
|
@ -231,7 +231,7 @@ async function subtestKeyboardAndMouse() {
|
|||
EventUtils.synthesizeKey(key, modifiers, content);
|
||||
await TestUtils.waitForCondition(
|
||||
() => !!selectHandler.seenEvent == expectEvent,
|
||||
`'select' event ${expectEvent ? "fired" : "did not fire"} as expected`
|
||||
`'select' event should ${expectEvent ? "" : "not "}get fired`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -243,32 +243,112 @@ async function subtestKeyboardAndMouse() {
|
|||
checkCurrent(1);
|
||||
checkSelected(1);
|
||||
|
||||
pressKey("VK_UP");
|
||||
await pressKey("VK_UP", { ctrlKey: true }, false);
|
||||
checkCurrent(0);
|
||||
checkSelected(1);
|
||||
|
||||
// Without Ctrl selection moves with focus again.
|
||||
await pressKey("VK_UP");
|
||||
checkCurrent(0);
|
||||
checkSelected(0);
|
||||
|
||||
// Does nothing.
|
||||
pressKey("VK_UP", undefined, false);
|
||||
await pressKey("VK_UP", {}, false);
|
||||
checkCurrent(0);
|
||||
checkSelected(0);
|
||||
|
||||
await pressKey("VK_DOWN", { ctrlKey: true }, false);
|
||||
checkCurrent(1);
|
||||
checkSelected(0);
|
||||
|
||||
await pressKey("VK_DOWN", { ctrlKey: true }, false);
|
||||
checkCurrent(2);
|
||||
checkSelected(0);
|
||||
|
||||
// Multi select with Ctrl+Space.
|
||||
await pressKey(" ", { ctrlKey: true });
|
||||
checkCurrent(2);
|
||||
checkSelected(0, 2);
|
||||
|
||||
await pressKey("VK_DOWN", { ctrlKey: true }, false);
|
||||
checkCurrent(3);
|
||||
checkSelected(0, 2);
|
||||
|
||||
await pressKey("VK_DOWN", { ctrlKey: true }, false);
|
||||
checkCurrent(4);
|
||||
checkSelected(0, 2);
|
||||
|
||||
await pressKey(" ", { ctrlKey: true });
|
||||
checkCurrent(4);
|
||||
checkSelected(0, 2, 4);
|
||||
|
||||
// Single selection restored with normal navigation.
|
||||
await pressKey("VK_UP");
|
||||
checkCurrent(3);
|
||||
checkSelected(3);
|
||||
|
||||
// Can select none using Ctrl+Space.
|
||||
await pressKey(" ", { ctrlKey: true });
|
||||
checkCurrent(3);
|
||||
checkSelected();
|
||||
|
||||
await pressKey("VK_DOWN");
|
||||
checkCurrent(4);
|
||||
checkSelected(4);
|
||||
|
||||
await pressKey("VK_HOME", { ctrlKey: true }, false);
|
||||
checkCurrent(0);
|
||||
checkSelected(4);
|
||||
|
||||
// Select only the current item with Space (no modifier).
|
||||
await pressKey(" ");
|
||||
checkCurrent(0);
|
||||
checkSelected(0);
|
||||
|
||||
// The list is 630px high, so rows 0-11 are fully visible.
|
||||
|
||||
pressKey("VK_PAGE_DOWN");
|
||||
await pressKey("VK_PAGE_DOWN");
|
||||
await scrollingDelay();
|
||||
checkCurrent(12);
|
||||
checkSelected(12);
|
||||
Assert.equal(list.getFirstVisibleIndex(), 1, "scrolled to the correct place");
|
||||
|
||||
pressKey("VK_PAGE_UP", { shiftKey: true });
|
||||
await pressKey("VK_PAGE_UP", { shiftKey: true });
|
||||
await scrollingDelay();
|
||||
checkCurrent(0);
|
||||
checkSelected(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
|
||||
Assert.equal(list.getFirstVisibleIndex(), 0, "scrolled to the correct place");
|
||||
|
||||
// Shrink shift selection.
|
||||
await pressKey("VK_DOWN", { shiftKey: true });
|
||||
checkCurrent(1);
|
||||
checkSelected(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
|
||||
|
||||
await pressKey("VK_DOWN", { ctrlKey: true }, false);
|
||||
checkCurrent(2);
|
||||
checkSelected(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
|
||||
|
||||
await pressKey("VK_DOWN", { ctrlKey: true }, false);
|
||||
checkCurrent(3);
|
||||
checkSelected(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
|
||||
|
||||
// Break the shift sequence by Ctrl+Space.
|
||||
await pressKey(" ", { ctrlKey: true });
|
||||
checkCurrent(3);
|
||||
checkSelected(1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12);
|
||||
|
||||
await pressKey("VK_DOWN", { shiftKey: true });
|
||||
checkCurrent(4);
|
||||
checkSelected(3, 4);
|
||||
|
||||
// Reverse selection direction.
|
||||
await pressKey("VK_HOME", { shiftKey: true });
|
||||
checkCurrent(0);
|
||||
checkSelected(0, 1, 2, 3);
|
||||
|
||||
// Now rows 38-49 are fully visible.
|
||||
|
||||
pressKey("VK_END");
|
||||
await pressKey("VK_END");
|
||||
await scrollingDelay();
|
||||
checkCurrent(49);
|
||||
checkSelected(49);
|
||||
|
@ -279,7 +359,7 @@ async function subtestKeyboardAndMouse() {
|
|||
);
|
||||
|
||||
// Does nothing.
|
||||
pressKey("VK_DOWN", undefined, false);
|
||||
await pressKey("VK_DOWN", {}, false);
|
||||
checkCurrent(49);
|
||||
checkSelected(49);
|
||||
Assert.equal(
|
||||
|
@ -288,7 +368,7 @@ async function subtestKeyboardAndMouse() {
|
|||
"scrolled to the correct place"
|
||||
);
|
||||
|
||||
pressKey("VK_PAGE_UP");
|
||||
await pressKey("VK_PAGE_UP");
|
||||
await scrollingDelay();
|
||||
checkCurrent(37);
|
||||
checkSelected(37);
|
||||
|
@ -298,7 +378,7 @@ async function subtestKeyboardAndMouse() {
|
|||
"scrolled to the correct place"
|
||||
);
|
||||
|
||||
pressKey("VK_PAGE_DOWN", { shiftKey: true });
|
||||
await pressKey("VK_PAGE_DOWN", { shiftKey: true });
|
||||
await scrollingDelay();
|
||||
checkCurrent(49);
|
||||
checkSelected(37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49);
|
||||
|
@ -308,7 +388,7 @@ async function subtestKeyboardAndMouse() {
|
|||
"scrolled to the correct place"
|
||||
);
|
||||
|
||||
pressKey("VK_HOME");
|
||||
await pressKey("VK_HOME");
|
||||
await scrollingDelay();
|
||||
checkCurrent(0);
|
||||
checkSelected(0);
|
||||
|
@ -350,7 +430,7 @@ async function subtestKeyboardAndMouse() {
|
|||
"'select' event did not fire as expected"
|
||||
);
|
||||
|
||||
pressKey("VK_DOWN");
|
||||
await pressKey("VK_DOWN");
|
||||
await scrollingDelay();
|
||||
checkCurrent(1);
|
||||
checkSelected(1);
|
||||
|
@ -371,7 +451,7 @@ async function subtestKeyboardAndMouse() {
|
|||
"'select' event did not fire as expected"
|
||||
);
|
||||
|
||||
pressKey("VK_UP");
|
||||
await pressKey("VK_UP");
|
||||
checkCurrent(0);
|
||||
checkSelected(0);
|
||||
Assert.equal(list.getFirstVisibleIndex(), 0, "scrolled to the correct place");
|
||||
|
|
|
@ -1799,9 +1799,6 @@ var cardsPane = {
|
|||
_showContextMenu(event) {
|
||||
let row;
|
||||
if (event.target == this.cardsList) {
|
||||
if (this.cardsList.selectedIndex == -1) {
|
||||
return;
|
||||
}
|
||||
row = this.cardsList.getRowAtIndex(this.cardsList.currentIndex);
|
||||
} else {
|
||||
row = event.target.closest("ab-card-listrow, ab-table-card-listrow");
|
||||
|
@ -1811,6 +1808,8 @@ var cardsPane = {
|
|||
}
|
||||
if (!this.cardsList.selectedIndices.includes(row.index)) {
|
||||
this.cardsList.selectedIndex = row.index;
|
||||
// Re-fetch the row in case it was replaced.
|
||||
row = this.cardsList.getRowAtIndex(this.cardsList.currentIndex);
|
||||
}
|
||||
|
||||
this.cardsList.focus();
|
||||
|
@ -1979,7 +1978,6 @@ var cardsPane = {
|
|||
|
||||
_onSelect(event) {
|
||||
detailsPane.displayCards(this.selectedCards);
|
||||
this.cardsList.scrollToIndex(this.cardsList.selectedIndex);
|
||||
},
|
||||
|
||||
_onKeyPress(event) {
|
||||
|
|
|
@ -31,6 +31,7 @@ add_task(async function test_additions_and_removals() {
|
|||
EventUtils.synthesizeKey("VK_DELETE", {}, abWindow);
|
||||
await promptPromise;
|
||||
await new Promise(r => abWindow.setTimeout(r));
|
||||
await new Promise(r => abWindow.setTimeout(r));
|
||||
}
|
||||
|
||||
let bookA = createAddressBook("book A");
|
||||
|
|
|
@ -30,22 +30,38 @@ add_task(async function test_f6_cycle() {
|
|||
|
||||
let editButton = abDocument.getElementById("editButton");
|
||||
|
||||
// Check what happens with a contact selected.
|
||||
openDirectory(book);
|
||||
Assert.ok(BrowserTestUtils.is_hidden(detailsPane));
|
||||
// NOTE: When the "cards" element first receives focus it will select the
|
||||
// first item, which causes the panel to be displayed.
|
||||
cycle(
|
||||
"books",
|
||||
"searchInput",
|
||||
"cards",
|
||||
"editButton",
|
||||
"books",
|
||||
"searchInput",
|
||||
"cards"
|
||||
);
|
||||
Assert.ok(BrowserTestUtils.is_visible(detailsPane));
|
||||
|
||||
// Check with no selection.
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
cardsList.getRowAtIndex(0),
|
||||
{ ctrlKey: true },
|
||||
abWindow
|
||||
);
|
||||
Assert.ok(BrowserTestUtils.is_hidden(detailsPane));
|
||||
cycle("cards", "books", "searchInput", "cards");
|
||||
// Still hidden.
|
||||
Assert.ok(BrowserTestUtils.is_hidden(detailsPane));
|
||||
|
||||
// Check what happens with no contact selected.
|
||||
|
||||
cycle("searchInput", "cards", "books", "searchInput");
|
||||
|
||||
// Check what happens with a contact selected.
|
||||
|
||||
// Check what happens while editing. It should be nothing.
|
||||
openDirectory(book);
|
||||
EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(0), {}, abWindow);
|
||||
Assert.ok(BrowserTestUtils.is_visible(detailsPane));
|
||||
|
||||
cycle("cards", "editButton", "books", "searchInput", "cards");
|
||||
|
||||
// Check what happens while editing. It should be nothing.
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(editButton, {}, abWindow);
|
||||
Assert.equal(abDocument.activeElement.id, "vcard-n-firstname");
|
||||
EventUtils.synthesizeKey("KEY_F6", {}, abWindow);
|
||||
|
|
Загрузка…
Ссылка в новой задаче