--- /dev/null
+/*\r
+Copyright (c) 2003-2011, 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.$.attachEvent )\r
+ this.$.attachEvent( 'on' + eventName, listener );\r
+ else if ( this.$.addEventListener )\r
+ this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );\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.$.detachEvent )\r
+ this.$.detachEvent( 'on' + eventName, listener );\r
+ else if ( this.$.removeEventListener )\r
+ this.$.removeEventListener( eventName, listener, false );\r
+\r
+ delete nativeListeners[ eventName ];\r
+ }\r
+ }\r
+ },\r
+\r
+ /**\r
+ * Removes any listener set on this object.\r
+ * To avoid memory leaks we must assure that there are no\r
+ * references left after the object is no longer needed.\r
+ */\r
+ removeAllListeners : function()\r
+ {\r
+ var nativeListeners = this.getCustomData( '_cke_nativeListeners' );\r
+ for ( var eventName in nativeListeners )\r
+ {\r
+ var listener = nativeListeners[ eventName ];\r
+ if ( this.$.detachEvent )\r
+ this.$.detachEvent( 'on' + eventName, listener );\r
+ else if ( this.$.removeEventListener )\r
+ this.$.removeEventListener( eventName, listener, false );\r
+\r
+ delete nativeListeners[ eventName ];\r
+ }\r
+ }\r
+ };\r
+})();\r
+\r
+(function( domObjectProto )\r
+{\r
+ var customData = {};\r
+\r
+ CKEDITOR.on( 'reset', function()\r
+ {\r
+ customData = {};\r
+ });\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
+ * <strong>Note:</strong> The created data slot is only guarantied to be available on this unique dom node,\r
+ * thus any wish to continue access it from other element clones (either created by clone node or from innerHtml)\r
+ * will fail, for such usage, please use {@link CKEDITOR.dom.element::setAttribute} instead.\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.$[ 'data-cke-expando' ],\r
+ dataSlot = expandoNumber && customData[ expandoNumber ];\r
+\r
+ return dataSlot && dataSlot[ key ];\r
+ };\r
+\r
+ /**\r
+ * @name CKEDITOR.dom.domObject.prototype.removeCustomData\r
+ */\r
+ domObjectProto.removeCustomData = function( key )\r
+ {\r
+ var expandoNumber = this.$[ 'data-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
+ /**\r
+ * Removes any data stored on this object.\r
+ * To avoid memory leaks we must assure that there are no\r
+ * references left after the object is no longer needed.\r
+ * @name CKEDITOR.dom.domObject.prototype.clearCustomData\r
+ * @function\r
+ */\r
+ domObjectProto.clearCustomData = function()\r
+ {\r
+ // Clear all event listeners\r
+ this.removeAllListeners();\r
+\r
+ var expandoNumber = this.$[ 'data-cke-expando' ];\r
+ expandoNumber && delete customData[ expandoNumber ];\r
+ };\r
+\r
+ /**\r
+ * Gets an ID that can be used to identiquely identify this DOM object in\r
+ * the running session.\r
+ * @name CKEDITOR.dom.domObject.prototype.getUniqueId\r
+ * @function\r
+ * @returns {Number} A unique ID.\r
+ */\r
+ domObjectProto.getUniqueId = function()\r
+ {\r
+ return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR.tools.getNextNumber() );\r
+ };\r
+\r
+ // Implement CKEDITOR.event.\r
+ CKEDITOR.event.implementOn( domObjectProto );\r
+\r
+})( CKEDITOR.dom.domObject.prototype );\r