// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information.
///
module Helper.ListView {
"use strict";
var utilities = WinJS.Utilities,
constants = {
dimensions: {
itemHeight: 70,
itemWidth: 70,
},
aria: {
listViewRole: "listbox",
itemRole: "option",
multiSelectable: {
true: "true",
false: "false"
}
}
};
export var templates = {
syncJSTemplate: function (itemPromise) {
return itemPromise.then(function (item) {
var element = document.createElement("div");
element.id = item.data.title;
utilities.addClass(element, "syncJSTemplate");
element.style.width = item.data.itemWidth;
element.style.height = item.data.itemHeight;
element.innerHTML = "
" + item.data.title + "
";
return element;
});
},
asyncJSTemplate: function (itemPromise) {
return itemPromise.then(function (item) {
// TODO: Fill in the details later
});
}
};
export function defaultOptions() {
return {
selectionMode: WinJS.UI.SelectionMode.multi,
tapBehavior: WinJS.UI.TapBehavior.invokeOnly,
scrollPosition: 0
};
};
export function _ASSERT(condition) {
LiveUnit.Assert.isTrue(!!condition);
}
export function _TRACE(text) {
LiveUnit.LoggingCore.logComment(text);
}
WinJS.UI['ListDataSource'] = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function (listDataAdapter) {
this._baseDataSourceConstructor(listDataAdapter);
});
export function checkAttribute(element, attribute, expectedValue) {
var values = element.getAttribute(attribute).match(expectedValue),
value = values ? values[0] : null;
LiveUnit.Assert.areEqual(value, expectedValue, "Expected " + attribute + ": " + expectedValue +
" Actual: " + value);
}
// Returns a number between 0 to parameter
export function randomNumber(upto) {
return Math.floor(Math.random() * (upto + 1));
};
export function validateListView(listView) {
// Check properties and methods
LiveUnit.Assert.isTrue(listView);
LiveUnit.Assert.isTrue(listView.itemDataSource);
LiveUnit.Assert.isTrue(listView.layout);
LiveUnit.Assert.isTrue(listView.selectionMode);
LiveUnit.Assert.isTrue(listView.tapBehavior);
LiveUnit.Assert.isTrue(listView.loadingState);
LiveUnit.Assert.isTrue(listView.selection);
LiveUnit.Assert.isTrue(listView.tapBehavior);
LiveUnit.Assert.isTrue(listView.zoomableView);
LiveUnit.Assert.isTrue(listView.itemTemplate && (typeof listView.itemTemplate === "function"));
LiveUnit.Assert.isTrue(listView.addEventListener && (typeof listView.addEventListener === "function"));
LiveUnit.Assert.isTrue(listView.removeEventListener && (typeof listView.removeEventListener === "function"));
LiveUnit.Assert.isTrue(listView.elementFromIndex && (typeof listView.elementFromIndex === "function"));
LiveUnit.Assert.isTrue(listView.indexOfElement && (typeof listView.indexOfElement === "function"));
LiveUnit.Assert.isTrue(listView.ensureVisible && (typeof listView.ensureVisible === "function"));
LiveUnit.Assert.isTrue(listView.forceLayout && (typeof listView.forceLayout === "function"));
var element = listView.element,
viewport = listView._viewport,
surface = listView._canvas;
// Check for proper css classes
checkAttribute(element, "class", WinJS.UI._listViewClass);
checkAttribute(viewport, "class", WinJS.UI._viewportClass);
var horizontal;
horizontal = (listView.layout.orientation === "horizontal");
checkAttribute(viewport, "class", (horizontal ? WinJS.UI._horizontalClass : WinJS.UI._verticalClass));
checkAttribute(surface, "class", WinJS.UI._scrollableClass);
// Check for accessibility attributes
// 592099 ListView needs to set the aria attributes on the DOM elements before the loadingState is set to complete
// TODO: Uncomment following lines after the above bug is fixed
//checkAttribute(element, "role", constants.aria.listViewRole);
//checkAttribute(element, "aria-multiselectable", ((listView.selectionMode === "multi") ? "true" : "false"));
return true;
}
export function validateResetFocusState(listView, context, listViewIsEmpty = false) {
var childFocus = listView._tabManager.childFocus;
LiveUnit.Assert.areEqual(0, listView.currentItem.index, "ListView's currentItem wasn't reset " + context);
if (listViewIsEmpty) {
LiveUnit.Assert.areEqual(null, childFocus, "_tabManager's childFocus wasn't reset " + context);
} else {
LiveUnit.Assert.isTrue(childFocus === listView.elementFromIndex(0) || childFocus === null, "_tabManager's childFocus wasn't reset " + context);
}
}
export function waitForDeferredAction(listView) {
if (listView.winControl) { listView = listView.winControl; }
return function (x?) {
return new WinJS.Promise(function (complete) {
function waitForDeferredAction_handler() {
listView.removeEventListener("accessibilityannotationcomplete", waitForDeferredAction_handler, false);
WinJS.Utilities._setImmediate(function () {
complete(x);
});
}
listView.addEventListener("accessibilityannotationcomplete", waitForDeferredAction_handler, false);
});
}
}
export function waitForReady(listView, delay?) {
if (listView.winControl) { listView = listView.winControl; }
return function (x?): WinJS.Promise {
return new WinJS.Promise(function (c, e, p) {
function waitForReady_handler() {
LiveUnit.LoggingCore.logComment("waitForReady_handler, listView.loadingState:" + listView.loadingState);
if (listView.loadingState === "complete") {
listView.removeEventListener("loadingstatechanged", waitForReady_handler, false);
waitForReady_work();
}
}
function waitForReady_work() {
if (listView._versionManager.locked) {
listView._versionManager.unlocked.then(waitForReady_work);
} else if (listView.loadingState !== "complete") {
listView.addEventListener("loadingstatechanged", waitForReady_handler, false);
} else {
WinJS.Utilities.Scheduler.schedulePromiseIdle(null, "ListViewWaitForReadyComplete").then(function () {
c(x);
});
}
}
function waitForReady_start() {
WinJS.Utilities.Scheduler.schedulePromiseIdle(null, "ListViewWaitForReady").then(waitForReady_work);
}
LiveUnit.LoggingCore.logComment("listView.loadingState: " + listView.loadingState);
if (delay) {
if (delay < 0) {
WinJS.Utilities._setImmediate(waitForReady_start);
} else {
setTimeout(waitForReady_start, delay);
}
} else {
waitForReady_work();
}
});
};
}
export function waitForState(listView, state, delay) {
if (listView.winControl) { listView = listView.winControl; }
return function (x?) {
return new WinJS.Promise(function (c, e, p) {
function waitForReady_handler() {
LiveUnit.LoggingCore.logComment("waitForReady_handler: ListView loadingState = " + listView.loadingState);
if (listView.loadingState === state) {
listView.removeEventListener("loadingstatechanged", waitForReady_handler, false);
c(x);
}
}
function waitForReady_work() {
LiveUnit.LoggingCore.logComment("waitForReady_work ListView loadingState = " + listView.loadingState);
if (listView.loadingState !== state) {
listView.addEventListener("loadingstatechanged", waitForReady_handler, false);
}
else {
c(x);
}
}
if (delay) {
if (delay < 0) {
WinJS.Utilities._setImmediate(waitForReady_work);
}
else {
setTimeout(waitForReady_work, delay);
}
}
else {
waitForReady_work();
}
});
}
}
export function waitForAllContainers(listView) {
if (listView.winControl) { listView = listView.winControl; }
return waitForReady(listView, -1)().then(function () {
return listView._view._creatingContainersWork ? listView._view._creatingContainersWork.promise : null;
}).then(function () {
return listView._view._getLayoutCompleted();
}).then(function () {
return waitForReady(listView, -1)();
});
}
export function waitForNotReady(listView) {
if (listView.winControl) { listView = listView.winControl; }
return function (x) {
return new WinJS.Promise(function (c, e, p) {
function waitForNotReady_handler() {
if (listView.loadingState !== 'complete') {
listView.removeEventListener('loadingstatechanged', waitForNotReady_handler);
c(x);
}
}
if (listView.loadingState === 'complete') {
listView.addEventListener('loadingstatechanged', waitForNotReady_handler);
} else {
c(x);
}
});
}
}
export function whenLoadingComplete(listview, func) {
function checkAndExecute() {
if (listview.loadingState === "complete") {
func();
}
}
listview.addEventListener("loadingstatechanged", LiveUnit.GetWrappedCallback(checkAndExecute), false);
checkAndExecute();
}
export function runTests(listview, tests) {
var current = 0;
function stateChanged() {
while (current < tests.length && listview.loadingState === "complete") {
LiveUnit.LoggingCore.logComment("executing test " + current);
if (tests[current++]()) {
break;
}
}
}
WinJS.Utilities._setImmediate(function () {
whenLoadingComplete(listview, stateChanged);
});
}
export function createAsyncRenderer(templateId, width, height, targetId?, delay?) {
var templateElement = document.getElementById(templateId).cloneNode(true);
templateElement.id = "";
var templateText = templateElement.innerHTML;
function process(item) {
var pattern = /{{(\w+)}}/g;
return templateText.replace(pattern, function (str, field) {
var value = item.data[field];
return value !== undefined ? value : str;
});
}
return function renderer(itemPromise) {
var element = templateElement.cloneNode(false);
element.style.width = width + "px";
element.style.height = height + "px";
element.style.display = "block";
element.textContent = "Loading";
var renderComplete = itemPromise.then(function (item) {
element.innerHTML = process(item);
if (targetId) {
element.id = targetId + item.index;
}
return WinJS.Promise.timeout(delay);
});
return {
element: element,
renderComplete: renderComplete
};
};
}
export function createRenderer(templateId, targetId?) {
var element = document.getElementById(templateId).cloneNode(true);
element.id = "";
var temp = element.outerHTML;
return function renderer(itemPromise) {
return itemPromise.then(function (item) {
var pattern = /{{(\w+)}}/g;
var text = temp.replace(pattern, function (str, field) {
var value = item.data[field];
return value !== undefined ? value : str;
});
var element: HTMLElement = document.createElement("div");
element.innerHTML = text;
element = element.firstChild;
element.style.display = "block";
if (targetId) {
element.id = targetId + item.index;
}
return element;
});
};
}
export function viewport(element) {
return element.winControl._viewport;
}
export function canvas(element) {
return element.winControl._canvas;
}
export function itemCanvas(element) {
return element.winControl._itemCanvas;
}
export function extend(target, source) {
target = target || {};
for (var fieldname in source) {
if (!target.hasOwnProperty(fieldname)) {
target[fieldname] = source[fieldname];
}
}
return target;
}
export function getDataObjects(dataSource, indices) {
var listBinding = dataSource.createListBinding(),
promises = [];
for (var i = 0; i < indices.length; ++i) {
promises.push(listBinding.fromIndex(indices[i]));
}
return WinJS.Promise.join(promises).then(function (items) {
listBinding.release();
return items;
});
}
export function getRealizedCount(element) {
var containers = element.querySelectorAll("." + WinJS.UI._containerClass),
count = 0;
for (var i = 0; i < containers.length; i++) {
count += containers[i].childNodes.length ? 1 : 0;
}
return count;
}
export function getItemsCount(canvas) {
var count = 0;
for (var i = 0; i < canvas.childNodes.length; i++) {
if (canvas.childNodes[i].className.indexOf(WinJS.UI._containerClass) !== -1 && canvas.childNodes[i].innerHTML !== "") {
count++;
}
}
return count;
}
export function elementsEqual(expectedArray, actualArray) {
if (expectedArray === actualArray) {
return;
}
if ((expectedArray === undefined && actualArray !== undefined) ||
(expectedArray !== undefined && actualArray === undefined)) {
LiveUnit.Assert.isTrue(false);
}
if ((expectedArray === null && actualArray !== null) ||
(expectedArray !== null && actualArray === null)) {
LiveUnit.Assert.isTrue(false);
}
LiveUnit.Assert.areEqual(expectedArray.length, actualArray.length);
for (var i = 0; i < expectedArray.length; i++) {
LiveUnit.Assert.areEqual(expectedArray[i], actualArray[i]);
}
}
export function setItemsOut(rtl, affectedItems, inserted, removed) {
var positionProperty = (rtl ? "right" : "left");
function forEachItem(map, callback) {
var itemIDs = Object.keys(map);
for (var i = 0; i < itemIDs.length; i++) {
callback(map[itemIDs[i]]);
}
}
forEachItem(affectedItems, function (record) {
record.element.style[positionProperty] = record.left + "px";
record.element.style.top = record.top + "px";
});
forEachItem(removed, function (record) {
if (record.element.parentNode) {
record.element.parentNode.removeChild(record.element);
}
});
forEachItem(inserted, function (record) {
record.element.style.opacity = 1.0;
});
}
export function containerFrom(element) {
while (element && !WinJS.Utilities.hasClass(element, WinJS.UI._containerClass)) {
element = element.parentNode;
}
return element;
}
export function headerContainerFrom(listView, element) {
var layout = listView.layout;
while (element && !WinJS.Utilities.hasClass(element, WinJS.UI._headerContainerClass)) {
element = element.parentNode;
}
return element;
}
export function offsetLeftFromSurface(listView, element) {
return WinJS.Utilities.getPosition(element).left - WinJS.Utilities.getPosition(listView._canvas).left;
}
export function offsetRightFromSurface(listView, element) {
var surfacePos: any = WinJS.Utilities.getPosition(listView._canvas),
elementPos: any = WinJS.Utilities.getPosition(element);
surfacePos.right = surfacePos.left + surfacePos.width;
elementPos.right = elementPos.left + elementPos.width;
return surfacePos.right - elementPos.right;
}
export function offsetTopFromSurface(listView, element) {
return WinJS.Utilities.getPosition(element).top - WinJS.Utilities.getPosition(listView._canvas).top;
}
export function getBasicColorString(rVal, gVal, bVal) {
rVal = ((rVal || 0) % 16).toString(16);
gVal = ((gVal || 0) % 16).toString(16);
bVal = ((bVal || 0) % 16).toString(16);
return "#" + rVal + rVal + gVal + gVal + bVal + bVal;
}
export function getBasicDataSource(itemsCount, grouped, itemsPerGroup): WinJS.Binding.ListBaseWithMutators {
var rawData = [];
for (var i = 0; i < itemsCount; i++) {
rawData.push({ index: i });
}
var list = new WinJS.Binding.List(rawData);
if (!grouped) {
return list;
}
return list.createGrouped(function (item) {
return "Group" + Math.floor(item.index / itemsPerGroup);
}, function (item) {
return { title: "Group" + Math.floor(item.index / itemsPerGroup) };
});
}
export function basicRenderer(itemPromise) {
var element = document.createElement("div");
return {
element: element,
renderComplete: itemPromise.then(function (item) {
element.textContent = "Item" + item.data.index;
element.style.backgroundColor = getBasicColorString(0, 0, item.data.index);
})
};
}
export function basicHeaderRenderer(itemPromise) {
var element = document.createElement("div");
return {
element: element,
renderComplete: itemPromise.then(function (item) {
element.textContent = item.data.title;
element.style.backgroundColor = getBasicColorString(0, 15, item.data.index);
})
};
}
export function calcExpectedItemBarAndSlot(itemIndex, options) {
if (options.grouped) {
var itemGroup = Math.floor(itemIndex / options.itemsPerGroup);
itemIndex -= (options.itemsPerGroup * itemGroup);
}
var barInGroup = Math.floor(itemIndex / options.itemsPerBar);
var slotInBar = itemIndex % options.itemsPerBar;
return {
bar: barInGroup,
slot: slotInBar,
}
}
export function calcExpectedItemStart(itemIndex, options) {
var itemGroup = 0,
barsPerGroup = 0;
if (options.grouped) {
itemGroup = Math.floor(itemIndex / options.itemsPerGroup);
barsPerGroup = Math.ceil(options.itemsPerGroup / options.itemsPerBar);
itemIndex -= (options.itemsPerGroup * itemGroup);
}
var barInGroup = Math.floor(itemIndex / options.itemsPerBar);
return ((options.headersInline ? options.headerSize : 0) + barInGroup * options.itemSize) +
(options.grouped ? (itemGroup * ((options.headersInline ? options.headerSize : 0) + barsPerGroup * options.itemSize)) : 0) +
(options.grouped ? ((itemGroup + 1) * options.groupLeaderOffset) : 0) +
(options.horizontal ? options.canvasMargins[options.rtl ? "right" : "left"] : options.canvasMargins.top);
}
export function calcExpectedItemEnd(itemIndex, options) {
return calcExpectedItemStart(itemIndex, options) + options.itemSize;
}
export function computeExpectedLayoutInformation(options) {
var currentAbsoluteIndex = 0;
var currentPosition = options.groupLeaderOffset + (options.horizontal ? options.canvasMargins.left : options.canvasMargins.top);
var layoutInfo = {
horizontal: options.horizontal,
groupsInfo: [],
grouped: options.grouped,
headersInline: options.headersInline,
itemsPerBar: options.itemsPerBar,
itemsCount: options.itemsCount,
itemsPerGroup: options.itemsPerGroup
};
options.itemSize = options.horizontal ? options.totalItemWidth : options.totalItemHeight;
for (var i = 0; i < options.groupsCount; i++) {
layoutInfo.groupsInfo.push({
start: currentPosition,
bars: [],
items: []
});
for (var j = 0; j < options.maxGroupSize && currentAbsoluteIndex < options.itemsCount; j++) {
var itemLayoutLocation = calcExpectedItemBarAndSlot(currentAbsoluteIndex, options);
var expectedStart = calcExpectedItemStart(currentAbsoluteIndex, options);
var expectedEnd = calcExpectedItemEnd(currentAbsoluteIndex, options);
var itemDetails = {
start: expectedStart,
end: expectedEnd,
bar: itemLayoutLocation.bar,
slot: itemLayoutLocation.slot,
absoluteIndex: currentAbsoluteIndex,
left: (options.horizontal ? expectedStart : (options.canvasMargins.top + itemLayoutLocation.slot * options.totalItemWidth + (options.grouped && !options.headersInline ? options.headerSize : 0))),
top: (!options.horizontal ? expectedStart : (options.canvasMargins[options.rtl ? "right" : "left"] + itemLayoutLocation.slot * options.totalItemHeight + (options.grouped && !options.headersInline ? options.headerSize : 0))),
itemWidth: null,
itemHeight: null
};
itemDetails.left += options.itemMargins.left;
itemDetails.top += options.itemMargins.top;
itemDetails.itemWidth = options.totalItemWidth - (options.itemMargins.left + options.itemMargins.right);
itemDetails.itemHeight = options.totalItemHeight - (options.itemMargins.top + options.itemMargins.bottom);
currentPosition = Math.max(currentPosition, expectedStart);
if (layoutInfo.groupsInfo[i].bars.length <= itemLayoutLocation.bar) {
layoutInfo.groupsInfo[i].bars.push([]);
}
layoutInfo.groupsInfo[i].bars[itemDetails.bar].push(itemDetails);
layoutInfo.groupsInfo[i].items.push(itemDetails);
currentAbsoluteIndex++;
}
layoutInfo.groupsInfo[i].end = currentPosition = layoutInfo.groupsInfo[i].items[layoutInfo.groupsInfo[i].items.length - 1].end;
}
return layoutInfo;
}
export var uniqueCounter = 0;
export function addStylesForView(root, options) {
var styleElement = document.createElement("style");
document.head.appendChild(styleElement);
if (!root.id) {
root.id = WinJS.Utilities._uniqueID(root);
}
var styleClass = "generatedListView" + uniqueCounter++;
WinJS.Utilities.addClass(root, styleClass);
var rootClass = "#" + root.id + "." + styleClass;
var rules = [rootClass + " {width: " + options.viewWidth + "px; height: " + options.viewHeight + "px;}",
rootClass + " .win-surface {margin: " + options.canvasMargins.top + "px " + options.canvasMargins.right + "px " + options.canvasMargins.bottom + "px " + options.canvasMargins.left + "px;}",
rootClass + " .win-container {margin: " + options.itemMargins.top + "px " + options.itemMargins.right + "px " + options.itemMargins.bottom + "px " + options.itemMargins.left + "px;}",
rootClass + " .win-container, .win-item {width: " + options.itemWidth + "px; height: " + options.itemHeight + "px;}"
];
if (options.grouped) {
rules.push(rootClass + " .win-groupheadercontainer, .win-groupheader {width: " + options.headerSize + "px; height: " + options.headerSize + "px;padding: 0;}");
rules.push(rootClass + " .win-horizontal .win-groupleader {" + (options.rtl ? "margin-right" : "margin-left") + ": " + options.groupLeaderOffset + "px;}");
rules.push(rootClass + " .win-vertical .win-groupleader {margin-top: " + options.groupLeaderOffset + "px;}");
}
var sheet = styleElement.sheet;
for (var i = 0; i < rules.length; i++) {
sheet.insertRule(rules[i], sheet.cssRules.length);
}
return styleElement;
}
export var defaultItemSize = 100;
export var defaultHeaderSize = 100;
export var defaultItemsCount = 100;
export var defaultItemsPerGroup = 10;
export var defaultViewWidth = 500;
export var defaultViewHeight = 500;
export var defaultGroupLeaderOffset = 100;
export var defaultListOrientation = "vertical";
export var defaultGridOrientation = "horizontal";
export var defaultLayout = "GridLayout";
export var defaultMargins = { left: 0, right: 0, top: 0, bottom: 0 };
export var defaultHeadersAbove = false;
export function getMarginOptions(marginsProvided) {
marginsProvided = marginsProvided || { left: 0, right: 0, top: 0, bottom: 0 };
if (marginsProvided.left === undefined) {
marginsProvided.left = defaultMargins.left;
}
if (marginsProvided.right === undefined) {
marginsProvided.right = defaultMargins.right;
}
if (marginsProvided.top === undefined) {
marginsProvided.top = defaultMargins.top;
}
if (marginsProvided.bottom === undefined) {
marginsProvided.bottom = defaultMargins.bottom;
}
return marginsProvided;
}
export function buildGenericListView(root, options) {
options = options || {};
options.itemWidth = options.itemWidth || defaultItemSize;
options.itemHeight = options.itemHeight || defaultItemSize;
options.itemsCount = options.itemsCount || defaultItemsCount;
options.itemMargins = getMarginOptions(options.itemMargins);
options.canvasMargins = getMarginOptions(options.canvasMargins);
options.layout = options.layout || defaultLayout;
options.rtl = options.rtl || false;
options.itemTemplate = options.itemTemplate || basicRenderer;
options.viewWidth = options.viewWidth || defaultViewWidth;
options.viewHeight = options.viewHeight || defaultViewHeight;
if (options.grouped) {
options.headerSize = options.headerSize || defaultHeaderSize;
options.itemsPerGroup = options.itemsPerGroup || defaultItemsPerGroup;
options.headerTemplate = options.headerTemplate || basicHeaderRenderer;
options.headersAbove = (options.headersAbove !== undefined ? !!options.headersAbove : defaultHeadersAbove);
options.groupLeaderOffset = (options.groupLeaderOffset !== undefined ? options.groupLeaderOffset : defaultGroupLeaderOffset);
}
var usingListLayout = (options.layout === "ListLayout");
options.orientation = options.orientation || (usingListLayout ? defaultListOrientation : defaultGridOrientation);
options.horizontal = (options.orientation === "horizontal");
options.totalItemHeight = options.itemHeight + options.itemMargins.top + options.itemMargins.bottom;
options.totalItemWidth = options.itemWidth + options.itemMargins.left + options.itemMargins.right;
if (options.forceOneItemPerBar || usingListLayout) {
if (options.horizontal) {
var totalAvailableHeight = options.viewHeight - options.canvasMargins.top;
if (options.grouped && options.headersAbove) {
totalAvailableHeight -= options.headerSize;
}
if (options.forceOneItemPerBar) {
options.canvasMargins.bottom = totalAvailableHeight - options.totalItemHeight;
} else {
options.itemHeight = totalAvailableHeight;
}
} else {
var totalAvailableWidth = options.viewWidth - options.canvasMargins.left;
if (options.grouped && !options.headersAbove) {
totalAvailableWidth -= options.headerSize;
}
if (options.forceOneItemPerBar) {
options.canvasMargins.right = totalAvailableWidth - options.totalItemWidth;
} else {
options.itemWidth = totalAvailableWidth;
}
}
}
options.availableLayoutWidth = options.viewWidth - (options.canvasMargins.left + options.canvasMargins.right);
options.availableLayoutHeight = options.viewHeight - (options.canvasMargins.top + options.canvasMargins.bottom);
options.expectedItemsPerBar = (usingListLayout ? 1 : (options.horizontal ? Math.floor(options.availableLayoutHeight / options.totalItemHeight) : Math.floor(options.availableLayoutWidth / options.totalItemWidth)));
options.headersInline = (options.grouped ? ((options.horizontal && !options.headersAbove) || (!options.horizontal && options.headersAbove)) : false);
options.itemsPerBar = Math.max((options.headersInline || !options.grouped ? options.expectedItemsPerBar : options.expectedItemsPerBar - 1), 1);
options.groupsCount = (options.grouped ? Math.ceil(options.itemsCount / options.itemsPerGroup) : 1);
options.lastBarInGroup = (options.grouped ? Math.floor(options.itemsPerGroup / options.itemsPerBar) : Math.floor(options.itemsCount / options.itemsPerBar));
options.maxGroupSize = (options.grouped ? options.itemsPerGroup : options.itemsCount);
if (options.rtl) {
var temp = options.itemMargins.left;
options.itemMargins.left = options.itemMargins.right;
options.itemMargins.right = temp;
temp = options.canvasMargins.left;
options.canvasMargins.left = options.canvasMargins.right;
options.canvasMargins.right = temp;
}
var layoutInfo = computeExpectedLayoutInformation(options);
var styleElement = addStylesForView(root, options);
root.style.direction = options.rtl ? "rtl" : "ltr";
var bindingList = > getBasicDataSource(options.itemsCount, options.grouped, options.itemsPerGroup);
var layoutOptions: any = {
orientation: options.orientation
};
var viewOptions: any = {
itemDataSource: bindingList.dataSource,
itemTemplate: options.itemTemplate,
};
if (options.grouped) {
layoutOptions.groupHeaderPosition = (options.headersAbove ? WinJS.UI.HeaderPosition.top : WinJS.UI.HeaderPosition.left);
viewOptions.groupDataSource = bindingList.groups.dataSource;
viewOptions.groupHeaderTemplate = options.headerTemplate;
}
viewOptions.layout = new WinJS.UI[options.layout](layoutOptions);
var listView = new WinJS.UI.ListView(root, viewOptions);
var originalDispose = listView.dispose.bind(listView);
listView.dispose = function () {
originalDispose();
document.head.removeChild(styleElement);
};
return {
listView: listView,
layoutInfo: layoutInfo
};
}
export function skipFirstAnimation(listView) {
var firstAnimation = true;
listView.addEventListener("contentanimating", function (eventObject) {
if (firstAnimation) {
firstAnimation = false;
eventObject.preventDefault();
}
});
}
}