devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,222 lines (982 loc) • 38.6 kB
JavaScript
"use strict";
var $ = require("../core/renderer"),
eventsEngine = require("../events/core/events_engine"),
registerComponent = require("../core/component_registrator"),
commonUtils = require("../core/utils/common"),
typeUtils = require("../core/utils/type"),
windowUtils = require("../core/utils/window"),
extend = require("../core/utils/extend").extend,
getPublicElement = require("../core/utils/dom").getPublicElement,
fx = require("../animation/fx"),
clickEvent = require("../events/click"),
translator = require("../animation/translator"),
devices = require("../core/devices"),
Widget = require("./widget/ui.widget"),
eventUtils = require("../events/utils"),
CollectionWidget = require("./collection/ui.collection_widget.edit"),
Swipeable = require("../events/gesture/swipeable"),
BindableTemplate = require("./widget/bindable_template"),
Deferred = require("../core/utils/deferred").Deferred;
var GALLERY_CLASS = "dx-gallery",
GALLERY_WRAPPER_CLASS = GALLERY_CLASS + "-wrapper",
GALLERY_LOOP_CLASS = "dx-gallery-loop",
GALLERY_ITEM_CONTAINER_CLASS = GALLERY_CLASS + "-container",
GALLERY_ACTIVE_CLASS = GALLERY_CLASS + "-active",
GALLERY_ITEM_CLASS = GALLERY_CLASS + "-item",
GALLERY_INVISIBLE_ITEM_CLASS = GALLERY_CLASS + "-item-invisible",
GALLERY_LOOP_ITEM_CLASS = GALLERY_ITEM_CLASS + "-loop",
GALLERY_ITEM_SELECTOR = "." + GALLERY_ITEM_CLASS,
GALLERY_ITEM_SELECTED_CLASS = GALLERY_ITEM_CLASS + "-selected",
GALLERY_INDICATOR_CLASS = GALLERY_CLASS + "-indicator",
GALLERY_INDICATOR_ITEM_CLASS = GALLERY_INDICATOR_CLASS + "-item",
GALLERY_INDICATOR_ITEM_SELECTOR = "." + GALLERY_INDICATOR_ITEM_CLASS,
GALLERY_INDICATOR_ITEM_SELECTED_CLASS = GALLERY_INDICATOR_ITEM_CLASS + "-selected",
GALLERY_IMAGE_CLASS = "dx-gallery-item-image",
GALLERY_ITEM_DATA_KEY = "dxGalleryItemData",
MAX_CALC_ERROR = 1;
var GalleryNavButton = Widget.inherit({
_supportedKeys: function _supportedKeys() {
return extend(this.callBase(), {
pageUp: commonUtils.noop,
pageDown: commonUtils.noop
});
},
_getDefaultOptions: function _getDefaultOptions() {
return extend(this.callBase(), {
direction: "next",
onClick: null,
hoverStateEnabled: true,
activeStateEnabled: true
});
},
_render: function _render() {
this.callBase();
var that = this,
$element = this.$element(),
eventName = eventUtils.addNamespace(clickEvent.name, this.NAME);
$element.addClass(GALLERY_CLASS + "-nav-button-" + this.option("direction"));
eventsEngine.off($element, eventName);
eventsEngine.on($element, eventName, function (e) {
that._createActionByOption("onClick")({ event: e });
});
},
_optionChanged: function _optionChanged(args) {
switch (args.name) {
case "onClick":
case "direction":
this._invalidate();
break;
default:
this.callBase(args);
}
}
});
/**
* @name dxgallery
* @publicName dxGallery
* @inherits CollectionWidget
* @module ui/gallery
* @export default
*/
var Gallery = CollectionWidget.inherit({
_activeStateUnit: GALLERY_ITEM_SELECTOR,
_getDefaultOptions: function _getDefaultOptions() {
return extend(this.callBase(), {
/**
* @name dxGalleryOptions.activeStateEnabled
* @publicName activeStateEnabled
* @type boolean
* @default false
*/
activeStateEnabled: false,
/**
* @name dxGalleryOptions.animationDuration
* @publicName animationDuration
* @type number
* @default 400
*/
animationDuration: 400,
/**
* @name dxGalleryOptions.animationEnabled
* @publicName animationEnabled
* @type boolean
* @default true
*/
animationEnabled: true,
/**
* @name dxGalleryOptions.loop
* @publicName loop
* @type boolean
* @default false
*/
loop: false,
/**
* @name dxGalleryOptions.swipeEnabled
* @publicName swipeEnabled
* @type boolean
* @default true
*/
swipeEnabled: true,
/**
* @name dxGalleryOptions.indicatorEnabled
* @publicName indicatorEnabled
* @type boolean
* @default true
*/
indicatorEnabled: true,
/**
* @name dxGalleryOptions.showIndicator
* @publicName showIndicator
* @type boolean
* @default true
*/
showIndicator: true,
/**
* @name dxGalleryOptions.selectedindex
* @publicName selectedIndex
* @type number
* @default 0
*/
selectedIndex: 0,
/**
* @name dxGalleryOptions.slideshowdelay
* @publicName slideshowDelay
* @type number
* @default 0
*/
slideshowDelay: 0,
/**
* @name dxGalleryOptions.showNavButtons
* @publicName showNavButtons
* @type boolean
* @default false
*/
showNavButtons: false,
/**
* @name dxGalleryOptions.wrapAround
* @publicName wrapAround
* @type boolean
* @default false
*/
wrapAround: false,
/**
* @name dxGalleryOptions.initialItemWidth
* @publicName initialItemWidth
* @type number
* @default undefined
*/
initialItemWidth: undefined,
/**
* @name dxGalleryOptions.stretchImages
* @publicName stretchImages
* @type boolean
* @default false
*/
stretchImages: false,
/**
* @name dxGalleryOptions.activeStateEnabled
* @publicName activeStateEnabled
* @hidden
*/
/**
* @name dxGalleryOptions.noDataText
* @publicName noDataText
* @hidden
* @inheritdoc
*/
/**
* @name dxGalleryOptions.selectedItems
* @publicName selectedItems
* @hidden
* @inheritdoc
*/
/**
* @name dxGalleryOptions.selectedItemKeys
* @publicName selectedItemKeys
* @hidden
* @inheritdoc
*/
/**
* @name dxGalleryOptions.keyExpr
* @publicName keyExpr
* @hidden
* @inheritdoc
*/
_itemAttributes: { role: "option" },
loopItemFocus: false,
selectOnFocus: true,
selectionMode: "single",
selectionRequired: true,
selectionByClick: false
});
},
_defaultOptionsRules: function _defaultOptionsRules() {
return this.callBase().concat([{
device: function device() {
return devices.real().deviceType === "desktop" && !devices.isSimulator();
},
options: {
/**
* @name dxGalleryOptions.focusStateEnabled
* @publicName focusStateEnabled
* @type boolean
* @default true @for desktop
* @inheritdoc
*/
focusStateEnabled: true
}
}]);
},
_init: function _init() {
this.callBase();
this.option("loopItemFocus", this.option("loop"));
},
_initTemplates: function _initTemplates() {
this.callBase();
/**
* @name dxGalleryItemTemplate
* @publicName dxGalleryItemTemplate
* @inherits CollectionWidgetItemTemplate
* @type object
*/
/**
* @name dxGalleryItemTemplate.imageSrc
* @publicName imageSrc
* @type String
*/
/**
* @name dxGalleryItemTemplate.imageAlt
* @publicName imageAlt
* @type String
*/
/**
* @name dxGalleryItemTemplate.visible
* @publicName visible
* @hidden
* @inheritdoc
*/
this._defaultTemplates["item"] = new BindableTemplate(function ($container, data) {
var $img = $('<img>').addClass(GALLERY_IMAGE_CLASS);
if (typeUtils.isPlainObject(data)) {
this._prepareDefaultItemTemplate(data, $container);
$img.attr({
'src': data.imageSrc,
'alt': data.imageAlt
}).appendTo($container);
} else {
$img.attr('src', String(data)).appendTo($container);
}
}.bind(this), ["imageSrc", "imageAlt", "text", "html"], this.option("integrationOptions.watchMethod"));
},
_dataSourceOptions: function _dataSourceOptions() {
return {
paginate: false
};
},
_itemContainer: function _itemContainer() {
return this._$container;
},
_itemClass: function _itemClass() {
return GALLERY_ITEM_CLASS;
},
_itemDataKey: function _itemDataKey() {
return GALLERY_ITEM_DATA_KEY;
},
_actualItemWidth: function _actualItemWidth() {
var itemPerPage = this.option("wrapAround") ? this._itemsPerPage() + 1 : this._itemsPerPage();
if (this.option("stretchImages")) {
return 1 / itemPerPage;
}
if (this.option("wrapAround")) {
return this._itemPercentWidth() * this._itemsPerPage() / (this._itemsPerPage() + 1);
}
return this._itemPercentWidth();
},
_itemPercentWidth: function _itemPercentWidth() {
var percentWidth,
elementWidth = this.$element().outerWidth(),
initialItemWidth = this.option("initialItemWidth");
if (initialItemWidth && initialItemWidth <= elementWidth) {
percentWidth = this.option("initialItemWidth") / elementWidth;
} else {
percentWidth = 1;
}
return percentWidth;
},
_itemsPerPage: function _itemsPerPage() {
var itemsPerPage = windowUtils.hasWindow() ? Math.floor(1 / this._itemPercentWidth()) : 1;
return Math.min(itemsPerPage, this._itemsCount());
},
_pagesCount: function _pagesCount() {
return Math.ceil(this._itemsCount() / this._itemsPerPage());
},
_itemsCount: function _itemsCount() {
return (this.option("items") || []).length;
},
_offsetDirection: function _offsetDirection() {
return this.option("rtlEnabled") ? -1 : 1;
},
_initMarkup: function _initMarkup() {
this._renderWrapper();
this._renderItemsContainer();
this.$element().addClass(GALLERY_CLASS);
this.$element().toggleClass(GALLERY_LOOP_CLASS, this.option("loop"));
this.callBase();
this.setAria({
"role": "listbox",
"label": "gallery"
});
},
_render: function _render() {
this._renderDragHandler();
this._renderContainerPosition();
this._renderItemSizes();
this._renderItemPositions();
this._renderNavButtons();
this._renderIndicator();
this._renderSelectedItem();
this._renderItemVisibility();
this._renderUserInteraction();
this._setupSlideShow();
this._reviseDimensions();
this.callBase();
},
_dimensionChanged: function _dimensionChanged() {
var selectedIndex = this.option("selectedIndex") || 0;
this._stopItemAnimations();
this._clearCacheWidth();
this._renderDuplicateItems();
this._renderItemSizes();
this._renderItemPositions();
this._renderIndicator();
this._renderContainerPosition(this._calculateIndexOffset(selectedIndex), true);
this._renderItemVisibility();
},
_renderDragHandler: function _renderDragHandler() {
var eventName = eventUtils.addNamespace("dragstart", this.NAME);
eventsEngine.off(this.$element(), eventName);
eventsEngine.on(this.$element(), eventName, "img", function () {
return false;
});
},
_renderWrapper: function _renderWrapper() {
if (this._$wrapper) {
return;
}
this._$wrapper = $("<div>").addClass(GALLERY_WRAPPER_CLASS).appendTo(this.$element());
},
_renderItems: function _renderItems(items) {
if (!windowUtils.hasWindow()) {
var selectedIndex = this.option("selectedIndex");
items = items.length > selectedIndex ? items.slice(selectedIndex, selectedIndex + 1) : items.slice(0, 1);
}
this.callBase(items);
this._loadNextPageIfNeeded();
},
_renderItemsContainer: function _renderItemsContainer() {
if (this._$container) {
return;
}
this._$container = $("<div>").addClass(GALLERY_ITEM_CONTAINER_CLASS).appendTo(this._$wrapper);
},
_renderDuplicateItems: function _renderDuplicateItems() {
if (!this.option("loop")) {
return;
}
var items = this.option("items") || [],
itemsCount = items.length,
lastItemIndex = itemsCount - 1,
i;
if (!itemsCount) return;
this._getLoopedItems().remove();
var duplicateCount = Math.min(this._itemsPerPage(), itemsCount);
for (i = 0; i < duplicateCount; i++) {
this._renderItem(0, items[i]).addClass(GALLERY_LOOP_ITEM_CLASS);
}
for (i = 0; i < duplicateCount; i++) {
this._renderItem(0, items[lastItemIndex - i]).addClass(GALLERY_LOOP_ITEM_CLASS);
}
},
_getLoopedItems: function _getLoopedItems() {
return this.$element().find("." + GALLERY_LOOP_ITEM_CLASS);
},
_emptyMessageContainer: function _emptyMessageContainer() {
return this._$wrapper;
},
_renderItemSizes: function _renderItemSizes(startIndex) {
var $items = this._itemElements(),
itemWidth = this._actualItemWidth();
if (startIndex !== undefined) {
$items = $items.slice(startIndex);
}
$items.each(function (index) {
$($items[index]).outerWidth(itemWidth * 100 + "%");
});
},
_renderItemPositions: function _renderItemPositions() {
var itemWidth = this._actualItemWidth(),
itemsCount = this._itemsCount(),
itemsPerPage = this._itemsPerPage(),
loopItemsCount = this.$element().find("." + GALLERY_LOOP_ITEM_CLASS).length,
lastItemDuplicateIndex = itemsCount + loopItemsCount - 1,
offsetRatio = this.option("wrapAround") ? 0.5 : 0,
freeSpace = this._itemFreeSpace(),
rtlEnabled = this.option("rtlEnabled");
this._itemElements().each(function (index) {
var realIndex = index;
if (index > itemsCount + itemsPerPage - 1) {
realIndex = lastItemDuplicateIndex - realIndex - itemsPerPage;
}
var itemPosition = itemWidth * (realIndex + offsetRatio) + freeSpace * (realIndex + 1 - offsetRatio);
$(this).css(rtlEnabled ? "right" : "left", itemPosition * 100 + "%");
});
this._relocateItems(this.option("selectedIndex"), this.option("selectedIndex"), true);
},
_itemFreeSpace: function _itemFreeSpace() {
var itemsPerPage = this._itemsPerPage();
if (this.option("wrapAround")) {
itemsPerPage = itemsPerPage + 1;
}
return (1 - this._actualItemWidth() * itemsPerPage) / (itemsPerPage + 1);
},
_renderContainerPosition: function _renderContainerPosition(offset, hideItems, animate) {
this._releaseInvisibleItems();
offset = offset || 0;
var that = this,
itemWidth = this._actualItemWidth(),
targetIndex = offset,
targetPosition = this._offsetDirection() * targetIndex * (itemWidth + this._itemFreeSpace()),
positionReady;
if (typeUtils.isDefined(this._animationOverride)) {
animate = this._animationOverride;
delete this._animationOverride;
}
if (animate) {
that._startSwipe();
positionReady = that._animate(targetPosition).done(that._endSwipe.bind(that));
} else {
translator.move(this._$container, { left: targetPosition * this._elementWidth(), top: 0 });
positionReady = new Deferred().resolveWith(that);
}
positionReady.done(function () {
this._deferredAnimate && that._deferredAnimate.resolveWith(that);
hideItems && this._renderItemVisibility();
});
return positionReady.promise();
},
_startSwipe: function _startSwipe() {
this.$element().addClass(GALLERY_ACTIVE_CLASS);
},
_endSwipe: function _endSwipe() {
this.$element().removeClass(GALLERY_ACTIVE_CLASS);
},
_animate: function _animate(targetPosition, extraConfig) {
var that = this,
$container = this._$container,
animationComplete = new Deferred();
fx.animate(this._$container, extend({
type: "slide",
to: { left: targetPosition * this._elementWidth() },
duration: that.option("animationDuration"),
complete: function complete() {
if (that._needMoveContainerForward()) {
translator.move($container, { left: 0, top: 0 });
}
if (that._needMoveContainerBack()) {
translator.move($container, { left: that._maxContainerOffset() * that._elementWidth(), top: 0 });
}
animationComplete.resolveWith(that);
}
}, extraConfig || {}));
return animationComplete;
},
_needMoveContainerForward: function _needMoveContainerForward() {
var expectedPosition = this._$container.position().left * this._offsetDirection(),
actualPosition = -this._maxItemWidth() * this._elementWidth() * this._itemsCount();
return expectedPosition <= actualPosition + MAX_CALC_ERROR;
},
_needMoveContainerBack: function _needMoveContainerBack() {
var expectedPosition = this._$container.position().left * this._offsetDirection(),
actualPosition = this._actualItemWidth() * this._elementWidth();
return expectedPosition >= actualPosition - MAX_CALC_ERROR;
},
_maxContainerOffset: function _maxContainerOffset() {
return -this._maxItemWidth() * (this._itemsCount() - this._itemsPerPage()) * this._offsetDirection();
},
_maxItemWidth: function _maxItemWidth() {
return this._actualItemWidth() + this._itemFreeSpace();
},
_reviseDimensions: function _reviseDimensions() {
var that = this,
$firstItem = that._itemElements().first().find(".dx-item-content");
if (!$firstItem || $firstItem.is(":hidden")) {
return;
}
if (!that.option("height")) {
that.option("height", $firstItem.outerHeight());
}
if (!that.option("width")) {
that.option("width", $firstItem.outerWidth());
}
this._dimensionChanged();
},
_renderIndicator: function _renderIndicator() {
this._cleanIndicators();
if (!this.option("showIndicator")) {
return;
}
var indicator = this._$indicator = $("<div>").addClass(GALLERY_INDICATOR_CLASS).appendTo(this._$wrapper);
for (var i = 0; i < this._pagesCount(); i++) {
$("<div>").addClass(GALLERY_INDICATOR_ITEM_CLASS).appendTo(indicator);
}
this._renderSelectedPageIndicator();
},
_cleanIndicators: function _cleanIndicators() {
if (this._$indicator) {
this._$indicator.remove();
}
},
_renderSelectedItem: function _renderSelectedItem() {
var selectedIndex = this.option("selectedIndex");
this._itemElements().removeClass(GALLERY_ITEM_SELECTED_CLASS).eq(selectedIndex).addClass(GALLERY_ITEM_SELECTED_CLASS);
},
_renderItemVisibility: function _renderItemVisibility() {
if (this.option("initialItemWidth") || this.option("wrapAround")) {
this._releaseInvisibleItems();
return;
}
this._itemElements().each(function (index, item) {
if (this.option("selectedIndex") === index) {
$(item).removeClass(GALLERY_INVISIBLE_ITEM_CLASS);
} else {
$(item).addClass(GALLERY_INVISIBLE_ITEM_CLASS);
}
}.bind(this));
this._getLoopedItems().addClass(GALLERY_INVISIBLE_ITEM_CLASS);
},
_releaseInvisibleItems: function _releaseInvisibleItems() {
this._itemElements().removeClass(GALLERY_INVISIBLE_ITEM_CLASS);
this._getLoopedItems().removeClass(GALLERY_INVISIBLE_ITEM_CLASS);
},
_renderSelectedPageIndicator: function _renderSelectedPageIndicator() {
if (!this._$indicator) {
return;
}
var itemIndex = this.option("selectedIndex"),
lastIndex = this._pagesCount() - 1,
pageIndex = Math.ceil(itemIndex / this._itemsPerPage());
pageIndex = Math.min(lastIndex, pageIndex);
this._$indicator.find(GALLERY_INDICATOR_ITEM_SELECTOR).removeClass(GALLERY_INDICATOR_ITEM_SELECTED_CLASS).eq(pageIndex).addClass(GALLERY_INDICATOR_ITEM_SELECTED_CLASS);
},
_renderUserInteraction: function _renderUserInteraction() {
var rootElement = this.$element(),
swipeEnabled = this.option("swipeEnabled") && this._itemsCount() > 1;
this._createComponent(rootElement, Swipeable, {
disabled: this.option("disabled") || !swipeEnabled,
onStart: this._swipeStartHandler.bind(this),
onUpdated: this._swipeUpdateHandler.bind(this),
onEnd: this._swipeEndHandler.bind(this),
itemSizeFunc: this._elementWidth.bind(this)
});
var indicatorSelectAction = this._createAction(this._indicatorSelectHandler);
eventsEngine.off(rootElement, eventUtils.addNamespace(clickEvent.name, this.NAME), GALLERY_INDICATOR_ITEM_SELECTOR);
eventsEngine.on(rootElement, eventUtils.addNamespace(clickEvent.name, this.NAME), GALLERY_INDICATOR_ITEM_SELECTOR, function (e) {
indicatorSelectAction({ event: e });
});
},
_indicatorSelectHandler: function _indicatorSelectHandler(args) {
var e = args.event,
instance = args.component;
if (!instance.option("indicatorEnabled")) {
return;
}
var indicatorIndex = $(e.target).index(),
itemIndex = instance._fitPaginatedIndex(indicatorIndex * instance._itemsPerPage());
instance._needLongMove = true;
instance.option("selectedIndex", itemIndex);
instance._loadNextPageIfNeeded(itemIndex);
},
_renderNavButtons: function _renderNavButtons() {
var that = this;
if (!that.option("showNavButtons")) {
that._cleanNavButtons();
return;
}
that._prevNavButton = $("<div>").appendTo(this._$wrapper);
that._createComponent(that._prevNavButton, GalleryNavButton, {
direction: "prev",
onClick: function onClick() {
that._prevPage();
}
});
that._nextNavButton = $("<div>").appendTo(this._$wrapper);
that._createComponent(that._nextNavButton, GalleryNavButton, {
direction: "next",
onClick: function onClick() {
that._nextPage();
}
});
this._renderNavButtonsVisibility();
},
_prevPage: function _prevPage() {
var visiblePageSize = this._itemsPerPage(),
newSelectedIndex = this.option("selectedIndex") - visiblePageSize;
if (newSelectedIndex === -visiblePageSize && visiblePageSize === this._itemsCount()) {
return this._relocateItems(newSelectedIndex, 0);
} else {
return this.goToItem(this._fitPaginatedIndex(newSelectedIndex));
}
},
_nextPage: function _nextPage() {
var visiblePageSize = this._itemsPerPage(),
newSelectedIndex = this.option("selectedIndex") + visiblePageSize;
if (newSelectedIndex === visiblePageSize && visiblePageSize === this._itemsCount()) {
return this._relocateItems(newSelectedIndex, 0);
} else {
return this.goToItem(this._fitPaginatedIndex(newSelectedIndex)).done(this._loadNextPageIfNeeded);
}
},
_loadNextPageIfNeeded: function _loadNextPageIfNeeded(selectedIndex) {
selectedIndex = selectedIndex === undefined ? this.option("selectedIndex") : selectedIndex;
if (this._dataSource && this._dataSource.paginate() && this._shouldLoadNextPage(selectedIndex) && !this._isDataSourceLoading() && !this._isLastPage()) {
this._loadNextPage().done(function () {
this._renderIndicator();
this._renderItemPositions();
this._renderNavButtonsVisibility();
this._renderItemSizes(selectedIndex);
}.bind(this));
}
},
_shouldLoadNextPage: function _shouldLoadNextPage(selectedIndex) {
var visiblePageSize = this._itemsPerPage();
return selectedIndex + 2 * visiblePageSize > this.option("items").length;
},
_allowDynamicItemsAppend: function _allowDynamicItemsAppend() {
return true;
},
_fitPaginatedIndex: function _fitPaginatedIndex(itemIndex) {
var itemsPerPage = this._itemsPerPage();
var restItemsCount = itemIndex < 0 ? itemsPerPage + itemIndex : this._itemsCount() - itemIndex;
if (itemIndex > this._itemsCount() - 1) {
itemIndex = 0;
this._goToGhostItem = true;
} else if (restItemsCount < itemsPerPage && restItemsCount > 0) {
if (itemIndex > 0) {
itemIndex = itemIndex - (itemsPerPage - restItemsCount);
} else {
itemIndex = itemIndex + (itemsPerPage - restItemsCount);
}
}
return itemIndex;
},
_cleanNavButtons: function _cleanNavButtons() {
if (this._prevNavButton) {
this._prevNavButton.remove();
delete this._prevNavButton;
}
if (this._nextNavButton) {
this._nextNavButton.remove();
delete this._nextNavButton;
}
},
_renderNavButtonsVisibility: function _renderNavButtonsVisibility() {
if (!this.option("showNavButtons") || !this._prevNavButton || !this._nextNavButton) {
return;
}
var selectedIndex = this.option("selectedIndex"),
loop = this.option("loop"),
itemsCount = this._itemsCount();
this._prevNavButton.show();
this._nextNavButton.show();
if (itemsCount === 0) {
this._prevNavButton.hide();
this._nextNavButton.hide();
}
if (loop) {
return;
}
var nextHidden = selectedIndex === itemsCount - this._itemsPerPage(),
prevHidden = itemsCount < 2 || selectedIndex === 0;
if (this._dataSource && this._dataSource.paginate()) {
nextHidden = nextHidden && this._isLastPage();
} else {
nextHidden = nextHidden || itemsCount < 2;
}
if (prevHidden) {
this._prevNavButton.hide();
}
if (nextHidden) {
this._nextNavButton.hide();
}
},
_setupSlideShow: function _setupSlideShow() {
var that = this,
slideshowDelay = that.option("slideshowDelay");
clearTimeout(that._slideshowTimer);
if (!slideshowDelay) {
return;
}
that._slideshowTimer = setTimeout(function () {
if (that._userInteraction) {
that._setupSlideShow();
return;
}
that.nextItem(true).done(that._setupSlideShow);
}, slideshowDelay);
},
_elementWidth: function _elementWidth() {
if (!this._cacheElementWidth) {
this._cacheElementWidth = this.$element().width();
}
return this._cacheElementWidth;
},
_clearCacheWidth: function _clearCacheWidth() {
delete this._cacheElementWidth;
},
_swipeStartHandler: function _swipeStartHandler(e) {
this._releaseInvisibleItems();
this._clearCacheWidth();
this._elementWidth();
var itemsCount = this._itemsCount();
if (!itemsCount) {
e.event.cancel = true;
return;
}
this._stopItemAnimations();
this._startSwipe();
this._userInteraction = true;
if (!this.option("loop")) {
var selectedIndex = this.option("selectedIndex"),
startOffset = itemsCount - selectedIndex - this._itemsPerPage(),
endOffset = selectedIndex,
rtlEnabled = this.option("rtlEnabled");
e.event.maxLeftOffset = rtlEnabled ? endOffset : startOffset;
e.event.maxRightOffset = rtlEnabled ? startOffset : endOffset;
}
},
_stopItemAnimations: function _stopItemAnimations() {
fx.stop(this._$container, true);
},
_swipeUpdateHandler: function _swipeUpdateHandler(e) {
var wrapAroundRatio = this.option("wrapAround") ? 1 : 0;
var offset = this._offsetDirection() * e.event.offset * (this._itemsPerPage() + wrapAroundRatio) - this.option("selectedIndex");
if (offset < 0) {
this._loadNextPageIfNeeded(Math.ceil(Math.abs(offset)));
}
this._renderContainerPosition(offset);
},
_swipeEndHandler: function _swipeEndHandler(e) {
var targetOffset = e.event.targetOffset * this._offsetDirection() * this._itemsPerPage(),
selectedIndex = this.option("selectedIndex"),
newIndex = this._fitIndex(selectedIndex - targetOffset),
paginatedIndex = this._fitPaginatedIndex(newIndex);
if (Math.abs(targetOffset) < this._itemsPerPage()) {
this._relocateItems(selectedIndex);
return;
}
if (this._itemsPerPage() === this._itemsCount()) {
if (targetOffset > 0) {
this._relocateItems(-targetOffset);
} else {
this._relocateItems(0);
}
return;
}
this.option("selectedIndex", paginatedIndex);
},
_setFocusOnSelect: function _setFocusOnSelect() {
this._userInteraction = true;
var selectedItem = this.itemElements().filter("." + GALLERY_ITEM_SELECTED_CLASS);
this.option("focusedElement", getPublicElement(selectedItem));
this._userInteraction = false;
},
_flipIndex: function _flipIndex(index) {
var itemsCount = this._itemsCount();
index = index % itemsCount;
if (index > (itemsCount + 1) / 2) {
index -= itemsCount;
}
if (index < -(itemsCount - 1) / 2) {
index += itemsCount;
}
return index;
},
_fitIndex: function _fitIndex(index) {
if (!this.option("loop")) {
return index;
}
var itemsCount = this._itemsCount();
if (index >= itemsCount || index < 0) {
this._goToGhostItem = true;
}
if (index >= itemsCount) {
index = itemsCount - index;
}
index = index % itemsCount;
if (index < 0) {
index += itemsCount;
}
return index;
},
_clean: function _clean() {
this.callBase();
this._cleanIndicators();
this._cleanNavButtons();
},
_dispose: function _dispose() {
clearTimeout(this._slideshowTimer);
this.callBase();
},
_updateSelection: function _updateSelection(addedSelection, removedSelection) {
this._stopItemAnimations();
this._renderNavButtonsVisibility();
this._renderSelectedItem();
this._relocateItems(addedSelection[0], removedSelection[0]);
this._renderSelectedPageIndicator();
},
_relocateItems: function _relocateItems(newIndex, prevIndex, withoutAnimation) {
if (prevIndex === undefined) {
prevIndex = newIndex;
}
var indexOffset = this._calculateIndexOffset(newIndex, prevIndex);
this._renderContainerPosition(indexOffset, true, this.option("animationEnabled") && !withoutAnimation).done(function () {
this._setFocusOnSelect();
this._userInteraction = false;
this._setupSlideShow();
});
},
_focusInHandler: function _focusInHandler() {
if (fx.isAnimating(this._$container) || this._userInteraction) {
return;
}
this.callBase.apply(this, arguments);
},
_focusOutHandler: function _focusOutHandler() {
if (fx.isAnimating(this._$container) || this._userInteraction) {
return;
}
this.callBase.apply(this, arguments);
},
_selectFocusedItem: commonUtils.noop,
_moveFocus: function _moveFocus() {
this._stopItemAnimations();
this.callBase.apply(this, arguments);
var index = this.itemElements().index($(this.option("focusedElement")));
this.goToItem(index, this.option("animationEnabled"));
},
_visibilityChanged: function _visibilityChanged(visible) {
if (visible) {
this._reviseDimensions();
}
},
_calculateIndexOffset: function _calculateIndexOffset(newIndex, lastIndex) {
if (lastIndex === undefined) {
lastIndex = newIndex;
}
var indexOffset = lastIndex - newIndex;
if (this.option("loop") && !this._needLongMove && this._goToGhostItem) {
if (this._isItemOnFirstPage(newIndex) && this._isItemOnLastPage(lastIndex)) {
indexOffset = -this._itemsPerPage();
} else if (this._isItemOnLastPage(newIndex) && this._isItemOnFirstPage(lastIndex)) {
indexOffset = this._itemsPerPage();
}
this._goToGhostItem = false;
}
this._needLongMove = false;
indexOffset = indexOffset - lastIndex;
return indexOffset;
},
_isItemOnLastPage: function _isItemOnLastPage(itemIndex) {
return itemIndex >= this._itemsCount() - this._itemsPerPage();
},
_isItemOnFirstPage: function _isItemOnFirstPage(itemIndex) {
return itemIndex <= this._itemsPerPage();
},
_optionChanged: function _optionChanged(args) {
switch (args.name) {
case "width":
case "initialItemWidth":
this.callBase.apply(this, arguments);
this._dimensionChanged();
break;
case "animationDuration":
this._renderNavButtonsVisibility();
break;
case "animationEnabled":
break;
case "loop":
this.$element().toggleClass(GALLERY_LOOP_CLASS, args.value);
this.option("loopItemFocus", args.value);
if (windowUtils.hasWindow()) {
this._renderDuplicateItems();
this._renderItemPositions();
this._renderNavButtonsVisibility();
}
break;
case "showIndicator":
this._renderIndicator();
break;
case "showNavButtons":
this._renderNavButtons();
break;
case "slideshowDelay":
this._setupSlideShow();
break;
case "wrapAround":
case "stretchImages":
if (windowUtils.hasWindow()) {
this._renderItemSizes();
this._renderItemPositions();
this._renderItemVisibility();
}
break;
case "swipeEnabled":
case "indicatorEnabled":
this._renderUserInteraction();
break;
default:
this.callBase(args);
}
},
/**
* @name dxgallerymethods.goToItem
* @publicName goToItem(itemIndex, animation)
* @param1 itemIndex:numeric
* @param2 animation:boolean
* @return Promise<void>
*/
goToItem: function goToItem(itemIndex, animation) {
var selectedIndex = this.option("selectedIndex"),
itemsCount = this._itemsCount();
if (animation !== undefined) {
this._animationOverride = animation;
}
itemIndex = this._fitIndex(itemIndex);
this._deferredAnimate = new Deferred();
if (itemIndex > itemsCount - 1 || itemIndex < 0 || selectedIndex === itemIndex) {
return this._deferredAnimate.resolveWith(this).promise();
}
this.option("selectedIndex", itemIndex);
return this._deferredAnimate.promise();
},
/**
* @name dxgallerymethods.prevItem
* @publicName prevItem(animation)
* @param1 animation:boolean
* @return Promise<void>
*/
prevItem: function prevItem(animation) {
return this.goToItem(this.option("selectedIndex") - 1, animation);
},
/**
* @name dxgallerymethods.nextItem
* @publicName nextItem(animation)
* @param1 animation:boolean
* @return Promise<void>
*/
nextItem: function nextItem(animation) {
return this.goToItem(this.option("selectedIndex") + 1, animation);
}
});
registerComponent("dxGallery", Gallery);
module.exports = Gallery;