View Javadoc
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 }