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