ColumnSet.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. define(["dojo/_base/kernel", "dojo/_base/declare", "dojo/_base/lang", "dojo/_base/Deferred", "dojo/on", "dojo/aspect", "dojo/query", "dojo/has", "./util/misc", "put-selector/put", "xstyle/has-class", "./Grid", "dojo/_base/sniff", "xstyle/css!./css/columnset.css"],
  2. function(kernel, declare, lang, Deferred, listen, aspect, query, has, miscUtil, put, hasClass, Grid){
  3. has.add("event-mousewheel", function(global, document, element){
  4. return typeof element.onmousewheel !== "undefined";
  5. });
  6. has.add("event-wheel", function(global, document, element){
  7. var supported = false;
  8. // From https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/wheel
  9. try{
  10. WheelEvent("wheel");
  11. supported = true;
  12. }catch(e){ // empty catch block; prevent debuggers from snagging
  13. }finally{
  14. return supported;
  15. }
  16. });
  17. var colsetidAttr = "data-dgrid-column-set-id";
  18. hasClass("safari", "ie-7");
  19. function adjustScrollLeft(grid, row){
  20. var scrollLefts = grid._columnSetScrollLefts;
  21. function doAdjustScrollLeft(){
  22. query(".dgrid-column-set", row).forEach(function(element){
  23. element.scrollLeft = scrollLefts[element.getAttribute(colsetidAttr)];
  24. });
  25. }
  26. if(has("ie") < 8 || has("quirks")){
  27. setTimeout(doAdjustScrollLeft, 1);
  28. }else{
  29. doAdjustScrollLeft();
  30. }
  31. }
  32. function scrollColumnSet(grid, columnSetNode, amount){
  33. var id = columnSetNode.getAttribute(colsetidAttr),
  34. scroller = grid._columnSetScrollers[id],
  35. scrollLeft = scroller.scrollLeft + amount;
  36. scroller.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft;
  37. }
  38. var horizMouseWheel;
  39. if(!has("touch")){
  40. horizMouseWheel = has("event-mousewheel") || has("event-wheel") ? function(grid){
  41. return function(target, listener){
  42. return listen(target, has("event-wheel") ? "wheel" : "mousewheel", function(event){
  43. var node = event.target, deltaX;
  44. // WebKit will invoke mousewheel handlers with an event target of a text
  45. // node; check target and if it's not an element node, start one node higher
  46. // in the tree
  47. if(node.nodeType !== 1){
  48. node = node.parentNode;
  49. }
  50. while(!query.matches(node, ".dgrid-column-set[" + colsetidAttr + "]", target)){
  51. if(node === target || !(node = node.parentNode)){
  52. return;
  53. }
  54. }
  55. // Normalize reported delta value:
  56. // wheelDeltaX (webkit, mousewheel) needs to be negated and divided by 3
  57. // deltaX (FF17+, wheel) can be used exactly as-is
  58. deltaX = event.deltaX || -event.wheelDeltaX / 3;
  59. if(deltaX){
  60. // only respond to horizontal movement
  61. listener.call(null, grid, node, deltaX);
  62. }
  63. });
  64. };
  65. } : function(grid){
  66. return function(target, listener){
  67. return listen(target, ".dgrid-column-set[" + colsetidAttr + "]:MozMousePixelScroll", function(event){
  68. if(event.axis === 1){
  69. // only respond to horizontal movement
  70. listener.call(null, grid, this, event.detail);
  71. }
  72. });
  73. };
  74. };
  75. }
  76. return declare(null, {
  77. // summary:
  78. // Provides column sets to isolate horizontal scroll of sets of
  79. // columns from each other. This mainly serves the purpose of allowing for
  80. // column locking.
  81. postCreate: function(){
  82. this.inherited(arguments);
  83. if(!has("touch")){
  84. this.on(horizMouseWheel(this), function(grid, colsetNode, amount){
  85. var id = colsetNode.getAttribute(colsetidAttr),
  86. scroller = grid._columnSetScrollers[id],
  87. scrollLeft = scroller.scrollLeft + amount;
  88. scroller.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft;
  89. });
  90. }
  91. },
  92. columnSets: [],
  93. createRowCells: function(tag, each, subRows, object){
  94. var row = put("table.dgrid-row-table");
  95. var tr = put(row, "tbody tr");
  96. for(var i = 0, l = this.columnSets.length; i < l; i++){
  97. // iterate through the columnSets
  98. var cell = put(tr, tag + ".dgrid-column-set-cell.dgrid-column-set-" + i +
  99. " div.dgrid-column-set[" + colsetidAttr + "=" + i + "]");
  100. cell.appendChild(this.inherited(arguments, [tag, each, this.columnSets[i], object]));
  101. }
  102. return row;
  103. },
  104. renderArray: function(){
  105. var grid = this,
  106. rows = this.inherited(arguments);
  107. Deferred.when(rows, function(rows){
  108. for(var i = 0; i < rows.length; i++){
  109. adjustScrollLeft(grid, rows[i]);
  110. }
  111. });
  112. return rows;
  113. },
  114. renderHeader: function(){
  115. // summary:
  116. // Setup the headers for the grid
  117. this.inherited(arguments);
  118. var columnSets = this.columnSets,
  119. domNode = this.domNode,
  120. scrollers = this._columnSetScrollers,
  121. scrollerContents = this._columnSetScrollerContents = {},
  122. scrollLefts = this._columnSetScrollLefts = {},
  123. grid = this,
  124. i, l;
  125. function reposition(){
  126. grid._positionScrollers();
  127. }
  128. if (scrollers) {
  129. // this isn't the first time; destroy existing scroller nodes first
  130. for(i in scrollers){
  131. put(scrollers[i], "!");
  132. }
  133. } else {
  134. // first-time-only operations: hook up event/aspected handlers
  135. aspect.after(this, "resize", reposition, true);
  136. aspect.after(this, "styleColumn", reposition, true);
  137. listen(domNode, ".dgrid-column-set:dgrid-cellfocusin", lang.hitch(this, '_onColumnSetScroll'));
  138. }
  139. // reset to new object to be populated in loop below
  140. scrollers = this._columnSetScrollers = {};
  141. for(i = 0, l = columnSets.length; i < l; i++){
  142. this._putScroller(columnSets[i], i);
  143. }
  144. this._positionScrollers();
  145. },
  146. styleColumnSet: function(colsetId, css){
  147. // summary:
  148. // Dynamically creates a stylesheet rule to alter a columnset's style.
  149. var rule = this.addCssRule("#" + miscUtil.escapeCssIdentifier(this.domNode.id) + " .dgrid-column-set-" + colsetId, css);
  150. this._positionScrollers();
  151. return rule;
  152. },
  153. _destroyColumns: function(){
  154. var columnSetsLength = this.columnSets.length,
  155. i, j, k, subRowsLength, len, columnSet, subRow, column;
  156. for(i = 0; i < columnSetsLength; i++){
  157. columnSet = this.columnSets[i];
  158. for(j = 0, subRowsLength = columnSet.length; j < subRowsLength; j++){
  159. subRow = columnSet[j];
  160. for(k = 0, len = subRow.length; k < len; k++){
  161. column = subRow[k];
  162. if(typeof column.destroy === "function"){ column.destroy(); }
  163. }
  164. }
  165. }
  166. this.inherited(arguments);
  167. },
  168. configStructure: function(){
  169. this.columns = {};
  170. for(var i = 0, l = this.columnSets.length; i < l; i++){
  171. // iterate through the columnSets
  172. var columnSet = this.columnSets[i];
  173. for(var j = 0; j < columnSet.length; j++){
  174. columnSet[j] = this._configColumns(i + "-" + j + "-", columnSet[j]);
  175. }
  176. }
  177. },
  178. _positionScrollers: function (){
  179. var domNode = this.domNode,
  180. scrollers = this._columnSetScrollers,
  181. scrollerContents = this._columnSetScrollerContents,
  182. columnSets = this.columnSets,
  183. left = 0,
  184. scrollerWidth = 0,
  185. numScrollers = 0, // tracks number of visible scrollers (sets w/ overflow)
  186. i, l, columnSetElement, contentWidth;
  187. for(i = 0, l = columnSets.length; i < l; i++){
  188. // iterate through the columnSets
  189. left += scrollerWidth;
  190. columnSetElement = query('.dgrid-column-set[' + colsetidAttr + '="' + i +'"]', domNode)[0];
  191. scrollerWidth = columnSetElement.offsetWidth;
  192. contentWidth = columnSetElement.firstChild.offsetWidth;
  193. scrollerContents[i].style.width = contentWidth + "px";
  194. scrollers[i].style.width = scrollerWidth + "px";
  195. scrollers[i].style.bottom = this.showFooter ? this.footerNode.offsetHeight + "px" : "0px";
  196. // IE seems to need scroll to be set explicitly
  197. scrollers[i].style.overflowX = contentWidth > scrollerWidth ? "scroll" : "auto";
  198. scrollers[i].style.left = left + "px";
  199. // Keep track of how many scrollbars we're showing
  200. if(contentWidth > scrollerWidth){ numScrollers++; }
  201. }
  202. // Align bottom of body node depending on whether there are scrollbars
  203. this.bodyNode.style.bottom = numScrollers ?
  204. (has("dom-scrollbar-height") + (has("ie") ? 1 : 0) + "px") :
  205. "0";
  206. },
  207. _putScroller: function (columnSet, i){
  208. // function called for each columnSet
  209. var scroller = this._columnSetScrollers[i] =
  210. put(this.domNode, "div.dgrid-column-set-scroller.dgrid-column-set-scroller-" + i +
  211. "[" + colsetidAttr + "=" + i +"]");
  212. this._columnSetScrollerContents[i] = put(scroller, "div.dgrid-column-set-scroller-content");
  213. listen(scroller, "scroll", lang.hitch(this, '_onColumnSetScroll'));
  214. },
  215. _onColumnSetScroll: function (evt){
  216. var scrollLeft = evt.target.scrollLeft,
  217. colSetId = evt.target.getAttribute(colsetidAttr),
  218. newScrollLeft;
  219. if(this._columnSetScrollLefts[colSetId] != scrollLeft){
  220. query('.dgrid-column-set[' + colsetidAttr + '="' + colSetId + '"],.dgrid-column-set-scroller[' + colsetidAttr + '="' + colSetId + '"]', this.domNode).
  221. forEach(function(element, i){
  222. element.scrollLeft = scrollLeft;
  223. if(!i){
  224. // Compute newScrollLeft based on actual resulting
  225. // value of scrollLeft, which may be different than
  226. // what we assigned under certain circumstances
  227. // (e.g. Chrome under 33% / 67% / 90% zoom).
  228. // Only need to compute this once, as it will be the
  229. // same for every row.
  230. newScrollLeft = element.scrollLeft;
  231. }
  232. });
  233. this._columnSetScrollLefts[colSetId] = newScrollLeft;
  234. }
  235. },
  236. _setColumnSets: function(columnSets){
  237. this._destroyColumns();
  238. this.columnSets = columnSets;
  239. this._updateColumns();
  240. },
  241. setColumnSets: function(columnSets){
  242. kernel.deprecated("setColumnSets(...)", 'use set("columnSets", ...) instead', "dgrid 0.4");
  243. this.set("columnSets", columnSets);
  244. }
  245. });
  246. });