001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.core.util.string; 018 019import org.apache.wicket.request.Response; 020import org.apache.wicket.util.string.Strings; 021import org.apache.wicket.util.value.AttributeMap; 022 023/** 024 * Provide some helpers to write javascript related tags to the response object. 025 * 026 * @author Juergen Donnerstag 027 */ 028public class JavaScriptUtils 029{ 030 /** 031 * Prefix for JavaScript CDATA content. If this is changed, also update 032 * Wicket.Head.Contributor.processScript() function from wicket-ajax-jquery.js 033 */ 034 public final static String SCRIPT_CONTENT_PREFIX = "\n/*<![CDATA[*/\n"; 035 036 /** 037 * Suffix for JavaScript CDATA content. If this is changed, also update 038 * Wicket.Head.Contributor.processScript() function from wicket-ajax-jquery.js 039 */ 040 public final static String SCRIPT_CONTENT_SUFFIX = "\n/*]]>*/\n"; 041 042 /** Script open tag including content prefix */ 043 public final static String SCRIPT_OPEN_TAG = "<script type=\"text/javascript\">" + 044 SCRIPT_CONTENT_PREFIX; 045 046 /** Script close tag including content suffix */ 047 public final static String SCRIPT_CLOSE_TAG = SCRIPT_CONTENT_SUFFIX + "</script>\n"; 048 049 public static final String ATTR_ID = "id"; 050 public static final String ATTR_TYPE = "type"; 051 public static final String ATTR_SCRIPT_SRC = "src"; 052 public static final String ATTR_SCRIPT_DEFER = "defer"; 053 public static final String ATTR_SCRIPT_ASYNC = "async"; 054 public static final String ATTR_CSP_NONCE = "nonce"; 055 public static final String ATTR_CROSS_ORIGIN = "crossOrigin"; 056 public static final String ATTR_INTEGRITY = "integrity"; 057 058 /** The response object */ 059 private final Response response; 060 061 /** 062 * Construct. 063 * 064 * @param response 065 * The response object 066 * @param id 067 */ 068 public JavaScriptUtils(final Response response, String id) 069 { 070 this.response = response; 071 writeOpenTag(response, id); 072 } 073 074 /** 075 * Constructor without id for backward compatibility 076 * 077 * @param response 078 * The response object 079 */ 080 public JavaScriptUtils(final Response response) 081 { 082 this.response = response; 083 writeOpenTag(response); 084 } 085 086 087 /** 088 * Escape single and double quotes so that they can be part of e.g. an alert call. 089 * 090 * Note: JSON values need to escape only the double quote, so this method wont help. 091 * 092 * @param input 093 * the JavaScript which needs to be escaped 094 * @return Escaped version of the input 095 */ 096 public static CharSequence escapeQuotes(final CharSequence input) 097 { 098 CharSequence s = input; 099 if (s != null) 100 { 101 s = Strings.replaceAll(s, "'", "\\'"); 102 s = Strings.replaceAll(s, "\"", "\\\""); 103 } 104 return s; 105 } 106 107 /** 108 * Write a reference to a javascript file to the response object 109 * 110 * @param response 111 * The HTTP response 112 * @param url 113 * The javascript file URL 114 * @param id 115 * Unique identifier of element 116 * @deprecated please use {@link #writeScript(Response, AttributeMap)} instead 117 */ 118 @Deprecated 119 public static void writeJavaScriptUrl(final Response response, final CharSequence url, 120 final String id) 121 { 122 writeJavaScriptUrl(response, url, id, false, null, false); 123 } 124 125 /** 126 * Write a reference to a javascript file to the response object 127 * 128 * @param response 129 * The HTTP response 130 * @param url 131 * The javascript file URL 132 * @param id 133 * Unique identifier of element 134 * @param defer 135 * specifies that the execution of a script should be deferred (delayed) until after 136 * the page has been loaded. 137 * @param charset 138 * a non null value specifies the charset attribute of the script tag 139 * @deprecated please use {@link #writeScript(Response, AttributeMap)} instead 140 */ 141 @Deprecated 142 public static void writeJavaScriptUrl(final Response response, final CharSequence url, 143 final String id, boolean defer, String charset) 144 { 145 writeJavaScriptUrl(response, url, id, defer, charset, false); 146 } 147 148 /** 149 * Write a reference to a javascript file to the response object 150 * 151 * @param response 152 * The HTTP response 153 * @param url 154 * The javascript file URL 155 * @param id 156 * Unique identifier of element 157 * @param defer 158 * specifies that the execution of a script should be deferred (delayed) until after 159 * the page has been loaded. 160 * @param charset 161 * a non null value specifies the charset attribute of the script tag 162 * @param async 163 * specifies that the script can be loaded asynchronously by the browser 164 * @deprecated please use {@link #writeScript(Response, AttributeMap)} instead 165 */ 166 @Deprecated 167 public static void writeJavaScriptUrl(final Response response, final CharSequence url, 168 final String id, boolean defer, String charset, boolean async) 169 { 170 AttributeMap attributes = new AttributeMap(); 171 // XXX JS mimetype can be omitted (also see below) 172 attributes.putAttribute(ATTR_TYPE, "text/javascript"); 173 attributes.putAttribute(ATTR_SCRIPT_SRC, url); 174 attributes.putAttribute(ATTR_ID, id); 175 attributes.putAttribute(ATTR_SCRIPT_DEFER, defer); 176 attributes.putAttribute(ATTR_SCRIPT_ASYNC, async); 177 // FIXME charset attr is deprecated 178 // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#Deprecated_attributes 179 attributes.putAttribute("charset", charset); 180 writeScript(response, attributes); 181 } 182 183 /** 184 * Write a reference to a javascript file to the response object 185 * 186 * @param response 187 * The HTTP response 188 * @param attributes 189 * Extra tag attributes 190 */ 191 public static void writeScript(final Response response, AttributeMap attributes) 192 { 193 response.write("<script"); 194 response.write(attributes.toCharSequence()); 195 response.write("></script>"); 196 response.write("\n"); 197 } 198 199 /** 200 * Write a reference to a javascript file to the response object 201 * 202 * @param response 203 * The HTTP response 204 * @param url 205 * The javascript file URL 206 * @deprecated please use {@link #writeScript(Response, AttributeMap)} instead 207 */ 208 @Deprecated 209 public static void writeJavaScriptUrl(final Response response, final CharSequence url) 210 { 211 writeJavaScriptUrl(response, url, null); 212 } 213 214 /** 215 * Write the simple text to the response object surrounded by a script tag. 216 * 217 * @param response 218 * The HTTP: response 219 * @param text 220 * The text to added in between the script tags 221 * @param id 222 * Unique identifier of element 223 * @deprecated please use {@link #writeInlineScript(Response, CharSequence, AttributeMap)} instead 224 */ 225 public static void writeJavaScript(final Response response, final CharSequence text, String id) 226 { 227 writeOpenTag(response, id); 228 response.write(Strings.replaceAll(text, "</", "<\\/")); 229 writeCloseTag(response); 230 } 231 232 /** 233 * Write the simple text to the response object surrounded by a script tag. 234 * 235 * @param response 236 * The HTTP: response 237 * @param text 238 * The text to added in between the script tags 239 * @param attributes 240 * Extra tag attributes 241 */ 242 public static void writeInlineScript(final Response response, final CharSequence text, AttributeMap attributes) 243 { 244 writeOpenTag(response, attributes); 245 response.write(Strings.replaceAll(text, "</", "<\\/")); 246 writeCloseTag(response); 247 } 248 249 /** 250 * Write the simple text to the response object surrounded by a script tag. 251 * 252 * @param response 253 * The HTTP: response 254 * @param text 255 * The text to added in between the script tags 256 */ 257 public static void writeJavaScript(final Response response, final CharSequence text) 258 { 259 AttributeMap attributes = new AttributeMap(); 260 attributes.putAttribute(ATTR_TYPE, "text/javascript"); 261 writeInlineScript(response, text, attributes); 262 } 263 264 /** 265 * 266 * @param response 267 * @param id 268 * @deprecated please use {@link #writeOpenTag(Response, AttributeMap)} 269 */ 270 @Deprecated 271 public static void writeOpenTag(final Response response, String id) 272 { 273 AttributeMap attributes = new AttributeMap(); 274 attributes.putAttribute(ATTR_TYPE, "text/javascript"); 275 attributes.putAttribute(ATTR_ID, id); 276 writeOpenTag(response, attributes); 277 } 278 279 /** 280 * Write open script tag for inline script. 281 * Content is prefixed with {@link #SCRIPT_CONTENT_PREFIX}. 282 * 283 * @param response 284 * the response to write to 285 * @param attributes 286 * Tag attributes map 287 */ 288 public static void writeOpenTag(final Response response, AttributeMap attributes) 289 { 290 response.write("<script"); 291 response.write(attributes.toCharSequence()); 292 response.write(">"); 293 response.write(SCRIPT_CONTENT_PREFIX); 294 } 295 296 /** 297 * 298 * @param response 299 * @deprecated please use {@link #writeOpenTag(Response, AttributeMap)} 300 */ 301 @Deprecated 302 public static void writeOpenTag(final Response response) 303 { 304 AttributeMap attributes = new AttributeMap(); 305 attributes.putAttribute(ATTR_TYPE, "text/javascript"); 306 writeOpenTag(response, attributes); 307 } 308 309 /** 310 * Write close script tag for inline script. The close tag is prefixed with {@link #SCRIPT_CONTENT_SUFFIX} 311 * 312 * @param response 313 * the response to write to 314 */ 315 public static void writeCloseTag(final Response response) 316 { 317 response.write(SCRIPT_CONTENT_SUFFIX); 318 response.write("</script>\n"); 319 } 320 321 /** 322 * @see Response#write(java.lang.CharSequence) 323 * @param script 324 */ 325 public void write(final CharSequence script) 326 { 327 response.write(script); 328 } 329 330 /** 331 * @see Response#write(CharSequence) 332 * @param script 333 */ 334 public void println(final CharSequence script) 335 { 336 response.write(script); 337 } 338 339 /** 340 * Write the inline script close tag to the response. The response output stream remains open. 341 * Calls {@link #writeCloseTag(Response)} internally. 342 * The close tag is prefixed with {@link #SCRIPT_CONTENT_SUFFIX}. 343 */ 344 public void close() 345 { 346 writeCloseTag(response); 347 } 348}