ui.scrollable.native.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /**
  2. * DevExtreme (ui/scroll_view/ui.scrollable.native.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 _events_engine = require("../../events/core/events_engine");
  13. var _events_engine2 = _interopRequireDefault(_events_engine);
  14. var _utils = require("../../events/utils");
  15. var _utils2 = _interopRequireDefault(_utils);
  16. var _common = require("../../core/utils/common");
  17. var _iterator = require("../../core/utils/iterator");
  18. var _devices = require("../../core/devices");
  19. var _devices2 = _interopRequireDefault(_devices);
  20. var _class = require("../../core/class");
  21. var _class2 = _interopRequireDefault(_class);
  22. var _ui = require("./ui.scrollbar");
  23. var _ui2 = _interopRequireDefault(_ui);
  24. function _interopRequireDefault(obj) {
  25. return obj && obj.__esModule ? obj : {
  26. "default": obj
  27. }
  28. }
  29. var SCROLLABLE_NATIVE = "dxNativeScrollable";
  30. var SCROLLABLE_NATIVE_CLASS = "dx-scrollable-native";
  31. var SCROLLABLE_SCROLLBAR_SIMULATED = "dx-scrollable-scrollbar-simulated";
  32. var SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden";
  33. var VERTICAL = "vertical";
  34. var HORIZONTAL = "horizontal";
  35. var HIDE_SCROLLBAR_TIMEOUT = 500;
  36. var NativeStrategy = _class2.default.inherit({
  37. ctor: function(scrollable) {
  38. this._init(scrollable)
  39. },
  40. _init: function(scrollable) {
  41. this._component = scrollable;
  42. this._$element = scrollable.$element();
  43. this._$container = scrollable._$container;
  44. this._$content = scrollable._$content;
  45. this._direction = scrollable.option("direction");
  46. this._useSimulatedScrollbar = scrollable.option("useSimulatedScrollbar");
  47. this._showScrollbar = scrollable.option("showScrollbar");
  48. this.option = scrollable.option.bind(scrollable);
  49. this._createActionByOption = scrollable._createActionByOption.bind(scrollable);
  50. this._isLocked = scrollable._isLocked.bind(scrollable);
  51. this._isDirection = scrollable._isDirection.bind(scrollable);
  52. this._allowedDirection = scrollable._allowedDirection.bind(scrollable)
  53. },
  54. render: function() {
  55. this._renderPushBackOffset();
  56. var device = _devices2.default.real();
  57. var deviceType = device.platform;
  58. this._$element.addClass(SCROLLABLE_NATIVE_CLASS).addClass(SCROLLABLE_NATIVE_CLASS + "-" + deviceType).toggleClass(SCROLLABLE_SCROLLBARS_HIDDEN, !this._showScrollbar);
  59. if (this._showScrollbar && this._useSimulatedScrollbar) {
  60. this._renderScrollbars()
  61. }
  62. },
  63. updateBounds: _common.noop,
  64. _renderPushBackOffset: function() {
  65. var pushBackValue = this.option("pushBackValue");
  66. if (!pushBackValue && !this._component._lastPushBackValue) {
  67. return
  68. }
  69. this._$content.css({
  70. paddingTop: pushBackValue,
  71. paddingBottom: pushBackValue
  72. });
  73. this._component._lastPushBackValue = pushBackValue
  74. },
  75. _renderScrollbars: function() {
  76. this._scrollbars = {};
  77. this._hideScrollbarTimeout = 0;
  78. this._$element.addClass(SCROLLABLE_SCROLLBAR_SIMULATED);
  79. this._renderScrollbar(VERTICAL);
  80. this._renderScrollbar(HORIZONTAL)
  81. },
  82. _renderScrollbar: function(direction) {
  83. if (!this._isDirection(direction)) {
  84. return
  85. }
  86. this._scrollbars[direction] = new _ui2.default((0, _renderer2.default)("<div>").appendTo(this._$element), {
  87. direction: direction,
  88. expandable: this._component.option("scrollByThumb")
  89. })
  90. },
  91. handleInit: _common.noop,
  92. handleStart: function() {
  93. this._disablePushBack = true
  94. },
  95. handleMove: function(e) {
  96. if (this._isLocked()) {
  97. e.cancel = true;
  98. return
  99. }
  100. if (this._allowedDirection()) {
  101. e.originalEvent.isScrollingEvent = true
  102. }
  103. },
  104. handleEnd: function() {
  105. this._disablePushBack = false
  106. },
  107. handleCancel: _common.noop,
  108. handleStop: _common.noop,
  109. _eachScrollbar: function(callback) {
  110. callback = callback.bind(this);
  111. (0, _iterator.each)(this._scrollbars || {}, function(direction, scrollbar) {
  112. callback(scrollbar, direction)
  113. })
  114. },
  115. createActions: function() {
  116. this._scrollAction = this._createActionByOption("onScroll");
  117. this._updateAction = this._createActionByOption("onUpdated")
  118. },
  119. _createActionArgs: function() {
  120. var location = this.location();
  121. var containerElement = this._$container.get(0);
  122. return {
  123. event: this._eventForUserAction,
  124. scrollOffset: {
  125. top: -location.top,
  126. left: -location.left
  127. },
  128. reachedLeft: this._isDirection(HORIZONTAL) ? location.left >= 0 : void 0,
  129. reachedRight: this._isDirection(HORIZONTAL) ? Math.abs(location.left) >= containerElement.scrollWidth - containerElement.clientWidth : void 0,
  130. reachedTop: this._isDirection(VERTICAL) ? location.top >= 0 : void 0,
  131. reachedBottom: this._isDirection(VERTICAL) ? Math.abs(location.top) >= containerElement.scrollHeight - containerElement.clientHeight - 2 * this.option("pushBackValue") : void 0
  132. }
  133. },
  134. handleScroll: function(e) {
  135. if (!this._isScrollLocationChanged()) {
  136. e.stopImmediatePropagation();
  137. return
  138. }
  139. this._eventForUserAction = e;
  140. this._moveScrollbars();
  141. this._scrollAction(this._createActionArgs());
  142. this._lastLocation = this.location();
  143. this._pushBackFromBoundary()
  144. },
  145. _pushBackFromBoundary: function() {
  146. var pushBackValue = this.option("pushBackValue");
  147. if (!pushBackValue || this._disablePushBack) {
  148. return
  149. }
  150. var scrollOffset = this._containerSize.height - this._contentSize.height;
  151. var scrollTopPos = this._$container.scrollTop();
  152. var scrollBottomPos = scrollOffset + scrollTopPos - 2 * pushBackValue;
  153. if (!scrollTopPos) {
  154. this._$container.scrollTop(pushBackValue)
  155. } else {
  156. if (!scrollBottomPos) {
  157. this._$container.scrollTop(pushBackValue - scrollOffset)
  158. }
  159. }
  160. },
  161. _isScrollLocationChanged: function() {
  162. var currentLocation = this.location();
  163. var lastLocation = this._lastLocation || {};
  164. var isTopChanged = lastLocation.top !== currentLocation.top;
  165. var isLeftChanged = lastLocation.left !== currentLocation.left;
  166. return isTopChanged || isLeftChanged
  167. },
  168. _moveScrollbars: function() {
  169. this._eachScrollbar(function(scrollbar) {
  170. scrollbar.moveTo(this.location());
  171. scrollbar.option("visible", true)
  172. });
  173. this._hideScrollbars()
  174. },
  175. _hideScrollbars: function() {
  176. clearTimeout(this._hideScrollbarTimeout);
  177. this._hideScrollbarTimeout = setTimeout(function() {
  178. this._eachScrollbar(function(scrollbar) {
  179. scrollbar.option("visible", false)
  180. })
  181. }.bind(this), HIDE_SCROLLBAR_TIMEOUT)
  182. },
  183. location: function() {
  184. return {
  185. left: -this._$container.scrollLeft(),
  186. top: this.option("pushBackValue") - this._$container.scrollTop()
  187. }
  188. },
  189. disabledChanged: _common.noop,
  190. update: function() {
  191. this._update();
  192. this._updateAction(this._createActionArgs())
  193. },
  194. _update: function() {
  195. this._updateDimensions();
  196. this._updateScrollbars()
  197. },
  198. _updateDimensions: function() {
  199. this._containerSize = {
  200. height: this._$container.height(),
  201. width: this._$container.width()
  202. };
  203. this._componentContentSize = {
  204. height: this._component.$content().height(),
  205. width: this._component.$content().width()
  206. };
  207. this._contentSize = {
  208. height: this._$content.height(),
  209. width: this._$content.width()
  210. };
  211. this._pushBackFromBoundary()
  212. },
  213. _updateScrollbars: function() {
  214. this._eachScrollbar(function(scrollbar, direction) {
  215. var dimension = direction === VERTICAL ? "height" : "width";
  216. scrollbar.option({
  217. containerSize: this._containerSize[dimension],
  218. contentSize: this._componentContentSize[dimension]
  219. });
  220. scrollbar.update()
  221. })
  222. },
  223. _allowedDirections: function() {
  224. return {
  225. vertical: this._isDirection(VERTICAL) && this._contentSize.height > this._containerSize.height,
  226. horizontal: this._isDirection(HORIZONTAL) && this._contentSize.width > this._containerSize.width
  227. }
  228. },
  229. dispose: function() {
  230. var className = this._$element.get(0).className;
  231. var scrollableNativeRegexp = new RegExp(SCROLLABLE_NATIVE_CLASS + "\\S*", "g");
  232. if (scrollableNativeRegexp.test(className)) {
  233. this._$element.removeClass(className.match(scrollableNativeRegexp).join(" "))
  234. }
  235. _events_engine2.default.off(this._$element, "." + SCROLLABLE_NATIVE);
  236. _events_engine2.default.off(this._$container, "." + SCROLLABLE_NATIVE);
  237. this._removeScrollbars();
  238. clearTimeout(this._hideScrollbarTimeout)
  239. },
  240. _removeScrollbars: function() {
  241. this._eachScrollbar(function(scrollbar) {
  242. scrollbar.$element().remove()
  243. })
  244. },
  245. scrollBy: function(distance) {
  246. var location = this.location();
  247. this._$container.scrollTop(Math.round(-location.top - distance.top + this.option("pushBackValue")));
  248. this._$container.scrollLeft(Math.round(-location.left - distance.left))
  249. },
  250. validate: function(e) {
  251. if (this.option("disabled")) {
  252. return false
  253. }
  254. if (_utils2.default.isDxMouseWheelEvent(e) && this._isScrolledInMaxDirection(e)) {
  255. return false
  256. }
  257. return !!this._allowedDirection()
  258. },
  259. _isScrolledInMaxDirection: function(e) {
  260. var container = this._$container.get(0);
  261. var result;
  262. if (e.delta > 0) {
  263. result = e.shiftKey ? !container.scrollLeft : !container.scrollTop
  264. } else {
  265. if (e.shiftKey) {
  266. result = container.clientWidth + container.scrollLeft >= container.scrollWidth
  267. } else {
  268. result = container.clientHeight + container.scrollTop >= container.scrollHeight
  269. }
  270. }
  271. return result
  272. },
  273. getDirection: function() {
  274. return this._allowedDirection()
  275. },
  276. verticalOffset: function() {
  277. return this.option("pushBackValue")
  278. }
  279. });
  280. module.exports = NativeStrategy;