]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Handler/Click.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Handler / Click.js
1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
2  * See http://svn.openlayers.org/trunk/openlayers/license.txt 
3  * for the full text of the license. */
4
5 /**
6  * @requires OpenLayers/Handler.js
7  */
8
9 /**
10  * Class: OpenLayers.Handler.Click
11  * A handler for mouse clicks.  The intention of this handler is to give
12  *     controls more flexibility with handling clicks.  Browsers trigger
13  *     click events twice for a double-click.  In addition, the mousedown,
14  *     mousemove, mouseup sequence fires a click event.  With this handler,
15  *     controls can decide whether to ignore clicks associated with a double
16  *     click.  By setting a <pixelTolerance>, controls can also ignore clicks
17  *     that include a drag.  Create a new instance with the
18  *     <OpenLayers.Handler.Click> constructor.
19  * 
20  * Inherits from:
21  *  - <OpenLayers.Handler> 
22  */
23 OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
24
25     /**
26      * APIProperty: delay
27      * {Number} Number of milliseconds between clicks before the event is
28      *     considered a double-click.
29      */
30     delay: 300,
31     
32     /**
33      * APIProperty: single
34      * {Boolean} Handle single clicks.  Default is true.  If false, clicks
35      * will not be reported.  If true, single-clicks will be reported.
36      */
37     single: true,
38     
39     /**
40      * APIProperty: double
41      * {Boolean} Handle double-clicks.  Default is false.
42      */
43     'double': false,
44     
45     /**
46      * APIProperty: pixelTolerance
47      * {Number} Maximum number of pixels between mouseup and mousedown for an
48      *     event to be considered a click.  Default is 0.  If set to an
49      *     integer value, clicks with a drag greater than the value will be
50      *     ignored.  This property can only be set when the handler is
51      *     constructed.
52      */
53     pixelTolerance: 0,
54     
55     /**
56      * APIProperty: stopSingle
57      * {Boolean} Stop other listeners from being notified of clicks.  Default
58      *     is false.  If true, any click listeners registered before this one
59      *     will not be notified of *any* click event (associated with double
60      *     or single clicks).
61      */
62     stopSingle: false,
63     
64     /**
65      * APIProperty: stopDouble
66      * {Boolean} Stop other listeners from being notified of double-clicks.
67      *     Default is false.  If true, any click listeners registered before
68      *     this one will not be notified of *any* double-click events.
69      * 
70      * The one caveat with stopDouble is that given a map with two click
71      *     handlers, one with stopDouble true and the other with stopSingle
72      *     true, the stopSingle handler should be activated last to get
73      *     uniform cross-browser performance.  Since IE triggers one click
74      *     with a dblclick and FF triggers two, if a stopSingle handler is
75      *     activated first, all it gets in IE is a single click when the
76      *     second handler stops propagation on the dblclick.
77      */
78     stopDouble: false,
79
80     /**
81      * Property: timerId
82      * {Number} The id of the timeout waiting to clear the <delayedCall>.
83      */
84     timerId: null,
85     
86     /**
87      * Property: down
88      * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
89      */
90     down: null,
91     
92     /**
93      * Property: rightclickTimerId
94      * {Number} The id of the right mouse timeout waiting to clear the 
95      *     <delayedEvent>.
96      */
97     rightclickTimerId: null,
98     
99     /**
100      * Constructor: OpenLayers.Handler.Click
101      * Create a new click handler.
102      * 
103      * Parameters:
104      * control - {<OpenLayers.Control>} The control that is making use of
105      *     this handler.  If a handler is being used without a control, the
106      *     handler's setMap method must be overridden to deal properly with
107      *     the map.
108      * callbacks - {Object} An object with keys corresponding to callbacks
109      *     that will be called by the handler. The callbacks should
110      *     expect to recieve a single argument, the click event.
111      *     Callbacks for 'click' and 'dblclick' are supported.
112      * options - {Object} Optional object whose properties will be set on the
113      *     handler.
114      */
115     initialize: function(control, callbacks, options) {
116         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
117         // optionally register for mouseup and mousedown
118         if(this.pixelTolerance != null) {
119             this.mousedown = function(evt) {
120                 this.down = evt.xy;
121                 return true;
122             };
123         }
124     },
125     
126     /**
127      * Method: mousedown
128      * Handle mousedown.  Only registered as a listener if pixelTolerance is
129      *     a non-zero value at construction.
130      *
131      * Returns:
132      * {Boolean} Continue propagating this event.
133      */
134     mousedown: null,
135
136     /**
137      * Method: mouseup
138      * Handle mouseup.  Installed to support collection of right mouse events.
139      * 
140      * Returns:
141      * {Boolean} Continue propagating this event.
142      */
143     mouseup:  function (evt) {
144         var propagate = true;
145
146         // Collect right mouse clicks from the mouseup
147         //  IE - ignores the second right click in mousedown so using
148         //  mouseup instead
149         if (this.checkModifiers(evt) && 
150             this.control.handleRightClicks && 
151             OpenLayers.Event.isRightClick(evt)) {
152           propagate = this.rightclick(evt);
153         }
154
155         return propagate;
156     },
157     
158     /**
159      * Method: rightclick
160      * Handle rightclick.  For a dblrightclick, we get two clicks so we need 
161      *     to always register for dblrightclick to properly handle single 
162      *     clicks.
163      *     
164      * Returns:
165      * {Boolean} Continue propagating this event.
166      */
167     rightclick: function(evt) {
168         if(this.passesTolerance(evt)) {
169            if(this.rightclickTimerId != null) {
170                 //Second click received before timeout this must be 
171                 // a double click
172                 this.clearTimer();      
173                 this.callback('dblrightclick', [evt]);
174                 return !this.stopDouble;
175             } else { 
176                 //Set the rightclickTimerId, send evt only if double is 
177                 // true else trigger single
178                 var clickEvent = this['double'] ?
179                     OpenLayers.Util.extend({}, evt) : 
180                     this.callback('rightclick', [evt]);
181
182                 var delayedRightCall = OpenLayers.Function.bind(
183                     this.delayedRightCall, 
184                     this, 
185                     clickEvent
186                 );
187                 this.rightclickTimerId = window.setTimeout(
188                     delayedRightCall, this.delay
189                 );
190             } 
191         }
192         return !this.stopSingle;
193     },
194     
195     /**
196      * Method: delayedRightCall
197      * Sets <rightclickTimerId> to null.  And optionally triggers the 
198      *     rightclick callback if evt is set.
199      */
200     delayedRightCall: function(evt) {
201         this.rightclickTimerId = null;
202         if (evt) {
203            this.callback('rightclick', [evt]);
204         }
205         return !this.stopSingle;
206     },
207     
208     /**
209      * Method: dblclick
210      * Handle dblclick.  For a dblclick, we get two clicks in some browsers
211      *     (FF) and one in others (IE).  So we need to always register for
212      *     dblclick to properly handle single clicks.
213      *     
214      * Returns:
215      * {Boolean} Continue propagating this event.
216      */
217     dblclick: function(evt) {
218         if(this.passesTolerance(evt)) {
219             if(this["double"]) {
220                 this.callback('dblclick', [evt]);
221             }
222             this.clearTimer();
223         }
224         return !this.stopDouble;
225     },
226     
227     /**
228      * Method: click
229      * Handle click.
230      *
231      * Returns:
232      * {Boolean} Continue propagating this event.
233      */
234     click: function(evt) {
235         if(this.passesTolerance(evt)) {
236             if(this.timerId != null) {
237                 // already received a click
238                 this.clearTimer();
239             } else {
240                 // set the timer, send evt only if single is true
241                 //use a clone of the event object because it will no longer 
242                 //be a valid event object in IE in the timer callback
243                 var clickEvent = this.single ?
244                     OpenLayers.Util.extend({}, evt) : null;
245                 this.timerId = window.setTimeout(
246                     OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
247                     this.delay
248                 );
249             }
250         }
251         return !this.stopSingle;
252     },
253     
254     /**
255      * Method: passesTolerance
256      * Determine whether the event is within the optional pixel tolerance.  Note
257      *     that the pixel tolerance check only works if mousedown events get to
258      *     the listeners registered here.  If they are stopped by other elements,
259      *     the <pixelTolerance> will have no effect here (this method will always
260      *     return true).
261      *
262      * Returns:
263      * {Boolean} The click is within the pixel tolerance (if specified).
264      */
265     passesTolerance: function(evt) {
266         var passes = true;
267         if(this.pixelTolerance != null && this.down) {
268             var dpx = Math.sqrt(
269                 Math.pow(this.down.x - evt.xy.x, 2) +
270                 Math.pow(this.down.y - evt.xy.y, 2)
271             );
272             if(dpx > this.pixelTolerance) {
273                 passes = false;
274             }
275         }
276         return passes;
277     },
278
279     /**
280      * Method: clearTimer
281      * Clear the timer and set <timerId> to null.
282      */
283     clearTimer: function() {
284         if(this.timerId != null) {
285             window.clearTimeout(this.timerId);
286             this.timerId = null;
287         }
288         if(this.rightclickTimerId != null) {
289             window.clearTimeout(this.rightclickTimerId);
290             this.rightclickTimerId = null;
291         }
292     },
293     
294     /**
295      * Method: delayedCall
296      * Sets <timerId> to null.  And optionally triggers the click callback if
297      *     evt is set.
298      */
299     delayedCall: function(evt) {
300         this.timerId = null;
301         if(evt) {
302             this.callback('click', [evt]);
303         }
304     },
305
306     /**
307      * APIMethod: deactivate
308      * Deactivate the handler.
309      *
310      * Returns:
311      * {Boolean} The handler was successfully deactivated.
312      */
313     deactivate: function() {
314         var deactivated = false;
315         if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
316             this.clearTimer();
317             this.down = null;
318             deactivated = true;
319         }
320         return deactivated;
321     },
322
323     CLASS_NAME: "OpenLayers.Handler.Click"
324 });