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