• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 389

12 Aug 2025 11:17PM UTC coverage: 80.48% (-0.02%) from 80.503%
389

push

github

hazendaz
Merge branch 'master' into javax

3216 of 4105 branches covered (78.34%)

Branch coverage included in aggregate %.

238 of 258 new or added lines in 68 files covered. (92.25%)

2 existing lines in 2 files now uncovered.

8254 of 10147 relevant lines covered (81.34%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.8
/src/main/java/com/meterware/httpunit/javascript/JavaScript.java
1
/*
2
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.httpunit.javascript;
21

22
import com.meterware.httpunit.ClientProperties;
23
import com.meterware.httpunit.HTMLPage;
24
import com.meterware.httpunit.HttpUnitOptions;
25
import com.meterware.httpunit.HttpUnitUtils;
26
import com.meterware.httpunit.WebForm;
27
import com.meterware.httpunit.WebImage;
28
import com.meterware.httpunit.WebLink;
29
import com.meterware.httpunit.WebResponse;
30
import com.meterware.httpunit.javascript.events.EventException;
31
import com.meterware.httpunit.javascript.events.EventTarget;
32
import com.meterware.httpunit.scripting.DocumentElement;
33
import com.meterware.httpunit.scripting.FormScriptable;
34
import com.meterware.httpunit.scripting.IdentifiedDelegate;
35
import com.meterware.httpunit.scripting.Input;
36
import com.meterware.httpunit.scripting.NamedDelegate;
37
import com.meterware.httpunit.scripting.ScriptableDelegate;
38
import com.meterware.httpunit.scripting.ScriptingEngine;
39
import com.meterware.httpunit.scripting.ScriptingHandler;
40
import com.meterware.httpunit.scripting.SelectionOption;
41
import com.meterware.httpunit.scripting.SelectionOptions;
42

43
import java.io.IOException;
44
import java.lang.reflect.InvocationTargetException;
45
import java.net.URL;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.Map;
49
import java.util.Set;
50

51
import org.mozilla.javascript.Context;
52
import org.mozilla.javascript.EvaluatorException;
53
import org.mozilla.javascript.JavaScriptException;
54
import org.mozilla.javascript.Scriptable;
55
import org.mozilla.javascript.ScriptableObject;
56
import org.mozilla.javascript.Undefined;
57
import org.xml.sax.SAXException;
58

59
/**
60
 * This class is the Rhino-compatible implementation of the JavaScript DOM objects.
61
 *
62
 * @author <a href="mailto:russgold@httpunit.org">Russell Gold</a>
63
 **/
64
public class JavaScript {
×
65

66
    private static boolean _throwExceptionsOnError = true;
1✔
67

68
    public static boolean isThrowExceptionsOnError() {
69
        return _throwExceptionsOnError;
1✔
70
    }
71

72
    public static void setThrowExceptionsOnError(boolean throwExceptionsOnError) {
73
        _throwExceptionsOnError = throwExceptionsOnError;
1✔
74
    }
1✔
75

76
    /**
77
     * Initiates JavaScript execution for the specified web response.
78
     */
79
    public static void run(WebResponse response) throws IllegalAccessException, InstantiationException,
80
            InvocationTargetException, EvaluatorException, EvaluatorException, SAXException, JavaScriptException {
81
        Context context = Context.enter();
1✔
82
        // suggest bug fix for large java scripts see
83
        // bug report [ 1216567 ] Exception for large javascripts
84
        // by Grzegorz Lukasik
85
        // and
86

87
        context.setOptimizationLevel(HttpUnitOptions.getJavaScriptOptimizationLevel());
1✔
88
        Scriptable scope = context.initStandardObjects(null);
1✔
89
        initHTMLObjects(scope);
1✔
90

91
        Window w = (Window) context.newObject(scope, "Window");
1✔
92
        w.initialize(null, response.getScriptableObject());
1✔
93
    }
1✔
94

95
    /**
96
     * Runs the onload event for the specified web response.
97
     */
98
    public static void load(WebResponse response) throws EvaluatorException, InstantiationException,
99
            IllegalAccessException, InvocationTargetException, JavaScriptException, SAXException, EvaluatorException {
100
        if (!(response.getScriptableObject().getScriptEngine() instanceof JavaScriptEngine)) {
1!
101
            run(response);
×
102
        }
103
        response.getScriptableObject().load();
1✔
104
    }
1✔
105

106
    private static void initHTMLObjects(Scriptable scope)
107
            throws IllegalAccessException, InstantiationException, InvocationTargetException, EvaluatorException {
108
        ScriptableObject.defineClass(scope, Window.class);
1✔
109
        ScriptableObject.defineClass(scope, Document.class);
1✔
110
        ScriptableObject.defineClass(scope, Style.class);
1✔
111
        ScriptableObject.defineClass(scope, Location.class);
1✔
112
        ScriptableObject.defineClass(scope, Navigator.class);
1✔
113
        ScriptableObject.defineClass(scope, Screen.class);
1✔
114
        ScriptableObject.defineClass(scope, Link.class);
1✔
115
        ScriptableObject.defineClass(scope, Form.class);
1✔
116
        ScriptableObject.defineClass(scope, Control.class);
1✔
117
        ScriptableObject.defineClass(scope, Link.class);
1✔
118
        ScriptableObject.defineClass(scope, Image.class);
1✔
119
        ScriptableObject.defineClass(scope, Options.class);
1✔
120
        ScriptableObject.defineClass(scope, Option.class);
1✔
121
        ScriptableObject.defineClass(scope, ElementArray.class);
1✔
122
        ScriptableObject.defineClass(scope, HTMLElement.class);
1✔
123
    }
1✔
124

125
    /**
126
     * abstract Engine for JavaScript
127
     */
128
    abstract static class JavaScriptEngine extends ScriptingEngineImpl implements EventTarget {
1✔
129

130
        private static final long serialVersionUID = 1L;
131
        protected ScriptableDelegate _scriptable;
132
        protected JavaScriptEngine _parent;
133
        protected Map _eventListeners = new HashMap<>(); // Map<String,Set<EventListener>>
1✔
134
        protected Map _eventCaptureListeners = new HashMap<>(); // Map<String,Set<EventListener>>
1✔
135

136
        /**
137
         * initialize JavaScript for the given ScriptEngine
138
         *
139
         * @parent - the Script Engine to use
140
         *
141
         * @scriptable - the scriptable object to do the initialization for
142
         */
143
        void initialize(JavaScriptEngine parent, ScriptableDelegate scriptable)
144
                throws SAXException, JavaScriptException, EvaluatorException {
145
            _scriptable = scriptable;
1✔
146
            _scriptable.setScriptEngine(this);
1✔
147
            _parent = parent;
1✔
148
            if (parent != null) {
1✔
149
                setParentScope(parent);
1✔
150
            }
151
        }
1✔
152

153
        String getName() {
154
            return _scriptable instanceof NamedDelegate ? ((NamedDelegate) _scriptable).getName() : "";
1!
155
        }
156

157
        String getID() {
158
            return _scriptable instanceof IdentifiedDelegate ? ((IdentifiedDelegate) _scriptable).getID() : "";
1✔
159
        }
160

161
        /**
162
         * get the event Handler script for the event e.g. onchange, onmousedown, onclick, onmouseup execute the script
163
         * if it's assigned by calling doEvent for the script
164
         *
165
         * @param eventName
166
         *
167
         * @return
168
         */
169
        @Override
170
        public boolean handleEvent(String eventName) {
171
            return _scriptable.handleEvent(eventName);
×
172
        }
173

174
        @Override
175
        public boolean has(String propertyName, Scriptable scriptable) {
176
            return super.has(propertyName, scriptable) || _scriptable != null && _scriptable.get(propertyName) != null;
1✔
177
        }
178

179
        @Override
180
        public Object get(String propertyName, Scriptable scriptable) {
181
            Object result = super.get(propertyName, scriptable);
1✔
182
            if (result != NOT_FOUND) {
1✔
183
                return result;
1✔
184
            }
185
            if (_scriptable == null) {
1✔
186
                return NOT_FOUND;
1✔
187
            }
188

189
            return convertIfNeeded(_scriptable.get(propertyName));
1✔
190

191
        }
192

193
        @Override
194
        public Object get(int i, Scriptable scriptable) {
195
            Object result = super.get(i, scriptable);
1✔
196
            if (result != NOT_FOUND) {
1!
197
                return result;
×
198
            }
199
            if (_scriptable == null) {
1!
200
                return NOT_FOUND;
×
201
            }
202

203
            return convertIfNeeded(_scriptable.get(i));
1✔
204
        }
205

206
        private Object convertIfNeeded(final Object property) {
207
            if (property == null) {
1✔
208
                return NOT_FOUND;
1✔
209
            }
210

211
            if (property instanceof ScriptableDelegate[]) {
1✔
212
                return toScriptable((ScriptableDelegate[]) property);
1✔
213
            }
214
            if (!(property instanceof ScriptableDelegate)) {
1✔
215
                return property;
1✔
216
            }
217
            return toScriptable((ScriptableDelegate) property);
1✔
218
        }
219

220
        private Object toScriptable(ScriptableDelegate[] list) {
221
            Object[] delegates = new Object[list.length];
1✔
222
            for (int i = 0; i < delegates.length; i++) {
1✔
223
                delegates[i] = toScriptable(list[i]);
1✔
224
            }
225
            return Context.getCurrentContext().newArray(this, delegates);
1✔
226
        }
227

228
        @Override
229
        public void put(String propertyName, Scriptable scriptable, Object value) {
230
            if (_scriptable == null || _scriptable.get(propertyName) == null) {
1✔
231
                super.put(propertyName, scriptable, value);
1✔
232
            } else {
233
                _scriptable.set(propertyName, value);
1✔
234
            }
235
        }
1✔
236

237
        @Override
238
        public String toString() {
239
            return (_scriptable == null ? "prototype " : "") + getClassName();
×
240
        }
241

242
        @Override
243
        public ScriptingEngine newScriptingEngine(ScriptableDelegate child) {
244
            try {
245
                return (ScriptingEngine) toScriptable(child);
1✔
246
            } catch (Exception e) {
×
247
                HttpUnitUtils.handleException(e);
×
248
                throw new RuntimeException(e.toString());
×
249
            }
250
        }
251

252
        @Override
253
        public void clearCaches() {
254
        }
×
255

256
        protected static String toStringIfNotUndefined(Object object) {
257
            return object == null || Undefined.instance.equals(object) ? null : object.toString();
1!
258
        }
259

260
        /**
261
         * Converts a scriptable delegate obtained from a subobject into the appropriate Rhino-compatible Scriptable.
262
         **/
263
        final Object toScriptable(ScriptableDelegate delegate) {
264
            if (delegate == null) {
1!
265
                return NOT_FOUND;
×
266
            }
267
            if (delegate.getScriptEngine() instanceof Scriptable) {
1✔
268
                return delegate.getScriptEngine();
1✔
269
            }
270
            try {
271
                JavaScriptEngine element = (JavaScriptEngine) Context.getCurrentContext().newObject(this,
1✔
272
                        getScriptableClassName(delegate));
1✔
273
                element.initialize(this, delegate);
1✔
274
                return element;
1✔
275
            } catch (RuntimeException e) {
×
276
                throw e;
×
277
            } catch (Exception e) {
×
278
                throw new RhinoException(e);
×
279
            }
280
        }
281

282
        /**
283
         * get the classname of the given ScriptableDelegate
284
         *
285
         * @param delegate
286
         *            - the object to get the class name for
287
         *
288
         * @return - the simple local class name for the delegate e.g. Window, Document, Form, Link, Image, Options,
289
         *         Option, Control, HTMLElement
290
         *
291
         * @throws an
292
         *             IllegalArgumentException if the delegate is not known
293
         */
294
        private String getScriptableClassName(ScriptableDelegate delegate) {
295
            if (delegate instanceof WebResponse.Scriptable) {
1✔
296
                return "Window";
1✔
297
            }
298
            if (delegate instanceof HTMLPage.Scriptable) {
1✔
299
                return "Document";
1✔
300
            }
301
            if (delegate instanceof FormScriptable) {
1✔
302
                return "Form";
1✔
303
            }
304
            if (delegate instanceof WebLink.Scriptable) {
1✔
305
                return "Link";
1✔
306
            }
307
            if (delegate instanceof WebImage.Scriptable) {
1✔
308
                return "Image";
1✔
309
            }
310
            if (delegate instanceof SelectionOptions) {
1✔
311
                return "Options";
1✔
312
            }
313
            if (delegate instanceof SelectionOption) {
1✔
314
                return "Option";
1✔
315
            }
316
            if (delegate instanceof Input) {
1✔
317
                return "Control";
1✔
318
            }
319
            if (delegate instanceof DocumentElement) {
1!
320
                return "HTMLElement";
1✔
321
            }
322

323
            throw new IllegalArgumentException("Unknown ScriptableDelegate class: " + delegate.getClass());
×
324
        }
325

326
        protected ElementArray toElementArray(ScriptingHandler[] scriptables) {
327
            JavaScriptEngine[] elements = new JavaScriptEngine[scriptables.length];
1✔
328
            for (int i = 0; i < elements.length; i++) {
1✔
329
                elements[i] = (JavaScriptEngine) toScriptable((ScriptableDelegate) scriptables[i]);
1✔
330
            }
331
            ElementArray result = ElementArray.newElementArray(this);
1✔
332
            result.initialize(elements);
1✔
333
            return result;
1✔
334
        }
335

336
        /**
337
         * {@inheritDoc}
338
         */
339
        @Override
340
        public void jsFunction_addEventListener(String type, Scriptable listener, boolean useCapture) {
341
            if (useCapture) {
×
342
                Set set = (Set) _eventCaptureListeners.get(type); // Set<Scriptable>
×
343
                if (set == null) {
×
NEW
344
                    set = new HashSet<>();
×
345
                    _eventCaptureListeners.put(type, set);
×
346
                }
347
                set.add(listener);
×
348
            } else {
×
349
                Set set = (Set) _eventListeners.get(type); // Set<Scriptable>
×
350
                if (set == null) {
×
NEW
351
                    set = new HashSet<>();
×
352
                    _eventListeners.put(type, set);
×
353
                }
354
                set.add(listener);
×
355
            }
356
            // System.out.println(getClassName()+".addEventListener("+type+")");
357
        }
×
358

359
        /**
360
         * {@inheritDoc}
361
         */
362
        @Override
363
        public boolean jsFunction_dispatchEvent(Scriptable evt) throws EventException {
364
            // TODO implement event dispatching & listener invocation
365
            // System.out.println(getClassName()+".dispatchEvent("+evt.get("type",evt)+")");
366
            return true;
×
367
        }
368

369
        /**
370
         * {@inheritDoc}
371
         */
372
        @Override
373
        public void jsFunction_removeEventListener(String type, Scriptable listener, boolean useCapture) {
374
            if (useCapture) {
×
375
                Set set = (Set) _eventCaptureListeners.get(type); // Set<EventListener>
×
376
                if (set != null) {
×
377
                    set.remove(listener);
×
378
                }
379
            } else {
×
380
                Set set = (Set) _eventListeners.get(type); // Set<EventListener>
×
381
                if (set != null) {
×
382
                    set.remove(listener);
×
383
                }
384
            }
385
            // System.out.println(getClassName()+".removeEventListener("+type+")");
386
        }
×
387
    }
388

389
    /**
390
     * Window functions
391
     */
392
    static public class Window extends JavaScriptEngine {
1✔
393

394
        private static final long serialVersionUID = 1L;
395
        private Document _document;
396
        private Navigator _navigator;
397
        private Location _location;
398
        private Screen _screen;
399
        private ElementArray _frames;
400

401
        @Override
402
        public String getClassName() {
403
            return "Window";
1✔
404
        }
405

406
        public Window jsGet_window() {
407
            return this;
1✔
408
        }
409

410
        public Window jsGet_self() {
411
            return this;
×
412
        }
413

414
        public Document jsGet_document() {
415
            if (_document == null) {
1✔
416
                _document = (Document) toScriptable(getDelegate().getDocument());
1✔
417
            }
418
            return _document;
1✔
419
        }
420

421
        public Scriptable jsGet_frames() throws SAXException, JavaScriptException, EvaluatorException {
422
            if (_frames == null) {
1✔
423
                WebResponse.Scriptable[] scriptables = getDelegate().getFrames();
1✔
424
                Window[] frames = new Window[scriptables.length];
1✔
425
                for (int i = 0; i < frames.length; i++) {
1✔
426
                    frames[i] = (Window) toScriptable(scriptables[i]);
1✔
427
                }
428
                _frames = (ElementArray) Context.getCurrentContext().newObject(this, "ElementArray");
1✔
429
                _frames.initialize(frames);
1✔
430
            }
431
            return _frames;
1✔
432
        }
433

434
        public Navigator jsGet_navigator() {
435
            return _navigator;
1✔
436
        }
437

438
        public Screen jsGet_screen() {
439
            return _screen;
1✔
440
        }
441

442
        public Location jsGet_location() {
443
            return _location;
1✔
444
        }
445

446
        public void jsSet_location(String relativeURL) throws IOException, SAXException {
447
            setLocation(relativeURL);
1✔
448
        }
1✔
449

450
        void setLocation(String relativeURL) throws IOException, SAXException {
451
            getDelegate().setLocation(relativeURL);
1✔
452
        }
1✔
453

454
        /**
455
         * initialize JavaScript for the given ScriptEngine
456
         *
457
         * @parent - the Script Engine to use
458
         *
459
         * @scriptable - the scriptable object to do the initialization for
460
         */
461
        @Override
462
        void initialize(JavaScriptEngine parent, ScriptableDelegate scriptable)
463
                throws JavaScriptException, EvaluatorException, SAXException {
464
            super.initialize(parent, scriptable);
1✔
465

466
            _location = (Location) Context.getCurrentContext().newObject(this, "Location");
1✔
467
            _location.initialize(this, ((WebResponse.Scriptable) scriptable).getURL());
1✔
468

469
            _navigator = (Navigator) Context.getCurrentContext().newObject(this, "Navigator");
1✔
470
            _navigator.setClientProperties(getDelegate().getClientProperties());
1✔
471

472
            _screen = (Screen) Context.getCurrentContext().newObject(this, "Screen");
1✔
473
            _screen.setClientProperties(getDelegate().getClientProperties());
1✔
474
        }
1✔
475

476
        /**
477
         * javascript alert handling
478
         *
479
         * @param message
480
         *            - the alert message
481
         */
482
        public void jsFunction_alert(String message) {
483
            getDelegate().alertUser(message);
1✔
484
        }
1✔
485

486
        /**
487
         * javascript built in function "toLowerCase"
488
         *
489
         * @param s
490
         */
491
        public String jsFunction_toLowerCase(String s) {
492
            return s.toLowerCase();
1✔
493
        }
494

495
        public boolean jsFunction_confirm(String message) {
496
            return getDelegate().getConfirmationResponse(message);
1✔
497
        }
498

499
        public String jsFunction_prompt(String message, String defaultResponse) {
500
            return getDelegate().getUserResponse(message, defaultResponse);
1✔
501
        }
502

503
        public void jsFunction_moveTo(int x, int y) {
504
        }
×
505

506
        public void jsFunction_scrollTo(int x, int y) {
507
        }
×
508

509
        public void jsFunction_focus() {
510
        }
×
511

512
        public void jsFunction_setTimeout() {
513
        }
×
514

515
        public void jsFunction_close() {
516
            getDelegate().closeWindow();
1✔
517
        }
1✔
518

519
        public Window jsFunction_open(Object url, String name, String features, boolean replace)
520
                throws JavaScriptException, EvaluatorException, IOException, SAXException {
521
            WebResponse.Scriptable delegate = getDelegate().open(toStringIfNotUndefined(url), name, features, replace);
1✔
522
            return delegate == null ? null : (Window) toScriptable(delegate);
1✔
523
        }
524

525
        /** The global "event" object is not supported, so return null (instead of causing '"event" is not defined') */
526
        public Location jsGet_event() {
527
            return null;
×
528
        }
529

530
        @Override
531
        public void clearCaches() {
532
            if (_document != null) {
1✔
533
                _document.clearCaches();
1✔
534
            }
535
        }
1✔
536

537
        @Override
538
        protected String getDocumentWriteBuffer() {
539
            return jsGet_document().getWriteBuffer().toString();
1✔
540
        }
541

542
        @Override
543
        protected void discardDocumentWriteBuffer() {
544
            jsGet_document().clearWriteBuffer();
1✔
545
        }
1✔
546

547
        private WebResponse.Scriptable getDelegate() {
548
            return (WebResponse.Scriptable) _scriptable;
1✔
549
        }
550
    }
551

552
    /**
553
     * Document script handling
554
     */
555
    static public class Document extends JavaScriptEngine {
1✔
556

557
        private static final long serialVersionUID = 1L;
558
        private ElementArray _forms;
559
        private ElementArray _links;
560
        private ElementArray _images;
561
        private StringBuilder _writeBuffer;
562
        private String _mimeType;
563

564
        @Override
565
        public String getClassName() {
566
            return "Document";
1✔
567
        }
568

569
        @Override
570
        public void clearCaches() {
571
            _forms = _links = _images = null;
1✔
572
        }
1✔
573

574
        public String jsGet_title() throws SAXException {
575
            return getDelegate().getTitle();
1✔
576
        }
577

578
        public Scriptable jsGet_images() throws SAXException {
579
            if (_images == null) {
1✔
580
                _images = toElementArray(getDelegate().getImages());
1✔
581
            }
582
            return _images;
1✔
583
        }
584

585
        public Scriptable jsGet_links() throws SAXException {
586
            if (_links == null) {
1✔
587
                _links = toElementArray(getDelegate().getLinks());
1✔
588
            }
589
            return _links;
1✔
590
        }
591

592
        public Scriptable jsGet_forms() throws SAXException {
593
            if (_forms == null) {
1✔
594
                _forms = toElementArray(getDelegate().getForms());
1✔
595
            }
596
            return _forms;
1✔
597
        }
598

599
        public Object jsFunction_getElementById(String id) {
600
            ScriptableDelegate elementWithID = getDelegate().getElementWithID(id);
1✔
601
            return elementWithID == null ? null : toScriptable(elementWithID);
1✔
602
        }
603

604
        public Object jsFunction_getElementsByName(String name) {
605
            return toElementArray(getDelegate().getElementsByName(name));
1✔
606
        }
607

608
        public Object jsFunction_getElementsByTagName(String name) {
609
            return toElementArray(getDelegate().getElementsByTagName(name));
1✔
610
        }
611

612
        public Object jsGet_location() {
613
            return _parent == null ? NOT_FOUND : getWindow().jsGet_location();
1!
614
        }
615

616
        public void jsSet_location(String urlString) throws IOException, SAXException {
617
            if (urlString.startsWith("color")) {
1!
618
                return;
×
619
            }
620
            getWindow().setLocation(urlString);
1✔
621
        }
1✔
622

623
        public String jsGet_cookie() {
624
            return getDelegate().getCookie();
1✔
625
        }
626

627
        public void jsSet_cookie(String cookieSpec) {
628
            final int equalsIndex = cookieSpec.indexOf('=');
1✔
629
            if (equalsIndex < 0) {
1✔
630
                return;
1✔
631
            }
632
            int endIndex = cookieSpec.indexOf(";", equalsIndex);
1✔
633
            if (endIndex < 0) {
1!
634
                endIndex = cookieSpec.length();
×
635
            }
636
            String name = cookieSpec.substring(0, equalsIndex);
1✔
637
            String value = cookieSpec.substring(equalsIndex + 1, endIndex);
1✔
638
            getDelegate().setCookie(name, value);
1✔
639
        }
1✔
640

641
        private Window getWindow() {
642
            return (Window) _parent;
1✔
643
        }
644

645
        public void jsFunction_open(Object mimeType) {
646
            _mimeType = toStringIfNotUndefined(mimeType);
1✔
647
        }
1✔
648

649
        public void jsFunction_close() {
650
            if (getDelegate().replaceText(getWriteBuffer().toString(), _mimeType == null ? "text/html" : _mimeType)) {
1✔
651
                getWriteBuffer().setLength(0);
1✔
652
            }
653
        }
1✔
654

655
        public void jsFunction_write(String string) {
656
            getWriteBuffer().append(string);
1✔
657
        }
1✔
658

659
        public void jsFunction_writeln(String string) {
660
            getWriteBuffer().append(string).append((char) 0x0D).append((char) 0x0A);
1✔
661
        }
1✔
662

663
        protected StringBuilder getWriteBuffer() {
664
            if (_writeBuffer == null) {
1✔
665
                _writeBuffer = new StringBuilder();
1✔
666
            }
667
            return _writeBuffer;
1✔
668
        }
669

670
        protected void clearWriteBuffer() {
671
            _writeBuffer = null;
1✔
672
        }
1✔
673

674
        private HTMLPage.Scriptable getDelegate() {
675
            return (HTMLPage.Scriptable) _scriptable;
1✔
676
        }
677

678
        @Override
679
        public void jsFunction_addEventListener(String type, Scriptable listener, boolean useCapture) {
680
            // TODO Auto-generated method stub
681

682
        }
×
683

684
        @Override
685
        public boolean jsFunction_dispatchEvent(Scriptable evt) throws EventException {
686
            // TODO Auto-generated method stub
687
            return false;
×
688
        }
689

690
        @Override
691
        public void jsFunction_removeEventListener(String type, Scriptable listener, boolean useCapture) {
692
            // TODO Auto-generated method stub
693

694
        }
×
695

696
    }
697

698
    static public class Location extends JavaScriptEngine {
1✔
699

700
        private static final long serialVersionUID = 1L;
701
        private URL _url;
702
        private Window _window;
703

704
        @Override
705
        public String getClassName() {
706
            return "Location";
1✔
707
        }
708

709
        void initialize(Window window, URL url) {
710
            _window = window;
1✔
711
            _url = url;
1✔
712
        }
1✔
713

714
        public void jsFunction_replace(String urlString) throws IOException, SAXException {
715
            _window.setLocation(urlString);
1✔
716
        }
1✔
717

718
        public String jsGet_href() {
719
            return toString();
1✔
720
        }
721

722
        public void jsSet_href(String urlString) throws SAXException, IOException {
723
            _window.setLocation(urlString);
1✔
724
        }
1✔
725

726
        public String jsGet_protocol() {
727
            return _url.getProtocol() + ':';
1✔
728
        }
729

730
        public String jsGet_host() {
731
            return _url.getHost() + ':' + _url.getPort();
1✔
732
        }
733

734
        public String jsGet_hostname() {
735
            return _url.getHost();
1✔
736
        }
737

738
        public String jsGet_port() {
739
            return String.valueOf(_url.getPort());
1✔
740
        }
741

742
        public String jsGet_pathname() {
743
            return _url.getPath();
1✔
744
        }
745

746
        public void jsSet_pathname(String newPath) throws SAXException, IOException {
747
            if (!newPath.startsWith("/")) {
1!
748
                newPath = '/' + newPath;
×
749
            }
750
            URL newURL = new URL(_url, newPath);
1✔
751
            _window.setLocation(newURL.toExternalForm());
1✔
752
        }
1✔
753

754
        public String jsGet_search() {
755
            return '?' + _url.getQuery();
1✔
756
        }
757

758
        public void jsSet_search(String newSearch) throws SAXException, IOException {
759
            if (!newSearch.startsWith("?")) {
1!
760
                newSearch = '?' + newSearch;
×
761
            }
762
            _window.setLocation(jsGet_protocol() + "//" + jsGet_host() + jsGet_pathname() + newSearch);
1✔
763
        }
1✔
764

765
        /**
766
         * Returns the default value of this scriptable object. In this case, it returns simply the URL as a string.
767
         * Note that this method is necessary, since Rhino will only call the toString method directly if there are no
768
         * Rhino methods defined (jsGet_*, jsFunction_*, etc.)
769
         */
770
        @Override
771
        public Object getDefaultValue(Class typeHint) {
772
            return _url.toExternalForm();
1✔
773
        }
774

775
        @Override
776
        public String toString() {
777
            return _url.toExternalForm();
1✔
778
        }
779

780
    }
781

782
    static public class Style extends JavaScriptEngine {
1✔
783

784
        private static final long serialVersionUID = 1L;
785
        private String _display = "inline";
1✔
786
        private String _visibility = "visible";
1✔
787

788
        @Override
789
        public String getClassName() {
790
            return "Style";
1✔
791
        }
792

793
        public String jsGet_display() {
794
            return _display;
1✔
795
        }
796

797
        public void jsSet_display(String display) {
798
            _display = display;
1✔
799
        }
1✔
800

801
        public String jsGet_visibility() {
802
            return _visibility;
1✔
803
        }
804

805
        public void jsSet_visibility(String visibility) {
806
            _visibility = visibility;
1✔
807
        }
1✔
808
    }
809

810
    static public class Navigator extends JavaScriptEngine {
1✔
811

812
        private static final long serialVersionUID = 1L;
813
        private ClientProperties _clientProperties;
814

815
        @Override
816
        public String getClassName() {
817
            return "Navigator";
1✔
818
        }
819

820
        void setClientProperties(ClientProperties clientProperties) {
821
            _clientProperties = clientProperties;
1✔
822
        }
1✔
823

824
        public String jsGet_appName() {
825
            return _clientProperties.getApplicationName();
1✔
826
        }
827

828
        public String jsGet_appCodeName() {
829
            return _clientProperties.getApplicationCodeName();
1✔
830
        }
831

832
        public String jsGet_appVersion() {
833
            return _clientProperties.getApplicationVersion();
1✔
834
        }
835

836
        public String jsGet_userAgent() {
837
            return _clientProperties.getUserAgent();
1✔
838
        }
839

840
        public String jsGet_platform() {
841
            return _clientProperties.getPlatform();
1✔
842
        }
843

844
        public Object[] jsGet_plugins() {
845
            return new Object[0];
1✔
846
        }
847

848
        public boolean jsFunction_javaEnabled() {
849
            return false; // no support is provided for applets at present
1✔
850
        }
851

852
    }
853

854
    static public class Screen extends JavaScriptEngine {
1✔
855

856
        private static final long serialVersionUID = 1L;
857
        private ClientProperties _clientProperties;
858

859
        void setClientProperties(ClientProperties clientProperties) {
860
            _clientProperties = clientProperties;
1✔
861
        }
1✔
862

863
        @Override
864
        public String getClassName() {
865
            return "Screen";
1✔
866
        }
867

868
        public int jsGet_availWidth() {
869
            return _clientProperties.getAvailableScreenWidth();
1✔
870
        }
871

872
        public int jsGet_availHeight() {
873
            return _clientProperties.getAvailHeight();
1✔
874
        }
875

876
    }
877

878
    static public class ElementArray extends ScriptableObject {
879

880
        private static final long serialVersionUID = 1L;
881
        private JavaScriptEngine[] _contents = new HTMLElement[0];
1✔
882

883
        static ElementArray newElementArray(Scriptable parent) {
884
            try {
885
                return (ElementArray) Context.getCurrentContext().newObject(parent, "ElementArray");
1✔
886
            } catch (EvaluatorException | JavaScriptException e) {
×
887
                throw new RhinoException(e);
×
888
            }
889
        }
890

891
        public ElementArray() {
1✔
892
        }
1✔
893

894
        void initialize(JavaScriptEngine[] contents) {
895
            _contents = contents;
1✔
896
        }
1✔
897

898
        public int jsGet_length() {
899
            return _contents.length;
1✔
900
        }
901

902
        @Override
903
        public String getClassName() {
904
            return "ElementArray";
1✔
905
        }
906

907
        @Override
908
        public Object get(int i, Scriptable scriptable) {
909
            if (i >= 0 && i < _contents.length) {
1!
910
                return _contents[i];
1✔
911
            }
912
            return super.get(i, scriptable);
×
913
        }
914

915
        @Override
916
        public Object get(String name, Scriptable scriptable) {
917
            for (JavaScriptEngine content : _contents) {
1✔
918
                if (name.equalsIgnoreCase(content.getID())) {
1✔
919
                    return content;
1✔
920
                }
921
            }
922
            for (JavaScriptEngine content : _contents) {
1✔
923
                if (name.equalsIgnoreCase(content.getName())) {
1✔
924
                    return content;
1✔
925
                }
926
            }
927
            return super.get(name, scriptable);
1✔
928
        }
929

930
        protected JavaScriptEngine[] getContents() {
931
            return _contents;
×
932
        }
933
    }
934

935
    /**
936
     * HTML Element support for JavaScript
937
     */
938
    static public class HTMLElement extends JavaScriptEngine {
1✔
939

940
        private static final long serialVersionUID = 1L;
941
        private Style _style;
942
        private Document _document;
943

944
        @Override
945
        public String getClassName() {
946
            return "HTMLElement";
1✔
947
        }
948

949
        public Document jsGet_document() {
950
            return _document;
1✔
951
        }
952

953
        public Style jsGet_style() {
954
            return _style;
1✔
955
        }
956

957
        /**
958
         * arbitrary attribute access
959
         *
960
         * @param attributeName
961
         *
962
         * @return
963
         */
964
        public Object jsFunction_getAttribute(String attributeName) {
965
            return _scriptable.get(attributeName);
×
966
        }
967

968
        @Override
969
        void initialize(JavaScriptEngine parent, ScriptableDelegate scriptable)
970
                throws JavaScriptException, EvaluatorException, SAXException {
971
            super.initialize(parent, scriptable);
1✔
972
            _document = (Document) parent;
1✔
973
            _style = (Style) Context.getCurrentContext().newObject(this, "Style");
1✔
974
        }
1✔
975

976
    }
977

978
    static public class Image extends HTMLElement {
1✔
979

980
        private static final long serialVersionUID = 1L;
981

982
        @Override
983
        public String getClassName() {
984
            return "Image";
1✔
985
        }
986
    }
987

988
    static public class Link extends HTMLElement {
1✔
989

990
        private static final long serialVersionUID = 1L;
991

992
        @Override
993
        public Document jsGet_document() {
994
            return super.jsGet_document();
1✔
995
        }
996

997
        @Override
998
        public String getClassName() {
999
            return "Link";
1✔
1000
        }
1001
    }
1002

1003
    /**
1004
     * Form functions
1005
     */
1006
    static public class Form extends HTMLElement {
1✔
1007

1008
        private static final long serialVersionUID = 1L;
1009
        private ElementArray _controls;
1010

1011
        @Override
1012
        public String getClassName() {
1013
            return "Form";
1✔
1014
        }
1015

1016
        public String jsGet_name() {
1017
            return getDelegate().getName();
1✔
1018
        }
1019

1020
        /**
1021
         * @since FR [ 2163079 ] make form.name property mutable by Peter De Bruycker
1022
         *
1023
         * @param name
1024
         */
1025
        public void jsSet_name(String name) {
1026
            getDelegate().set("name", name);
1✔
1027
        }
1✔
1028

1029
        public String jsGet_action() {
1030
            return getDelegate().getAction();
×
1031
        }
1032

1033
        public void jsSet_action(String action) {
1034
            getDelegate().setAction(action);
×
1035
        }
×
1036

1037
        public Scriptable jsGet_elements() throws EvaluatorException, JavaScriptException {
1038
            if (_controls == null) {
1✔
1039
                initializeControls();
1✔
1040
            }
1041
            return _controls;
1✔
1042
        }
1043

1044
        public Object jsFunction_getElementsByTagName(String name) throws SAXException {
1045
            return toElementArray(getDelegate().getElementsByTagName(name));
1✔
1046
        }
1047

1048
        public void jsFunction_submit() throws IOException, SAXException {
1049
            getDelegate().submit();
1✔
1050
        }
1✔
1051

1052
        public void jsFunction_reset() throws IOException, SAXException {
1053
            getDelegate().reset();
1✔
1054
        }
1✔
1055

1056
        private void initializeControls() throws EvaluatorException, JavaScriptException {
1057
            ScriptableDelegate[] scriptables = getDelegate().getElementDelegates();
1✔
1058
            Control[] controls = new Control[scriptables.length];
1✔
1059
            for (int i = 0; i < controls.length; i++) {
1✔
1060
                controls[i] = (Control) toScriptable(scriptables[i]);
1✔
1061
            }
1062
            _controls = (ElementArray) Context.getCurrentContext().newObject(this, "ElementArray");
1✔
1063
            _controls.initialize(controls);
1✔
1064
        }
1✔
1065

1066
        private WebForm.Scriptable getDelegate() {
1067
            return (WebForm.Scriptable) _scriptable;
1✔
1068
        }
1069

1070
    }
1071

1072
    /**
1073
     * Javascript support for any control
1074
     */
1075
    static public class Control extends JavaScriptEngine {
1✔
1076

1077
        private static final long serialVersionUID = 1L;
1078
        private Form _form;
1079

1080
        @Override
1081
        public String getClassName() {
1082
            return "Control";
1✔
1083
        }
1084

1085
        public Form jsGet_form() {
1086
            return _form;
1✔
1087
        }
1088

1089
        public void jsFunction_focus() {
1090
        }
×
1091

1092
        public void jsFunction_select() {
1093
        }
×
1094

1095
        /**
1096
         * click via javascript
1097
         *
1098
         * @throws IOException
1099
         * @throws SAXException
1100
         */
1101
        public void jsFunction_click() throws IOException, SAXException {
1102
            getDelegate().click();
1✔
1103
        }
1✔
1104

1105
        private Input getDelegate() {
1106
            return (Input) _scriptable;
1✔
1107
        }
1108

1109
        /** Support getting value of arbitrary attribute */
1110
        public Object jsFunction_getAttribute(String attributeName) throws JavaScriptException {
1111
            return getDelegate().get(attributeName);
1✔
1112
        }
1113

1114
        /** Support getting value of arbitrary attribute */
1115
        public void jsFunction_setAttribute(String attributeName, Object value) throws JavaScriptException {
1116
            getDelegate().setAttribute(attributeName, value);
1✔
1117
        }
1✔
1118

1119
        /** Support getting value of arbitrary attribute */
1120
        public void jsFunction_removeAttribute(String attributeName) throws JavaScriptException {
1121
            getDelegate().removeAttribute(attributeName);
×
1122
        }
×
1123

1124
        /** Allow calling onchange() from within a JavaScript function */
1125
        public void jsFunction_onchange() throws JavaScriptException {
1126
            Input myInput = this.getDelegate();
1✔
1127
            myInput.sendOnChangeEvent();
1✔
1128
        }
1✔
1129

1130
        @Override
1131
        void initialize(JavaScriptEngine parent, ScriptableDelegate scriptable)
1132
                throws JavaScriptException, EvaluatorException, SAXException {
1133
            super.initialize(parent, scriptable);
1✔
1134
            if (parent instanceof Form) {
1✔
1135
                _form = (Form) parent;
1✔
1136
            }
1137
        }
1✔
1138

1139
    }
1140

1141
    static public class Options extends JavaScriptEngine {
1✔
1142

1143
        private static final long serialVersionUID = 1L;
1144

1145
        @Override
1146
        public String getClassName() {
1147
            return "Options";
1✔
1148
        }
1149

1150
        public int jsGet_length() {
1151
            return getDelegate().getLength();
1✔
1152
        }
1153

1154
        public void jsSet_length(int length) {
1155
            getDelegate().setLength(length);
1✔
1156
        }
1✔
1157

1158
        @Override
1159
        public void put(int i, Scriptable scriptable, Object object) {
1160
            if (object == null) {
1✔
1161
                getDelegate().put(i, null);
1✔
1162
            } else {
1163
                if (!(object instanceof Option)) {
1!
1164
                    throw new IllegalArgumentException("May only add an Option to this array");
×
1165
                }
1166
                Option option = (Option) object;
1✔
1167
                getDelegate().put(i, option.getDelegate());
1✔
1168
            }
1169
        }
1✔
1170

1171
        private SelectionOptions getDelegate() {
1172
            return (SelectionOptions) _scriptable;
1✔
1173
        }
1174

1175
    }
1176

1177
    static public class Option extends JavaScriptEngine {
1✔
1178

1179
        private static final long serialVersionUID = 1L;
1180

1181
        @Override
1182
        public String getClassName() {
1183
            return "Option";
1✔
1184
        }
1185

1186
        public void jsConstructor(String text, String value, boolean defaultSelected, boolean selected) {
1187
            _scriptable = WebResponse.newDelegate("Option");
1✔
1188
            getDelegate().initialize(text, value, defaultSelected, selected);
1✔
1189
        }
1✔
1190

1191
        public int jsGet_index() {
1192
            return getDelegate().getIndex();
1✔
1193
        }
1194

1195
        public String jsGet_text() {
1196
            return getDelegate().getText();
1✔
1197
        }
1198

1199
        public void jsSet_text(String text) {
1200
            getDelegate().setText(text);
1✔
1201
        }
1✔
1202

1203
        public String jsGet_value() {
1204
            return getDelegate().getValue();
1✔
1205
        }
1206

1207
        public void jsSet_value(String value) {
1208
            getDelegate().setValue(value);
1✔
1209
        }
1✔
1210

1211
        public boolean jsGet_selected() {
1212
            return getDelegate().isSelected();
1✔
1213
        }
1214

1215
        public void jsSet_selected(boolean selected) {
1216
            getDelegate().setSelected(selected);
1✔
1217
        }
1✔
1218

1219
        public boolean jsGet_defaultSelected() {
1220
            return getDelegate().isDefaultSelected();
×
1221
        }
1222

1223
        SelectionOption getDelegate() {
1224
            return (SelectionOption) _scriptable;
1✔
1225
        }
1226
    }
1227

1228
}
1229

1230
/**
1231
 * special exception for the Rhino Javscript engine
1232
 */
1233
class RhinoException extends RuntimeException {
1234

1235
    private static final long serialVersionUID = 1L;
1236
    private Exception _cause;
1237

1238
    public RhinoException(Exception cause) {
×
1239
        _cause = cause;
×
1240
    }
×
1241

1242
    @Override
1243
    public String getMessage() {
1244
        return "Rhino exception: " + _cause;
×
1245
    }
1246
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc