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