View Javadoc
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 }