/* *+------------------------------------------------------------------------+ *| Licensed Materials - Property of IBM *| IBM Cognos Products: Viewer *| (C) Copyright IBM Corp. 2001, 2014 *| *| US Government Users Restricted Rights - Use, duplication or *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *| *+------------------------------------------------------------------------+ */ function ViewerA11YHelper(oCV) { this.m_oCV = oCV; } ViewerA11YHelper.prototype.onFocus = function(evt) { var targetNode = getCrossBrowserNode(evt); targetNode = ViewerA11YHelper.findChildOfTableCell(targetNode); this.updateCellAccessibility(targetNode, false); }; ViewerA11YHelper.prototype.onKeyDown = function(evt) { //get the event in a cross-browser fashion evt = (evt) ? evt : ((event) ? event : null); var srcNode = getCrossBrowserNode(evt); // In IE, if the user clicked on the white space instead of the text in a cell, the srcNode // will point to the TD or TH. Get the span within the TD or TH if (ViewerA11YHelper.isTableCell(srcNode)) { for (var i=0; i < srcNode.childNodes.length; i++) { if (srcNode.childNodes[i].nodeName.toLowerCase() == "span") { srcNode = srcNode.childNodes[i]; break; } } } // if the event didn't come from an element we'd select then let it bubble up if (!this.isValidNodeToSelect(srcNode)) { return true; } srcNode = ViewerA11YHelper.findChildOfTableCell(srcNode); if (srcNode) { if (evt.keyCode == "39") { // right arrow if (this.m_oCV.getState() && this.m_oCV.getState().getFindState() && evt.ctrlKey && evt.shiftKey ) { // Ctrl+Shilf+ right arrow this.m_oCV.executeAction("FindNext"); } else { this.moveRight(srcNode); } return stopEventBubble(evt); } else if (evt.keyCode == "37") { // left arrow this.moveLeft(srcNode); return stopEventBubble(evt); } else if (evt.keyCode == "38") { // up arrow this.moveUp(srcNode); return stopEventBubble(evt); } else if (evt.keyCode == "40") { // down arrow this.moveDown(srcNode); return stopEventBubble(evt); } else if (evt.keyCode == "13") { // enter if (this.m_oCV.isBux) { if( this.m_oCV.getViewerWidget().isSelectionFilterEnabled() ){ this.m_oCV.getViewerWidget().preprocessPageClicked( false /*invokingContextMenu*/, evt); if( this.m_oCV.getSelectionController().pageClicked(evt) !== false ){ this.m_oCV.JAWSTalk( RV_RES.IDS_JS_SELECTION_FILTER_INFO_JAWS ); this.m_oCV.getViewerWidget().updateToolbar(); } } else { this.m_oCV.getSelectionController().pageClicked(evt); var selectionAction = this.m_oCV.getActionFactory().load("Selection"); selectionAction.onKeyDown(evt); } this.m_oCV.getViewerWidget().onSelectionChange(); } else { this.m_oCV.de(evt); } } else if (evt.keyCode == "32") { // space if( this.m_oCV.isBux ) { this.m_oCV.getViewerWidget().preprocessPageClicked( false /*invokingContextMenu*/); if( this.m_oCV.getSelectionController().pageClicked(evt) !== false && this.m_oCV.getViewerWidget().isSelectionFilterEnabled() ) { this.m_oCV.JAWSTalk( RV_RES.IDS_JS_SELECTION_FILTER_INFO_JAWS ); } this.m_oCV.getViewerWidget().updateToolbar(); this.m_oCV.getViewerWidget().onSelectionChange(); } else { this.m_oCV.getSelectionController().pageClicked(evt); } return stopEventBubble(evt); } else if(evt.keyCode == "46" && this.m_oCV.isBux) { // delete key if (typeof this.m_oCV.envParams != "undefined" && typeof this.m_oCV.envParams["ui.action"] != "undefined" && this.m_oCV.envParams["ui.action"] != "view" && !this.m_oCV.isLimitedInteractiveMode()) { var deleteAction = this.m_oCV.getActionFactory().load("Delete"); if(!this.m_oCV.isBlacklisted("Delete") && deleteAction.canDelete()) { deleteAction.execute(); return stopEventBubble(evt); } } } else if (this.m_oCV.isBux && evt.ctrlKey == true && evt.shiftKey == true && evt.keyCode == "49") { // Ctrl + shift + ! var lid = this.m_oCV.getSelectionController().getSelectionObjectFactory().getLayoutElementId(srcNode); if (lid != "") { // get the lid without the Viewer id appended to it. lid = lid.split(this.m_oCV.getId())[0]; var containerIdx = -1; var oRAPReportInfo = this.m_oCV.getRAPReportInfo(); if (oRAPReportInfo) { var container = oRAPReportInfo.getContainer(lid); if (typeof container.layoutIndex != "undefined") { containerIdx = container.layoutIndex; } } var infoBarHeaderButton = document.getElementById("infoBarHeaderButton" + containerIdx + this.m_oCV.getId()); if (infoBarHeaderButton !== null) { this.m_oCV.setCurrentNodeFocus(getCrossBrowserNode(evt)); infoBarHeaderButton.focus(); } } return stopEventBubble(evt); } else if (!this.m_oCV.isBux && evt.shiftKey == true && evt.keyCode == "121") { // Shift - F10 (context menu) -- standalone viewer //Only cover Shift + F10. Menu button is already covered by the body's onContextMenu callback. var ocv = this.m_oCV; var openContextMenu = function() { //Some browsers don't populate the evt.clientX/Y fields on keyboard //events, which the display content menu function requires. if (typeof evt.clientX == "undefined" || typeof evt.clientY == "undefined") { var coords = clientToScreenCoords(evt.target, document.body); evt.clientX = coords.leftCoord; evt.clientY = coords.topCoord; } ocv.dcm(evt, true); }; if(isFF()) { //In FF, need to invoke this code after this thread's execution is done. setTimeout(openContextMenu, 0); } else { //Other browsers, should invoke right away //(Espcially IE, where evt's state is cleared after) openContextMenu.call(); } //Swallow event so browser's context menu is not shown return stopEventBubble(evt); } else if (this.m_oCV.isBux && (evt.keyCode == "93" || (evt.shiftKey == true && evt.keyCode == "121"))) { // Shift - F10 / menu button (context menu) -- BUX var viewerWidget = this.m_oCV.getViewerWidget(); var selectionController = this.m_oCV.getSelectionController(); viewerWidget.preprocessPageClicked( true /*invokingContextMenu*/); selectionController.pageClicked(evt); viewerWidget.updateToolbar(); viewerWidget.onContextMenu(evt); } } }; ViewerA11YHelper.prototype.isValidNodeToSelect = function(node) { return this.getValidNodeToSelect(node) ? true : false; }; ViewerA11YHelper.prototype.getValidNodeToSelect = function(node) { if (node && node.style && node.style.visibility != "hidden" && node.style.display != "none") { var sNodeName = node.nodeName.toLowerCase(); if ( (sNodeName == "span" && (!node.getAttribute("class") || node.getAttribute("class").indexOf("expandButton") === -1)) || (sNodeName == "div" && node.getAttribute("flashchartcontainer") == "true") || (sNodeName == "div" && node.getAttribute("chartcontainer") == "true") || (sNodeName == "img" && (!node.id || node.id.indexOf("sortimg") !== 0 )) ) { return node; } if (ViewerA11YHelper.isSemanticNode(node)) { var child = node.childNodes && node.childNodes.length ? node.childNodes[0] : null; if(child) { return this.getValidNodeToSelect(child); } } } return null; }; ViewerA11YHelper.isSemanticNode = function(node) { if(!ViewerA11YHelper.isSemanticNode._semanticNodeNames) { ViewerA11YHelper.isSemanticNode._semanticNodeNames = [ "strong", "em", "h1", "h2", "h3", "h4", "h5", "h6" ]; } var sNodeName = node.nodeName.toLowerCase(); for(var i = 0; i < ViewerA11YHelper.isSemanticNode._semanticNodeNames.length; i++) { if(sNodeName === ViewerA11YHelper.isSemanticNode._semanticNodeNames[i]) { return true; } } return false; }; ViewerA11YHelper.isTableCell = function(node) { var sNodeName = node.nodeName.toLowerCase(); return sNodeName === "td" || sNodeName === "th"; }; ViewerA11YHelper.findChildOfTableCell = function(startNode) { var srcNode = startNode; while(srcNode && srcNode.parentNode) { if (ViewerA11YHelper.getTableCell(srcNode)) { break; } srcNode = srcNode.parentNode; } return srcNode; }; ViewerA11YHelper.getTableCell = function(node) { var parent = node.parentNode; if(ViewerA11YHelper.isTableCell(parent)) { return parent; } //Treat a semantic node under the as parent of the if (ViewerA11YHelper.isSemanticNode(parent) && ViewerA11YHelper.isTableCell(parent.parentNode)) { return parent.parentNode; } return null; }; ViewerA11YHelper.prototype.moveRight = function(srcNode) { var nextNode = this.getNextNonTextSibling(srcNode); nextNode = this.getValidNodeToSelect(nextNode); // case where we have multiple spans inside a td if (nextNode) { this.setFocusToNode(nextNode); return true; } var tdNode = ViewerA11YHelper.getTableCell(srcNode); tdNode = this.getPfMainOutputCell(tdNode); while (tdNode.nextSibling) { if (this.moveToTD(tdNode.nextSibling)) { return true; } tdNode = tdNode.nextSibling; } var trNode = tdNode.parentNode; while (trNode.nextSibling) { var nextTR = trNode.nextSibling; if (this.moveToTD(nextTR.childNodes[0])) { return true; } trNode = trNode.nextSibling; } return false; }; ViewerA11YHelper.prototype.moveLeft = function(srcNode) { var previousNode = this.getPreviousNonTextSibling(srcNode); previousNode = this.getValidNodeToSelect(previousNode); // case where we have multiple spans inside a td if (previousNode) { this.setFocusToNode(previousNode); return true; } var tdNode = ViewerA11YHelper.getTableCell(srcNode); tdNode = this.getPfMainOutputCell(tdNode); while (tdNode.previousSibling) { if (this.moveToTDFromTheRight(tdNode.previousSibling)) { return true; } tdNode = tdNode.previousSibling; } var trNode = tdNode.parentNode; while (trNode.previousSibling) { var previousTR = trNode.previousSibling; if (this.moveToTDFromTheRight(previousTR.lastChild)) { return true; } trNode = trNode.previousSibling; } return false; }; ViewerA11YHelper.prototype.moveDown = function(srcNode) { var tdNode = ViewerA11YHelper.getTableCell(srcNode); tdNode = this.getPfMainOutputCell(tdNode); var srcColSpan = this.getColumnIndex(tdNode); srcColSpan += this.getColSpanFromRowSpans(tdNode); // if the current node has a rowSpan, we need to jump over a bunch of TR's var trNode = tdNode.parentNode; if (tdNode.rowSpan && tdNode.rowSpan > 1) { var nodeRowSpan = tdNode.rowSpan; for (var rowSpanIndex=1; rowSpanIndex < nodeRowSpan; rowSpanIndex++) { trNode = trNode.nextSibling; } } var bTriedNextColumn = false; while(trNode) { if (trNode.nextSibling) { // get the next TR trNode = trNode.nextSibling; } else if (tdNode.nextSibling && !bTriedNextColumn) { // move to the next column trNode = trNode.parentNode.firstChild; bTriedNextColumn = true; srcColSpan++; } else { // last span is selected return false; } if (this.doMoveUpDown(trNode, srcColSpan)) { return true; } } return false; }; ViewerA11YHelper.prototype.moveUp = function(srcNode) { var tdNode = ViewerA11YHelper.getTableCell(srcNode); tdNode = this.getPfMainOutputCell(tdNode); var trNode = tdNode.parentNode; var srcColSpan = this.getColumnIndex(tdNode); srcColSpan += this.getColSpanFromRowSpans(tdNode); var bTriedPreviousColumn = false; while(trNode) { if (trNode.previousSibling) { // get the next TR trNode = trNode.previousSibling; } else if (tdNode.previousSibling && !bTriedPreviousColumn) { // move to the next column trNode = trNode.parentNode.lastChild; bTriedPreviousColumn = true; srcColSpan--; } else { // last span is selected return false; } if (this.doMoveUpDown(trNode, srcColSpan)) { return true; } } return false; }; ViewerA11YHelper.prototype.getNextNonTextSibling = function(node) { while (node.nextSibling) { node = node.nextSibling; if (node.nodeName.toLowerCase() != '#text') { return node; } } if (ViewerA11YHelper.isSemanticNode(node.parentNode)) { return this.getNextNonTextSibling(node.parentNode); } return null; }; ViewerA11YHelper.prototype.doMoveUpDown = function(trNode, srcColSpan) { if (trNode != null) { var currentColumn = trNode.firstChild; var pos = this.getColSpanFromRowSpans(currentColumn); while (currentColumn) { if (pos == srcColSpan) { return this.moveToTDFromTheRight(currentColumn); } else if (pos > srcColSpan) { break; } var nodeColSpan = 0; if (currentColumn.colSpan) { nodeColSpan = currentColumn.colSpan; } else { nodeColSpan++; } pos += nodeColSpan; currentColumn = currentColumn.nextSibling; } } }; ViewerA11YHelper.prototype.moveToTDFromTheRight = function(td) { td = this.getPfVisibleCell(td); var childNodes = td.childNodes; for (var iChildIndex=childNodes.length-1; iChildIndex >= 0; iChildIndex--) { var node = this.getValidNodeToSelect(childNodes[iChildIndex]); if (node) { // sometimes have a span inside a span if (node.childNodes && node.childNodes[0] && node.childNodes[0].nodeName.toLowerCase() == "span") { node = node.childNodes[0]; } if (node.tabIndex != -1 && node.tabIndex != 0) { node.tabIndex = -1; } this.setFocusToNode(node); return true; } } return false; }; ViewerA11YHelper.prototype.moveToTD = function(td) { td = this.getPfVisibleCell(td); var childNodes = td.childNodes; for (var iChildIndex=0; iChildIndex < childNodes.length; iChildIndex++) { var node = this.getValidNodeToSelect(childNodes[iChildIndex]); if (node) { // sometimes have a span inside a span if (node.childNodes && node.childNodes[0] && node.childNodes[0].nodeName.toLowerCase() == "span") { node = node.childNodes[0]; } if (node.tabIndex != -1 && node.tabIndex != 0) { node.tabIndex = -1; } this.setFocusToNode(node); return true; } } return false; }; ViewerA11YHelper.prototype.setFocusToNode = function(node) { this.m_oCV.setCurrentNodeFocus(node); this.updateCellAccessibility(node, false); node.focus(); if(this.m_oCV.m_pinFreezeManager) { var container = this.m_oCV.m_pinFreezeManager.nodeToContainer(node); if(container) { container.updateScroll(node); } } }; /** * Given an element, return the main it is based on. This may be itself. */ ViewerA11YHelper.prototype.getPfMainOutputCell = function(element) { var main = null var slid = element.getAttribute("pfslid"); if(slid) { var lid = PinFreezeContainer.getLidFromSlid(slid); if(lid && this.m_oCV.m_pinFreezeManager) { lid = this.m_oCV.m_pinFreezeManager.removeNamespace(lid); var container = this.m_oCV.m_pinFreezeManager.getContainer(lid); if(container) { main = container.getMain(element); } } } return main ? main : element; }; ViewerA11YHelper.prototype.getPreviousNonTextSibling = function(node) { while (node.previousSibling) { node = node.previousSibling; if (node.nodeName.toLowerCase() != '#text') { return node; } } if (ViewerA11YHelper.isSemanticNode(node.parentNode)) { return this.getPreviousNonTextSibling(node.parentNode); } return null; }; /** * Returns the column index of the node with all the colspans. * This function excludes any td's that have a rowspan */ ViewerA11YHelper.prototype.getColumnIndex = function(node) { var colIndex = 0; while (node.previousSibling) { node = node.previousSibling; if (node.rowSpan == 1) { if (node.colSpan) { colIndex += node.colSpan; } else { colIndex++; } } } return colIndex; }; /** * Given an element, return the visible copy of it. This may be itself. */ ViewerA11YHelper.prototype.getPfVisibleCell = function(element) { var copy = null; var slid = element.getAttribute("pfslid"); if(slid) { var lid = PinFreezeContainer.getLidFromSlid(slid); if(lid && this.m_oCV.m_pinFreezeManager) { lid = this.m_oCV.m_pinFreezeManager.removeNamespace(lid); var container = this.m_oCV.m_pinFreezeManager.getContainer(lid); if(container) { copy = container.getCopy(element); } } } return copy ? copy : element; }; ViewerA11YHelper.prototype.updateCellAccessibility = function(srcNode, force) { if (!srcNode) { return false; } var canDrillDown = false; var canDrillUp = false; var canDrillThrough = false; var ctxNode = srcNode.getAttribute("ctx") != null ? srcNode : srcNode.parentNode; if (srcNode.getAttribute("flashChartContainer") != "true") { if (ctxNode.getAttribute("ctx") != null) { if (this.m_oCV.isBux) { var action = this.m_oCV.getAction("DrillUpDown"); action.updateDrillability(this.m_oCV, ctxNode); canDrillDown = action.canDrillDown(); canDrillUp = action.canDrillUp(); } else { var ctxAttribute = ctxNode.getAttribute("ctx"); var ctxID = ctxAttribute.indexOf(':') == -1 ? ctxAttribute : ctxAttribute.substring(0, ctxAttribute.indexOf(":")); var selCon = this.m_oCV.getSelectionController(); canDrillDown = selCon.canDrillDown(ctxID); canDrillUp = selCon.canDrillUp(ctxID); } } canDrillThrough = srcNode.parentNode.getAttribute("dtTargets") ? true : false; } var isImage = srcNode.nodeName.toLowerCase() == "img"; var isColumnTitle = srcNode.parentNode.getAttribute("type") == "columnTitle"; if ( !isImage && (force || ((srcNode.getAttribute("aria-labelledby") != null || isColumnTitle || this.m_oCV.isAccessibleMode())))) { var innerHTML = ""; // crosstab corner if (srcNode.parentNode.getAttribute("cc") == "true") { innerHTML += " " + RV_RES.IDS_JS_CROSSTAB_CORNER; } if (srcNode.innerHTML.length === 0) { srcNode.innerHTML = " "; innerHTML += " " + RV_RES.IDS_JS_EMPTY_CELL; } if (canDrillDown && canDrillUp) { innerHTML += " " + RV_RES.IDS_JS_DRILL_DOWN_UP_JAWS; } else if (canDrillDown) { innerHTML += " " + RV_RES.IDS_JS_DRILL_DOWN_JAWS; } else if (canDrillUp) { innerHTML += " " + RV_RES.IDS_JS_DRILL_UP_JAWS; } if (canDrillThrough) { innerHTML += " " + RV_RES.IDS_JS_DRILL_THROUGH_JAWS; } if (srcNode.altText && srcNode.altText.length > 0) { innerHTML = srcNode.altText; } else if (srcNode.getAttribute("flashChartContainer") == "true") { innerHTML = RV_RES.IDS_JS_CHART_IMAGE; } if( this.m_oCV.isBux ) { var sibling = srcNode.previousSibling; if (sibling) { var wid = sibling.getAttribute("widgetid"); if (wid && wid.indexOf("comment")) { innerHTML += " " + RV_RES.IDS_JS_ANNOTATION_JAWS; } } if (srcNode.getAttribute("rp_name") || srcNode.parentNode.getAttribute("rp_name")) { innerHTML += " " + RV_RES.IDS_JS_LABEL_HAS_BEEN_RENAMED; } if (srcNode.nextSibling && srcNode.nextSibling.getAttribute("class") == "sortIconVisible") { innerHTML += " " + srcNode.nextSibling.getAttribute("alt"); } } // is there any extra information that JAWS needs to speak out if (innerHTML.length > 0) { this.addAriaLabelledByOnCell(srcNode, innerHTML); } } if (canDrillUp || canDrillDown || canDrillThrough) { this.addDrillAccessibilityAttributes(srcNode, canDrillThrough); } if(srcNode.attachEvent) { srcNode.attachEvent("onblur", this.onBlur); } else { srcNode.addEventListener("blur", this.onBlur, false); } if ((isIE() && srcNode.getAttribute("tabIndex") != 0) || isImage) { srcNode.setAttribute("modifiedTabIndex", "true"); srcNode.setAttribute("oldTabIndex", srcNode.getAttribute("tabIndex")); srcNode.setAttribute("tabIndex", 0); } }; ViewerA11YHelper.prototype.addAriaLabelledByOnCell = function(srcNode, labelledBy) { // can have multiple spans inside a td, get the position to help make the id unique var srcNodePos = 0; var tempNode = srcNode; while (tempNode.previousSibling) { srcNodePos++; tempNode = tempNode.previousSibling; } var hiddenSpanId = srcNode.getAttribute("ariaHiddenSpanId"); // if we already have a hidden span, use it if (hiddenSpanId && document.getElementById(hiddenSpanId)) { document.getElementById(hiddenSpanId).innerHTML = labelledBy; } else { if (!srcNode.parentNode.id && !srcNode.id) { srcNode.parentNode.id = Math.random(); } var newSpan = document.createElement("span"); newSpan.style.visibility = "hidden"; newSpan.style.display = "none"; newSpan.id = (srcNode.id == "" ? srcNode.parentNode.id : srcNode.id) + "_" + srcNodePos; newSpan.innerHTML = labelledBy; srcNode.parentNode.appendChild(newSpan); var ariaLabelledBy = ""; if (srcNode.getAttribute("aria-labelledby") != null) { ariaLabelledBy += srcNode.getAttribute("aria-labelledby"); } else { if (srcNode.id == "") { srcNode.id = srcNode.parentNode.id + "_main_" + srcNodePos; } ariaLabelledBy += srcNode.id; } ariaLabelledBy += " " + newSpan.id; srcNode.setAttribute("aria-labelledby", ariaLabelledBy); srcNode.setAttribute("ariaHiddenSpanId", newSpan.id); } }; ViewerA11YHelper.prototype.addDrillAccessibilityAttributes = function(srcNode, canDrillThrough) { if (!srcNode.getAttribute("oldClassName")) { // drill throughs already have a link if (!canDrillThrough) { srcNode.setAttribute("oldClassName", srcNode.className); srcNode.className = "dl " + srcNode.className; } if (!srcNode.getAttribute("role")) { srcNode.setAttribute("role", "link"); } } }; ViewerA11YHelper.prototype.onBlur = function(evt) { var srcNode = null; if(isIE()) { srcNode = getNodeFromEvent(evt, true); } else { srcNode = this; } srcNode = ViewerA11YHelper.findChildOfTableCell(srcNode); if (srcNode) { if (srcNode.getAttribute("oldClassName")) { srcNode.className = srcNode.getAttribute("oldClassName"); srcNode.removeAttribute("oldClassName"); } if (srcNode.getAttribute("modifiedTabIndex") == "true") { srcNode.removeAttribute("modifiedTabIndex"); srcNode.removeAttribute("tabIndex"); if (srcNode.getAttribute("oldTabIndex")) { srcNode.setAttribute("tabIndex", srcNode.getAttribute("oldTabIndex")); } srcNode.removeAttribute("oldTabIndex"); } // blank out any extra info for JAWS when we leave the cell. var ariaSpanId = srcNode.getAttribute("ariaHiddenSpanId"); if (ariaSpanId) { var ariaSpanEle = document.getElementById(ariaSpanId); if (ariaSpanEle) { ariaSpanEle.innerHTML = ""; } } } }; /** * Method that walks the tree from the given TD and calculates * the colspans that are from TD's with rowspan's on them */ ViewerA11YHelper.prototype.getColSpanFromRowSpans = function(tdNode) { var nodeColSpan = 0; var trNode = tdNode.parentNode; var trChildCount = 0; while (trNode) { var rowChildNode = trNode.firstChild; // if there's a diff in the #of columns, we must of found a new TD with a rowspan var colCountDiff = this.getColumnCount(trNode) - trChildCount; while (rowChildNode && rowChildNode.rowSpan > 1 && colCountDiff > 0 && rowChildNode != tdNode) { nodeColSpan += rowChildNode.colSpan; rowChildNode = rowChildNode.nextSibling; colCountDiff--; } // never decrease the column count, only increase it if (trNode.childNodes.length > trChildCount) { trChildCount = this.getColumnCount(trNode); } // get the previous TR.. keep walking the DOM trNode = trNode.previousSibling; } return nodeColSpan; }; /** * Gets the column count for the given TR which includes all the colspans */ ViewerA11YHelper.prototype.getColumnCount = function(trNode) { var columnCount = 0; var node = trNode.firstChild; while (node) { columnCount += node.colSpan; node = node.nextSibling; } return columnCount; }; /** * Sets up the aria labelledBy for cells outside of a data container (list/crosstab) */ ViewerA11YHelper.prototype.addLabelledByForItemsOutsideOfContainers = function() { // Only needs to be done when accesibility preference is set if (!this.m_oCV.isAccessibleMode()) { return; } var content = document.getElementById("RVContent" + this.m_oCV.getId()); if (!content) { return; } // Get all the spans that have a tabinex of 0. This should be a small list var focusableSpans = getElementsByAttribute(content, "span", "tabindex", "0"); if (!focusableSpans) { return; } for (var i=0; i < focusableSpans.length; i++) { var span = focusableSpans[i]; this.updateCellAccessibility(span, false); } };