1 /*
2 * Copyright (c) 2002-2025 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.event;
16
17 import org.htmlunit.corejs.javascript.BaseFunction;
18 import org.htmlunit.corejs.javascript.Context;
19 import org.htmlunit.corejs.javascript.Function;
20 import org.htmlunit.corejs.javascript.JavaScriptException;
21 import org.htmlunit.corejs.javascript.Scriptable;
22 import org.htmlunit.html.DomNode;
23
24 /**
25 * Allows to wrap event handler code as Function object.
26 *
27 * @author Marc Guillemot
28 * @author Ronald Brill
29 */
30 public class EventHandler extends BaseFunction {
31 private final DomNode node_;
32 private final String eventName_;
33 private final String jsSnippet_;
34 private Function realFunction_;
35
36 /**
37 * Builds a function that will execute the JavaScript code provided.
38 * @param node the element for which the event is build
39 * @param eventName the event for which this handler is created
40 * @param jsSnippet the JavaScript code
41 */
42 public EventHandler(final DomNode node, final String eventName, final String jsSnippet) {
43 super();
44 node_ = node;
45 eventName_ = eventName;
46 jsSnippet_ = jsSnippet;
47 }
48
49 /**
50 * {@inheritDoc}
51 */
52 @Override
53 public Object call(final Context cx, final Scriptable scope,
54 final Scriptable thisObj, final Object[] args)
55 throws JavaScriptException {
56
57 // the js object to which this event is attached has to be the scope
58 // final HtmlUnitScriptable jsObj = node_.getScriptableObject();
59 // have changed this - the scope is now thisObj to fix
60 // https://github.com/HtmlUnit/htmlunit/issues/347
61 // but still have not found any description about the right scope
62
63 // compile "just in time"
64 if (realFunction_ == null) {
65 final String js = "function on" + eventName_ + "(event) { " + jsSnippet_ + " \n}";
66 realFunction_ = cx.compileFunction(thisObj, js, eventName_ + " event for " + node_
67 + " in " + node_.getPage().getUrl(), 0, null);
68 realFunction_.setParentScope(thisObj);
69 }
70
71 return realFunction_.call(cx, scope, thisObj, args);
72 }
73
74 /**
75 * @see org.htmlunit.corejs.javascript.ScriptableObject#getDefaultValue(java.lang.Class)
76 * @param typeHint the type hint
77 * @return the js code of the function declaration
78 */
79 @Override
80 public Object getDefaultValue(final Class<?> typeHint) {
81 return "function on" + eventName_ + "(event) { " + jsSnippet_ + " }";
82 }
83
84 /**
85 * {@inheritDoc}
86 */
87 @Override
88 public Object get(final String name, final Scriptable start) {
89 // quick and dirty
90 if ("toString".equals(name)) {
91 return new BaseFunction() {
92 @Override
93 public Object call(final Context cx, final Scriptable scope,
94 final Scriptable thisObj, final Object[] args) {
95 return "function on" + eventName_ + "(event) { " + jsSnippet_ + " }";
96 }
97 };
98 }
99
100 return super.get(name, start);
101 }
102 }