text: /**
   * DevExtreme (ui/panorama.js)
   * Version: 16.2.6
   * Build date: Tue Mar 28 2017
   *
   * Copyright (c) 2012 - 2017 Developer Express Inc. ALL RIGHTS RESERVED
   * EULA: https://www.devexpress.com/Support/EULAs/DevExtreme.xml
   */
  "use strict";
  var $ = require("jquery"),
      when = require("../integration/jquery/deferred").when,
      fx = require("../animation/fx"),
      translator = require("../animation/translator"),
      Class = require("../core/class"),
      abstract = abstract,
      registerComponent = require("../core/component_registrator"),
      PanoramaItem = require("./panorama/item"),
      swipeEvents = require("../events/swipe"),
      eventUtils = require("../events/utils"),
      config = require("../core/config"),
      CollectionWidget = require("./collection/ui.collection_widget.edit");
  var PANORAMA_CLASS = "dx-panorama",
      PANORAMA_WRAPPER_CLASS = "dx-panorama-wrapper",
      PANORAMA_TITLE_CLASS = "dx-panorama-title",
      PANORAMA_GHOST_TITLE_CLASS = "dx-panorama-ghosttitle",
      PANORAMA_ITEMS_CONTAINER_CLASS = "dx-panorama-itemscontainer",
      PANORAMA_ITEM_CLASS = "dx-panorama-item",
      PANORAMA_GHOST_ITEM_CLASS = "dx-panorama-ghostitem",
      PANORAMA_ITEM_DATA_KEY = "dxPanoramaItemData",
      PANORAMA_ITEM_MARGIN_SCALE = .02,
      PANORAMA_TITLE_MARGIN_SCALE = .02,
      PANORAMA_BACKGROUND_MOVE_DURATION = 300,
      PANORAMA_BACKGROUND_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)",
      PANORAMA_TITLE_MOVE_DURATION = 300,
      PANORAMA_TITLE_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)",
      PANORAMA_ITEM_MOVE_DURATION = 300,
      PANORAMA_ITEM_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)";
  var moveBackground = function($element, position) {
      $element.css("background-position", position + "px 0%")
  };
  var position = function($element) {
      return translator.locate($element).left
  };
  var move = function($element, position) {
      translator.move($element, {
          left: position
      });
      $element.css("visibility", "")
  };
  var animation = {
      backgroundMove: function($element, position, completeAction) {
          return fx.animate($element, {
              to: {
                  "background-position": position + "px 0%"
              },
              duration: PANORAMA_BACKGROUND_MOVE_DURATION,
              easing: PANORAMA_BACKGROUND_MOVE_EASING,
              complete: completeAction
          })
      },
      titleMove: function($title, position, completeAction) {
          return fx.animate($title, {
              type: "slide",
              to: {
                  left: position
              },
              duration: PANORAMA_TITLE_MOVE_DURATION,
              easing: PANORAMA_TITLE_MOVE_EASING,
              complete: completeAction
          })
      },
      itemMove: function($item, itemPosition, completeAction) {
          return fx.animate($item, {
              type: "slide",
              to: {
                  left: itemPosition
              },
              duration: PANORAMA_ITEM_MOVE_DURATION,
              easing: PANORAMA_ITEM_MOVE_EASING,
              complete: function() {
                  completeAction && completeAction.apply(this, arguments);
                  $item.css("visibility", position($item) > 0 ? "" : "hidden")
              }
          })
      }
  };
  var endAnimation = function(elements) {
      if (!elements) {
          return
      }
      $.each(elements, function(_, element) {
          fx.stop(element, true)
      })
  };
  var PanoramaItemsRenderStrategy = Class.inherit({
      ctor: function(panorama) {
          this._panorama = panorama
      },
      init: $.noop,
      render: $.noop,
      allItemElements: function() {
          return this._panorama._itemElements()
      },
      updatePositions: abstract,
      animateRollback: abstract,
      detectBoundsTransition: abstract,
      animateComplete: abstract,
      _getRTLSignCorrection: function() {
          return this._panorama._getRTLSignCorrection()
      },
      _isRTLEnabled: function() {
          return this._panorama.option("rtlEnabled")
      },
      _itemMargin: function() {
          return this._containerWidth() * PANORAMA_ITEM_MARGIN_SCALE
      },
      _containerWidth: function() {
          return this._panorama._elementWidth()
      },
      _itemWidth: function() {
          return this._panorama._itemWidth()
      },
      _indexBoundary: function() {
          return this._panorama._indexBoundary()
      },
      _normalizeIndex: function(index) {
          return this._panorama._normalizeIndex(index)
      },
      _startNextPosition: function() {
          if (this._isRTLEnabled()) {
              return this._containerWidth() - (this._itemMargin() + this._itemWidth())
          } else {
              return this._itemMargin()
          }
      },
      _startPrevPosition: function() {
          if (this._isRTLEnabled()) {
              return this._containerWidth()
          } else {
              return -this._itemWidth()
          }
      }
  });
  var PanoramaOneAndLessItemsRenderStrategy = PanoramaItemsRenderStrategy.inherit({
      updatePositions: function() {
          var $items = this._panorama._itemElements(),
              startPosition = this._startNextPosition();
          $items.each(function() {
              move($(this), startPosition)
          })
      },
      animateRollback: $.noop,
      detectBoundsTransition: $.noop,
      animateComplete: $.noop
  });
  var PanoramaTwoItemsRenderStrategy = PanoramaItemsRenderStrategy.inherit({
      init: function() {
          this._initGhostItem()
      },
      render: function() {
          this._renderGhostItem()
      },
      _initGhostItem: function() {
          this._$ghostItem = $("<div>").addClass(PANORAMA_GHOST_ITEM_CLASS)
      },
      _renderGhostItem: function() {
          this._panorama._itemContainer().append(this._$ghostItem);
          this._toggleGhostItem(false)
      },
      _toggleGhostItem: function(visible) {
          var $ghostItem = this._$ghostItem;
          if (visible) {
              $ghostItem.css("opacity", 1)
          } else {
              $ghostItem.css("opacity", 0)
          }
      },
      _updateGhostItemContent: function(index) {
          if (false !== index && index !== this._prevGhostIndex) {
              this._$ghostItem.html(this._panorama._itemElements().eq(index).html());
              this._prevGhostIndex = index
          }
      },
      _isGhostItemVisible: function() {
          return "1" === this._$ghostItem.css("opacity")
      },
      _swapGhostWithItem: function($item) {
          var $ghostItem = this._$ghostItem,
              lastItemPosition = position($item);
          move($item, position($ghostItem));
          move($ghostItem, lastItemPosition)
      },
      allItemElements: function() {
          return this._panorama._itemContainer().find("." + PANORAMA_ITEM_CLASS + ", ." + PANORAMA_GHOST_ITEM_CLASS)
      },
      updatePositions: function(offset) {
          var $items = this.allItemElements(),
              selectedIndex = this._panorama.option("selectedIndex"),
              adjustedOffset = offset * this._getRTLSignCorrection(),
              isGhostReplaceLast = adjustedOffset > 0 && 0 === selectedIndex || adjustedOffset < 0 && 1 === selectedIndex,
              isGhostReplaceFirst = adjustedOffset < 0 && 0 === selectedIndex || adjustedOffset > 0 && 1 === selectedIndex,
              ghostPosition = isGhostReplaceLast && "replaceLast" || isGhostReplaceFirst && "replaceFirst",
              ghostContentIndex = isGhostReplaceLast && 1 || isGhostReplaceFirst && 0,
              positions = this._calculateItemPositions(selectedIndex, ghostPosition);
          this._updateGhostItemContent(ghostContentIndex);
          this._toggleGhostItem(isGhostReplaceLast || isGhostReplaceFirst);
          $items.each(function(index) {
              move($(this), positions[index] + offset)
          })
      },
      animateRollback: function(currentIndex) {
          var that = this,
              $items = this._panorama._itemElements(),
              startPosition = this._startNextPosition(),
              signCorrection = this._getRTLSignCorrection(),
              offset = (position($items.eq(currentIndex)) - startPosition) * signCorrection,
              ghostOffset = (position(this._$ghostItem) - startPosition) * signCorrection,
              positions = this._calculateItemPositions(currentIndex, ghostOffset > 0 ? "prepend" : "append"),
              isLastReplacedByGhost = 0 === currentIndex && offset > 0 && ghostOffset > 0 || 1 === currentIndex && ghostOffset < 0;
          if (isLastReplacedByGhost) {
              this._swapGhostWithItem($items.eq(1))
          } else {
              this._swapGhostWithItem($items.eq(0))
          }
          $items.each(function(index) {
              animation.itemMove($(this), positions[index])
          });
          animation.itemMove(this._$ghostItem, positions[2], function() {
              that._toggleGhostItem(false)
          })
      },
      detectBoundsTransition: function(newIndex, currentIndex) {
          var ghostLocation = position(this._$ghostItem),
              startPosition = this._startNextPosition(),
              rtl = this._isRTLEnabled();
          if (0 === newIndex && rtl ^ ghostLocation < startPosition) {
              return "left"
          }
          if (0 === currentIndex && rtl ^ ghostLocation > startPosition) {
              return "right"
          }
      },
      animateComplete: function(boundCross, newIndex, currentIndex) {
          var that = this,
              ghostPosition = !boundCross ^ 0 !== currentIndex ? "prepend" : "append",
              $items = this._panorama._itemElements(),
              positions = this._calculateItemPositions(newIndex, ghostPosition),
              animations = [];
          $items.each(function(index) {
              animations.push(animation.itemMove($(this), positions[index]))
          });
          animations.push(animation.itemMove(this._$ghostItem, positions[2], function() {
              that._toggleGhostItem(false)
          }));
          return when.apply($, animations)
      },
      _calculateItemPositions: function(atIndex, ghostPosition) {
          var positions = [],
              itemMargin = this._itemMargin(),
              itemWidth = this._itemWidth(),
              itemPositionOffset = (itemWidth + itemMargin) * this._getRTLSignCorrection(),
              normalFlow = 0 === atIndex,
              prevPosition = this._startPrevPosition(),
              nextPosition = this._startNextPosition();
          positions.push(nextPosition);
          nextPosition += itemPositionOffset;
          if (normalFlow) {
              positions.push(nextPosition)
          } else {
              positions.splice(0, 0, nextPosition)
          }
          nextPosition += itemPositionOffset;
          switch (ghostPosition) {
              case "replaceFirst":
                  positions.push(positions[0]);
                  if (normalFlow) {
                      positions[0] = nextPosition
                  } else {
                      positions[0] = prevPosition
                  }
                  break;
              case "replaceLast":
                  if (normalFlow) {
                      positions.splice(1, 0, prevPosition)
                  } else {
                      positions.splice(1, 0, nextPosition)
                  }
                  break;
              case "prepend":
                  positions.push(prevPosition);
                  break;
              case "append":
                  positions.push(nextPosition)
          }
          return positions
      }
  });
  var PanoramaThreeAndMoreItemsRenderStrategy = PanoramaItemsRenderStrategy.inherit({
      updatePositions: function(offset) {
          var $items = this._panorama._itemElements(),
              movingBack = offset * this._getRTLSignCorrection() < 0,
              positions = this._calculateItemPositions(this._panorama.option("selectedIndex"), movingBack);
          $items.each(function(index) {
              move($(this), positions[index] + offset)
          })
      },
      animateRollback: function(selectedIndex) {
          var $items = this._panorama._itemElements(),
              positions = this._calculateItemPositions(selectedIndex),
              animatingItems = [selectedIndex, this._normalizeIndex(selectedIndex + 1)];
          if (this._isRTLEnabled() ^ position($items.eq(selectedIndex)) > this._startNextPosition()) {
              animatingItems.push(this._normalizeIndex(selectedIndex - 1))
          }
          $items.each(function(index) {
              var $item = $(this);
              if ($.inArray(index, animatingItems) !== -1) {
                  animation.itemMove($item, positions[index])
              } else {
                  move($item, positions[index])
              }
          })
      },
      detectBoundsTransition: function(newIndex, currentIndex) {
          var lastIndex = this._indexBoundary() - 1;
          if (currentIndex === lastIndex && 0 === newIndex) {
              return "left"
          }
          if (0 === currentIndex && newIndex === lastIndex) {
              return "right"
          }
      },
      animateComplete: function(boundCross, newIndex, currentIndex) {
          var animations = [],
              $items = this._panorama._itemElements(),
              positions = this._calculateItemPositions(newIndex);
          var transitionBack = this._normalizeIndex(currentIndex - 1) === newIndex,
              cyclingItemIndex = 3 === $items.length && transitionBack ? this._normalizeIndex(currentIndex + 1) : null,
              cyclingItemPosition = positions[this._indexBoundary()];
          var animatingItems = [newIndex, currentIndex],
              backAnimatedItemIndex = transitionBack ? currentIndex : newIndex;
          if (!transitionBack) {
              animatingItems.push(this._normalizeIndex(backAnimatedItemIndex + 1))
          }
          $items.each(function(index) {
              var $item = $(this);
              if ($.inArray(index, animatingItems) === -1) {
                  move($item, positions[index]);
                  return
              }
              animations.push(index !== cyclingItemIndex ? animation.itemMove($item, positions[index]) : animation.itemMove($item, cyclingItemPosition, function() {
                  move($item, positions[index])
              }))
          });
          return when.apply($, animations)
      },
      _calculateItemPositions: function(atIndex, movingBack) {
          var previousIndex = this._normalizeIndex(atIndex - 1),
              itemMargin = this._itemMargin(),
              itemWidth = this._itemWidth(),
              itemPositionOffset = (itemWidth + itemMargin) * this._getRTLSignCorrection(),
              positions = [],
              prevPosition = this._startPrevPosition(),
              nextPosition = this._startNextPosition();
          for (var i = atIndex; i !== previousIndex; i = this._normalizeIndex(i + 1)) {
              positions[i] = nextPosition;
              nextPosition += itemPositionOffset
          }
          if (movingBack) {
              positions[previousIndex] = nextPosition;
              nextPosition += itemPositionOffset
          } else {
              positions[previousIndex] = prevPosition
          }
          positions.push(nextPosition);
          return positions
      }
  });
  var Panorama = CollectionWidget.inherit({
      _getDefaultOptions: function() {
          return $.extend(this.callBase(), {
              selectedIndex: 0,
              title: "panorama",
              backgroundImage: {
                  url: null,
                  width: 0,
                  height: 0
              },
              focusStateEnabled: false,
              selectionMode: "single",
              selectionRequired: true,
              selectionByClick: false,
              titleExpr: function(data) {
                  return data ? data.title : void 0
              }
          })
      },
      _itemClass: function() {
          return PANORAMA_ITEM_CLASS
      },
      _itemDataKey: function() {
          return PANORAMA_ITEM_DATA_KEY
      },
      _itemContainer: function() {
          return this._$itemsContainer
      },
      _itemWidth: function() {
          if (!this._itemWidthCache) {
              this._itemWidthCache = this._itemElements().eq(0).outerWidth() || 0
          }
          return this._itemWidthCache
      },
      _clearItemWidthCache: function() {
          delete this._itemWidthCache
      },
      _elementWidth: function() {
          if (!this._elementWidthCache) {
              this._elementWidthCache = this.element().width()
          }
          return this._elementWidthCache
      },
      _clearElementWidthCache: function() {
          delete this._elementWidthCache
      },
      _titleWidth: function() {
          if (!this._titleWidthCache) {
              this._titleWidthCache = this._$title.outerWidth()
          }
          return this._titleWidthCache
      },
      _clearTitleWidthCache: function() {
          delete this._titleWidthCache
      },
      _init: function() {
          this.callBase();
          this._initItemsRenderStrategy();
          this._initWrapper();
          this._initTitle();
          this._initItemsContainer();
          this._initSwipeHandlers()
      },
      _dimensionChanged: function() {
          this._clearItemWidthCache();
          this._clearElementWidthCache();
          this._clearTitleWidthCache();
          this._updatePositions()
      },
      _initWrapper: function() {
          this._$wrapper = $("<div>").addClass(PANORAMA_WRAPPER_CLASS).appendTo(this.element())
      },
      _initItemsRenderStrategy: function() {
          var itemsRenderStrategy;
          switch (this.option("items").length) {
              case 0:
              case 1:
                  itemsRenderStrategy = PanoramaOneAndLessItemsRenderStrategy;
                  break;
              case 2:
                  itemsRenderStrategy = PanoramaTwoItemsRenderStrategy;
                  break;
              default:
                  itemsRenderStrategy = PanoramaThreeAndMoreItemsRenderStrategy
          }
          this._itemsRenderStrategy = new itemsRenderStrategy(this);
          this._itemsRenderStrategy.init()
      },
      _initBackgroundImage: function() {
          var backgroundUrl = this.option("backgroundImage.url");
          if (backgroundUrl) {
              this.element().css("background-image", "url(" + backgroundUrl + ")")
          }
      },
      _initTitle: function() {
          this._$title = $("<div>").addClass(PANORAMA_TITLE_CLASS);
          this._$ghostTitle = $("<div>").addClass(PANORAMA_GHOST_TITLE_CLASS);
          this._$wrapper.append(this._$title);
          this._$wrapper.append(this._$ghostTitle);
          this._updateTitle()
      },
      _updateTitle: function() {
          var title = this.option("title");
          this._$title.text(title);
          this._$ghostTitle.text(title);
          this._toggleGhostTitle(false)
      },
      _toggleGhostTitle: function(visible) {
          var $ghostTitle = this._$ghostTitle;
          if (visible) {
              $ghostTitle.css("opacity", 1)
          } else {
              $ghostTitle.css("opacity", 0)
          }
      },
      _getRTLSignCorrection: function() {
          return this.option("rtlEnabled") ? -1 : 1
      },
      _initItemsContainer: function() {
          this._$itemsContainer = $("<div>").addClass(PANORAMA_ITEMS_CONTAINER_CLASS);
          this._$wrapper.append(this._$itemsContainer)
      },
      _render: function() {
          this.element().addClass(PANORAMA_CLASS);
          this.callBase();
          this._initBackgroundImage();
          this._itemsRenderStrategy.render()
      },
      _updatePositions: function(offset) {
          offset = offset || 0;
          this._updateBackgroundPosition(offset * this._calculateBackgroundStep());
          this._updateTitlePosition(offset * this._calculateTitleStep());
          this._itemsRenderStrategy.updatePositions(offset * this._elementWidth())
      },
      _updateBackgroundPosition: function(offset) {
          moveBackground(this.element(), this._calculateBackgroundPosition(this.option("selectedIndex")) + offset)
      },
      _updateTitlePosition: function(offset) {
          move(this._$title, this._calculateTitlePosition(this.option("selectedIndex")) + offset)
      },
      _animateRollback: function(currentIndex) {
          this._animateBackgroundMove(currentIndex);
          this._animateTitleMove(currentIndex);
          this._itemsRenderStrategy.animateRollback(currentIndex)
      },
      _animateBackgroundMove: function(toIndex) {
          return animation.backgroundMove(this.element(), this._calculateBackgroundPosition(toIndex))
      },
      _animateTitleMove: function(toIndex) {
          return animation.titleMove(this._$title, this._calculateTitlePosition(toIndex))
      },
      _animateComplete: function(newIndex, currentIndex) {
          var that = this,
              boundCross = this._itemsRenderStrategy.detectBoundsTransition(newIndex, currentIndex);
          var backgroundAnimation = this._performBackgroundAnimation(boundCross, newIndex);
          var titleAnimation = this._performTitleAnimation(boundCross, newIndex);
          var itemsAnimation = this._itemsRenderStrategy.animateComplete(boundCross, newIndex, currentIndex);
          when(backgroundAnimation, titleAnimation, itemsAnimation).done(function() {
              that._indexChangeOnAnimation = true;
              that.option("selectedIndex", newIndex);
              that._indexChangeOnAnimation = false
          })
      },
      _performBackgroundAnimation: function(boundCross, newIndex) {
          if (boundCross) {
              return this._animateBackgroundBoundsTransition(boundCross, newIndex)
          }
          return this._animateBackgroundMove(newIndex)
      },
      _animateBackgroundBoundsTransition: function(bound, newIndex) {
          var that = this,
              isLeft = "left" === bound,
              afterAnimationPosition = this._calculateBackgroundPosition(newIndex),
              animationEndPositionShift = isLeft ^ this.option("rtlEnabled") ? -this._calculateBackgroundScaledWidth() : this._calculateBackgroundScaledWidth(),
              animationEndPosition = afterAnimationPosition + animationEndPositionShift;
          return animation.backgroundMove(this.element(), animationEndPosition, function() {
              moveBackground(that.element(), afterAnimationPosition)
          })
      },
      _performTitleAnimation: function(boundCross, newIndex) {
          if (boundCross) {
              return this._animateTitleBoundsTransition(boundCross, newIndex)
          }
          return this._animateTitleMove(newIndex)
      },
      _animateTitleBoundsTransition: function(bound, newIndex) {
          var that = this,
              $ghostTitle = this._$ghostTitle,
              ghostWidth = this._titleWidth(),
              panoramaWidth = this._elementWidth(),
              isLeft = "left" === bound,
              rtl = this.option("rtlEnabled"),
              ghostTitleStartPosition = isLeft ^ rtl ? panoramaWidth : -ghostWidth,
              ghostTitleEndPosition = isLeft ^ rtl ? -(panoramaWidth + ghostWidth) : panoramaWidth;
          move($ghostTitle, ghostTitleStartPosition);
          this._toggleGhostTitle(true);
          this._swapGhostWithTitle();
          var ghostAnimation = animation.titleMove($ghostTitle, ghostTitleEndPosition, function() {
              that._toggleGhostTitle(false)
          });
          var titleAnimation = animation.titleMove(this._$title, this._calculateTitlePosition(newIndex));
          return when(ghostAnimation, titleAnimation)
      },
      _swapGhostWithTitle: function() {
          var $ghostTitle = this._$ghostTitle,
              $title = this._$title,
              lastTitlePosition = position($title);
          move($title, position($ghostTitle));
          move($ghostTitle, lastTitlePosition)
      },
      _calculateTitlePosition: function(atIndex) {
          var panoramaWidth = this._elementWidth(),
              titleWidth = this._titleWidth(),
              titleMargin = panoramaWidth * PANORAMA_TITLE_MARGIN_SCALE,
              titleStartPosition = this.option("rtlEnabled") ? panoramaWidth - titleMargin - titleWidth : titleMargin,
              titleStep = atIndex * this._calculateTitleStep() * this._getRTLSignCorrection();
          return titleStartPosition - titleStep
      },
      _calculateTitleStep: function() {
          var panoramaWidth = this._elementWidth(),
              titleWidth = this._titleWidth(),
              indexBoundary = this._indexBoundary() || 1;
          return Math.max((titleWidth - panoramaWidth) / indexBoundary, titleWidth / indexBoundary)
      },
      _calculateBackgroundPosition: function(atIndex) {
          var panoramaWidth = this._elementWidth(),
              backgroundScaledWidth = this._calculateBackgroundScaledWidth(),
              backgroundStartPosition = this.option("rtlEnabled") ? panoramaWidth - backgroundScaledWidth : 0,
              backgroundOffset = atIndex * this._calculateBackgroundStep() * this._getRTLSignCorrection();
          return backgroundStartPosition - backgroundOffset
      },
      _calculateBackgroundStep: function() {
          var itemWidth = this._itemWidth(),
              backgroundScaledWidth = this._calculateBackgroundScaledWidth();
          return Math.max((backgroundScaledWidth - itemWidth) / (this._indexBoundary() || 1), 0)
      },
      _calculateBackgroundScaledWidth: function() {
          return this.element().height() * this.option("backgroundImage.width") / (this.option("backgroundImage.height") || 1)
      },
      _initSwipeHandlers: function() {
          this.element().on(eventUtils.addNamespace(swipeEvents.start, this.NAME), {
              itemSizeFunc: $.proxy(this._elementWidth, this)
          }, $.proxy(this._swipeStartHandler, this)).on(eventUtils.addNamespace(swipeEvents.swipe, this.NAME), $.proxy(this._swipeUpdateHandler, this)).on(eventUtils.addNamespace(swipeEvents.end, this.NAME), $.proxy(this._swipeEndHandler, this))
      },
      _swipeStartHandler: function(e) {
          this._stopAnimations();
          e.maxLeftOffset = 1;
          e.maxRightOffset = 1;
          if (config().designMode || this.option("disabled") || this._indexBoundary() <= 1) {
              e.cancel = true
          }
      },
      _stopAnimations: function() {
          endAnimation([this.element(), this._$ghostTitle, this._$title]);
          endAnimation(this._itemsRenderStrategy.allItemElements())
      },
      _swipeUpdateHandler: function(e) {
          this._updatePositions(e.offset)
      },
      _swipeEndHandler: function(e) {
          var currentIndex = this.option("selectedIndex"),
              targetOffset = e.targetOffset * this._getRTLSignCorrection();
          if (0 === targetOffset) {
              this._animateRollback(currentIndex)
          } else {
              this._animateComplete(this._normalizeIndex(currentIndex - targetOffset), currentIndex)
          }
      },
      _renderSelection: function() {
          if (!this._indexChangeOnAnimation) {
              this._updatePositions()
          }
      },
      _normalizeIndex: function(index) {
          var boundary = this._indexBoundary();
          if (index < 0) {
              index = boundary + index
          }
          if (index >= boundary) {
              index -= boundary
          }
          return index
      },
      _indexBoundary: function() {
          return this.option("items").length
      },
      _visibilityChanged: function(visible) {
          if (visible) {
              this._dimensionChanged()
          }
      },
      _optionChanged: function(args) {
          switch (args.name) {
              case "width":
                  this.callBase(args);
                  this._dimensionChanged();
                  break;
              case "backgroundImage":
                  this._invalidate();
                  break;
              case "title":
                  this._updateTitle();
                  break;
              case "items":
                  this._initItemsRenderStrategy();
                  this.callBase(args);
                  break;
              case "titleExpr":
                  this._invalidate();
                  break;
              default:
                  this.callBase(args)
          }
      }
  });
  Panorama.ItemClass = PanoramaItem;
  registerComponent("dxPanorama", Panorama);
  module.exports = Panorama;
  module.exports.default = module.exports;
  