1 /* 2 * CKEditor - The text editor for Internet - http://ckeditor.com 3 * Copyright (C) 2003-2008 Frederico Caldeira Knabben 4 * 5 * == BEGIN LICENSE == 6 * 7 * Licensed under the terms of any of the following licenses at your 8 * choice: 9 * 10 * - GNU General Public License Version 2 or later (the "GPL") 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 14 * http://www.gnu.org/licenses/lgpl.html 15 * 16 * - Mozilla Public License Version 1.1 or later (the "MPL") 17 * http://www.mozilla.org/MPL/MPL-1.1.html 18 * 19 * == END LICENSE == 20 */ 21 22 /** 23 * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base 24 * for other classes representing DOM objects. 25 */ 26 27 /** 28 * Represents a DOM object. This class is not intended to be used directly. It 29 * serves as the base class for other classes representing specific DOM 30 * objects. 31 * @constructor 32 * @param {Object} nativeDomObject A native DOM object. 33 * @augments CKEDITOR.event 34 * @example 35 */ 36 CKEDITOR.dom.domObject = function( nativeDomObject ) 37 { 38 if ( nativeDomObject ) 39 { 40 /** 41 * The native DOM object represented by this class instance. 42 * @type Object 43 * @example 44 * var element = new CKEDITOR.dom.element( 'span' ); 45 * alert( element.$.nodeType ); // "1" 46 */ 47 this.$ = nativeDomObject; 48 49 // Get the main private function from the custom data. Create it if not 50 // defined. 51 if ( !( this._ = this.getCustomData( '_' ) ) ) 52 this.setCustomData( '_', ( this._ = {} ) ); 53 54 // Call the base event constructor. 55 CKEDITOR.event.call( this ); 56 } 57 }; 58 59 CKEDITOR.dom.domObject.prototype = (function() 60 { 61 // Do not define other local variables here. We want to keep the native 62 // listener closures as clean as possible. 63 64 var getNativeListener = function( domObject, eventName ) 65 { 66 return function( domEvent ) 67 { 68 domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) ); 69 }; 70 }; 71 72 return /** @lends CKEDITOR.dom.domObject.prototype */ { 73 74 /** @ignore */ 75 on : function( eventName ) 76 { 77 // We customize the "on" function here. The basic idea is that we'll have 78 // only one listener for a native event, which will then call all listeners 79 // set to the event. 80 81 // Get the listeners holder object. 82 var nativeListeners = this.getCustomData( '_cke_nativeListeners' ) || this.setCustomData( '_cke_nativeListeners', {} ); 83 84 // Check if we have a listener for that event. 85 if ( !nativeListeners[ eventName ] ) 86 { 87 var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName ); 88 89 if ( this.$.addEventListener ) 90 this.$.addEventListener( eventName, listener, false ); 91 else if ( this.$.attachEvent ) 92 this.$.attachEvent( 'on' + eventName, listener ); 93 } 94 95 // Call the original implementation. 96 return CKEDITOR.event.prototype.on.apply( this, arguments ); 97 }, 98 99 /** @ignore */ 100 removeListener : function( eventName ) 101 { 102 // Call the original implementation. 103 CKEDITOR.event.prototype.fire.removeListener.apply( this, arguments ); 104 105 // If we don't have listeners for this event, clean the DOM up. 106 if ( !this.hasListeners( eventName ) ) 107 { 108 var nativeListeners = this.getCustomData( '_cke_nativeListeners' ); 109 var listener = nativeListeners && nativeListeners[ eventName ]; 110 if ( listener ) 111 { 112 if ( this.$.removeEventListener ) 113 this.$.removeEventListener( eventName, listener ); 114 else if ( this.$.dettachEvent ) 115 this.$.dettachEvent( eventName, listener ); 116 117 delete nativeListeners[ eventName ]; 118 } 119 } 120 } 121 }; 122 })(); 123 124 (function( domObjectProto ) 125 { 126 var customData = {}; 127 128 /** 129 * Determines whether the specified object is equal to the current object. 130 * @name CKEDITOR.dom.domObject.prototype.equals 131 * @function 132 * @param {Object} object The object to compare with the current object. 133 * @returns {Boolean} "true" if the object is equal. 134 * @example 135 * var doc = new CKEDITOR.dom.document( document ); 136 * alert( doc.equals( CKEDITOR.document ) ); // "true" 137 * alert( doc == CKEDITOR.document ); // "false" 138 */ 139 domObjectProto.equals = function( object ) 140 { 141 return ( object && object.$ === this.$ ); 142 }, 143 144 /** 145 * Sets a data slot value for this object. These values are shared by all 146 * instances pointing to that same DOM object. 147 * @name CKEDITOR.dom.domObject.prototype.setCustomData 148 * @function 149 * @param {String} key A key used to identify the data slot. 150 * @param {Object} value The value to set to the data slot. 151 * @returns {CKEDITOR.dom.domObject} This DOM object instance. 152 * @see CKEDITOR.dom.domObject.prototype.getCustomData 153 * @example 154 * var element = new CKEDITOR.dom.element( 'span' ); 155 * element.setCustomData( 'hasCustomData', true ); 156 */ 157 domObjectProto.setCustomData = function( key, value ) 158 { 159 var expandoNumber = this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() ), 160 dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} ); 161 162 dataSlot[ key ] = value; 163 164 return this; 165 }; 166 167 /** 168 * Gets the value set to a data slot in this object. 169 * @name CKEDITOR.dom.domObject.prototype.getCustomData 170 * @function 171 * @param {String} key The key used to identify the data slot. 172 * @returns {Object} This value set to the data slot. 173 * @see CKEDITOR.dom.domObject.prototype.setCustomData 174 * @example 175 * var element = new CKEDITOR.dom.element( 'span' ); 176 * alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true' 177 */ 178 domObjectProto.getCustomData = function( key ) 179 { 180 var expandoNumber = this.$._cke_expando, 181 dataSlot = expandoNumber && customData[ expandoNumber ]; 182 183 return ( dataSlot && dataSlot[ key ] ) || null; 184 }; 185 186 // Implement CKEDITOR.event. 187 CKEDITOR.event.implementOn( domObjectProto ); 188 189 })( CKEDITOR.dom.domObject.prototype ); 190