/* *+------------------------------------------------------------------------+ *| Licensed Materials - Property of IBM *| BI and PM: prmt *| (C) Copyright IBM Corp. 2002, 2017 *| *| US Government Users Restricted Rights - Use, duplication or *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *| *+------------------------------------------------------------------------+ */ //IOS TREE CONTROL: We subclass the tree class to handle the fact that iOS' Voiceover intercepts key events and doesn't support some aria attributes // oPane: the HTML element where the tree will be rendered // oSubmit: the form control to submit selections to the server // bRequired: is this a required field [true|false] // bMultiSelect: can the user pick more than one value [true|false] // sRef: the name of this object // oImgTest: the image object used for validation handling // oErrorFeedback: object used to provide validation feedback // sCVId // sStyle // sTextDir // sPromptName: the name of the prompt associated with the tree. This is used as a cache key prefix CInnerTreeIOS.prototype = new CInnerTree; function CInnerTreeIOS(oPane, oSubmit, bRequired, bMultiSelect, sRef, oImgTest, oErrorFeedback, sCVId, sStyle, sTextDir, sPromptName, oPromptControl) { CInnerTree.call(this, oPane, oSubmit, bRequired, bMultiSelect, sRef, oImgTest, oErrorFeedback, sCVId, sStyle, sTextDir, sPromptName, oPromptControl); if(this.m_sDirection != "RTL") // Mobile iOS a11y: Remove the expando image from the read order { this.m_oToggleIMG.setAttribute("role", "presentation"); } } // * CInnerTree.prototype = new CPromptControl(); // Set this to the tree's parameter name if this is a prompt control tree // getPromptValues OM function will be called automatically if this is a prompting tree CInnerTreeIOS.prototype.drawLoading = function(node, nodeId) { var theElement = document.getElementById(nodeId); if (!theElement && node.getNodeType() == TREE_ROOT && this.getRootNodeShowing() == false) { theElement = this.m_oPane; } if (theElement != null) { var newDivContainer = document.createElement("DIV"); newDivContainer.className = CLS_TREE_LEVEL; newDivContainer.id = this.getName() + node.getTreeRef() + "loading"; newDivContainer.style.width = "100%"; var newNobrContainer = document.createElement("NOBR"); this.drawTreeLines(node, newNobrContainer, node.getLevel() + 1); if (!(node.getNodeType() == TREE_ROOT && node.getTree().getRootNodeShowing() == false && node.getMoreData() != true)) { var newLIcon = document.createElement("IMG"); newLIcon.align = gsCTREE_middle; newLIcon.src = (this.m_sDirection == "RTL" ? TREE_L_ONLY_RTL : TREE_L_ONLY); //mobile a11y if(this.m_sDirection != "RTL") { newLIcon.setAttribute("role", "presentation"); } newNobrContainer.appendChild(newLIcon); } var newStateIcon = document.createElement("IMG"); newStateIcon.align = gsCTREE_middle; newStateIcon.src = TREE_LOADING; newNobrContainer.appendChild(newStateIcon); var newLabelContainer = document.createElement("SPAN"); newLabelContainer.className = CLS_TREE_NODE_UNSELECTED + K_PRMT_sSP + CLS_TREE_TEXT; //We need the localized string for "Loading..." here if (typeof PMT_TRE_TREE_LOADING != K_PRMT_sUNDEFINED) { var newStateText = document.createTextNode(PMT_TRE_TREE_LOADING); newLabelContainer.appendChild(newStateText); newLabelContainer.title = PMT_TRE_TREE_LOADING; } newNobrContainer.appendChild(newLabelContainer); newDivContainer.appendChild(newNobrContainer); theElement.appendChild(newDivContainer); } }; CInnerTreeIOS.prototype.drawMoreData = function(node, nodeId) { var theElement = document.getElementById(nodeId); if (!theElement && node.getNodeType() == TREE_ROOT && this.getRootNodeShowing() == false) { theElement = this.m_oPane; } var childrenContainer = (theElement.getAttribute("role") == "tree"? theElement : theElement.firstChild.nextSibling); if (theElement != null && childrenContainer != null && (childrenContainer.getAttribute("role") == "group" || childrenContainer.getAttribute("role") == "tree")) { var newDivContainer = document.createElement("DIV"); newDivContainer.className = CLS_TREE_LEVEL; newDivContainer.id = this.getName() + node.getTreeRef() + "moredata"; newDivContainer.style.width = "100%"; var newNobrContainer = document.createElement("NOBR"); this.drawTreeLines(node, newNobrContainer, node.getLevel() + 1); var newLIcon = document.createElement("IMG"); newLIcon.align = gsCTREE_middle; newLIcon.src = (this.m_sDirection == "RTL" ? TREE_L_ONLY_RTL : TREE_L_ONLY); //mobile a11y if(this.m_sDirection != "RTL") { newLIcon.setAttribute("role", "presentation"); } newNobrContainer.appendChild(newLIcon); var newStateIcon = document.createElement("IMG"); newStateIcon.align = gsCTREE_middle; newStateIcon.src = TREE_MORE_DATA; newStateIcon.setAttribute("role", "presentation"); newNobrContainer.appendChild(newStateIcon); var newLabelContainer = document.createElement("SPAN"); newLabelContainer.className = CLS_TREE_NODE_UNSELECTED + K_PRMT_sSP + CLS_TREE_TEXT_LINK; //We need the localized string for "More" here if (typeof PMT_TRE_MORE != K_PRMT_sUNDEFINED) { var newStateText = document.createTextNode(PMT_TRE_MORE); newLabelContainer.appendChild(newStateText); newLabelContainer.title = PMT_TRE_MORE; } newLabelContainer.id = this.getName() + node.getTreeRef() + "moredatalabel"; newLabelContainer.setAttribute(gsCTREE_tree, this.getName()); newLabelContainer.setAttribute(gsCTREE_treeRef, node.getTreeRef()); newLabelContainer.tabIndex = 0; PRMTUtils.f_addEvent(newLabelContainer, "click", getMoreDataForTreeNode); PRMTUtils.f_addEvent(newLabelContainer, "keydown", getMoreDataForTreeNode); PRMTUtils.f_addEvent(newLabelContainer, "keypress", getMoreDataForTreeNode); newNobrContainer.appendChild(newLabelContainer); newDivContainer.appendChild(newNobrContainer); childrenContainer.appendChild(newDivContainer); } }; CInnerTreeIOS.prototype.draw = function(node, oParentElement) { if (node.getTree().getDisabled() == true) { return false; } var treeRef = node.getTreeRef(); var treeName = this.getName(); //if the node is the root node, removes the old root node so that the entire tree is redrawn //this takes care of the case where a loading tree is replaced with real data if (node.getNodeType() == TREE_ROOT) { var rootNode = document.getElementById(treeName); if (rootNode != null) { oParentElement.removeChild(rootNode); } oParentElement.setAttribute(gsCTREE_treeRef, treeRef); oParentElement.setAttribute(gsCTREE_tree, treeName); } // clone outer container DIV (it's much faster than create a new one) var nodeElement = this.m_oDIVnewElement.cloneNode(true); PRMTUtils.f_addEvent( nodeElement, "dragstart", dragStartOnNode ); PRMTUtils.f_addEvent( nodeElement, "drag", dragOnNode ); PRMTUtils.f_addEvent( nodeElement, "dragend", dragEndOnNode ); nodeElement.setAttribute(gsCTREE_treeRef, treeRef); nodeElement.setAttribute(gsCTREE_tree, treeName); if (treeRef == K_PRMT_sEMPTY) { nodeElement.setAttribute(K_PRMT_ARIA_ROLE, "listbox"); } nodeElement.id = treeName + treeRef; if (!(node.getNodeType() == TREE_ROOT && this.getRootNodeShowing() == false)) { this.drawNode(node, nodeElement); } // ****************************************************************** // deal with children // ****************************************************************** oParentElement.appendChild(nodeElement); this.drawNodeChildren (node, nodeElement); this.m_bHasBeenDrawn = true; }; CInnerTreeIOS.prototype.detailToogleIcon = function(node, newToggleIcon) { // text for high contrast var newToggleText = this.m_oTextSPAN.cloneNode(true); newToggleText.className= K_PRMT_TREE_TOGGLE_TEXT; newToggleText.setAttribute(K_PRMT_ARIA_ROLE, K_PRMT_ARIA_ROLE_PRESENTATION); var toggleTextContent = ""; if (node.canHaveChildren() == true) { newToggleIcon.setAttribute("aria-labelledby", node.id); if (node.isOpen() == true) { newToggleIcon.className = K_PRMT_TREE_TOGGLE_OPENED + this.m_sDirection; newToggleIcon.title = PMT_TRE_COLLAPSE; newToggleIcon.alt = PMT_TRE_COLLAPSE; //newToggleIcon.setAttribute(K_PRMT_TREE_STATE_EXPANDED, true); toggleTextContent = "-"; } else { newToggleIcon.className= K_PRMT_TREE_TOGGLE_CLOSED + this.m_sDirection; newToggleIcon.title = PMT_TRE_EXPAND; newToggleIcon.alt = PMT_TRE_EXPAND; toggleTextContent = "+"; } newToggleIcon.tabIndex = -1; newToggleIcon.onclick = this.toggle; newToggleText.onclick = this.toggle; } else { newToggleIcon.className= K_PRMT_TREE_TOGGLE_LEAF; newToggleIcon.src = PROMT_IMAGES + "blank.gif"; newToggleIcon.alt = ""; newToggleIcon.onclick = null; newToggleIcon.removeAttribute("aria-labelledby"); newToggleIcon.removeAttribute("title"); newToggleIcon.removeAttribute("tabindex"); } var toggleTextNode= document.createTextNode(toggleTextContent); newToggleText.appendChild(toggleTextNode); newToggleIcon.setAttribute(gsCTREE_treeRef, gsCTREE_img); return [newToggleIcon, newToggleText]; }; /** * Draws the checkbox * */ CInnerTreeIOS.prototype.drawNodeCheckboxIcon = function(node) { var checkBoxIcon = CInnerTree.prototype.drawNodeCheckboxIcon.call(this, node); checkBoxIcon.setAttribute("aria-hidden", "true"); return checkBoxIcon; }; /** * Draws the label Node label * */ CInnerTreeIOS.prototype.drawNodeLabel = function(node, treeName, treeRef) { var nodeElementLabelContainer = this.m_oLabelSPAN.cloneNode(true); nodeElementLabelContainer.id = treeName + treeRef + gsCTREE_labelText; this.updateLabelClass(nodeElementLabelContainer, getClassName(node, this), node); nodeElementLabelContainer.setAttribute(gsCTREE_treeRef, treeRef); nodeElementLabelContainer.setAttribute(gsCTREE_dragRef, treeRef.toString()); nodeElementLabelContainer.setAttribute(gsCTREE_dragTree, treeName); nodeElementLabelContainer.setAttribute(gsCTREE_tree, treeName); node.m_oLabelText = nodeElementLabelContainer; if (node.isFirst()) { nodeElementLabelContainer.tabIndex = 0; this.m_lastFocus = nodeElementLabelContainer; } var labelText = document.createTextNode( G_IsBidiEnabled && this.m_sTextDir ? PRMT_BidiUtils.enforceBidiDirection(node.getName(), this.m_sTextDir) : node.getName() ); nodeElementLabelContainer.appendChild(labelText); var sStyle = this.getStyle(); nodeElementLabelContainer.style.color= cssParser(sStyle,"color",true); nodeElementLabelContainer.style.backgroundColor= cssParser(sStyle,"background-color",true); nodeElementLabelContainer.style.fontFamily= cssParser(sStyle,"font-family",true); nodeElementLabelContainer.style.fontSize= cssParser(sStyle,"font-size",true); nodeElementLabelContainer.style.fontWeight= cssParser(sStyle,"font-weight",true); nodeElementLabelContainer.style.fontStyle= cssParser(sStyle,"font-style",true); nodeElementLabelContainer.style.fontVariant= cssParser(sStyle,"font-variant",true); nodeElementLabelContainer.style.textAlign= cssParser(sStyle,"text-align",true); nodeElementLabelContainer.style.textVariant= cssParser(sStyle,"text-variant",true); nodeElementLabelContainer.style.textIndent= cssParser(sStyle,"text-indent",true); nodeElementLabelContainer.style.textTransform= cssParser(sStyle,"text-transform",true); nodeElementLabelContainer.setAttribute(gsCTREE_treeRef, treeRef); nodeElementLabelContainer.setAttribute(gsCTREE_dragRef, treeRef.toString()); nodeElementLabelContainer.setAttribute(gsCTREE_dragTree, treeName); nodeElementLabelContainer.setAttribute(gsCTREE_tree, treeName); nodeElementLabelContainer.setAttribute("onfocus","this.classname='" + CLS_TREE_NODE_HOVER + " " + CLS_TREE_TEXT + "';"); nodeElementLabelContainer.setAttribute("onblur","this.classname='" + CLS_TREE_NODE_UNSELECTED + " " + CLS_TREE_TEXT + "';"); return nodeElementLabelContainer; }; /** * Process event from click in Toggle icon */ CInnerTreeIOS.prototype.toggle = function(evt, uiNode) { //get the event in a cross-browser fashion evt = (evt) ? evt : ((event) ? event : null); //cancel any text selection clearSelection(); //prevent the event from bubbling to other elements PRMTUtils.F_StopEvent(evt); //get UI Node uiNode = (uiNode? getUINode(null, uiNode) : getUINode(evt)); var uiNodeTreeRef = uiNode.getAttribute(gsCTREE_treeRef).toString(); //get the tree object var tree = uiNode.getAttribute(gsCTREE_tree).toString(); //get tree Node var node = getTreeNode(tree, uiNodeTreeRef); var v_oTree = node.getTree(); if (v_oTree && v_oTree.canToggleNode(node)) { v_oTree.toggleExpandCollapse(uiNode, node, 0); } }; CInnerTreeIOS.prototype.toggleExpandCollapse = function(uiNode, node, toggleDirection) { var result = false; var tree = uiNode.getAttribute(gsCTREE_tree).toString(); //toggle folders var isExpanded = null; if ( node.isClosed() && toggleDirection != K_PRMT_TREE_COLLAPSE ) { isExpanded = true; this.expandNode(uiNode, node); result = true; } else if ( (node.isOpen()) && toggleDirection != K_PRMT_TREE_EXPAND ) { isExpanded = false; this.collapseNode(uiNode, node); result = true; } if (isExpanded){ this.setCacheValue(this.getExpandedNodeCacheKey(node), "true"); }else{ this.removeCacheValue(this.getExpandedNodeCacheKey(node)); } updateToggleIcon(node, tree); // update aria-expanded if ( isExpanded != null ) { this.updateAriaLabelContainer(node, tree, isExpanded); } return result; }; /** * Update the label container aria-expanded attribute */ CInnerTreeIOS.prototype.updateAriaLabelContainer = function(oNode, sTreeName, ariaExpanded) { var labelContainer = document.getElementById(sTreeName + oNode.getTreeRef() + gsCTREE_labelText); if (labelContainer && oNode.canHaveChildren()) { labelContainer.setAttribute(K_PRMT_TREE_STATE_EXPANDED, ariaExpanded); } else if(!oNode.canHaveChildren()) { oNode.removeAttribute(K_PRMT_TREE_STATE_EXPANDED); } };