5f87135929726b475b022ee869f058c96d8dc04d.svn-base 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670
  1. /*
  2. * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com
  3. *
  4. * http://extjs.com/license
  5. */
  6. /**
  7. * @class Ext.grid.GridView
  8. * @extends Ext.util.Observable
  9. * <p>
  10. * This class encapsulates the user interface of an
  11. * {@link Ext.grid.GridPanel}. Methods of this class may be used to
  12. * access user interface elements to enable special display effects. Do
  13. * not change the DOM structure of the user interface.
  14. * </p>
  15. * <p>
  16. * This class does not provide ways to manipulate the underlying data.
  17. * The data model of a Grid is held in an {@link Ext.data.Store}.
  18. * </p>
  19. * @constructor
  20. * @param {Object}
  21. * config
  22. */
  23. Ext.grid.GridView = function(config) {
  24. Ext.apply(this, config);
  25. // These events are only used internally by the grid components
  26. this.addEvents(
  27. /**
  28. * @event beforerowremoved Internal UI Event. Fired before a row is
  29. * removed.
  30. * @param {Ext.grid.GridView}
  31. * view
  32. * @param {Number}
  33. * rowIndex The index of the row to be removed.
  34. * @param {Ext.data.Record}
  35. * record The Record to be removed
  36. */
  37. "beforerowremoved",
  38. /**
  39. * @event beforerowsinserted Internal UI Event. Fired before rows
  40. * are inserted.
  41. * @param {Ext.grid.GridView}
  42. * view
  43. * @param {Number}
  44. * firstRow The index of the first row to be inserted.
  45. * @param {Number}
  46. * lastRow The index of the last row to be inserted.
  47. */
  48. "beforerowsinserted",
  49. /**
  50. * @event beforerefresh Internal UI Event. Fired before the view is
  51. * refreshed.
  52. * @param {Ext.grid.GridView}
  53. * view
  54. */
  55. "beforerefresh",
  56. /**
  57. * @event rowremoved Internal UI Event. Fired after a row is
  58. * removed.
  59. * @param {Ext.grid.GridView}
  60. * view
  61. * @param {Number}
  62. * rowIndex The index of the row that was removed.
  63. * @param {Ext.data.Record}
  64. * record The Record that was removed
  65. */
  66. "rowremoved",
  67. /**
  68. * @event rowsinserted Internal UI Event. Fired after rows are
  69. * inserted.
  70. * @param {Ext.grid.GridView}
  71. * view
  72. * @param {Number}
  73. * firstRow The index of the first inserted.
  74. * @param {Number}
  75. * lastRow The index of the last row inserted.
  76. */
  77. "rowsinserted",
  78. /**
  79. * @event rowupdated Internal UI Event. Fired after a row has been
  80. * updated.
  81. * @param {Ext.grid.GridView}
  82. * view
  83. * @param {Number}
  84. * firstRow The index of the row updated.
  85. * @param {Ext.data.record}
  86. * record The Record backing the row updated.
  87. */
  88. "rowupdated",
  89. /**
  90. * @event refresh Internal UI Event. Fired after the GridView's body
  91. * has been refreshed.
  92. * @param {Ext.grid.GridView}
  93. * view
  94. */
  95. "refresh");
  96. Ext.grid.GridView.superclass.constructor.call(this);
  97. };
  98. Ext.extend(Ext.grid.GridView, Ext.util.Observable, {
  99. /**
  100. * Override this function to apply custom CSS classes to rows during
  101. * rendering. You can also supply custom parameters to the row template for
  102. * the current row to customize how it is rendered using the <b>rowParams</b>
  103. * parameter. This function should return the CSS class name (or empty
  104. * string '' for none) that will be added to the row's wrapping div. To
  105. * apply multiple class names, simply return them space-delimited within the
  106. * string (e.g., 'my-class another-class').
  107. *
  108. * @param {Record}
  109. * record The {@link Ext.data.Record} corresponding to the
  110. * current row
  111. * @param {Number}
  112. * index The row index
  113. * @param {Object}
  114. * rowParams A config object that is passed to the row template
  115. * during rendering that allows customization of various aspects
  116. * of a body row, if applicable. Note that this object will only
  117. * be applied if {@link #enableRowBody} = true, otherwise it will
  118. * be ignored. The object may contain any of these properties:
  119. * <ul>
  120. * <li><code>body</code> : String <div class="sub-desc">An
  121. * HTML fragment to be rendered as the cell's body content
  122. * (defaults to '').</div></li>
  123. * <li><code>bodyStyle</code> : String <div class="sub-desc">A
  124. * CSS style string that will be applied to the row's TR style
  125. * attribute (defaults to '').</div></li>
  126. * <li><code>cols</code> : Number <div class="sub-desc">The
  127. * column count to apply to the body row's TD colspan attribute
  128. * (defaults to the current column count of the grid).</div></li>
  129. * </ul>
  130. * @param {Store}
  131. * store The {@link Ext.data.Store} this grid is bound to
  132. * @method getRowClass
  133. * @return {String} a CSS class name to add to the row.
  134. */
  135. /**
  136. * @cfg {Boolean} enableRowBody True to add a second TR element per row that
  137. * can be used to provide a row body that spans beneath the data row.
  138. * Use the {@link #getRowClass} method's rowParams config to customize
  139. * the row body.
  140. */
  141. /**
  142. * @cfg {String} emptyText Default text to display in the grid body when no
  143. * rows are available (defaults to '').
  144. */
  145. /**
  146. * The amount of space to reserve for the scrollbar (defaults to 19 pixels)
  147. *
  148. * @type Number
  149. */
  150. scrollOffset : 19,
  151. /**
  152. * @cfg {Boolean} autoFill True to auto expand the columns to fit the grid
  153. * <b>when the grid is created</b>.
  154. */
  155. autoFill : false,
  156. /**
  157. * @cfg {Boolean} forceFit True to auto expand/contract the size of the
  158. * columns to fit the grid width and prevent horizontal scrolling.
  159. */
  160. forceFit : false,
  161. /**
  162. * The CSS classes applied to a header when it is sorted. (defaults to
  163. * ["sort-asc", "sort-desc"])
  164. *
  165. * @type Array
  166. */
  167. sortClasses : ["sort-asc", "sort-desc"],
  168. /**
  169. * The text displayed in the "Sort Ascending" menu item
  170. *
  171. * @type String
  172. */
  173. sortAscText : "Sort Ascending",
  174. /**
  175. * The text displayed in the "Sort Descending" menu item
  176. *
  177. * @type String
  178. */
  179. sortDescText : "Sort Descending",
  180. /**
  181. * The text displayed in the "Columns" menu item
  182. *
  183. * @type String
  184. */
  185. columnsText : "Columns",
  186. // private
  187. borderWidth : 2,
  188. /*
  189. * -------------------------------- UI Specific
  190. * -----------------------------
  191. */
  192. // private
  193. initTemplates : function() {
  194. var ts = this.templates || {};
  195. if (!ts.master) {
  196. ts.master = new Ext.Template(
  197. '<div class="x-grid3" hidefocus="true">',
  198. '<div class="x-grid3-viewport">',
  199. '<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset">{header}</div></div><div class="x-clear"></div></div>',
  200. '<div class="x-grid3-scroller"><div class="x-grid3-body">{body}</div><a href="javascript:;" class="x-grid3-focus" tabIndex="-1"></a></div>',
  201. "</div>",
  202. '<div class="x-grid3-resize-marker">&#160;</div>',
  203. '<div class="x-grid3-resize-proxy">&#160;</div>', "</div>");
  204. }
  205. if (!ts.header) {
  206. ts.header = new Ext.Template(
  207. '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  208. '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',
  209. "</table>");
  210. }
  211. if (!ts.hcell) {
  212. ts.hcell = new Ext.Template(
  213. '<td class="x-grid3-hd x-grid3-cell x-grid3-td-{id}" style="{style}"><div {attr} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">',
  214. this.grid.enableHdMenu
  215. ? '<a class="x-grid3-hd-btn" href="javascript:;"></a>'
  216. : '',
  217. '{value}<img class="x-grid3-sort-icon" src="',
  218. Ext.BLANK_IMAGE_URL, '" />', "</div></td>");
  219. }
  220. if (!ts.body) {
  221. ts.body = new Ext.Template('{rows}');
  222. }
  223. if (!ts.row) {
  224. ts.row = new Ext.Template(
  225. '<div class="x-grid3-row {alt}" style="{tstyle}"><table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  226. '<tbody><tr>{cells}</tr>',
  227. (this.enableRowBody
  228. ? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>'
  229. : ''), '</tbody></table></div>');
  230. }
  231. if (!ts.cell) {
  232. ts.cell = new Ext.Template(
  233. '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>',
  234. '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>',
  235. "</td>");
  236. }
  237. for (var k in ts) {
  238. var t = ts[k];
  239. if (t && typeof t.compile == 'function' && !t.compiled) {
  240. t.disableFormats = true;
  241. t.compile();
  242. }
  243. }
  244. this.templates = ts;
  245. this.tdClass = 'x-grid3-cell';
  246. this.cellSelector = 'td.x-grid3-cell';
  247. this.hdCls = 'x-grid3-hd';
  248. this.rowSelector = 'div.x-grid3-row';
  249. this.colRe = new RegExp("x-grid3-td-([^\\s]+)", "");
  250. },
  251. // private
  252. fly : function(el) {
  253. if (!this._flyweight) {
  254. this._flyweight = new Ext.Element.Flyweight(document.body);
  255. }
  256. this._flyweight.dom = el;
  257. return this._flyweight;
  258. },
  259. // private
  260. getEditorParent : function(ed) {
  261. return this.scroller.dom;
  262. },
  263. // private
  264. initElements : function() {
  265. var E = Ext.Element;
  266. var el = this.grid.getGridEl().dom.firstChild;
  267. var cs = el.childNodes;
  268. this.el = new E(el);
  269. this.mainWrap = new E(cs[0]);
  270. this.mainHd = new E(this.mainWrap.dom.firstChild);
  271. this.innerHd = this.mainHd.dom.firstChild;
  272. this.scroller = new E(this.mainWrap.dom.childNodes[1]);
  273. if (this.forceFit) {
  274. this.scroller.setStyle('overflow-x', 'hidden');
  275. }
  276. this.mainBody = new E(this.scroller.dom.firstChild);
  277. this.focusEl = new E(this.scroller.dom.childNodes[1]);
  278. this.focusEl.swallowEvent("click", true);
  279. this.resizeMarker = new E(cs[1]);
  280. this.resizeProxy = new E(cs[2]);
  281. },
  282. // private
  283. getRows : function() {
  284. return this.hasRows() ? this.mainBody.dom.childNodes : [];
  285. },
  286. // finder methods, used with delegation
  287. // private
  288. findCell : function(el) {
  289. if (!el) {
  290. return false;
  291. }
  292. return this.fly(el).findParent(this.cellSelector, 3);
  293. },
  294. // private
  295. findCellIndex : function(el, requiredCls) {
  296. var cell = this.findCell(el);
  297. if (cell && (!requiredCls || this.fly(cell).hasClass(requiredCls))) {
  298. return this.getCellIndex(cell);
  299. }
  300. return false;
  301. },
  302. // private
  303. getCellIndex : function(el) {
  304. if (el) {
  305. var m = el.className.match(this.colRe);
  306. if (m && m[1]) {
  307. return this.cm.getIndexById(m[1]);
  308. }
  309. }
  310. return false;
  311. },
  312. // private
  313. findHeaderCell : function(el) {
  314. var cell = this.findCell(el);
  315. return cell && this.fly(cell).hasClass(this.hdCls) ? cell : null;
  316. },
  317. // private
  318. findHeaderIndex : function(el) {
  319. return this.findCellIndex(el, this.hdCls);
  320. },
  321. // private
  322. findRow : function(el) {
  323. if (!el) {
  324. return false;
  325. }
  326. return this.fly(el).findParent(this.rowSelector, 10);
  327. },
  328. // private
  329. findRowIndex : function(el) {
  330. var r = this.findRow(el);
  331. return r ? r.rowIndex : false;
  332. },
  333. // getter methods for fetching elements dynamically in the grid
  334. /**
  335. * Return the &lt;TR> HtmlElement which represents a Grid row for the
  336. * specified index.
  337. *
  338. * @param {Number}
  339. * index The row index
  340. * @return {HtmlElement} The &lt;TR> element.
  341. */
  342. getRow : function(row) {
  343. return this.getRows()[row];
  344. },
  345. /**
  346. * Returns the grid's &lt;TD> HtmlElement at the specified coordinates.
  347. *
  348. * @param {Number}
  349. * row The row index in which to find the cell.
  350. * @param {Number}
  351. * col The column index of the cell.
  352. * @return {HtmlElement} The &lt;TD> at the specified coordinates.
  353. */
  354. getCell : function(row, col) {
  355. return this.getRow(row).getElementsByTagName('td')[col];
  356. },
  357. /**
  358. * Return the &lt;TD> HtmlElement which represents the Grid's header cell
  359. * for the specified column index.
  360. *
  361. * @param {Number}
  362. * index The column index
  363. * @return {HtmlElement} The &lt;TD> element.
  364. */
  365. getHeaderCell : function(index) {
  366. return this.mainHd.dom.getElementsByTagName('td')[index];
  367. },
  368. // manipulating elements
  369. // private - use getRowClass to apply custom row classes
  370. addRowClass : function(row, cls) {
  371. var r = this.getRow(row);
  372. if (r) {
  373. this.fly(r).addClass(cls);
  374. }
  375. },
  376. // private
  377. removeRowClass : function(row, cls) {
  378. var r = this.getRow(row);
  379. if (r) {
  380. this.fly(r).removeClass(cls);
  381. }
  382. },
  383. // private
  384. removeRow : function(row) {
  385. Ext.removeNode(this.getRow(row));
  386. },
  387. // private
  388. removeRows : function(firstRow, lastRow) {
  389. var bd = this.mainBody.dom;
  390. for (var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++) {
  391. Ext.removeNode(bd.childNodes[firstRow]);
  392. }
  393. },
  394. // scrolling stuff
  395. // private
  396. getScrollState : function() {
  397. var sb = this.scroller.dom;
  398. return {
  399. left : sb.scrollLeft,
  400. top : sb.scrollTop
  401. };
  402. },
  403. // private
  404. restoreScroll : function(state) {
  405. var sb = this.scroller.dom;
  406. sb.scrollLeft = state.left;
  407. sb.scrollTop = state.top;
  408. },
  409. /**
  410. * Scrolls the grid to the top
  411. */
  412. scrollToTop : function() {
  413. this.scroller.dom.scrollTop = 0;
  414. this.scroller.dom.scrollLeft = 0;
  415. },
  416. // private
  417. syncScroll : function() {
  418. var mb = this.scroller.dom;
  419. this.innerHd.scrollLeft = mb.scrollLeft;
  420. this.innerHd.scrollLeft = mb.scrollLeft; // second time for IE (1/2
  421. // time first fails, other
  422. // browsers ignore)
  423. this.grid.fireEvent("bodyscroll", mb.scrollLeft, mb.scrollTop);
  424. },
  425. // private
  426. updateSortIcon : function(col, dir) {
  427. var sc = this.sortClasses;
  428. var hds = this.mainHd.select('td').removeClass(sc);
  429. hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
  430. },
  431. // private
  432. updateAllColumnWidths : function() {
  433. var tw = this.getTotalWidth();
  434. var clen = this.cm.getColumnCount();
  435. var ws = [];
  436. for (var i = 0; i < clen; i++) {
  437. ws[i] = this.getColumnWidth(i);
  438. }
  439. this.innerHd.firstChild.firstChild.style.width = tw;
  440. for (var i = 0; i < clen; i++) {
  441. var hd = this.getHeaderCell(i);
  442. hd.style.width = ws[i];
  443. }
  444. var ns = this.getRows();
  445. for (var i = 0, len = ns.length; i < len; i++) {
  446. ns[i].style.width = tw;
  447. ns[i].firstChild.style.width = tw;
  448. var row = ns[i].firstChild.rows[0];
  449. for (var j = 0; j < clen; j++) {
  450. row.childNodes[j].style.width = ws[j];
  451. }
  452. }
  453. this.onAllColumnWidthsUpdated(ws, tw);
  454. },
  455. // private
  456. updateColumnWidth : function(col, width) {
  457. var w = this.getColumnWidth(col);
  458. var tw = this.getTotalWidth();
  459. this.innerHd.firstChild.firstChild.style.width = tw;
  460. var hd = this.getHeaderCell(col);
  461. hd.style.width = w;
  462. var ns = this.getRows();
  463. for (var i = 0, len = ns.length; i < len; i++) {
  464. ns[i].style.width = tw;
  465. ns[i].firstChild.style.width = tw;
  466. ns[i].firstChild.rows[0].childNodes[col].style.width = w;
  467. }
  468. this.onColumnWidthUpdated(col, w, tw);
  469. },
  470. // private
  471. updateColumnHidden : function(col, hidden) {
  472. var tw = this.getTotalWidth();
  473. this.innerHd.firstChild.firstChild.style.width = tw;
  474. var display = hidden ? 'none' : '';
  475. var hd = this.getHeaderCell(col);
  476. hd.style.display = display;
  477. var ns = this.getRows();
  478. for (var i = 0, len = ns.length; i < len; i++) {
  479. ns[i].style.width = tw;
  480. ns[i].firstChild.style.width = tw;
  481. ns[i].firstChild.rows[0].childNodes[col].style.display = display;
  482. }
  483. this.onColumnHiddenUpdated(col, hidden, tw);
  484. delete this.lastViewWidth; // force recalc
  485. this.layout();
  486. },
  487. // private
  488. doRender : function(cs, rs, ds, startRow, colCount, stripe) {
  489. var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount - 1;
  490. var tstyle = 'width:' + this.getTotalWidth() + ';';
  491. // buffers
  492. var buf = [], cb, c, p = {}, rp = {
  493. tstyle : tstyle
  494. }, r;
  495. for (var j = 0, len = rs.length; j < len; j++) {
  496. r = rs[j];
  497. cb = [];
  498. var rowIndex = (j + startRow);
  499. for (var i = 0; i < colCount; i++) {
  500. c = cs[i];
  501. p.id = c.id;
  502. p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last
  503. ? 'x-grid3-cell-last '
  504. : '');
  505. p.attr = p.cellAttr = "";
  506. p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
  507. p.style = c.style;
  508. if (p.value == undefined || p.value === "")
  509. p.value = "&#160;";
  510. if (r.dirty && typeof r.modified[c.name] !== 'undefined') {
  511. p.css += ' x-grid3-dirty-cell';
  512. }
  513. cb[cb.length] = ct.apply(p);
  514. }
  515. var alt = [];
  516. if (stripe && ((rowIndex + 1) % 2 == 0)) {
  517. alt[0] = "x-grid3-row-alt";
  518. }
  519. if (r.dirty) {
  520. alt[1] = " x-grid3-dirty-row";
  521. }
  522. rp.cols = colCount;
  523. if (this.getRowClass) {
  524. alt[2] = this.getRowClass(r, rowIndex, rp, ds);
  525. }
  526. rp.alt = alt.join(" ");
  527. rp.cells = cb.join("");
  528. buf[buf.length] = rt.apply(rp);
  529. }
  530. return buf.join("");
  531. },
  532. // private
  533. processRows : function(startRow, skipStripe) {
  534. if (this.ds.getCount() < 1) {
  535. return;
  536. }
  537. skipStripe = skipStripe || !this.grid.stripeRows;
  538. startRow = startRow || 0;
  539. var rows = this.getRows();
  540. var cls = ' x-grid3-row-alt ';
  541. for (var i = startRow, len = rows.length; i < len; i++) {
  542. var row = rows[i];
  543. row.rowIndex = i;
  544. if (!skipStripe) {
  545. var isAlt = ((i + 1) % 2 == 0);
  546. var hasAlt = (' ' + row.className + ' ').indexOf(cls) != -1;
  547. if (isAlt == hasAlt) {
  548. continue;
  549. }
  550. if (isAlt) {
  551. row.className += " x-grid3-row-alt";
  552. } else {
  553. row.className = row.className
  554. .replace("x-grid3-row-alt", "");
  555. }
  556. }
  557. }
  558. },
  559. // private
  560. renderUI : function() {
  561. var header = this.renderHeaders();
  562. var body = this.templates.body.apply({
  563. rows : ''
  564. });
  565. var html = this.templates.master.apply({
  566. body : body,
  567. header : header
  568. });
  569. var g = this.grid;
  570. g.getGridEl().dom.innerHTML = html;
  571. this.initElements();
  572. this.mainBody.dom.innerHTML = this.renderRows();
  573. this.processRows(0, true);
  574. // get mousedowns early
  575. Ext.fly(this.innerHd).on("click", this.handleHdDown, this);
  576. this.mainHd.on("mouseover", this.handleHdOver, this);
  577. this.mainHd.on("mouseout", this.handleHdOut, this);
  578. this.mainHd.on("mousemove", this.handleHdMove, this);
  579. this.scroller.on('scroll', this.syncScroll, this);
  580. if (g.enableColumnResize !== false) {
  581. this.splitone = new Ext.grid.GridView.SplitDragZone(g,
  582. this.mainHd.dom);
  583. }
  584. if (g.enableColumnMove) {
  585. this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g,
  586. this.innerHd);
  587. this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);
  588. }
  589. if (g.enableHdMenu !== false) {
  590. if (g.enableColumnHide !== false) {
  591. this.colMenu = new Ext.menu.Menu({
  592. id : g.id + "-hcols-menu"
  593. });
  594. this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
  595. this.colMenu.on("itemclick", this.handleHdMenuClick, this);
  596. }
  597. this.hmenu = new Ext.menu.Menu({
  598. id : g.id + "-hctx"
  599. });
  600. this.hmenu.add({
  601. id : "asc",
  602. text : this.sortAscText,
  603. cls : "xg-hmenu-sort-asc"
  604. }, {
  605. id : "desc",
  606. text : this.sortDescText,
  607. cls : "xg-hmenu-sort-desc"
  608. });
  609. if (g.enableColumnHide !== false) {
  610. this.hmenu.add('-', {
  611. id : "columns",
  612. text : this.columnsText,
  613. menu : this.colMenu,
  614. iconCls : 'x-cols-icon'
  615. });
  616. }
  617. this.hmenu.on("itemclick", this.handleHdMenuClick, this);
  618. // g.on("headercontextmenu", this.handleHdCtx, this);
  619. }
  620. if (g.enableDragDrop || g.enableDrag) {
  621. var dd = new Ext.grid.GridDragZone(g, {
  622. ddGroup : g.ddGroup || 'GridDD'
  623. });
  624. }
  625. this.updateHeaderSortState();
  626. },
  627. // private
  628. layout : function() {
  629. if (!this.mainBody) {
  630. return; // not rendered
  631. }
  632. var g = this.grid;
  633. var c = g.getGridEl(), cm = this.cm, expandCol = g.autoExpandColumn, gv = this;
  634. var csize = c.getSize(true);
  635. var vw = csize.width;
  636. if (vw < 20 || csize.height < 20) { // display: none?
  637. return;
  638. }
  639. if (g.autoHeight) {
  640. this.scroller.dom.style.overflow = 'visible';
  641. } else {
  642. this.el.setSize(csize.width, csize.height);
  643. var hdHeight = this.mainHd.getHeight();
  644. var vh = csize.height - (hdHeight);
  645. this.scroller.setSize(vw, vh);
  646. if (this.innerHd) {
  647. this.innerHd.style.width = (vw) + 'px';
  648. }
  649. }
  650. if (this.forceFit) {
  651. if (this.lastViewWidth != vw) {
  652. this.fitColumns(false, false);
  653. this.lastViewWidth = vw;
  654. }
  655. } else {
  656. this.autoExpand();
  657. }
  658. this.onLayout(vw, vh);
  659. },
  660. // template functions for subclasses and plugins
  661. // these functions include precalculated values
  662. onLayout : function(vw, vh) {
  663. // do nothing
  664. },
  665. onColumnWidthUpdated : function(col, w, tw) {
  666. // template method
  667. },
  668. onAllColumnWidthsUpdated : function(ws, tw) {
  669. // template method
  670. },
  671. onColumnHiddenUpdated : function(col, hidden, tw) {
  672. // template method
  673. },
  674. updateColumnText : function(col, text) {
  675. // template method
  676. },
  677. afterMove : function(colIndex) {
  678. // template method
  679. },
  680. /*
  681. * ----------------------------------- Core Specific
  682. * -------------------------------------------
  683. */
  684. // private
  685. init : function(grid) {
  686. this.grid = grid;
  687. this.initTemplates();
  688. this.initData(grid.store, grid.colModel);
  689. this.initUI(grid);
  690. },
  691. // private
  692. getColumnId : function(index) {
  693. return this.cm.getColumnId(index);
  694. },
  695. // private
  696. renderHeaders : function() {
  697. var cm = this.cm, ts = this.templates;
  698. var ct = ts.hcell;
  699. var cb = [], sb = [], p = {};
  700. for (var i = 0, len = cm.getColumnCount(); i < len; i++) {
  701. p.id = cm.getColumnId(i);
  702. p.value = cm.getColumnHeader(i) || "";
  703. p.style = this.getColumnStyle(i, true);
  704. if (cm.config[i].align == 'right') {
  705. p.istyle = 'padding-right:16px';
  706. }
  707. cb[cb.length] = ct.apply(p);
  708. }
  709. return ts.header.apply({
  710. cells : cb.join(""),
  711. tstyle : 'width:' + this.getTotalWidth() + ';'
  712. });
  713. },
  714. // private
  715. beforeUpdate : function() {
  716. this.grid.stopEditing();
  717. },
  718. // private
  719. updateHeaders : function() {
  720. this.innerHd.firstChild.innerHTML = this.renderHeaders();
  721. },
  722. /**
  723. * Focuses the specified row..
  724. *
  725. * @param {Number}
  726. * row The row index
  727. */
  728. focusRow : function(row) {
  729. this.focusCell(row, 0, false);
  730. },
  731. /**
  732. * Focuses the specified cell.
  733. *
  734. * @param {Number}
  735. * row The row index
  736. * @param {Number}
  737. * col The column index
  738. */
  739. focusCell : function(row, col, hscroll) {
  740. var el = this.ensureVisible(row, col, hscroll);
  741. if (el) {
  742. this.focusEl.alignTo(el, "tl-tl");
  743. if (Ext.isGecko) {
  744. this.focusEl.focus();
  745. } else {
  746. this.focusEl.focus.defer(1, this.focusEl);
  747. }
  748. }
  749. },
  750. // private
  751. ensureVisible : function(row, col, hscroll) {
  752. if (typeof row != "number") {
  753. row = row.rowIndex;
  754. }
  755. if (row < 0 || row >= this.ds.getCount()) {
  756. return;
  757. }
  758. col = (col !== undefined ? col : 0);
  759. var rowEl = this.getRow(row), cellEl;
  760. if (!(hscroll === false && col === 0)) {
  761. while (this.cm.isHidden(col)) {
  762. col++;
  763. }
  764. cellEl = this.getCell(row, col);
  765. }
  766. if (!rowEl) {
  767. return;
  768. }
  769. var c = this.scroller.dom;
  770. var ctop = 0;
  771. var p = rowEl, stop = this.el.dom;
  772. while (p && p != stop) {
  773. ctop += p.offsetTop;
  774. p = p.offsetParent;
  775. }
  776. ctop -= this.mainHd.dom.offsetHeight;
  777. var cbot = ctop + rowEl.offsetHeight;
  778. var ch = c.clientHeight;
  779. var stop = parseInt(c.scrollTop, 10);
  780. var sbot = stop + ch;
  781. if (ctop < stop) {
  782. c.scrollTop = ctop;
  783. } else if (cbot > sbot) {
  784. c.scrollTop = cbot - ch;
  785. }
  786. if (hscroll !== false) {
  787. var cleft = parseInt(cellEl.offsetLeft, 10);
  788. var cright = cleft + cellEl.offsetWidth;
  789. var sleft = parseInt(c.scrollLeft, 10);
  790. var sright = sleft + c.clientWidth;
  791. if (cleft < sleft) {
  792. c.scrollLeft = cleft;
  793. } else if (cright > sright) {
  794. c.scrollLeft = cright - c.clientWidth;
  795. }
  796. }
  797. return cellEl || rowEl;
  798. },
  799. // private
  800. insertRows : function(dm, firstRow, lastRow, isUpdate) {
  801. if (firstRow === 0 && lastRow == dm.getCount() - 1) {
  802. this.refresh();
  803. } else {
  804. if (!isUpdate) {
  805. this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
  806. }
  807. var html = this.renderRows(firstRow, lastRow);
  808. var before = this.getRow(firstRow);
  809. if (before) {
  810. Ext.DomHelper.insertHtml('beforeBegin', before, html);
  811. } else {
  812. Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);
  813. }
  814. if (!isUpdate) {
  815. this.fireEvent("rowsinserted", this, firstRow, lastRow);
  816. this.processRows(firstRow);
  817. }
  818. }
  819. },
  820. // private
  821. deleteRows : function(dm, firstRow, lastRow) {
  822. if (dm.getRowCount() < 1) {
  823. this.refresh();
  824. } else {
  825. this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
  826. this.removeRows(firstRow, lastRow);
  827. this.processRows(firstRow);
  828. this.fireEvent("rowsdeleted", this, firstRow, lastRow);
  829. }
  830. },
  831. // private
  832. getColumnStyle : function(col, isHeader) {
  833. var style = !isHeader ? (this.cm.config[col].css || '') : '';
  834. style += 'width:' + this.getColumnWidth(col) + ';';
  835. if (this.cm.isHidden(col)) {
  836. style += 'display:none;';
  837. }
  838. var align = this.cm.config[col].align;
  839. if (align) {
  840. style += 'text-align:' + align + ';';
  841. }
  842. return style;
  843. },
  844. // private
  845. getColumnWidth : function(col) {
  846. var w = this.cm.getColumnWidth(col);
  847. if (typeof w == 'number') {
  848. return (Ext.isBorderBox ? w : (w - this.borderWidth > 0 ? w
  849. - this.borderWidth : 0))
  850. + 'px';
  851. }
  852. return w;
  853. },
  854. // private
  855. getTotalWidth : function() {
  856. return this.cm.getTotalWidth() + 'px';
  857. },
  858. // private
  859. fitColumns : function(preventRefresh, onlyExpand, omitColumn) {
  860. var cm = this.cm, leftOver, dist, i;
  861. var tw = cm.getTotalWidth(false);
  862. var aw = this.grid.getGridEl().getWidth(true) - this.scrollOffset;
  863. if (aw < 20) { // not initialized, so don't screw up the default widths
  864. return;
  865. }
  866. var extra = aw - tw;
  867. if (extra === 0) {
  868. return false;
  869. }
  870. var vc = cm.getColumnCount(true);
  871. var ac = vc - (typeof omitColumn == 'number' ? 1 : 0);
  872. if (ac === 0) {
  873. ac = 1;
  874. omitColumn = undefined;
  875. }
  876. var colCount = cm.getColumnCount();
  877. var cols = [];
  878. var extraCol = 0;
  879. var width = 0;
  880. var w;
  881. for (i = 0; i < colCount; i++) {
  882. if (!cm.isHidden(i) && !cm.isFixed(i) && i !== omitColumn) {
  883. w = cm.getColumnWidth(i);
  884. cols.push(i);
  885. extraCol = i;
  886. cols.push(w);
  887. width += w;
  888. }
  889. }
  890. var frac = (aw - cm.getTotalWidth()) / width;
  891. while (cols.length) {
  892. w = cols.pop();
  893. i = cols.pop();
  894. cm.setColumnWidth(i, Math.max(this.grid.minColumnWidth, Math
  895. .floor(w + w * frac)), true);
  896. }
  897. if ((tw = cm.getTotalWidth(false)) > aw) {
  898. var adjustCol = ac != vc ? omitColumn : extraCol;
  899. cm.setColumnWidth(adjustCol, Math.max(1, cm
  900. .getColumnWidth(adjustCol)
  901. - (tw - aw)), true);
  902. }
  903. if (preventRefresh !== true) {
  904. this.updateAllColumnWidths();
  905. }
  906. return true;
  907. },
  908. // private
  909. autoExpand : function(preventUpdate) {
  910. var g = this.grid, cm = this.cm;
  911. if (!this.userResized && g.autoExpandColumn) {
  912. var tw = cm.getTotalWidth(false);
  913. var aw = this.grid.getGridEl().getWidth(true) - this.scrollOffset;
  914. if (tw != aw) {
  915. var ci = cm.getIndexById(g.autoExpandColumn);
  916. var currentWidth = cm.getColumnWidth(ci);
  917. var cw = Math.min(Math.max(((aw - tw) + currentWidth),
  918. g.autoExpandMin), g.autoExpandMax);
  919. if (cw != currentWidth) {
  920. cm.setColumnWidth(ci, cw, true);
  921. if (preventUpdate !== true) {
  922. this.updateColumnWidth(ci, cw);
  923. }
  924. }
  925. }
  926. }
  927. },
  928. // private
  929. getColumnData : function() {
  930. // build a map for all the columns
  931. var cs = [], cm = this.cm, colCount = cm.getColumnCount();
  932. for (var i = 0; i < colCount; i++) {
  933. var name = cm.getDataIndex(i);
  934. cs[i] = {
  935. name : (typeof name == 'undefined'
  936. ? this.ds.fields.get(i).name
  937. : name),
  938. renderer : cm.getRenderer(i),
  939. id : cm.getColumnId(i),
  940. style : this.getColumnStyle(i)
  941. };
  942. }
  943. return cs;
  944. },
  945. // private
  946. renderRows : function(startRow, endRow) {
  947. // pull in all the crap needed to render rows
  948. var g = this.grid, cm = g.colModel, ds = g.store, stripe = g.stripeRows;
  949. var colCount = cm.getColumnCount();
  950. if (ds.getCount() < 1) {
  951. return "";
  952. }
  953. var cs = this.getColumnData();
  954. startRow = startRow || 0;
  955. endRow = typeof endRow == "undefined" ? ds.getCount() - 1 : endRow;
  956. // records to render
  957. var rs = ds.getRange(startRow, endRow);
  958. return this.doRender(cs, rs, ds, startRow, colCount, stripe);
  959. },
  960. // private
  961. renderBody : function() {
  962. var markup = this.renderRows();
  963. return this.templates.body.apply({
  964. rows : markup
  965. });
  966. },
  967. // private
  968. refreshRow : function(record) {
  969. var ds = this.ds, index;
  970. if (typeof record == 'number') {
  971. index = record;
  972. record = ds.getAt(index);
  973. } else {
  974. index = ds.indexOf(record);
  975. }
  976. var cls = [];
  977. this.insertRows(ds, index, index, true);
  978. this.getRow(index).rowIndex = index;
  979. this.onRemove(ds, record, index + 1, true);
  980. this.fireEvent("rowupdated", this, index, record);
  981. },
  982. /**
  983. * Refreshs the grid UI
  984. *
  985. * @param {Boolean}
  986. * headersToo (optional) True to also refresh the headers
  987. */
  988. refresh : function(headersToo) {
  989. this.fireEvent("beforerefresh", this);
  990. this.grid.stopEditing();
  991. var result = this.renderBody();
  992. this.mainBody.update(result);
  993. if (headersToo === true) {
  994. this.updateHeaders();
  995. this.updateHeaderSortState();
  996. }
  997. this.processRows(0, true);
  998. this.layout();
  999. this.applyEmptyText();
  1000. this.fireEvent("refresh", this);
  1001. },
  1002. // private
  1003. applyEmptyText : function() {
  1004. if (this.emptyText && !this.hasRows()) {
  1005. this.mainBody.update('<div class="x-grid-empty">' + this.emptyText
  1006. + '</div>');
  1007. }
  1008. },
  1009. // private
  1010. updateHeaderSortState : function() {
  1011. var state = this.ds.getSortState();
  1012. if (!state) {
  1013. return;
  1014. }
  1015. if (!this.sortState
  1016. || (this.sortState.field != state.field || this.sortState.direction != state.direction)) {
  1017. this.grid.fireEvent('sortchange', this.grid, state);
  1018. }
  1019. this.sortState = state;
  1020. var sortColumn = this.cm.findColumnIndex(state.field);
  1021. if (sortColumn != -1) {
  1022. var sortDir = state.direction;
  1023. this.updateSortIcon(sortColumn, sortDir);
  1024. }
  1025. },
  1026. // private
  1027. destroy : function() {
  1028. if (this.colMenu) {
  1029. this.colMenu.removeAll();
  1030. Ext.menu.MenuMgr.unregister(this.colMenu);
  1031. this.colMenu.getEl().remove();
  1032. delete this.colMenu;
  1033. }
  1034. if (this.hmenu) {
  1035. this.hmenu.removeAll();
  1036. Ext.menu.MenuMgr.unregister(this.hmenu);
  1037. this.hmenu.getEl().remove();
  1038. delete this.hmenu;
  1039. }
  1040. if (this.grid.enableColumnMove) {
  1041. var dds = Ext.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
  1042. if (dds) {
  1043. for (var dd in dds) {
  1044. if (!dds[dd].config.isTarget && dds[dd].dragElId) {
  1045. var elid = dds[dd].dragElId;
  1046. dds[dd].unreg();
  1047. Ext.get(elid).remove();
  1048. } else if (dds[dd].config.isTarget) {
  1049. dds[dd].proxyTop.remove();
  1050. dds[dd].proxyBottom.remove();
  1051. dds[dd].unreg();
  1052. }
  1053. if (Ext.dd.DDM.locationCache[dd]) {
  1054. delete Ext.dd.DDM.locationCache[dd];
  1055. }
  1056. }
  1057. delete Ext.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
  1058. }
  1059. }
  1060. Ext.destroy(this.resizeMarker, this.resizeProxy);
  1061. this.initData(null, null);
  1062. Ext.EventManager.removeResizeListener(this.onWindowResize, this);
  1063. },
  1064. // private
  1065. onDenyColumnHide : function() {
  1066. },
  1067. // private
  1068. render : function() {
  1069. var cm = this.cm;
  1070. var colCount = cm.getColumnCount();
  1071. if (this.grid.monitorWindowResize === true) {
  1072. Ext.EventManager.onWindowResize(this.onWindowResize, this, true);
  1073. }
  1074. if (this.autoFill) {
  1075. this.fitColumns(true, true);
  1076. } else if (this.forceFit) {
  1077. this.fitColumns(true, false);
  1078. } else if (this.grid.autoExpandColumn) {
  1079. this.autoExpand(true);
  1080. }
  1081. this.renderUI();
  1082. // this.refresh();
  1083. },
  1084. // private
  1085. onWindowResize : function() {
  1086. if (!this.grid.monitorWindowResize || this.grid.autoHeight) {
  1087. return;
  1088. }
  1089. this.layout();
  1090. },
  1091. /*
  1092. * --------------------------------- Model Events and Handlers
  1093. * --------------------------------
  1094. */
  1095. // private
  1096. initData : function(ds, cm) {
  1097. if (this.ds) {
  1098. this.ds.un("load", this.onLoad, this);
  1099. this.ds.un("datachanged", this.onDataChange, this);
  1100. this.ds.un("add", this.onAdd, this);
  1101. this.ds.un("remove", this.onRemove, this);
  1102. this.ds.un("update", this.onUpdate, this);
  1103. this.ds.un("clear", this.onClear, this);
  1104. }
  1105. if (ds) {
  1106. ds.on("load", this.onLoad, this);
  1107. ds.on("datachanged", this.onDataChange, this);
  1108. ds.on("add", this.onAdd, this);
  1109. ds.on("remove", this.onRemove, this);
  1110. ds.on("update", this.onUpdate, this);
  1111. ds.on("clear", this.onClear, this);
  1112. }
  1113. this.ds = ds;
  1114. if (this.cm) {
  1115. this.cm.un("configchange", this.onColConfigChange, this);
  1116. this.cm.un("widthchange", this.onColWidthChange, this);
  1117. this.cm.un("headerchange", this.onHeaderChange, this);
  1118. this.cm.un("hiddenchange", this.onHiddenChange, this);
  1119. this.cm.un("columnmoved", this.onColumnMove, this);
  1120. this.cm.un("columnlockchange", this.onColumnLock, this);
  1121. }
  1122. if (cm) {
  1123. cm.on("configchange", this.onColConfigChange, this);
  1124. cm.on("widthchange", this.onColWidthChange, this);
  1125. cm.on("headerchange", this.onHeaderChange, this);
  1126. cm.on("hiddenchange", this.onHiddenChange, this);
  1127. cm.on("columnmoved", this.onColumnMove, this);
  1128. cm.on("columnlockchange", this.onColumnLock, this);
  1129. }
  1130. this.cm = cm;
  1131. },
  1132. // private
  1133. onDataChange : function() {
  1134. this.refresh();
  1135. this.updateHeaderSortState();
  1136. },
  1137. // private
  1138. onClear : function() {
  1139. this.refresh();
  1140. },
  1141. // private
  1142. onUpdate : function(ds, record) {
  1143. this.refreshRow(record);
  1144. },
  1145. // private
  1146. onAdd : function(ds, records, index) {
  1147. this.insertRows(ds, index, index + (records.length - 1));
  1148. },
  1149. // private
  1150. onRemove : function(ds, record, index, isUpdate) {
  1151. if (isUpdate !== true) {
  1152. this.fireEvent("beforerowremoved", this, index, record);
  1153. }
  1154. this.removeRow(index);
  1155. if (isUpdate !== true) {
  1156. this.processRows(index);
  1157. this.applyEmptyText();
  1158. this.fireEvent("rowremoved", this, index, record);
  1159. }
  1160. },
  1161. // private
  1162. onLoad : function() {
  1163. this.scrollToTop();
  1164. },
  1165. // private
  1166. onColWidthChange : function(cm, col, width) {
  1167. this.updateColumnWidth(col, width);
  1168. },
  1169. // private
  1170. onHeaderChange : function(cm, col, text) {
  1171. this.updateHeaders();
  1172. },
  1173. // private
  1174. onHiddenChange : function(cm, col, hidden) {
  1175. this.updateColumnHidden(col, hidden);
  1176. },
  1177. // private
  1178. onColumnMove : function(cm, oldIndex, newIndex) {
  1179. this.indexMap = null;
  1180. var s = this.getScrollState();
  1181. this.refresh(true);
  1182. this.restoreScroll(s);
  1183. this.afterMove(newIndex);
  1184. },
  1185. // private
  1186. onColConfigChange : function() {
  1187. delete this.lastViewWidth;
  1188. this.indexMap = null;
  1189. this.refresh(true);
  1190. },
  1191. /*
  1192. * -------------------- UI Events and Handlers
  1193. * ------------------------------
  1194. */
  1195. // private
  1196. initUI : function(grid) {
  1197. grid.on("headerclick", this.onHeaderClick, this);
  1198. if (grid.trackMouseOver) {
  1199. grid.on("mouseover", this.onRowOver, this);
  1200. grid.on("mouseout", this.onRowOut, this);
  1201. }
  1202. },
  1203. // private
  1204. initEvents : function() {
  1205. },
  1206. // private
  1207. onHeaderClick : function(g, index) {
  1208. if (this.headersDisabled || !this.cm.isSortable(index)) {
  1209. return;
  1210. }
  1211. g.stopEditing();
  1212. g.store.sort(this.cm.getDataIndex(index));
  1213. },
  1214. // private
  1215. onRowOver : function(e, t) {
  1216. var row;
  1217. if ((row = this.findRowIndex(t)) !== false) {
  1218. this.addRowClass(row, "x-grid3-row-over");
  1219. }
  1220. },
  1221. // private
  1222. onRowOut : function(e, t) {
  1223. var row;
  1224. if ((row = this.findRowIndex(t)) !== false
  1225. && row !== this.findRowIndex(e.getRelatedTarget())) {
  1226. this.removeRowClass(row, "x-grid3-row-over");
  1227. }
  1228. },
  1229. // private
  1230. handleWheel : function(e) {
  1231. e.stopPropagation();
  1232. },
  1233. // private
  1234. onRowSelect : function(row) {
  1235. this.addRowClass(row, "x-grid3-row-selected");
  1236. },
  1237. // private
  1238. onRowDeselect : function(row) {
  1239. this.removeRowClass(row, "x-grid3-row-selected");
  1240. },
  1241. // private
  1242. onCellSelect : function(row, col) {
  1243. var cell = this.getCell(row, col);
  1244. if (cell) {
  1245. this.fly(cell).addClass("x-grid3-cell-selected");
  1246. }
  1247. },
  1248. // private
  1249. onCellDeselect : function(row, col) {
  1250. var cell = this.getCell(row, col);
  1251. if (cell) {
  1252. this.fly(cell).removeClass("x-grid3-cell-selected");
  1253. }
  1254. },
  1255. // private
  1256. onColumnSplitterMoved : function(i, w) {
  1257. this.userResized = true;
  1258. var cm = this.grid.colModel;
  1259. cm.setColumnWidth(i, w, true);
  1260. if (this.forceFit) {
  1261. this.fitColumns(true, false, i);
  1262. this.updateAllColumnWidths();
  1263. } else {
  1264. this.updateColumnWidth(i, w);
  1265. }
  1266. this.grid.fireEvent("columnresize", i, w);
  1267. },
  1268. // private
  1269. handleHdMenuClick : function(item) {
  1270. var index = this.hdCtxIndex;
  1271. var cm = this.cm, ds = this.ds;
  1272. switch (item.id) {
  1273. case "asc" :
  1274. ds.sort(cm.getDataIndex(index), "ASC");
  1275. break;
  1276. case "desc" :
  1277. ds.sort(cm.getDataIndex(index), "DESC");
  1278. break;
  1279. default :
  1280. index = cm.getIndexById(item.id.substr(4));
  1281. if (index != -1) {
  1282. if (item.checked
  1283. && cm.getColumnsBy(this.isHideableColumn, this).length <= 1) {
  1284. this.onDenyColumnHide();
  1285. return false;
  1286. }
  1287. cm.setHidden(index, item.checked);
  1288. }
  1289. }
  1290. return true;
  1291. },
  1292. // private
  1293. isHideableColumn : function(c) {
  1294. return !c.hidden && !c.fixed;
  1295. },
  1296. // private
  1297. beforeColMenuShow : function() {
  1298. var cm = this.cm, colCount = cm.getColumnCount();
  1299. this.colMenu.removeAll();
  1300. for (var i = 0; i < colCount; i++) {
  1301. if (cm.config[i].fixed !== true && cm.config[i].hideable !== false) {
  1302. this.colMenu.add(new Ext.menu.CheckItem({
  1303. id : "col-" + cm.getColumnId(i),
  1304. text : cm.getColumnHeader(i),
  1305. checked : !cm.isHidden(i),
  1306. hideOnClick : false,
  1307. disabled : cm.config[i].hideable === false
  1308. }));
  1309. }
  1310. }
  1311. },
  1312. // private
  1313. handleHdDown : function(e, t) {
  1314. if (Ext.fly(t).hasClass('x-grid3-hd-btn')) {
  1315. e.stopEvent();
  1316. var hd = this.findHeaderCell(t);
  1317. Ext.fly(hd).addClass('x-grid3-hd-menu-open');
  1318. var index = this.getCellIndex(hd);
  1319. this.hdCtxIndex = index;
  1320. var ms = this.hmenu.items, cm = this.cm;
  1321. ms.get("asc").setDisabled(!cm.isSortable(index));
  1322. ms.get("desc").setDisabled(!cm.isSortable(index));
  1323. this.hmenu.on("hide", function() {
  1324. Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
  1325. }, this, {
  1326. single : true
  1327. });
  1328. this.hmenu.show(t, "tl-bl?");
  1329. }
  1330. },
  1331. // private
  1332. handleHdOver : function(e, t) {
  1333. var hd = this.findHeaderCell(t);
  1334. if (hd && !this.headersDisabled) {
  1335. this.activeHd = hd;
  1336. this.activeHdIndex = this.getCellIndex(hd);
  1337. var fly = this.fly(hd);
  1338. this.activeHdRegion = fly.getRegion();
  1339. if (this.cm.isSortable(this.activeHdIndex)
  1340. && !this.cm.isFixed(this.activeHdIndex)) {
  1341. fly.addClass("x-grid3-hd-over");
  1342. this.activeHdBtn = fly.child('.x-grid3-hd-btn');
  1343. if (this.activeHdBtn) {
  1344. this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight - 1)
  1345. + 'px';
  1346. }
  1347. }
  1348. }
  1349. },
  1350. // private
  1351. handleHdMove : function(e, t) {
  1352. if (this.activeHd && !this.headersDisabled) {
  1353. var hw = this.splitHandleWidth || 5;
  1354. var r = this.activeHdRegion;
  1355. var x = e.getPageX();
  1356. var ss = this.activeHd.style;
  1357. if (x - r.left <= hw && this.cm.isResizable(this.activeHdIndex - 1)) {
  1358. if (Ext.isSafari) {
  1359. ss.cursor = 'e-resize';// col-resize not always supported
  1360. } else {
  1361. ss.cursor = 'col-resize';
  1362. }
  1363. } else if (r.right - x <= (!this.activeHdBtn ? hw : 2)
  1364. && this.cm.isResizable(this.activeHdIndex)) {
  1365. if (Ext.isSafari) {
  1366. ss.cursor = 'w-resize'; // col-resize not always supported
  1367. } else {
  1368. ss.cursor = 'col-resize';
  1369. }
  1370. } else {
  1371. ss.cursor = '';
  1372. }
  1373. }
  1374. },
  1375. // private
  1376. handleHdOut : function(e, t) {
  1377. var hd = this.findHeaderCell(t);
  1378. if (hd && (!Ext.isIE || !e.within(hd, true))) {
  1379. this.activeHd = null;
  1380. this.fly(hd).removeClass("x-grid3-hd-over");
  1381. hd.style.cursor = '';
  1382. }
  1383. },
  1384. // private
  1385. hasRows : function() {
  1386. var fc = this.mainBody.dom.firstChild;
  1387. return fc && fc.className != 'x-grid-empty';
  1388. },
  1389. // back compat
  1390. bind : function(d, c) {
  1391. this.initData(d, c);
  1392. }
  1393. });
  1394. // private
  1395. // This is a support class used internally by the Grid components
  1396. Ext.grid.GridView.SplitDragZone = function(grid, hd) {
  1397. this.grid = grid;
  1398. this.view = grid.getView();
  1399. this.marker = this.view.resizeMarker;
  1400. this.proxy = this.view.resizeProxy;
  1401. Ext.grid.GridView.SplitDragZone.superclass.constructor.call(this, hd,
  1402. "gridSplitters" + this.grid.getGridEl().id, {
  1403. dragElId : Ext.id(this.proxy.dom),
  1404. resizeFrame : false
  1405. });
  1406. this.scroll = false;
  1407. this.hw = this.view.splitHandleWidth || 5;
  1408. };
  1409. Ext.extend(Ext.grid.GridView.SplitDragZone, Ext.dd.DDProxy, {
  1410. b4StartDrag : function(x, y) {
  1411. this.view.headersDisabled = true;
  1412. var h = this.view.mainWrap.getHeight();
  1413. this.marker.setHeight(h);
  1414. this.marker.show();
  1415. this.marker.alignTo(this.view.getHeaderCell(this.cellIndex),
  1416. 'tl-tl', [-2, 0]);
  1417. this.proxy.setHeight(h);
  1418. var w = this.cm.getColumnWidth(this.cellIndex);
  1419. var minw = Math.max(w - this.grid.minColumnWidth, 0);
  1420. this.resetConstraints();
  1421. this.setXConstraint(minw, 1000);
  1422. this.setYConstraint(0, 0);
  1423. this.minX = x - minw;
  1424. this.maxX = x + 1000;
  1425. this.startPos = x;
  1426. Ext.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
  1427. },
  1428. handleMouseDown : function(e) {
  1429. var t = this.view.findHeaderCell(e.getTarget());
  1430. if (t) {
  1431. var xy = this.view.fly(t).getXY(), x = xy[0], y = xy[1];
  1432. var exy = e.getXY(), ex = exy[0], ey = exy[1];
  1433. var w = t.offsetWidth, adjust = false;
  1434. if ((ex - x) <= this.hw) {
  1435. adjust = -1;
  1436. } else if ((x + w) - ex <= this.hw) {
  1437. adjust = 0;
  1438. }
  1439. if (adjust !== false) {
  1440. this.cm = this.grid.colModel;
  1441. var ci = this.view.getCellIndex(t);
  1442. if (adjust == -1) {
  1443. while (this.cm.isHidden(ci + adjust)) {
  1444. --adjust;
  1445. if (ci + adjust < 0) {
  1446. return;
  1447. }
  1448. }
  1449. }
  1450. this.cellIndex = ci + adjust;
  1451. this.split = t.dom;
  1452. if (this.cm.isResizable(this.cellIndex)
  1453. && !this.cm.isFixed(this.cellIndex)) {
  1454. Ext.grid.GridView.SplitDragZone.superclass.handleMouseDown
  1455. .apply(this, arguments);
  1456. }
  1457. } else if (this.view.columnDrag) {
  1458. this.view.columnDrag.callHandleMouseDown(e);
  1459. }
  1460. }
  1461. },
  1462. endDrag : function(e) {
  1463. this.marker.hide();
  1464. var v = this.view;
  1465. var endX = Math.max(this.minX, e.getPageX());
  1466. var diff = endX - this.startPos;
  1467. v.onColumnSplitterMoved(this.cellIndex, this.cm
  1468. .getColumnWidth(this.cellIndex)
  1469. + diff);
  1470. setTimeout(function() {
  1471. v.headersDisabled = false;
  1472. }, 50);
  1473. },
  1474. autoOffset : function() {
  1475. this.setDelta(0, 0);
  1476. }
  1477. });