001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.event;
021 
022 import js.ArrayLike;
023 import js.Disposable;
024 import js.Id;
025 import js.Js;
026 import js.ObjectLike;
027 import js.Static;
028 import js.Value;
029 import js.Var;
030 import js.Vars;
031 import js.core.JsFunction;
032 import js.core.JsObject;
033 import js.dom.EventTarget;
034 import jsx.Code;
035 import jsx.client.Browser;
036 import jsx.core.ArrayLikes;
037 
038 /**
039  * <p>A class of browser event handles that handle browser events and their listening functions,
040  * eliminating browser dependencies.</p>
041  * 
042  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
043  */
044 public final class Handle extends Disposable
045 {
046     private final EventTarget et;
047     private final String eventtype;
048     private final JsFunction<?> listener;
049     private final boolean useCapture;
050     private boolean attached;
051 
052     /**
053      * <p>Constructs a browser-level event handle.</p>
054      * @param et The browser event target.
055      * @param eventtype The browser event type.
056      * @param listener A browser event listening function.
057      * @param useCapture Specifies whether the <tt>listener</tt> is to be invoked only during 
058      * the capturing phase of event propagation.
059      * @see EventTarget#addEventListener(String, JsFunction, Boolean)
060      * @see EventTarget#attachEvent(String, JsFunction)
061      * @see EventTarget#removeEventListener(String, JsFunction, Boolean)
062      * @see EventTarget#detachEvent(String, JsFunction)
063      * @since 1.0
064      */
065     public Handle(EventTarget et, String eventtype, JsFunction<?> listener, boolean useCapture) {
066         this.et = et;
067         this.eventtype = Browser.isIE ?
068                 new Value.String("on").add(eventtype).var() : eventtype;
069         this.listener = listener;
070         this.useCapture = useCapture;
071         this.attached = false;
072     }
073 
074     /**
075      * <p>Adds the browser event listener to the set of event handlers for the event target.</p>
076      * @see EventTarget#addEventListener(String, JsFunction, Boolean)
077      * @see EventTarget#attachEvent(String, JsFunction)
078      * @see #attach(Handle)
079      * @since 1.0
080      */
081     public final void attach() {
082         if (attached) return;
083         attached = true;
084         if (Browser.isIE) {
085             et.attachEvent(
086                     eventtype, listener
087             );
088         } else {
089             et.addEventListener(
090                     eventtype, listener, useCapture
091             );
092         }
093     }
094 
095     /**
096      * <p>Attaches a handle if it exists.</p>
097      * @param h The handle to manipulate.
098      * @see #attach()
099      * @see EventTarget#addEventListener(String, JsFunction, Boolean)
100      * @see EventTarget#attachEvent(String, JsFunction)
101      * @since 1.0
102      */
103     public static final void attach(Handle h) {
104         if (Js.be(h)) {
105             h.attach();
106         }
107     }
108 
109     /**
110      * <p>Detaches a handle if it exists.</p>
111      * @param h The handle to manipulate.
112      * @see #detach()
113      * @see #detach(ObjectLike, ArrayLike)
114      * @see EventTarget#removeEventListener(String, JsFunction, Boolean)
115      * @see EventTarget#detachEvent(String, JsFunction)
116      * @since 1.0
117      */
118     public static final void detach(Handle h) {
119         if (Js.be(h)) {
120             h.detach();
121         }
122     }
123 
124     /**
125      * <p>Detaches handles in bulk.</p>
126      * @param ini An object that keeps the handles.
127      * @param hids The ids of the handles.
128      * @see #detach()
129      * @see #detach(Handle)
130      * @see EventTarget#removeEventListener(String, JsFunction, Boolean)
131      * @see EventTarget#detachEvent(String, JsFunction)
132      * @since 1.0
133      */
134     public static final void detach(ObjectLike ini, ArrayLike<Id<Handle>> hids) {
135         for (int i = 0, len = ArrayLikes.length(hids); i < len; i++) {
136             detach(ini.var(hids.get(i)));
137         }
138     }
139 
140     /**
141      * <p>Removes the browser event listener from the set of event handlers for the event target.</p>
142      * @see EventTarget#removeEventListener(String, JsFunction, Boolean)
143      * @see EventTarget#detachEvent(String, JsFunction)
144      * @see #detach(Handle)
145      * @see #detach(ObjectLike, ArrayLike)
146      * @since 1.0
147      */
148     public final void detach() {
149         if (!attached) return;
150         attached = false;
151         if (Browser.isIE) {
152             et.detachEvent(
153                     eventtype, listener
154             );
155         } else {
156             et.removeEventListener(
157                     eventtype, listener, useCapture
158             );
159         }
160     }
161 
162     /**
163      * <p>A global JavaScript function that creates browser event handlers.</p>
164      * <p>This function returns an event handler function that handles browser events more 
165      * efficiently, especially in JS Simulation mode, if invoked with the first argument 
166      * being the browser event object to handle and the second argument being a function that 
167      * performs an action.</p>
168      * @since 1.0
169      */
170     public final static Var<JsFunction<JsObject>> HANDLER = new Static<JsFunction<JsObject>>(
171             new Var<JsFunction<JsObject>>() {
172                 @Override
173                 public JsFunction<JsObject> var() {
174                     return Js.function(
175                             new Vars<String>().add("e").add("f"),
176                             Code.ret(
177                                     Code.function(
178                                             Code.call("f", "e")
179                                     )
180                             )
181                     );
182                 }
183             }
184     );
185 
186     /**
187      * <p>An IE specific global JavaScript function that creates browser event handlers.</p>
188      * <p>This function returns an event handler function that handles browser events more 
189      * efficiently, especially in JS Simulation mode, if invoked with the argument being a 
190      * function that performs an action with {@link js.user.JsWindow#event} as its argument.</p>
191      * @since 1.0
192      */
193     public final static Var<JsFunction<JsObject>> IE = new Static<JsFunction<JsObject>>(
194             new Var<JsFunction<JsObject>>() {
195                 @Override
196                 public JsFunction<JsObject> var() {
197                     return Js.function(
198                             "f",
199                             Code.ret(
200                                     Code.function(
201                                             Code.invoke("f", "event")
202                                     )
203                             )
204                     );
205                 }
206             }
207     );
208 
209     /**
210      * <p>A global JavaScript function that creates browser event handlers that 
211      * simply return <tt>false</tt> without doing anything else.</p>
212      * <p>This function returns an event handler function that handles browser events more 
213      * efficiently, especially in JS Simulation mode, if invoked with the argument 
214      * being a browser event object.</p>
215      * @since 1.0
216      */
217     public final static Var<JsFunction<Void>> FALSE = new Static<JsFunction<Void>>(
218             new Var<JsFunction<Void>>() {
219                 @Override
220                 public JsFunction<Void> var() {
221                     return Js.function(
222                             "e",
223                             Code.ret(
224                                     "false"
225                             )
226                     );
227                 }
228             }
229     );
230 
231     /**
232      * <p>A global JavaScript function that creates browser event handlers that 
233      * simply set {@link js.user.JsEvent#cancelBubble} of a browser event or the current event 
234      * object for IE to <tt>true</tt> 
235      * without doing anything else.</p>
236      * <p>This function returns an event handler function that handles browser events more 
237      * efficiently, especially in JS Simulation mode, if invoked with or without the argument 
238      * being a browser event object.</p>
239      * @since 1.0
240      */
241     public final static Var<JsFunction<Void>> CANCELBUBBLE = new Static<JsFunction<Void>>(
242             new Var<JsFunction<Void>>() {
243                 @Override
244                 public JsFunction<Void> var() {
245                     return Js.function(
246                             "e",
247                             Code.join(
248                                     Code.ifnot("e", Code.asg("e", "event")),
249                                     ";",
250                                     Code.asg(
251                                             Code.ref("e", "cancelBubble"),
252                                             "true"
253                                     )
254                             )
255                     );
256                 }
257             }
258     );
259 
260     /**
261      * <p>A IE specific global JavaScript function that creates mouse event handlers.</p>
262      * <p>This function returns an event handler function that handles mouse events more 
263      * efficiently, especially in JS Simulation mode, if invoked with the first argument 
264      * being a function that performs the action when a browser click event has happened on 
265      * the source element and the second argument meaning whether to be checking a browser 
266      * mouse out event.</p>
267      * @since 1.0
268      */
269     public final static Var<JsFunction<JsObject>> IEHOVER = new Static<JsFunction<JsObject>>(
270             new Var<JsFunction<JsObject>>() {
271                 @Override
272                 public JsFunction<JsObject> var() {
273                     return Js.function(
274                             new Vars<String>().add("f").add("t"),
275                             "return function(){var e=event,p=e.srcElement,c=t?e.toElement:e.fromElement;while(c){if(c==p)return;c=c.parentNode;}f(e);};"
276                     );
277                 }
278             }
279     );
280 }