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        /**
059         * Escape single and double quotes so that they can be part of e.g. an alert call.
060         * 
061         * Note: JSON values need to escape only the double quote, so this method wont help.
062         * 
063         * @param input
064         *            the JavaScript which needs to be escaped
065         * @return Escaped version of the input
066         */
067        public static CharSequence escapeQuotes(final CharSequence input)
068        {
069                CharSequence s = input;
070                if (s != null)
071                {
072                        s = Strings.replaceAll(s, "'", "\\'");
073                        s = Strings.replaceAll(s, "\"", "\\\"");
074                }
075                return s;
076        }
077
078        /**
079         * Write a reference to a javascript file to the response object
080         *
081         * @param response
082         *            The HTTP response
083         * @param attributes
084         *            Extra tag attributes
085         */
086        public static void writeScript(final Response response, AttributeMap attributes)
087        {
088                response.write("<script");
089                response.write(attributes.toCharSequence());
090                response.write("></script>");
091                response.write("\n");
092        }
093
094        /**
095         * Write the simple text to the response object surrounded by a script tag.
096         *
097         * @param response
098         *              The HTTP: response
099         * @param text
100         *              The text to added in between the script tags
101         * @param attributes
102         *              Extra tag attributes
103         */
104        public static void writeInlineScript(final Response response, final CharSequence text, AttributeMap attributes)
105        {
106                writeOpenTag(response, attributes);
107                response.write(Strings.replaceAll(text, "</", "<\\/"));
108                writeCloseTag(response);
109        }
110
111        /**
112         * Write the simple text to the response object surrounded by a script tag.
113         * 
114         * @param response
115         *            The HTTP: response
116         * @param text
117         *            The text to added in between the script tags
118         */
119        public static void writeJavaScript(final Response response, final CharSequence text)
120        {
121                AttributeMap attributes = new AttributeMap();
122                attributes.putAttribute(ATTR_TYPE, "text/javascript");
123                writeInlineScript(response, text, attributes);
124        }
125
126        /**
127         * Write open script tag for inline script.
128         * Content is prefixed with {@link #SCRIPT_CONTENT_PREFIX}.
129         *
130         * @param response
131         *              the response to write to
132         * @param attributes
133         *              Tag attributes map
134         */
135        public static void writeOpenTag(final Response response, AttributeMap attributes)
136        {
137                response.write("<script");
138                response.write(attributes.toCharSequence());
139                response.write(">");
140                response.write(SCRIPT_CONTENT_PREFIX);
141        }
142
143        /**
144         * Write close script tag for inline script. The close tag is prefixed with {@link #SCRIPT_CONTENT_SUFFIX}
145         *
146         * @param response
147         *              the response to write to
148         */
149        public static void writeCloseTag(final Response response)
150        {
151                response.write(SCRIPT_CONTENT_SUFFIX);
152                response.write("</script>\n");
153        }
154}