|
|||
|
Event parts.
Lot of them. Spread out over several files. Check in comments vary from "Good luck little buddy" to "Checking in to the SVN repository for Closure". Cargo cult for sure (always add comments, no mater how absurd and wasteful). // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Copyright 2005 Google Inc. All Rights Reserved. Another time capsule of misdeeds and misconceptions. ![]() /** * @fileoverview Class to create objects which want to handle multiple events * and have their listeners easily cleaned up via a dispose method. Class?! So the authors don't speak the language. How do they communicate ideas? * * Example: * <pre> * function Something() { * goog.events.EventHandler.call(this); * * ... set up object ... * * // Add event listeners * this.listen(this.starEl, 'click', this.handleStar); * this.listen(this.headerEl, 'click', this.expand); * this.listen(this.collapseEl, 'click', this.collapse); * this.listen(this.infoEl, 'mouseover', this.showHover); * this.listen(this.infoEl, 'mouseout', this.hideHover); * } * goog.inherits(Something, goog.events.EventHandler); * * Something.prototype.disposeInternal = function() { * Something.superClass_.disposeInternal.call(this); * goog.dom.removeNode(this.container); * }; * * * // Then elsewhere: * * var activeSomething = null; * function openSomething() { * activeSomething = new Something(); * } * * function closeSomething() { * if (activeSomething) { * activeSomething.dispose(); // Remove event listeners * activeSomething = null; * } * } * </pre> * */ And this is evidence that they create memory leaks in IE, but don't really understand why. goog.provide('goog.events.EventHandler'); goog.require('goog.Disposable'); goog.require('goog.events'); goog.require('goog.events.EventWrapper'); goog.require('goog.object'); goog.require('goog.structs.SimplePool'); /** * Super class for objects that want to easily manage a number of event * listeners. It allows a short cut to listen and also provides a quick way * to remove all events listeners belonging to this object. It is optimized to * use less objects if only one event is being listened to, but if that's the * case, it may not be worth using the EventHandler anyway. * @param {Object} opt_handler Object in whose scope to call the listeners. This has _nothing_ to do with scope. * @constructor * @extends {goog.Disposable} */ goog.events.EventHandler = function(opt_handler) { this.handler_ = opt_handler; }; goog.inherits(goog.events.EventHandler, goog.Disposable); /** * Initial count for the keyPool_ * @type {number} */ goog.events.EventHandler.KEY_POOL_INITIAL_COUNT = 0; /** * Max count for the keyPool_ * @type {number} */ goog.events.EventHandler.KEY_POOL_MAX_COUNT = 100; Sounds arbitrary. /** * SimplePool to cache the key object. This was implemented to make IE6 * performance better and removed an object allocation in the listen method * when in steady state. * @type {goog.structs.SimplePool} * @private */ goog.events.EventHandler.keyPool_ = new goog.structs.SimplePool( goog.events.EventHandler.KEY_POOL_INITIAL_COUNT, goog.events.EventHandler.KEY_POOL_MAX_COUNT); /** * Keys for events that are being listened to. This is used once there are more * than one event to listen to. If there is only one event to listen to, key_ * is used. * @type {Object?} * @private */ goog.events.EventHandler.keys_ = null; /** * Keys for event that is being listened to if only one event is being listened * to. This is a performance optimization to avoid creating an extra object * if not necessary. * @type {string?} * @private */ goog.events.EventHandler.key_ = null; /** * Listen to an event on a DOM node or EventTarget. Tangled. If the function is ommitted * then the EventHandler's handleEvent method will be used. * @param {goog.events.EventTarget|EventTarget} src Event source. * @param {string|Array.<string>} type Event type to listen for or array of * event types. * @param {Function|Object} opt_fn Optional callback function to be used as the * listener or an object with handleEvent function. * @param {boolean} opt_capture Optional whether to use capture phase. * @param {Object} opt_handler Object in whose scope to call the listener. * @return {goog.events.EventHandler} This object, allowing for chaining of * calls. */ goog.events.EventHandler.prototype.listen = function(src, type, opt_fn, opt_capture, opt_handler) { if (goog.isArray(type)) { Oops, indicator. Check for the string, not the array. for (var i = 0; i < type.length; i++) { this.listen(src, type[i], opt_fn, opt_capture, opt_handler); } } else { var key = (/** @type {number} */ goog.events.listen(src, type, opt_fn || this, opt_capture || false, opt_handler || this.handler_ || this)); this.recordListenerKey_(key); } return this; }; /** * Listen to an event on a DOM node or EventTarget. If the function is ommitted * then the EventHandler's handleEvent method will be used. After the event has * fired the event listener is removed from the target. If an array of event * types is provided, each event type will be listened to once. * @param {goog.events.EventTarget|EventTarget} src Event source. * @param {string|Array.<string>} type Event type to listen for or array of * event types. * @param {Function|Object} opt_fn Optional callback function to be used as the * listener or an object with handleEvent function. * @param {boolean} opt_capture Optional whether to use capture phase. Capture?! * @param {Object} opt_handler Object in whose scope to call the listener. * @return {goog.events.EventHandler} This object, allowing for chaining of * calls. */ goog.events.EventHandler.prototype.listenOnce = function(src, type, opt_fn, opt_capture, opt_handler) { if (goog.isArray(type)) { Same mistakes over and over. for (var i = 0; i < type.length; i++) { this.listenOnce(src, type[i], opt_fn, opt_capture, opt_handler); } } else { var key = (/** @type {number} */ goog.events.listenOnce(src, type, opt_fn || this, opt_capture || false, opt_handler || this.handler_ || this)); this.recordListenerKey_(key); } return this; }; /** * Adds an event listener with a specific event wrapper on a DOM Node or an * object that has implemented {@link goog.events.EventTarget}. A listener can * only be added once to an object. * * @param {EventTarget|goog.events.EventTarget} src The node to listen to * events on. * @param {goog.events.EventWrapper} wrapper Event wrapper to use. * @param {Function|Object} listener Callback method, or an object with a * handleEvent function. * @param {boolean} opt_capt Whether to fire in capture phase (defaults to * false). * @param {Object} opt_handler Element in whose scope to call the listener. * @return {goog.events.EventHandler} This object, allowing for chaining of * calls. */ goog.events.EventHandler.prototype.listenWithWrapp er = function(src, wrapper, listener, opt_capt, opt_handler) { wrapper.listen(src, listener, opt_capt, opt_handler || this.handler_, this); return this; }; /** * Record the key returned for the listener so that it can be user later * to remove the listener. * @param {number} key Unique key for the listener. * @private */ goog.events.EventHandler.prototype.recordListenerK ey_ = function(key) { if (this.keys_) { // already have multiple keys this.keys_[key] = true; } else if (this.key_) { // going from one key to multiple - must now use object as map this.keys_ = goog.events.EventHandler.keyPool_.getObject(); this.keys_[this.key_] = true; this.key_ = null; this.keys_[key] = true; } else { // first key - can use single key this.key_ = key; } }; /** * Unlistens on an event. Unlistens? Apparently they don't speak English either. * @param {goog.events.EventTarget|EventTarget} src Event source. * @param {string|Array.<string>} type Event type to listen for. * @param {Function|Object} opt_fn Optional callback function to be used as the * listener or an object with handleEvent function. * @param {boolean} opt_capture Optional whether to use capture phase. * @param {Object} opt_handler Object in whose scope to call the listener. * @return {goog.events.EventHandler} This object, allowing for chaining of * calls. */ goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn, opt_capture, opt_handler) { Capture?! if (this.key_ || this.keys_) { if (goog.isArray(type)) { for (var i = 0; i < type.length; i++) { this.unlisten(src, type[i], opt_fn, opt_capture, opt_handler); } } else { var listener = goog.events.getListener(src, type, opt_fn || this, opt_capture || false, opt_handler || this.handler_ || this); if (listener) { var key = listener.key; goog.events.unlistenByKey(key); if (this.keys_) { goog.object.remove(this.keys_, key); } else if (this.key_ == key) { this.key_ = null; } } } } return this; }; /** * Removes an event listener which was added with listenWithWrapper(). * * @param {EventTarget|goog.events.EventTarget} src The target to stop * listening to events on. * @param {goog.events.EventWrapper} wrapper Event wrapper to use. * @param {Function|Object} listener The listener function to remove. * @param {boolean} opt_capt In DOM-compliant browsers, this determines * whether the listener is fired during the capture or bubble phase of the * event. * @param {Object} opt_handler Element in whose scope to call the listener. * @return {goog.events.EventHandler} This object, allowing for chaining of * calls. */ goog.events.EventHandler.prototype.unlistenWithWra pper = function(src, wrapper, listener, opt_capt, opt_handler) { wrapper.unlisten(src, listener, opt_capt, opt_handler || this.handler_, this); return this; }; /** * Unlistens to all events. */ goog.events.EventHandler.prototype.removeAll = function() { if (this.keys_) { for (var key in this.keys_) { goog.events.unlistenByKey((/** @type {number} */ key)); // Clean the keys before returning object to the pool. delete this.keys_[key]; } goog.events.EventHandler.keyPool_.releaseObject(th is.keys_); this.keys_ = null; } else if (this.key_) { goog.events.unlistenByKey(this.key_); } }; /** * Disposes of this EventHandler and remove all listeners that it registered. */ goog.events.EventHandler.prototype.disposeInternal = function() { goog.events.EventHandler.superClass_.disposeIntern al.call(this); this.removeAll(); }; /** * Default event handler * @param {goog.events.Event} e Event object. */ goog.events.EventHandler.prototype.handleEvent = function(e) { throw Error('EventHandler.handleEvent not implemented'); }; Whatever. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Copyright 2005 Google Inc. All Rights Reserved. /** * @fileoverview Implementation of EventTarget as defined by W3C DOM 2/3. * * @see ../demos/eventtarget.html */ /** * Namespace for events */ goog.provide('goog.events.EventTarget'); goog.require('goog.Disposable'); goog.require('goog.events'); /** * This implements the EventTarget interface as defined by W3C DOM 2/3. The * main difference from the spec is that the this does not know about event * propagation and therefore the flag whether to use bubbling or capturing is * not used. * * Another difference is that event objects do not really have to implement * the Event interface. An object is treated as an event object if it has a * type property. * * It also allows you to pass a string instead of an event object and in that * case an event like object is created with the type set to the string value. * * Unless propagation is stopped, events dispatched by an EventTarget bubble * to its parent event target, returned by <code>getParentEventTarget</ code>. * To set the parent event target, call <code>setParentEventTarget</ code> or * override <code>getParentEventTarget</code> in a subclass. Subclasses that * don't support changing the parent event target should override the setter * to throw an error. * * Example usage: * <pre> * var et = new goog.events.EventTarget; * function f(e) { * alert("Type: " + e.type + "\nTarget: " + e.target); * } * et.addEventListener("foo", f); * ... * et.dispatchEvent({type: "foo"}); // will call f * // or et.dispatchEvent("foo"); * ... * et.removeEventListener("foo", f); * * // You can also use the EventHandler interface: * var eh = { * handleEvent: function(e) { * ... * } * }; * et.addEventListener("bar", eh); * </pre> * * @constructor * @extends {goog.Disposable} */ goog.events.EventTarget = function() { goog.Disposable.call(this); }; goog.inherits(goog.events.EventTarget, goog.Disposable); /** * Used to tell if an event is a real event in goog.events.listen() so we don't * get listen() calling addEventListener() and vice-versa. * @type {boolean} * @private */ goog.events.EventTarget.prototype.customEvent_ = true; /** * Parent event target, used during event bubbling. * @type {goog.events.EventTarget?} * @private */ goog.events.EventTarget.prototype.parentEventTarge t_ = null; /** * Returns the parent of this event target to use for bubbling. * * @return {goog.events.EventTarget} The parent EventTarget or null if there * is no parent. */ goog.events.EventTarget.prototype.getParentEventTa rget = function() { return this.parentEventTarget_; }; /** * Sets the parent of this event target to use for bubbling. * * @param {goog.events.EventTarget?} parent Parent EventTarget (null if none). */ goog.events.EventTarget.prototype.setParentEventTa rget = function (parent) { this.parentEventTarget_ = parent; }; /** * Adds an event listener to the event target. The same handler can only be * added once per the type. Even if you add the same handler multiple times * using the same type then it will only be called once when the event is * dispatched. * * Supported for legacy but use goog.events.listen(src, type, handler) instead. * * @param {string} type The type of the event to listen for. * @param {Function|Object} handler The function to handle the event. The * handler can also be an object that implements the handleEvent method * which takes the event object as argument. * @param {boolean} opt_capture In DOM-compliant browsers, this determines * whether the listener is fired during the capture or bubble phase * of the event. * @param {Object} opt_handlerScope Object in whose scope to call the listener. */ goog.events.EventTarget.prototype.addEventListener = function( type, handler, opt_capture, opt_handlerScope) { goog.events.listen(this, type, handler, opt_capture, opt_handlerScope); }; /** * Removes an event listener from the event target. The handler must be the * same object as the one added. If the handler has not been added then * nothing is done. * @param {string} type The type of the event to listen for. * @param {Function|Object} handler The function to handle the event. The * handler can also be an object that implements the handleEvent method * which takes the event object as argument. * @param {boolean} opt_capture In DOM-compliant browsers, this determines * whether the listener is fired during the capture or bubble phase * of the event. * @param {Object} opt_handlerScope Object in whose scope to call the listener. */ goog.events.EventTarget.prototype.removeEventListe ner = function( type, handler, opt_capture, opt_handlerScope) { goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope); }; /** * Dispatches an event (or event like object) and calls all listeners * listening for events of this type. The type of the event is decided by the * type property on the event object. * * If any of the listeners returns false OR calls preventDefault then this * function will return false. If one of the capture listeners calls * stopPropagation, then the bubble listeners won't fire. * * @param {string|Object|goog.events.Event} e Event object. * @return {boolean} If anyone called preventDefault on the event object (or * if any of the handlers returns false this will also return false. */ goog.events.EventTarget.prototype.dispatchEvent = function(e) { return goog.events.dispatchEvent(this, e); }; /** * Unattach listeners from this object. Classes that extend EventTarget may * need to override this method in order to remove references to DOM Elements * and additional listeners, it should be something like this: * <pre> * MyClass.prototype.disposeInternal = function() { * MyClass.superClass_.disposeInternal.call(this); * // Dispose logic for MyClass * }; * </pre> * @protected */ goog.events.EventTarget.prototype.disposeInternal = function() { goog.events.EventTarget.superClass_.disposeInterna l.call(this); goog.events.removeAll(this); this.parentEventTarget_ = null; }; // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Copyright 2005 Google Inc. All Rights Reserved. /** * @fileoverview Event Manager. * * Provides an abstracted interface to the browsers' event * systems. This uses 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. I doubt it. * * It simulates capture & bubble in Internet Explorer. Again. * * The listeners will also automagically have their event objects patched, so * your handlers don't need to worry about the browser. * * Example usage: * <pre> * goog.events.listen(myNode, 'click', function(e) { alert('woo') }); * goog.events.listen(myNode, 'mouseover', mouseHandler, true); * goog.events.unlisten(myNode, 'mouseover', mouseHandler, true); * goog.events.removeAll(myNode); * goog.events.removeAll(); * </pre> * * in IE and event object patching] * * @supported IE6+, FF1.5+, WebKit, Opera. * @see ../demos/events.html * @see ../demos/event-propagation.html * @see ../demos/stopevent.html */ // This uses 3 lookup tables/trees. // listenerTree_ is a tree of type -> capture -> src hash code ->[Listener] // listeners_ is a map of key ->[Listener] // // The key is a field of the Listener. The Listener class also has the type, // capture and the src so one can always trace back in the tree // // sources_: src hc ->[Listener] goog.provide('goog.events'); goog.provide('goog.events.EventType'); goog.require('goog.array'); goog.require('goog.debug.errorHandlerWeakDep'); goog.require('goog.events.BrowserEvent'); goog.require('goog.events.Event'); goog.require('goog.events.EventWrapper'); goog.require('goog.events.pools'); goog.require('goog.object'); goog.require('goog.userAgent'); Note that last one. I think "goof" would be more appropriate a name for this "space". /** * Container for storing event listeners and their proxies * @private * @type {Object.<goog.events.Listener>} */ goog.events.listeners_ = {}; /** * The root of the listener tree * @private * @type {Object} */ goog.events.listenerTree_ = {}; /** * Lookup for mapping source hash codes to listeners * @private * @type {Object} */ goog.events.sources_ = {}; /** * String used to prepend to IE event types. Not a constant so that it is not * inlined. * @type {string} * @private */ goog.events.onString_ = 'on'; /** * Map of computed on strings for IE event types. Caching this removes an extra * object allocation in goog.events.listen which improves IE6 performance. * @type {Object} * @private */ goog.events.onStringMap_ = {}; /** * Separator used to split up the various parts of an event key, to help avoid * the possibilities of collisions. * @type {string} * @private */ goog.events.keySeparator_ = '_'; /** * Adds an event listener for a specific event on a DOM Node or an object that * has implemented {@link goog.events.EventTarget}. A listener can only be * added once to an object and if it is added again the key for the listener * is returned. * * @param {EventTarget|goog.events.EventTarget} src The node to listen to * events on. * @param {string|Array.<string>} type Event type or array of event types. * @param {Function|Object} listener Callback method, or an object with a * handleEvent function. * @param {boolean} opt_capt Whether to fire in capture phase (defaults to * false). * @param {Object} opt_handler Element in whose scope to call the listener. * @return {number?} Unique key for the listener. */ goog.events.listen = function(src, type, listener, opt_capt, opt_handler) { if (!type) { throw Error('Invalid event type'); Waste of time and space. } else if (goog.isArray(type)) { Notice how the design aims for the path of most resistance every time. ![]() for (var i = 0; i < type.length; i++) { Inefficient. Rookie mistake. goog.events.listen(src, type[i], listener, opt_capt, opt_handler); } return null; } else { var capture = !!opt_capt; var map = goog.events.listenerTree_; if (!(type in map)) { map[type] = goog.events.pools.getObject(); } map = map[type]; if (!(capture in map)) { !map[capture] map[capture] = goog.events.pools.getObject(); map.count_++; } map = map[capture]; var srcHashCode = goog.getHashCode(src); var listenerArray, listenerObj; // The remaining_ property is used to be able to short circuit the iteration // of the event listeners. // // Increment the remaining event listeners to call even if this event might // already have been fired. At this point we do not know if the event has // been fired and it is too expensive to find out. By incrementing it we are // guaranteed that we will not skip any event listeners. map.remaining_++; // Do not use srcHashCode in map here since that will cast the number to a // string which will allocate one string object. if (!map[srcHashCode]) { listenerArray = map[srcHashCode] = goog.events.pools.getArray(); map.count_++; } else { listenerArray = map[srcHashCode]; // Ensure that the listeners do not already contain the current listener for (var i = 0; i < listenerArray.length; i++) { listenerObj = listenerArray[i]; if (listenerObj.listener == listener && listenerObj.handler == opt_handler) { // If this listener has been removed we should not return its key. It // is OK that we create new listenerObj below since the removed one // will be cleaned up later. if (listenerObj.removed) { break; } // We already have this listener. Return its key. return listenerArray[i].key; } } } var proxy = goog.events.pools.getProxy(); proxy.src = src; listenerObj = goog.events.pools.getListener(); listenerObj.init(listener, proxy, src, type, capture, opt_handler); var key = listenerObj.key; proxy.key = key; listenerArray.push(listenerObj); goog.events.listeners_[key] = listenerObj; if (!goog.events.sources_[srcHashCode]) { goog.events.sources_[srcHashCode] = goog.events.pools.getArray (); } goog.events.sources_[srcHashCode].push(listenerObj); // Attach the proxy through the browser's API if (src.addEventListener) { if (src == goog.global || !src.customEvent_) { src.addEventListener(type, proxy, capture); } } else { // The else above used to be else if (src.attachEvent) and then there was // another else statement that threw an exception warning the developer // they made a mistake. This resulted in an extra object allocation in IE6 // due to a wrapper object that had to be implemented around the element // and so was removed. src.attachEvent(goog.events.getOnString_(type), proxy); } return key; } }; All of that madness, just to attach/detach listeners? And who would want to try their simulated capture and bubbling? /** * Adds an event listener for a specific event on a DomNode or an object that * has implemented {@link goog.events.EventTarget}. After the event has fired * the event listener is removed from the target. * * @param {EventTarget|goog.events.EventTarget} src The node to listen to * events on. * @param {string|Array.<string>} type Event type or array of event types. * @param {Function|Object} listener Callback method. * @param {boolean} opt_capt Fire in capture phase?. * @param {Object} opt_handler Element in whose scope to call the listener. * @return {number?} Unique key for the listener. */ goog.events.listenOnce = function(src, type, listener, opt_capt, opt_handler) { if (goog.isArray(type)) { Again. It's like they are purposely trying to do everything in the least reliable way possible. Check for a string, not an array (former is 100%, latter is not). for (var i = 0; i < type.length; i++) { goog.events.listenOnce(src, type[i], listener, opt_capt, opt_handler); } return null; } var key = goog.events.listen(src, type, listener, opt_capt, opt_handler); var listenerObj = goog.events.listeners_[key]; listenerObj.callOnce = true; return key; }; /** * Adds an event listener with a specific event wrapper on a DOM Node or an * object that has implemented {@link goog.events.EventTarget}. A listener can * only be added once to an object. * * @param {EventTarget|goog.events.EventTarget} src The node to listen to * events on. * @param {goog.events.EventWrapper} wrapper Event wrapper to use. * @param {Function|Object} listener Callback method, or an object with a * handleEvent function. * @param {boolean} opt_capt Whether to fire in capture phase (defaults to * false). * @param {Object} opt_handler Element in whose scope to call the listener. */ goog.events.listenWithWrapper = function(src, wrapper, listener, opt_capt, opt_handler) { wrapper.listen(src, listener, opt_capt, opt_handler); }; /** * Removes an event listener which was added with listen(). * * @param {EventTarget|goog.events.EventTarget} src The target to stop * listening to events on. * @param {string|Array.<string>} type The name of the event without the 'on' * prefix. * @param {Function|Object} listener The listener function to remove. * @param {boolean} opt_capt In DOM-compliant browsers, this determines * whether the listener is fired during the capture or bubble phase of the * event. * @param {Object} opt_handler Element in whose scope to call the listener. * @return {boolean?} indicating whether the listener was there to remove. */ goog.events.unlisten = function(src, type, listener, opt_capt, opt_handler) { if (goog.isArray(type)) { Again. for (var i = 0; i < type.length; i++) { goog.events.unlisten(src, type[i], listener, opt_capt, opt_handler); } return null; } var capture = !!opt_capt; var listenerArray = goog.events.getListeners_(src, type, capture); if (!listenerArray) { return false; } for (var i = 0; i < listenerArray.length; i++) { if (listenerArray[i].listener == listener && listenerArray[i].capture == capture && listenerArray[i].handler == opt_handler) { return goog.events.unlistenByKey(listenerArray[i].key); } } return false; }; /** * Removes an event listener which was added with listen() by the key * returned by listen(). * * @param {number?} key The key returned by listen() for this event listener. * @return {boolean} indicating whether the listener was there to remove. */ goog.events.unlistenByKey = function(key) { // Do not use key in listeners here since that will cast the number to a // string which will allocate one string object. if (!goog.events.listeners_[key]) { return false; } var listener = goog.events.listeners_[key]; if (listener.removed) { return false; } var src = listener.src; var type = listener.type; var proxy = listener.proxy; var capture = listener.capture; if (src.removeEventListener) { // EventTarget calls unlisten so we need to ensure that the source is not // an event target to prevent re-entry. // TODO: What is this goog.global for? Why would anyone listen to // events on the [[Global]] object? Is it supposed to be window? Why would // we not want to allow removing event listeners on the window? if (src == goog.global || !src.customEvent_) { src.removeEventListener(type, proxy, capture); } } else if (src.detachEvent) { src.detachEvent(goog.events.getOnString_(type), proxy); } var srcHashCode = goog.getHashCode(src); var listenerArray = goog.events.listenerTree_[type][capture] [srcHashCode]; // In a perfect implementation we would decrement the remaining_ field here // but then we would need to know if the listener has already been fired or // not. We therefore skip doing this and in this uncommon case the entire // ancestor chain will need to be traversed as before. // Remove from sources_ if (goog.events.sources_[srcHashCode]) { var sourcesArray = goog.events.sources_[srcHashCode]; goog.array.remove(sourcesArray, listener); if (sourcesArray.length == 0) { delete goog.events.sources_[srcHashCode]; } } listener.removed = true; listenerArray.needsCleanup_ = true; goog.events.cleanUp_(type, capture, srcHashCode, listenerArray); delete goog.events.listeners_[key]; return true; }; /** * Removes an event listener which was added with listenWithWrapper(). * * @param {EventTarget|goog.events.EventTarget} src The target to stop * listening to events on. * @param {goog.events.EventWrapper} wrapper Event wrapper to use. * @param {Function|Object} listener The listener function to remove. * @param {boolean} opt_capt In DOM-compliant browsers, this determines * whether the listener is fired during the capture or bubble phase of the * event. * @param {Object} opt_handler Element in whose scope to call the listener. */ goog.events.unlistenWithWrapper = function(src, wrapper, listener, opt_capt, opt_handler) { wrapper.unlisten(src, listener, opt_capt, opt_handler); }; /** * Cleans up the listener array as well as the listener tree * @param {string} type The type of the event. * @param {boolean} capture Whether to clean up capture phase listeners instead * bubble phase listeners. * @param {number} srcHashCode The hash code of the source. * @param {Array.<goog.events.Listener>} listenerArray The array being cleaned. * @private */ goog.events.cleanUp_ = function(type, capture, srcHashCode, listenerArray) { // The listener array gets locked during the dispatch phase so that removals // of listeners during this phase does not screw up the indeces. This method // is called after we have removed a listener as well as after the dispatch // phase in case any listeners were removed. if (!listenerArray.locked_) { // catches both 0 and not set if (listenerArray.needsCleanup_) { // Loop over the listener array and remove listeners that have removed set // to true. This could have been done with filter or something similar but // we want to change the array in place and we want to minimize // allocations. Adding a listener during this phase adds to the end of the // array so that works fine as long as the length is rechecked every in // iteration. for (var oldIndex = 0, newIndex = 0; oldIndex < listenerArray.length; oldIndex++) { if (listenerArray[oldIndex].removed) { var proxy = listenerArray[oldIndex].proxy; proxy.src = null; goog.events.pools.releaseProxy(proxy); goog.events.pools.releaseListener(listenerArray[oldIndex]); continue; } if (oldIndex != newIndex) { listenerArray[newIndex] = listenerArray[oldIndex]; } newIndex++; } listenerArray.length = newIndex; listenerArray.needsCleanup_ = false; // In case the length is now zero we release the object. if (newIndex == 0) { goog.events.pools.releaseArray(listenerArray); delete goog.events.listenerTree_[type][capture][srcHashCode]; goog.events.listenerTree_[type][capture].count_--; if (goog.events.listenerTree_[type][capture].count_ == 0) { goog.events.pools.releaseObject( goog.events.listenerTree_[type][capture]); delete goog.events.listenerTree_[type][capture]; goog.events.listenerTree_[type].count_--; } if (goog.events.listenerTree_[type].count_ == 0) { goog.events.pools.releaseObject(goog.events.listen erTree_ [type]); delete goog.events.listenerTree_[type]; } } } } }; /** * Removes all listeners from an object, if no object is specified it will * remove all listeners that have been registered. You can also optionally * remove listeners of a particular type or capture phase. * * @param {Object} opt_obj Object to remove listeners from. * @param {string} opt_type Type of event to, default is all types. * @param {boolean} opt_capt Whether to remove the listeners from the capture or * bubble phase. If unspecified, will remove both. * @return {number} Number of listeners removed. */ goog.events.removeAll = function(opt_obj, opt_type, opt_capt) { var count = 0; var noObj = opt_obj == null; var noType = opt_type == null; var noCapt = opt_capt == null; opt_capt = !!opt_capt; if (!noObj) { var srcHashCode = goog.getHashCode(/** @type {Object} */ (opt_obj)); if (goog.events.sources_[srcHashCode]) { var sourcesArray = goog.events.sources_[srcHashCode]; for (var i = sourcesArray.length - 1; i >= 0; i--) { var listener = sourcesArray[i]; if ((noType || opt_type == listener.type) && (noCapt || opt_capt == listener.capture)) { goog.events.unlistenByKey(listener.key); count++; } } } } else { // Loop over the sources_ map instead of over the listeners_ since it is // smaller which results in fewer allocations. goog.object.forEach(goog.events.sources_, function(listeners) { for (var i = listeners.length - 1; i >= 0; i--) { var listener = listeners[i]; if ((noType || opt_type == listener.type) && (noCapt || opt_capt == listener.capture)) { goog.events.unlistenByKey(listener.key); count++; } } }); } return count; }; /** * Gets the listeners for a given object, type and capture phase. * * @param {Object} obj Object to get listeners for. * @param {string} type Event type. * @param {boolean} capture Capture phase?. * @return {Array.<goog.events.Listener>} Array of listener objects. */ goog.events.getListeners = function(obj, type, capture) { return goog.events.getListeners_(obj, type, capture) || []; }; /** * Gets the listeners for a given object, type and capture phase. * * @param {Object} obj Object to get listeners for. * @param {string?} type Event type. * @param {boolean} capture Capture phase?. * @return {Array.<goog.events.Listener>?} Array of listener objects. * Returns null if object has no lsiteners of that type. * @private */ goog.events.getListeners_ = function(obj, type, capture) { var map = goog.events.listenerTree_; if (type in map) { map = map[type]; if (capture in map) { map = map[capture]; var objHashCode = goog.getHashCode(obj); if (map[objHashCode]) { return map[objHashCode]; } } } return null; }; /** * Gets the goog.events.Listener for the event or null if no such listener is * in use. * * @param {EventTarget|goog.events.EventTarget} src The node to stop * listening to events on. * @param {string?} type The name of the event without the 'on' prefix. * @param {Function|Object} listener The listener function to remove. * @param {boolean} opt_capt In DOM-compliant browsers, this determines * whether the listener is fired during the * capture or bubble phase of the event. * @param {Object} opt_handler Element in whose scope to call the listener. * @return {goog.events.Listener?} the found listener or null if not found. */ goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) { var capture = !!opt_capt; var listenerArray = goog.events.getListeners_(src, type, capture); if (listenerArray) { for (var i = 0; i < listenerArray.length; i++) { if (listenerArray[i].listener == listener && listenerArray[i].capture == capture && listenerArray[i].handler == opt_handler) { // We already have this listener. Return its key. return listenerArray[i]; } } } return null; }; How many methods does this interface have? They all look like initial efforts to me. /** * Returns whether an event target has any active listeners matching the * specified signature. If either the type or capture parameters are * unspecified, the function will match on the remaining criteria. * * @param {EventTarget|goog.events.EventTarget} obj Target to get listeners for. * @param {string} opt_type Event type. * @param {boolean} opt_capture Whether to check for capture or bubble- phase * listeners. * @return {boolean} Whether an event target has one or more listeners matching * the requested type and/or capture phase. */ goog.events.hasListener = function(obj, opt_type, opt_capture) { var objHashCode = goog.getHashCode(obj) var listeners = goog.events.sources_[objHashCode]; if (listeners) { var hasType = goog.isDef(opt_type); var hasCapture = goog.isDef(opt_capture); if (hasType && hasCapture) { // Lookup in the listener tree whether the specified listener exists. var map = goog.events.listenerTree_[opt_type] return !!map && !!map[opt_capture] && objHashCode in map [opt_capture]; } else if (!(hasType || hasCapture)) { // Simple check for whether the event target has any listeners at all. return true; } else { // Iterate through the listeners for the event target to find a match. return goog.array.some(listeners, function(listener) { return (hasType && listener.type == opt_type) || (hasCapture && listener.capture == opt_capture); }); } } return false; }; What a mess. /** * Provides a nice string showing the normalized event objects public members * @param {Object} e Event Object. * @return {string} String of the public members of the normalized event object. */ goog.events.expose = function(e) { var str = []; for (var key in e) { if (e[key] && e[key].id) { str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')'); } else { str.push(key + ' = ' + e[key]); } } return str.join('\n'); }; Not nice. /** * Constants for event names. * @enum {string} */ // TODO: Move to its own file. I think they've got enough files at this point. goog.events.EventType = { // Mouse events CLICK: 'click', DBLCLICK: 'dblclick', MOUSEDOWN: 'mousedown', MOUSEUP: 'mouseup', MOUSEOVER: 'mouseover', MOUSEOUT: 'mouseout', MOUSEMOVE: 'mousemove', SELECTSTART: 'selectstart', // IE, Safari, Chrome // Key events KEYPRESS: 'keypress', KEYDOWN: 'keydown', KEYUP: 'keyup', // Focus BLUR: 'blur', FOCUS: 'focus', DEACTIVATE: 'deactivate', // IE only // TODO: Test these. I experienced problems with DOMFocusIn, the event // just wasn't firing. A little late isn't? The people who would use this will not read the code comments. FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn', FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut', // Forms CHANGE: 'change', SELECT: 'select', SUBMIT: 'submit', // Misc CONTEXTMENU: 'contextmenu', DRAGSTART: 'dragstart', ERROR: 'error', HASHCHANGE: 'hashchange', HELP: 'help', LOAD: 'load', LOSECAPTURE: 'losecapture', READYSTATECHANGE: 'readystatechange', RESIZE: 'resize', SCROLL: 'scroll', UNLOAD: 'unload' }; /** * Returns a string wth on prepended to the specified type. This is used for IE * which expects "on" to be prepended. This function caches the string in order * to avoid extra allocations in steady state. * @param {string} type Event type strng. * @return {string} The type string with 'on' prepended. * @private */ goog.events.getOnString_ = function(type) { if (type in goog.events.onStringMap_) { return goog.events.onStringMap_[type]; } return goog.events.onStringMap_[type] = goog.events.onString_ + type; }; /** * Fires an object's listeners of a particular type and phase * * @param {Object} obj Object whose listeners to call. * @param {string} type Event type. * @param {boolean} capture Which event phase. * @param {Object} eventObject Event object to be passed to listener. * @return {boolean} True if all listeners returned true else false. */ goog.events.fireListeners = function(obj, type, capture, eventObject) { var map = goog.events.listenerTree_; if (type in map) { map = map[type]; if (capture in map) { return goog.events.fireListeners_(map[capture], obj, type, capture, eventObject); } } return true; }; /** * Fires an object's listeners of a particular type and phase. * * @param {Object} map Object with listeners in it. * @param {Object} obj Object whose listeners to call. * @param {string} type Event type. * @param {boolean} capture Which event phase. * @param {Object} eventObject Event object to be passed to listener. * @return {boolean} True if all listeners returned true else false. * @private */ goog.events.fireListeners_ = function(map, obj, type, capture, eventObject) { var retval = 1; var objHashCode = goog.getHashCode(obj); if (map[objHashCode]) { map.remaining_--; var listenerArray = map[objHashCode]; // If locked_ is not set (and if already 0) initialize it to 1. if (!listenerArray.locked_) { listenerArray.locked_ = 1; } else { listenerArray.locked_++; } try { // Events added in the dispatch phase should not be dispatched in // the current dispatch phase. They will be included in the next // dispatch phase though. var length = listenerArray.length; for (var i = 0; i < length; i++) { var listener = listenerArray[i]; // We might not have a listener if the listener was removed. if (listener && !listener.removed) { retval &= goog.events.fireListener(listener, eventObject) !== false; } } } finally { listenerArray.locked_--; goog.events.cleanUp_(type, capture, objHashCode, listenerArray); } try...finally (!) is too expansive. } return Boolean(retval); Odd they weren't dealing with a boolean all along. }; /** * Fires a listener with a set of arguments * * @param {goog.events.Listener} listener The listener object to call. * @param {Object} eventObject The event object to pass to the listener. * @return {boolean} Result of listener. */ goog.events.fireListener = function(listener, eventObject) { var rv = listener.handleEvent(eventObject); if (listener.callOnce) { goog.events.unlistenByKey(listener.key); } return rv; }; /** * Gets the total number of listeners currently in the system. * @return {number} Number of listeners. */ goog.events.getTotalListenerCount = function() { return goog.object.getCount(goog.events.listeners_); }; /** * Dispatches an event (or event like object) and calls all listeners * listening for events of this type. The type of the event is decided by the * type property on the event object. * * If any of the listeners returns false OR calls preventDefault then this * function will return false. If one of the capture listeners calls * stopPropagation, then the bubble listeners won't fire. * * @param {goog.events.EventTarget} src The event target. * @param {string|Object|goog.events.Event} e Event object. * @return {boolean} If anyone called preventDefault on the event object (or * if any of the handlers returns false) this will also return false. * If there are no handlers, or if all handlers return true, this returns * true. */ goog.events.dispatchEvent = function(src, e) { // If accepting a string or object, create a custom event object so that // preventDefault and stopPropagation work with the event. If accepting a string or object? if (goog.isString(e)) { e = new goog.events.Event(e, src); } else if (!(e instanceof goog.events.Event)) { var oldEvent = e; e = new goog.events.Event(e.type, src); goog.object.extend(e, oldEvent); } else { e.target = e.target || src; This is clearly awful code in any language. No wonder it has sat since 2005 (who is going to untangle such a mess?) Provides insight into the constant unraveling effects caused by Google's attempts to patch their apps. } var rv = 1, ancestors; var type = e.type; var map = goog.events.listenerTree_; if (!(type in map)) { return true; } map = map[type]; var hasCapture = true in map; What do you say about a line of code like that? var targetsMap; if (hasCapture) { // Build ancestors now ancestors = []; for (var parent = src; parent; parent = parent.getParentEventTarget ()) { ancestors.push(parent); } targetsMap = map[true]; targetsMap.remaining_ = targetsMap.count_; // Call capture listeners for (var i = ancestors.length - 1; !e.propagationStopped_ && i >= 0 && targetsMap.remaining_; i--) { e.currentTarget = ancestors[i]; rv &= goog.events.fireListeners_(targetsMap, ancestors[i], e.type, true, e) && e.returnValue_ != false; } } var hasBubble = false in map; Again. if (hasBubble) { targetsMap = map[false]; targetsMap.remaining_ = targetsMap.count_; if (hasCapture) { // We have the ancestors. // Call bubble listeners for (var i = 0; !e.propagationStopped_ && i < ancestors.length && targetsMap.remaining_; i++) { e.currentTarget = ancestors[i]; rv &= goog.events.fireListeners_(targetsMap, ancestors[i], e.type, false, e) && e.returnValue_ != false; } } else { // In case we don't have capture we don't have to build up the // ancestors array. for (var current = src; !e.propagationStopped_ && current && targetsMap.remaining_; current = current.getParentEventTarget()) { e.currentTarget = current; rv &= goog.events.fireListeners_(targetsMap, current, e.type, false, e) && e.returnValue_ != false; } } } return Boolean(rv); And again. Why not use a boolean to begin with? }; /** * Installs exception protection for the browser event entry point using the * given error handler. * * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to * protect the entry point. * @param {boolean} opt_tracers Whether to install tracers around the browser * event entry point. */ goog.events.protectBrowserEventEntryPoint = function( errorHandler, opt_tracers) { goog.events.handleBrowserEvent_ = errorHandler.protectEntryPoint( goog.events.handleBrowserEvent_, opt_tracers); goog.events.pools.setProxyCallbackFunction (goog.events.handleBrowserEvent_); }; /** * Handles an event and dispatches it to the correct listeners. This * function is a proxy for the real listener the user specified. * * @param {string} key Unique key for the listener. * @param {Event} opt_evt Optional event object that gets passed in via the * native event handlers. * @return {boolean} Result of the event handler. * @this {goog.events.EventTarget|Object} The object or Element that * fired the event. * @private */ goog.events.handleBrowserEvent_ = function(key, opt_evt) { // If the listener isn't there it was probably removed when processing // another listener on the same event (e.g. the later listener is // not managed by closure so that they are both fired under IE) This is certainly well documented (as an exercise in futility). If only it were in English. ![]() if (!goog.events.listeners_[key]) { return true; } var listener = goog.events.listeners_[key]; var type = listener.type; var map = goog.events.listenerTree_; if (!(type in map)) { return true; } map = map[type]; var retval, targetsMap; if (goog.userAgent.IE) { All right, put that away sonny. |
|
|
||||
|
||||
|
|
|
|||
|
David Mark wrote:
> Event parts. > This is a very long posting of code. It is hard to read the code because it wraps. Wrap code at 72 chars so that it is easier to follow. If you want others to digest something, don't post such a long post. Instead, focus on something smaller. You might choose a format such as: I saw a problem [description] This is bad because [demonstration/evidence] Here is the relevant part [formatted code] Recap on problem -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/ |
|
|||
|
On Nov 18, 9:10*pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> David Mark wrote: > > Event parts. > > This is a very long posting of code. I didn't write it (the code that is). > > It is hard to read the code because it wraps. I know. > > Wrap code at 72 chars so that it is easier to follow. Sure, I'll get right on it. ![]() > > If you want others to digest something, don't post such a long post. Much of the post is indigestible (the code parts). > Instead, focus on something smaller. You might choose a format such as: > > * *I saw a problem [description] > * *This is bad because [demonstration/evidence] > * *Here is the relevant part [formatted code] > * *Recap on problem Of course not. There's a problem on practically every line. The whole thing is a waste of time. That's the point. |
|
|||
|
On Nov 18, 8:36*pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Nov 18, 9:10*pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote: > > Instead, focus on something smaller. You might choose a format such as: > > * *I saw a problem [description] > > * *This is bad because [demonstration/evidence] > > * *Here is the relevant part [formatted code] > > * *Recap on problem > Of course not. *There's a problem on practically every line. *The > whole thing is a waste of time. *That's the point. Your rants are unreadable, because I can't even distinguish between their code and your complaints. When I can figure out where your comments are, they read like a script for Statler and Waldorf, the two muppets in the theater balcony that insult and complain about everything. Just little snide remarks thrown out with some vague context and no supporting evidence or arguments. Even if you have valid criticisms, they are all lost because of your laziness in snipping, quoting, and organizing your thoughts for comprehension. At least your new anti-Closure crusade is a welcome change from your anti-jQuery crusade. Anxiously awaiting the awesome new Dojo, Matt Kruse |
|
|||
|
On Nov 19, 1:11*pm, Matt Kruse <m...@thekrusefamily.com> wrote:
> On Nov 18, 8:36*pm, David Mark <dmark.cins...@gmail.com> wrote: > > > On Nov 18, 9:10*pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote: > > > Instead, focus on something smaller. You might choose a format such as: > > > * *I saw a problem [description] > > > * *This is bad because [demonstration/evidence] > > > * *Here is the relevant part [formatted code] > > > * *Recap on problem > > Of course not. *There's a problem on practically every line. *The > > whole thing is a waste of time. *That's the point. > > Your rants are unreadable, because I can't even distinguish between > their code and your complaints. I don't care if you can read them. > > When I can figure out where your comments are, they read like a script > for Statler and Waldorf, the two muppets in the theater balcony that > insult and complain about everything. Just little snide remarks thrown > out with some vague context and no supporting evidence or arguments. Who has time to re-hash the same old bullshit. We had most of these same discussions over the last couple of years with regard to your favorite library. > > Even if you have valid criticisms, they are all lost because of your > laziness in snipping, quoting, and organizing your thoughts for > comprehension. Rubbish. The organization is the code. It is what it is. ![]() > > At least your new anti-Closure crusade is a welcome change from your > anti-jQuery crusade. You are such a waste of time. > > Anxiously awaiting the awesome new Dojo, I bet you are. ![]() |
|
|||
|
On Nov 19, 12:10*am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> David Mark wrote: > > Event parts. > > This is a very long posting of code. > > It is hard to read the code because it wraps. > > Wrap code at 72 chars so that it is easier to follow. > > If you want others to digest something, don't post such a long post. > Instead, focus on something smaller. You might choose a format such as: > > * *I saw a problem [description] > * *This is bad because [demonstration/evidence] > * *Here is the relevant part [formatted code] > * *Recap on problem > -- > Garrett > comp.lang.javascript FAQ:http://jibbering.com/faq/ This kind of long text should be posted on a blog or website. |
|
|||
|
On Nov 19, 4:59*pm, JR <groups_j...@yahoo.com.br> wrote:
> On Nov 19, 12:10*am, Garrett Smith <dhtmlkitc...@gmail.com> wrote: > > > > > David Mark wrote: > > > Event parts. > > > This is a very long posting of code. > > > It is hard to read the code because it wraps. > > > Wrap code at 72 chars so that it is easier to follow. > > > If you want others to digest something, don't post such a long post. > > Instead, focus on something smaller. You might choose a format such as: > > > * *I saw a problem [description] > > * *This is bad because [demonstration/evidence] > > * *Here is the relevant part [formatted code] > > * *Recap on problem > > -- > > Garrett > > comp.lang.javascript FAQ:http://jibbering.com/faq/ > > This kind of long text should be posted on a blog or website. What a great idea! ![]() |
|
|||
|
On Nov 19, 5:00*pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Nov 19, 4:59*pm, JR <groups_j...@yahoo.com.br> wrote: > > > > > On Nov 19, 12:10*am, Garrett Smith <dhtmlkitc...@gmail.com> wrote: > > > > David Mark wrote: > > > > Event parts. > > > > This is a very long posting of code. > > > > It is hard to read the code because it wraps. > > > > Wrap code at 72 chars so that it is easier to follow. > > > > If you want others to digest something, don't post such a long post. > > > Instead, focus on something smaller. You might choose a format such as: > > > > * *I saw a problem [description] > > > * *This is bad because [demonstration/evidence] > > > * *Here is the relevant part [formatted code] > > > * *Recap on problem > > > -- > > > Garrett > > > comp.lang.javascript FAQ:http://jibbering.com/faq/ > > > This kind of long text should be posted on a blog or website. > > What a great idea! * ![]() Fixed subject. |
|
|||
|
On Nov 19, 8:00*pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Nov 19, 4:59*pm, JR <groups_j...@yahoo.com.br> wrote: > > > > > On Nov 19, 12:10*am, Garrett Smith <dhtmlkitc...@gmail.com> wrote: > > > > David Mark wrote: > > > > Event parts. > > > > This is a very long posting of code. > > > > It is hard to read the code because it wraps. > > > > Wrap code at 72 chars so that it is easier to follow. > > > > If you want others to digest something, don't post such a long post. > > > Instead, focus on something smaller. You might choose a format such as: > > > > * *I saw a problem [description] > > > * *This is bad because [demonstration/evidence] > > > * *Here is the relevant part [formatted code] > > > * *Recap on problem > > > -- > > > Garrett > > > comp.lang.javascript FAQ:http://jibbering.com/faq/ > > > This kind of long text should be posted on a blog or website. > > What a great idea! * ![]() David, I'm not being ironic (this time :-), but I really think you should post your important comments on your site (as you did recently in www.cinsoft.net/attributes.html), instead of repeating them dozens of times here in the newsgroup. For example, I find very positive when you point out errors or inefficiencies in codes of other developers / companies, but it is difficult to search for your relevant comments in c.l.js because of countless flame wars so common (unfortunately) here. Think about it. Cheers, JR |
|
|||
|
On Nov 19, 5:19*pm, JR <groups_j...@yahoo.com.br> wrote:
> On Nov 19, 8:00*pm, David Mark <dmark.cins...@gmail.com> wrote: > > > > > On Nov 19, 4:59*pm, JR <groups_j...@yahoo.com.br> wrote: > > > > On Nov 19, 12:10*am, Garrett Smith <dhtmlkitc...@gmail.com> wrote: > > > > > David Mark wrote: > > > > > Event parts. > > > > > This is a very long posting of code. > > > > > It is hard to read the code because it wraps. > > > > > Wrap code at 72 chars so that it is easier to follow. > > > > > If you want others to digest something, don't post such a long post.. > > > > Instead, focus on something smaller. You might choose a format suchas: > > > > > * *I saw a problem [description] > > > > * *This is bad because [demonstration/evidence] > > > > * *Here is the relevant part [formatted code] > > > > * *Recap on problem > > > > -- > > > > Garrett > > > > comp.lang.javascript FAQ:http://jibbering.com/faq/ > > > > This kind of long text should be posted on a blog or website. > > > What a great idea! * ![]() > > David, > I'm not being ironic (this time :-), but I really think you should > post your important comments on your site (as you did recently inwww.cinsoft.net/attributes.html), instead of repeating them dozens of > times here in the newsgroup. Believe it or not, I wasn't being (entirely) ironic either. It would be hysterical to add GoogClosure's attribute handling as an additional test case to that very page. Same for jQuery. But I don't have time for that right now. I do have time to glance at their code and post a small sample of the more obvious blunders. For some people, the glass is always half full. ![]() But realize that that project is painted into a corner (even worse than jQuery). The whole design is tied to the browser sniffing, so if they lose the browser sniffing (inevitable), they lose the way-cool "compiler" that they use to cover up the fact that these scripts are bloated beyond belief. Somehow they relate this quandary to their mobile aspirations, which are clearly pipe dreams (slow code doesn't fare well on those either.) ![]() > For example, I find very positive when > you point out errors or inefficiencies in codes of other developers / > companies, but it is difficult to search for your relevant comments in > c.l.js because of countless flame wars so common (unfortunately) here. > Think about it. I have thought about it and I completely agree. The twits show up and start changing the subject from ideas to people (e.g. I don't like your posts, they are too hard to read). They just want attention. ![]() |
|
|||
|
David Mark wrote:
> On Nov 19, 5:19 pm, JR <groups_j...@yahoo.com.br> wrote: >> On Nov 19, 8:00 pm, David Mark <dmark.cins...@gmail.com> wrote: >> >> >> >>> On Nov 19, 4:59 pm, JR <groups_j...@yahoo.com.br> wrote: >>>> On Nov 19, 12:10 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote: >>>>> David Mark wrote: >>>>>> Event parts. >>>>> This is a very long posting of code. >>>>> It is hard to read the code because it wraps. >>>>> Wrap code at 72 chars so that it is easier to follow. >>>>> If you want others to digest something, don't post such a long post. >>>>> Instead, focus on something smaller. You might choose a format such as: >>>>> I saw a problem [description] >>>>> This is bad because [demonstration/evidence] >>>>> Here is the relevant part [formatted code] >>>>> Recap on problem [snip sig] >>>> This kind of long text should be posted on a blog or website. Try to keep the review focused, explain things well. This has potential to be valuable archived material if done properly. Publishing code review here will reach many. What you Look carefully to Cornford's recent review of Google Groups' Function.prototype.bind strategy, using [].peek, bungling the thisArg, converting object args to strings. All carefully and professionally explained. > > But realize that that project is painted into a corner (even worse > than jQuery). The whole design is tied to the browser sniffing, so if > they lose the browser sniffing (inevitable), they lose the way-cool > "compiler" that they use to cover up the fact that these scripts are > bloated beyond belief. Somehow they relate this quandary to their > mobile aspirations, which are clearly pipe dreams (slow code doesn't > fare well on those either.) ![]() > No, and particularly not with a browser such as Blackberry. The blackberry has limited memory. In exhaustive testing, I have witnessed the emulator freezing and barfing up java.lang.NullPointerException (npe). The Blackberry browser is a very light browser intended for the battery powered device. Javascript is turned off, by default. The browser does not handle inefficient javascript elegantly. Mobile devices in general have much more limited CPU, much less battery life. Javascript that is less efficient uses phone battery faster. Javascript will not execute as quickly on a Mobile device as it would on a 2ghz dual processor. The more javascript that is downloaded, the less likely it will be cached. Indeed, this is a good reason to minify the script file to the smallest possible size. Cached code is going to be available much sooner than code that is downloaded. Connection speed varies and bandwidth fees may apply. The iphone is not a matter of light discussion. Of the many things Apple is doing with the iPhone, none are for the greater good; all are intended to benefit Apple. All of it preying on consumer ignorance. In a nutshell, the Evil parts are: the app store, choosing the carrier for the user (not allowed to use as a pure device), and browser Touch Events (an incompatible API for "standard" RIAs). Apple and Nokia are also (pay-to-play) sponsoring the w3c efforts (I accidentally just typed "w3c errors", but that may have been a more fitting term for what is going on). I'll omit discussion of considering Apple iPhone (in contempt). Your opinion of what is "evil" falls quite short of what I see Apple doing, the things I have experienced in life, and of the significantly ill-minded and dire acts known to man. Part of my annoyance with this title is that naivete it portrays. *sigh* Now that I've gotten that out... Take time to review each small part and double check how it reads in the NG. You should want to reformat the code so that it wraps properly. Explain the problems and the consequences carefully. Don't focus on any small things like "bad form" or make flippant remarks. -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/ [1]http://github.com/GarrettS/ape-javascript-library/blob/master/adhoctest/offsetTopUpdated.test |
|
|||
|
On Thu, 19 Nov 2009 14:41:45 -0800 (PST), David Mark wrote:
>> > > This kind of long text should be posted on a blog or website. >> [...] I really think you should post your important comments on >> your site (as you did recently inwww.cinsoft.net/attributes.html), >> instead of repeating them dozens of times here in the newsgroup. >But realize that that project is painted into a corner (even worse >than jQuery). The whole design is tied to the browser sniffing, so if >they lose the browser sniffing (inevitable), they lose the way-cool >"compiler" that they use to cover up the fact that these scripts are >bloated beyond belief. Somehow they relate this quandary to their >mobile aspirations, which are clearly pipe dreams (slow code doesn't >fare well on those either.) ![]() If anybody wants a personal blog for such purposes, you can have one on http://winhlp.com/ . There are already some JavaScript articles on that site in the programming forum. (Type javascript into the search field to find them quickly.) Hans-Georg |
|
|||
|
David Mark wrote:
> I know that. For something that large it was out of the question. If > I post smaller bits (or more likely a wrap-up with highlights), I'll > wrap them. Or maybe I'll just post it on a Web page, but that defeats > the archival purposes of doing this. > And who maintains the archives? Isn't it those incompetent ignoramuses working from Mountain View that you are railing against? |
|
|||
|
On Nov 20, 12:28*pm, SteveYoungTbird <stephen.yo...@chello.at> wrote:
> David Mark wrote: > > I know that. *For something that large it was out of the question. *If > > I post smaller bits (or more likely a wrap-up with highlights), I'll > > wrap them. *Or maybe I'll just post it on a Web page, but that defeats > > the archival purposes of doing this. > > And who maintains the archives? Isn't it those incompetent ignoramuses > working from Mountain View that you are railing against? You seem to have missed something. For one, GG is a piece of crap (archive interface included). For two, we're talking about JS. |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Google Closure: The Dumb Parts | David Mark | Newsgroup comp.lang.javascript | 1 | 11-18-2009 10:16 PM |
| Google Groups currently not forwarding to [comp.lang.c++.moderated] | Alf P. Steinbach | Newsgroup comp.language.c++.moderated | 1 | 09-24-2009 08:44 AM |
| How to understand this form (something) (param); | john_woo | Newsgroup comp.lang.javascript | 56 | 08-07-2009 06:37 PM |
| OT Re: Google docs IS as secure AS | ajay ohri | Newsgroup comp.soft-sys.sas | 0 | 11-15-2008 07:16 AM |
| Re: OT for a Friday: A new-to-me Google Feature | Schechter, Robert S | Newsgroup comp.soft-sys.sas | 0 | 01-28-2005 06:28 PM |