2013-04-23 74 views
0

我正在使用gwt和gwt-dnd(一個很棒的拖放庫)。確定重疊元素順序

我有一個與另一個重疊的dropTarget(一個div),並且該庫爲下拉操作選擇一個。 其原因是,在的choise與以下標準完成:

確定哪個DropController表示位於所提供的位置(x, y)最深DOM後裔 放置目標。

這是正確的降DropTargets,但不是這樣的層次結構:

<body> 
    <div id="a"> 
     <div id="b"> 
      <div id="c"> 
       <div id="DropTarget_D"></div> 
      </div> 
     </div> 
    </div> 
    <div id="1" style="position:absolute; z-index: 1; top:0; left:0"> 
     <div id="DropTarget_2"></div> 
    </div> 
</body> 

演示:http://jsfiddle.net/rxwMB/

正如你可以從代碼中看到(在帖子的末尾),在這種情況下DropTarget_C被使用(因爲它是「最深」的),即使DropTarget_2顯示在上面。

我怎麼知道,給出兩個組件,哪一個是最頂層的?

這裏的代碼,使的choise:

private int compareElement(Element myElement, Element otherElement) { 
    if (myElement == otherElement) { 
    return 0; 
    } else if (DOM.isOrHasChild(myElement, otherElement)) { 
    return -1; 
    } else if (DOM.isOrHasChild(otherElement, myElement)) { 
    return 1; 
    } else { 
    // check parent ensuring global candidate sorting is correct 
    Element myParentElement = myElement.getParentElement().cast(); 
    Element otherParentElement = otherElement.getParentElement().cast(); 
    if (myParentElement != null && otherParentElement != null) { 
     return compareElement(myParentElement, otherParentElement); 
    } 
    return 0; 
    } 
} 

的DropTarget處於從有序列表,其使用該功能被勒令採摘。 如果列表中只包含DropTarget_D和DropTarget_2無一不符合條件,第一個被挑(即使它是由DropTarget_2覆蓋)

回答

0

這裏是我的解決方案:

(對GWT-DND:https://code.google.com/p/gwt-dnd/issues/detail?id=169

package com.allen_sauer.gwt.dnd.client; 

import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.ListIterator; 
import java.util.Queue; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

import com.allen_sauer.gwt.dnd.client.DropControllerCollection.Candidate; 
import com.google.gwt.dom.client.Element; 
import com.google.gwt.user.client.ui.RootPanel; 

public class OverlappingDropTargetsHandler { 

    private static class StackingContext{ 
     private Element element; 
     private LinkedList<Object> childrens; 

     public StackingContext(Element element) { 
      if(element == null){ 
       throw new RuntimeException(); 
      } 
      this.element = element; 
      this.childrens = new LinkedList<Object>(); 
     } 

     public Element getElement() { 
      return element; 
     } 

     public void addChildren(Candidate candidate) { 
      this.childrens.add(candidate); 
     } 

     public void addChildren(StackingContext stackingContext) { 
      this.childrens.add(stackingContext);    
     } 

     public LinkedList<Object> getChildrens() { 
      return this.childrens; 
     } 

     public int getZIndex(){ 
      return this.element.getPropertyInt("z-index"); 
     } 

     @Override 
     public int hashCode() { 
      return element.hashCode(); 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if(obj instanceof StackingContext){ 
       return this.element.equals(((StackingContext)obj).element); 
      }else{ 
       return false; 
      } 
     } 
    } 

    public static void sort(Candidate[] candidates) {  
     HashMap<Element, OverlappingDropTargetsHandler.StackingContext> cache = new HashMap<Element, OverlappingDropTargetsHandler.StackingContext>(); 

     initStackingContextsList(candidates, cache); 

     StackingContext rootStackingContext = resolveStackingContextsHierarcy(cache); 

     cache = null; //non mi serve piu 

     assert rootStackingContext != null; 

     Comparator<Object> comparator = new Comparator<Object>() { 
      @Override 
      public int compare(Object a, Object b) { 
       assert a instanceof StackingContext || a instanceof Candidate; 
       assert b instanceof StackingContext || b instanceof Candidate; 

       boolean aInstanceOfStackingContext = a instanceof StackingContext; 
       boolean bInstanceOfStackingContext = b instanceof StackingContext; 

       if(aInstanceOfStackingContext && bInstanceOfStackingContext){ 
        int ai = ((StackingContext)a).getZIndex(); 
        int bi = ((StackingContext)b).getZIndex(); 
        if(ai<bi){ return -1; 
        }else if(ai>bi){ return 1; 
        }else{ return 0;} 
       }else if(aInstanceOfStackingContext && !bInstanceOfStackingContext){ 
        return ((StackingContext)a).getZIndex()<0? -1: 1; 
       }else if(!aInstanceOfStackingContext && bInstanceOfStackingContext){ 
        return ((StackingContext)b).getZIndex()<0? 1: -1; 
       }else /* if(!aInstanceOfStackingContext && !bInstanceOfStackingContext) */{ 
        return ((Candidate)a).compareTo((Candidate)b); 
       } 
      }   
     }; 

     Queue<Object> queue = new LinkedList<Object>(); 
     queue.add(rootStackingContext); 
     Object o; 
     int i = 0; 
     while((o = queue.poll()) != null){ 
      if(o instanceof StackingContext){ 
       Collections.sort(((StackingContext)o).getChildrens(), comparator); 
       //reverse iterator 
       ListIterator<Object> it = ((StackingContext)o).getChildrens().listIterator(((StackingContext)o).getChildrens().size()); 
       while(it.hasPrevious()){ 
        queue.offer(it.previous()); 
       } 
      }else /* if(o instanceof Candidate) */{ 
       candidates[i++] = (Candidate)o; 
      } 
     } 

//  if(DOMUtil.DEBUG == true){ 
//   printTree(rootStackingContext, 0);  
//   printArray(candidates); 
//  } 
    } 

    private static void initStackingContextsList(Candidate[] candidates, HashMap<Element, OverlappingDropTargetsHandler.StackingContext> cache){ 
     for(Candidate candidate : candidates) { 
      Element stackingContextElement = findNearestStackingContextParentElement(candidate.getDropTarget().getElement()); 
      if(stackingContextElement != null){ 
       StackingContext stackingContext = cache.get(stackingContextElement); 
       if(stackingContext == null){ 
        stackingContext = new StackingContext(stackingContextElement); 
        cache.put(stackingContextElement, stackingContext); 
       } 
       stackingContext.addChildren(candidate); 
      } 
     } 
    } 

    /** 
    * 
    * @param cache 
    * @return the root StackingContext 
    */ 
    private static StackingContext resolveStackingContextsHierarcy(HashMap<Element, OverlappingDropTargetsHandler.StackingContext> cache) { 
     Queue<StackingContext> queue = new LinkedList<OverlappingDropTargetsHandler.StackingContext>(cache.values()); 

     StackingContext stackingContext; 
     StackingContext rootStackingContext = null; 
     while((stackingContext = queue.poll()) != null){ 
      Element parentElement = findNearestStackingContextParentElement(stackingContext.getElement()); 
      if(parentElement != null){ 
       StackingContext parentStackingContext = cache.get(parentElement); 
       if(parentStackingContext == null){ 
        parentStackingContext = new StackingContext(parentElement); 
        cache.put(parentElement, parentStackingContext); 
        queue.offer(parentStackingContext); 
       } 
       parentStackingContext.addChildren(stackingContext); 
      }else{ 
       //this stackingContext is the root 
       assert rootStackingContext == null || rootStackingContext == stackingContext; 
       rootStackingContext = stackingContext; 
      } 
     } 

     return rootStackingContext; 
    } 

    /** 
    * @param element 
    * @return the first parent that create a StackingContext or null if element is the root 
    */ 
    private static Element findNearestStackingContextParentElement(Element element) { 
     assert element != null; 
     Element parentElement = element; 
     while((parentElement = parentElement.getParentElement()) != null){ 
//   if(DOMUtil.DEBUG == true){ 
//    parentElement.getStyle().setProperty("border", "2px solid " + "orange"); 
//   } 
      if(isStackingContext(parentElement)){ 
       return parentElement; 
      } 
//   if(DOMUtil.DEBUG == true){ 
//    parentElement.getStyle().setProperty("border", "2px solid " + "white"); 
//   } 
     } 
     return null; 
    } 

    private static native String getComputedProperty(Element e, String property) /*-{ 
     return window.getComputedStyle(e).getPropertyValue(property); 
    }-*/; 

    private static boolean isStackingContext(Element element) { 
     String position = getComputedProperty(element, "position"); 
     String zindex = getComputedProperty(element, "z-index"); 

     if((!position.equals("static")) && (!zindex.equals("") && !zindex.equals("0"))){ 
      return true; 
     }else if(RootPanel.get().getElement() == element){ 
      return true; 
     }else{ 
      return false; 
     } 
     //TODO: gestire gli altri casi in cui viene creata un stacking context: 

//  The root element always holds a root stacking context. 
// 
//  Setting z-index to anything other than 1 on an element that is positioned (i.e. an element with position that isn't static). 
// 
//  Note that this behavior is slated to be changed for elements with position: fixed such that they will always establish stacking contexts regardless of their z-index value. Some browsers have begun to adopt this behavior, however the change has not been reflected in either CSS2.1 or the new CSS Positioned Layout Module yet, so it may not be wise to rely on this behavior for now. 
// 
//  This change in behavior is explored in another answer of mine, which in turn links to this article and this set of CSSWG telecon minutes. 
// 
//  Another exception to this is with a flex item. Setting z-index on a flex item will always cause it to establish a stacking context even if it isn't positioned. 
// 
//  Setting opacity to anything less than 1. 
// 
//  Transforming the element: 
// 
//  Setting transform to anything other than none. 
// 
//  Setting transform-style to preserve-3d. 
// 
//  Setting perspective to anything other than none. 
// 
//  Creating a CSS region: setting flow-from to anything other than none on an element whose content is anything other than normal. 
// 
//  In paged media, each page-margin box establishes its own stacking context. 
    } 

    private static void printTree(StackingContext stackingContext, int level){ 

     String s = ""; 
     for(int i = 0; i < level; i++) { 
      s += "_"; 
     } 

     for(Object o : stackingContext.getChildrens()){ 
      if(o instanceof StackingContext){ 
       Logger.getLogger("test").log(Level.WARNING, s + "(s) "+((StackingContext)o).getElement().getClassName()+" z-index="+ ((StackingContext)o).getZIndex()); 
       printTree((StackingContext)o, level+1); 
      }else /* if(o instanceof Candidate) */{ 
       Logger.getLogger("test").log(Level.WARNING, s + "(c) "+((Candidate)o).getDropTarget().getElement().getClassName()); 
      } 
     } 
    } 

    private static void printArray(Candidate[] candidates) { 
     String s = "["; 
     for(int i = 0; i < candidates.length; i++) { 
      s+=candidates[i].getDropTarget().getElement().getNodeName(); 
      if(i < candidates.length-1){ 
       s += ", "; 
      } 
     } 
     Logger.getLogger("test").log(Level.WARNING, s +"]"); 
    } 
}