JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.0
[ckeditor.git] / _source / core / dom / domobject.js
diff --git a/_source/core/dom/domobject.js b/_source/core/dom/domobject.js
new file mode 100644 (file)
index 0000000..d8c3fde
--- /dev/null
@@ -0,0 +1,204 @@
+/*\r
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+/**\r
+ * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base\r
+ *             for other classes representing DOM objects.\r
+ */\r
+\r
+/**\r
+ * Represents a DOM object. This class is not intended to be used directly. It\r
+ * serves as the base class for other classes representing specific DOM\r
+ * objects.\r
+ * @constructor\r
+ * @param {Object} nativeDomObject A native DOM object.\r
+ * @augments CKEDITOR.event\r
+ * @example\r
+ */\r
+CKEDITOR.dom.domObject = function( nativeDomObject )\r
+{\r
+       if ( nativeDomObject )\r
+       {\r
+               /**\r
+                * The native DOM object represented by this class instance.\r
+                * @type Object\r
+                * @example\r
+                * var element = new CKEDITOR.dom.element( 'span' );\r
+                * alert( element.$.nodeType );  // "1"\r
+                */\r
+               this.$ = nativeDomObject;\r
+       }\r
+};\r
+\r
+CKEDITOR.dom.domObject.prototype = (function()\r
+{\r
+       // Do not define other local variables here. We want to keep the native\r
+       // listener closures as clean as possible.\r
+\r
+       var getNativeListener = function( domObject, eventName )\r
+       {\r
+               return function( domEvent )\r
+               {\r
+                       // In FF, when reloading the page with the editor focused, it may\r
+                       // throw an error because the CKEDITOR global is not anymore\r
+                       // available. So, we check it here first. (#2923)\r
+                       if ( typeof CKEDITOR != 'undefined' )\r
+                               domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) );\r
+               };\r
+       };\r
+\r
+       return /** @lends CKEDITOR.dom.domObject.prototype */ {\r
+\r
+               getPrivate : function()\r
+               {\r
+                       var priv;\r
+\r
+                       // Get the main private function from the custom data. Create it if not\r
+                       // defined.\r
+                       if ( !( priv = this.getCustomData( '_' ) ) )\r
+                               this.setCustomData( '_', ( priv = {} ) );\r
+\r
+                       return priv;\r
+               },\r
+\r
+               /** @ignore */\r
+               on  : function( eventName )\r
+               {\r
+                       // We customize the "on" function here. The basic idea is that we'll have\r
+                       // only one listener for a native event, which will then call all listeners\r
+                       // set to the event.\r
+\r
+                       // Get the listeners holder object.\r
+                       var nativeListeners = this.getCustomData( '_cke_nativeListeners' );\r
+\r
+                       if ( !nativeListeners )\r
+                       {\r
+                               nativeListeners = {};\r
+                               this.setCustomData( '_cke_nativeListeners', nativeListeners );\r
+                       }\r
+\r
+                       // Check if we have a listener for that event.\r
+                       if ( !nativeListeners[ eventName ] )\r
+                       {\r
+                               var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName );\r
+\r
+                               if ( this.$.addEventListener )\r
+                                       this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );\r
+                               else if ( this.$.attachEvent )\r
+                                       this.$.attachEvent( 'on' + eventName, listener );\r
+                       }\r
+\r
+                       // Call the original implementation.\r
+                       return CKEDITOR.event.prototype.on.apply( this, arguments );\r
+               },\r
+\r
+               /** @ignore */\r
+               removeListener : function( eventName )\r
+               {\r
+                       // Call the original implementation.\r
+                       CKEDITOR.event.prototype.removeListener.apply( this, arguments );\r
+\r
+                       // If we don't have listeners for this event, clean the DOM up.\r
+                       if ( !this.hasListeners( eventName ) )\r
+                       {\r
+                               var nativeListeners = this.getCustomData( '_cke_nativeListeners' );\r
+                               var listener = nativeListeners && nativeListeners[ eventName ];\r
+                               if ( listener )\r
+                               {\r
+                                       if ( this.$.removeEventListener )\r
+                                               this.$.removeEventListener( eventName, listener, false );\r
+                                       else if ( this.$.detachEvent )\r
+                                               this.$.detachEvent( 'on' + eventName, listener );\r
+\r
+                                       delete nativeListeners[ eventName ];\r
+                               }\r
+                       }\r
+               }\r
+       };\r
+})();\r
+\r
+(function( domObjectProto )\r
+{\r
+       var customData = {};\r
+\r
+       /**\r
+        * Determines whether the specified object is equal to the current object.\r
+        * @name CKEDITOR.dom.domObject.prototype.equals\r
+        * @function\r
+        * @param {Object} object The object to compare with the current object.\r
+        * @returns {Boolean} "true" if the object is equal.\r
+        * @example\r
+        * var doc = new CKEDITOR.dom.document( document );\r
+        * alert( doc.equals( CKEDITOR.document ) );  // "true"\r
+        * alert( doc == CKEDITOR.document );         // "false"\r
+        */\r
+       domObjectProto.equals = function( object )\r
+       {\r
+               return ( object && object.$ === this.$ );\r
+       };\r
+\r
+       /**\r
+        * Sets a data slot value for this object. These values are shared by all\r
+        * instances pointing to that same DOM object.\r
+        * @name CKEDITOR.dom.domObject.prototype.setCustomData\r
+        * @function\r
+        * @param {String} key A key used to identify the data slot.\r
+        * @param {Object} value The value to set to the data slot.\r
+        * @returns {CKEDITOR.dom.domObject} This DOM object instance.\r
+        * @see CKEDITOR.dom.domObject.prototype.getCustomData\r
+        * @example\r
+        * var element = new CKEDITOR.dom.element( 'span' );\r
+        * element.setCustomData( 'hasCustomData', true );\r
+        */\r
+       domObjectProto.setCustomData = function( key, value )\r
+       {\r
+               var expandoNumber = this.getUniqueId(),\r
+                       dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );\r
+\r
+               dataSlot[ key ] = value;\r
+\r
+               return this;\r
+       };\r
+\r
+       /**\r
+        * Gets the value set to a data slot in this object.\r
+        * @name CKEDITOR.dom.domObject.prototype.getCustomData\r
+        * @function\r
+        * @param {String} key The key used to identify the data slot.\r
+        * @returns {Object} This value set to the data slot.\r
+        * @see CKEDITOR.dom.domObject.prototype.setCustomData\r
+        * @example\r
+        * var element = new CKEDITOR.dom.element( 'span' );\r
+        * alert( element.getCustomData( 'hasCustomData' ) );  // e.g. 'true'\r
+        */\r
+       domObjectProto.getCustomData = function( key )\r
+       {\r
+               var expandoNumber = this.$._cke_expando,\r
+                       dataSlot = expandoNumber && customData[ expandoNumber ];\r
+\r
+               return dataSlot && dataSlot[ key ];\r
+       };\r
+\r
+       domObjectProto.removeCustomData = function( key )\r
+       {\r
+               var expandoNumber = this.$._cke_expando,\r
+                       dataSlot = expandoNumber && customData[ expandoNumber ],\r
+                       retval = dataSlot && dataSlot[ key ];\r
+\r
+               if ( typeof retval != 'undefined' )\r
+                       delete dataSlot[ key ];\r
+\r
+               return retval || null;\r
+       };\r
+\r
+       domObjectProto.getUniqueId = function()\r
+       {\r
+               return this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() );\r
+       };\r
+\r
+       // Implement CKEDITOR.event.\r
+       CKEDITOR.event.implementOn( domObjectProto );\r
+\r
+})( CKEDITOR.dom.domObject.prototype );\r