1 /* See license.txt for terms of usage */
  2 
  3 FBL.ns(function() { with (FBL) {
  4 
  5 // ************************************************************************************************
  6 // Constants
  7 
  8 const maxWidth = 100, maxHeight = 80;
  9 const infoTipMargin = 10;
 10 const infoTipWindowPadding = 25;
 11 
 12 // ************************************************************************************************
 13 
 14 Firebug.InfoTip = extend(Firebug.Module,
 15 {
 16     dispatchName: "infoTip",
 17     tags: domplate(
 18     {
 19         infoTipTag: DIV({"class": "infoTip"}),
 20 
 21         colorTag:
 22             DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, " "),
 23 
 24         imgTag:
 25             DIV({"class": "infoTipImageBox infoTipLoading"},
 26                 IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat",
 27                     onload: "$onLoadImage"}),
 28                 IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}),
 29                 DIV({"class": "infoTipCaption"})
 30             ),
 31 
 32         onLoadImage: function(event)
 33         {
 34             var img = event.currentTarget;
 35             var bgImg = img.nextSibling;
 36             if (!bgImg)
 37                 return; // Sometimes gets called after element is dead
 38 
 39             var caption = bgImg.nextSibling;
 40             var innerBox = img.parentNode;
 41 
 42             var w = img.naturalWidth, h = img.naturalHeight;
 43             var repeat = img.getAttribute("repeat");
 44 
 45             if (repeat == "repeat-x" || (w == 1 && h > 1))
 46             {
 47                 collapse(img, true);
 48                 collapse(bgImg, false);
 49                 bgImg.style.background = "url(" + img.src + ") repeat-x";
 50                 bgImg.style.width = maxWidth + "px";
 51                 if (h > maxHeight)
 52                     bgImg.style.height = maxHeight + "px";
 53                 else
 54                     bgImg.style.height = h + "px";
 55             }
 56             else if (repeat == "repeat-y" || (h == 1 && w > 1))
 57             {
 58                 collapse(img, true);
 59                 collapse(bgImg, false);
 60                 bgImg.style.background = "url(" + img.src + ") repeat-y";
 61                 bgImg.style.height = maxHeight + "px";
 62                 if (w > maxWidth)
 63                     bgImg.style.width = maxWidth + "px";
 64                 else
 65                     bgImg.style.width = w + "px";
 66             }
 67             else if (repeat == "repeat" || (w == 1 && h == 1))
 68             {
 69                 collapse(img, true);
 70                 collapse(bgImg, false);
 71                 bgImg.style.background = "url(" + img.src + ") repeat";
 72                 bgImg.style.width = maxWidth + "px";
 73                 bgImg.style.height = maxHeight + "px";
 74             }
 75             else
 76             {
 77                 if (w > maxWidth || h > maxHeight)
 78                 {
 79                     if (w > h)
 80                     {
 81                         img.style.width = maxWidth + "px";
 82                         img.style.height = Math.round((h / w) * maxWidth) + "px";
 83                     }
 84                     else
 85                     {
 86                         img.style.width = Math.round((w / h) * maxHeight) + "px";
 87                         img.style.height = maxHeight + "px";
 88                     }
 89                 }
 90             }
 91 
 92             caption.innerHTML = $STRF("Dimensions", [w, h]);
 93 
 94             removeClass(innerBox, "infoTipLoading");
 95         }
 96     }),
 97 
 98     initializeBrowser: function(browser)
 99     {
100         browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser);
101         browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser);
102 
103         var doc = browser.contentDocument;
104         if (!doc)
105             return;
106 
107         doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true);
108         doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true);
109         doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true);
110 
111         return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc));
112     },
113 
114     uninitializeBrowser: function(browser)
115     {
116         if (browser.infoTip)
117         {
118             var doc = browser.contentDocument;
119             doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true);
120             doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true);
121             doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true);
122 
123             browser.infoTip.parentNode.removeChild(browser.infoTip);
124             delete browser.infoTip;
125             delete browser.onInfoTipMouseMove;
126         }
127     },
128 
129     showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset)
130     {
131         if (!Firebug.showInfoTips)
132             return;
133 
134         var scrollParent = getOverflowParent(target);
135         var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0);
136 
137         if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset))
138         {
139             var htmlElt = infoTip.ownerDocument.documentElement;
140             var panelWidth = htmlElt.clientWidth;
141             var panelHeight = htmlElt.clientHeight;
142 
143             if (x+infoTip.offsetWidth+infoTipMargin > panelWidth)
144             {
145                 infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px";
146                 infoTip.style.right = "auto";
147             }
148             else
149             {
150                 infoTip.style.left = (x+infoTipMargin) + "px";
151                 infoTip.style.right = "auto";
152             }
153 
154             if (y+infoTip.offsetHeight+infoTipMargin > panelHeight)
155             {
156                 infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px";
157                 infoTip.style.bottom = "auto";
158             }
159             else
160             {
161                 infoTip.style.top = (y+infoTipMargin) + "px";
162                 infoTip.style.bottom = "auto";
163             }
164 
165             if (FBTrace.DBG_INFOTIP)
166                 FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top +
167                     ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom +
168                     ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight +
169                     ", offsetWidth: " + infoTip.offsetWidth +
170                     ", x: " + x + ", panelWidth: " + panelWidth +
171                     ", y: " + y + ", panelHeight: " + panelHeight);
172 
173             infoTip.setAttribute("active", "true");
174         }
175         else
176             this.hideInfoTip(infoTip);
177     },
178 
179     hideInfoTip: function(infoTip)
180     {
181         if (infoTip)
182             infoTip.removeAttribute("active");
183     },
184 
185     onMouseOut: function(event, browser)
186     {
187         if (!event.relatedTarget)
188             this.hideInfoTip(browser.infoTip);
189     },
190 
191     onMouseMove: function(event, browser)
192     {
193         // Ignore if the mouse is moving over the existing info tip.
194         if (getAncestorByClass(event.target, "infoTip"))
195             return;
196 
197         if (browser.currentPanel)
198         {
199             var x = event.clientX, y = event.clientY;
200             this.showInfoTip(browser.infoTip, browser.currentPanel, event.target, x, y, event.rangeParent, event.rangeOffset);
201         }
202         else
203             this.hideInfoTip(browser.infoTip);
204     },
205 
206     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
207 
208     populateColorInfoTip: function(infoTip, color)
209     {
210         this.tags.colorTag.replace({rgbValue: color}, infoTip);
211         return true;
212     },
213 
214     populateImageInfoTip: function(infoTip, url, repeat)
215     {
216         if (!repeat)
217             repeat = "no-repeat";
218 
219         this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip);
220 
221         return true;
222     },
223 
224     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
225     // extends Module
226 
227     disable: function()
228     {
229         // XXXjoe For each browser, call uninitializeBrowser
230     },
231 
232     showPanel: function(browser, panel)
233     {
234         if (panel)
235         {
236             var infoTip = panel.panelBrowser.infoTip;
237             if (!infoTip)
238                 infoTip = this.initializeBrowser(panel.panelBrowser);
239             this.hideInfoTip(infoTip);
240         }
241 
242     },
243 
244     showSidePanel: function(browser, panel)
245     {
246         this.showPanel(browser, panel);
247     }
248 });
249 
250 // ************************************************************************************************
251 
252 Firebug.registerModule(Firebug.InfoTip);
253 
254 // ************************************************************************************************
255 
256 }});
257