RowModel.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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-selection-RowModel'>/**
  19. </span> * Implements row based navigation via keyboard.
  20. *
  21. * Must synchronize across grid sections.
  22. */
  23. Ext.define('Ext.selection.RowModel', {
  24. extend: 'Ext.selection.Model',
  25. alias: 'selection.rowmodel',
  26. requires: ['Ext.util.KeyNav'],
  27. <span id='Ext-selection-RowModel-property-deltaScroll'> /**
  28. </span> * @private
  29. * Number of pixels to scroll to the left/right when pressing
  30. * left/right keys.
  31. */
  32. deltaScroll: 5,
  33. <span id='Ext-selection-RowModel-cfg-enableKeyNav'> /**
  34. </span> * @cfg {Boolean} enableKeyNav
  35. *
  36. * Turns on/off keyboard navigation within the grid.
  37. */
  38. enableKeyNav: true,
  39. <span id='Ext-selection-RowModel-cfg-ignoreRightMouseSelection'> /**
  40. </span> * @cfg {Boolean} [ignoreRightMouseSelection=false]
  41. * True to ignore selections that are made when using the right mouse button if there are
  42. * records that are already selected. If no records are selected, selection will continue
  43. * as normal
  44. */
  45. ignoreRightMouseSelection: false,
  46. constructor: function() {
  47. this.addEvents(
  48. <span id='Ext-selection-RowModel-event-beforedeselect'> /**
  49. </span> * @event beforedeselect
  50. * Fired before a record is deselected. If any listener returns false, the
  51. * deselection is cancelled.
  52. * @param {Ext.selection.RowModel} this
  53. * @param {Ext.data.Model} record The deselected record
  54. * @param {Number} index The row index deselected
  55. */
  56. 'beforedeselect',
  57. <span id='Ext-selection-RowModel-event-beforeselect'> /**
  58. </span> * @event beforeselect
  59. * Fired before a record is selected. If any listener returns false, the
  60. * selection is cancelled.
  61. * @param {Ext.selection.RowModel} this
  62. * @param {Ext.data.Model} record The selected record
  63. * @param {Number} index The row index selected
  64. */
  65. 'beforeselect',
  66. <span id='Ext-selection-RowModel-event-deselect'> /**
  67. </span> * @event deselect
  68. * Fired after a record is deselected
  69. * @param {Ext.selection.RowModel} this
  70. * @param {Ext.data.Model} record The deselected record
  71. * @param {Number} index The row index deselected
  72. */
  73. 'deselect',
  74. <span id='Ext-selection-RowModel-event-select'> /**
  75. </span> * @event select
  76. * Fired after a record is selected
  77. * @param {Ext.selection.RowModel} this
  78. * @param {Ext.data.Model} record The selected record
  79. * @param {Number} index The row index selected
  80. */
  81. 'select'
  82. );
  83. this.views = [];
  84. this.callParent(arguments);
  85. },
  86. bindComponent: function(view) {
  87. var me = this;
  88. me.views = me.views || [];
  89. me.views.push(view);
  90. me.bindStore(view.getStore(), true);
  91. view.on({
  92. itemmousedown: me.onRowMouseDown,
  93. scope: me
  94. });
  95. if (me.enableKeyNav) {
  96. me.initKeyNav(view);
  97. }
  98. },
  99. initKeyNav: function(view) {
  100. var me = this;
  101. if (!view.rendered) {
  102. view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
  103. return;
  104. }
  105. // view.el has tabIndex -1 to allow for
  106. // keyboard events to be passed to it.
  107. view.el.set({
  108. tabIndex: -1
  109. });
  110. // Drive the KeyNav off the View's itemkeydown event so that beforeitemkeydown listeners may veto
  111. me.keyNav = new Ext.util.KeyNav({
  112. target: view,
  113. ignoreInputFields: true,
  114. eventName: 'itemkeydown',
  115. processEvent: function(view, record, node, index, event) {
  116. event.record = record;
  117. event.recordIndex = index;
  118. return event;
  119. },
  120. up: me.onKeyUp,
  121. down: me.onKeyDown,
  122. right: me.onKeyRight,
  123. left: me.onKeyLeft,
  124. pageDown: me.onKeyPageDown,
  125. pageUp: me.onKeyPageUp,
  126. home: me.onKeyHome,
  127. end: me.onKeyEnd,
  128. space: me.onKeySpace,
  129. enter: me.onKeyEnter,
  130. scope: me
  131. });
  132. },
  133. // Returns the number of rows currently visible on the screen or
  134. // false if there were no rows. This assumes that all rows are
  135. // of the same height and the first view is accurate.
  136. getRowsVisible: function() {
  137. var rowsVisible = false,
  138. view = this.views[0],
  139. row = view.getNode(0),
  140. rowHeight, gridViewHeight;
  141. if (row) {
  142. rowHeight = Ext.fly(row).getHeight();
  143. gridViewHeight = view.el.getHeight();
  144. rowsVisible = Math.floor(gridViewHeight / rowHeight);
  145. }
  146. return rowsVisible;
  147. },
  148. // go to last visible record in grid.
  149. onKeyEnd: function(e) {
  150. var me = this,
  151. last = me.store.getAt(me.store.getCount() - 1);
  152. if (last) {
  153. if (e.shiftKey) {
  154. me.selectRange(last, me.lastFocused || 0);
  155. me.setLastFocused(last);
  156. } else if (e.ctrlKey) {
  157. me.setLastFocused(last);
  158. } else {
  159. me.doSelect(last);
  160. }
  161. }
  162. },
  163. // go to first visible record in grid.
  164. onKeyHome: function(e) {
  165. var me = this,
  166. first = me.store.getAt(0);
  167. if (first) {
  168. if (e.shiftKey) {
  169. me.selectRange(first, me.lastFocused || 0);
  170. me.setLastFocused(first);
  171. } else if (e.ctrlKey) {
  172. me.setLastFocused(first);
  173. } else {
  174. me.doSelect(first, false);
  175. }
  176. }
  177. },
  178. // Go one page up from the lastFocused record in the grid.
  179. onKeyPageUp: function(e) {
  180. var me = this,
  181. rowsVisible = me.getRowsVisible(),
  182. selIdx,
  183. prevIdx,
  184. prevRecord;
  185. if (rowsVisible) {
  186. selIdx = e.recordIndex;
  187. prevIdx = selIdx - rowsVisible;
  188. if (prevIdx &lt; 0) {
  189. prevIdx = 0;
  190. }
  191. prevRecord = me.store.getAt(prevIdx);
  192. if (e.shiftKey) {
  193. me.selectRange(prevRecord, e.record, e.ctrlKey, 'up');
  194. me.setLastFocused(prevRecord);
  195. } else if (e.ctrlKey) {
  196. e.preventDefault();
  197. me.setLastFocused(prevRecord);
  198. } else {
  199. me.doSelect(prevRecord);
  200. }
  201. }
  202. },
  203. // Go one page down from the lastFocused record in the grid.
  204. onKeyPageDown: function(e) {
  205. var me = this,
  206. rowsVisible = me.getRowsVisible(),
  207. selIdx,
  208. nextIdx,
  209. nextRecord;
  210. if (rowsVisible) {
  211. selIdx = e.recordIndex;
  212. nextIdx = selIdx + rowsVisible;
  213. if (nextIdx &gt;= me.store.getCount()) {
  214. nextIdx = me.store.getCount() - 1;
  215. }
  216. nextRecord = me.store.getAt(nextIdx);
  217. if (e.shiftKey) {
  218. me.selectRange(nextRecord, e.record, e.ctrlKey, 'down');
  219. me.setLastFocused(nextRecord);
  220. } else if (e.ctrlKey) {
  221. // some browsers, this means go thru browser tabs
  222. // attempt to stop.
  223. e.preventDefault();
  224. me.setLastFocused(nextRecord);
  225. } else {
  226. me.doSelect(nextRecord);
  227. }
  228. }
  229. },
  230. // Select/Deselect based on pressing Spacebar.
  231. // Assumes a SIMPLE selectionmode style
  232. onKeySpace: function(e) {
  233. var me = this,
  234. record = me.lastFocused;
  235. if (record) {
  236. if (me.isSelected(record)) {
  237. me.doDeselect(record, false);
  238. } else {
  239. me.doSelect(record, true);
  240. }
  241. }
  242. },
  243. onKeyEnter: Ext.emptyFn,
  244. // Navigate one record up. This could be a selection or
  245. // could be simply focusing a record for discontiguous
  246. // selection. Provides bounds checking.
  247. onKeyUp: function(e) {
  248. var me = this,
  249. idx = me.store.indexOf(me.lastFocused),
  250. record;
  251. if (idx &gt; 0) {
  252. // needs to be the filtered count as thats what
  253. // will be visible.
  254. record = me.store.getAt(idx - 1);
  255. if (e.shiftKey &amp;&amp; me.lastFocused) {
  256. if (me.isSelected(me.lastFocused) &amp;&amp; me.isSelected(record)) {
  257. me.doDeselect(me.lastFocused, true);
  258. me.setLastFocused(record);
  259. } else if (!me.isSelected(me.lastFocused)) {
  260. me.doSelect(me.lastFocused, true);
  261. me.doSelect(record, true);
  262. } else {
  263. me.doSelect(record, true);
  264. }
  265. } else if (e.ctrlKey) {
  266. me.setLastFocused(record);
  267. } else {
  268. me.doSelect(record);
  269. //view.focusRow(idx - 1);
  270. }
  271. }
  272. // There was no lastFocused record, and the user has pressed up
  273. // Ignore??
  274. //else if (this.selected.getCount() == 0) {
  275. //
  276. // this.doSelect(record);
  277. // //view.focusRow(idx - 1);
  278. //}
  279. },
  280. // Navigate one record down. This could be a selection or
  281. // could be simply focusing a record for discontiguous
  282. // selection. Provides bounds checking.
  283. onKeyDown: function(e) {
  284. var me = this,
  285. idx = me.store.indexOf(me.lastFocused),
  286. record;
  287. // needs to be the filtered count as thats what
  288. // will be visible.
  289. if (idx + 1 &lt; me.store.getCount()) {
  290. record = me.store.getAt(idx + 1);
  291. if (me.selected.getCount() === 0) {
  292. if (!e.ctrlKey) {
  293. me.doSelect(record);
  294. } else {
  295. me.setLastFocused(record);
  296. }
  297. //view.focusRow(idx + 1);
  298. } else if (e.shiftKey &amp;&amp; me.lastFocused) {
  299. if (me.isSelected(me.lastFocused) &amp;&amp; me.isSelected(record)) {
  300. me.doDeselect(me.lastFocused, true);
  301. me.setLastFocused(record);
  302. } else if (!me.isSelected(me.lastFocused)) {
  303. me.doSelect(me.lastFocused, true);
  304. me.doSelect(record, true);
  305. } else {
  306. me.doSelect(record, true);
  307. }
  308. } else if (e.ctrlKey) {
  309. me.setLastFocused(record);
  310. } else {
  311. me.doSelect(record);
  312. //view.focusRow(idx + 1);
  313. }
  314. }
  315. },
  316. scrollByDeltaX: function(delta) {
  317. var view = this.views[0],
  318. section = view.up(),
  319. hScroll = section.horizontalScroller;
  320. if (hScroll) {
  321. hScroll.scrollByDeltaX(delta);
  322. }
  323. },
  324. onKeyLeft: function(e) {
  325. this.scrollByDeltaX(-this.deltaScroll);
  326. },
  327. onKeyRight: function(e) {
  328. this.scrollByDeltaX(this.deltaScroll);
  329. },
  330. // Select the record with the event included so that
  331. // we can take into account ctrlKey, shiftKey, etc
  332. onRowMouseDown: function(view, record, item, index, e) {
  333. if (!this.allowRightMouseSelection(e)) {
  334. return;
  335. }
  336. if (e.button === 0 || !this.isSelected(record)) {
  337. this.selectWithEvent(record, e);
  338. }
  339. },
  340. <span id='Ext-selection-RowModel-method-allowRightMouseSelection'> /**
  341. </span> * Checks whether a selection should proceed based on the ignoreRightMouseSelection
  342. * option.
  343. * @private
  344. * @param {Ext.EventObject} e The event
  345. * @return {Boolean} False if the selection should not proceed
  346. */
  347. allowRightMouseSelection: function(e) {
  348. var disallow = this.ignoreRightMouseSelection &amp;&amp; e.button !== 0;
  349. if (disallow) {
  350. disallow = this.hasSelection();
  351. }
  352. return !disallow;
  353. },
  354. // Allow the GridView to update the UI by
  355. // adding/removing a CSS class from the row.
  356. onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
  357. var me = this,
  358. views = me.views,
  359. viewsLn = views.length,
  360. store = me.store,
  361. rowIdx = store.indexOf(record),
  362. eventName = isSelected ? 'select' : 'deselect',
  363. i = 0;
  364. if ((suppressEvent || me.fireEvent('before' + eventName, me, record, rowIdx)) !== false &amp;&amp;
  365. commitFn() !== false) {
  366. for (; i &lt; viewsLn; i++) {
  367. if (isSelected) {
  368. views[i].onRowSelect(rowIdx, suppressEvent);
  369. } else {
  370. views[i].onRowDeselect(rowIdx, suppressEvent);
  371. }
  372. }
  373. if (!suppressEvent) {
  374. me.fireEvent(eventName, me, record, rowIdx);
  375. }
  376. }
  377. },
  378. // Provide indication of what row was last focused via
  379. // the gridview.
  380. onLastFocusChanged: function(oldFocused, newFocused, supressFocus) {
  381. var views = this.views,
  382. viewsLn = views.length,
  383. store = this.store,
  384. rowIdx,
  385. i = 0;
  386. if (oldFocused) {
  387. rowIdx = store.indexOf(oldFocused);
  388. if (rowIdx != -1) {
  389. for (; i &lt; viewsLn; i++) {
  390. views[i].onRowFocus(rowIdx, false);
  391. }
  392. }
  393. }
  394. if (newFocused) {
  395. rowIdx = store.indexOf(newFocused);
  396. if (rowIdx != -1) {
  397. for (i = 0; i &lt; viewsLn; i++) {
  398. views[i].onRowFocus(rowIdx, true, supressFocus);
  399. }
  400. }
  401. }
  402. this.callParent();
  403. },
  404. onEditorTab: function(editingPlugin, e) {
  405. var me = this,
  406. view = me.views[0],
  407. record = editingPlugin.getActiveRecord(),
  408. header = editingPlugin.getActiveColumn(),
  409. position = view.getPosition(record, header),
  410. direction = e.shiftKey ? 'left' : 'right';
  411. do {
  412. position = view.walkCells(position, direction, e, me.preventWrap);
  413. } while(position &amp;&amp; !view.headerCt.getHeaderAtIndex(position.column).getEditor());
  414. if (position) {
  415. editingPlugin.startEditByPosition(position);
  416. }
  417. },
  418. <span id='Ext-selection-RowModel-method-getCurrentPosition'> /**
  419. </span> * Returns position of the first selected cell in the selection in the format {row: row, column: column}
  420. */
  421. getCurrentPosition: function() {
  422. var firstSelection = this.selected.items[0];
  423. if (firstSelection) {
  424. return {
  425. row: this.store.indexOf(firstSelection),
  426. column: 0
  427. };
  428. }
  429. },
  430. selectByPosition: function(position) {
  431. var record = this.store.getAt(position.row);
  432. this.select(record);
  433. },
  434. <span id='Ext-selection-RowModel-method-selectNext'> /**
  435. </span> * Selects the record immediately following the currently selected record.
  436. * @param {Boolean} [keepExisting] True to retain existing selections
  437. * @param {Boolean} [suppressEvent] Set to false to not fire a select event
  438. * @return {Boolean} `true` if there is a next record, else `false`
  439. */
  440. selectNext: function(keepExisting, suppressEvent) {
  441. var me = this,
  442. store = me.store,
  443. selection = me.getSelection(),
  444. record = selection[selection.length - 1],
  445. index = store.indexOf(record) + 1,
  446. success;
  447. if(index === store.getCount() || index === 0) {
  448. success = false;
  449. } else {
  450. me.doSelect(index, keepExisting, suppressEvent);
  451. success = true;
  452. }
  453. return success;
  454. },
  455. <span id='Ext-selection-RowModel-method-selectPrevious'> /**
  456. </span> * Selects the record that precedes the currently selected record.
  457. * @param {Boolean} [keepExisting] True to retain existing selections
  458. * @param {Boolean} [suppressEvent] Set to false to not fire a select event
  459. * @return {Boolean} `true` if there is a previous record, else `false`
  460. */
  461. selectPrevious: function(keepExisting, suppressEvent) {
  462. var me = this,
  463. selection = me.getSelection(),
  464. record = selection[0],
  465. index = me.store.indexOf(record) - 1,
  466. success;
  467. if (index &lt; 0) {
  468. success = false;
  469. } else {
  470. me.doSelect(index, keepExisting, suppressEvent);
  471. success = true;
  472. }
  473. return success;
  474. }
  475. });</pre>
  476. </body>
  477. </html>