API Docs for: 3.8.0
Show:

File: datatable-deprecated/js/datatable-scroll.js

  1. // API Doc comments disabled to avoid deprecated class leakage into
  2. // non-deprecated class API docs.  See the 3.4.1 datatable API doc files in the
  3. // download at http://yui.zenfs.com/releases/yui3/yui_3.4.1.zip for reference.
  4. /**
  5. Extends DataTable base to enable x,y, and xy scrolling.

  6. DEPRECATED. As of YUI 3.5.0, DataTable has been rebuilt.  This module
  7. is designed to work with `datatable-base-deprecated` (effectively the 3.4.1
  8. version of DataTable) and will be removed from the library in a future version.

  9. See http://yuilibrary.com/yui/docs/migration.html for help upgrading to the
  10. latest version.

  11. For complete API docs for the classes in this and other deprecated
  12. DataTable-related modules, refer to the static API doc files in the 3.4.1
  13. download at http://yui.zenfs.com/releases/yui3/yui_3.4.1.zip

  14. @module datatable-deprecated
  15. @submodule datatable-scroll-deprecated
  16. @deprecated
  17. **/


  18. var YNode = Y.Node,
  19.     YLang = Y.Lang,
  20.     YUA = Y.UA,
  21.     YgetClassName = Y.ClassNameManager.getClassName,
  22.     DATATABLE = "datatable",
  23.     CLASS_HEADER = YgetClassName(DATATABLE, "hd"),
  24.     CLASS_BODY = YgetClassName(DATATABLE, "bd"),
  25.     CLASS_DATA = YgetClassName(DATATABLE, "data"),
  26.     CLASS_LINER = YgetClassName(DATATABLE, "liner"),
  27.     CLASS_SCROLLABLE = YgetClassName(DATATABLE, "scrollable"),
  28.     CONTAINER_HEADER = '<div class="'+CLASS_HEADER+'"></div>',
  29.     CONTAINER_BODY = '<div class="'+CLASS_BODY+'"></div>',
  30.     TEMPLATE_TABLE = '<table></table>',
  31.     scrollbarWidth = Y.cached(function () {
  32.         var testNode = Y.one('body').appendChild('<div style="position:absolute;visibility:hidden;overflow:scroll;width:20px;"><p style="height:1px"/></div>'),
  33.             width = testNode.get('offsetWidth') - testNode.get('clientWidth');

  34.         testNode.remove(true);

  35.         return width;
  36.     });
  37.    
  38. /*
  39.  * Adds scrolling to DataTable.
  40.  * @class DataTableScroll
  41.  * @extends Plugin.Base
  42.  */
  43. function DataTableScroll() {
  44.     DataTableScroll.superclass.constructor.apply(this, arguments);
  45. }

  46. Y.mix(DataTableScroll, {
  47.     NS: "scroll",

  48.     NAME: "dataTableScroll",

  49.     ATTRS: {
  50.    
  51.         /*
  52.         *  The width for the table. Set to a string (ex: "200px", "20em") if you want the table to scroll in the x direction.
  53.         *
  54.         * @attribute width
  55.         * @public
  56.         * @type string
  57.         */
  58.         width: {
  59.             value: undefined,
  60.             writeOnce: "initOnly"
  61.         },
  62.        
  63.         /*
  64.         *  The height for the table. Set to a string (ex: "200px", "20em") if you want the table to scroll in the y-direction.
  65.         *
  66.         * @attribute height
  67.         * @public
  68.         * @type string
  69.         */
  70.         height: {
  71.             value: undefined,
  72.             writeOnce: "initOnly"
  73.         },
  74.        
  75.        
  76.         /*
  77.         *  The scrolling direction for the table.
  78.         *
  79.         * @attribute scroll
  80.         * @private
  81.         * @type string
  82.         */
  83.         _scroll: {
  84.             //value: 'y',
  85.             valueFn: function() {
  86.                 var w = this.get('width'),
  87.                 h = this.get('height');
  88.                
  89.                 if (w && h) {
  90.                     return 'xy';
  91.                 }
  92.                 else if (w) {
  93.                     return 'x';
  94.                 }
  95.                 else if (h) {
  96.                     return 'y';
  97.                 }
  98.                 else {
  99.                     return null;
  100.                 }
  101.             }
  102.         },
  103.        
  104.        
  105.         /*
  106.         *  The hexadecimal colour value to set on the top-right of the table if a scrollbar exists.
  107.         *
  108.         * @attribute COLOR_COLUMNFILLER
  109.         * @public
  110.         * @type string
  111.         */
  112.         COLOR_COLUMNFILLER: {
  113.             value: '#f2f2f2',
  114.             validator: YLang.isString,
  115.             setter: function(param) {
  116.                 if (this._headerContainerNode) {
  117.                     this._headerContainerNode.setStyle('backgroundColor', param);
  118.                 }
  119.             }
  120.         }
  121.     }
  122. });

  123. Y.extend(DataTableScroll, Y.Plugin.Base, {
  124.    
  125.     /*
  126.     *  The table node created in datatable-base
  127.     *
  128.     * @property _parentTableNode
  129.     * @private
  130.     * @type {Node}
  131.     */
  132.     _parentTableNode: null,
  133.    
  134.    
  135.     /*
  136.     *  The THEAD node which resides within the table node created in datatable-base
  137.     *
  138.     * @property _parentTheadNode
  139.     * @private
  140.     * @type {Node}
  141.     */
  142.     _parentTheadNode: null,
  143.    
  144.    
  145.     /*
  146.     *  The TBODY node which resides within the table node created in datatable-base
  147.     *
  148.     * @property _parentTbodyNode
  149.     * @private
  150.     * @type {Node}
  151.     */
  152.     _parentTbodyNode: null,
  153.    
  154.    
  155.     /*
  156.     *  The TBODY Message node which resides within the table node created in datatable-base
  157.     *
  158.     * @property _parentMsgNode
  159.     * @private
  160.     * @type {Node}
  161.     */
  162.     _parentMsgNode: null,
  163.    
  164.    
  165.     /*
  166.     *  The contentBox specified for the datatable in datatable-base
  167.     *
  168.     * @property _parentContainer
  169.     * @private
  170.     * @type {Node}
  171.     */
  172.     _parentContainer: null,
  173.    
  174.    
  175.     /*
  176.     *  The DIV node that contains all the scrollable elements (a table with a tbody on it)
  177.     *
  178.     * @property _bodyContainerNode
  179.     * @private
  180.     * @type {Node}
  181.     */
  182.     _bodyContainerNode: null,
  183.    
  184.    
  185.     /*
  186.     *  The DIV node that contains a table with a THEAD in it (which syncs its horizontal scroll with the _bodyContainerNode above)
  187.     *
  188.     * @property _headerContainerNode
  189.     * @private
  190.     * @type {Node}
  191.     */
  192.     _headerContainerNode: null,
  193.    
  194.    
  195.     //--------------------------------------
  196.     //  Methods
  197.     //--------------------------------------


  198.    
  199.     initializer: function(config) {
  200.         var dt = this.get("host");
  201.         this._parentContainer = dt.get('contentBox');
  202.         this._parentContainer.addClass(CLASS_SCROLLABLE);
  203.         this._setUpNodes();
  204.     },
  205.    
  206.     /////////////////////////////////////////////////////////////////////////////
  207.     //
  208.     // Set up Table Nodes
  209.     //
  210.     /////////////////////////////////////////////////////////////////////////////
  211.    
  212.     /*
  213.     *  Set up methods to fire after host methods execute
  214.     *
  215.     * @method _setUpNodes
  216.     * @private
  217.     */          
  218.     _setUpNodes: function() {
  219.        
  220.         this.afterHostMethod("_addTableNode", this._setUpParentTableNode);
  221.         this.afterHostMethod("_addTheadNode", this._setUpParentTheadNode);
  222.         this.afterHostMethod("_addTbodyNode", this._setUpParentTbodyNode);
  223.         this.afterHostMethod("_addMessageNode", this._setUpParentMessageNode);
  224.         //this.beforeHostMethod('renderUI', this._removeCaptionNode);
  225.         this.afterHostMethod("renderUI", this.renderUI);
  226.         this.afterHostMethod("bindUI", this.bindUI);
  227.         this.afterHostMethod("syncUI", this.syncUI);
  228.        
  229.         if (this.get('_scroll') !== 'x') {
  230.             this.afterHostMethod('_attachTheadThNode', this._attachTheadThNode);
  231.             this.afterHostMethod('_attachTbodyTdNode', this._attachTbodyTdNode);
  232.         }
  233.        
  234.     },
  235.        
  236.     /*
  237.     *  Stores the main &lt;table&gt; node provided by the host as a private property
  238.     *
  239.     * @method _setUpParentTableNode
  240.     * @private
  241.     */
  242.     _setUpParentTableNode: function() {
  243.         this._parentTableNode = this.get('host')._tableNode;
  244.     },
  245.    
  246.    
  247.     /*
  248.     *  Stores the main &lt;thead&gt; node provided by the host as a private property
  249.     *
  250.     * @method _setUpParentTheadNode
  251.     * @private
  252.     */
  253.     _setUpParentTheadNode: function() {
  254.         this._parentTheadNode = this.get('host')._theadNode;
  255.     },
  256.    
  257.     /*
  258.     *  Stores the main &lt;tbody&gt; node provided by the host as a private property
  259.     *
  260.     * @method _setUpParentTbodyNode
  261.     * @private
  262.     */
  263.     _setUpParentTbodyNode: function() {
  264.         this._parentTbodyNode = this.get('host')._tbodyNode;
  265.     },
  266.    
  267.    
  268.     /*
  269.     *  Stores the main &lt;tbody&gt; message node provided by the host as a private property
  270.     *
  271.     * @method _setUpParentMessageNode
  272.     * @private
  273.     */
  274.     _setUpParentMessageNode: function() {
  275.         this._parentMsgNode = this.get('host')._msgNode;
  276.     },
  277.    
  278.     /////////////////////////////////////////////////////////////////////////////
  279.     //
  280.     // Renderer
  281.     //
  282.     /////////////////////////////////////////////////////////////////////////////
  283.    
  284.     /*
  285.     *  Primary rendering method that takes the datatable rendered in
  286.     * the host, and splits it up into two separate &lt;divs&gt; each containing two
  287.     * separate tables (one containing the head and one containing the body).
  288.     * This method fires after renderUI is called on datatable-base.
  289.     *
  290.     * @method renderUI
  291.     */
  292.     renderUI: function() {
  293.         //Y.Profiler.start('render');
  294.         this._createBodyContainer();
  295.         this._createHeaderContainer();
  296.         this._setContentBoxDimensions();
  297.         //Y.Profiler.stop('render');
  298.         //console.log(Y.Profiler.getReport("render"));
  299.     },
  300.    
  301.     /*
  302.     Binds event subscriptions to keep the state and UI in sync

  303.     @method bindUI
  304.     **/
  305.     bindUI: function () {
  306.         // FIXME: I don't know why the string bind, but I don't want to break
  307.         // stuff until I have time to rebuild it properly
  308.         this._bodyContainerNode.on('scroll', Y.bind("_onScroll", this));

  309.         this.afterHostEvent("recordsetChange", this.syncUI);
  310.         this.afterHostEvent("recordset:recordsChange", this.syncUI);
  311.     },

  312.     /*
  313.     *  Post rendering method that is responsible for creating a column
  314.     * filler, and performing width and scroll synchronization between the &lt;th&gt;
  315.     * elements and the &lt;td&gt; elements.
  316.     * This method fires after syncUI is called on datatable-base
  317.     *
  318.     * @method syncUI
  319.     * @public
  320.     */
  321.     syncUI: function() {
  322.         //Y.Profiler.start('sync');
  323.         this._removeCaptionNode();
  324.         this._syncWidths();
  325.         this._syncScroll();
  326.         //Y.Profiler.stop('sync');
  327.         //console.log(Y.Profiler.getReport("sync"));
  328.        
  329.     },
  330.    
  331.     /*
  332.     *  Remove the caption created in base. Scrolling datatables dont support captions.
  333.     *
  334.     * @method _removeCaptionNode
  335.     * @private
  336.     */
  337.     _removeCaptionNode: function() {
  338.         this.get('host')._captionNode.remove();
  339.         //Y.DataTable.Base.prototype.createCaption = function(v) {/*do nothing*/};
  340.         //Y.DataTable.Base.prototype._uiSetCaption = function(v) {/*do nothing*/};
  341.     },

  342.     /*
  343.     *  Adjusts the width of the TH and the TDs to make sure that the two are in sync
  344.     *
  345.     * Implementation Details:
  346.     *   Compares the width of the TH liner div to the the width of the TD node.
  347.     *   The TD liner width is not actually used because the TD often stretches
  348.     *   past the liner if the parent DIV is very large. Measuring the TD width
  349.     *   is more accurate.
  350.     *  
  351.     *   Instead of measuring via .get('width'), 'clientWidth' is used, as it
  352.     *   returns a number, whereas 'width' returns a string, In IE6,
  353.     *   'clientWidth' is not supported, so 'offsetWidth' is used. 'offsetWidth'
  354.     *   is not as accurate on Chrome,FF as 'clientWidth' - thus the need for
  355.     *   the fork.
  356.     *
  357.     * @method _syncWidths
  358.     * @private
  359.     */
  360.     _syncWidths: function() {
  361.         var headerTable = this._parentContainer.one('.' + CLASS_HEADER),
  362.             bodyTable   = this._parentContainer.one('.' + CLASS_BODY),
  363.             // nodelist of all the THs
  364.             headers     = headerTable.all('thead .' + CLASS_LINER),
  365.             // nodelist of the TDs in the first row
  366.             firstRow    = bodyTable.one('.' + CLASS_DATA + ' tr'),
  367.             cells       = firstRow && firstRow.all('.' + CLASS_LINER),
  368.             // FIXME: Code smell
  369.             widthProperty = (YUA.ie) ? 'offsetWidth' : 'clientWidth';

  370.             //stylesheet = new YStyleSheet('columnsSheet'),
  371.             //className;
  372.            
  373.         // If there are data rows, iterate each header and the cells of the
  374.         // first row comparing cell widths.  Assign the larger width to the
  375.         // narrower node (header or cell).
  376.         if (cells && cells.size()) {
  377.             headers.each(function (header, i) {
  378.                 var cell        = cells.item(i),
  379.                     headerWidth = header.get(widthProperty),
  380.                     cellWidth   = cell.get(widthProperty),
  381.                     width       = Math.max(headerWidth, cellWidth);

  382.                 width -= (parseInt(header.getComputedStyle('paddingLeft'),10)|0) +
  383.                          (parseInt(header.getComputedStyle('paddingRight'),10)|0);
  384.                
  385.                 header.setStyle('width', width + 'px');
  386.                 cell.setStyle('width', width + 'px');
  387.             });
  388.         }
  389.             /*
  390.             // If browser is not IE - get the clientWidth of the Liner
  391.             // div and the TD.
  392.             // Note:  We are not getting the width of the TDLiner, we
  393.             // are getting the width of the actual cell.  Why? Because
  394.             // when the table is set to auto width, the cell will grow
  395.             // to try to fit the table in its container.  The liner
  396.             // could potentially be much smaller than the cell width.
  397.             // TODO: Explore if there is a better way using only LINERS
  398.             // widths - I don't think this should be a problem, given
  399.             // that the liner is a div, a block element and will
  400.             // expand to width.
  401.             if (!ie) {
  402.                 // TODO: this should actually be done with
  403.                 // getComputedStyle('width') but this messes up
  404.                 // columns. Explore this option.
  405.                 thWidth = thLiner.get('clientWidth');
  406.                 tdWidth = td.item(i).get('clientWidth');
  407.             } else {
  408.                 // IE wasn't recognizing clientWidths, so we are using
  409.                 // offsetWidths.
  410.                 // TODO: should use getComputedStyle('width') because
  411.                 // offsetWidth will screw up when padding is changed.
  412.                 // TODO: for some reason, using
  413.                 // tdLiner.get('clientWidth') doesn't work - why not?
  414.                 thWidth = thLiner.get('offsetWidth');
  415.                 tdWidth = td.item(i).get('offsetWidth');
  416.                 //thWidth = parseFloat(thLiner.getComputedStyle('width').split('px')[0]);
  417.                 //tdWidth = parseFloat(td.item(i).getComputedStyle('width').split('px')[0]);
  418.             }
  419.                                
  420.             // expand the TH or the TD to match the wider
  421.             if (thWidth > tdWidth) {
  422.                 tdLiner.setStyle('width', (thWidth - 20 + 'px'));
  423.                 //thLiner.setStyle('width', (tdWidth - 20 + 'px'));
  424.                 //stylesheet.set(className,{'width': (thWidth - 20 + 'px')});
  425.             } else if (tdWidth > thWidth) {
  426.                 // if you don't set an explicit width here, when the width
  427.                 // is set in line 368, it will auto-shrink the widths of
  428.                 // the other cells (because they dont have an explicit
  429.                 // width)
  430.                 thLiner.setStyle('width', (tdWidth - 20 + 'px'));
  431.                 tdLiner.setStyle('width', (tdWidth - 20 + 'px'));
  432.                 //stylesheet.set(className,{'width': (tdWidth - 20 + 'px')});
  433.             }
  434.                
  435.             //}

  436.         }
  437.         */
  438.        
  439.         //stylesheet.enable();

  440.     },
  441.    
  442.     /*
  443.     *  Adds the approriate width to the liner divs of the TH nodes before they are appended to DOM
  444.     *
  445.     * @method _attachTheadThNode
  446.     * @private
  447.     */
  448.     _attachTheadThNode: function(o) {
  449.         var width = o.column.get('width');
  450.        
  451.         if (width) {
  452.             o.th.one('.' + CLASS_LINER)
  453.                 .setStyles({
  454.                     width: width,
  455.                     overflow:'hidden'
  456.                 });
  457.         }
  458.     },
  459.    
  460.     /*
  461.     *  Adds the appropriate width to the liner divs of the TD nodes before they are appended to DOM
  462.     *
  463.     * @method _attachTbodyTdNode
  464.     * @private
  465.     */
  466.     _attachTbodyTdNode: function(o) {
  467.         var width = o.column.get('width');
  468.        
  469.         if (width) {
  470.             o.td.one('.' + CLASS_LINER)
  471.                 .setStyles({
  472.                     width: width,
  473.                     overflow: 'hidden'
  474.                 });
  475.         }
  476.     },
  477.    
  478.     /*
  479.     *  Creates the body DIV that contains all the data.
  480.     *
  481.     * @method _createBodyContainer
  482.     * @private
  483.     */
  484.     _createBodyContainer: function() {
  485.         var bd = YNode.create(CONTAINER_BODY);
  486.            
  487.         this._bodyContainerNode = bd;      
  488.         this._setStylesForTbody();
  489.        
  490.         bd.appendChild(this._parentTableNode);
  491.         this._parentContainer.appendChild(bd);
  492.     },
  493.    
  494.     /*
  495.     *  Creates the DIV that contains a &lt;table&gt; with all the headers.
  496.     *
  497.     * @method _createHeaderContainer
  498.     * @private
  499.     */
  500.     _createHeaderContainer: function() {
  501.         var hd = YNode.create(CONTAINER_HEADER),
  502.             tbl = YNode.create(TEMPLATE_TABLE);
  503.            
  504.         this._headerContainerNode = hd;
  505.        
  506.         //hd.setStyle('backgroundColor',this.get("COLOR_COLUMNFILLER"));
  507.         this._setStylesForThead();
  508.         tbl.appendChild(this._parentTheadNode);
  509.         hd.appendChild(tbl);
  510.         this._parentContainer.prepend(hd);
  511.        
  512.     },
  513.    
  514.     /*
  515.     *  Creates styles for the TBODY based on what type of table it is.
  516.     *
  517.     * @method _setStylesForTbody
  518.     * @private
  519.     */
  520.     _setStylesForTbody: function() {
  521.         var dir = this.get('_scroll'),
  522.             w = this.get('width') || "",
  523.             h = this.get('height') || "",
  524.             el = this._bodyContainerNode,
  525.             styles = {width:"", height:h};
  526.                
  527.         if (dir === 'x') {
  528.             //X-Scrolling tables should not have a Y-Scrollbar so overflow-y is hidden. THe width on x-scrolling tables must be set by user.
  529.             styles.overflowY = 'hidden';
  530.             styles.width = w;
  531.         } else if (dir === 'y') {
  532.             //Y-Scrolling tables should not have a X-Scrollbar so overflow-x is hidden. The width isn't neccessary because it can be auto.
  533.             styles.overflowX = 'hidden';
  534.         } else if (dir === 'xy') {
  535.             styles.width = w;
  536.         } else {
  537.             //scrolling is set to 'null' - ie: width and height are not set. Don't have any type of scrolling.
  538.             styles.overflowX = 'hidden';
  539.             styles.overflowY = 'hidden';
  540.             styles.width = w;
  541.         }
  542.        
  543.         el.setStyles(styles);
  544.         return el;
  545.     },
  546.    
  547.    
  548.     /*
  549.     *  Creates styles for the THEAD based on what type of datatable it is.
  550.     *
  551.     * @method _setStylesForThead
  552.     * @private
  553.     */
  554.     _setStylesForThead: function() {
  555.         var w = this.get('width') || "",
  556.             el = this._headerContainerNode;
  557.        
  558.         //if (dir !== 'y') {
  559.         el.setStyles({'width': w, 'overflow': 'hidden'});
  560.         // }
  561.     },
  562.    
  563.     /*
  564.     *  Sets an auto width on the content box if it doesn't exist or if its a y-datatable.
  565.     *
  566.     * @method _setContentBoxDimensions
  567.     * @private
  568.     */
  569.     _setContentBoxDimensions: function() {
  570.        
  571.         if (this.get('_scroll') === 'y' || (!this.get('width'))) {
  572.             this._parentContainer.setStyle('width', 'auto');
  573.         }
  574.        
  575.     },
  576.    
  577.     /////////////////////////////////////////////////////////////////////////////
  578.     //
  579.     // Scroll Syncing
  580.     //
  581.     /////////////////////////////////////////////////////////////////////////////
  582.    
  583.     /*
  584.     *  Ensures that scrolling is synced across the two tables
  585.     *
  586.     * @method _onScroll
  587.     * @private
  588.     */
  589.     _onScroll: function() {
  590.         this._headerContainerNode.set('scrollLeft', this._bodyContainerNode.get('scrollLeft'));
  591.     },
  592.    
  593.     /*
  594.      *  Syncs padding around scrollable tables, including Column header right-padding
  595.      * and container width and height.
  596.      *
  597.      * @method _syncScroll
  598.      * @private
  599.      */
  600.     _syncScroll : function() {
  601.         this._syncScrollX();
  602.         this._syncScrollY();
  603.         this._syncScrollOverhang();
  604.         if (YUA.opera) {
  605.             // Bug 1925874
  606.             this._headerContainerNode.set('scrollLeft', this._bodyContainerNode.get('scrollLeft'));
  607.            
  608.             if(!this.get("width")) {
  609.                 // Bug 1926125
  610.                 document.body.style += '';
  611.             }
  612.         }
  613.     },
  614.    
  615.     /*
  616.     *  Snaps container width for y-scrolling tables.
  617.     *
  618.     * @method _syncScrollY
  619.     * @private
  620.     */
  621.     _syncScrollY : function() {
  622.         var tBody = this._parentTbodyNode,
  623.             tBodyContainer = this._bodyContainerNode,
  624.             w;
  625.             // X-scrolling not enabled
  626.             if(!this.get("width")) {
  627.                 // Snap outer container width to content
  628.                 w = (tBodyContainer.get('scrollHeight') > tBodyContainer.get('clientHeight')) ?
  629.                 // but account for y-scrollbar since it is visible
  630.                     (tBody.get('parentNode').get('clientWidth') + scrollbarWidth()) + "px" :
  631.                     // no y-scrollbar, just borders
  632.                     (tBody.get('parentNode').get('clientWidth') + 2) + "px";
  633.                 this._parentContainer.setStyle('width', w);
  634.         }
  635.     },
  636.        
  637.     /*
  638.      *  Snaps container height for x-scrolling tables in IE. Syncs message TBODY width.
  639.      * Taken from YUI2 ScrollingDataTable.js
  640.      *
  641.      * @method _syncScrollX
  642.      * @private
  643.      */
  644.     _syncScrollX: function() {
  645.         var tBody = this._parentTbodyNode,
  646.             tBodyContainer = this._bodyContainerNode,
  647.             w;

  648.         this._headerContainerNode.set('scrollLeft',
  649.             this._bodyContainerNode.get('scrollLeft'));
  650.        
  651.         if (!this.get('height') && (YUA.ie)) {
  652.             w = (tBodyContainer.get('scrollWidth') > tBodyContainer.get('offsetWidth')) ?
  653.                 (tBody.get('parentNode').get('offsetHeight') + scrollbarWidth()) + "px" :
  654.                 tBody.get('parentNode').get('offsetHeight') + "px";
  655.            
  656.             tBodyContainer.setStyle('height', w);
  657.         }
  658.            
  659.         if (tBody.get('rows').size()) {
  660.             this._parentMsgNode.get('parentNode').setStyle('width', "");
  661.         } else {
  662.             this._parentMsgNode.get('parentNode').setStyle('width', this._parentTheadNode.get('parentNode').get('offsetWidth')+'px');
  663.         }
  664.            
  665.     },
  666.    
  667.     /*
  668.      *  Adds/removes Column header overhang as necesary.
  669.      * Taken from YUI2 ScrollingDataTable.js
  670.      *
  671.      * @method _syncScrollOverhang
  672.      * @private
  673.      */
  674.     _syncScrollOverhang: function() {
  675.         var tBodyContainer = this._bodyContainerNode,
  676.             padding = 1;
  677.        
  678.         //when its both x and y scrolling
  679.         if ((tBodyContainer.get('scrollHeight') > tBodyContainer.get('clientHeight')) || (tBodyContainer.get('scrollWidth') > tBodyContainer.get('clientWidth'))) {
  680.             padding = 18;
  681.         }
  682.        
  683.         this._setOverhangValue(padding);
  684.        
  685.         // After the widths have synced, there is a wrapping issue in the
  686.         // headerContainer in IE6. The header does not span the full length of
  687.         // the table (does not cover all of the y-scrollbar). By adding this
  688.         // line in when there is a y-scroll, the header will span correctly.
  689.         // TODO: this should not really occur on this.get('_scroll') === y - it
  690.         // should occur when scrollHeight > clientHeight, but clientHeight is
  691.         // not getting recognized in IE6?
  692.         if (YUA.ie !== 0 && this.get('_scroll') === 'y' && this._bodyContainerNode.get('scrollHeight') > this._bodyContainerNode.get('offsetHeight'))
  693.         {
  694.             this._headerContainerNode.setStyle('width', this._parentContainer.get('width'));
  695.         }
  696.     },
  697.    
  698.    
  699.     /*
  700.      *  Sets Column header overhang to given width.
  701.      * Taken from YUI2 ScrollingDataTable.js with minor modifications
  702.      *
  703.      * @method _setOverhangValue
  704.      * @param nBorderWidth {Number} Value of new border for overhang.
  705.      * @private
  706.      */
  707.     _setOverhangValue: function(borderWidth) {
  708.         var host = this.get('host'),
  709.             cols = host.get('columnset').get('definitions'),
  710.             //lastHeaders = cols[cols.length-1] || [],
  711.             len = cols.length,
  712.             value = borderWidth + "px solid " + this.get("COLOR_COLUMNFILLER"),
  713.             children = YNode.all('#'+this._parentContainer.get('id')+ ' .' + CLASS_HEADER + ' table thead th');

  714.         children.item(len-1).setStyle('borderRight', value);
  715.     }
  716.    
  717. });

  718. Y.namespace("Plugin").DataTableScroll = DataTableScroll;

  719.