` of the configured width for "x"
+ scrolling.
+
+ @method _syncXScrollUI
+ @param {Boolean} xy True if the table is configured with scrollable ="xy"
+ @protected
+ @since 3.5.0
+ **/
+ _syncXScrollUI: function (xy) {
+ var scroller = this._xScrollNode,
+ yScroller = this._yScrollContainer,
+ table = this._tableNode,
+ width = this.get('width'),
+ bbWidth = this.get('boundingBox').get('offsetWidth'),
+ scrollbarWidth = Y.DOM.getScrollbarWidth(),
+ borderWidth, tableWidth;
+
+ if (!scroller) {
+ scroller = this._createXScrollNode();
+
+ // Not using table.wrap() because IE went all crazy, wrapping the
+ // table in the last td in the table itself.
+ (yScroller || table).replace(scroller).appendTo(scroller);
+ }
+
+ // Can't use offsetHeight - clientHeight because IE6 returns
+ // clientHeight of 0 intially.
+ borderWidth = styleDim(scroller, 'borderLeftWidth') +
+ styleDim(scroller, 'borderRightWidth');
+
+ scroller.setStyle('width', '');
+ this._uiSetDim('width', '');
+ if (xy && this._yScrollContainer) {
+ this._yScrollContainer.setStyle('width', '');
+ }
+
+ // Lock the table's unconstrained width to avoid configured column
+ // widths being ignored
+ if (Y.UA.ie && Y.UA.ie < 8) {
+ // Have to assign a style and trigger a reflow to allow the
+ // subsequent clearing of width + reflow to expand the table to
+ // natural width in IE 6
+ table.setStyle('width', width);
+ table.get('offsetWidth');
+ }
+ table.setStyle('width', '');
+ tableWidth = table.get('offsetWidth');
+ table.setStyle('width', tableWidth + 'px');
+
+ this._uiSetDim('width', width);
+
+ // Can't use 100% width because the borders add additional width
+ // TODO: Cache the border widths, though it won't prevent a reflow
+ scroller.setStyle('width', (bbWidth - borderWidth) + 'px');
+
+ // expand the table to fill the assigned width if it doesn't
+ // already overflow the configured width
+ if ((scroller.get('offsetWidth') - borderWidth) > tableWidth) {
+ // Assumes the wrapped table doesn't have borders
+ if (xy) {
+ table.setStyle('width', (scroller.get('offsetWidth') -
+ borderWidth - scrollbarWidth) + 'px');
+ } else {
+ table.setStyle('width', '100%');
+ }
+ }
+ },
+
+ /**
+ Wraps the table in a scrolling `
` of the configured height (accounting
+ for the caption if there is one) if "y" scrolling is enabled. Otherwise,
+ unwraps the table if necessary.
+
+ @method _syncYScrollUI
+ @param {Boolean} xy True if the table is configured with scrollable = "xy"
+ @protected
+ @since 3.5.0
+ **/
+ _syncYScrollUI: function (xy) {
+ var yScroller = this._yScrollContainer,
+ yScrollNode = this._yScrollNode,
+ xScroller = this._xScrollNode,
+ fixedHeader = this._yScrollHeader,
+ scrollbar = this._scrollbarNode,
+ table = this._tableNode,
+ thead = this._theadNode,
+ captionTable = this._captionTable,
+ boundingBox = this.get('boundingBox'),
+ contentBox = this.get('contentBox'),
+ width = this.get('width'),
+ height = boundingBox.get('offsetHeight'),
+ scrollbarWidth = Y.DOM.getScrollbarWidth(),
+ outerScroller;
+
+ if (captionTable && !xy) {
+ captionTable.setStyle('width', width || '100%');
+ }
+
+ if (!yScroller) {
+ yScroller = this._createYScrollNode();
+
+ yScrollNode = this._yScrollNode;
+
+ table.replace(yScroller).appendTo(yScrollNode);
+ }
+
+ outerScroller = xy ? xScroller : yScroller;
+
+ if (!xy) {
+ table.setStyle('width', '');
+ }
+
+ // Set the scroller height
+ if (xy) {
+ // Account for the horizontal scrollbar in the overall height
+ height -= scrollbarWidth;
+ }
+
+ yScrollNode.setStyle('height',
+ (height - outerScroller.get('offsetTop') -
+ // because IE6 is returning clientHeight 0 initially
+ styleDim(outerScroller, 'borderTopWidth') -
+ styleDim(outerScroller, 'borderBottomWidth')) + 'px');
+
+ // Set the scroller width
+ if (xy) {
+ // For xy scrolling tables, the table should expand freely within
+ // the x scroller
+ yScroller.setStyle('width',
+ (table.get('offsetWidth') + scrollbarWidth) + 'px');
+ } else {
+ this._uiSetYScrollWidth(width);
+ }
+
+ if (captionTable && !xy) {
+ captionTable.setStyle('width', yScroller.get('offsetWidth') + 'px');
+ }
+
+ // Allow headerless scrolling
+ if (thead && !fixedHeader) {
+ fixedHeader = this._createYScrollHeader();
+
+ yScroller.prepend(fixedHeader);
+
+ this._syncScrollHeaders();
+ }
+
+ if (fixedHeader) {
+ this._syncScrollColumnWidths();
+
+ fixedHeader.setStyle('display', '');
+ // This might need to come back if FF has issues
+ //fixedHeader.setStyle('width', '100%');
+ //(yScroller.get('clientWidth') + scrollbarWidth) + 'px');
+
+ if (!scrollbar) {
+ scrollbar = this._createScrollbar();
+
+ this._bindScrollbar();
+
+ contentBox.prepend(scrollbar);
+ }
+
+ this._uiSetScrollbarHeight();
+ this._uiSetScrollbarPosition(outerScroller);
+ }
+ },
+
+ /**
+ Assigns the appropriate class to the `boundingBox` to identify the DataTable
+ as horizontally scrolling, vertically scrolling, or both (adds both classes).
+
+ Classes added are "yui3-datatable-scrollable-x" or "...-y"
+
+ @method _uiSetScrollable
+ @protected
+ @since 3.5.0
+ **/
+ _uiSetScrollable: function () {
+ this.get('boundingBox')
+ .toggleClass(this.getClassName('scrollable','x'), this._xScroll)
+ .toggleClass(this.getClassName('scrollable','y'), this._yScroll);
+ },
+
+ /**
+ Updates the virtual scrollbar's height to avoid overlapping with the fixed
+ headers.
+
+ @method _uiSetScrollbarHeight
+ @protected
+ @since 3.5.0
+ **/
+ _uiSetScrollbarHeight: function () {
+ var scrollbar = this._scrollbarNode,
+ scroller = this._yScrollNode,
+ fixedHeader = this._yScrollHeader;
+
+ if (scrollbar && scroller && fixedHeader) {
+ scrollbar.get('firstChild').setStyle('height',
+ this._tbodyNode.get('scrollHeight') + 'px');
+
+ scrollbar.setStyle('height',
+ (parseFloat(scroller.getComputedStyle('height')) -
+ parseFloat(fixedHeader.getComputedStyle('height'))) + 'px');
+ }
+ },
+
+ /**
+ Updates the virtual scrollbar's placement to avoid overlapping the fixed
+ headers or the data table.
+
+ @method _uiSetScrollbarPosition
+ @param {Node} scroller Reference node to position the scrollbar over
+ @protected
+ @since 3.5.0
+ **/
+ _uiSetScrollbarPosition: function (scroller) {
+ var scrollbar = this._scrollbarNode,
+ fixedHeader = this._yScrollHeader;
+
+ if (scrollbar && scroller && fixedHeader) {
+ scrollbar.setStyles({
+ // Using getCS instead of offsetHeight because FF uses
+ // fractional values, but reports ints to offsetHeight, so
+ // offsetHeight is unreliable. It is probably fine to use
+ // offsetHeight in this case but this was left in place after
+ // fixing an off-by-1px issue in FF 10- by fixing the caption
+ // font style so FF picked it up.
+ top: (parseFloat(fixedHeader.getComputedStyle('height')) +
+ styleDim(scroller, 'borderTopWidth') +
+ scroller.get('offsetTop')) + 'px',
+
+ // Minus 1 because IE 6-10 require the scrolled area to be
+ // visible by at least 1px or it won't respond to clicks on the
+ // scrollbar rail or endcap arrows.
+ left: (scroller.get('offsetWidth') -
+ Y.DOM.getScrollbarWidth() - 1 -
+ styleDim(scroller, 'borderRightWidth')) + 'px'
+ });
+ }
+ },
+
+ /**
+ Assigns the width of the `
` wrapping the data table in vertically
+ scrolling tables.
+
+ If the table can't compress to the specified width, the container is
+ expanded accordingly.
+
+ @method _uiSetYScrollWidth
+ @param {String} width The CSS width to attempt to set
+ @protected
+ @since 3.5.0
+ **/
+ _uiSetYScrollWidth: function (width) {
+ var scroller = this._yScrollContainer,
+ table = this._tableNode,
+ tableWidth, borderWidth, scrollerWidth, scrollbarWidth;
+
+ if (scroller && table) {
+ scrollbarWidth = Y.DOM.getScrollbarWidth();
+
+ if (width) {
+ // Assumes no table border
+ borderWidth = scroller.get('offsetWidth') -
+ scroller.get('clientWidth') +
+ scrollbarWidth; // added back at the end
+
+ // The table's rendered width might be greater than the
+ // configured width
+ scroller.setStyle('width', width);
+
+ // Have to subtract the border width from the configured width
+ // because the scroller's width will need to be reduced by the
+ // border width as well during the width reassignment below.
+ scrollerWidth = scroller.get('clientWidth') - borderWidth;
+
+ // Assumes no table borders
+ table.setStyle('width', scrollerWidth + 'px');
+
+ tableWidth = table.get('offsetWidth');
+
+ // Expand the scroll node width if the table can't fit.
+ // Otherwise, reassign the scroller a pixel width that
+ // accounts for the borders.
+ scroller.setStyle('width',
+ (tableWidth + scrollbarWidth) + 'px');
+ } else {
+ // Allow the table to expand naturally
+ table.setStyle('width', '');
+ scroller.setStyle('width', '');
+
+ scroller.setStyle('width',
+ (table.get('offsetWidth') + scrollbarWidth) + 'px');
+ }
+ }
+ },
+
+ /**
+ Detaches the scroll event subscriptions used to maintain scroll position
+ parity between the scrollable `
` wrapper around the data table and the
+ virtual scrollbar for vertically scrolling tables.
+
+ @method _unbindScrollbar
+ @protected
+ @since 3.5.0
+ **/
+ _unbindScrollbar: function () {
+ if (this._scrollbarEventHandle) {
+ this._scrollbarEventHandle.detach();
+ }
+ },
+
+ /**
+ Detaches the resize event subscription used to maintain column parity for
+ vertically scrolling tables with percentage widths.
+
+ @method _unbindScrollResize
+ @protected
+ @since 3.5.0
+ **/
+ _unbindScrollResize: function () {
+ if (this._scrollResizeHandle) {
+ this._scrollResizeHandle.detach();
+ delete this._scrollResizeHandle;
+ }
+ }
+
+ /**
+ Indicates horizontal table scrolling is enabled.
+
+ @property _xScroll
+ @type {Boolean}
+ @default undefined (not initially set)
+ @private
+ @since 3.5.0
+ **/
+ //_xScroll: null,
+
+ /**
+ Indicates vertical table scrolling is enabled.
+
+ @property _yScroll
+ @type {Boolean}
+ @default undefined (not initially set)
+ @private
+ @since 3.5.0
+ **/
+ //_yScroll: null,
+
+ /**
+ Fixed column header `
` Node for vertical scrolling tables.
+
+ @property _yScrollHeader
+ @type {Node}
+ @default undefined (not initially set)
+ @protected
+ @since 3.5.0
+ **/
+ //_yScrollHeader: null,
+
+ /**
+ Overflow Node used to contain the data rows in a vertically scrolling table.
+
+ @property _yScrollNode
+ @type {Node}
+ @default undefined (not initially set)
+ @protected
+ @since 3.5.0
+ **/
+ //_yScrollNode: null,
+
+ /**
+ Overflow Node used to contain the table headers and data in a horizontally
+ scrolling table.
+
+ @property _xScrollNode
+ @type {Node}
+ @default undefined (not initially set)
+ @protected
+ @since 3.5.0
+ **/
+ //_xScrollNode: null
+}, true);
+
+Y.Base.mix(Y.DataTable, [Scrollable]);
+
+
+}, '3.10.3', {"requires": ["datatable-base", "datatable-column-widths", "dom-screen"], "skinnable": true});