define('application/widgets/masonrygrid', [
'rofl/widgets/horizontallist',
'rofl/widgets/verticallist',
'rofl/lib/utils',
'application/utils'
], function (
HorizontalList,
VerticalList,
Utils,
AppUtils
) {
'use strict';
return HorizontalList.extend({
/**
* Initialises the MasonryGrid.
*
* @param {Object} config - The configuration.
* @param {number} config.columns - The columns needed.
* @param {Array} config.types - The types of grid items.
*/
init: function init (config) {
init.base.call(this);
this.addClass(['masonrygrid']);
this._configuration = config;
this._onSelectedItemChangeBound = Utils.bind(this._onSelectedItemChange, this);
this.setContinuousListener(true);
this._setEventListeners();
},
/**
* Sets the event listeners.
*
* @private
*/
_setEventListeners: function () {
this.addEventListener('selecteditemchange', this._onSelectedItemChangeBound);
},
/**
* Removes the event listeners.
*
* @private
*/
_removeEventListeners: function () {
this.removeEventListener('selecteditemchange', this._onSelectedItemChangeBound);
},
/**
* Sets the data item.
*
* @param {Array} items - The item data.
*/
setDataItem: function setDataItem (items) {
setDataItem.base.call(this, items);
Utils.each(this.getChildWidgets(), function (widget) {
widget.dispose();
});
this.removeChildWidgets();
this._currentItemHeight = 0;
this._items = [];
this._heights = [];
this._generateColumns();
this._appendItems(items);
},
/**
* Generates the columns needed.
*
* @private
*/
_generateColumns: function () {
var amountOfColumns = this._configuration.columns,
i;
for (i = 0; i < amountOfColumns; i++) {
this._appendColumn();
}
},
/**
* Appends a column.
*
* @private
*/
_appendColumn: function () {
var column = new VerticalList();
column.addClass('column');
column.setContinuousListener(true);
this.appendChildWidget(column);
},
/**
* Appends the items.
*
* @param {Array} items - The items.
* @private
*/
_appendItems: function (items) {
var amountOfColumns = this._configuration.columns,
itemsPerRow = Math.floor(items.length / amountOfColumns),
self = this,
currentColumn,
currentItems,
i;
for (i = 0; i < amountOfColumns; i++) {
currentColumn = this.getChildWidgetByIndex(i);
currentItems = this._generateItems(items.splice(0, itemsPerRow));
this._items[i] = currentItems;
this._heights[i] = [];
// eslint-disable-next-line no-loop-func
Utils.each(currentItems, function (item) {
self._heights[i].push(item.height);
currentColumn.appendChildWidget(item.widget);
});
}
},
/**
* Generates the items.
*
* @param {Array} items - The item data.
* @returns {Array} - The formatted items randomised.
* @private
*/
_generateItems: function (items) {
var types = this._configuration.types,
formattedItems = [],
lastItemIndex = 0,
itemsOfType;
Utils.each(types, Utils.bind(function (type) {
itemsOfType = Math.round((items.length / 100) * type.percentage);
formattedItems = formattedItems.concat(this._generateItemsPerType(type, items.slice(lastItemIndex, lastItemIndex + itemsOfType - 1)));
lastItemIndex = lastItemIndex + itemsOfType;
}, this));
return AppUtils.randomiseArray(formattedItems);
},
/**
* Generates the items per type.
*
* @param {Object} type - The type.
* @param {Array} items - The item data.
* @returns {Array} - The formatted items.
* @private
*/
_generateItemsPerType: function (type, items) {
var formattedItems = [];
Utils.each(items, function (item) {
formattedItems.push({
height: type.height,
type: type.class,
widget: type.formatter.format(item)
});
});
return formattedItems;
},
/**
* Gets executed when the selected item changes.
*
* @param {Object} e - The event data.
* @private
*/
_onSelectedItemChange: function (e) {
// The item changed was an individual row asset.
if (e.target.parentWidget === this) {
this._setCurrentAssetHeight(e);
}
// The item changes was a row.
if (e.target === this) {
this._setActiveChildWidget(e);
}
},
/**
* Attempts to set the correct active item according to the current asset height.
*
* @param {Object} e - The item.
* @private
*/
_setActiveChildWidget: function (e) {
var rowIndex = e.index,
heights = this._heights[rowIndex],
combinedHeights = 0,
i,
j;
if (!heights) {
return;
}
for (i = 0, j = heights.length; i < j; i++) {
if (heights[i] + combinedHeights > this._currentItemHeight) {
break;
}
combinedHeights += heights[i];
}
this._currentItemHeight = combinedHeights;
this.getChildWidgetByIndex(rowIndex).setActiveChildIndex(i);
},
/**
* Sets the current asset height.
*
* @param {Object} e - The event data.
* @private
*/
_setCurrentAssetHeight: function (e) {
var target = e.target,
parentWidget = target.parentWidget,
rowIndex = parentWidget.getIndexOfChildWidget(target),
heights = this._heights[rowIndex],
itemIndex = e.index,
combinedHeights = 0,
heightsAtIndex;
if (!heights) {
return;
}
heightsAtIndex = heights.slice(0, itemIndex);
Utils.each(heightsAtIndex, function (height) {
combinedHeights += height;
});
this._currentItemHeight = combinedHeights;
},
/**
* Empties the grid.
*/
empty: function () {
Utils.each(this.getChildWidgets(), function (widget) {
widget.dispose();
});
this._currentItemHeight = 0;
this._heights = [];
this._items = [];
},
/**
* Disposes the widget.
*/
dispose: function () {
this._removeEventListeners();
this.empty();
},
/**
* Returns the active child index.
*
* @returns {number} - The active child index.
*/
getActiveChildIndex: function () {
var activeElement = this.getActiveChildWidget();
if (!activeElement) {
return 0;
}
return activeElement.getActiveChildWidgetIndex();
},
/**
* Aligns to proper index.
*
*/
alignToTop: function () {
var firstColumn = this.getChildWidgetByIndex(0),
firstAsset = firstColumn.getChildWidgetByIndex(0);
// Reset the current item height to allow focus from any position.
this._currentItemHeight = 0;
firstAsset.focus();
}
});
});