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. */
6 * @requires OpenLayers/Handler.js
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.
21 * - <OpenLayers.Handler>
23 OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
27 * {Number} Number of milliseconds between clicks before the event is
28 * considered a double-click.
34 * {Boolean} Handle single clicks. Default is true. If false, clicks
35 * will not be reported. If true, single-clicks will be reported.
41 * {Boolean} Handle double-clicks. Default is false.
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
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
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.
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.
82 * {Number} The id of the timeout waiting to clear the <delayedCall>.
88 * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
93 * Property: rightclickTimerId
94 * {Number} The id of the right mouse timeout waiting to clear the
97 rightclickTimerId: null,
100 * Constructor: OpenLayers.Handler.Click
101 * Create a new click handler.
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
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
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) {
128 * Handle mousedown. Only registered as a listener if pixelTolerance is
129 * a non-zero value at construction.
132 * {Boolean} Continue propagating this event.
138 * Handle mouseup. Installed to support collection of right mouse events.
141 * {Boolean} Continue propagating this event.
143 mouseup: function (evt) {
144 var propagate = true;
146 // Collect right mouse clicks from the mouseup
147 // IE - ignores the second right click in mousedown so using
149 if (this.checkModifiers(evt) &&
150 this.control.handleRightClicks &&
151 OpenLayers.Event.isRightClick(evt)) {
152 propagate = this.rightclick(evt);
160 * Handle rightclick. For a dblrightclick, we get two clicks so we need
161 * to always register for dblrightclick to properly handle single
165 * {Boolean} Continue propagating this event.
167 rightclick: function(evt) {
168 if(this.passesTolerance(evt)) {
169 if(this.rightclickTimerId != null) {
170 //Second click received before timeout this must be
173 this.callback('dblrightclick', [evt]);
174 return !this.stopDouble;
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]);
182 var delayedRightCall = OpenLayers.Function.bind(
183 this.delayedRightCall,
187 this.rightclickTimerId = window.setTimeout(
188 delayedRightCall, this.delay
192 return !this.stopSingle;
196 * Method: delayedRightCall
197 * Sets <rightclickTimerId> to null. And optionally triggers the
198 * rightclick callback if evt is set.
200 delayedRightCall: function(evt) {
201 this.rightclickTimerId = null;
203 this.callback('rightclick', [evt]);
205 return !this.stopSingle;
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.
215 * {Boolean} Continue propagating this event.
217 dblclick: function(evt) {
218 if(this.passesTolerance(evt)) {
220 this.callback('dblclick', [evt]);
224 return !this.stopDouble;
232 * {Boolean} Continue propagating this event.
234 click: function(evt) {
235 if(this.passesTolerance(evt)) {
236 if(this.timerId != null) {
237 // already received a click
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),
251 return !this.stopSingle;
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
263 * {Boolean} The click is within the pixel tolerance (if specified).
265 passesTolerance: function(evt) {
267 if(this.pixelTolerance != null && this.down) {
269 Math.pow(this.down.x - evt.xy.x, 2) +
270 Math.pow(this.down.y - evt.xy.y, 2)
272 if(dpx > this.pixelTolerance) {
281 * Clear the timer and set <timerId> to null.
283 clearTimer: function() {
284 if(this.timerId != null) {
285 window.clearTimeout(this.timerId);
288 if(this.rightclickTimerId != null) {
289 window.clearTimeout(this.rightclickTimerId);
290 this.rightclickTimerId = null;
295 * Method: delayedCall
296 * Sets <timerId> to null. And optionally triggers the click callback if
299 delayedCall: function(evt) {
302 this.callback('click', [evt]);
307 * APIMethod: deactivate
308 * Deactivate the handler.
311 * {Boolean} The handler was successfully deactivated.
313 deactivate: function() {
314 var deactivated = false;
315 if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
323 CLASS_NAME: "OpenLayers.Handler.Click"