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   * 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 }