001package com.hfg.javascript;
002
003import java.util.Map;
004import java.util.HashMap;
005
006import com.hfg.html.HTML;
007import com.hfg.util.StringUtil;
008import com.hfg.xml.XMLNode;
009import com.hfg.svg.SvgNode;
010
011//------------------------------------------------------------------------------
012/**
013  Generic tooltip generation javascript.
014  Tooltips can be added to any tag which supports onmouseover and onmouseout.
015  You will also need to add generateJS() to the javascript in the page's <head> tag.
016  <p>
017  See <a href='doc-files/tooltipTest.html' target='_parent'>this page</a> for tooltip examples.
018  </p>
019
020  <div>Simple code example:
021  <pre>
022       <b>TooltipJS tooltip = new TooltipJS();</b>
023
024       HTMLDoc htmlDoc = new HTMLDoc();
025
026       // Keep IE from going into quirks mode.
027       htmlDoc.setDoctype(Doctype.HTML_4_01_TRANSITIONAL_NO_URL);
028
029       HTML html = new HTML();
030       htmlDoc.setRootTag(html);
031       html.getHead().addSubtag(Meta.CONTENT_TYPE_ISO_8859_1);
032
033       <b>// Add the necessary javascript to the page.
034       html.getHead().addJavascript(tooltip.generateJS());</b>
035
036       Body body = html.getBody();
037       body.br(2);
038
039       // Create the target tag (in this case a span) the tooltip will function on.
040       Span testSpan = body.addSpan("Test span");
041
042       <b>// Create the tooltip content
043       Pre tooltip1Content = new Pre("foobar and all that stuff\n");
044       tooltip1Content.addSpan("just grinds my axe!\n").setStyle(CSS.BOLD + CSS.fontSize(24));
045
046       // Attach the tooltip to the target.
047       tooltip.addTooltip(testSpan, tooltip1Content.toHTML());</b>
048
049  </pre>
050  </div>
051
052  @author J. Alex Taylor, hairyfatguy.com
053 */
054//------------------------------------------------------------------------------
055// com.hfg XML/HTML Coding Library
056//
057// This library is free software; you can redistribute it and/or
058// modify it under the terms of the GNU Lesser General Public
059// License as published by the Free Software Foundation; either
060// version 2.1 of the License, or (at your option) any later version.
061//
062// This library is distributed in the hope that it will be useful,
063// but WITHOUT ANY WARRANTY; without even the implied warranty of
064// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
065// Lesser General Public License for more details.
066//
067// You should have received a copy of the GNU Lesser General Public
068// License along with this library; if not, write to the Free Software
069// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
070//
071// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
072// jataylor@hairyfatguy.com
073//------------------------------------------------------------------------------
074
075public class TooltipJS
076{
077   //##########################################################################
078   // PRIVATE FIELDS
079   //##########################################################################
080
081   private int     mDelay          = 500;
082   private int     mXOffset        = 10;
083   private int     mYOffset        = 20;
084   private int     mMaxWidth       = 300;
085   private String  mBorder         = "1px solid #666666";
086   private String  mFont           = "arial,sans-serif";
087   private String  mFontSize       = "11px";
088   private String  mFontColor      = "#006600";
089   private String  mBgColor        = "#eeffee";
090   private int     mPadding        = 3;
091   private String  mShadowColor    = "#000000";
092   private int     mShadowOffset   = 3;
093   private boolean mAddOnMouseMove = false;
094
095   private String  mCachedJs;
096
097   //##########################################################################
098   // CONSTRUCTORS
099   //##########################################################################
100
101   //--------------------------------------------------------------------------
102   public TooltipJS()
103   {
104   }
105
106   //##########################################################################
107   // PUBLIC METHODS
108   //##########################################################################
109
110   //--------------------------------------------------------------------------
111   public TooltipJS setDelay(int inValue)
112   {
113      if (inValue != mDelay)
114      {
115         mDelay = inValue;
116         mCachedJs = null; // Invalidate the cache.
117      }
118      return this;
119   }
120
121   //--------------------------------------------------------------------------
122   public TooltipJS setXOffset(int inValue)
123   {
124      if (inValue != mXOffset)
125      {
126         mXOffset = inValue;
127         mCachedJs = null; // Invalidate the cache.
128      }
129      return this;
130   }
131
132   //--------------------------------------------------------------------------
133   public TooltipJS setYOffset(int inValue)
134   {
135      if (inValue != mYOffset)
136      {
137         mYOffset = inValue;
138         mCachedJs = null; // Invalidate the cache.
139      }
140      return this;
141   }
142
143   //--------------------------------------------------------------------------
144   public TooltipJS setBorder(String inValue)
145   {
146      if (null == inValue)
147      {
148         throw new RuntimeException("The border cannot be set to null!");
149      }
150
151      if (! inValue.equals(mBorder))
152      {
153         mBorder = inValue;
154         mCachedJs = null; // Invalidate the cache.
155      }
156      return this;
157   }
158
159   //--------------------------------------------------------------------------
160   public TooltipJS setFont(String inValue)
161   {
162      if (null == inValue)
163      {
164         throw new RuntimeException("The font cannot be set to null!");
165      }
166
167      if (! inValue.equals(mFont))
168      {
169         mFont = inValue;
170         mCachedJs = null; // Invalidate the cache.
171      }
172      return this;
173   }
174
175   //--------------------------------------------------------------------------
176   public TooltipJS setFontSize(String inValue)
177   {
178      if (null == inValue)
179      {
180         throw new RuntimeException("The font size cannot be set to null!");
181      }
182
183      if (! inValue.equals(mFontSize))
184      {
185         mFontSize = inValue;
186         mCachedJs = null; // Invalidate the cache.
187      }
188      return this;
189   }
190
191   //--------------------------------------------------------------------------
192   public TooltipJS setFontColor(String inValue)
193   {
194      if (null == inValue)
195      {
196         throw new RuntimeException("The font color cannot be set to null!");
197      }
198
199      if (! inValue.equals(mFontColor))
200      {
201         mFontColor = inValue;
202         mCachedJs = null; // Invalidate the cache.
203      }
204      return this;
205   }
206
207   //--------------------------------------------------------------------------
208   public TooltipJS setBackgroundColor(String inValue)
209   {
210      if (null == inValue)
211      {
212         throw new RuntimeException("The background color cannot be set to null!");
213      }
214
215      if (! inValue.equals(mBgColor))
216      {
217         mBgColor = inValue;
218         mCachedJs = null; // Invalidate the cache.
219      }
220      return this;
221   }
222
223   //--------------------------------------------------------------------------
224   public TooltipJS setPadding(int inValue)
225   {
226      if (inValue != mPadding)
227      {
228         mPadding = inValue;
229         mCachedJs = null; // Invalidate the cache.
230      }
231      return this;
232   }
233
234   //--------------------------------------------------------------------------
235   public TooltipJS setShadowColor(String inValue)
236   {
237      if (null == inValue)
238      {
239         throw new RuntimeException("The shadow color cannot be set to null!");
240      }
241
242      if (! inValue.equals(mShadowColor))
243      {
244         mShadowColor = inValue;
245         mCachedJs = null; // Invalidate the cache.
246      }
247      return this;
248   }
249
250   //--------------------------------------------------------------------------
251
252   /**
253    Sets the suggested maximum width for tooltips. If content cannot be
254    squeezed into this width, such as is sometimes the case with Pre's, tables, etc.,
255    the the tooltip will grow. It will always enclose all of the content.
256    * @param inValue
257    */
258   public TooltipJS setMaxWidth(int inValue)
259   {
260      if (inValue != mMaxWidth)
261      {
262         mMaxWidth = inValue;
263         mCachedJs = null; // Invalidate the cache.
264      }
265      return this;
266   }
267
268   //--------------------------------------------------------------------------
269   public TooltipJS setShadowOffset(int inValue)
270   {
271      if (inValue != mShadowOffset)
272      {
273         mShadowOffset = inValue;
274         mCachedJs = null; // Invalidate the cache.
275      }
276      return this;
277   }
278
279   //--------------------------------------------------------------------------
280   /**
281    Move the tooltip via onmousemove().
282    */
283   // Changing the value does not affect the cached js.
284   public TooltipJS setMouseMove(boolean inValue)
285   {
286      mAddOnMouseMove = inValue;
287      return this;
288   }
289
290   //--------------------------------------------------------------------------
291   /**
292    * Tooltips can be added to any tag which supports onmouseover and onmouseout.
293    * You will also need to add generateJS() to the javascript in the page's &lt;head&gt; tag.
294    * @param inTag the tag to which the onmouseover and onmouseout attributes will
295    *              be set to display a popup tooltip.
296    * @param inValue the text or HTML to display in the tooltip.
297    */
298   public void addTooltip(XMLNode inTag, String inValue)
299   {
300//      String safeString = StringUtil.replaceAll(inValue, "'", "\\'");
301//      String safeString = XMLUtil.escapeAttributeValue(inValue);
302      String safeString = StringUtil.replaceAll(inValue, "\n", "\\n");
303      safeString = StringUtil.replaceAll(safeString, "\r", "\\r");
304      safeString = StringUtil.replaceAll(safeString, "'", "&apos;");
305      safeString = StringUtil.replaceAll(safeString, "\"", "&quot;");
306
307
308      // Firefox (as of 3.0.*) still only recognized 'evt' and not 'event'
309      // Safari seems to recognize both.
310      String eventName = (inTag instanceof SvgNode ? "evt" : "event");
311
312      String currentValue = inTag.getAttributeValue(HTML.ONMOUSEOVER);
313      inTag.setAttribute(HTML.ONMOUSEOVER, (currentValue != null ? currentValue + ";" : "")
314                                           + "showTooltip("
315                                           + eventName + ", '"
316                                           + safeString + "');");
317
318      if (mAddOnMouseMove)
319      {
320         currentValue = inTag.getAttributeValue(HTML.ONMOUSEMOVE);
321         inTag.setAttribute(HTML.ONMOUSEMOVE, (currentValue != null ? currentValue + ";" : "")
322                                              + "moveTooltip(" + eventName + ");");
323      }
324
325      currentValue = inTag.getAttributeValue(HTML.ONMOUSEOUT);
326      inTag.setAttribute(HTML.ONMOUSEOUT, (currentValue != null ? currentValue + ";" : "")
327                                          + "hideTooltip();");
328   }
329
330   //--------------------------------------------------------------------------
331   /**
332    * Creates a tooltip using the tag's 'title' attribute as the tooltip text.
333    * @param inTag the tag to which the onmouseover and onmouseout attributes will
334    *              be added in order to display the popup tooltip.
335    */
336   public void addTitleTooltip(XMLNode inTag)
337   {
338      String currentValue = inTag.getAttributeValue(HTML.ONMOUSEOVER);
339      inTag.setAttribute(HTML.ONMOUSEOVER, (currentValue != null ? currentValue + ";" : "")
340                                           + "showTitleTooltip(event, this)");
341
342      if (mAddOnMouseMove)
343      {
344         currentValue = inTag.getAttributeValue(HTML.ONMOUSEMOVE);
345         inTag.setAttribute(HTML.ONMOUSEMOVE, (currentValue != null ? currentValue + ";" : "")
346                                              + "moveTooltip(event)");
347      }
348
349      currentValue = inTag.getAttributeValue(HTML.ONMOUSEOUT);
350      inTag.setAttribute(HTML.ONMOUSEOUT, (currentValue != null ? currentValue + ";" : "")
351                                          + "hideTitleTooltip()");
352   }
353
354   //--------------------------------------------------------------------------
355   public String generateJS()
356   {
357      if (null == mCachedJs)
358      {
359         Map<String, String> tokenSubstitutionMap = new HashMap<String, String>();
360         tokenSubstitutionMap.put("TOOLTIP_DELAY", mDelay + "");
361         tokenSubstitutionMap.put("TOOLTIP_XOFFSET", mXOffset + "");
362         tokenSubstitutionMap.put("TOOLTIP_YOFFSET", mYOffset + "");
363         tokenSubstitutionMap.put("TOOLTIP_BORDER", mBorder + "");
364         tokenSubstitutionMap.put("TOOLTIP_FONT", mFont + "");
365         tokenSubstitutionMap.put("TOOLTIP_FONT_SIZE", mFontSize + "");
366         tokenSubstitutionMap.put("TOOLTIP_FONT_COLOR", mFontColor + "");
367         tokenSubstitutionMap.put("TOOLTIP_BGCOLOR", mBgColor + "");
368         tokenSubstitutionMap.put("TOOLTIP_PADDING", mPadding + "");
369         tokenSubstitutionMap.put("TOOLTIP_MAX_WIDTH", mMaxWidth + "");
370         tokenSubstitutionMap.put("TOOLTIP_SHADOW_COLOR", mShadowColor + "");
371         tokenSubstitutionMap.put("TOOLTIP_SHADOW_OFFSET", mShadowOffset + "");
372
373         mCachedJs = JsUtil.getJSResourceAsString("tooltip.js", tokenSubstitutionMap);
374      }
375
376      return mCachedJs;
377   }
378}