Author: mgrigorov
Date: Sun Jul 18 09:29:02 2010
New Revision: 965183

URL: http://svn.apache.org/viewvc?rev=965183&view=rev
Log:
Port from wicket-1.4.x

r886735
Author: jcompagner
Date:   Thu Dec 3 10:50:01 2009 UTC (7 months, 2 weeks ago)
Changed paths:  4
Log Message:    
fixes and improvements (browser issues)


Modified:
    
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteBehavior.java
    
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AutoCompleteSettings.java
    
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/DefaultCssAutoCompleteTextField.css
    
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js

Modified: 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteBehavior.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteBehavior.java?rev=965183&r1=965182&r2=965183&view=diff
==============================================================================
--- 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteBehavior.java
 (original)
+++ 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteBehavior.java
 Sun Jul 18 09:29:02 2010
@@ -82,6 +82,8 @@ public abstract class AbstractAutoComple
                sb.append("{preselect: ").append(settings.getPreselect());
                sb.append(",maxHeight: ").append(settings.getMaxHeightInPx());
                sb.append(",adjustInputWidth: 
").append(settings.isAdjustInputWidth());
+               sb.append(",useSmartPositioning: 
").append(settings.getUseSmartPositioning());
+               sb.append(",useHideShowCoveredIEFix: 
").append(settings.getUseHideShowCoveredIEFix());
                sb.append(",showListOnEmptyInput: 
").append(settings.getShowListOnEmptyInput());
                sb.append(",showListOnFocusGain: 
").append(settings.getShowListOnFocusGain());
                sb.append(",throttleDelay: 
").append(settings.getThrottleDelay());

Modified: 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AutoCompleteSettings.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AutoCompleteSettings.java?rev=965183&r1=965182&r2=965183&view=diff
==============================================================================
--- 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AutoCompleteSettings.java
 (original)
+++ 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AutoCompleteSettings.java
 Sun Jul 18 09:29:02 2010
@@ -55,6 +55,10 @@ public final class AutoCompleteSettings 
 
        private boolean showListOnEmptyInput = false;
 
+       private boolean useSmartPositioning = false;
+
+       private boolean useHideShowCoveredIEFix = true;
+
        private String cssClassName = null;
 
        private boolean adjustInputWidth = true;
@@ -150,6 +154,29 @@ public final class AutoCompleteSettings 
        }
 
        /**
+        * Indicates whether the popup positioning will take into account 
browser window visible area or
+        * not. (so always show popup bottom-right or not)
+        * 
+        * @return true if popup smart positioning is used, false otherwise.
+        */
+       public boolean getUseSmartPositioning()
+       {
+               return useSmartPositioning;
+       }
+
+       /**
+        * Indicates whether in case of IE (and Opera), "select" "iframe" and 
"applet" tags should be
+        * hidden if covered by popup. (as they might appear on top)<br>
+        * By default this is true (before this flag was added).
+        * 
+        * @return true if the fix/workaround should be used for IE and Opera, 
false otherwise.
+        */
+       public boolean getUseHideShowCoveredIEFix()
+       {
+               return useHideShowCoveredIEFix;
+       }
+
+       /**
         * Indicates whether the autocomplete list will be shown if the input 
is empty.
         * 
         * @return true if the autocomlete list will be shown if the input 
string is empty, false
@@ -191,10 +218,12 @@ public final class AutoCompleteSettings 
         * 
         * @param cssClassName
         *            valid CSS class name
+        * @return this {...@link AutoCompleteSettings}.
         */
-       public void setCssClassName(final String cssClassName)
+       public AutoCompleteSettings setCssClassName(final String cssClassName)
        {
                this.cssClassName = cssClassName;
+               return this;
        }
 
        /**
@@ -218,10 +247,12 @@ public final class AutoCompleteSettings 
         * @param adjustInputWidth
         *            <code>true</code> if the autocompleter should have the 
same size as the input
         *            field, <code>false</code> for default browser behavior
+        * @return this {...@link AutoCompleteSettings}.
         */
-       public void setAdjustInputWidth(final boolean adjustInputWidth)
+       public AutoCompleteSettings setAdjustInputWidth(final boolean 
adjustInputWidth)
        {
                this.adjustInputWidth = adjustInputWidth;
+               return this;
        }
 
        /**
@@ -240,10 +271,12 @@ public final class AutoCompleteSettings 
         * 
         * @param showCompleteListOnFocusGain
         *            the flag
+        * @return this {...@link AutoCompleteSettings}.
         */
-       public void setShowCompleteListOnFocusGain(final boolean 
showCompleteListOnFocusGain)
+       public AutoCompleteSettings setShowCompleteListOnFocusGain(final 
boolean showCompleteListOnFocusGain)
        {
                this.showCompleteListOnFocusGain = showCompleteListOnFocusGain;
+               return this;
        }
 
        /**
@@ -262,9 +295,41 @@ public final class AutoCompleteSettings 
         * 
         * @param showListOnFocusGain
         *            the flag
+        * @return this {...@link AutoCompleteSettings}.
         */
-       public void setShowListOnFocusGain(final boolean showListOnFocusGain)
+       public AutoCompleteSettings setShowListOnFocusGain(final boolean 
showListOnFocusGain)
        {
                this.showListOnFocusGain = showListOnFocusGain;
+               return this;
        }
+
+       /**
+        * Sets whether the popup positioning will take into account browser 
window visible area or not. (so always show popup bottom-right or not)<br>
+        * THIS WILL PRODUCE UNWANTED BEHAVIOR WITH IE versions < 8 (probably 
because of unreliable clientWidth/clientHeight browser element properties).
+        * 
+        * @param useSmartPositioning
+        *            the flag
+        * @return this {...@link AutoCompleteSettings}.
+        */
+       public AutoCompleteSettings setUseSmartPositioning(final boolean 
useSmartPositioning)
+       {
+               this.useSmartPositioning = useSmartPositioning;
+               return this;
+       }
+
+       /**
+        * Indicates whether in case of IE (and Opera), "select" "iframe" and 
"applet" tags should be
+        * hidden if covered by popup. (as they might appear on top)<br>
+        * By default this is true (before this flag was added).
+        * 
+        * @param useHideShowCoveredIEFix
+        *            the flag
+        * @return this {...@link AutoCompleteSettings}.
+        */
+       public AutoCompleteSettings setUseHideShowCoveredIEFix(final boolean 
useHideShowCoveredIEFix)
+       {
+               this.useHideShowCoveredIEFix = useHideShowCoveredIEFix;
+               return this;
+       }
+
 }

Modified: 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/DefaultCssAutoCompleteTextField.css
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/DefaultCssAutoCompleteTextField.css?rev=965183&r1=965182&r2=965183&view=diff
==============================================================================
--- 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/DefaultCssAutoCompleteTextField.css
 (original)
+++ 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/DefaultCssAutoCompleteTextField.css
 Sun Jul 18 09:29:02 2010
@@ -14,15 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+ 
+div.wicket-aa-container {
+       border-width: 1px;
+       border-color: #cccccc;
+       border-style: solid;
+}
+
 div.wicket-aa {
         font-family: "Lucida Grande","Lucida Sans Unicode",Tahoma,Verdana;
         font-size: 12px;
         background-color: white;
-        border-color: #cccccc;
-        border-width: 1px;
-        border-style: solid;
         padding: 2px;
-        margin: 1px 0 0 0;
         text-align:left;
 }
  

Modified: 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js?rev=965183&r1=965182&r2=965183&view=diff
==============================================================================
--- 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js
 (original)
+++ 
wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js
 Sun Jul 18 09:29:02 2010
@@ -52,10 +52,24 @@ Wicket.AutoComplete=function(elementId, 
        var objonkeypress;
        var objonchange;
        var objonchangeoriginal;
-       var objonfocus;
        
-      var ignoreOneFocusGain = false; // on FF, clicking an option in the 
popup would make field loose focus; focus() call only has effect in FF after 
popup is hidden, so the re-focusing must not show popup again in this case
+       // holds the eventual margins, padding, etc. of the menu container.
+       // it is computed when the menu is first rendered, and then reused.
+       var initialDelta = -1;
+       // remember popup container border size so we can use 
style.width/height = ... correctly; array [horizontal, vertical]
+       var usefulDimensionsInitialized = false;
+       var containerBorderWidths = [0, 0];
+       var scrollbarSize = 0;
+       var selChSinceLastRender = false;
+       
 
+    // this are the last visible and non-temporary bounds of the pop-up; the 
may change position and size several times when showing/updating choices and so 
on
+    // before it reaches the bounds that will be visible by the user (this is 
because of height/width settings limits or because it tries to compute 
preferred size);
+    // used for IE fix with hideShowCovered() - to be able to call it when 
bounds change while popup is visible.  
+    var lastStablePopupBounds = [0, 0, 0, 0];
+    
+    var ignoreOneFocusGain = false; // on FF, clicking an option in the pop-up 
would make field loose focus; focus() call only has effect in FF after popup is 
hidden, so the re-focusing must not show popup again in this case
+    
        // holds a throttler, for not sending many requests if the user types
        // too quickly.
        var localThrottler = new Wicket.Throttler(true);
@@ -89,7 +103,7 @@ Wicket.AutoComplete=function(elementId, 
                 
        obj.onblur=function(event){                     
                if(mouseactive==1){
-                  ignoreOneFocusGain = true;
+                ignoreOneFocusGain = true;
                        Wicket.$(elementId).focus();
                        return killEvent(event);
                }
@@ -98,8 +112,11 @@ Wicket.AutoComplete=function(elementId, 
         }
        
        obj.onfocus=function(event){
-                       if (mouseactive==1) return killEvent(event);
-            if (!ignoreOneFocusGain && cfg.showListOnFocusGain) {
+            if (mouseactive==1) {
+                ignoreOneFocusGain = false;
+                return killEvent(event);
+            }
+            if (!ignoreOneFocusGain && cfg.showListOnFocusGain && visible==0) {
                 if (cfg.showCompleteListOnFocusGain) {
                     updateChoices(true);
                 } else {
@@ -113,20 +130,22 @@ Wicket.AutoComplete=function(elementId, 
         obj.onkeydown=function(event){
             switch(wicketKeyCode(Wicket.fixEvent(event))){
                 case KEY_UP:
-                       if(selected>-1)selected--;
+                       if(selected>-1) setSelected(selected-1);
                    if(selected==-1){
                            hideAutoComplete();
                        } else {
-                           render();
+                           render(true);
                        }
                    if(Wicket.Browser.isSafari())return killEvent(event);
                        break;
                 case KEY_DOWN:
-                               if(selected<elementCount-1) selected++;
+                               if(selected<elementCount-1){
+                           setSelected(selected+1);
+                       }
                    if(visible==0){
                            updateChoices();
                    } else {
-                           render();
+                           render(true);
                        showAutoComplete();
                        }
                    if(Wicket.Browser.isSafari())return killEvent(event);
@@ -139,23 +158,20 @@ Wicket.AutoComplete=function(elementId, 
                 case KEY_ENTER:
                     if(selected > -1) {
                         var value = getSelectedValue();
-                        if(value = handleSelection(value)) {
+                        value = handleSelection(value);
+                        hideAutoComplete();
+                        hidingAutocomplete = 1;                        
+                        if(value) {
                           obj.value = value;
                           if(typeof objonchange=="function") 
objonchange.apply(this,[event]);
                         }
-                        hideAutoComplete();
-                        hidingAutocomplete = 1;
                     } else if 
(Wicket.AutoCompleteSettings.enterHidesWithNoSelection) {
                         hideAutoComplete();
                         hidingAutocomplete = 1;
                     }
-                       mouseactive=0;
-                       if(typeof 
objonkeydown=="function")objonkeydown.apply(this,[event]);
-
-                       if(selected>-1){
-                               //return killEvent(event);
-                   }
-                   return true;
+                    mouseactive = 0;
+                    if (typeof objonkeydown=="function") 
objonkeydown.apply(this,[event]);
+                    return true;
                 break;
                 default:
             }
@@ -163,7 +179,7 @@ Wicket.AutoComplete=function(elementId, 
 
         obj.onkeyup=function(event){
             switch(wicketKeyCode(Wicket.fixEvent(event))){
-               case KEY_TAB:
+                case KEY_TAB:
                 case KEY_ENTER:
                        return killEvent(event);
                 case KEY_UP:
@@ -179,7 +195,6 @@ Wicket.AutoComplete=function(elementId, 
                    updateChoices();
             }
                        if(typeof 
objonkeyup=="function")objonkeyup.apply(this,[event]);
-            return null;
         }
 
         obj.onkeypress=function(event){
@@ -192,13 +207,20 @@ Wicket.AutoComplete=function(elementId, 
                        if(typeof 
objonkeypress=="function")objonkeypress.apply(this,[event]);
         }
     }
+    
+    function setSelected(newSelected) {
+        if (newSelected != selected) {
+            selected = newSelected;
+            selChSinceLastRender = true;
+        }
+    }
 
     function handleSelection(input) {
-       var menu = getAutocompleteMenu();
-       var attr = menu.firstChild.childNodes[selected].attributes['onselect'];
-       return attr ? eval(attr.value) : input;
+        var menu = getAutocompleteMenu();
+        var attr = menu.firstChild.childNodes[selected].attributes['onselect'];
+        return attr ? eval(attr.value) : input;
     }
-    
+
     function getMenuId() {
         return elementId+"-autocomplete";
     }
@@ -213,7 +235,9 @@ Wicket.AutoComplete=function(elementId, 
             document.body.appendChild(container);
                container.style.display="none";
                container.style.overflow="auto";
-            container.style.position="absolute";            
+            container.style.position="absolute";
+            container.style.margin="0px"; // this needs to be 0 or 
size/location calculations would not be exact
+            container.style.padding="0px"; // this needs to be 0 or 
size/location calculations would not be exact
             container.id=getMenuId()+"-container";
                
             container.show = function() { wicketShow(this.id) };
@@ -259,7 +283,7 @@ Wicket.AutoComplete=function(elementId, 
     }
 
     function updateChoices(showAll){
-               selected=-1;
+        setSelected(-1);
         if (showAll) {
             localThrottler.throttle(getMenuId(), throttleDelay, 
actualUpdateChoicesShowAll);
         } else {
@@ -278,7 +302,8 @@ Wicket.AutoComplete=function(elementId, 
     {
        showIndicator();
         var value = wicketGet(elementId).value;
-               var request = new 
Wicket.Ajax.Request(callbackUrl+(callbackUrl.indexOf("?")>-1 ? "&" : "?") + 
"q="+processValue(value), doUpdateChoices, false, true, false, 
"wicket-autocomplete|d");          request.get();
+               var request = new 
Wicket.Ajax.Request(callbackUrl+(callbackUrl.indexOf("?")>-1 ? "&" : "?") + 
"q="+processValue(value), doUpdateChoices, false, true, false, 
"wicket-autocomplete|d");
+               request.get();
     }
     
     function showIndicator() {
@@ -298,33 +323,191 @@ Wicket.AutoComplete=function(elementId, 
     }
 
     function showAutoComplete(){
-        var position=getPosition(wicketGet(elementId));
+        var input = wicketGet(elementId);
         var container = getAutocompleteContainer();
-        var input=wicketGet(elementId);
         var index=getOffsetParentZIndex(elementId);
         container.show();
         if (!isNaN(new Number(index))) {
             container.style.zIndex=(new Number(index)+1);
-        }  
-        container.style.left=position[0]+'px';
-        container.style.top=(input.offsetHeight+position[1])+'px';
-        if(cfg.adjustInputWidth)
-          container.style.width=input.offsetWidth+'px';
-        visible=1;
-        hideShowCovered();
+        } 
+        if (!usefulDimensionsInitialized)
+        {
+            initializeUsefulDimensions(input, container);
+        }
+        if (cfg.adjustInputWidth) {
+          var newW = input.offsetWidth-containerBorderWidths[0];
+          container.style.width = (newW >= 0 ? newW : input.offsetWidth)+'px';
+        }
+          
+        calculateAndSetPopupBounds(input, container);
+        
+        if (visible == 0) {
+            visible = 1;
+            hideShowCovered(true, lastStablePopupBounds[0], 
lastStablePopupBounds[1], lastStablePopupBounds[2], lastStablePopupBounds[3]);
+        }
+    }
+    
+    function initializeUsefulDimensions(input, container) {
+        usefulDimensionsInitialized = true;
+        // a few checks to increase the odds that we can count on 
clientWidth/Height
+        if (typeof (container.clientWidth) != "undefined" && typeof 
(container.clientHeight) != "undefined" && container.clientWidth > 0 && 
container.clientHeight > 0) {
+            var tmp = container.style.overflow; // clientWidth & clientHeight 
exclude border and scollbars
+            container.style.overflow = "visible";
+            containerBorderWidths[0] = container.offsetWidth - 
container.clientWidth;
+            containerBorderWidths[1] = container.offsetHeight - 
container.clientHeight;
+            
+            if (cfg.useSmartPositioning) {
+                container.style.overflow = "scroll";
+                scrollbarSize = container.offsetWidth - container.clientWidth 
- containerBorderWidths[0];
+            }
+            // although border is computed correctly, resizing needs 1 less px 
on FF for some dubious reason...
+            if (Wicket.Browser.isGecko() && containerBorderWidths[0] > 0 && 
containerBorderWidths[1] > 0) {
+                containerBorderWidths[0]--;
+                containerBorderWidths[1]--;
+            }
+            
+            container.style.overflow = tmp;
+        }
     }
 
     function hideAutoComplete(){
         visible=0;
-        selected=-1;
-        if ( getAutocompleteContainer() )
+        setSelected(-1);
+        mouseactive=0;
+        var container = getAutocompleteContainer();
+        if (container)
         {
-               getAutocompleteContainer().hide();
-           hideShowCovered();
+            hideShowCovered(false, lastStablePopupBounds[0], 
lastStablePopupBounds[1], lastStablePopupBounds[2], lastStablePopupBounds[3]);
+            container.hide();
+            if (!cfg.adjustInputWidth && container.style.width != "auto") {
+                container.style.width = "auto"; // let browser auto-set width 
again next time it is shown
+            }
+        }
+    }
+
+    function getWindowWidthAndHeigth() {
+        var myWidth = 0, myHeight = 0;
+        if( typeof( window.innerWidth ) == 'number' ) {
+            //Non-IE
+            myWidth = window.innerWidth;
+            myHeight = window.innerHeight;
+        } else if( document.documentElement && ( 
document.documentElement.clientWidth || document.documentElement.clientHeight ) 
) {
+            //IE 6+ in 'standards compliant mode'
+            myWidth = document.documentElement.clientWidth;
+            myHeight = document.documentElement.clientHeight;
+        } else if( document.body && ( document.body.clientWidth || 
document.body.clientHeight ) ) {
+            //IE 4 compatible
+            myWidth = document.body.clientWidth;
+            myHeight = document.body.clientHeight;
+        }
+        return [ myWidth, myHeight ];
+    }
+
+    function getWindowScrollXY() {
+        var scrOfX = 0, scrOfY = 0;
+        if( typeof( window.pageYOffset ) == 'number' ) {
+            //Netscape compliant
+            scrOfY = window.pageYOffset;
+            scrOfX = window.pageXOffset;
+        } else if( document.body && ( document.body.scrollLeft || 
document.body.scrollTop ) ) {
+            //DOM compliant
+            scrOfY = document.body.scrollTop;
+            scrOfX = document.body.scrollLeft;
+        } else if( document.documentElement && ( 
document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
+            //IE6 standards compliant mode
+            scrOfY = document.documentElement.scrollTop;
+            scrOfX = document.documentElement.scrollLeft;
+        }
+        return [ scrOfX, scrOfY ];
+    }
+
+    function calculateAndSetPopupBounds(input, popup)
+    {
+        var leftPosition=0;
+        var topPosition=0;
+        var inputPosition=getPosition(input);
+        if (cfg.useSmartPositioning) {
+            // there are 4 possible positions for the popup: top-left, 
top-right, buttom-left, bottom-right
+            // relative to the field; we will try to use the position that 
does not get out of the visible page 
+            if (popup.style.width == "auto") {
+                popup.style.left = "0px"; // allow browser to stretch div as 
much as needed to see where the popup should be put
+                popup.style.top = "0px";
+            }
+            var windowScrollXY = getWindowScrollXY();
+            var windowWH = getWindowWidthAndHeigth();
+            var windowScrollX = windowScrollXY[0];
+            var windowScrollY = windowScrollXY[1];
+            var windowWidth = windowWH[0];
+            var windowHeight = windowWH[1];
+            
+            var dx1 = windowScrollX + windowWidth - inputPosition[0] - 
popup.offsetWidth;
+            var dx2 = inputPosition[0] + input.offsetWidth - popup.offsetWidth 
- windowScrollX;
+            if (popup.style.width == "auto" && dx1 < 0 && dx2 < 0) {
+                // browser determined popup width; if it does not fit either 
right or left aligned with the input, calculate and set fixed width
+                // so that after initial position calculation after popup 
opens, bounds do not change every time a mouse over or other event happens.
+                // The browser can change the width/height when div if 
repositioned - if they were not already restricted because of maxHeight and 
field width (and that can result in a relocation of the div and so on).
+                var newW = popup.offsetWidth + Math.max(dx1, dx2) - 
containerBorderWidths[0];
+                popup.style.width = (newW >= 0 ? newW : popup.offsetWidth + 
Math.max(dx1, dx2))+'px';
+                dx1 = windowScrollX + windowWidth - inputPosition[0] - 
popup.offsetWidth;
+                dx2 = inputPosition[0] + input.offsetWidth - popup.offsetWidth 
- windowScrollX;
+            }
+
+            var dy1 = windowScrollY + windowHeight - inputPosition[1] - 
input.offsetHeight - popup.offsetHeight;
+            var dy2 = inputPosition[1] - popup.offsetHeight - windowScrollY;
+            if (dy1 < 0 && dy2 < 0) {
+                // limit height if it gets outside the screen
+                var newH = popup.offsetHeight + Math.max(dy1, dy2) - 
containerBorderWidths[1];
+                popup.style.height = (newH >= 0 ? newH : popup.offsetHeight + 
Math.max(dy1, dy2))+'px';
+                var dy1 = windowScrollY + windowHeight - inputPosition[1] - 
input.offsetHeight - popup.offsetHeight;
+                var dy2 = inputPosition[1] - popup.offsetHeight - 
windowScrollY;
+            }
+            
+            // choose the location that shows the most surface of the popup, 
with preference for bottom right
+            if (dx1 < 0 && dx1 < dx2) {
+                if (dy1 < 0 && dy1 < dy2) {
+                    // choice 4 : top left
+                    leftPosition = inputPosition[0] + input.offsetWidth - 
popup.offsetWidth;
+                    topPosition = inputPosition[1] - popup.offsetHeight;
+                } else {
+                    // choice 3 : bottom left
+                    leftPosition = inputPosition[0] + input.offsetWidth - 
popup.offsetWidth;
+                    topPosition = inputPosition[1] + input.offsetHeight;
+                }
+            } else {
+                if (dy1 < 0 && dy1 < dy2) {
+                    // choice 2 : top right
+                    leftPosition = inputPosition[0];
+                    topPosition = inputPosition[1] - popup.offsetHeight;
+                } else {
+                    // choice 1 : bottom right
+                    leftPosition = inputPosition[0];
+                    topPosition = inputPosition[1] + input.offsetHeight;
+                }
+            }
+            if (popup.style.width == "auto") {
+                var newW = popup.offsetWidth - containerBorderWidths[0];
+                popup.style.width = (newW >= 0 ? newW : 
popup.offsetWidth)+'px';
+            }
+        } else {
+            leftPosition = inputPosition[0];
+            topPosition = inputPosition[1] + input.offsetHeight;
+        }
+        popup.style.left=leftPosition+'px';
+        popup.style.top=topPosition+'px';
+        
+        if (visible == 1 &&
+                (lastStablePopupBounds[0] != popup.offsetLeft ||
+                 lastStablePopupBounds[1] != popup.offsetTop ||
+                 lastStablePopupBounds[2] != popup.offsetWidth ||
+                 lastStablePopupBounds[3] != popup.offsetHeight)) {
+            hideShowCovered(false, lastStablePopupBounds[0], 
lastStablePopupBounds[1], lastStablePopupBounds[2], lastStablePopupBounds[3]); 
// show previously hidden
+            hideShowCovered(true, popup.offsetLeft, popup.offsetTop, 
popup.offsetWidth, popup.offsetHeight); // hide ones under new bounds
         }
+
+        lastStablePopupBounds = [popup.offsetLeft, popup.offsetTop, 
popup.offsetWidth, popup.offsetHeight];
     }
 
-        function getPosition(obj) {
+    function getPosition(obj) {
         var leftPosition = obj.offsetLeft || 0;
         var topPosition = obj.offsetTop || 0;
         obj = obj.offsetParent;
@@ -335,7 +518,7 @@ Wicket.AutoComplete=function(elementId, 
                leftPosition -= obj.scrollLeft || 0;
             obj = obj.offsetParent;
         }
- 
+
         return [leftPosition,topPosition];
     }
     
@@ -349,53 +532,55 @@ Wicket.AutoComplete=function(elementId, 
                        hideIndicator();
                        return;
                }
-    
+
         var element = getAutocompleteMenu();
+        if (!cfg.adjustInputWidth && element.parentNode && 
element.parentNode.style.width != "auto") {
+            element.parentNode.style.width = "auto"; // let browser auto-set 
width again as displayed elements may change
+            selChSinceLastRender = true; // selected item will not have 
selected style until rendrered
+        }
         element.innerHTML=resp;
         if(element.firstChild && element.firstChild.childNodes) {
-               elementCount=element.firstChild.childNodes.length;
+                   elementCount=element.firstChild.childNodes.length;
 
-               var clickFunc = function(event){
-                       mouseactive=0;
-                       var value = getSelectedValue();
-                       if(value = handleSelection(value)) {
-                               wicketGet(elementId).value=value;
-                               if (typeof objonchange=="function") 
{objonchange.apply(wicketGet(elementId), [event]);}
-                       }
-                       hideAutoComplete();
-                if (Wicket.Focus.getFocusedElement() != input)
-                {
+            var clickFunc = function(event) {
+                mouseactive = 0;
+                var value = getSelectedValue();
+                var input = wicketGet(elementId);
+                if(value = handleSelection(value)) {
+                  input.value = value;
+                  if(typeof objonchange=="function") 
objonchange.apply(input,[event]);
+                }
+                hideAutoComplete();
+                if (Wicket.Focus.getFocusedElement() != input) {
                     ignoreOneFocusGain = true;
                     input.focus();
                 }
-               };
+            };
                        
-               var mouseOverFunc = function(event){
-                mouseactive=1; // Opera needs this as mousemove for menu is 
not always triggered
-                       selected = getElementIndex(this);
-                       render();
-                       showAutoComplete();
-               };
-
-               var parentNode = element.firstChild;
-               for(var i = 0;i < elementCount; i++) {
-                       var node = parentNode.childNodes[i];
-                       node.onclick = clickFunc;
-                       node.onmouseover = mouseOverFunc;
-               }
+            var mouseOverFunc = function(event) {
+                setSelected(getElementIndex(this));
+                render(false); // don't scroll - breaks mouse weel scrolling
+                showAutoComplete();
+            };
+            var parentNode = element.firstChild; 
+            for(var i = 0;i < elementCount; i++) {
+                var node = parentNode.childNodes[i];
+                node.onclick = clickFunc;
+                node.onmouseover = mouseOverFunc;
+            }
         } else {
             elementCount=0;
         }
 
         if(elementCount>0){
-                if(cfg.preselect==true){
-                        selected = 0;
-                }            
-                showAutoComplete();
+            if(cfg.preselect==true){
+                setSelected(0);
+            }            
+            showAutoComplete();
         } else {
             hideAutoComplete();
         }
-        render();
+        render(false);
         
         scheduleEmptyCheck();
         
@@ -437,31 +622,33 @@ Wicket.AutoComplete=function(elementId, 
         return str.replace(/<[^>]+>/g,"");
     }
     
-    function adjustScrollOffset(menu, item) {          
+    function adjustScrollOffset(menu, item) { // this should consider 
margins/paddings; now it is not exact
        if (item.offsetTop + item.offsetHeight > menu.scrollTop + 
menu.offsetHeight) {
                        menu.scrollTop = item.offsetTop + item.offsetHeight - 
menu.offsetHeight;
                } else
                // adjust to the top
                if (item.offsetTop < menu.scrollTop) {
                        menu.scrollTop = item.offsetTop;
-               }       
+               }
     }
 
-    function render(){
+    function render(adjustScroll){
         var menu=getAutocompleteMenu();
         var height=0;
                var node=menu.firstChild.childNodes[0];
                var re = /\bselected\b/gi;
+               var sizeAffected = false;
         for(var i=0;i<elementCount;i++)
                {
             var origClassNames = node.className;
                        var classNames = origClassNames.replace(re, "");
                        if(selected==i){
                                classNames += " selected";
-                               adjustScrollOffset(menu.parentNode, node);
+                               if (adjustScroll) 
adjustScrollOffset(menu.parentNode, node);
                        }
-                       if (classNames != origClassNames)
+                       if (classNames != origClassNames) {
                 node.className = classNames;
+            }
        
                        if (cfg.maxHeight > -1)
                                height+=node.offsetHeight;
@@ -469,12 +656,27 @@ Wicket.AutoComplete=function(elementId, 
                        node = node.nextSibling;
                }
         if (cfg.maxHeight > -1) {
-               if (height<cfg.maxHeight) {
-                menu.parentNode.style.height="auto";
-            } else {
-                   menu.parentNode.style.height=cfg.maxHeight+"px";
+            if (initialDelta == -1)
+            {
+                // remember size occupied by parent border, padding, and 
menu+ul margins, border, padding
+                initialDelta = menu.parentNode.offsetHeight - height;
+            }
+            if (height + initialDelta > cfg.maxHeight) {
+                var newH = cfg.maxHeight - containerBorderWidths[1];
+                menu.parentNode.style.height = (newH >= 0 ? newH : 
cfg.maxHeight) + "px";
+                sizeAffected = true;
+            } else if (menu.parentNode.style.height != "auto") { // if height 
is limited
+                menu.parentNode.style.height = "auto"; // no limiting, let 
popup determine it's own height
+                sizeAffected = true;
             }
         }
+        if (cfg.useSmartPositioning && !cfg.adjustInputWidth && 
menu.parentNode.style.width != "auto" && selChSinceLastRender) {
+            // selected item has different padding - so the preferred width of 
the popup might want to change so as not to wrap it
+            selChSinceLastRender = false;
+            menu.parentNode.style.width = "auto";
+            sizeAffected = true;
+        }
+        if (sizeAffected) calculateAndSetPopupBounds(wicketGet(elementId), 
menu.parentNode); // update stuff related to bounds if needed 
     }
     
     // From 
http://www.robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
@@ -511,49 +713,35 @@ Wicket.AutoComplete=function(elementId, 
        return index;
     }
 
-    function hideShowCovered(){
-        if (!/msie/i.test(navigator.userAgent) && 
!/opera/i.test(navigator.userAgent)) {
+    function hideShowCovered(popupVisible, acLeftX, acTopY, acWidth, acHeight) 
{
+        if (!cfg.useHideShowCoveredIEFix || 
(!/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent))) {
             return;
         }
-        // IE7 fix, if this doesn't go in a timeout then the complete page 
could become invisible.
-        // when closing the popup.
-               setTimeout(hideShowCoveredTimeout,1);
-    }
-    
-    function hideShowCoveredTimeout(){
-               var el=getAutocompleteContainer();
-        var p=getPosition(el);
-
-        var acLeftX=p[0];
-        var acRightX=el.offsetWidth+acLeftX;
-        var acTopY=p[1];
-        var acBottomY=el.offsetHeight+acTopY;
 
         var hideTags=new Array("select","iframe","applet");
+        var acRightX = acLeftX + acWidth;
+        var acBottomY = acTopY + acHeight;
 
         for (var j=0;j<hideTags.length;j++) {
             var tagsFound=document.getElementsByTagName(hideTags[j]);
             for (var i=0; i<tagsFound.length; i++){
                 var tag=tagsFound[i];
-                p=getPosition(tag);
+                var p=getPosition(tag); // maybe determine only visible area 
of tag somehow? as it could be in a small scrolled container...
                 var leftX=p[0];
                 var rightX=leftX+tag.offsetWidth;
                 var topY=p[1];
                 var bottomY=topY+tag.offsetHeight;
 
-                if (this.hidden || (leftX>acRightX) || (rightX<acLeftX) || 
(topY>acBottomY) || (bottomY<acTopY)) {
-                    if(!tag.wicket_element_visibility) {
-                        tag.wicket_element_visibility=isVisible(tag);
-                    }
-                    tag.style.visibility=tag.wicket_element_visibility;
+                if (!tag.wicket_element_visibility) {
+                    tag.wicket_element_visibility=isVisible(tag);
+                }
+                if (popupVisible==0 || (leftX>acRightX) || (rightX<acLeftX) || 
(topY>acBottomY) || (bottomY<acTopY)) {
+                    tag.style.visibility = tag.wicket_element_visibility;
                                } else {
-                                       if (!tag.wicket_element_visibility) {
-                                               
tag.wicket_element_visibility=isVisible(tag);
-                                       }
                     tag.style.visibility = "hidden";
                 }
             }
-        }        
+        }
     }
 
     initialize();


Reply via email to