Scroller2.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-layout-container-boxOverflow-Scroller'>/**
  19. </span> * @private
  20. */
  21. Ext.define('Ext.layout.container.boxOverflow.Scroller', {
  22. /* Begin Definitions */
  23. extend: 'Ext.layout.container.boxOverflow.None',
  24. requires: ['Ext.util.ClickRepeater', 'Ext.Element'],
  25. alternateClassName: 'Ext.layout.boxOverflow.Scroller',
  26. mixins: {
  27. observable: 'Ext.util.Observable'
  28. },
  29. /* End Definitions */
  30. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-animateScroll'> /**
  31. </span> * @cfg {Boolean} animateScroll
  32. * True to animate the scrolling of items within the layout (ignored if enableScroll is false)
  33. */
  34. animateScroll: false,
  35. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollIncrement'> /**
  36. </span> * @cfg {Number} scrollIncrement
  37. * The number of pixels to scroll by on scroller click
  38. */
  39. scrollIncrement: 20,
  40. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-wheelIncrement'> /**
  41. </span> * @cfg {Number} wheelIncrement
  42. * The number of pixels to increment on mouse wheel scrolling.
  43. */
  44. wheelIncrement: 10,
  45. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollRepeatInterval'> /**
  46. </span> * @cfg {Number} scrollRepeatInterval
  47. * Number of milliseconds between each scroll while a scroller button is held down
  48. */
  49. scrollRepeatInterval: 60,
  50. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollDuration'> /**
  51. </span> * @cfg {Number} scrollDuration
  52. * Number of milliseconds that each scroll animation lasts
  53. */
  54. scrollDuration: 400,
  55. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-beforeCtCls'> /**
  56. </span> * @cfg {String} beforeCtCls
  57. * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
  58. * which must always be present at the leftmost edge of the Container
  59. */
  60. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-afterCtCls'> /**
  61. </span> * @cfg {String} afterCtCls
  62. * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
  63. * which must always be present at the rightmost edge of the Container
  64. */
  65. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollerCls'> /**
  66. </span> * @cfg {String} [scrollerCls='x-box-scroller']
  67. * CSS class added to both scroller elements if enableScroll is used
  68. */
  69. scrollerCls: Ext.baseCSSPrefix + 'box-scroller',
  70. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-beforeScrollerCls'> /**
  71. </span> * @cfg {String} beforeScrollerCls
  72. * CSS class added to the left scroller element if enableScroll is used
  73. */
  74. <span id='Ext-layout-container-boxOverflow-Scroller-cfg-afterScrollerCls'> /**
  75. </span> * @cfg {String} afterScrollerCls
  76. * CSS class added to the right scroller element if enableScroll is used
  77. */
  78. constructor: function(layout, config) {
  79. var me = this;
  80. me.layout = layout;
  81. Ext.apply(me, config || {});
  82. // Dont pass the config so that it is not applied to 'this' again
  83. me.mixins.observable.constructor.call(me);
  84. me.addEvents(
  85. <span id='Ext-layout-container-boxOverflow-Scroller-event-scroll'> /**
  86. </span> * @event scroll
  87. * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller
  88. * @param {Number} newPosition The new position of the scroller
  89. * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false
  90. */
  91. 'scroll'
  92. );
  93. me.scrollPosition = 0;
  94. me.scrollSize = 0;
  95. },
  96. getPrefixConfig: function() {
  97. var me = this;
  98. me.initCSSClasses();
  99. return {
  100. cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls,
  101. cn : {
  102. id : me.layout.owner.id + '-before-scroller',
  103. cls: me.scrollerCls + ' ' + me.beforeScrollerCls,
  104. style: 'display:none'
  105. }
  106. };
  107. },
  108. getSuffixConfig: function() {
  109. var me = this;
  110. return {
  111. cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls,
  112. cn : {
  113. id : me.layout.owner.id + '-after-scroller',
  114. cls: me.scrollerCls + ' ' + me.afterScrollerCls,
  115. style: 'display:none'
  116. }
  117. };
  118. },
  119. getOverflowCls: function() {
  120. return Ext.baseCSSPrefix + this.layout.direction + '-box-overflow-body';
  121. },
  122. initCSSClasses: function() {
  123. var me = this,
  124. prefix = Ext.baseCSSPrefix,
  125. layout = me.layout,
  126. names = layout.getNames(),
  127. leftName = names.left,
  128. rightName = names.right,
  129. type = me.getOwnerType(layout.owner);
  130. me.beforeCtCls = me.beforeCtCls || prefix + 'box-scroller-' + leftName;
  131. me.afterCtCls = me.afterCtCls || prefix + 'box-scroller-' + rightName;
  132. me.beforeScrollerCls = me.beforeScrollerCls || prefix + type + '-scroll-' + leftName;
  133. me.afterScrollerCls = me.afterScrollerCls || prefix + type + '-scroll-' + rightName;
  134. },
  135. beginLayout: function (ownerContext) {
  136. var layout = this.layout,
  137. names = layout.getNames();
  138. ownerContext.innerCtScrollPos = layout.innerCt.dom['scroll' + names.leftCap];
  139. this.callParent(arguments);
  140. },
  141. completeLayout: function (ownerContext) {
  142. // capture this before callParent since it calls handle/clearOverflow:
  143. this.scrollSize = ownerContext.props['content'+this.layout.getNames().widthCap];
  144. this.callParent(arguments);
  145. },
  146. finishedLayout: function(ownerContext) {
  147. var me = this,
  148. layout = me.layout,
  149. names = layout.getNames(),
  150. scrollPos = Math.min(me.getMaxScrollPosition(), ownerContext.innerCtScrollPos);
  151. layout.innerCt.dom['scroll' + names.leftCap] = scrollPos;
  152. },
  153. handleOverflow: function(ownerContext) {
  154. var me = this,
  155. layout = me.layout,
  156. names = layout.getNames(),
  157. methodName = 'get' + names.widthCap;
  158. me.captureChildElements();
  159. me.showScrollers();
  160. return {
  161. reservedSpace: me.beforeCt[methodName]() + me.afterCt[methodName]()
  162. };
  163. },
  164. <span id='Ext-layout-container-boxOverflow-Scroller-method-captureChildElements'> /**
  165. </span> * @private
  166. * Gets references to the beforeCt and afterCt elements if they have not already been captured
  167. * and creates click handlers for them.
  168. */
  169. captureChildElements: function() {
  170. var me = this,
  171. el = me.layout.owner.el,
  172. before,
  173. after;
  174. // Grab the scroll click receiving elements
  175. if (!me.beforeCt) {
  176. before = me.beforeScroller = el.getById(me.layout.owner.id + '-before-scroller');
  177. after = me.afterScroller = el.getById(me.layout.owner.id + '-after-scroller');
  178. me.beforeCt = before.up('');
  179. me.afterCt = after.up('');
  180. me.createWheelListener();
  181. before.addClsOnOver(me.beforeScrollerCls + '-hover');
  182. after.addClsOnOver(me.afterScrollerCls + '-hover');
  183. before.setVisibilityMode(Ext.Element.DISPLAY);
  184. after.setVisibilityMode(Ext.Element.DISPLAY);
  185. me.beforeRepeater = new Ext.util.ClickRepeater(before, {
  186. interval: me.scrollRepeatInterval,
  187. handler : me.scrollLeft,
  188. scope : me
  189. });
  190. me.afterRepeater = new Ext.util.ClickRepeater(after, {
  191. interval: me.scrollRepeatInterval,
  192. handler : me.scrollRight,
  193. scope : me
  194. });
  195. }
  196. },
  197. <span id='Ext-layout-container-boxOverflow-Scroller-method-createWheelListener'> /**
  198. </span> * @private
  199. * Sets up an listener to scroll on the layout's innerCt mousewheel event
  200. */
  201. createWheelListener: function() {
  202. this.layout.innerCt.on({
  203. mousewheel: function(e) {
  204. this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
  205. },
  206. stopEvent: true,
  207. scope: this
  208. });
  209. },
  210. <span id='Ext-layout-container-boxOverflow-Scroller-method-clearOverflow'> /**
  211. </span> * @private
  212. */
  213. clearOverflow: function () {
  214. var layout = this.layout;
  215. this.hideScrollers();
  216. },
  217. <span id='Ext-layout-container-boxOverflow-Scroller-method-showScrollers'> /**
  218. </span> * @private
  219. * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
  220. * present.
  221. */
  222. showScrollers: function() {
  223. var me = this;
  224. me.captureChildElements();
  225. me.beforeScroller.show();
  226. me.afterScroller.show();
  227. me.updateScrollButtons();
  228. me.layout.owner.addClsWithUI('scroller');
  229. // TODO - this may invalidates data in the ContextItem's styleCache
  230. },
  231. <span id='Ext-layout-container-boxOverflow-Scroller-method-hideScrollers'> /**
  232. </span> * @private
  233. * Hides the scroller elements in the beforeCt and afterCt
  234. */
  235. hideScrollers: function() {
  236. var me = this;
  237. if (me.beforeScroller !== undefined) {
  238. me.beforeScroller.hide();
  239. me.afterScroller.hide();
  240. me.layout.owner.removeClsWithUI('scroller');
  241. // TODO - this may invalidates data in the ContextItem's styleCache
  242. }
  243. },
  244. <span id='Ext-layout-container-boxOverflow-Scroller-method-destroy'> /**
  245. </span> * @private
  246. */
  247. destroy: function() {
  248. var me = this;
  249. Ext.destroy(me.beforeRepeater, me.afterRepeater, me.beforeScroller, me.afterScroller, me.beforeCt, me.afterCt);
  250. },
  251. <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollBy'> /**
  252. </span> * @private
  253. * Scrolls left or right by the number of pixels specified
  254. * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
  255. */
  256. scrollBy: function(delta, animate) {
  257. this.scrollTo(this.getScrollPosition() + delta, animate);
  258. },
  259. <span id='Ext-layout-container-boxOverflow-Scroller-method-getScrollAnim'> /**
  260. </span> * @private
  261. * @return {Object} Object passed to scrollTo when scrolling
  262. */
  263. getScrollAnim: function() {
  264. return {
  265. duration: this.scrollDuration,
  266. callback: this.updateScrollButtons,
  267. scope : this
  268. };
  269. },
  270. <span id='Ext-layout-container-boxOverflow-Scroller-method-updateScrollButtons'> /**
  271. </span> * @private
  272. * Enables or disables each scroller button based on the current scroll position
  273. */
  274. updateScrollButtons: function() {
  275. var me = this,
  276. beforeMeth,
  277. afterMeth,
  278. beforeCls,
  279. afterCls;
  280. if (me.beforeScroller === undefined || me.afterScroller === undefined) {
  281. return;
  282. }
  283. beforeMeth = me.atExtremeBefore() ? 'addCls' : 'removeCls';
  284. afterMeth = me.atExtremeAfter() ? 'addCls' : 'removeCls';
  285. beforeCls = me.beforeScrollerCls + '-disabled';
  286. afterCls = me.afterScrollerCls + '-disabled';
  287. me.beforeScroller[beforeMeth](beforeCls);
  288. me.afterScroller[afterMeth](afterCls);
  289. me.scrolling = false;
  290. },
  291. <span id='Ext-layout-container-boxOverflow-Scroller-method-atExtremeBefore'> /**
  292. </span> * @private
  293. * Returns true if the innerCt scroll is already at its left-most point
  294. * @return {Boolean} True if already at furthest left point
  295. */
  296. atExtremeBefore: function() {
  297. return !this.getScrollPosition();
  298. },
  299. <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollLeft'> /**
  300. </span> * @private
  301. * Scrolls to the left by the configured amount
  302. */
  303. scrollLeft: function() {
  304. this.scrollBy(-this.scrollIncrement, false);
  305. },
  306. <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollRight'> /**
  307. </span> * @private
  308. * Scrolls to the right by the configured amount
  309. */
  310. scrollRight: function() {
  311. this.scrollBy(this.scrollIncrement, false);
  312. },
  313. <span id='Ext-layout-container-boxOverflow-Scroller-method-getScrollPosition'> /**
  314. </span> * Returns the current scroll position of the innerCt element
  315. * @return {Number} The current scroll position
  316. */
  317. getScrollPosition: function(){
  318. var me = this,
  319. layout = me.layout,
  320. result;
  321. // Until we actually scroll, the scroll[Top|Left] is stored as zero to avoid DOM hits.
  322. if (me.hasOwnProperty('scrollPosition')) {
  323. result = me.scrollPosition;
  324. } else {
  325. result = parseInt(layout.innerCt.dom['scroll' + layout.getNames().leftCap], 10) || 0;
  326. }
  327. return result;
  328. },
  329. <span id='Ext-layout-container-boxOverflow-Scroller-method-getMaxScrollPosition'> /**
  330. </span> * @private
  331. * Returns the maximum value we can scrollTo
  332. * @return {Number} The max scroll value
  333. */
  334. getMaxScrollPosition: function() {
  335. var me = this,
  336. layout = me.layout,
  337. names = layout.getNames(),
  338. maxScrollPos = me.scrollSize - layout.innerCt['get'+names.widthCap]();
  339. return (maxScrollPos &lt; 0) ? 0 : maxScrollPos;
  340. },
  341. <span id='Ext-layout-container-boxOverflow-Scroller-method-atExtremeAfter'> /**
  342. </span> * @private
  343. * Returns true if the innerCt scroll is already at its right-most point
  344. * @return {Boolean} True if already at furthest right point
  345. */
  346. atExtremeAfter: function() {
  347. return this.getScrollPosition() &gt;= this.getMaxScrollPosition();
  348. },
  349. <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollTo'> /**
  350. </span> * @private
  351. * Scrolls to the given position. Performs bounds checking.
  352. * @param {Number} position The position to scroll to. This is constrained.
  353. * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
  354. */
  355. scrollTo: function(position, animate) {
  356. var me = this,
  357. layout = me.layout,
  358. names = layout.getNames(),
  359. oldPosition = me.getScrollPosition(),
  360. newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());
  361. if (newPosition != oldPosition &amp;&amp; !me.scrolling) {
  362. delete me.scrollPosition;
  363. if (animate === undefined) {
  364. animate = me.animateScroll;
  365. }
  366. layout.innerCt.scrollTo(names.left, newPosition, animate ? me.getScrollAnim() : false);
  367. if (animate) {
  368. me.scrolling = true;
  369. } else {
  370. me.updateScrollButtons();
  371. }
  372. me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
  373. }
  374. },
  375. <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollToItem'> /**
  376. </span> * Scrolls to the given component.
  377. * @param {String/Number/Ext.Component} item The item to scroll to. Can be a numerical index, component id
  378. * or a reference to the component itself.
  379. * @param {Boolean} animate True to animate the scrolling
  380. */
  381. scrollToItem: function(item, animate) {
  382. var me = this,
  383. layout = me.layout,
  384. names = layout.getNames(),
  385. visibility,
  386. box,
  387. newPos;
  388. item = me.getItem(item);
  389. if (item !== undefined) {
  390. visibility = me.getItemVisibility(item);
  391. if (!visibility.fullyVisible) {
  392. box = item.getBox(true, true);
  393. newPos = box[names.x];
  394. if (visibility.hiddenEnd) {
  395. newPos -= (me.layout.innerCt['get' + names.widthCap]() - box[names.width]);
  396. }
  397. me.scrollTo(newPos, animate);
  398. }
  399. }
  400. },
  401. <span id='Ext-layout-container-boxOverflow-Scroller-method-getItemVisibility'> /**
  402. </span> * @private
  403. * For a given item in the container, return an object with information on whether the item is visible
  404. * with the current innerCt scroll value.
  405. * @param {Ext.Component} item The item
  406. * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd
  407. */
  408. getItemVisibility: function(item) {
  409. var me = this,
  410. box = me.getItem(item).getBox(true, true),
  411. layout = me.layout,
  412. names = layout.getNames(),
  413. itemStart = box[names.x],
  414. itemEnd = itemStart + box[names.width],
  415. scrollStart = me.getScrollPosition(),
  416. scrollEnd = scrollStart + layout.innerCt['get' + names.widthCap]();
  417. return {
  418. hiddenStart : itemStart &lt; scrollStart,
  419. hiddenEnd : itemEnd &gt; scrollEnd,
  420. fullyVisible: itemStart &gt; scrollStart &amp;&amp; itemEnd &lt; scrollEnd
  421. };
  422. }
  423. });
  424. </pre>
  425. </body>
  426. </html>