// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. // // /// /// module WinJSTests { "use strict"; var ListView = WinJS.UI.ListView; var Key = WinJS.Utilities.Key; var list, proxy, items, invoked; function verifySelection(mode, expected) { if (!Array.isArray(expected)) { expected = [expected]; } Helper.ListView.elementsEqual(expected, mode.site._selection.getIndices()); } function eventOnElement(element) { var rect = element.getBoundingClientRect(); // Simulate clicking the middle of the element return { target: element, clientX: (rect.left + rect.right) / 2, clientY: (rect.top + rect.bottom) / 2, defaultPrevented: false, preventDefault: function () { this.defaultPrevented = true; } }; } // As a side effect, this will scroll the browser to make the clicked element visible function click(mode, eventObject) { var target = eventObject.target, elementCoords; invoked = { type: "item", index: -1 }; if (typeof eventObject.button !== "number") { eventObject.button = WinJS.UI._LEFT_MSPOINTER_BUTTON; } target.scrollIntoView(false); elementCoords = eventOnElement(target); eventObject.clientX = elementCoords.clientX; eventObject.clientY = elementCoords.clientY; eventObject.preventDefault = function () { }; mode.onPointerDown(eventObject); mode.onPointerUp(eventObject); mode.onclick(); } function rightClick(mode, eventObject) { eventObject.button = WinJS.UI._RIGHT_MSPOINTER_BUTTON; click(mode, eventObject); } function createEvent(key, shiftKey?, ctrlKey?) { return { keyCode: key, shiftKey: shiftKey, ctrlKey: ctrlKey, target: items[0], stopPropagation: function () { }, preventDefault: function () { } }; } function createMode(site) { var mode = new WinJS.UI._SelectionMode(site); mode._fireInvokeEvent = function (entity) { invoked = entity; }; return mode; } function createSite(configuration) { var dataSource = (new WinJS.Binding.List([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])).dataSource; var selectionManager = new WinJS.UI._SelectionManager({}); selectionManager._fireSelectionChanging = function () { return WinJS.Promise.wrap(true); }; selectionManager._fireSelectionChanged = function () { }; var site = { itemDataSource: dataSource, _groups: new WinJS.UI._NoGroups(), _versionManager: new WinJS.UI._VersionManager(), _selectionMode: configuration.selectionMode, _tap: configuration.tap, _isZombie: function () { return true; }, _element: list, _viewport: list, _canvas: list, _itemCanvas: list, _canvasProxy: proxy, _rtl: function () { return window.getComputedStyle(site._canvas, null).direction === "rtl"; }, keyboardFocusedItem: { type: "item", index: 0 }, _lastFocusedElementInGroupTrack: { type: "item", index: -1 }, _updateSelection: function () { }, _unsetFocusOnItem: function () { this.keyboardFocusedItem = { type: "item", index: -1 }; }, _setFocusOnItem: function (item) { this.keyboardFocusedItem = item; }, _setupTabOrder: function () { }, addEventListener: function () { }, removeEventListener: function () { }, ensureVisible: function () { }, _selection: selectionManager, _getItemPosition: function (index) { return { then: function (callback) { callback({ left: 0, top: 0, contentWidth: 100, contentHeight: 100 }); } }; }, _layout: { // We're pretending to be a 3x3 horizontal grid here getKeyboardNavigatedItem: function (entity, element, keyPressed) { if (keyPressed === WinJS.Utilities.Key.upArrow) { return WinJS.Promise.wrap({ type: "item", index: Math.max(0, entity.index - 1) }); } else if (keyPressed === WinJS.Utilities.Key.downArrow) { return WinJS.Promise.wrap({ type: "item", index: entity.index + 1 }); } else if (keyPressed === WinJS.Utilities.Key.leftArrow) { return WinJS.Promise.wrap({ type: "item", index: ((entity.index - 3 < 0) ? entity.index : entity.index - 3) }); } else { return WinJS.Promise.wrap({ type: "item", index: entity.index + 3 }); } } }, _changeFocus: function (newFocus, skipSelection, ctrlKeyDown) { this._selection._setFocused(newFocus); this.keyboardFocusedItem = newFocus; if (!skipSelection && this._selectFocused(ctrlKeyDown)) { this._selection.set([{ index: newFocus }]); } }, _selectionAllowed: function () { return this._selectionMode !== "none"; }, _multiSelection: function () { return this._selectionMode === "multi"; }, _selectOnTap: function () { return this._tap === "toggleSelect" || this._tap === "directSelect"; }, _selectFocused: function ListView_selectFocused(ctrlKeyDown) { return this._tap === WinJS.UI.TapBehavior.directSelect && this._selectionMode === WinJS.UI.SelectionMode.multi && !ctrlKeyDown; }, _renderSelection: function () { }, _getItemOffset: function (index) { return { then: function (callback) { callback({ begin: 0, end: 100 }); } }; }, _convertFromCanvasCoordinates: function (range) { return range; }, _batchViewUpdates: function (stage, priority, functor) { functor(); }, _getViewportLength: function () { return 350; }, _view: { getAdjacent: function (oldFocus, direction) { return site._layout.getKeyboardNavigatedItem(oldFocus, null, direction); }, items: { index: function (element) { var itemElement = element; for (var i = 0; i < items.length; ++i) { if (items[i] === itemElement) { return i; } } return -1; }, itemAt: function (index) { return items[index]; }, itemBoxAt: function (index) { return items[index]; }, containerAt: function (index) { return items[index]; }, containerFrom: function (element) { while (element && this.index(element) === -1) { element = element.parentNode; } return element; }, itemDataAt: function (index) { return { element: items[index], itemBox: items[index], container: items[index] }; } }, groups: null, // We're pretending to be a 3x3 horizontal grid here lastItemIndex: function () { return 8; } }, _itemsCount: function () { return dataSource.getCount(); }, _itemsManager: { dataSource: dataSource, _listBinding: dataSource.createListBinding() } }; WinJS.UI._ItemEventsHandler.renderSelection = function () { }; selectionManager._listView = site; return site; } // Verifies shift selection (mouse) using all combinations of left, right, and ctrl click. // Options: // - createSite: required // - shiftLeftClickIsAdditive: a boolean representing whether or not a shift+left-click // (no ctrl key) should add to the current selection rather than destroying it. function verifyRangeSelectionWithClick(options) { // options: site (required), shouldBeAdditive, shiftKey, rightClick, ctrlKey // When shouldBeAdditive is true, verifies that the current selection // is maintained and the range is added to it. Otherwise, verifies that // the range becomes selected and all other items become deselected. function verify(options) { var mode = createMode(options.site); var doClick = options.rightClick ? rightClick : click; doClick(mode, { target: items[2], ctrlKey: true }); verifySelection(mode, [2]); LiveUnit.Assert.areEqual(-1, invoked.index); doClick(mode, { target: items[0], shiftKey: true, ctrlKey: options.ctrlKey }); verifySelection(mode, [0, 1, 2]); LiveUnit.Assert.areEqual(-1, invoked.index); doClick(mode, { target: items[5], ctrlKey: true }); verifySelection(mode, [0, 1, 2, 5]); LiveUnit.Assert.areEqual(-1, invoked.index); doClick(mode, { target: items[8], shiftKey: true, ctrlKey: options.ctrlKey }); verifySelection(mode, options.shouldBeAdditive ? [0, 1, 2, 5, 6, 7, 8] : [5, 6, 7, 8]); LiveUnit.Assert.areEqual(-1, invoked.index); } [true, false].forEach(function (ctrlKey) { var shiftKeyOnly = !ctrlKey; verify({ shouldBeAdditive: shiftKeyOnly ? options.shiftLeftClickIsAdditive : true, site: options.createSite(), rightClick: false, ctrlKey: ctrlKey }); }); } // Verifies shift selection (keyboard) using the up and down arrows with and without the control key // Options: // - createSite: required // - shiftArrowIsAdditive: a boolean representing whether or not a shift+arrow // (no ctrl key) should add to the current selection rather than destroying it. function verifyRangeSelectionWithKeyboard(options) { // options: site (required), shouldBeAdditive, shiftKey, ctrlKey // When shouldBeAdditive is true, verifies that the current selection // is maintained and the range is added to it. Otherwise, verifies that // the range becomes selected and all other items become deselected. function verify(options) { var site = options.site; var mode = createMode(site); var shiftKey = true; verifySelection(mode, []); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 0); // Move to index 3 mode.onKeyDown(createEvent(Key.downArrow)); mode.onKeyDown(createEvent(Key.downArrow)); mode.onKeyDown(createEvent(Key.downArrow)); verifySelection(mode, []); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 3); // Test range selection using the up arrow mode.onKeyDown(createEvent(Key.upArrow, shiftKey, options.ctrlKey)); verifySelection(mode, [2, 3]); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 2); mode.onKeyDown(createEvent(Key.upArrow, shiftKey, options.ctrlKey)); verifySelection(mode, [1, 2, 3]); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); // Move to index 5 while maintaining the current selection mode.onKeyDown(createEvent(Key.downArrow, false, true)); mode.onKeyDown(createEvent(Key.downArrow, false, true)); mode.onKeyDown(createEvent(Key.downArrow, false, true)); mode.onKeyDown(createEvent(Key.downArrow, false, true)); verifySelection(mode, [1, 2, 3]); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 5); // Test range selection using the down arrow var expectedSelection = options.shouldBeAdditive ? [1, 2, 3] : []; mode.onKeyDown(createEvent(Key.downArrow, shiftKey, options.ctrlKey)); expectedSelection.push(5); expectedSelection.push(6); verifySelection(mode, expectedSelection); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 6); mode.onKeyDown(createEvent(Key.downArrow, shiftKey, options.ctrlKey)); expectedSelection.push(7); verifySelection(mode, expectedSelection); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 7); mode.onKeyDown(createEvent(Key.downArrow, shiftKey, options.ctrlKey)); expectedSelection.push(8); verifySelection(mode, expectedSelection); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); } [true, false].forEach(function (ctrlKey) { var shiftKeyOnly = !ctrlKey; verify({ shouldBeAdditive: shiftKeyOnly ? options.shiftArrowIsAdditive : true, site: options.createSite(), ctrlKey: ctrlKey }); }); } function blockSelectWithTap(eventObject) { eventObject.detail.preventTapBehavior(); } var oldHasWinRT; var oldRenderSelection; export class SelectionModeTests { // This is the setup function that will be called at the beginning of each test function. setUp() { LiveUnit.LoggingCore.logComment("In setup"); list = document.createElement("div"); list.id = "SelectionModeTests"; proxy = document.createElement("div"); list.appendChild(proxy); proxy.setPointerCapture = function () { }; proxy.releasePointerCapture = function () { }; list.setPointerCapture = function () { }; list.releasePointerCapture = function () { }; items = []; for (var i = 0; i < 10; ++i) { items[i] = document.createElement("div"); items[i].textContent = "Tile " + i; list.appendChild(items[i]); } document.body.appendChild(list); oldHasWinRT = WinJS.Utilities.hasWinRT; oldRenderSelection = WinJS.UI._ItemEventsHandler.renderSelection; WinJS.Utilities._setHasWinRT(false); invoked = { type: "item", index: -1 }; } tearDown() { LiveUnit.LoggingCore.logComment("In tearDown"); WinJS.Utilities._setHasWinRT(oldHasWinRT); WinJS.UI._ItemEventsHandler.renderSelection = oldRenderSelection; var element = document.getElementById("SelectionModeTests"); document.body.removeChild(element); } testStatic = function () { var mode = createMode(createSite({ selectionMode: "none", tap: "none" })); click(mode, { target: items[2] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(2, invoked.index); click(mode, { target: items[0], shiftKey: true }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[2], shiftKey: true, ctrlKey: true }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[0], ctrlKey: true }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); rightClick(mode, { target: items[0] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); }; testContentLibrarySingle = function () { var mode = createMode(createSite({ selectionMode: "single", tap: "invokeOnly" })); click(mode, { target: items[2] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(2, invoked.index); click(mode, { target: items[0], shiftKey: true }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[0], ctrlKey: true }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[2], shiftKey: true, ctrlKey: true }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[0] }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(0, invoked.index); click(mode, { target: items[0], ctrlKey: true }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); rightClick(mode, { target: items[1] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); }; testContentLibraryMulti = function () { var siteConfig = { selectionMode: "multi", tap: "invokeOnly" }; var site = createSite(siteConfig); var mode = createMode(site); click(mode, { target: items[2] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(2, invoked.index); click(mode, { target: items[0], shiftKey: true }); verifySelection(mode, [0, 1, 2]); LiveUnit.Assert.areEqual(-1, invoked.index); site._selection._pivot = 1; mode.onKeyDown(createEvent(Key.escape)); verifySelection(mode, []); LiveUnit.Assert.areEqual(WinJS.UI._INVALID_INDEX, site._selection._pivot, "Selection pivot wasn't reset when hitting escape"); click(mode, { target: items[0], ctrlKey: true }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[1], ctrlKey: true }); verifySelection(mode, [0, 1]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[1], ctrlKey: true }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[0] }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(0, invoked.index); rightClick(mode, { target: items[1] }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(-1, invoked.index); verifyRangeSelectionWithClick({ shiftLeftClickIsAdditive: false, createSite: function () { return createSite(siteConfig); } }); }; testContentLibraryMultiKeyboard = function () { var siteConfig = { selectionMode: "multi", tap: "invokeOnly" }; verifyRangeSelectionWithKeyboard({ shiftArrowIsAdditive: false, createSite: function () { return createSite(siteConfig); } }); }; testMasterDetailSingle = function () { var mode = createMode(createSite({ selectionMode: "single", tap: "directSelect" })); click(mode, { target: items[2] }); verifySelection(mode, [2]); LiveUnit.Assert.areEqual(2, invoked.index); click(mode, { target: items[1] }); verifySelection(mode, [1]); LiveUnit.Assert.areEqual(1, invoked.index); click(mode, { target: items[1] }); verifySelection(mode, [1]); LiveUnit.Assert.areEqual(1, invoked.index); click(mode, { target: items[0], shiftKey: true }); verifySelection(mode, [1]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[2], shiftKey: true, ctrlKey: true }); verifySelection(mode, [1]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[1], ctrlKey: true }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); rightClick(mode, { target: items[1] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(-1, invoked.index); list.addEventListener("selectionchanging", blockSelectWithTap, false); click(mode, { target: items[2] }); verifySelection(mode, []); list.removeEventListener("selectionchanging", blockSelectWithTap, false); }; testMasterDetailSingleKeyboard = function () { var site = createSite({ selectionMode: "single", tap: "directSelect" }); var mode = createMode(site); function verifyEvent(eventArgs, expectedSelection) { invoked = { type: "item", index: -1 }; mode.onKeyDown(createEvent.apply(null, eventArgs)); verifySelection(mode, expectedSelection); LiveUnit.Assert.areEqual(-1, invoked.index); } // These should not modify the selection verifyEvent([Key.menu], []); verifyEvent([Key.F10, true], []); // shift+F10 // These should modify the selection verifyEvent([Key.space], [0]); mode.onKeyDown(createEvent(Key.downArrow)); verifyEvent([Key.enter, false, true], [1]); // ctrl+enter }; testMasterDetailMulti = function () { var siteConfig = { selectionMode: "multi", tap: "directSelect" }; var mode = createMode(createSite(siteConfig)); click(mode, { target: items[2] }); verifySelection(mode, [2]); LiveUnit.Assert.areEqual(2, invoked.index); click(mode, { target: items[1] }); verifySelection(mode, [1]); LiveUnit.Assert.areEqual(1, invoked.index); click(mode, { target: items[1] }); verifySelection(mode, [1]); LiveUnit.Assert.areEqual(1, invoked.index); click(mode, { target: items[0], shiftKey: true }); verifySelection(mode, [0, 1]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[2], ctrlKey: true }); verifySelection(mode, [0, 1, 2]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[2], ctrlKey: true }); verifySelection(mode, [0, 1]); LiveUnit.Assert.areEqual(-1, invoked.index); rightClick(mode, { target: items[2] }); verifySelection(mode, [0, 1]); LiveUnit.Assert.areEqual(-1, invoked.index); list.addEventListener("selectionchanging", blockSelectWithTap, false); click(mode, { target: items[2] }); verifySelection(mode, [0, 1]); list.removeEventListener("selectionchanging", blockSelectWithTap, false); verifyRangeSelectionWithClick({ shiftLeftClickIsAdditive: false, createSite: function () { return createSite(siteConfig); } }); }; testMasterDetailMultiKeyboard = function () { var siteConfig = { selectionMode: "multi", tap: "directSelect" }; verifyRangeSelectionWithKeyboard({ shiftArrowIsAdditive: false, createSite: function () { return createSite(siteConfig); } }); }; testPickerSingleMode = function () { var mode = createMode(createSite({ selectionMode: "single", tap: "toggleSelect" })); click(mode, { target: items[2] }); verifySelection(mode, [2]); LiveUnit.Assert.areEqual(2, invoked.index); click(mode, { target: items[0], shiftKey: true }); verifySelection(mode, [2]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[3], shiftKey: true, ctrlKey: true }); verifySelection(mode, [2]); LiveUnit.Assert.areEqual(-1, invoked.index); click(mode, { target: items[0] }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(0, invoked.index); click(mode, { target: items[0] }); verifySelection(mode, []); LiveUnit.Assert.areEqual(0, invoked.index); list.addEventListener("selectionchanging", blockSelectWithTap, false); click(mode, { target: items[2] }); verifySelection(mode, []); list.removeEventListener("selectionchanging", blockSelectWithTap, false); }; testPickerSingleModeKeyboard = function () { var site = createSite({ selectionMode: "single", tap: "toggleSelect" }); var mode = createMode(site); mode.onKeyDown(createEvent(Key.space)); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 2); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.upArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.leftArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.rightArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 4); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 5); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 6); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 7); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.rightArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.rightArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.home)); mode.onKeyDown(createEvent(Key.space)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 0); verifySelection(mode, []); mode.onKeyDown(createEvent(Key.end)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); verifySelection(mode, []); }; testPickerMultiMode = function () { var siteConfig = { selectionMode: "multi", tap: "toggleSelect" }; var mode = createMode(createSite(siteConfig)); click(mode, { target: items[0] }); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(0, invoked.index); click(mode, { target: items[3] }); verifySelection(mode, [0, 3]); LiveUnit.Assert.areEqual(3, invoked.index); click(mode, { target: items[5], shiftKey: true }); verifySelection(mode, [0, 3, 4, 5]); click(mode, { target: items[5] }); verifySelection(mode, [0, 3, 4]); list.addEventListener("selectionchanging", blockSelectWithTap, false); click(mode, { target: items[2] }); verifySelection(mode, [0, 3, 4]); list.removeEventListener("selectionchanging", blockSelectWithTap, false); verifyRangeSelectionWithClick({ shiftLeftClickIsAdditive: true, createSite: function () { return createSite(siteConfig); } }); }; testPickerMultiModeKeyboard = function () { var siteConfig = { selectionMode: "multi", tap: "toggleSelect" }; var site = createSite(siteConfig); var mode = createMode(site); verifySelection(mode, []); mode.onKeyDown(createEvent(Key.space)); mode.onKeyDown(createEvent(Key.downArrow)); verifySelection(mode, [0]); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [0, 1]); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [0]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 2); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [0, 2]); mode.onKeyDown(createEvent(Key.upArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [0, 1, 2]); mode.onKeyDown(createEvent(Key.leftArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 1); verifySelection(mode, [0, 1, 2]); mode.onKeyDown(createEvent(Key.rightArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 4); verifySelection(mode, [0, 1, 2]); mode.onKeyDown(createEvent(Key.downArrow)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 5); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [0, 1, 2, 5]); mode.onKeyDown(createEvent(Key.home)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 0); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [1, 2, 5]); mode.onKeyDown(createEvent(Key.end)); LiveUnit.Assert.areEqual(site.keyboardFocusedItem.index, 8); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [1, 2, 5, 8]); mode.onKeyDown(createEvent(Key.space)); verifySelection(mode, [1, 2, 5]); verifyRangeSelectionWithKeyboard({ shiftArrowIsAdditive: true, createSite: function () { return createSite(siteConfig); } }); }; // Ensure that onContextMenu calls preventDefault when an item is clicked and the selection mode is not none testContextMenu = function () { function testWithSelectionMode(selectionMode) { var mode = createMode(createSite({ selectionMode: selectionMode, tap: "none" })), eventObject; eventObject = eventOnElement(items[0]); mode.onContextMenu(eventObject); LiveUnit.Assert.areEqual(eventObject.defaultPrevented, selectionMode !== "none"); eventObject = eventOnElement(list); mode.onContextMenu(eventObject); LiveUnit.Assert.areEqual(eventObject.defaultPrevented, false); } testWithSelectionMode("none"); testWithSelectionMode("single"); testWithSelectionMode("multi"); }; } var generatePickerMultiModeUITests = function generatePickerMultiModeUITests() { [ { name: "GridLayout", type: WinJS.UI.GridLayout, orientation: WinJS.UI.Orientation.vertical }, { name: "ListLayout", type: WinJS.UI.ListLayout } ].forEach(function (layoutDescriptor: any) { SelectionModeTests.prototype["testPickerMultiModeUI_" + layoutDescriptor.name] = function () { var lv = new WinJS.UI.ListView(undefined, { selectionMode: WinJS.UI.SelectionMode.none, tapBehavior: WinJS.UI.TapBehavior.invokeOnly, layout: layoutDescriptor }); LiveUnit.Assert.areEqual(0, lv.element.querySelectorAll("." + WinJS.UI._selectionModeClass).length); lv.selectionMode = WinJS.UI.SelectionMode.multi; lv.tapBehavior = WinJS.UI.TapBehavior.toggleSelect; LiveUnit.Assert.areEqual(1, lv.element.querySelectorAll("." + WinJS.UI._selectionModeClass).length); lv.selectionMode = WinJS.UI.SelectionMode.none; LiveUnit.Assert.areEqual(0, lv.element.querySelectorAll("." + WinJS.UI._selectionModeClass).length); lv.selectionMode = WinJS.UI.SelectionMode.multi; lv.tapBehavior = WinJS.UI.TapBehavior.invokeOnly; LiveUnit.Assert.areEqual(0, lv.element.querySelectorAll("." + WinJS.UI._selectionModeClass).length); }; }); }; generatePickerMultiModeUITests(); var generateDataChangeInSelChangedHandler = function (layoutName) { SelectionModeTests.prototype["testDataChangeInSelChangedHandler" + layoutName] = function (complete) { function test(tap, ctrl?) { return new WinJS.Promise(function (complete) { LiveUnit.LoggingCore.logComment("testing " + tap + " mode"); var myData = []; for (var i = 0; i < 10; ++i) { myData.push({ title: "Tile" + i }); } var newNode = document.createElement("div"); newNode.style.width = "1000px"; newNode.style.height = "600px"; document.body.appendChild(newNode); var listView = new ListView(newNode, { itemDataSource: (new WinJS.Binding.List(myData)).dataSource, selectionMode: "multi", tapBehavior: tap }); listView.addEventListener("selectionchanged", function (eventObject) { listView.itemDataSource = (new WinJS.Binding.List([])).dataSource; listView.layout = new WinJS.UI[layoutName](); }); listView._canvas.setPointerCapture = function () { }; Helper.ListView.runTests(listView, [ function () { LiveUnit.Assert.areEqual(myData.length, newNode.querySelectorAll(".win-item").length); click(listView._currentMode(), { target: listView.elementFromIndex(1), ctrlKey: ctrl }); return true; }, function () { LiveUnit.Assert.areEqual(0, newNode.querySelectorAll(".win-item").length); document.body.removeChild(newNode); complete(); } ]); }); } test("invokeOnly", true).then(function () { if (WinJS.Utilities.isPhone) { return WinJS.Promise.wrap(); } else { return test("directSelect"); } }).then(function () { return test("toggleSelect"); }).then(complete); }; }; generateDataChangeInSelChangedHandler("GridLayout"); } // register the object as a test class by passing in the name LiveUnit.registerTestClass("WinJSTests.SelectionModeTests");