/* *+------------------------------------------------------------------------+ *| Licensed Materials - Property of IBM *| IBM Cognos Products: Viewer *| (C) Copyright IBM Corp. 2014 *| *| US Government Users Restricted Rights - Use, duplication or *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *| *+------------------------------------------------------------------------+ */ function CognosTabControl(container, callback) { this._init(); this._outsideContainer = container; // Container provisded by the caller this._callback = callback; // function to call when a tab is clicked } CognosTabControl.prototype._init = function() { this._tabs = null; this._tabControlNode = null; this._scrollButtonsVisible = false; this._scrollLeftButton = null; this._scrollRightButton = null; this._selectedTab = null; this._wrapperDiv = null; this._topContainer = null; this._seperator = null; this._isSavedOutput = false; this._isHighContrast = false; }; CognosTabControl.prototype.destroy = function() { if (this._wrapperDiv) { this._wrapperDiv.parentNode.removeChild(this._wrapperDiv); delete this._wrapperDiv; this._wrapperDiv = null; } }; CognosTabControl.prototype.setHighContrast = function(isHighContrast) { this._isHighContrast = isHighContrast; }; CognosTabControl.prototype.isHighContrast = function() { return this._isHighContrast; }; /** * In CW we have to save enough room for the absolutly positions tab control */ CognosTabControl.prototype.setSpaceSaverContainer = function(node) { this._spaceSaverContainer = node; }; /** * Used when we're in BUX so that the tab control is absolutly positioned inside the widget div */ CognosTabControl.prototype.useAbsolutePosition = function(value) { this._useAbsolutePosition = value; }; CognosTabControl.prototype.setScrollAttachNode = function(node) { this._scrollAttachNode = node; }; CognosTabControl.prototype.setIsSavedOutput = function(isSavedOutput) { this._isSavedOutput = isSavedOutput; }; CognosTabControl.prototype.isSavedOutput = function() { return this._isSavedOutput; }; CognosTabControl.prototype.getSelectedTabId = function() { if (this._selectedTab) { return this._selectedTab.getId(); } return null; }; CognosTabControl.prototype.getSelectedTab = function() { return this._selectedTab ? this._selectedTab : null; }; CognosTabControl.prototype.isTopAligned = function() { return this._isTopAligned; }; CognosTabControl.prototype.getWrapperDiv = function() { return this._wrapperDiv; }; CognosTabControl.prototype.getVisibleWidth = function() { var scrollButtonWidth = this._scrollRightButton ? this._scrollRightButton.getWidth() + 11 : 0; return this._wrapperDiv.clientWidth - scrollButtonWidth; }; CognosTabControl.prototype.getMaxRightScroll = function() { var scrollButtonWidth = this._scrollRightButton ? this._scrollRightButton.getWidth() + 11 : 0; return this._totalWrapperWidth + scrollButtonWidth + 8 - this._wrapperDiv.clientWidth; }; CognosTabControl.prototype.hide = function() { this._topContainer.style.display = "none"; }; /** * If we're using absolute positioning then this will reset the left, top and bottom values */ CognosTabControl.prototype.resetPosition = function() { if (this._useAbsolutePosition === true) { this._outsideContainer.srollLeft = "0px"; this._outsideContainer.scrollTop = "0px"; this._topContainer.style.top = ""; this._topContainer.style.bottom = ""; this._topContainer.style.left = "0px"; if (this._isTopAligned) { this._topContainer.style.top = "0px"; } else { this._topContainer.style.bottom = "0px"; } } }; /** Renders all the tabs **/ CognosTabControl.prototype.render = function(tabControlInfo) { this._updateTabInfo(tabControlInfo); if (!this._tabControlNode) { var tabControl = this; var scrollAttachNode = this._scrollAttachNode ? this._scrollAttachNode : this._outsideContainer; if (window.attachEvent) { window.attachEvent("onresize", function() { tabControl.onResize(); }); if (this._useAbsolutePosition === true) { scrollAttachNode.attachEvent("onscroll", function() { tabControl.onContainerScroll(); }); } } else { window.addEventListener("resize", function() { tabControl.onResize(); }, false); if (this._useAbsolutePosition === true) { scrollAttachNode.addEventListener("scroll", function() { tabControl.onContainerScroll(); }, false); } } this._outsideContainer.originalClassName = this._outsideContainer.className; this._outsideContainer.className = this._outsideContainer.className + (this._isTopAligned ? " ct_controlTop" : " ct_controlBottom"); this._topContainer = document.createElement("div"); this._topContainer.className = "ct_wrapperDiv"; if (this._useAbsolutePosition === true) { this._topContainer.style.width = "100%"; this._topContainer.style.position = "absolute"; this._topContainer.style.left = "0px"; if (this._isTopAligned) { this._topContainer.style.top = "0px"; } else { this._topContainer.style.bottom = "0px"; } } if (this._isTopAligned && this._outsideContainer.firstChild) { this._outsideContainer.insertBefore(this._topContainer, this._outsideContainer.firstChild); } else { this._outsideContainer.appendChild(this._topContainer); } this._wrapperDiv = document.createElement("div"); this._wrapperDiv.setAttribute("role", "presentation"); this._wrapperDiv.className = "ct_wrapperDiv"; this._topContainer.appendChild(this._wrapperDiv); this._tabControlNode = document.createElement("div"); this._tabControlNode.setAttribute("role", "tablist"); this._tabControlNode.className = "ct_control"; this._wrapperDiv.appendChild(this._tabControlNode); this._totalWrapperWidth = 0; for (var i=0; i < this._tabs.length; i++) { var tab = this._tabs[i]; tab.render(this._tabControlNode); this._totalWrapperWidth += this._tabs[i].getWidth(); } var wrapperDivHeight = 0; if (this._tabs[0]) { wrapperDivHeight = this._tabs[0].getHeight(); } this._wrapperDiv.style.height = wrapperDivHeight + 5 + "px"; if (this._spaceSaverContainer) { this.spaceSaverDiv = document.createElement("div"); this.spaceSaverDiv.style.height = wrapperDivHeight + 5 + "px"; this.spaceSaverDiv.style.position = "relative"; this.spaceSaverDiv.style.display = "block"; this._spaceSaverContainer.appendChild(this.spaceSaverDiv); } this._createSeperator(); } else { this.resetPosition(); } this._topContainer.style.display = ""; this.onResize(); this.selectTab(tabControlInfo.currentTabId, false); if (this._selectedTab) { this._selectedTab.scrollIntoView(); this.updateScrollButtons(); } }; /** * In BUX when the use scroll the widget container we need to make sure the tab control gets moved horizontally */ CognosTabControl.prototype.onContainerScroll = function() { var container = this._scrollAttachNode ? this._scrollAttachNode : this._topContainer; this._topContainer.style.left = container.scrollLeft + "px"; if (this._isTopAligned) { this._topContainer.style.top = container.scrollTop + "px"; } else { this._topContainer.style.bottom = (-container.scrollTop) + "px"; } }; CognosTabControl.prototype._resetTabControl = function() { if (this._outsideContainer.originalClassName) { this._outsideContainer.className = this._outsideContainer.originalClassName; } else { this._outsideContainer.className = ""; } if (this._topContainer) { var node = this._outsideContainer.removeChild(this._topContainer); node = null; } this._init(); }; /** Creates or updates the tab objects **/ CognosTabControl.prototype._updateTabInfo = function(tabControlInfo) { this._isTopAligned = tabControlInfo.position == "topLeft" ? true : false; var tabs = tabControlInfo.tabs; // We already have tabs, make sure nothing has changed if (this._tabs) { if (this._tabs.length != tabs.length) { this._resetTabControl(); } else { for (var i=0; i < this._tabs.length; i++) { if (tabs[i].id != this._tabs[i].getId()) { this._resetTabControl(); break; } } } } if (!this._tabs) { this._tabs = []; if (!tabs) { return; } for (var ii=0; ii < tabs.length; ii++) { var tab = new CognosTab(tabs[ii], this, ii); this._tabs.push(tab); } } }; CognosTabControl.prototype.getScrollPos = function() { return this._wrapperDiv.scrollLeft; }; CognosTabControl.prototype.scrollTo = function(scrollPos) { this._wrapperDiv.scrollLeft = scrollPos; this.updateScrollButtons(); }; /** Handles the window resize event to show/hide the scroll buttons **/ CognosTabControl.prototype.onResize = function(evt) { if (this._wrapperDiv.offsetWidth < this._totalWrapperWidth) { this._showScrollButtons(); this.updateScrollButtons(); if (this._selectedTab) { this._selectedTab.scrollIntoView(); } if (this._scrollRightButton.isDisabled()) { this.scrollTo(this.getMaxRightScroll()); } } else { this._hideScrollButtons(); this.scrollTo(0); } }; CognosTabControl.prototype._showScrollButtons = function() { if (this._scrollButtonsVisible) { return; } if (!this._scrollLeftButton) { var wrapperDivHeight = 0; if (this._tabs[0]) { wrapperDivHeight = this._tabs[0].getHeight(); } this._scrollLeftButton = new CognosScrollButton("left", wrapperDivHeight, this); this._scrollLeftButton.render(this._topContainer); this._scrollRightButton = new CognosScrollButton("right", wrapperDivHeight, this); this._scrollRightButton.render(this._topContainer); } this._scrollButtonsVisible = true; this._scrollLeftButton.show(); this._scrollRightButton.show(); this._tabControlNode.style.left = this._scrollLeftButton.getWidth() - 2 + "px"; }; CognosTabControl.prototype.updateScrollButtons = function() { if (this._scrollLeftButton) { this._scrollLeftButton.update(); } if (this._scrollRightButton) { this._scrollRightButton.update(); } }; CognosTabControl.prototype._hideScrollButtons = function() { if (!this._scrollButtonsVisible) { return; } this._scrollButtonsVisible = false; this._tabControlNode.style.left = "0px"; this._scrollLeftButton.hide(); this._scrollRightButton.hide(); }; /** Creates the line seperator that's either above or below the tabs **/ CognosTabControl.prototype._createSeperator = function() { this._seperator = document.createElement("div"); this._seperator.setAttribute("role", "presendation"); this._seperator.setAttribute("style", ""); this._seperator.className = "ct_verticalLine"; this._seperator.setAttribute("role", "presentation"); this._tabControlNode.appendChild(this._seperator); }; /** Selects one tab while making sure all the other tabs are unselected **/ CognosTabControl.prototype.selectTab = function(tabId, userInvokved, evt) { if (!evt) { evt = window.event; } for (var i=0; i < this._tabs.length; i++) { var tab = this._tabs[i]; var isSelected = tab.getId() == tabId; tab.select(isSelected); if (isSelected) { this._selectedTab = tab; if (userInvokved && this._callback) { this._callback(tabId); } } if (userInvokved) { tab.focus(isSelected); } } if (evt && window.stopEventBubble) { window.stopEventBubble(evt); } return false; }; CognosTabControl.prototype.handleKeyDown = function(evt, position) { if (!evt) { evt = window.event; } if (!evt) { return; } if (evt.keyCode == "39" || evt.keyCode == "37") { if (evt.keyCode == "39") { // left arrow position++; if (position >= this._tabs.length) { position = 0; } } else { position--; if (position < 0) { position = this._tabs.length-1; } } this._tabs[position].focus(); this._tabs[position].scrollIntoView(); } else if (evt.keyCode == "32" || evt.keyCode == "13") { // space or enter var tabId = this._tabs[position].getId(); this.selectTab(tabId, true); } }; /** Class that handles one tab in the tabControl **/ function CognosTab(tabInfo, tabControl, position) { if (!tabInfo) { return; } this._id = tabInfo.id; this._label = tabInfo.label; this._position = position; this._contentClassName = tabInfo.className; this._imgURL = tabInfo.img; this._selected = false; this._tabControl = tabControl; this._outerTabDiv = null; this._focusDiv = null; } CognosTab.prototype.getWidth = function() { return this._outerTabDiv.offsetWidth + 1; }; CognosTab.prototype.getHeight = function() { return this._outerTabDiv.clientHeight; }; CognosTab.prototype.getId = function() { return this._id; }; /** Either selects or deselects the tab **/ CognosTab.prototype.select = function(selected) { if (selected != this._selected) { this._selected = selected; if (selected) { this.scrollIntoView(); } if (this._outerTabDiv) { this._updateSelectedClass(); this._updateAriaSelected(); } } }; /** Scroll the tab into view if necessary **/ CognosTab.prototype.scrollIntoView = function() { var tabRightCoord = this._outerTabDiv.offsetLeft + this._outerTabDiv.clientWidth; var scrollLength = this._tabControl.getVisibleWidth(); var mainScrollPos = this._tabControl.getScrollPos(); var tabOffsetLeft = this._outerTabDiv.offsetLeft; if (tabOffsetLeft === 0) { this._tabControl.scrollTo(0); } else if ( (tabOffsetLeft >= mainScrollPos) && (tabRightCoord <= (mainScrollPos + scrollLength))) { // If the tab is already visible don't move the scroll position } else if (tabOffsetLeft < mainScrollPos) { var scrollTo = tabOffsetLeft < 3 ? 0 : tabOffsetLeft - 3; this._tabControl.scrollTo(scrollTo); } else if (tabRightCoord - scrollLength > 0 || tabRightCoord < mainScrollPos) { this._tabControl.scrollTo(tabRightCoord - scrollLength + 10); } }; /** Renders a tab **/ CognosTab.prototype.render = function(parentNode) { if (!this._outerTabDiv) { var tabId = this._id; var tabControl = this._tabControl; var tab = this; // Outer div this._outerTabDiv = document.createElement("div"); this._outerTabDiv.onmousedown = function(event) { tabControl.selectTab(tabId, true, event); }; this._outerTabDiv.onmouseover = function() { this.className = this.className + ' ct_highlight'; }; this._outerTabDiv.onmouseout = function() { tab._updateSelectedClass(); }; this._outerTabDiv.setAttribute("style", ""); this._outerTabDiv.setAttribute("role", "presentation"); this._updateSelectedClass(); parentNode.appendChild(this._outerTabDiv); // This is the div that takes focus var textWrapperDiv = document.createElement("div"); textWrapperDiv.className = "ct_content"; textWrapperDiv.setAttribute("role", "presentation"); this._outerTabDiv.appendChild(textWrapperDiv); // Tab text this._focusDiv = document.createElement("span"); this._focusDiv.innerHTML = this._label ? this._label : " "; this._focusDiv.className = "ct_text"; this._focusDiv.setAttribute("tabIndex", this._position === 0 ? "0" : "-1"); this._focusDiv.setAttribute("role", "tab"); this._focusDiv.onkeydown = function(event) {tabControl.handleKeyDown(event, tab._position);}; this._updateAriaSelected(); textWrapperDiv.appendChild(this._focusDiv); // Only needed in IE quirks mode since min-width doesn't work if (this.isIE() && this.getWidth() < 75) { this._outerTabDiv.style.width = "75px"; } } else { this._updateSelectedClass(); this._updateAriaSelected(); } }; CognosTab.prototype.isIE = function() { return (navigator.userAgent.indexOf('MSIE') != -1 || navigator.userAgent.indexOf('Trident') != -1); }; CognosTab.prototype.getFocusableDiv = function() { return this._focusDiv; }; CognosTab.prototype.focus = function(selected) { if (typeof selected === "undefined") { selected = true; } this._focusDiv.setAttribute("tabIndex", selected ? "0" : "-1"); if (selected && this._focusDiv.focus) { this._focusDiv.focus(); } }; /** Update the css class attribute depending on if the tab is selected **/ CognosTab.prototype._updateSelectedClass = function() { this._outerTabDiv.className = this._selected ? "ct_outerDiv ct_highlight ct_selected" : "ct_outerDiv"; }; /** Updated the aria-selected attribute **/ CognosTab.prototype._updateAriaSelected = function() { this._focusDiv.setAttribute("aria-selected", this._selected ? "true" : "false"); }; function CognosScrollButton(direction, height, tabControl) { this._direction = direction; this._height = height; this._tabControl = tabControl; this._disabled = true; this._scrolling = false; } CognosScrollButton.prototype.getWidth = function() { return this._scrollButtonDiv.offsetWidth + 1; }; CognosScrollButton.prototype.show = function() { this._wrapperDiv.style.display = "block"; }; CognosScrollButton.prototype.hide = function() { this._wrapperDiv.style.display = "none"; }; CognosScrollButton.prototype.update = function() { var wrapperDiv = this._tabControl.getWrapperDiv(); var disableButton = false; if (this._direction == 'left') { if (wrapperDiv.scrollLeft === 0) { disableButton = true; } } else { if (wrapperDiv.scrollLeft >= (this._tabControl.getMaxRightScroll() - 2)) { disableButton = true; } } if (disableButton) { this._disable(); } else { this._enable(); } }; CognosScrollButton.prototype.isDisabled = function() { return this._disabled; }; CognosScrollButton.prototype._disable = function() { this._disabled = true; this._outerDiv.className = "ct_outerDiv ct_scrollDisabled"; }; CognosScrollButton.prototype._enable = function() { this._disabled = false; this._outerDiv.className = "ct_outerDiv ct_scrollEnabled"; }; CognosScrollButton.prototype.scroll = function() { if (!this._scrolling) { this._scrolling = true; var scrollLength = this._tabControl.getWrapperDiv().clientWidth; this._doAnimateScroll(scrollLength, this._tabControl.getMaxRightScroll()); } }; CognosScrollButton.prototype._doAnimateScroll = function(scrollLength, maxRightScroll) { if (scrollLength > 0) { var scrollOffset = 10; var wrapperDiv = this._tabControl.getWrapperDiv(); if (this._direction == 'left') { if (wrapperDiv.scrollLeft > scrollOffset) { this._tabControl.scrollTo(wrapperDiv.scrollLeft - scrollOffset); } else { this._tabControl.scrollTo(0); this._scrolling = false; return; } } else { if (wrapperDiv.scrollLeft + scrollOffset < maxRightScroll) { this._tabControl.scrollTo(wrapperDiv.scrollLeft + scrollOffset); } else { this._scrolling = false; this._tabControl.scrollTo(maxRightScroll); this._tabControl.updateScrollButtons(); return; } } scrollLength -= scrollOffset; var scrollButton = this; setTimeout(function() { scrollButton._doAnimateScroll(scrollLength, maxRightScroll);}, 3); } else { this._scrolling = false; this._tabControl.updateScrollButtons(); } }; CognosScrollButton.prototype.isIE = function() { return (navigator.userAgent.indexOf('MSIE') != -1 || navigator.userAgent.indexOf('Trident') != -1); }; CognosScrollButton.prototype.render = function(parentNode) { this._scrollButtonDiv = document.createElement("div"); this._scrollButtonDiv.className = "ct_scrollButton"; var offset = -1; if (this.isIE() && document.compatMode != 'CSS1Compat') { // Only needed until we support standards mode. Once we do this work-around for // proper alignment can be removed offset = 1; } this._scrollButtonDiv.style.height = this._height + offset + "px"; if (this._tabControl.isHighContrast()) { this._scrollButtonDiv.innerHTML = this._direction == "left" ? "«" : "»"; } this._outerDiv = document.createElement("div"); this._outerDiv.className = "ct_scrollDisabled"; this._outerDiv.appendChild(this._scrollButtonDiv); this._outerDiv.style.height = this._height + "px"; var scrollButton = this; this._outerDiv.onclick = function() {scrollButton.scroll();}; this._wrapperDiv = document.createElement("div"); this._wrapperDiv.style.height = this._height + "px"; this._wrapperDiv.className = "ct_scroll " + (this._direction == "left" ? "ct_left" : "ct_right") + (this._tabControl.isHighContrast() ? " a11y" : ""); this._wrapperDiv.appendChild(this._outerDiv); if (this._direction == "left") { parentNode.insertBefore(this._wrapperDiv, parentNode.firstChild); this._wrapperDiv.style.left = "0px"; } else { parentNode.appendChild(this._wrapperDiv); this._wrapperDiv.style.right = "0px"; } };