Package inexp.waiaria

Source Code of inexp.waiaria.WAIARIADocument

package inexp.waiaria;

import org.itsnat.core.ItsNatNode;
import org.itsnat.core.event.ItsNatKeyEvent;
import org.itsnat.core.html.ItsNatHTMLDocument;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.events.MouseEvent;
import org.w3c.dom.html.HTMLDocument;
import org.w3c.dom.html.HTMLImageElement;

/**
*
* @author jmarranz
*/
public class WAIARIADocument implements EventListener
{
    private final static String ROLE_TREEITEM = "treeitem";
    private final static String ROLE_TREE = "tree";
    private final static String ROLE_GROUP = "group";
    private final static String STATE_EXPANDED = "aria-expanded";

    private final static short KEY_ENTER=0x0D;
    private final static short KEY_END = 0x23;
    private final static short KEY_HOME = 0x24;
    private final static short KEY_LEFT = 0x25;
    private final static short KEY_UP = 0x26;
    private final static short KEY_RIGHT = 0x27;
    private final static short KEY_DOWN = 0x28;

    private final static String COLLAPSE = "waiaria/img/minus.gif";
    private final static String EXPAND= "waiaria/img/plus.gif";
   
    protected ItsNatHTMLDocument itsNatDoc;
    protected Element treeElem;

    public WAIARIADocument(ItsNatHTMLDocument itsNatDoc)
    {
        this.itsNatDoc = itsNatDoc;

        HTMLDocument doc = itsNatDoc.getHTMLDocument();
        this.treeElem = doc.getElementById("tree");
        ((EventTarget)treeElem).addEventListener("click", this, false);
        ((EventTarget)treeElem).addEventListener("dblclick", this, false);
        ((EventTarget)treeElem).addEventListener("keydown", this, false);
        ((EventTarget)treeElem).addEventListener("keypress", this, false);
    }

    public void handleEvent(Event evt)
    {
        String type = evt.getType();
        if (type.equals("click"))
        {
            if (evt.getTarget() instanceof HTMLImageElement)
                imgToggle(evt);
           
            if (!treeItemClick(evt))
                evt.preventDefault();
        }
        else if (type.equals("dblclick") || type.equals("keydown") || type.equals("keypress"))
        {
            if (!treeItemEvent(evt))
                evt.preventDefault();
        }

    }

    public EventTarget getTarget(Event event) {
      return event.getTarget();
    }   

    public void debugOut(String debugStr)
    {
        itsNatDoc.addCodeToSend("alert('" + debugStr + "');");
    }
   
    public Node getTree(Node treeItem)
    {
      Node tree = treeItem;
      try
      {

        while (!getRole(tree).equals(ROLE_TREE))
        {
              tree = tree.getParentNode();
        }
      }
      catch(Exception ex)
      {
        debugOut("error in getTree(); " + ex.getMessage());
        return null; // No tree container for tree item
      }
      return tree;
    }

    public String getRole(Node node)
    {
        if (!(node instanceof Element)) return "";
      try
      {
        return ((Element)node).getAttribute("role");
      }
      catch(Exception ex)
      {
        return "";
      }
    }

    public boolean isText(Node node)
    {
        return (node != null) && node.getNodeType() == Node.TEXT_NODE;
    }

    public boolean isValidTreeItem(Node treeItem)
    {
        boolean bIsTreeItem = false;
        Node testItem = treeItem;

        if (isText(testItem))
        {
            testItem = testItem.getNextSibling();
        }

        if (getRole(testItem).equals(ROLE_TREEITEM) )
        {
            bIsTreeItem = true;
        }

        return bIsTreeItem;
    }

    public Node getFirstTreeItem(Node tree)
    {
      Node first = tree.getFirstChild();
      Node treeItem = null;
      // FF reports firstChild as text node while IE does not
      while ( (first!=null) && isText(first) ) {
        first = first.getNextSibling()// tree had better have a child that is not text!
      }
      if ((first!=null) && first.hasChildNodes()) {
          for (int i=0; i<first.getChildNodes().getLength(); i++) {
          if (getRole(first.getChildNodes().item(i)).equals(ROLE_TREEITEM)) {
            treeItem = first.getChildNodes().item(i);
            break;
          }
        }
      }
      return treeItem;
    }

    public void setFocus(Node newFocus)
    {
      if (newFocus != null) {
            String ref = itsNatDoc.getScriptUtil().getNodeReference(newFocus);
            StringBuilder code = new StringBuilder();
            code.append("gNewFocus = " + ref + ";")// must store in a global variable so object is available when setTimeout occurs.
            code.append("setTimeout('gNewFocus.focus();', 0);");
            itsNatDoc.addCodeToSend(code);
      }
    }

    public void treeItemFocus(Element treeItem, boolean bFocus)
    {
        // Cache last focused tree item on the tree
        // The last focused item is always the only item in the tab order for this tree,
        // so we need to set its tabindex to 0, and the others to -1
        // var treeItem = getTarget(event);
        Node tree = getTree(treeItem);
        Element lastFocus = (Element)((ItsNatNode)tree).getUserValue("lastFocus");
        if (lastFocus == null) {
            lastFocus = (Element)getFirstTreeItem(tree); //debugOut(tree.lastFocus.firstChild.nodeValue);
            ((ItsNatNode)tree).setUserValue("lastFocus",lastFocus);
        }
        lastFocus.setAttribute("tabindex","-1");
        lastFocus.setAttribute("class","treeitem");
        ((ItsNatNode)tree).setUserValue("lastFocus",treeItem);
        treeItem.setAttribute("tabindex","0");
        treeItem.setAttribute("class","treeitemfocus");

        if (bFocus == true) {
            setFocus(treeItem);
        }
    }


    public boolean treeItemClick(Event event)
    {
        Node treeItem = (Node)getTarget(event);
        boolean bEventContinue = true;
        if (isValidTreeItem(treeItem) ) {
            // only process if click was on an actual tree item
            treeItemFocus((Element)treeItem, false)// update the tabindex and lastFocused variables, item already has focus from being clicked upon
            bEventContinue = false;
        }
        else {
            if (!((Element)treeItem).getTagName().toLowerCase().equals("img")) {
              //reset focus to existing treeItem (can always find Tree from any child)
              Element curTreeItem = (Element)((ItsNatNode)getTree(treeItem)).getUserValue("lastFocus");
              if (curTreeItem != null)
                setFocus(curTreeItem);
                bEventContinue = false;
            }
            // else not image so return true - only images are for expand/collapse which have their own event handler
        }
        return bEventContinue;
    }

    public boolean isGroupClosed(Node groupItem)
    {
        Element treeItemForGroup = (Element)getRelativeTreeItem(groupItem, -1, false);
        return (treeItemForGroup == null) || treeItemForGroup.getAttribute("aria-expanded").equals("false");
    }

    public Node getTreeItemFromPar(Node itemDiv)
    {
      Node treeItem = null;
      if ((itemDiv != null) && itemDiv.hasChildNodes()) {
        for (int i=0; i<itemDiv.getChildNodes().getLength(); i++) {
          if (getRole(itemDiv.getChildNodes().item(i)).equals(ROLE_TREEITEM)) {
            treeItem = itemDiv.getChildNodes().item(i);
            break;
          }
        }
      }
      return treeItem;
    }

    public Node getLastTreeItem(Node tree)
    {
      Node lastTreeItem = tree;
      do {
        lastTreeItem = lastTreeItem.getLastChild();
        if (isText(lastTreeItem)) {
          lastTreeItem = lastTreeItem.getPreviousSibling();
        }
      }
      while (getRole(lastTreeItem).equals(ROLE_GROUP));
      return  getTreeItemFromPar(lastTreeItem);
    }

    public Node getRelativeTreeItem(Node treeItem,int delta,boolean wrap)
    {
    // treeItem is really the parent div of the treeItem
      // delta: -1 = prev, 1 = next
      if (delta == 1)
      {  // Next
        Node newTreeItem = treeItem.getNextSibling();
        while (isText(newTreeItem)) {
          newTreeItem = newTreeItem.getNextSibling();
        }
      // if(newTreeItem)
        //  debugOut(newTreeItem.id + " " + getRole(newTreeItem) );

        Node treeItemSpan = null;
        if (newTreeItem != null) {
          String role = getRole((Element)newTreeItem);
          if (role.equals(ROLE_GROUP)) {
            if (isGroupClosed(newTreeItem)) {
              return getRelativeTreeItem(newTreeItem, 1, wrap);
            } // end of closed group
            else {
              newTreeItem = newTreeItem.getFirstChild();
              if (isText(newTreeItem)) {
                newTreeItem = newTreeItem.getNextSibling();
              }
            } // end of open group
           } // end of if group
           if ( (newTreeItem != null) && (treeItemSpan == null)) {
              //extract the actual treeItem span from the div
              for(int i=0; i < newTreeItem.getChildNodes().getLength(); i++ ) {
                treeItemSpan = newTreeItem.getChildNodes().item(i); //debugOut(treeItemSpan.tagName + " " + getRole(treeItemSpan) + "\n");
                if (treeItemSpan.getNodeName().equals("span") && getRole((Element)treeItemSpan).equals(ROLE_TREEITEM)) {
                  return treeItemSpan;
                }
              }
            }
           } // end of if newTreeItem
       } // end of next
      else {    // Prev
        Node newTreeItem = treeItem.getPreviousSibling();
        if (isText(newTreeItem)) {
          newTreeItem = newTreeItem.getPreviousSibling();
        }
        if (newTreeItem != null) {
          String role;
          while ((role = getRole((Element)newTreeItem)).equals(ROLE_GROUP)) {
            if (isGroupClosed(newTreeItem)) {
              return getRelativeTreeItem(newTreeItem, -1, wrap);
            } // end of if closed group
            else {
              newTreeItem = newTreeItem.getLastChild();
              if (isText(newTreeItem)) {
                newTreeItem = newTreeItem.getPreviousSibling();
              }
            } // end of open group
          // end of while

          Node treeItemSpan = null;
           if ((newTreeItem != null) && (treeItemSpan == null)) {
              //extract the actual treeItem span from the div
              for(int j=0; j < newTreeItem.getChildNodes().getLength(); j++ ) {
                treeItemSpan = newTreeItem.getChildNodes().item(j);
                if (treeItemSpan.getNodeName().equals("span") && getRole((Element)treeItemSpan).equals(ROLE_TREEITEM)) {
                  return treeItemSpan;
                }
              }
            }
        } // end of if newTreeItem
      } // end of prev
      if (getRole(treeItem.getParentNode()).equals(ROLE_TREE)) {
        if (!wrap) {
          return null;
        }
        Node tree = getTree(treeItem);
        return (delta == 1)? getFirstTreeItem(tree) : getLastTreeItem(tree);
      }
      return getRelativeTreeItem(treeItem.getParentNode(), delta, wrap); // Recursive
    }

    public void toggleExpandCollapse(Element treeItem, boolean isItemOpen)
    {
      treeItem.setAttribute("aria-expanded", isItemOpen? "false" : "true");
      Node image = treeItem.getPreviousSibling();
      if (isText(image)) {
        image = image.getPreviousSibling();
      }
      Node group = treeItem.getParentNode();
      group = group.getNextSibling();
      if (isText(group)) {
        group = group.getNextSibling();
      }
      if (!isItemOpen) {
        ((Element)image).setAttribute("src",COLLAPSE);
        ((Element)group).setAttribute("class","group")//treeitem is span within div followed by group div
      }
      else {
        ((Element)image).setAttribute("src",EXPAND);
        ((Element)group).setAttribute("class","collapsedgroup");
      }
    }

    public boolean treeItemEvent(Event event)
    { // debugOut(event.type + " : " + event.keyCode);
      Element treeItem = (Element)getTarget(event); //event.target;
      if (treeItem == this.treeElem) return false; // Por ejemplo cuando el usuario ha pulsado una letra pero no ha seleccionado antes ningún elemento del árbol, esto no estaba en el código original de JavaScript (que tiene el mismo error sin esta línea)

      if (treeItem.getTagName().toLowerCase().equals("img")) {
        Node tree = getTree(treeItem);
        // get the treeItem from tree.lastFocus
        if (((ItsNatNode)tree).getUserValue("lastFocus") == null) {
          ((ItsNatNode)tree).setUserValue("lastFocus", getFirstTreeItem(tree) );
        }
        treeItem = (Element)((ItsNatNode)tree).getUserValue("lastFocus");
      }
      String hasChildrenStr = treeItem.getAttribute("aria-expanded");
      boolean hasChildren = !hasChildrenStr.equals("");
      boolean isItemOpen = hasChildrenStr.equals("true");
      int focusDelta = 0// (-1 = up, 0 = no change, 1 = down)

      boolean toggleitem = false;
      if (event.getType().equals("dblclick") && (((MouseEvent)event).getButton() == 0)) {
        toggleitem = hasChildren;
        ((ItsNatNode)getTree(treeItem)).setUserValue("_incrementalString","");
      }
      else if (event.getType().equals("keydown")) {

        if (((ItsNatKeyEvent)event).getAltKey()) {
          return true// Browser should use this, the tree view doesnot need alt-modified keys
        }
        // XXX Implement multiple selection (ctrl+arrow, shift+arrow, ctrl+space)
        if (((ItsNatKeyEvent)event).getKeyCode() == KEY_HOME) {
          try {
            treeItemFocus((Element)getFirstTreeItem(getTree(treeItem)),true);
          } catch(Exception ex) { debugOut(ex.getMessage()); }
         
          return false;
        }
        if (((ItsNatKeyEvent)event).getKeyCode() == KEY_ENTER) {
          toggleitem = hasChildren;
        }
        else if (((ItsNatKeyEvent)event).getKeyCode() == KEY_DOWN) {
          focusDelta = 1;
        }
        else if (((ItsNatKeyEvent)event).getKeyCode() == KEY_UP) {
          focusDelta = -1;
        }
        else if (((ItsNatKeyEvent)event).getKeyCode() == KEY_LEFT) {
          if (isItemOpen) {
            toggleitem = true;
          }
          else {
            Node groupItem = treeItem.getParentNode().getParentNode()// relies on treeitems being spans nested in divs
            if (getRole((Element)groupItem).equals(ROLE_GROUP)) {
              Node nextItem = getRelativeTreeItem(groupItem, -1, false);
              treeItemFocus((Element)nextItem, true);
            }
          }
        }
        else if (((ItsNatKeyEvent)event).getKeyCode() == KEY_RIGHT) {
          if (isItemOpen) {
            focusDelta = 1;
          }
          else {
            toggleitem = hasChildren;
          }
        }
        else if (((ItsNatKeyEvent)event).getKeyCode() == KEY_END) {
          try {
            Node newTreeItemFocus = getLastTreeItem(getTree(treeItem));
            treeItemFocus((Element)newTreeItemFocus,true);
          } catch(Exception ex) { debugOut(ex.getMessage()); }
         
          return false;   // Consume the event
        }
        else {
          return true// We didn't need key, don't consume event
        }
      }
      else if (event.getType().equals("keypress")) {
        // Implement incremental find here, instead of keydown, because we
        // need to capture printable characters in a keypress handler
        Node tree = getTree(treeItem);
        ((ItsNatNode)tree).setUserValue("_incrementalString","");
        int key;
        if (((ItsNatKeyEvent)event).getCharCode() != 0) {
          key = ((ItsNatKeyEvent)event).getCharCode();
        }
        else {
          key = ((ItsNatKeyEvent)event).getKeyCode()// IE uses keyCode - for keypress event the value should be the same as event.charCode
        }
        if (key > 32 && !((ItsNatKeyEvent)event).getAltKey() && !((ItsNatKeyEvent)event).getCtrlKey() &&
           !((ItsNatKeyEvent)event).getShiftKey() && !((ItsNatKeyEvent)event).getMetaKey()) {
          //jmarranz: key = String.fromCharCode(key);
        }
        else {
          ((ItsNatNode)tree).setUserValue("_incrementalString","");
          return true;
        }
        key = Character.toLowerCase((char)key);
        long _lastKeyTime = 0;
        if (((ItsNatNode)tree).getUserValue("_lastKeyTime") != null)
            _lastKeyTime = ((Long)((ItsNatNode)tree).getUserValue("_lastKeyTime")).longValue();

        if (event.getTimeStamp() - _lastKeyTime > 1000) {
          ((ItsNatNode)tree).setUserValue("_incrementalString",Character.toString((char)key));
        }
        else {
          // IE does not have event.timeStamp so will always end up in this else in IE
            String _incrementalString = (String)((ItsNatNode)tree).getUserValue("_incrementalString");
            _incrementalString += key;
            ((ItsNatNode)tree).setUserValue("_incrementalString",_incrementalString);
         }
        ((ItsNatNode)tree).setUserValue("_lastKeyTime", new Long(event.getTimeStamp()));

        String incrementalString = (String)((ItsNatNode)tree).getUserValue("_incrementalString");
        int length = incrementalString.length();
        int charIndex = 1;
        while (charIndex < length && incrementalString.charAt(charIndex) == incrementalString.charAt(charIndex - 1))
          charIndex++;
        // If all letters in incremental string are same, just try to match the first one
        if (charIndex == length) {
          length = 1;
          incrementalString = incrementalString.substring(0, length);
        }
        Node origTreeItem = treeItem;
        if (length == 1) {
          treeItem = (Element)getRelativeTreeItem(treeItem.getParentNode(), 1, true);
        }
        do {
          String text = ((Text)treeItem.getFirstChild()).getData();
          if (((Text)treeItem.getFirstChild()).getData().substring(0, length).toLowerCase().equals(incrementalString)) {
            treeItemFocus((Element)treeItem, true);
            return false;
          }
          treeItem = (Element)getRelativeTreeItem(treeItem.getParentNode(), 1, true);
        } while (treeItem != origTreeItem);
        return false;
      }
      else if (event.getType().equals("click")) {
          ((ItsNatNode)getTree(treeItem)).setUserValue("_incrementalString","");
      }
      else {
        return true; // continue propagating event;
      }
      if (toggleitem) {
        toggleExpandCollapse(treeItem, isItemOpen);

        return false; // consume event
      }
      if (focusDelta != 0) {
        //try {
          // treeitem is a span, must pass parent div to getRelativeTreeItem();
          Node nextItem = getRelativeTreeItem(treeItem.getParentNode(), focusDelta, false);
          if (nextItem != null) {
            treeItemFocus((Element)nextItem, true);
          }
        //} catch(ex) { debugOut("error in focusDelta " + ex.message); }
        return false;
      }
      return true// Browser can still use event
    }


    public boolean isContainedChild(Node parent,Node item)
    {
      boolean bFound = false;
      if (parent.hasChildNodes()) {
        for (int i=0; i<parent.getChildNodes().getLength(); i++) {
          if (parent.getChildNodes().item(i) == item) {
            bFound = true;
          }
          else {
            bFound = isContainedChild(parent.getChildNodes().item(i),item);
          }
          if (bFound == true) {
            break;
          }
        }
      }
      return bFound;
    }

    public void imgToggle(Event event)
    {
      Element imgItem = (Element)getTarget(event);
      if ( (imgItem == null) || !imgItem.getTagName().toLowerCase().equals("img")) {
        itsNatDoc.addCodeToSend("alert('ERROR');");
      }
      Node treeItemDiv = imgItem.getParentNode()// parent of expand/collapse img is div
      Element treeItem = (Element)getTreeItemFromPar(treeItemDiv);
      boolean hasChildren = !treeItem.getAttribute("aria-expanded").equals("");
      boolean isItemOpen = hasChildren && treeItem.getAttribute("aria-expanded").equals("true");
      Node tree= getTree(treeItem);
      if (isItemOpen) {
        // if closing: need to determine if current focus is on a treeitem within the hierarchy of this item - if so,
        // need to update focus to this item.
        // next sibling of expand/collapse item is group; check all children of group and its next siblings to see if any have focus
        Node searchStart = treeItemDiv.getNextSibling();
        while ((searchStart != null) && isText(searchStart) ) {
          searchStart = searchStart.getNextSibling();
        }
        boolean bFound = false;
        bFound = isContainedChild(searchStart, (Node)((ItsNatNode)tree).getUserValue("lastFocus"));
        if (bFound) {
          treeItemFocus(treeItem,false); //update stored focus item; focus will actually be set with setFocus() call below
        }
      }
      toggleExpandCollapse(treeItem, isItemOpen);
      setFocus((Node)((ItsNatNode)tree).getUserValue("lastFocus"));
    }

}
TOP

Related Classes of inexp.waiaria.WAIARIADocument

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.