| 57 | | }, |
|---|
| 58 | | |
|---|
| 59 | | observers: false, |
|---|
| 60 | | |
|---|
| 61 | | _observeAndCache: function(element, name, observer, useCapture) { |
|---|
| 62 | | if (!this.observers) this.observers = []; |
|---|
| 63 | | if (element.addEventListener) { |
|---|
| 64 | | this.observers.push([element, name, observer, useCapture]); |
|---|
| 65 | | element.addEventListener(name, observer, useCapture); |
|---|
| 66 | | } else if (element.attachEvent) { |
|---|
| 67 | | this.observers.push([element, name, observer, useCapture]); |
|---|
| 68 | | element.attachEvent('on' + name, observer); |
|---|
| 69 | | } |
|---|
| 70 | | }, |
|---|
| 71 | | |
|---|
| 72 | | unloadCache: function() { |
|---|
| 73 | | if (!Event.observers) return; |
|---|
| 74 | | for (var i = 0, length = Event.observers.length; i < length; i++) { |
|---|
| 75 | | Event.stopObserving.apply(this, Event.observers[i]); |
|---|
| 76 | | Event.observers[i][0] = null; |
|---|
| 77 | | } |
|---|
| 78 | | Event.observers = false; |
|---|
| 79 | | }, |
|---|
| 80 | | |
|---|
| 81 | | observe: function(element, name, observer, useCapture) { |
|---|
| 82 | | element = $(element); |
|---|
| 83 | | useCapture = useCapture || false; |
|---|
| 84 | | |
|---|
| 85 | | if (name == 'keypress' && |
|---|
| 86 | | (Prototype.Browser.WebKit || element.attachEvent)) |
|---|
| 87 | | name = 'keydown'; |
|---|
| 88 | | |
|---|
| 89 | | Event._observeAndCache(element, name, observer, useCapture); |
|---|
| 90 | | }, |
|---|
| 91 | | |
|---|
| 92 | | stopObserving: function(element, name, observer, useCapture) { |
|---|
| 93 | | element = $(element); |
|---|
| 94 | | useCapture = useCapture || false; |
|---|
| 95 | | |
|---|
| 96 | | if (name == 'keypress' && |
|---|
| 97 | | (Prototype.Browser.WebKit || element.attachEvent)) |
|---|
| 98 | | name = 'keydown'; |
|---|
| 99 | | |
|---|
| 100 | | if (element.removeEventListener) { |
|---|
| 101 | | element.removeEventListener(name, observer, useCapture); |
|---|
| 102 | | } else if (element.detachEvent) { |
|---|
| 103 | | try { |
|---|
| 104 | | element.detachEvent('on' + name, observer); |
|---|
| 105 | | } catch (e) {} |
|---|
| 106 | | } |
|---|
| 110 | | /* prevent memory leaks in IE */ |
|---|
| 111 | | if (Prototype.Browser.IE) |
|---|
| 112 | | Event.observe(window, 'unload', Event.unloadCache, false); |
|---|
| | 62 | Object.extend(Event, function() |
|---|
| | 63 | { |
|---|
| | 64 | var B = Prototype.Browser; |
|---|
| | 65 | |
|---|
| | 66 | Observer = Class.create(); |
|---|
| | 67 | Observer.guid = 1; |
|---|
| | 68 | |
|---|
| | 69 | Object.extend(Observer.prototype, { |
|---|
| | 70 | initialize: function(element, type, observer, useCapture) { |
|---|
| | 71 | this.element = $(element); |
|---|
| | 72 | if (type == 'keypress' && (B.IE || B.WebKit)) type = 'keydown'; |
|---|
| | 73 | this.type = type; |
|---|
| | 74 | this.observer = observer; |
|---|
| | 75 | this.useCapture = useCapture || false; |
|---|
| | 76 | }, |
|---|
| | 77 | add: function() { |
|---|
| | 78 | this._add(); |
|---|
| | 79 | this.cache(); |
|---|
| | 80 | }, |
|---|
| | 81 | cache: function() { |
|---|
| | 82 | if (!this.element._observers) this.element._observers = {}; |
|---|
| | 83 | var local = this.element._observers[this.type]; |
|---|
| | 84 | if (!local) local = this.element._observers[this.type] = {}; |
|---|
| | 85 | if (!this.observer.$$guid) this.observer.$$guid = this.constructor.guid++; |
|---|
| | 86 | local[this.observer.$$guid] = this; |
|---|
| | 87 | }, |
|---|
| | 88 | remove: function() { |
|---|
| | 89 | if (!this.observer) { |
|---|
| | 90 | if (this.element._observers) { |
|---|
| | 91 | var collection = this.element._observers; |
|---|
| | 92 | if (this.type) { |
|---|
| | 93 | collection = collection[this.type] |
|---|
| | 94 | if (!collection) return; |
|---|
| | 95 | } |
|---|
| | 96 | for (var i in collection) { |
|---|
| | 97 | if (i > 0) collection[i].remove(); |
|---|
| | 98 | else for (var j in collection[i]) collection[i][j].remove(); |
|---|
| | 99 | } |
|---|
| | 100 | } |
|---|
| | 101 | return; |
|---|
| | 102 | } |
|---|
| | 103 | if (!this.observer.$$guid) return; |
|---|
| | 104 | this._remove(); |
|---|
| | 105 | delete this.element._observers[this.type][this.observer.$$guid]; |
|---|
| | 106 | } |
|---|
| | 107 | }); |
|---|
| | 108 | |
|---|
| | 109 | if (document.addEventListener) |
|---|
| | 110 | { |
|---|
| | 111 | Object.extend(Observer.prototype, { |
|---|
| | 112 | _add: function() { |
|---|
| | 113 | // TODO: create wrapper for Safari? |
|---|
| | 114 | this.element.addEventListener(this.type, this.observer, this.useCapture); |
|---|
| | 115 | }, |
|---|
| | 116 | _remove: function() { |
|---|
| | 117 | this.element.removeEventListener(this.type, this.observer, this.useCapture); |
|---|
| | 118 | } |
|---|
| | 119 | }); |
|---|
| | 120 | } else if (B.IE) |
|---|
| | 121 | { |
|---|
| | 122 | Object.extend(Observer.prototype, { |
|---|
| | 123 | _add: function() { |
|---|
| | 124 | // create a wrapper for scope correction and event object normalization |
|---|
| | 125 | var ob = this.observer, el = this.element, klass = this.constructor; |
|---|
| | 126 | this.wrapper = function(e) { |
|---|
| | 127 | return ob.call(el, klass.extendEvent(e)) |
|---|
| | 128 | }; |
|---|
| | 129 | this.element.attachEvent('on' + this.type, this.wrapper); |
|---|
| | 130 | this.constructor.globalCache.push(this); |
|---|
| | 131 | }, |
|---|
| | 132 | _remove: function() { |
|---|
| | 133 | if (!this.wrapper) this.wrapper = this.element._observers[this.type][this.observer.$$guid].wrapper; |
|---|
| | 134 | this.element.detachEvent('on' + this.type, this.wrapper); |
|---|
| | 135 | } |
|---|
| | 136 | }); |
|---|
| | 137 | |
|---|
| | 138 | Object.extend(Observer, { |
|---|
| | 139 | globalCache: [], |
|---|
| | 140 | unloadCache: function() { |
|---|
| | 141 | for(var i=0, length = this.globalCache.length; i < length; i++) |
|---|
| | 142 | this.globalCache[i].remove() |
|---|
| | 143 | }, |
|---|
| | 144 | /* adds standard DOM event model properties to IE's events */ |
|---|
| | 145 | extendEvent: function(event) { |
|---|
| | 146 | event || (event = window.event); |
|---|
| | 147 | return Object.extend(Object.extend(event, { |
|---|
| | 148 | target: event.srcElement, |
|---|
| | 149 | which: event.button, |
|---|
| | 150 | pageX: Event.pointerX(event), |
|---|
| | 151 | pageY: Event.pointerY(event), |
|---|
| | 152 | relatedTarget: Event.relatedTarget(event) |
|---|
| | 153 | }), |
|---|
| | 154 | this.eventMethods |
|---|
| | 155 | ); |
|---|
| | 156 | }, |
|---|
| | 157 | eventMethods: { |
|---|
| | 158 | stopPropagation: function() { this.cancelBubble = true }, |
|---|
| | 159 | preventDefault: function() { this.returnValue = false }, |
|---|
| | 160 | inspect: function() { return '[object Event]' } |
|---|
| | 161 | } |
|---|
| | 162 | }); |
|---|
| | 163 | |
|---|
| | 164 | /* unload to prevent memory leaks */ |
|---|
| | 165 | window.attachEvent('onunload', Observer.unloadCache.bind(Observer)); |
|---|
| | 166 | } |
|---|
| | 167 | |
|---|
| | 168 | // applies the calling method to an array of elements |
|---|
| | 169 | function applyToList(args) { |
|---|
| | 170 | if (args[0].constructor == Array) { |
|---|
| | 171 | var method = args.callee; |
|---|
| | 172 | args = $A(args); |
|---|
| | 173 | args.shift().each(function(el){ |
|---|
| | 174 | method.apply(null, [el].concat(args)); |
|---|
| | 175 | }); |
|---|
| | 176 | return true; // the calling method can end |
|---|
| | 177 | } |
|---|
| | 178 | return false; |
|---|
| | 179 | } |
|---|
| | 180 | |
|---|
| | 181 | return { |
|---|
| | 182 | observe: function(element, type, observer, useCapture) { |
|---|
| | 183 | if (applyToList(arguments)) return; |
|---|
| | 184 | |
|---|
| | 185 | new Observer(element, type, observer, useCapture).add(); |
|---|
| | 186 | }, |
|---|
| | 187 | stopObserving: function(element, type, observer, useCapture) { |
|---|
| | 188 | if (applyToList(arguments)) return; |
|---|
| | 189 | |
|---|
| | 190 | new Observer(element, type, observer, useCapture).remove(); |
|---|
| | 191 | } |
|---|
| | 192 | } |
|---|
| | 193 | }()); |
|---|