_View.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. require({cache:{
  2. 'url:dojox/grid/resources/View.html':"<div class=\"dojoxGridView\" role=\"presentation\">\n\t<div class=\"dojoxGridHeader\" dojoAttachPoint=\"headerNode\" role=\"presentation\">\n\t\t<div dojoAttachPoint=\"headerNodeContainer\" style=\"width:9000em\" role=\"presentation\">\n\t\t\t<div dojoAttachPoint=\"headerContentNode\" role=\"row\"></div>\n\t\t</div>\n\t</div>\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" dojoAttachPoint=\"hiddenFocusNode\" role=\"presentation\" />\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" role=\"presentation\" />\n\t<div class=\"dojoxGridScrollbox\" dojoAttachPoint=\"scrollboxNode\" role=\"presentation\">\n\t\t<div class=\"dojoxGridContent\" dojoAttachPoint=\"contentNode\" hidefocus=\"hidefocus\" role=\"presentation\"></div>\n\t</div>\n</div>\n"}});
  3. define("dojox/grid/_View", [
  4. "dojo",
  5. "dijit/registry",
  6. "../main",
  7. "dojo/_base/declare",
  8. "dojo/_base/array",
  9. "dojo/_base/lang",
  10. "dojo/_base/connect",
  11. "dojo/_base/sniff",
  12. "dojo/query",
  13. "dojo/_base/window",
  14. "dojo/text!./resources/View.html",
  15. "dojo/dnd/Source",
  16. "dijit/_Widget",
  17. "dijit/_TemplatedMixin",
  18. "dojox/html/metrics",
  19. "./util",
  20. "dojo/_base/html",
  21. "./_Builder",
  22. "dojo/dnd/Avatar",
  23. "dojo/dnd/Manager"
  24. ], function(dojo, dijit, dojox, declare, array, lang, connect, has, query,
  25. win, template, Source, _Widget, _TemplatedMixin, metrics, util, html, _Builder, Avatar){
  26. // a private function
  27. var getStyleText = function(inNode, inStyleText){
  28. return inNode.style.cssText == undefined ? inNode.getAttribute("style") : inNode.style.cssText;
  29. };
  30. // some public functions
  31. var _View = declare('dojox.grid._View', [_Widget, _TemplatedMixin], {
  32. // summary:
  33. // A collection of grid columns. A grid is comprised of a set of views that stack horizontally.
  34. // Grid creates views automatically based on grid's layout structure.
  35. // Users should typically not need to access individual views directly.
  36. //
  37. // defaultWidth: String
  38. // Default width of the view
  39. defaultWidth: "18em",
  40. // viewWidth: String
  41. // Width for the view, in valid css unit
  42. viewWidth: "",
  43. templateString: template,
  44. themeable: false,
  45. classTag: 'dojoxGrid',
  46. marginBottom: 0,
  47. rowPad: 2,
  48. // _togglingColumn: int
  49. // Width of the column being toggled (-1 for none)
  50. _togglingColumn: -1,
  51. // _headerBuilderClass: Object
  52. // The class to use for our header builder
  53. _headerBuilderClass: _Builder._HeaderBuilder,
  54. // _contentBuilderClass: Object
  55. // The class to use for our content builder
  56. _contentBuilderClass: _Builder._ContentBuilder,
  57. postMixInProperties: function(){
  58. this.rowNodes = {};
  59. },
  60. postCreate: function(){
  61. this.connect(this.scrollboxNode,"onscroll","doscroll");
  62. util.funnelEvents(this.contentNode, this, "doContentEvent", [ 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu', 'mousedown' ]);
  63. util.funnelEvents(this.headerNode, this, "doHeaderEvent", [ 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'click', 'contextmenu' ]);
  64. this.content = new this._contentBuilderClass(this);
  65. this.header = new this._headerBuilderClass(this);
  66. //BiDi: in RTL case, style width='9000em' causes scrolling problem in head node
  67. if(!this.grid.isLeftToRight()){
  68. this.headerNodeContainer.style.width = "";
  69. }
  70. },
  71. destroy: function(){
  72. html.destroy(this.headerNode);
  73. delete this.headerNode;
  74. for(var i in this.rowNodes){
  75. this._cleanupRowWidgets(this.rowNodes[i]);
  76. html.destroy(this.rowNodes[i]);
  77. }
  78. this.rowNodes = {};
  79. if(this.source){
  80. this.source.destroy();
  81. }
  82. this.inherited(arguments);
  83. },
  84. // focus
  85. focus: function(){
  86. if(has("ie") || has("webkit") || has("opera")){
  87. this.hiddenFocusNode.focus();
  88. }else{
  89. this.scrollboxNode.focus();
  90. }
  91. },
  92. setStructure: function(inStructure){
  93. var vs = (this.structure = inStructure);
  94. // FIXME: similar logic is duplicated in layout
  95. if(vs.width && !isNaN(vs.width)){
  96. this.viewWidth = vs.width + 'em';
  97. }else{
  98. this.viewWidth = vs.width || (vs.noscroll ? 'auto' : this.viewWidth); //|| this.defaultWidth;
  99. }
  100. this._onBeforeRow = vs.onBeforeRow||function(){};
  101. this._onAfterRow = vs.onAfterRow||function(){};
  102. this.noscroll = vs.noscroll;
  103. if(this.noscroll){
  104. this.scrollboxNode.style.overflow = "hidden";
  105. }
  106. this.simpleStructure = Boolean(vs.cells.length == 1);
  107. // bookkeeping
  108. this.testFlexCells();
  109. // accomodate new structure
  110. this.updateStructure();
  111. },
  112. _cleanupRowWidgets: function(inRowNode){
  113. // Summary:
  114. // Cleans up the widgets for the given row node so that
  115. // we can reattach them if needed
  116. if(inRowNode){
  117. array.forEach(query("[widgetId]", inRowNode).map(dijit.byNode), function(w){
  118. if(w._destroyOnRemove){
  119. w.destroy();
  120. delete w;
  121. }else if(w.domNode && w.domNode.parentNode){
  122. w.domNode.parentNode.removeChild(w.domNode);
  123. }
  124. });
  125. }
  126. },
  127. onBeforeRow: function(inRowIndex, cells){
  128. this._onBeforeRow(inRowIndex, cells);
  129. if(inRowIndex >= 0){
  130. this._cleanupRowWidgets(this.getRowNode(inRowIndex));
  131. }
  132. },
  133. onAfterRow: function(inRowIndex, cells, inRowNode){
  134. this._onAfterRow(inRowIndex, cells, inRowNode);
  135. var g = this.grid;
  136. array.forEach(query(".dojoxGridStubNode", inRowNode), function(n){
  137. if(n && n.parentNode){
  138. var lw = n.getAttribute("linkWidget");
  139. var cellIdx = window.parseInt(html.attr(n, "cellIdx"), 10);
  140. var cellDef = g.getCell(cellIdx);
  141. var w = dijit.byId(lw);
  142. if(w){
  143. n.parentNode.replaceChild(w.domNode, n);
  144. if(!w._started){
  145. w.startup();
  146. }
  147. dojo.destroy(n);
  148. }else{
  149. n.innerHTML = "";
  150. }
  151. }
  152. }, this);
  153. },
  154. testFlexCells: function(){
  155. // FIXME: cheater, this function does double duty as initializer and tester
  156. this.flexCells = false;
  157. for(var j=0, row; (row=this.structure.cells[j]); j++){
  158. for(var i=0, cell; (cell=row[i]); i++){
  159. cell.view = this;
  160. this.flexCells = this.flexCells || cell.isFlex();
  161. }
  162. }
  163. return this.flexCells;
  164. },
  165. updateStructure: function(){
  166. // header builder needs to update table map
  167. this.header.update();
  168. // content builder needs to update markup cache
  169. this.content.update();
  170. },
  171. getScrollbarWidth: function(){
  172. var hasScrollSpace = this.hasVScrollbar();
  173. var overflow = html.style(this.scrollboxNode, "overflow");
  174. if(this.noscroll || !overflow || overflow == "hidden"){
  175. hasScrollSpace = false;
  176. }else if(overflow == "scroll"){
  177. hasScrollSpace = true;
  178. }
  179. return (hasScrollSpace ? metrics.getScrollbar().w : 0); // Integer
  180. },
  181. getColumnsWidth: function(){
  182. var h = this.headerContentNode;
  183. return h && h.firstChild ? (h.firstChild.offsetWidth || html.style(h.firstChild, 'width')) : 0; // Integer
  184. },
  185. setColumnsWidth: function(width){
  186. this.headerContentNode.firstChild.style.width = width + 'px';
  187. if(this.viewWidth){
  188. this.viewWidth = width + 'px';
  189. }
  190. },
  191. getWidth: function(){
  192. return this.viewWidth || (this.getColumnsWidth()+this.getScrollbarWidth()) +'px'; // String
  193. },
  194. getContentWidth: function(){
  195. return Math.max(0, html._getContentBox(this.domNode).w - this.getScrollbarWidth()) + 'px'; // String
  196. },
  197. render: function(){
  198. this.scrollboxNode.style.height = '';
  199. this.renderHeader();
  200. if(this._togglingColumn >= 0){
  201. this.setColumnsWidth(this.getColumnsWidth() - this._togglingColumn);
  202. this._togglingColumn = -1;
  203. }
  204. var cells = this.grid.layout.cells;
  205. var getSibling = lang.hitch(this, function(node, before){
  206. !this.grid.isLeftToRight() && (before = !before);
  207. var inc = before?-1:1;
  208. var idx = this.header.getCellNodeIndex(node) + inc;
  209. var cell = cells[idx];
  210. while(cell && cell.getHeaderNode() && cell.getHeaderNode().style.display == "none"){
  211. idx += inc;
  212. cell = cells[idx];
  213. }
  214. if(cell){
  215. return cell.getHeaderNode();
  216. }
  217. return null;
  218. });
  219. if(this.grid.columnReordering && this.simpleStructure){
  220. if(this.source){
  221. this.source.destroy();
  222. }
  223. // Create the top and bottom markers
  224. var bottomMarkerId = "dojoxGrid_bottomMarker";
  225. var topMarkerId = "dojoxGrid_topMarker";
  226. if(this.bottomMarker){
  227. html.destroy(this.bottomMarker);
  228. }
  229. this.bottomMarker = html.byId(bottomMarkerId);
  230. if(this.topMarker){
  231. html.destroy(this.topMarker);
  232. }
  233. this.topMarker = html.byId(topMarkerId);
  234. if (!this.bottomMarker) {
  235. this.bottomMarker = html.create("div", {
  236. "id": bottomMarkerId,
  237. "class": "dojoxGridColPlaceBottom"
  238. }, win.body());
  239. this._hide(this.bottomMarker);
  240. this.topMarker = html.create("div", {
  241. "id": topMarkerId,
  242. "class": "dojoxGridColPlaceTop"
  243. }, win.body());
  244. this._hide(this.topMarker);
  245. }
  246. this.arrowDim = html.contentBox(this.bottomMarker);
  247. var headerHeight = html.contentBox(this.headerContentNode.firstChild.rows[0]).h;
  248. this.source = new Source(this.headerContentNode.firstChild.rows[0], {
  249. horizontal: true,
  250. accept: [ "gridColumn_" + this.grid.id ],
  251. viewIndex: this.index,
  252. generateText: false,
  253. onMouseDown: lang.hitch(this, function(e){
  254. this.header.decorateEvent(e);
  255. if((this.header.overRightResizeArea(e) || this.header.overLeftResizeArea(e)) &&
  256. this.header.canResize(e) && !this.header.moveable){
  257. this.header.beginColumnResize(e);
  258. }else{
  259. if(this.grid.headerMenu){
  260. this.grid.headerMenu.onCancel(true);
  261. }
  262. // IE reports a left click as 1, where everything else reports 0
  263. if(e.button === (has("ie") < 9 ? 1 : 0)){
  264. Source.prototype.onMouseDown.call(this.source, e);
  265. }
  266. }
  267. }),
  268. onMouseOver: lang.hitch(this, function(e){
  269. var src = this.source;
  270. if(src._getChildByEvent(e)){
  271. Source.prototype.onMouseOver.apply(src, arguments);
  272. }
  273. }),
  274. _markTargetAnchor: lang.hitch(this, function(before){
  275. var src = this.source;
  276. if(src.current == src.targetAnchor && src.before == before){ return; }
  277. if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
  278. src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
  279. }
  280. Source.prototype._markTargetAnchor.call(src, before);
  281. var target = before ? src.targetAnchor : getSibling(src.targetAnchor, src.before);
  282. var endAdd = 0;
  283. if (!target) {
  284. target = src.targetAnchor;
  285. endAdd = html.contentBox(target).w + this.arrowDim.w/2 + 2;
  286. }
  287. var pos = html.position(target, true);
  288. var left = Math.floor(pos.x - this.arrowDim.w/2 + endAdd);
  289. html.style(this.bottomMarker, "visibility", "visible");
  290. html.style(this.topMarker, "visibility", "visible");
  291. html.style(this.bottomMarker, {
  292. "left": left + "px",
  293. "top" : (headerHeight + pos.y) + "px"
  294. });
  295. html.style(this.topMarker, {
  296. "left": left + "px",
  297. "top" : (pos.y - this.arrowDim.h) + "px"
  298. });
  299. if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
  300. src._addItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
  301. }
  302. }),
  303. _unmarkTargetAnchor: lang.hitch(this, function(){
  304. var src = this.source;
  305. if(!src.targetAnchor){ return; }
  306. if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
  307. src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
  308. }
  309. this._hide(this.bottomMarker);
  310. this._hide(this.topMarker);
  311. Source.prototype._unmarkTargetAnchor.call(src);
  312. }),
  313. destroy: lang.hitch(this, function(){
  314. connect.disconnect(this._source_conn);
  315. connect.unsubscribe(this._source_sub);
  316. Source.prototype.destroy.call(this.source);
  317. if(this.bottomMarker){
  318. html.destroy(this.bottomMarker);
  319. delete this.bottomMarker;
  320. }
  321. if(this.topMarker){
  322. html.destroy(this.topMarker);
  323. delete this.topMarker;
  324. }
  325. }),
  326. onDndCancel: lang.hitch(this, function(){
  327. Source.prototype.onDndCancel.call(this.source);
  328. this._hide(this.bottomMarker);
  329. this._hide(this.topMarker);
  330. })
  331. });
  332. this._source_conn = connect.connect(this.source, "onDndDrop", this, "_onDndDrop");
  333. this._source_sub = connect.subscribe("/dnd/drop/before", this, "_onDndDropBefore");
  334. this.source.startup();
  335. }
  336. },
  337. _hide: function(node){
  338. html.style(node, {
  339. top: "-10000px",
  340. "visibility": "hidden"
  341. });
  342. },
  343. _onDndDropBefore: function(source, nodes, copy){
  344. if(dojo.dnd.manager().target !== this.source){
  345. return;
  346. }
  347. this.source._targetNode = this.source.targetAnchor;
  348. this.source._beforeTarget = this.source.before;
  349. var views = this.grid.views.views;
  350. var srcView = views[source.viewIndex];
  351. var tgtView = views[this.index];
  352. if(tgtView != srcView){
  353. srcView.convertColPctToFixed();
  354. tgtView.convertColPctToFixed();
  355. }
  356. },
  357. _onDndDrop: function(source, nodes, copy){
  358. if(dojo.dnd.manager().target !== this.source){
  359. if(dojo.dnd.manager().source === this.source){
  360. this._removingColumn = true;
  361. }
  362. return;
  363. }
  364. this._hide(this.bottomMarker);
  365. this._hide(this.topMarker);
  366. var getIdx = function(n){
  367. return n ? html.attr(n, "idx") : null;
  368. };
  369. var w = html.marginBox(nodes[0]).w;
  370. if(source.viewIndex !== this.index){
  371. var views = this.grid.views.views;
  372. var srcView = views[source.viewIndex];
  373. var tgtView = views[this.index];
  374. if(srcView.viewWidth && srcView.viewWidth != "auto"){
  375. srcView.setColumnsWidth(srcView.getColumnsWidth() - w);
  376. }
  377. if(tgtView.viewWidth && tgtView.viewWidth != "auto"){
  378. tgtView.setColumnsWidth(tgtView.getColumnsWidth());
  379. }
  380. }
  381. var stn = this.source._targetNode;
  382. var stb = this.source._beforeTarget;
  383. !this.grid.isLeftToRight() && (stb = !stb);
  384. var layout = this.grid.layout;
  385. var idx = this.index;
  386. delete this.source._targetNode;
  387. delete this.source._beforeTarget;
  388. layout.moveColumn(
  389. source.viewIndex,
  390. idx,
  391. getIdx(nodes[0]),
  392. getIdx(stn),
  393. stb);
  394. },
  395. renderHeader: function(){
  396. this.headerContentNode.innerHTML = this.header.generateHtml(this._getHeaderContent);
  397. if(this.flexCells){
  398. this.contentWidth = this.getContentWidth();
  399. this.headerContentNode.firstChild.style.width = this.contentWidth;
  400. }
  401. util.fire(this, "onAfterRow", [-1, this.structure.cells, this.headerContentNode]);
  402. },
  403. // note: not called in 'view' context
  404. _getHeaderContent: function(inCell){
  405. var n = inCell.name || inCell.grid.getCellName(inCell);
  406. if(/^\s+$/.test(n)){
  407. n = '&nbsp;'//otherwise arrow styles will be messed up
  408. }
  409. var ret = [ '<div class="dojoxGridSortNode' ];
  410. if(inCell.index != inCell.grid.getSortIndex()){
  411. ret.push('">');
  412. }else{
  413. ret = ret.concat([ ' ',
  414. inCell.grid.sortInfo > 0 ? 'dojoxGridSortUp' : 'dojoxGridSortDown',
  415. '"><div class="dojoxGridArrowButtonChar">',
  416. inCell.grid.sortInfo > 0 ? '&#9650;' : '&#9660;',
  417. '</div><div class="dojoxGridArrowButtonNode" role="presentation"></div>',
  418. '<div class="dojoxGridColCaption">']);
  419. }
  420. ret = ret.concat([n, '</div></div>']);
  421. return ret.join('');
  422. },
  423. resize: function(){
  424. this.adaptHeight();
  425. this.adaptWidth();
  426. },
  427. hasHScrollbar: function(reset){
  428. var hadScroll = this._hasHScroll||false;
  429. if(this._hasHScroll == undefined || reset){
  430. if(this.noscroll){
  431. this._hasHScroll = false;
  432. }else{
  433. var style = html.style(this.scrollboxNode, "overflow");
  434. if(style == "hidden"){
  435. this._hasHScroll = false;
  436. }else if(style == "scroll"){
  437. this._hasHScroll = true;
  438. }else{
  439. this._hasHScroll = (this.scrollboxNode.offsetWidth - this.getScrollbarWidth() < this.contentNode.offsetWidth );
  440. }
  441. }
  442. }
  443. if(hadScroll !== this._hasHScroll){
  444. this.grid.update();
  445. }
  446. return this._hasHScroll; // Boolean
  447. },
  448. hasVScrollbar: function(reset){
  449. var hadScroll = this._hasVScroll||false;
  450. if(this._hasVScroll == undefined || reset){
  451. if(this.noscroll){
  452. this._hasVScroll = false;
  453. }else{
  454. var style = html.style(this.scrollboxNode, "overflow");
  455. if(style == "hidden"){
  456. this._hasVScroll = false;
  457. }else if(style == "scroll"){
  458. this._hasVScroll = true;
  459. }else{
  460. this._hasVScroll = (this.scrollboxNode.scrollHeight > this.scrollboxNode.clientHeight);
  461. }
  462. }
  463. }
  464. if(hadScroll !== this._hasVScroll){
  465. this.grid.update();
  466. }
  467. return this._hasVScroll; // Boolean
  468. },
  469. convertColPctToFixed: function(){
  470. // Fix any percentage widths to be pixel values
  471. var hasPct = false;
  472. this.grid.initialWidth = "";
  473. var cellNodes = query("th", this.headerContentNode);
  474. var fixedWidths = array.map(cellNodes, function(c, vIdx){
  475. var w = c.style.width;
  476. html.attr(c, "vIdx", vIdx);
  477. if(w && w.slice(-1) == "%"){
  478. hasPct = true;
  479. }else if(w && w.slice(-2) == "px"){
  480. return window.parseInt(w, 10);
  481. }
  482. return html.contentBox(c).w;
  483. });
  484. if(hasPct){
  485. array.forEach(this.grid.layout.cells, function(cell, idx){
  486. if(cell.view == this){
  487. var cellNode = cell.view.getHeaderCellNode(cell.index);
  488. if(cellNode && html.hasAttr(cellNode, "vIdx")){
  489. var vIdx = window.parseInt(html.attr(cellNode, "vIdx"));
  490. this.setColWidth(idx, fixedWidths[vIdx]);
  491. html.removeAttr(cellNode, "vIdx");
  492. }
  493. }
  494. }, this);
  495. return true;
  496. }
  497. return false;
  498. },
  499. adaptHeight: function(minusScroll){
  500. if(!this.grid._autoHeight){
  501. var h = (this.domNode.style.height && parseInt(this.domNode.style.height.replace(/px/,''), 10)) || this.domNode.clientHeight;
  502. var self = this;
  503. var checkOtherViewScrollers = function(){
  504. var v;
  505. for(var i in self.grid.views.views){
  506. v = self.grid.views.views[i];
  507. if(v !== self && v.hasHScrollbar()){
  508. return true;
  509. }
  510. }
  511. return false;
  512. };
  513. if(minusScroll || (this.noscroll && checkOtherViewScrollers())){
  514. h -= metrics.getScrollbar().h;
  515. }
  516. util.setStyleHeightPx(this.scrollboxNode, h);
  517. }
  518. this.hasVScrollbar(true);
  519. },
  520. adaptWidth: function(){
  521. if(this.flexCells){
  522. // the view content width
  523. this.contentWidth = this.getContentWidth();
  524. this.headerContentNode.firstChild.style.width = this.contentWidth;
  525. }
  526. // FIXME: it should be easier to get w from this.scrollboxNode.clientWidth,
  527. // but clientWidth seemingly does not include scrollbar width in some cases
  528. var w = this.scrollboxNode.offsetWidth - this.getScrollbarWidth();
  529. if(!this._removingColumn){
  530. w = Math.max(w, this.getColumnsWidth()) + 'px';
  531. }else{
  532. w = Math.min(w, this.getColumnsWidth()) + 'px';
  533. this._removingColumn = false;
  534. }
  535. var cn = this.contentNode;
  536. cn.style.width = w;
  537. this.hasHScrollbar(true);
  538. },
  539. setSize: function(w, h){
  540. var ds = this.domNode.style;
  541. var hs = this.headerNode.style;
  542. if(w){
  543. ds.width = w;
  544. hs.width = w;
  545. }
  546. ds.height = (h >= 0 ? h + 'px' : '');
  547. },
  548. renderRow: function(inRowIndex){
  549. var rowNode = this.createRowNode(inRowIndex);
  550. this.buildRow(inRowIndex, rowNode);
  551. //this.grid.edit.restore(this, inRowIndex);
  552. return rowNode;
  553. },
  554. createRowNode: function(inRowIndex){
  555. var node = document.createElement("div");
  556. node.className = this.classTag + 'Row';
  557. if (this instanceof dojox.grid._RowSelector){
  558. html.attr(node,"role","presentation");
  559. }else{
  560. html.attr(node,"role","row");
  561. if (this.grid.selectionMode != "none") {
  562. node.setAttribute("aria-selected", "false"); //rows can be selected so add aria-selected prop
  563. }
  564. }
  565. node[util.gridViewTag] = this.id;
  566. node[util.rowIndexTag] = inRowIndex;
  567. this.rowNodes[inRowIndex] = node;
  568. return node;
  569. },
  570. buildRow: function(inRowIndex, inRowNode){
  571. this.buildRowContent(inRowIndex, inRowNode);
  572. this.styleRow(inRowIndex, inRowNode);
  573. },
  574. buildRowContent: function(inRowIndex, inRowNode){
  575. inRowNode.innerHTML = this.content.generateHtml(inRowIndex, inRowIndex);
  576. if(this.flexCells && this.contentWidth){
  577. // FIXME: accessing firstChild here breaks encapsulation
  578. inRowNode.firstChild.style.width = this.contentWidth;
  579. }
  580. util.fire(this, "onAfterRow", [inRowIndex, this.structure.cells, inRowNode]);
  581. },
  582. rowRemoved:function(inRowIndex){
  583. if(inRowIndex >= 0){
  584. this._cleanupRowWidgets(this.getRowNode(inRowIndex));
  585. }
  586. this.grid.edit.save(this, inRowIndex);
  587. delete this.rowNodes[inRowIndex];
  588. },
  589. getRowNode: function(inRowIndex){
  590. return this.rowNodes[inRowIndex];
  591. },
  592. getCellNode: function(inRowIndex, inCellIndex){
  593. var row = this.getRowNode(inRowIndex);
  594. if(row){
  595. return this.content.getCellNode(row, inCellIndex);
  596. }
  597. },
  598. getHeaderCellNode: function(inCellIndex){
  599. if(this.headerContentNode){
  600. return this.header.getCellNode(this.headerContentNode, inCellIndex);
  601. }
  602. },
  603. // styling
  604. styleRow: function(inRowIndex, inRowNode){
  605. inRowNode._style = getStyleText(inRowNode);
  606. this.styleRowNode(inRowIndex, inRowNode);
  607. },
  608. styleRowNode: function(inRowIndex, inRowNode){
  609. if(inRowNode){
  610. this.doStyleRowNode(inRowIndex, inRowNode);
  611. }
  612. },
  613. doStyleRowNode: function(inRowIndex, inRowNode){
  614. this.grid.styleRowNode(inRowIndex, inRowNode);
  615. },
  616. // updating
  617. updateRow: function(inRowIndex){
  618. var rowNode = this.getRowNode(inRowIndex);
  619. if(rowNode){
  620. rowNode.style.height = '';
  621. this.buildRow(inRowIndex, rowNode);
  622. }
  623. return rowNode;
  624. },
  625. updateRowStyles: function(inRowIndex){
  626. this.styleRowNode(inRowIndex, this.getRowNode(inRowIndex));
  627. },
  628. // scrolling
  629. lastTop: 0,
  630. firstScroll:0,
  631. _nativeScroll: false,
  632. doscroll: function(inEvent){
  633. if(has("ff") >= 13 || has("chrome")){
  634. this._nativeScroll = true;
  635. }
  636. //var s = dojo.marginBox(this.headerContentNode.firstChild);
  637. var isLtr = this.grid.isLeftToRight();
  638. if(this.firstScroll < 2){
  639. if((!isLtr && this.firstScroll == 1) || (isLtr && this.firstScroll === 0)){
  640. var s = html.marginBox(this.headerNodeContainer);
  641. if(has("ie")){
  642. this.headerNodeContainer.style.width = s.w + this.getScrollbarWidth() + 'px';
  643. }else if(has("mozilla")){
  644. //TODO currently only for FF, not sure for safari and opera
  645. this.headerNodeContainer.style.width = s.w - this.getScrollbarWidth() + 'px';
  646. //this.headerNodeContainer.style.width = s.w + 'px';
  647. //set scroll to right in FF
  648. this.scrollboxNode.scrollLeft = isLtr ?
  649. this.scrollboxNode.clientWidth - this.scrollboxNode.scrollWidth :
  650. this.scrollboxNode.scrollWidth - this.scrollboxNode.clientWidth;
  651. }
  652. }
  653. this.firstScroll++;
  654. }
  655. this.headerNode.scrollLeft = this.scrollboxNode.scrollLeft;
  656. // 'lastTop' is a semaphore to prevent feedback-loop with setScrollTop below
  657. var top = this.scrollboxNode.scrollTop;
  658. if(top !== this.lastTop){
  659. this.grid.scrollTo(top);
  660. }
  661. this._nativeScroll = false;
  662. },
  663. setScrollTop: function(inTop){
  664. // 'lastTop' is a semaphore to prevent feedback-loop with doScroll above
  665. this.lastTop = inTop;
  666. if(!this._nativeScroll){
  667. //fix #15487
  668. this.scrollboxNode.scrollTop = inTop;
  669. }
  670. return this.scrollboxNode.scrollTop;
  671. },
  672. // event handlers (direct from DOM)
  673. doContentEvent: function(e){
  674. if(this.content.decorateEvent(e)){
  675. this.grid.onContentEvent(e);
  676. }
  677. },
  678. doHeaderEvent: function(e){
  679. if(this.header.decorateEvent(e)){
  680. this.grid.onHeaderEvent(e);
  681. }
  682. },
  683. // event dispatch(from Grid)
  684. dispatchContentEvent: function(e){
  685. return this.content.dispatchEvent(e);
  686. },
  687. dispatchHeaderEvent: function(e){
  688. return this.header.dispatchEvent(e);
  689. },
  690. // column resizing
  691. setColWidth: function(inIndex, inWidth){
  692. this.grid.setCellWidth(inIndex, inWidth + 'px');
  693. },
  694. update: function(){
  695. if(!this.domNode){
  696. return;
  697. }
  698. this.content.update();
  699. this.grid.update();
  700. //get scroll after update or scroll left setting goes wrong on IE.
  701. //See trac: #8040
  702. var left = this.scrollboxNode.scrollLeft;
  703. this.scrollboxNode.scrollLeft = left;
  704. this.headerNode.scrollLeft = left;
  705. }
  706. });
  707. var _GridAvatar = declare("dojox.grid._GridAvatar", Avatar, {
  708. construct: function(){
  709. var dd = win.doc;
  710. var a = dd.createElement("table");
  711. a.cellPadding = a.cellSpacing = "0";
  712. a.className = "dojoxGridDndAvatar";
  713. a.style.position = "absolute";
  714. a.style.zIndex = 1999;
  715. a.style.margin = "0px"; // to avoid dojo.marginBox() problems with table's margins
  716. var b = dd.createElement("tbody");
  717. var tr = dd.createElement("tr");
  718. var td = dd.createElement("td");
  719. var img = dd.createElement("td");
  720. tr.className = "dojoxGridDndAvatarItem";
  721. img.className = "dojoxGridDndAvatarItemImage";
  722. img.style.width = "16px";
  723. var source = this.manager.source, node;
  724. if(source.creator){
  725. // create an avatar representation of the node
  726. node = source._normalizedCreator(source.getItem(this.manager.nodes[0].id).data, "avatar").node;
  727. }else{
  728. // or just clone the node and hope it works
  729. node = this.manager.nodes[0].cloneNode(true);
  730. var table, tbody;
  731. if(node.tagName.toLowerCase() == "tr"){
  732. // insert extra table nodes
  733. table = dd.createElement("table");
  734. tbody = dd.createElement("tbody");
  735. tbody.appendChild(node);
  736. table.appendChild(tbody);
  737. node = table;
  738. }else if(node.tagName.toLowerCase() == "th"){
  739. // insert extra table nodes
  740. table = dd.createElement("table");
  741. tbody = dd.createElement("tbody");
  742. var r = dd.createElement("tr");
  743. table.cellPadding = table.cellSpacing = "0";
  744. r.appendChild(node);
  745. tbody.appendChild(r);
  746. table.appendChild(tbody);
  747. node = table;
  748. }
  749. }
  750. node.id = "";
  751. td.appendChild(node);
  752. tr.appendChild(img);
  753. tr.appendChild(td);
  754. html.style(tr, "opacity", 0.9);
  755. b.appendChild(tr);
  756. a.appendChild(b);
  757. this.node = a;
  758. var m = dojo.dnd.manager();
  759. this.oldOffsetY = m.OFFSET_Y;
  760. m.OFFSET_Y = 1;
  761. },
  762. destroy: function(){
  763. dojo.dnd.manager().OFFSET_Y = this.oldOffsetY;
  764. this.inherited(arguments);
  765. }
  766. });
  767. var oldMakeAvatar = dojo.dnd.manager().makeAvatar;
  768. dojo.dnd.manager().makeAvatar = function(){
  769. var src = this.source;
  770. if(src.viewIndex !== undefined && !html.hasClass(win.body(),"dijit_a11y")){
  771. return new _GridAvatar(this);
  772. }
  773. return oldMakeAvatar.call(dojo.dnd.manager());
  774. };
  775. return _View;
  776. });