Index: appengine/monorail/static/js/graveyard/listen.js |
diff --git a/appengine/monorail/static/js/graveyard/listen.js b/appengine/monorail/static/js/graveyard/listen.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a1e1e2120a8d8271a2d7fe8dfc5607edb2559565 |
--- /dev/null |
+++ b/appengine/monorail/static/js/graveyard/listen.js |
@@ -0,0 +1,146 @@ |
+/* Copyright 2016 The Chromium Authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style |
+ * license that can be found in the LICENSE file or at |
+ * https://developers.google.com/open-source/licenses/bsd |
+ */ |
+ |
+var listen; |
+var unlisten; |
+var unlistenByKey; |
+ |
+(function() { |
+ var listeners = {}; |
+ var nextId = 0; |
+ |
+ function getHashCode_(obj) { |
+ if (obj.listen_hc_ == null) { |
+ obj.listen_hc_ = ++nextId; |
+ } |
+ return obj.listen_hc_; |
+ } |
+ |
+ /** |
+ * Takes a node, event, listener, and capture flag to create a key |
+ * to identify the tuple in the listeners hash. |
+ * |
+ * @param {Element} node The node to listen to events on. |
+ * @param {string} event The name of the event without the "on" prefix. |
+ * @param {Function} listener A function to call when the event occurs. |
+ * @param {boolean} opt_useCapture In DOM-compliant browsers, this determines |
+ * whether the listener is fired during the |
+ * capture or bubble phase of the event. |
+ * @return {string} key to identify this tuple in the listeners hash. |
+ */ |
+ function createKey_(node, event, listener, opt_useCapture) { |
+ var nodeHc = getHashCode_(node); |
+ var listenerHc = getHashCode_(listener); |
+ opt_useCapture = !!opt_useCapture; |
+ var key = nodeHc + '_' + event + '_' + listenerHc + '_' + opt_useCapture; |
+ return key; |
+ } |
+ |
+ /** |
+ * Adds an event listener to a DOM node for a specific event. |
+ * |
+ * Listen() and unlisten() use an indirect lookup of listener functions |
+ * to avoid circular references between DOM (in IE) or XPCOM (in Mozilla) |
+ * objects which leak memory. This makes it easier to write OO |
+ * Javascript/DOM code. |
+ * |
+ * Examples: |
+ * listen(myButton, 'click', myHandler, true); |
+ * listen(myButton, 'click', this.myHandler.bind(this), true); |
+ * |
+ * @param {Element} node The node to listen to events on. |
+ * @param {string} event The name of the event without the "on" prefix. |
+ * @param {Function} listener A function to call when the event occurs. |
+ * @param {boolean} opt_useCapture In DOM-compliant browsers, this determines |
+ * whether the listener is fired during the |
+ * capture or bubble phase of the event. |
+ * @return {string} a unique key to indentify this listener. |
+ */ |
+ listen = function(node, event, listener, opt_useCapture) { |
+ var key = createKey_(node, event, listener, opt_useCapture); |
+ |
+ // addEventListener does not allow multiple listeners |
+ if (key in listeners) { |
+ return key; |
+ } |
+ |
+ var proxy = handleEvent.bind(null, key); |
+ listeners[key] = { |
+ listener: listener, |
+ proxy: proxy, |
+ event: event, |
+ node: node, |
+ useCapture: opt_useCapture |
+ }; |
+ |
+ if (node.addEventListener) { |
+ node.addEventListener(event, proxy, opt_useCapture); |
+ } else if (node.attachEvent) { |
+ node.attachEvent('on' + event, proxy); |
+ } else { |
+ throw new Error('Node {' + node + '} does not support event listeners.'); |
+ } |
+ |
+ return key; |
+ } |
+ |
+ /** |
+ * Removes an event listener which was added with listen(). |
+ * |
+ * @param {Element} node The node to stop listening to events on. |
+ * @param {string} event The name of the event without the "on" prefix. |
+ * @param {Function} listener The listener function to remove. |
+ * @param {boolean} opt_useCapture In DOM-compliant browsers, this determines |
+ * whether the listener is fired during the |
+ * capture or bubble phase of the event. |
+ * @return {boolean} indicating whether the listener was there to remove. |
+ */ |
+ unlisten = function(node, event, listener, opt_useCapture) { |
+ var key = createKey_(node, event, listener, opt_useCapture); |
+ |
+ return unlistenByKey(key); |
+ } |
+ |
+ /** |
+ * Variant of {@link unlisten} that takes a key that was returned by |
+ * {@link listen} and removes that listener. |
+ * |
+ * @param {string} key Key of event to be unlistened. |
+ * @return {boolean} indicating whether it was there to be removed. |
+ */ |
+ unlistenByKey = function(key) { |
+ if (!(key in listeners)) { |
+ return false; |
+ } |
+ var listener = listeners[key]; |
+ var proxy = listener.proxy; |
+ var event = listener.event; |
+ var node = listener.node; |
+ var useCapture = listener.useCapture; |
+ |
+ if (node.removeEventListener) { |
+ node.removeEventListener(event, proxy, useCapture); |
+ } else if (node.detachEvent) { |
+ node.detachEvent('on' + event, proxy); |
+ } |
+ |
+ delete listeners[key]; |
+ return true; |
+ } |
+ |
+ /** |
+ * The function which is actually called when the DOM event occurs. This |
+ * function is a proxy for the real listener the user specified. |
+ */ |
+ function handleEvent(key) { |
+ // pass all arguments which were sent to this function except listenerID |
+ // on to the actual listener. |
+ var args = Array.prototype.splice.call(arguments, 1, arguments.length); |
+ return listeners[key].listener.apply(null, args); |
+ } |
+ |
+})(); |