multi_view.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /**
  2. * DevExtreme (ui/multi_view.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _renderer = require("../core/renderer");
  11. var _renderer2 = _interopRequireDefault(_renderer);
  12. var _fx = require("../animation/fx");
  13. var _fx2 = _interopRequireDefault(_fx);
  14. var _translator2 = require("../animation/translator");
  15. var _translator3 = _interopRequireDefault(_translator2);
  16. var _math = require("../core/utils/math");
  17. var _math2 = _interopRequireDefault(_math);
  18. var _extend = require("../core/utils/extend");
  19. var _common = require("../core/utils/common");
  20. var _dom = require("../core/utils/dom");
  21. var _type = require("../core/utils/type");
  22. var _devices = require("../core/devices");
  23. var _devices2 = _interopRequireDefault(_devices);
  24. var _component_registrator = require("../core/component_registrator");
  25. var _component_registrator2 = _interopRequireDefault(_component_registrator);
  26. var _uiCollection_widget = require("./collection/ui.collection_widget.live_update");
  27. var _uiCollection_widget2 = _interopRequireDefault(_uiCollection_widget);
  28. var _swipeable = require("../events/gesture/swipeable");
  29. var _swipeable2 = _interopRequireDefault(_swipeable);
  30. var _deferred = require("../core/utils/deferred");
  31. function _interopRequireDefault(obj) {
  32. return obj && obj.__esModule ? obj : {
  33. "default": obj
  34. }
  35. }
  36. var MULTIVIEW_CLASS = "dx-multiview";
  37. var MULTIVIEW_WRAPPER_CLASS = "dx-multiview-wrapper";
  38. var MULTIVIEW_ITEM_CONTAINER_CLASS = "dx-multiview-item-container";
  39. var MULTIVIEW_ITEM_CLASS = "dx-multiview-item";
  40. var MULTIVIEW_ITEM_HIDDEN_CLASS = "dx-multiview-item-hidden";
  41. var MULTIVIEW_ITEM_DATA_KEY = "dxMultiViewItemData";
  42. var MULTIVIEW_ANIMATION_DURATION = 200;
  43. var toNumber = function(value) {
  44. return +value
  45. };
  46. var position = function($element) {
  47. return _translator3.default.locate($element).left
  48. };
  49. var _translator = {
  50. move: function($element, position) {
  51. _translator3.default.move($element, {
  52. left: position
  53. })
  54. }
  55. };
  56. var animation = {
  57. moveTo: function($element, position, duration, completeAction) {
  58. _fx2.default.animate($element, {
  59. type: "slide",
  60. to: {
  61. left: position
  62. },
  63. duration: duration,
  64. complete: completeAction
  65. })
  66. },
  67. complete: function($element) {
  68. _fx2.default.stop($element, true)
  69. }
  70. };
  71. var MultiView = _uiCollection_widget2.default.inherit({
  72. _activeStateUnit: "." + MULTIVIEW_ITEM_CLASS,
  73. _supportedKeys: function() {
  74. return (0, _extend.extend)(this.callBase(), {
  75. pageUp: _common.noop,
  76. pageDown: _common.noop
  77. })
  78. },
  79. _getDefaultOptions: function() {
  80. return (0, _extend.extend)(this.callBase(), {
  81. selectedIndex: 0,
  82. swipeEnabled: true,
  83. animationEnabled: true,
  84. loop: false,
  85. deferRendering: true,
  86. _itemAttributes: {
  87. role: "tabpanel"
  88. },
  89. loopItemFocus: false,
  90. selectOnFocus: true,
  91. selectionMode: "single",
  92. selectionRequired: true,
  93. selectionByClick: false
  94. })
  95. },
  96. _defaultOptionsRules: function() {
  97. return this.callBase().concat([{
  98. device: function() {
  99. return "desktop" === _devices2.default.real().deviceType && !_devices2.default.isSimulator()
  100. },
  101. options: {
  102. focusStateEnabled: true
  103. }
  104. }])
  105. },
  106. _itemClass: function() {
  107. return MULTIVIEW_ITEM_CLASS
  108. },
  109. _itemDataKey: function() {
  110. return MULTIVIEW_ITEM_DATA_KEY
  111. },
  112. _itemContainer: function() {
  113. return this._$itemContainer
  114. },
  115. _itemElements: function() {
  116. return this._itemContainer().children(this._itemSelector())
  117. },
  118. _itemWidth: function() {
  119. if (!this._itemWidthValue) {
  120. this._itemWidthValue = this._$wrapper.width()
  121. }
  122. return this._itemWidthValue
  123. },
  124. _clearItemWidthCache: function() {
  125. delete this._itemWidthValue
  126. },
  127. _itemsCount: function() {
  128. return this.option("items").length
  129. },
  130. _normalizeIndex: function(index) {
  131. var count = this._itemsCount();
  132. if (index < 0) {
  133. index += count
  134. }
  135. if (index >= count) {
  136. index -= count
  137. }
  138. return index
  139. },
  140. _getRTLSignCorrection: function() {
  141. return this.option("rtlEnabled") ? -1 : 1
  142. },
  143. _init: function() {
  144. this.callBase.apply(this, arguments);
  145. var $element = this.$element();
  146. $element.addClass(MULTIVIEW_CLASS);
  147. this._$wrapper = (0, _renderer2.default)("<div>").addClass(MULTIVIEW_WRAPPER_CLASS);
  148. this._$wrapper.appendTo($element);
  149. this._$itemContainer = (0, _renderer2.default)("<div>").addClass(MULTIVIEW_ITEM_CONTAINER_CLASS);
  150. this._$itemContainer.appendTo(this._$wrapper);
  151. this.option("loopItemFocus", this.option("loop"));
  152. this._initSwipeable()
  153. },
  154. _initMarkup: function() {
  155. this._deferredItems = [];
  156. this.callBase();
  157. var selectedItemIndices = this._getSelectedItemIndices();
  158. this._updateItemsVisibility(selectedItemIndices[0])
  159. },
  160. _afterItemElementDeleted: function($item, deletedActionArgs) {
  161. this.callBase($item, deletedActionArgs);
  162. if (this._deferredItems) {
  163. this._deferredItems.splice(deletedActionArgs.itemIndex, 1)
  164. }
  165. },
  166. _beforeItemElementInserted: function(change) {
  167. this.callBase.apply(this, arguments);
  168. if (this._deferredItems) {
  169. this._deferredItems.splice(change.index, 0, null)
  170. }
  171. },
  172. _executeItemRenderAction: function(index, itemData, itemElement) {
  173. index = (this.option("items") || []).indexOf(itemData);
  174. this.callBase(index, itemData, itemElement)
  175. },
  176. _renderItemContent: function(args) {
  177. var renderContentDeferred = new _deferred.Deferred;
  178. var that = this;
  179. var callBase = this.callBase;
  180. var deferred = new _deferred.Deferred;
  181. deferred.done(function() {
  182. var $itemContent = callBase.call(that, args);
  183. renderContentDeferred.resolve($itemContent)
  184. });
  185. this._deferredItems[args.index] = deferred;
  186. this.option("deferRendering") || deferred.resolve();
  187. return renderContentDeferred.promise()
  188. },
  189. _render: function() {
  190. var _this = this;
  191. this.callBase();
  192. (0, _common.deferRender)(function() {
  193. var selectedItemIndices = _this._getSelectedItemIndices();
  194. _this._updateItems(selectedItemIndices[0])
  195. })
  196. },
  197. _updateItems: function(selectedIndex, newIndex) {
  198. this._updateItemsPosition(selectedIndex, newIndex);
  199. this._updateItemsVisibility(selectedIndex, newIndex)
  200. },
  201. _modifyByChanges: function() {
  202. this.callBase.apply(this, arguments);
  203. var selectedItemIndices = this._getSelectedItemIndices();
  204. this._updateItemsVisibility(selectedItemIndices[0])
  205. },
  206. _updateItemsPosition: function(selectedIndex, newIndex) {
  207. var $itemElements = this._itemElements();
  208. var positionSign = (0, _type.isDefined)(newIndex) ? -this._animationDirection(newIndex, selectedIndex) : void 0;
  209. var $selectedItem = $itemElements.eq(selectedIndex);
  210. _translator.move($selectedItem, 0);
  211. if ((0, _type.isDefined)(newIndex)) {
  212. _translator.move($itemElements.eq(newIndex), 100 * positionSign + "%")
  213. }
  214. },
  215. _updateItemsVisibility: function(selectedIndex, newIndex) {
  216. var $itemElements = this._itemElements();
  217. $itemElements.each(function(itemIndex, item) {
  218. var $item = (0, _renderer2.default)(item);
  219. var isHidden = itemIndex !== selectedIndex && itemIndex !== newIndex;
  220. if (!isHidden) {
  221. this._renderSpecificItem(itemIndex)
  222. }
  223. $item.toggleClass(MULTIVIEW_ITEM_HIDDEN_CLASS, isHidden);
  224. this.setAria("hidden", isHidden || void 0, $item)
  225. }.bind(this))
  226. },
  227. _renderSpecificItem: function(index) {
  228. var $item = this._itemElements().eq(index);
  229. var hasItemContent = $item.find(this._itemContentClass()).length > 0;
  230. if ((0, _type.isDefined)(index) && !hasItemContent) {
  231. this._deferredItems[index].resolve();
  232. (0, _dom.triggerResizeEvent)($item)
  233. }
  234. },
  235. _refreshItem: function($item, item) {
  236. this.callBase($item, item);
  237. this._updateItemsVisibility(this.option("selectedIndex"))
  238. },
  239. _setAriaSelected: _common.noop,
  240. _updateSelection: function(addedSelection, removedSelection) {
  241. var newIndex = addedSelection[0];
  242. var prevIndex = removedSelection[0];
  243. animation.complete(this._$itemContainer);
  244. this._updateItems(prevIndex, newIndex);
  245. var animationDirection = this._animationDirection(newIndex, prevIndex);
  246. this._animateItemContainer(animationDirection * this._itemWidth(), function() {
  247. _translator.move(this._$itemContainer, 0);
  248. this._updateItems(newIndex);
  249. this._$itemContainer.width()
  250. }.bind(this))
  251. },
  252. _animateItemContainer: function(position, completeCallback) {
  253. var duration = this.option("animationEnabled") ? MULTIVIEW_ANIMATION_DURATION : 0;
  254. animation.moveTo(this._$itemContainer, position, duration, completeCallback)
  255. },
  256. _animationDirection: function(newIndex, prevIndex) {
  257. var containerPosition = position(this._$itemContainer);
  258. var indexDifference = (prevIndex - newIndex) * this._getRTLSignCorrection() * this._getItemFocusLoopSignCorrection();
  259. var isSwipePresent = 0 !== containerPosition;
  260. var directionSignVariable = isSwipePresent ? containerPosition : indexDifference;
  261. return _math2.default.sign(directionSignVariable)
  262. },
  263. _getSwipeDisabledState: function() {
  264. return !this.option("swipeEnabled") || this._itemsCount() <= 1
  265. },
  266. _initSwipeable: function() {
  267. var _this2 = this;
  268. this._createComponent(this.$element(), _swipeable2.default, {
  269. disabled: this._getSwipeDisabledState(),
  270. elastic: false,
  271. itemSizeFunc: this._itemWidth.bind(this),
  272. onStart: function(args) {
  273. return _this2._swipeStartHandler(args.event)
  274. },
  275. onUpdated: function(args) {
  276. return _this2._swipeUpdateHandler(args.event)
  277. },
  278. onEnd: function(args) {
  279. return _this2._swipeEndHandler(args.event)
  280. }
  281. })
  282. },
  283. _swipeStartHandler: function(e) {
  284. animation.complete(this._$itemContainer);
  285. var selectedIndex = this.option("selectedIndex");
  286. var loop = this.option("loop");
  287. var lastIndex = this._itemsCount() - 1;
  288. var rtl = this.option("rtlEnabled");
  289. e.maxLeftOffset = toNumber(loop || (rtl ? selectedIndex > 0 : selectedIndex < lastIndex));
  290. e.maxRightOffset = toNumber(loop || (rtl ? selectedIndex < lastIndex : selectedIndex > 0));
  291. this._swipeDirection = null
  292. },
  293. _swipeUpdateHandler: function(e) {
  294. var offset = e.offset;
  295. var swipeDirection = _math2.default.sign(offset) * this._getRTLSignCorrection();
  296. _translator.move(this._$itemContainer, offset * this._itemWidth());
  297. if (swipeDirection !== this._swipeDirection) {
  298. this._swipeDirection = swipeDirection;
  299. var selectedIndex = this.option("selectedIndex");
  300. var newIndex = this._normalizeIndex(selectedIndex - swipeDirection);
  301. this._updateItems(selectedIndex, newIndex)
  302. }
  303. },
  304. _swipeEndHandler: function(e) {
  305. var targetOffset = e.targetOffset * this._getRTLSignCorrection();
  306. if (targetOffset) {
  307. this.option("selectedIndex", this._normalizeIndex(this.option("selectedIndex") - targetOffset));
  308. var $selectedElement = this.itemElements().filter(".dx-item-selected");
  309. this.option("focusStateEnabled") && this.option("focusedElement", (0, _dom.getPublicElement)($selectedElement))
  310. } else {
  311. this._animateItemContainer(0, _common.noop)
  312. }
  313. },
  314. _getItemFocusLoopSignCorrection: function() {
  315. return this._itemFocusLooped ? -1 : 1
  316. },
  317. _moveFocus: function() {
  318. this.callBase.apply(this, arguments);
  319. this._itemFocusLooped = false
  320. },
  321. _prevItem: function($items) {
  322. var $result = this.callBase.apply(this, arguments);
  323. this._itemFocusLooped = $result.is($items.last());
  324. return $result
  325. },
  326. _nextItem: function($items) {
  327. var $result = this.callBase.apply(this, arguments);
  328. this._itemFocusLooped = $result.is($items.first());
  329. return $result
  330. },
  331. _dimensionChanged: function() {
  332. this._clearItemWidthCache()
  333. },
  334. _visibilityChanged: function(visible) {
  335. if (visible) {
  336. this._dimensionChanged()
  337. }
  338. },
  339. _updateSwipeDisabledState: function() {
  340. var disabled = this._getSwipeDisabledState();
  341. _swipeable2.default.getInstance(this.$element()).option("disabled", disabled)
  342. },
  343. _optionChanged: function(args) {
  344. var value = args.value;
  345. switch (args.name) {
  346. case "loop":
  347. this.option("loopItemFocus", value);
  348. break;
  349. case "animationEnabled":
  350. break;
  351. case "swipeEnabled":
  352. this._updateSwipeDisabledState();
  353. break;
  354. case "deferRendering":
  355. this._invalidate();
  356. break;
  357. case "items":
  358. this._updateSwipeDisabledState();
  359. this.callBase(args);
  360. break;
  361. default:
  362. this.callBase(args)
  363. }
  364. }
  365. });
  366. (0, _component_registrator2.default)("dxMultiView", MultiView);
  367. module.exports = MultiView;
  368. module.exports.default = module.exports;