1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.css;
16
17 import java.io.IOException;
18 import java.io.StringReader;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.htmlunit.corejs.javascript.VarScope;
25 import org.htmlunit.css.CssStyleSheet;
26 import org.htmlunit.cssparser.dom.AbstractCSSRuleImpl;
27 import org.htmlunit.cssparser.dom.CSSCharsetRuleImpl;
28 import org.htmlunit.cssparser.dom.CSSRuleListImpl;
29 import org.htmlunit.cssparser.parser.InputSource;
30 import org.htmlunit.javascript.JavaScriptEngine;
31 import org.htmlunit.javascript.configuration.JsxClass;
32 import org.htmlunit.javascript.configuration.JsxConstructor;
33 import org.htmlunit.javascript.configuration.JsxFunction;
34 import org.htmlunit.javascript.configuration.JsxGetter;
35 import org.htmlunit.javascript.host.html.HTMLElement;
36 import org.w3c.dom.DOMException;
37
38
39
40
41
42
43
44
45
46
47
48
49
50 @JsxClass
51 public class CSSStyleSheet extends StyleSheet {
52
53 private static final Log LOG = LogFactory.getLog(CSSStyleSheet.class);
54
55
56 private CssStyleSheet styleSheet_;
57
58
59 private CSSRuleList cssRules_;
60 private List<Integer> cssRulesIndexFix_;
61
62
63
64
65 public CSSStyleSheet() {
66 super(null);
67 styleSheet_ = new CssStyleSheet(null, (InputSource) null, null);
68 }
69
70
71
72
73 @Override
74 @JsxConstructor
75 public void jsConstructor() {
76 super.jsConstructor();
77 styleSheet_ = new CssStyleSheet(null, (InputSource) null, null);
78 }
79
80
81
82
83
84
85
86 public CSSStyleSheet(final HTMLElement element, final InputSource source, final String uri) {
87 super(element);
88
89 setParentScope(getTopLevelScope(element.getParentScope()));
90 setPrototype(getPrototype(CSSStyleSheet.class));
91
92 styleSheet_ = new CssStyleSheet(element.getDomNodeOrDie(), source, uri);
93 }
94
95
96
97
98
99
100
101 public CSSStyleSheet(final HTMLElement element, final String styleSheet, final String uri) {
102 super(element);
103
104 CssStyleSheet css = null;
105 try (InputSource source = new InputSource(new StringReader(styleSheet))) {
106 css = new CssStyleSheet(element.getDomNodeOrDie(), source, uri);
107 }
108 catch (final IOException e) {
109 LOG.error(e.getMessage(), e);
110 }
111
112 setParentScope(element.getParentScope());
113 setPrototype(getPrototype(CSSStyleSheet.class));
114
115 styleSheet_ = css;
116 }
117
118
119
120
121
122
123
124 public CSSStyleSheet(final HTMLElement element, final VarScope parentScope,
125 final CssStyleSheet cssStyleSheet) {
126 super(element);
127
128 setParentScope(parentScope);
129 setPrototype(getPrototype(CSSStyleSheet.class));
130 styleSheet_ = cssStyleSheet;
131 }
132
133
134
135
136
137 public CssStyleSheet getCssStyleSheet() {
138 return styleSheet_;
139 }
140
141
142
143
144
145 @JsxGetter
146 public CSSRuleList getRules() {
147 return getCssRules();
148 }
149
150
151
152
153
154 @JsxGetter
155 public CSSRuleList getCssRules() {
156 initCssRules();
157 return cssRules_;
158 }
159
160
161
162
163
164
165
166
167 @JsxFunction
168 public int insertRule(final String rule, final int position) {
169 try {
170 initCssRules();
171 getCssStyleSheet().getWrappedSheet().insertRule(rule, fixIndex(position));
172 refreshCssRules();
173 return position;
174 }
175 catch (final DOMException e) {
176
177 final int pos = rule.indexOf('{');
178 if (pos > -1) {
179 final String newRule = rule.substring(0, pos) + "{}";
180 try {
181 getCssStyleSheet().getWrappedSheet().insertRule(newRule, fixIndex(position));
182 refreshCssRules();
183 return position;
184 }
185 catch (final DOMException ex) {
186 throw JavaScriptEngine.asJavaScriptException(getWindow(), ex.getMessage(), ex.code);
187 }
188 }
189 throw JavaScriptEngine.asJavaScriptException(getWindow(), e.getMessage(), e.code);
190 }
191 }
192
193 private void refreshCssRules() {
194 if (cssRules_ == null) {
195 return;
196 }
197
198 cssRules_.clearRules();
199 cssRulesIndexFix_.clear();
200
201 final CSSRuleListImpl ruleList = getCssStyleSheet().getWrappedSheet().getCssRules();
202 final List<AbstractCSSRuleImpl> rules = ruleList.getRules();
203 int pos = 0;
204 for (final AbstractCSSRuleImpl rule : rules) {
205 if (rule instanceof CSSCharsetRuleImpl) {
206 cssRulesIndexFix_.add(pos);
207 continue;
208 }
209
210 final CSSRule cssRule = CSSRule.create(this, rule);
211 if (null == cssRule) {
212 cssRulesIndexFix_.add(pos);
213 }
214 else {
215 cssRules_.addRule(cssRule);
216 }
217 pos++;
218 }
219
220
221 getCssStyleSheet().getWrappedSheet().resetRuleIndex();
222 }
223
224 private int fixIndex(int index) {
225 for (final int fix : cssRulesIndexFix_) {
226 if (fix > index) {
227 return index;
228 }
229 index++;
230 }
231 return index;
232 }
233
234
235
236
237
238
239 @JsxFunction
240 public void deleteRule(final int position) {
241 try {
242 initCssRules();
243 getCssStyleSheet().getWrappedSheet().deleteRule(fixIndex(position));
244 refreshCssRules();
245 }
246 catch (final DOMException e) {
247 throw JavaScriptEngine.asJavaScriptException(getWindow(), e.getMessage(), e.code);
248 }
249 }
250
251
252
253
254
255
256
257
258 @JsxFunction
259 public int addRule(final String selector, final String rule) {
260 String completeRule = selector + " {" + rule + "}";
261 try {
262 initCssRules();
263 getCssStyleSheet().getWrappedSheet().insertRule(completeRule,
264 getCssStyleSheet().getWrappedSheet().getCssRules().getLength());
265 refreshCssRules();
266 }
267 catch (final DOMException e) {
268
269 completeRule = selector + " {}";
270 try {
271 getCssStyleSheet().getWrappedSheet().insertRule(completeRule,
272 getCssStyleSheet().getWrappedSheet().getCssRules().getLength());
273 refreshCssRules();
274 }
275 catch (final DOMException ex) {
276 throw JavaScriptEngine.asJavaScriptException(getWindow(), ex.getMessage(), ex.code);
277 }
278 }
279 return -1;
280 }
281
282
283
284
285
286
287 @JsxFunction
288 public void removeRule(final int position) {
289 try {
290 initCssRules();
291 getCssStyleSheet().getWrappedSheet().deleteRule(fixIndex(position));
292 refreshCssRules();
293 }
294 catch (final DOMException e) {
295 throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
296 }
297 }
298
299
300
301
302
303
304 @Override
305 public String getUri() {
306 return getCssStyleSheet().getUri();
307 }
308
309 private void initCssRules() {
310 if (cssRules_ == null) {
311 cssRules_ = new CSSRuleList(this);
312 cssRulesIndexFix_ = new ArrayList<>();
313 refreshCssRules();
314 }
315 }
316 }