define('application/widgets/player/miniepg/carousel', [
'rofl/widgets/container',
'rofl/widgets/carousel',
'antie/widgets/carousel/keyhandlers/activatefirsthandler',
'application/widgets/carousel/strips/culling',
'application/widgets/carousel/horizontalcarouselaligner',
'antie/runtimecontext',
'rofl/lib/utils',
'application/managers/epg',
'application/managers/channel',
'application/widgets/pointerfocusablebutton',
'application/formatters/homeepgasset',
'application/widgets/player/miniepg/nextprogram',
'application/widgets/pointerbutton',
'rofl/events/keyevent'
], function (
Container,
Carousel,
KeyHandler,
CullingStrip,
Aligner,
RuntimeContext,
Utils,
EPGManager,
ChannelManager,
Button,
CurrentProgram,
NextProgram,
PointerButton,
KeyEvent
) {
'use strict';
var application = RuntimeContext.getCurrentApplication(),
layout = application.getLayout().miniepg,
loadmoreThreshold = 5,
channelManager = ChannelManager.getInstance(),
epgManager = EPGManager.getInstance();
return Container.extend({
/**
* Initialises the widget.
*/
init: function init () {
var keyHandler = new KeyHandler(),
aligner,
carousel;
init.base.call(this);
carousel = this._carousel = new Carousel('miniepg-carousel', Carousel.orientations.HORIZONTAL);
aligner = new Aligner(carousel.getMask());
carousel.setWidgetStrip(CullingStrip);
keyHandler.setAnimationOptions({
duration: 300,
easing: 'easeInOut',
fps: 60,
skipAnim: false
});
carousel.setMaskLength(layout.width);
aligner.setNumberOfItemsVisibleOnScreen(4);
carousel.setWidgetLengths(layout.itemWidth);
carousel.setAligner(aligner);
keyHandler.attach(carousel);
this.appendChildWidget(carousel);
this._leftPointer = this.appendChildWidget(new PointerButton(PointerButton.DIRECTIONS.LEFT));
this._rightPointer = this.appendChildWidget(new PointerButton(PointerButton.DIRECTIONS.RIGHT));
this._currentProgramFormatter = new CurrentProgram();
this.setListeners();
},
/**
* Sets the listeners.
*/
setListeners: function () {
this._onSelectedItemChangeBound = Utils.bind(this._onSelectedItemChange, this);
this._onSelectBound = Utils.bind(this._onSelect, this);
this._onKeyDownBound = Utils.bind(this._onKeyDown, this);
this.addEventListener('selecteditemchange', this._onSelectedItemChangeBound);
this.addEventListener('select', this._onSelectBound);
this.addEventListener('keydown', this._onKeyDownBound);
},
/**
* SelectedItemChange event.
*
* @param {Object} e - The event data.
* @private
*/
_onSelectedItemChange: function (e) {
var index = e.index;
if (index === 0) {
this._leftPointer.disable();
} else if (index - loadmoreThreshold <= 0 && !this._isLoadingMore) {
this.loadMore(true);
} else if (index + loadmoreThreshold >= this._carousel.getChildWidgetCount() - 1 && !this._isLoadingMore) {
this.loadMore(false);
} else if (index === this._carousel.getChildWidgetCount() - 1) {
this._rightPointer.disable();
} else {
this._leftPointer.enable();
this._rightPointer.enable();
}
},
/**
* Select event.
*
* @param {Object} e - The event data.
* @private
*/
_onSelect: function (e) {
if (e.target instanceof PointerButton) {
switch (e.target.getDirection()) {
case PointerButton.DIRECTIONS.LEFT:
this._carousel.alignPrevious();
break;
case PointerButton.DIRECTIONS.RIGHT:
this._carousel.alignNext();
break;
}
}
},
/**
* Keydown event.
*
* @param {Object} e - The event data.
* @private
*/
_onKeyDown: function (e) {
var carousel = this._carousel;
if (this._isLoadingInitial) {
e.preventDefault();
e.stopPropagation();
return;
}
switch (e.keyCode) {
case KeyEvent.VK_LEFT:
this.setChannel(channelManager.getChannelByNumber(999).getId())
.then(Utils.bind(function () {
carousel.alignToIndex(carousel.getChildWidgetCount() - 1, {
skipAnim: true,
onComplete: Utils.bind(function () {
setTimeout(Utils.bind(function () {
carousel.setActiveChildWidget(carousel.getChildWidgetByIndex(carousel.getChildWidgetCount() - 1));
}, this), 100);
}, this)
});
}, this));
e.preventDefault();
e.stopPropagation();
break;
case KeyEvent.VK_RIGHT:
this.setChannel(channelManager.getChannelByNumber(0).getId());
e.preventDefault();
e.stopPropagation();
break;
// No default.
}
},
/**
* Loads more data.
*
* @param {boolean} prepend - True if the data should be prepended.
*/
loadMore: function (prepend) {
var start,
end,
channels;
this._isLoadingMore = true;
if (prepend) {
end = channelManager.getChannelIndex(this._lastPrependedIndex);
if (end === 0) {
this._isLoadingMore = false;
return;
}
start = end - 12;
channels = channelManager.getChannelMap(start, end).slice().reverse();
// Last to prepend is now at the end due to reversing array.
this._lastPrependedIndex = channels[channels.length - 1];
} else {
start = channelManager.getChannelIndex(this._lastAppendedIndex) + 1;
end = start + 12;
channels = channelManager.getChannelMap(start, end).slice();
if (channels.length) {
this._lastAppendedIndex = channels[channels.length - 1];
}
}
if (channels && channels.length) {
epgManager.getNowNext(channels)
.then(Utils.bind(function (r) {
this._appendData(r, prepend, channels);
this._isLoadingMore = false;
}, this));
} else {
this._isLoadingMore = false;
}
},
/**
* Sets the current channel.
*
* @param {number} channel - The current channel.
* @returns {Object} - Promise.
*/
setChannel: function (channel) {
this._isLoadingInitial = true;
this._lastAppendedIndex = null;
this._lastPrependedIndex = null;
this._isLoadingMore = false;
this._carousel.completeAlignment();
this._carousel.removeChildWidgets();
this._carousel._aligner.reset();
this._carousel.getMask()._lastAlignIndex = null;
return this._loadData(channel)
.then(Utils.bind(function () {
this._isLoadingInitial = false;
}, this));
},
/**
* Loads the data for a given channel.
*
* @param {number} channel - The channel number.
* @returns {Object} - Promise.
* @private
*/
_loadData: function (channel) {
var index = channelManager.getChannelIndex(channel),
start = index - 6,
end = index + 6,
alignIndex,
channels;
if (start < 0) {
end -= start;
start = 0;
}
channels = channelManager.getChannelMap(start, end).slice();
this._lastPrependedIndex = channels[0];
this._lastAppendedIndex = channels[channels.length - 1];
return epgManager.getNowNext(channels)
.then(Utils.bind(function (r) {
this._appendData(r, false, channels);
alignIndex = channels.indexOf(channel);
alignIndex -= 2;
if (alignIndex < 0) {
alignIndex = 0;
}
this._carousel.alignToIndex(alignIndex, {
skipAnim: true
});
}, this));
},
/**
* Adds the data.
*
* @param {Object} data - The data to be added.
* @param {boolean} prepend - True if the data should be prepended.
* @param {Array} channels - The channels order in which the data should be added.
* @private
*/
_appendData: function (data, prepend, channels) {
var self = this;
Utils.each(channels, function (channel) {
var item = data[channel];
if (prepend) {
self._carousel.insert(0, self._createItem(item.now, item.next), layout.itemWidth);
} else {
self._carousel.append(self._createItem(item.now, item.next), layout.itemWidth);
}
});
if (prepend) {
this._carousel.alignToIndex(this._carousel.getActiveChildIndex(), {
skipAnim: true
});
}
this._updateProgressbars();
},
/**
* Creates a carousel item.
*
* @param {Object} now - The current program data.
* @param {Object} next - The next program data.
* @returns {Object} - The carousel item.
* @private
*/
_createItem: function (now, next) {
var button = new Button();
button.setDataItem(now.getChannel().getId());
button.appendChildWidget(this._currentProgramFormatter.format(now));
button.appendChildWidget(new NextProgram(next));
button.loadNext = Utils.bind(this._loadNext, this, button);
return button;
},
/**
* Loads next item for the given carousel item.
*
* @param {Object} button - The carousel item.
* @private
*/
_loadNext: function (button) {
epgManager.getNowNext(button.getDataItem())
.then(Utils.bind(function (r) {
r = r[button.getDataItem()];
this._currentProgramFormatter.format(r.now, button.getChildWidgetByIndex(0));
button.getChildWidgetByIndex(1).setData(r.next);
}, this));
},
/**
* Starts the progressbars update interval.
*/
_updateProgressbars: function () {
var carouselAssets,
asset,
currentProgramFinished,
now = application.getDate(),
dataItem;
if (this._progressInterval) {
clearInterval(this._progressInterval);
carouselAssets = this._carousel.getChildWidgets();
Utils.each(carouselAssets, Utils.bind(function (button) {
asset = button.getChildWidgetByIndex(0);
dataItem = asset.getDataItem();
currentProgramFinished = now >= dataItem.endTime;
asset.updateProgressBar();
if (currentProgramFinished) {
// Nasty check to avoid items that are removed from updating.
if (asset.parentWidget && asset.parentWidget.parentWidget) {
asset.parentWidget.loadNext();
}
}
}, this));
}
this._progressInterval = setInterval(Utils.bind(this._updateProgressbars, this), 5000);
},
/**
* Sets focus to the carousel.
*/
focus: function () {
this._carousel.focus();
},
/**
* Set miniEPG as focusable or not.
*
* @param {boolean} focusable - True to set miniEPG focusable, false not focusable.
*/
setFocusable: function (focusable) {
this._isFocusable = focusable;
},
/**
* Determines if the widget is focusable.
*
* @returns {boolean} - True if the widget is focusable.
*/
isFocusable: function isFocusable () {
return this._isFocusable;
}
});
});