1 /*
2 * Copyright (c) 2002-2026 Gargoyle Software Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit.javascript.host.css;
16
17 import org.htmlunit.corejs.javascript.Scriptable;
18 import org.htmlunit.javascript.HtmlUnitScriptable;
19 import org.htmlunit.javascript.configuration.JsxClass;
20 import org.htmlunit.javascript.configuration.JsxStaticFunction;
21 import org.htmlunit.util.StringUtils;
22
23 /**
24 * A JavaScript object for {@code CSS}.
25 *
26 * @author Ahmed Ashour
27 * @author Ronald Brill
28 *
29 * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS">MDN Documentation</a>
30 */
31 @JsxClass
32 public class CSS extends HtmlUnitScriptable {
33
34 /**
35 * {@inheritDoc}
36 */
37 @Override
38 public Object get(final String name, final Scriptable start) {
39 if ("prototype".equals(name)) {
40 return NOT_FOUND;
41 }
42 return super.get(name, start);
43 }
44
45 /**
46 * Indicates whether the browser supports a given CSS feature.
47 * @return a Boolean value indicating if the browser supports a given CSS feature, or not
48 */
49 @JsxStaticFunction
50 public static boolean supports() {
51 // for the moment we support everything :-)
52 return true;
53 }
54
55 /**
56 * Escapes a string for use as part of a CSS selector.
57 * @param ident the string to be escaped
58 * @return a string containing the escaped string passed as parameter,
59 * mostly for use as part of a CSS selector
60 */
61 @JsxStaticFunction
62 public static String escape(final String ident) {
63 if (StringUtils.isEmptyOrNull(ident)) {
64 return ident;
65 }
66
67 final int length = ident.length();
68 final StringBuilder escaped = new StringBuilder();
69 for (int i = 0; i < length; i++) {
70 final char c = ident.charAt(i);
71
72 // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
73 if (c == '\u0000') {
74 escaped.append('\ufffd');
75 }
76
77 // If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F,
78 // then the character escaped as code point.
79 else if (('\u0001' <= c && c <= '\u001f') || c == '\u007f') {
80 escaped.append('\\').append(Integer.toHexString(c)).append(' ');
81 }
82
83 // If the character is the first character and is in the range [0-9] (U+0030 to U+0039),
84 // then the character escaped as code point.
85 else if (i == 0 && ('\u0030' <= c && c <= '\u0039')) {
86 escaped.append('\\').append(Integer.toHexString(c)).append(' ');
87 }
88
89 // If the character is the second character and is in the range [0-9] (U+0030 to U+0039)
90 // and the first character is a "-" (U+002D), then the character escaped as code point.
91 else if (i == 1 && ('\u0030' <= c && c <= '\u0039') && ident.charAt(0) == '-') {
92 escaped.append('\\').append(Integer.toHexString(c)).append(' ');
93 }
94
95 // If the character is the first character and is a "-" (U+002D),
96 // and there is no second character, then the escaped character.
97 else if (i == 0 && c == '-' && length == 1) {
98 escaped.append('\\').append(c);
99 }
100
101 // If the character is not handled by one of the above rules
102 // and is greater than or equal to U+0080, is "-" (U+002D) or "_" (U+005F),
103 // or is in one of the ranges [0-9] (U+0030 to U+0039),
104 // [A-Z] (U+0041 to U+005A), or [a-z] (U+0061 to U+007A),
105 // then the character itself.
106 else if (c >= '\u0080'
107 || c == '\u002d'
108 || c == '\u005f'
109 || ('\u0030' <= c && c <= '\u0039')
110 || ('\u0041' <= c && c <= '\u005A')
111 || ('\u0061' <= c && c <= '\u007A')) {
112 escaped.append(c);
113 }
114
115 // Otherwise, the escaped character
116 else {
117 escaped.append('\\').append(c);
118 }
119 }
120
121 return escaped.toString();
122 }
123 }