Changeset 9136

Show
Ignore:
Timestamp:
06/14/07 11:25:29 (19 months ago)
Author:
bill
Message:

Make popup tooltip appear on left if no space on right. Refs #3267.
Major refactor of popup code. Refs #3423.

Location:
dijit/trunk
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • dijit/trunk/tests/test_Tooltip.html

    r9096 r9136  
    4040        <span id="btnTt" dojoType="dijit.Tooltip" connectId="four" caption="tooltip on button" style="display:none;"></span> 
    4141 
    42         <select id="seven"> 
    43                 <option value="alpha">Alpha</option> 
    44                 <option value="beta">Beta</option> 
    45                 <option value="gamma">Gamma</option> 
    46                 <option value="delta">Delta</option> 
    47         </select> 
    48  
    49         <span dojoType="dijit.Tooltip" connectId="seven" style="display:none;"> 
    50                 tooltip on a select<br> 
    51                 two line tooltip. 
     42        <span style="float: right"> 
     43                Test tooltip on right aligned element.  Tooltip should flow to the left --&gt; 
     44                <select id="seven"> 
     45                        <option value="alpha">Alpha</option> 
     46                        <option value="beta">Beta</option> 
     47                        <option value="gamma">Gamma</option> 
     48                        <option value="delta">Delta</option> 
     49                </select> 
     50         
     51                <span dojoType="dijit.Tooltip" connectId="seven" style="display:none;"> 
     52                        tooltip on a select<br> 
     53                        two line tooltip. 
     54                </span> 
    5255        </span> 
    5356 
  • dijit/trunk/Tooltip.js

    r9130 r9136  
    5252                        // position the element and change CSS according to position     
    5353                        var align = this.isLeftToRight() ? {'BR': 'BL', 'BL': 'BR'} : {'BL': 'BR', 'BR': 'BL'}; 
    54                         dijit.util.placeOnScreenAroundElement(this.domNode, aroundNode, align); 
    55                         // TODO: need to know which position placeOnScreenAroundElement picked 
    56                         this.domNode.className="dijitTooltip dijitTooltip" + (this.isLeftToRight() ? "Right" : "Left"); 
     54                        var pos = dijit.util.placeOnScreenAroundElement(this.domNode, aroundNode, align); 
     55                        this.domNode.className="dijitTooltip dijitTooltip" + (pos.corner=='BL' ? "Right" : "Left"); 
    5756                         
    5857                        // show it 
  • dijit/trunk/util/place.js

    r9133 r9136  
    4242        } 
    4343}; 
     44// TODO: combine above two functions 
    4445 
    4546dijit.util.placeOnScreen = function( 
    4647        /* HTMLElement */       node, 
    47         /* Object */            desiredPos, 
     48        /* Object */            pos, 
    4849        /* Object */            corners, 
    4950        /* boolean? */          tryOnly){ 
    5051        //      summary: 
    5152        //              Keeps 'node' in the visible area of the screen while trying to 
    52         //              place closest to desiredPos.x, desiredPos.y. The input coordinates are 
     53        //              place closest to pos.x, pos.y. The input coordinates are 
    5354        //              expected to be the desired document position. 
    5455        // 
     
    6162        //              and if a perfect match is found, it will be used. Otherwise, it goes through 
    6263        //              all of the specified corners, and choose the most appropriate one. 
    63         // 
    64         //              If tryOnly is set to true, the node will not be moved to the place. 
    6564        //               
    6665        //              NOTE: node is assumed to be absolutely or relatively positioned. 
     66         
     67        var choices = dojo.map(corners, function(corner){ return { corner: corner, pos: pos }; }); 
     68         
     69        return dijit.util._place(node, choices); 
     70} 
    6771 
    68         var scroll = dijit.util.getScroll(); 
    69         var view = dijit.util.getViewport(); 
     72dijit.util._place = function(/*HtmlElement*/ node, /* Array */ choices){ 
     73        // summary: 
     74        //              Given a list of spots to put node, put it at the first spot where it fits, 
     75        //              of if it doesn't fit anywhere then the place with the least overflow 
     76        // choices: Array 
     77        //              Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } 
     78        //              Above example says to put the top-left corner of the node at (10,20) 
     79                         
     80        // get {x: 10, y: 10, w: 100, h:100} type obj representing position of 
     81        // viewport over document 
     82        var view = dojo.mixin(dijit.util.getViewport(), dijit.util.getScroll()); 
    7083 
    71         node = dojo.byId(node); 
     84        // This won't work if the node is inside a <div style="position: relative">, 
     85        // so reattach it to document.body.   (Otherwise, the positioning will be wrong 
     86        // and also it might get cutoff) 
     87        if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ 
     88                dojo.body().appendChild(node); 
     89        } 
     90 
     91        // get node margin box size 
    7292        var oldDisplay = node.style.display; 
    7393        var oldVis = node.style.visibility; 
    7494        node.style.visibility = "hidden"; 
    7595        node.style.display = ""; 
    76 //      var bb = dojo.html.getBorderBox(node); 
    77         var bb = dojo.marginBox(node); //PORT okay? 
    78         var w = bb.w; 
    79         var h = bb.h; 
     96        var mb = dojo.marginBox(node); 
    8097        node.style.display = oldDisplay; 
    8198        node.style.visibility = oldVis; 
    8299 
    83         //#2670 
    84         var visiblew,visibleh,bestw,besth=""; 
     100        var best=null; 
     101        for(var i=0; i<choices.length; i++){ 
     102                var corner = choices[i].corner; 
     103                var pos = choices[i].pos; 
    85104 
    86         var bestx, besty, bestDistance = Infinity, bestCorner; 
    87  
    88         for(var cidex=0; cidex<corners.length; ++cidex){ 
    89                 var visiblew,visibleh=""; 
    90                 var corner = corners[cidex]; 
    91                 var match = true; 
    92  
    93                 // guess where to put the upper left corner of the popup, based on which corner was passed 
    94                 // if you choose a corner other than the upper left, 
    95                 // obviously you have to move the popup 
    96                 // so that the selected corner is at the x,y you asked for 
    97                 var tryX = desiredPos.x - (corner.charAt(1)=='L' ? 0 : w) - scroll.x; 
    98                 var tryY = desiredPos.y - (corner.charAt(0)=='T' ? 0 : h) - scroll.y; 
    99  
    100                 // x component 
    101                 // test if the popup does not fit 
    102                 var x = tryX + w; 
    103                 if(x > view.w){ 
    104                         match = false; 
     105                // coordinates and size of node with specified corner placed at pos, 
     106                // and clipped by viewport 
     107                var startX = (corner.charAt(1)=='L' ? pos.x : Math.max(view.x, pos.x - mb.w)), 
     108                        startY = (corner.charAt(0)=='T' ? pos.y : Math.max(view.y, pos.y -  mb.h)), 
     109                        endX = (corner.charAt(1)=='L' ? Math.min(view.x+view.w, startX+mb.w) : pos.x), 
     110                        endY = (corner.charAt(0)=='T' ? Math.min(view.y+view.h, startY+mb.h) : pos.y), 
     111                        width = endX-startX, 
     112                        height = endY-startY, 
     113                        overflow = (mb.w-width) + (mb.h-height); 
     114                         
     115                if(best==null || overflow<best.overflow){ 
     116                        best = { 
     117                                corner: corner, 
     118                                aroundCorner: choices[i].aroundCorner, 
     119                                x: startX, 
     120                                y: startY, 
     121                                w: width, 
     122                                h: height, 
     123                                overflow: overflow 
     124                        }; 
    105125                } 
    106                 // viewport => document 
    107                 // min: left side of screen 
    108                 x = tryX + scroll.x; 
    109                 // calculate the optimal width of the popup 
    110                 if(corner.charAt(1)=='L'){ 
    111                         if(w>view.w-tryX){ 
    112                                 visiblew=view.w-tryX; 
    113                                 match=false; 
    114                         }else{ 
    115                                 visiblew=w; 
    116                         } 
    117                 }else{ 
    118                         if(tryX<0){ 
    119                                 visiblew=w+tryX; 
    120                                 match=false; 
    121                         }else{ 
    122                                 visiblew=w; 
    123                         } 
    124                 } 
    125                 // y component 
    126                 // test if the popup does not fit 
    127                 var y = tryY + h; 
    128                 if(y > view.h){ 
    129                         match = false; 
    130                 } 
    131                 // viewport => document 
    132                 // min: top side of screen 
    133                 y = tryY + scroll.y; 
    134                 // calculate the optimal height of the popup 
    135                 if(corner.charAt(0)=='T'){ 
    136                         if(h>view.h-tryY){ 
    137                                 visibleh=view.h-tryY; 
    138                                 match=false; 
    139                         }else{ 
    140                                 visibleh=h; 
    141                         } 
    142                 }else{ 
    143                         if(tryY<0){ 
    144                                 visibleh=h+tryY; 
    145                                 match=false; 
    146                         }else{ 
    147                                 visibleh=h; 
    148                         } 
    149                 } 
    150  
    151                 if(match){ //perfect match, return now 
    152                         bestx = x; 
    153                         besty = y; 
    154                         bestDistance = 0; 
    155                         bestw = visiblew; 
    156                         besth = visibleh; 
    157                         bestCorner = corner; 
     126                if(overflow==0){ 
    158127                        break; 
    159                 }else{ 
    160                         //not perfect, find out whether it is better than the saved one 
    161                         // weight this position by its squared distance 
    162                         var dist = Math.pow(x-tryX-scroll.x,2)+Math.pow(y-tryY-scroll.y,2); 
    163                         // if there was not a perfect match but dist=0 anyway (popup too small) weight by size of popup 
    164                         if(dist==0){dist=Math.pow(h-visibleh,2);} 
    165                         // choose the lightest (closest or biggest popup) position 
    166                         if(bestDistance > dist){ 
    167                                 bestDistance = dist; 
    168                                 bestx = x; 
    169                                 besty = y; 
    170                                 bestw = visiblew; 
    171                                 besth = visibleh; 
    172                                 bestCorner = corner; 
    173                         } 
    174128                } 
    175129        } 
    176130 
    177         if(!tryOnly){ 
    178                 node.style.left = bestx + "px"; 
    179                 node.style.top = besty + "px"; 
    180         } 
    181  
    182         return {left: bestx, top: besty, x: bestx, y: besty, dist: bestDistance, corner:  bestCorner, h:besth, w:bestw};        //      object 
     131        node.style.left = best.x + "px"; 
     132        node.style.top = best.y + "px"; 
     133        return best; 
    183134} 
    184135 
     
    197148        //              corners parameter in dijit.util.placeOnScreen) 
    198149        //              e.g. {'TL': 'BL', 'BL': 'TL'} 
    199  
    200         // This won't work if the node is inside a <div style="position: relative">, 
    201         // so reattach it to document.body.   (Otherwise, the positioning will be wrong 
    202         // and also it might get cutoff) 
    203         if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ 
    204                 dojo.body().appendChild(node); 
    205         } 
    206  
    207         var best, bestDistance=Infinity; 
     150         
     151        // get coordinates of aroundNode 
    208152        aroundNode = dojo.byId(aroundNode); 
    209153        var oldDisplay = aroundNode.style.display; 
    210154        aroundNode.style.display=""; 
    211155        // #3172: use the slightly tighter border box instead of marginBox 
    212         //var mb = dojo.marginBox(aroundNode); 
    213         //aroundNode.style.borderWidth="10px"; 
    214156        var aroundNodeW = aroundNode.offsetWidth; //mb.w; 
    215157        var aroundNodeH = aroundNode.offsetHeight; //mb.h; 
     
    217159        aroundNode.style.display=oldDisplay; 
    218160 
     161        // Generate list of possible positions for node 
     162        var choices = []; 
    219163        for(var nodeCorner in aroundCorners){ 
    220                 var corners = aroundCorners[nodeCorner]; 
    221  
    222                 var desiredPos = { 
    223                         x: aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW), 
    224                         y: aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH) 
    225                 }; 
    226  
    227                 var pos = dijit.util.placeOnScreen(node, desiredPos, [corners], true); 
    228                 if(pos.dist == 0){ 
    229                         best = pos; 
    230                         break; 
    231                 }else{ 
    232                         //not perfect, find out whether it is better than the saved one 
    233                         if(bestDistance > pos.dist){ 
    234                                 bestDistance = pos.dist; 
    235                                 best = pos; 
     164                choices.push( { 
     165                        aroundCorner: nodeCorner, 
     166                        corner: aroundCorners[nodeCorner], 
     167                        pos: { 
     168                                x: aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW), 
     169                                y: aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH) 
    236170                        } 
    237                 } 
     171                }); 
    238172        } 
    239  
    240         node.style.left = best.left + "px"; 
    241         node.style.top = best.top + "px"; 
    242  
    243         return best;    //      object 
     173         
     174        return dijit.util._place(node, choices); 
    244175} 
  • dijit/trunk/util/popup.js

    r9133 r9136  
    7070                var best = args.around ? 
    7171                        dijit.util.placeOnScreenAroundElement(wrapper, args.around, args.orient) : 
    72                         dijit.util.placeOnScreen(wrapper, args, ['TL','BL','BL','BR']); 
     72                        dijit.util.placeOnScreen(wrapper, args, ['TL','BL','TR','BR']); 
    7373 
    7474                // TODO: use effects to fade in wrapper