001package com.hfg.html;
002
003import com.hfg.xml.XMLComment;
004import com.hfg.xml.XMLCDATA;
005import com.hfg.util.mime.MimeType;
006import com.hfg.util.StringUtil;
007import com.hfg.xml.XMLNode;
008
009import java.nio.charset.Charset;
010
011//------------------------------------------------------------------------------
012/**
013 * Represents a script (<script>) tag.
014 *
015 * @author J. Alex Taylor, hairyfatguy.com
016 */
017//------------------------------------------------------------------------------
018// com.hfg XML/HTML Coding Library
019//
020// This library is free software; you can redistribute it and/or
021// modify it under the terms of the GNU Lesser General Public
022// License as published by the Free Software Foundation; either
023// version 2.1 of the License, or (at your option) any later version.
024//
025// This library is distributed in the hope that it will be useful,
026// but WITHOUT ANY WARRANTY; without even the implied warranty of
027// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
028// Lesser General Public License for more details.
029//
030// You should have received a copy of the GNU Lesser General Public
031// License along with this library; if not, write to the Free Software
032// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
033//
034// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
035// jataylor@hairyfatguy.com
036//------------------------------------------------------------------------------
037
038/*
039For XHTML or XML the script should be escaped like so:
040<script>
041 <![CDATA[
042 ... unescaped script content ...
043 ]]>
044 </script>
045
046 However, older browser (such as IE5 on Mac) won't take kindly to this.
047 IE6 doesn't seem to like such escaping in returned AJAX content.
048*/
049public class Script extends HTMLTag
050{
051   private boolean  mUseCDATA = true;
052   private XMLCDATA mCDATA;
053
054   //##########################################################################
055   // PUBLIC FIELDS
056   //##########################################################################
057
058   public static final String JAVASCRIPT    = "JavaScript";
059   public static final String JAVASCRIPT1_1 = "JavaScript1.1";
060   public static final String JAVASCRIPT1_2 = "JavaScript1.2";
061   public static final String JAVASCRIPT1_3 = "JavaScript1.3";
062   public static final String VBSCRIPT      = "VBScript";
063
064   //##########################################################################
065   // CONSTRUCTORS
066   //##########################################################################
067
068   //--------------------------------------------------------------------------
069   public Script()
070   {
071      super(HTML.SCRIPT);
072      // Force the use of a closing tag. Some browsers will barf if they see an
073      // empty script tag in the HTML. Not necessary for XHTML but oh, well.
074      setContent("");
075   }
076
077   //--------------------------------------------------------------------------
078   public Script(MimeType inType)
079   {
080      this();
081      setType(inType);
082   }
083
084   //--------------------------------------------------------------------------
085   public Script(String inContent)
086   {
087      this();
088      addContent(inContent);
089   }
090
091   //--------------------------------------------------------------------------
092   public Script(CharSequence inContent)
093   {
094      this();
095      addContent(inContent);
096   }
097
098   //--------------------------------------------------------------------------
099   public Script(XMLNode inXMLNode)
100   {
101      this();
102      initFromXMLNode(inXMLNode);
103   }
104
105   //##########################################################################
106   // PUBLIC METHODS
107   //##########################################################################
108
109   //--------------------------------------------------------------------------
110   /**
111    Defaults to true.
112    */
113   public Script useCDATA(boolean inValue)
114   {
115      if (inValue != mUseCDATA)
116      {
117         String content = getContent();
118         mUseCDATA = inValue;
119
120         if (! mUseCDATA)
121         {
122            clearSubtags();
123            mCDATA = null;
124         }
125
126         setContent(content);
127      }
128
129      return this;
130   }
131
132   //--------------------------------------------------------------------------
133   /**
134    Sets the script language.
135    @deprecated Use setType() - The 'language' attribute has been deprecated
136                in favor of 'type' in the html standard.
137    */
138   public Script setLanguage(String inValue)
139   {
140      setAttribute(HTML.LANGUAGE, inValue);
141
142      return this;
143   }
144
145   //--------------------------------------------------------------------------
146   /**
147    Sets the charset.
148    @param inValue the charset of the referenced script.
149    @return this Script object - for method chaining
150    */
151   public Script setCharset(Charset inValue)
152   {
153      setAttribute(HTML.CHARSET, inValue.displayName());
154      return this;
155   }
156
157   //--------------------------------------------------------------------------
158   /**
159    Sets the script type.
160    */
161   public Script setType(MimeType inValue)
162   {
163      return setType(inValue.toString());
164   }
165
166   //--------------------------------------------------------------------------
167   /**
168    Sets the script type.
169    */
170   public Script setType(String inValue)
171   {
172      setAttribute(HTML.TYPE, inValue);
173
174      if (inValue != null
175          && inValue.equalsIgnoreCase(MimeType.TEXT_JAVASCRIPT.toString()))
176      {
177         // TODO: Is this necessary?
178         getCDATA().setHideWithCommentsForLegacyBrowsers(true);
179      }
180
181      return this;
182   }
183
184   //--------------------------------------------------------------------------
185   /**
186    When set, this boolean attribute provides a hint to the user agent that the
187    script is not going to generate any document content (e.g., no "document.write"
188    in javascript) and thus, the user agent can continue parsing and rendering.
189    */
190   public Script setDefer(boolean inValue)
191   {
192      setAttribute(HTML.DEFER, inValue);
193
194      return this;
195   }
196
197   //--------------------------------------------------------------------------
198   /**
199    Specifies the location of an external script.
200    */
201   public Script setSrc(String inValue)
202   {
203      setAttribute(HTML.SRC, inValue);
204
205      return this;
206   }
207
208   //--------------------------------------------------------------------------
209   @Override
210   public Script setContent(CharSequence inContent)
211   {
212      clearContent();
213
214      addContent(inContent);
215
216      return this;
217   }
218
219   //--------------------------------------------------------------------------
220   public Script appendln(CharSequence inContent)
221   {
222      addContent(inContent + "\n");
223      return this;
224   }
225
226   //--------------------------------------------------------------------------
227   @Override
228   public Script addContent(CharSequence inContent)
229   {
230      if (StringUtil.isSet(inContent))
231      {
232         if (mUseCDATA)
233         {
234            getCDATA().addContent(inContent);
235         }
236         else
237         {
238            super.addContentWithoutEscaping(inContent);
239         }
240      }
241      else
242      {
243         super.addContent(inContent);
244      }
245
246      return this;
247   }
248
249   //--------------------------------------------------------------------------
250   @Override
251   public void clearContent()
252   {
253      if (mCDATA != null) mCDATA.clearContent();
254      super.clearContent();
255   }
256
257   //--------------------------------------------------------------------------
258   @Override
259   public boolean hasContent()
260   {
261      boolean result = true;
262      if (mUseCDATA)
263      {
264         result = mCDATA != null && mCDATA.hasContent();
265      }
266      else
267      {
268         result = super.hasContent();
269      }
270
271      return result;
272   }
273
274   //--------------------------------------------------------------------------
275   @Override
276   public String getContent()
277   {
278      String result = "";
279      if (mUseCDATA)
280      {
281         if (mCDATA != null) result = mCDATA.getContent();
282      }
283      else
284      {
285         result = super.getContent();
286      }
287
288      return result;
289   }
290
291   //##########################################################################
292   // PRIVATE METHODS
293   //##########################################################################
294
295   //--------------------------------------------------------------------------
296   private XMLCDATA getCDATA()
297   {
298      if (null == mCDATA)
299      {
300         XMLComment commentTag = new XMLComment("//");
301         addSubtag(commentTag);
302         mCDATA = new XMLCDATA("\n");
303         addSubtag(mCDATA);
304      }
305
306      return mCDATA;
307   }
308}