~mortenoh/+junk/dhis2-detailed-import-export

« back to all changes in this revision

Viewing changes to gis/dhis-gis-geostat/mfbase/openlayers/lib/OpenLayers/Events.js

  • Committer: larshelge at gmail
  • Date: 2009-03-03 16:46:36 UTC
  • Revision ID: larshelge@gmail.com-20090303164636-2sjlrquo7ib1gf7r
Initial check-in

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 
2
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 
3
 * full text of the license. */
 
4
 
 
5
 
 
6
/**
 
7
 * @requires OpenLayers/Util.js
 
8
 */
 
9
 
 
10
/**
 
11
 * Namespace: OpenLayers.Event
 
12
 * Utility functions for event handling.
 
13
 */
 
14
OpenLayers.Event = {
 
15
 
 
16
    /** 
 
17
     * Property: observers 
 
18
     * {Object} A hashtable cache of the event observers. Keyed by
 
19
     * element._eventCacheID 
 
20
     */
 
21
    observers: false,
 
22
    
 
23
    /** 
 
24
     * Constant: KEY_BACKSPACE 
 
25
     * {int} 
 
26
     */
 
27
    KEY_BACKSPACE: 8,
 
28
 
 
29
    /** 
 
30
     * Constant: KEY_TAB 
 
31
     * {int} 
 
32
     */
 
33
    KEY_TAB: 9,
 
34
 
 
35
    /** 
 
36
     * Constant: KEY_RETURN 
 
37
     * {int} 
 
38
     */
 
39
    KEY_RETURN: 13,
 
40
 
 
41
    /** 
 
42
     * Constant: KEY_ESC 
 
43
     * {int} 
 
44
     */
 
45
    KEY_ESC: 27,
 
46
 
 
47
    /** 
 
48
     * Constant: KEY_LEFT 
 
49
     * {int} 
 
50
     */
 
51
    KEY_LEFT: 37,
 
52
 
 
53
    /** 
 
54
     * Constant: KEY_UP 
 
55
     * {int} 
 
56
     */
 
57
    KEY_UP: 38,
 
58
 
 
59
    /** 
 
60
     * Constant: KEY_RIGHT 
 
61
     * {int} 
 
62
     */
 
63
    KEY_RIGHT: 39,
 
64
 
 
65
    /** 
 
66
     * Constant: KEY_DOWN 
 
67
     * {int} 
 
68
     */
 
69
    KEY_DOWN: 40,
 
70
 
 
71
    /** 
 
72
     * Constant: KEY_DELETE 
 
73
     * {int} 
 
74
     */
 
75
    KEY_DELETE: 46,
 
76
 
 
77
 
 
78
    /**
 
79
     * Method: element
 
80
     * Cross browser event element detection.
 
81
     * 
 
82
     * Parameters:
 
83
     * event - {Event} 
 
84
     * 
 
85
     * Returns:
 
86
     * {DOMElement} The element that caused the event 
 
87
     */
 
88
    element: function(event) {
 
89
        return event.target || event.srcElement;
 
90
    },
 
91
 
 
92
    /**
 
93
     * Method: isLeftClick
 
94
     * Determine whether event was caused by a left click. 
 
95
     *
 
96
     * Parameters:
 
97
     * event - {Event} 
 
98
     * 
 
99
     * Returns:
 
100
     * {Boolean}
 
101
     */
 
102
    isLeftClick: function(event) {
 
103
        return (((event.which) && (event.which == 1)) ||
 
104
                ((event.button) && (event.button == 1)));
 
105
    },
 
106
 
 
107
    /**
 
108
     * Method: isRightClick
 
109
     * Determine whether event was caused by a right mouse click. 
 
110
     *
 
111
     * Parameters:
 
112
     * event - {Event} 
 
113
     * 
 
114
     * Returns:
 
115
     * {Boolean}
 
116
     */
 
117
     isRightClick: function(event) {
 
118
        return (((event.which) && (event.which == 3)) ||
 
119
                ((event.button) && (event.button == 2)));
 
120
    },
 
121
     
 
122
    /**
 
123
     * Method: stop
 
124
     * Stops an event from propagating. 
 
125
     *
 
126
     * Parameters: 
 
127
     * event - {Event} 
 
128
     * allowDefault - {Boolean} If true, we stop the event chain but 
 
129
     *                               still allow the default browser 
 
130
     *                               behaviour (text selection, radio-button 
 
131
     *                               clicking, etc)
 
132
     *                               Default false
 
133
     */
 
134
    stop: function(event, allowDefault) {
 
135
        
 
136
        if (!allowDefault) { 
 
137
            if (event.preventDefault) {
 
138
                event.preventDefault();
 
139
            } else {
 
140
                event.returnValue = false;
 
141
            }
 
142
        }
 
143
                
 
144
        if (event.stopPropagation) {
 
145
            event.stopPropagation();
 
146
        } else {
 
147
            event.cancelBubble = true;
 
148
        }
 
149
    },
 
150
 
 
151
    /** 
 
152
     * Method: findElement
 
153
     * 
 
154
     * Parameters:
 
155
     * event - {Event} 
 
156
     * tagName - {String} 
 
157
     * 
 
158
     * Returns:
 
159
     * {DOMElement} The first node with the given tagName, starting from the
 
160
     * node the event was triggered on and traversing the DOM upwards
 
161
     */
 
162
    findElement: function(event, tagName) {
 
163
        var element = OpenLayers.Event.element(event);
 
164
        while (element.parentNode && (!element.tagName ||
 
165
              (element.tagName.toUpperCase() != tagName.toUpperCase()))){
 
166
            element = element.parentNode;
 
167
        }
 
168
        return element;
 
169
    },
 
170
 
 
171
    /** 
 
172
     * Method: observe
 
173
     * 
 
174
     * Parameters:
 
175
     * elementParam - {DOMElement || String} 
 
176
     * name - {String} 
 
177
     * observer - {function} 
 
178
     * useCapture - {Boolean} 
 
179
     */
 
180
    observe: function(elementParam, name, observer, useCapture) {
 
181
        var element = OpenLayers.Util.getElement(elementParam);
 
182
        useCapture = useCapture || false;
 
183
 
 
184
        if (name == 'keypress' &&
 
185
           (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
 
186
           || element.attachEvent)) {
 
187
            name = 'keydown';
 
188
        }
 
189
 
 
190
        //if observers cache has not yet been created, create it
 
191
        if (!this.observers) {
 
192
            this.observers = {};
 
193
        }
 
194
 
 
195
        //if not already assigned, make a new unique cache ID
 
196
        if (!element._eventCacheID) {
 
197
            var idPrefix = "eventCacheID_";
 
198
            if (element.id) {
 
199
                idPrefix = element.id + "_" + idPrefix;
 
200
            }
 
201
            element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);
 
202
        }
 
203
 
 
204
        var cacheID = element._eventCacheID;
 
205
 
 
206
        //if there is not yet a hash entry for this element, add one
 
207
        if (!this.observers[cacheID]) {
 
208
            this.observers[cacheID] = [];
 
209
        }
 
210
 
 
211
        //add a new observer to this element's list
 
212
        this.observers[cacheID].push({
 
213
            'element': element,
 
214
            'name': name,
 
215
            'observer': observer,
 
216
            'useCapture': useCapture
 
217
        });
 
218
 
 
219
        //add the actual browser event listener
 
220
        if (element.addEventListener) {
 
221
            element.addEventListener(name, observer, useCapture);
 
222
        } else if (element.attachEvent) {
 
223
            element.attachEvent('on' + name, observer);
 
224
        }
 
225
    },
 
226
 
 
227
    /** 
 
228
     * Method: stopObservingElement
 
229
     * Given the id of an element to stop observing, cycle through the 
 
230
     *   element's cached observers, calling stopObserving on each one, 
 
231
     *   skipping those entries which can no longer be removed.
 
232
     * 
 
233
     * parameters:
 
234
     * elementParam - {DOMElement || String} 
 
235
     */
 
236
    stopObservingElement: function(elementParam) {
 
237
        var element = OpenLayers.Util.getElement(elementParam);
 
238
        var cacheID = element._eventCacheID;
 
239
 
 
240
        this._removeElementObservers(OpenLayers.Event.observers[cacheID]);
 
241
    },
 
242
 
 
243
    /**
 
244
     * Method: _removeElementObservers
 
245
     *
 
246
     * Parameters:
 
247
     * elementObservers - {Array(Object)} Array of (element, name, 
 
248
     *                                         observer, usecapture) objects, 
 
249
     *                                         taken directly from hashtable
 
250
     */
 
251
    _removeElementObservers: function(elementObservers) {
 
252
        if (elementObservers) {
 
253
            for(var i = elementObservers.length-1; i >= 0; i--) {
 
254
                var entry = elementObservers[i];
 
255
                var args = new Array(entry.element,
 
256
                                     entry.name,
 
257
                                     entry.observer,
 
258
                                     entry.useCapture);
 
259
                var removed = OpenLayers.Event.stopObserving.apply(this, args);
 
260
            }
 
261
        }
 
262
    },
 
263
 
 
264
    /**
 
265
     * Method: stopObserving
 
266
     * 
 
267
     * Parameters:
 
268
     * elementParam - {DOMElement || String} 
 
269
     * name - {String} 
 
270
     * observer - {function} 
 
271
     * useCapture - {Boolean} 
 
272
     *  
 
273
     * Returns:
 
274
     * {Boolean} Whether or not the event observer was removed
 
275
     */
 
276
    stopObserving: function(elementParam, name, observer, useCapture) {
 
277
        useCapture = useCapture || false;
 
278
    
 
279
        var element = OpenLayers.Util.getElement(elementParam);
 
280
        var cacheID = element._eventCacheID;
 
281
 
 
282
        if (name == 'keypress') {
 
283
            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || 
 
284
                 element.detachEvent) {
 
285
              name = 'keydown';
 
286
            }
 
287
        }
 
288
 
 
289
        // find element's entry in this.observers cache and remove it
 
290
        var foundEntry = false;
 
291
        var elementObservers = OpenLayers.Event.observers[cacheID];
 
292
        if (elementObservers) {
 
293
    
 
294
            // find the specific event type in the element's list
 
295
            var i=0;
 
296
            while(!foundEntry && i < elementObservers.length) {
 
297
                var cacheEntry = elementObservers[i];
 
298
    
 
299
                if ((cacheEntry.name == name) &&
 
300
                    (cacheEntry.observer == observer) &&
 
301
                    (cacheEntry.useCapture == useCapture)) {
 
302
    
 
303
                    elementObservers.splice(i, 1);
 
304
                    if (elementObservers.length == 0) {
 
305
                        delete OpenLayers.Event.observers[cacheID];
 
306
                    }
 
307
                    foundEntry = true;
 
308
                    break; 
 
309
                }
 
310
                i++;           
 
311
            }
 
312
        }
 
313
    
 
314
        //actually remove the event listener from browser
 
315
        if (foundEntry) {
 
316
            if (element.removeEventListener) {
 
317
                element.removeEventListener(name, observer, useCapture);
 
318
            } else if (element && element.detachEvent) {
 
319
                element.detachEvent('on' + name, observer);
 
320
            }
 
321
        }
 
322
        return foundEntry;
 
323
    },
 
324
    
 
325
    /** 
 
326
     * Method: unloadCache
 
327
     * Cycle through all the element entries in the events cache and call
 
328
     *   stopObservingElement on each. 
 
329
     */
 
330
    unloadCache: function() {
 
331
        // check for OpenLayers.Event before checking for observers, because
 
332
        // OpenLayers.Event may be undefined in IE if no map instance was
 
333
        // created
 
334
        if (OpenLayers.Event && OpenLayers.Event.observers) {
 
335
            for (var cacheID in OpenLayers.Event.observers) {
 
336
                var elementObservers = OpenLayers.Event.observers[cacheID];
 
337
                OpenLayers.Event._removeElementObservers.apply(this, 
 
338
                                                           [elementObservers]);
 
339
            }
 
340
            OpenLayers.Event.observers = false;
 
341
        }
 
342
    },
 
343
 
 
344
    CLASS_NAME: "OpenLayers.Event"
 
345
};
 
346
 
 
347
/* prevent memory leaks in IE */
 
348
OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
 
349
 
 
350
// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
 
351
// by OpenLayers.
 
352
if (window.Event) {
 
353
    OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
 
354
} else {
 
355
    var Event = OpenLayers.Event;
 
356
}
 
357
 
 
358
/**
 
359
 * Class: OpenLayers.Events
 
360
 */
 
361
OpenLayers.Events = OpenLayers.Class({
 
362
 
 
363
    /** 
 
364
     * Constant: BROWSER_EVENTS
 
365
     * {Array(String)} supported events 
 
366
     */
 
367
    BROWSER_EVENTS: [
 
368
        "mouseover", "mouseout",
 
369
        "mousedown", "mouseup", "mousemove", 
 
370
        "click", "dblclick", "rightclick", "dblrightclick",
 
371
        "resize", "focus", "blur"
 
372
    ],
 
373
 
 
374
    /** 
 
375
     * Property: listeners 
 
376
     * {Object} Hashtable of Array(Function): events listener functions  
 
377
     */
 
378
    listeners: null,
 
379
 
 
380
    /** 
 
381
     * Property: object 
 
382
     * {Object}  the code object issuing application events 
 
383
     */
 
384
    object: null,
 
385
 
 
386
    /** 
 
387
     * Property: element 
 
388
     * {DOMElement}  the DOM element receiving browser events 
 
389
     */
 
390
    element: null,
 
391
 
 
392
    /** 
 
393
     * Property: eventTypes 
 
394
     * {Array(String)}  list of support application events 
 
395
     */
 
396
    eventTypes: null,
 
397
 
 
398
    /** 
 
399
     * Property: eventHandler 
 
400
     * {Function}  bound event handler attached to elements 
 
401
     */
 
402
    eventHandler: null,
 
403
 
 
404
    /** 
 
405
     * APIProperty: fallThrough 
 
406
     * {Boolean} 
 
407
     */
 
408
    fallThrough: null,
 
409
 
 
410
    /** 
 
411
     * APIProperty: includeXY
 
412
     * {Boolean} Should the .xy property automatically be created for browser
 
413
     *    mouse events? In general, this should be false. If it is true, then
 
414
     *    mouse events will automatically generate a '.xy' property on the 
 
415
     *    event object that is passed. (Prior to OpenLayers 2.7, this was true
 
416
     *    by default.) Otherwise, you can call the getMousePosition on the
 
417
     *    relevant events handler on the object available via the 'evt.object'
 
418
     *    property of the evt object. So, for most events, you can call:
 
419
     *    function named(evt) { 
 
420
     *        this.xy = this.object.events.getMousePosition(evt) 
 
421
     *    } 
 
422
     *
 
423
     *    This option typically defaults to false for performance reasons:
 
424
     *    when creating an events object whose primary purpose is to manage
 
425
     *    relatively positioned mouse events within a div, it may make
 
426
     *    sense to set it to true.
 
427
     *
 
428
     *    This option is also used to control whether the events object caches
 
429
     *    offsets. If this is false, it will not: the reason for this is that
 
430
     *    it is only expected to be called many times if the includeXY property
 
431
     *    is set to true. If you set this to true, you are expected to clear 
 
432
     *    the offset cache manually (using this.clearMouseCache()) if:
 
433
     *        the border of the element changes
 
434
     *        the location of the element in the page changes
 
435
    */
 
436
    includeXY: false,      
 
437
 
 
438
    /**
 
439
     * Constructor: OpenLayers.Events
 
440
     * Construct an OpenLayers.Events object.
 
441
     *
 
442
     * Parameters:
 
443
     * object - {Object} The js object to which this Events object  is being
 
444
     * added element - {DOMElement} A dom element to respond to browser events
 
445
     * eventTypes - {Array(String)} Array of custom application events 
 
446
     * fallThrough - {Boolean} Allow events to fall through after these have
 
447
     *                         been handled?
 
448
     * options - {Object} Options for the events object.
 
449
     */
 
450
    initialize: function (object, element, eventTypes, fallThrough, options) {
 
451
        OpenLayers.Util.extend(this, options);
 
452
        this.object     = object;
 
453
        this.element    = element;
 
454
        this.fallThrough = fallThrough;
 
455
        this.listeners  = {};
 
456
 
 
457
        // keep a bound copy of handleBrowserEvent() so that we can
 
458
        // pass the same function to both Event.observe() and .stopObserving()
 
459
        this.eventHandler = OpenLayers.Function.bindAsEventListener(
 
460
            this.handleBrowserEvent, this
 
461
        );
 
462
 
 
463
        // if eventTypes is specified, create a listeners list for each 
 
464
        // custom application event.
 
465
        this.eventTypes = [];
 
466
        if (eventTypes != null) {
 
467
            for (var i=0, len=eventTypes.length; i<len; i++) {
 
468
                this.addEventType(eventTypes[i]);
 
469
            }
 
470
        }
 
471
        
 
472
        // if a dom element is specified, add a listeners list 
 
473
        // for browser events on the element and register them
 
474
        if (this.element != null) {
 
475
            this.attachToElement(element);
 
476
        }
 
477
    },
 
478
 
 
479
    /**
 
480
     * APIMethod: destroy
 
481
     */
 
482
    destroy: function () {
 
483
        if (this.element) {
 
484
            OpenLayers.Event.stopObservingElement(this.element);
 
485
        }
 
486
        this.element = null;
 
487
 
 
488
        this.listeners = null;
 
489
        this.object = null;
 
490
        this.eventTypes = null;
 
491
        this.fallThrough = null;
 
492
        this.eventHandler = null;
 
493
    },
 
494
 
 
495
    /**
 
496
     * APIMethod: addEventType
 
497
     * Add a new event type to this events object.
 
498
     * If the event type has already been added, do nothing.
 
499
     * 
 
500
     * Parameters:
 
501
     * eventName - {String}
 
502
     */
 
503
    addEventType: function(eventName) {
 
504
        if (!this.listeners[eventName]) {
 
505
            this.eventTypes.push(eventName);
 
506
            this.listeners[eventName] = [];
 
507
        }
 
508
    },
 
509
 
 
510
    /**
 
511
     * Method: attachToElement
 
512
     *
 
513
     * Parameters:
 
514
     * element - {HTMLDOMElement} a DOM element to attach browser events to
 
515
     */
 
516
    attachToElement: function (element) {
 
517
        for (var i=0, len=this.BROWSER_EVENTS.length; i<len; i++) {
 
518
            var eventType = this.BROWSER_EVENTS[i];
 
519
 
 
520
            // every browser event has a corresponding application event 
 
521
            // (whether it's listened for or not).
 
522
            this.addEventType(eventType);
 
523
            
 
524
            // use Prototype to register the event cross-browser
 
525
            OpenLayers.Event.observe(element, eventType, this.eventHandler);
 
526
        }
 
527
        // disable dragstart in IE so that mousedown/move/up works normally
 
528
        OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
 
529
    },
 
530
    
 
531
    /**
 
532
     * Method: on
 
533
     * Convenience method for registering listeners with a common scope.
 
534
     *
 
535
     * Example use:
 
536
     * (code)
 
537
     * events.on({
 
538
     *     "loadstart": loadStartListener,
 
539
     *     "loadend": loadEndListener,
 
540
     *     scope: object
 
541
     * });
 
542
     * (end)
 
543
     */
 
544
    on: function(object) {
 
545
        for(var type in object) {
 
546
            if(type != "scope") {
 
547
                this.register(type, object.scope, object[type]);
 
548
            }
 
549
        }
 
550
    },
 
551
 
 
552
    /**
 
553
     * APIMethod: register
 
554
     * Register an event on the events object.
 
555
     *
 
556
     * When the event is triggered, the 'func' function will be called, in the
 
557
     * context of 'obj'. Imagine we were to register an event, specifying an 
 
558
     * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the 
 
559
     * context in the callback function will be our Bounds object. This means
 
560
     * that within our callback function, we can access the properties and 
 
561
     * methods of the Bounds object through the "this" variable. So our 
 
562
     * callback could execute something like: 
 
563
     * :    leftStr = "Left: " + this.left;
 
564
     *   
 
565
     *                   or
 
566
     *  
 
567
     * :    centerStr = "Center: " + this.getCenterLonLat();
 
568
     *
 
569
     * Parameters:
 
570
     * type - {String} Name of the event to register
 
571
     * obj - {Object} The object to bind the context to for the callback#.
 
572
     *                     If no object is specified, default is the Events's 
 
573
     *                     'object' property.
 
574
     * func - {Function} The callback function. If no callback is 
 
575
     *                        specified, this function does nothing.
 
576
     * 
 
577
     * 
 
578
     */
 
579
    register: function (type, obj, func) {
 
580
 
 
581
        if ( (func != null) && 
 
582
             (OpenLayers.Util.indexOf(this.eventTypes, type) != -1) ) {
 
583
 
 
584
            if (obj == null)  {
 
585
                obj = this.object;
 
586
            }
 
587
            var listeners = this.listeners[type];
 
588
            listeners.push( {obj: obj, func: func} );
 
589
        }
 
590
    },
 
591
 
 
592
    /**
 
593
     * APIMethod: registerPriority
 
594
     * Same as register() but adds the new listener to the *front* of the
 
595
     *     events queue instead of to the end.
 
596
     *    
 
597
     *     TODO: get rid of this in 3.0 - Decide whether listeners should be 
 
598
     *     called in the order they were registered or in reverse order.
 
599
     *
 
600
     *
 
601
     * Parameters:
 
602
     * type - {String} Name of the event to register
 
603
     * obj - {Object} The object to bind the context to for the callback#.
 
604
     *                If no object is specified, default is the Events's 
 
605
     *                'object' property.
 
606
     * func - {Function} The callback function. If no callback is 
 
607
     *                   specified, this function does nothing.
 
608
     */
 
609
    registerPriority: function (type, obj, func) {
 
610
 
 
611
        if (func != null) {
 
612
            if (obj == null)  {
 
613
                obj = this.object;
 
614
            }
 
615
            var listeners = this.listeners[type];
 
616
            if (listeners != null) {
 
617
                listeners.unshift( {obj: obj, func: func} );
 
618
            }
 
619
        }
 
620
    },
 
621
    
 
622
    /**
 
623
     * Method: un
 
624
     * Convenience method for unregistering listeners with a common scope.
 
625
     *
 
626
     * Example use:
 
627
     * (code)
 
628
     * events.un({
 
629
     *     "loadstart": loadStartListener,
 
630
     *     "loadend": loadEndListener,
 
631
     *     scope: object
 
632
     * });
 
633
     * (end)
 
634
     */
 
635
    un: function(object) {
 
636
        for(var type in object) {
 
637
            if(type != "scope") {
 
638
                this.unregister(type, object.scope, object[type]);
 
639
            }
 
640
        }
 
641
    },
 
642
 
 
643
    /**
 
644
     * APIMethod: unregister
 
645
     *
 
646
     * Parameters:
 
647
     * type - {String} 
 
648
     * obj - {Object} If none specified, defaults to this.object
 
649
     * func - {Function} 
 
650
     */
 
651
    unregister: function (type, obj, func) {
 
652
        if (obj == null)  {
 
653
            obj = this.object;
 
654
        }
 
655
        var listeners = this.listeners[type];
 
656
        if (listeners != null) {
 
657
            for (var i=0, len=listeners.length; i<len; i++) {
 
658
                if (listeners[i].obj == obj && listeners[i].func == func) {
 
659
                    listeners.splice(i, 1);
 
660
                    break;
 
661
                }
 
662
            }
 
663
        }
 
664
    },
 
665
 
 
666
    /** 
 
667
     * Method: remove
 
668
     * Remove all listeners for a given event type. If type is not registered,
 
669
     *     does nothing.
 
670
     *
 
671
     * Parameters:
 
672
     * type - {String} 
 
673
     */
 
674
    remove: function(type) {
 
675
        if (this.listeners[type] != null) {
 
676
            this.listeners[type] = [];
 
677
        }
 
678
    },
 
679
 
 
680
    /**
 
681
     * APIMethod: triggerEvent
 
682
     * Trigger a specified registered event.  
 
683
     * 
 
684
     * Parameters:
 
685
     * type - {String} 
 
686
     * evt - {Event}
 
687
     *
 
688
     * Returns:
 
689
     * {Boolean} The last listener return.  If a listener returns false, the
 
690
     *     chain of listeners will stop getting called.
 
691
     */
 
692
    triggerEvent: function (type, evt) {
 
693
 
 
694
        // prep evt object with object & div references
 
695
        if (evt == null) {
 
696
            evt = {};
 
697
        }
 
698
        evt.object = this.object;
 
699
        evt.element = this.element;
 
700
        if(!evt.type) {
 
701
            evt.type = type;
 
702
        }
 
703
    
 
704
        // execute all callbacks registered for specified type
 
705
        // get a clone of the listeners array to
 
706
        // allow for splicing during callbacks
 
707
        var listeners = (this.listeners[type]) ?
 
708
                            this.listeners[type].slice() : null;
 
709
        if ((listeners != null) && (listeners.length > 0)) {
 
710
            var continueChain;
 
711
            for (var i=0, len=listeners.length; i<len; i++) {
 
712
                var callback = listeners[i];
 
713
                // bind the context to callback.obj
 
714
                continueChain = callback.func.apply(callback.obj, [evt]);
 
715
    
 
716
                if ((continueChain != undefined) && (continueChain == false)) {
 
717
                    // if callback returns false, execute no more callbacks.
 
718
                    break;
 
719
                }
 
720
            }
 
721
            // don't fall through to other DOM elements
 
722
            if (!this.fallThrough) {           
 
723
                OpenLayers.Event.stop(evt, true);
 
724
            }
 
725
        }
 
726
        return continueChain;
 
727
    },
 
728
 
 
729
    /**
 
730
     * Method: handleBrowserEvent
 
731
     * Basically just a wrapper to the triggerEvent() function, but takes 
 
732
     *     care to set a property 'xy' on the event with the current mouse 
 
733
     *     position.
 
734
     *
 
735
     * Parameters:
 
736
     * evt - {Event} 
 
737
     */
 
738
    handleBrowserEvent: function (evt) {
 
739
        if (this.includeXY) {
 
740
            evt.xy = this.getMousePosition(evt);
 
741
        } 
 
742
        this.triggerEvent(evt.type, evt);
 
743
    },
 
744
 
 
745
    /**
 
746
     * APIMethod: clearMouseCache
 
747
     * Clear cached data about the mouse position. This should be called any 
 
748
     *     time the element that events are registered on changes position 
 
749
     *     within the page.
 
750
     */
 
751
    clearMouseCache: function() { 
 
752
        this.element.scrolls = null;
 
753
        this.element.lefttop = null;
 
754
        this.element.offsets = null;
 
755
    },      
 
756
 
 
757
    /**
 
758
     * Method: getMousePosition
 
759
     * 
 
760
     * Parameters:
 
761
     * evt - {Event} 
 
762
     * 
 
763
     * Returns:
 
764
     * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
 
765
     *                      for offsets
 
766
     */
 
767
    getMousePosition: function (evt) {
 
768
        if (!this.includeXY) {
 
769
            this.clearMouseCache();
 
770
        } else if (!this.element.hasScrollEvent) {
 
771
            OpenLayers.Event.observe(window, 'scroll', 
 
772
                OpenLayers.Function.bind(this.clearMouseCache, this)); 
 
773
            this.element.hasScrollEvent = true;
 
774
        }
 
775
        
 
776
        if (!this.element.scrolls) {
 
777
            this.element.scrolls = [];
 
778
            this.element.scrolls[0] = (document.documentElement.scrollLeft
 
779
                         || document.body.scrollLeft);
 
780
            this.element.scrolls[1] = (document.documentElement.scrollTop
 
781
                         || document.body.scrollTop);
 
782
        }
 
783
 
 
784
        if (!this.element.lefttop) {
 
785
            this.element.lefttop = [];
 
786
            this.element.lefttop[0] = (document.documentElement.clientLeft || 0);
 
787
            this.element.lefttop[1] = (document.documentElement.clientTop || 0);
 
788
        }
 
789
        
 
790
        if (!this.element.offsets) {
 
791
            this.element.offsets = OpenLayers.Util.pagePosition(this.element);
 
792
            this.element.offsets[0] += this.element.scrolls[0];
 
793
            this.element.offsets[1] += this.element.scrolls[1];
 
794
        }
 
795
        return new OpenLayers.Pixel(
 
796
            (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
 
797
                         - this.element.lefttop[0], 
 
798
            (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1]
 
799
                         - this.element.lefttop[1]
 
800
        ); 
 
801
    },
 
802
 
 
803
    CLASS_NAME: "OpenLayers.Events"
 
804
});