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 // Call the base event constructor. 41 CKEDITOR.event.call( this ); 42 43 /** 44 * The native DOM object represented by this class instance. 45 * @type Object 46 * @example 47 * var element = new CKEDITOR.dom.element( 'span' ); 48 * alert( element.$.nodeType ); // "1" 49 */ 50 this.$ = nativeDomObject; 51 } 52 }; 53 54 CKEDITOR.dom.domObject.prototype = (function() 55 { 56 // Do not define other local variables here. We want to keep the native 57 // listener closures as clean as possible. 58 59 var getNativeListener = function( domObject, eventName ) 60 { 61 return function( domEvent ) 62 { 63 domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) ); 64 }; 65 }; 66 67 return /** @lends CKEDITOR.dom.domObject.prototype */ { 68 69 /** @ignore */ 70 on : function( eventName ) 71 { 72 // We customize the "on" function here. The basic idea is that we'll have 73 // only one listener for a native event, which will then call all listeners 74 // set to the event. 75 76 // Get the listeners holder object. 77 var nativeListeners = this.getCustomData( '_cke_nativeListeners' ) || this.setCustomData( '_cke_nativeListeners', {} ); 78 79 // Check if we have a listener for that event. 80 if ( !nativeListeners[ eventName ] ) 81 { 82 var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName ); 83 84 if ( this.$.addEventListener ) 85 this.$.addEventListener( eventName, listener, false ); 86 else if ( this.$.attachEvent ) 87 this.$.attachEvent( 'on' + eventName, listener ); 88 } 89 90 // Call the original implementation. 91 return CKEDITOR.event.prototype.on.apply( this, arguments ); 92 }, 93 94 /** @ignore */ 95 removeListener : function( eventName ) 96 { 97 // Call the original implementation. 98 CKEDITOR.event.prototype.fire.removeListener.apply( this, arguments ); 99 100 // If we don't have listeners for this event, clean the DOM up. 101 if ( !this.hasListeners( eventName ) ) 102 { 103 var nativeListeners = this.getCustomData( '_cke_nativeListeners' ); 104 var listener = nativeListeners && nativeListeners[ eventName ]; 105 if ( listener ) 106 { 107 if ( this.$.removeEventListener ) 108 this.$.removeEventListener( eventName, listener ); 109 else if ( this.$.dettachEvent ) 110 this.$.dettachEvent( eventName, listener ); 111 112 delete nativeListeners[ eventName ]; 113 } 114 } 115 } 116 }; 117 })(); 118 119 (function( domObjectProto ) 120 { 121 var customData = {}; 122 123 /** 124 * Sets a data slot value for this object. These values are shared by all 125 * instances pointing to that same DOM object. 126 * @name CKEDITOR.dom.domObject.prototype.setCustomData 127 * @param {String} key A key used to identify the data slot. 128 * @param {Object} value The value to set to the data slot. 129 * @returns {CKEDITOR.dom.domObject} This DOM object instance. 130 * @see CKEDITOR.dom.domObject.prototype.getCustomData 131 * @example 132 * var element = new CKEDITOR.dom.element( 'span' ); 133 * element.setCustomData( 'hasCustomData', true ); 134 */ 135 domObjectProto.setCustomData = function( key, value ) 136 { 137 var expandoNumber = this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() ), 138 dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} ); 139 140 dataSlot[ key ] = value; 141 142 return this; 143 }; 144 145 /** 146 * Gets the value set to a data slot in this object. 147 * @name CKEDITOR.dom.domObject.prototype.getCustomData 148 * @param {String} key The key used to identify the data slot. 149 * @returns {Object} This value set to the data slot. 150 * @see CKEDITOR.dom.domObject.prototype.setCustomData 151 * @example 152 * var element = new CKEDITOR.dom.element( 'span' ); 153 * alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true' 154 */ 155 domObjectProto.getCustomData = function( key ) 156 { 157 var expandoNumber = this.$._cke_expando, 158 dataSlot = expandoNumber && customData[ expandoNumber ]; 159 160 return ( dataSlot && dataSlot[ key ] ) || null; 161 }; 162 163 // Implement CKEDITOR.event. 164 CKEDITOR.event.implementOn( domObjectProto ); 165 166 })( CKEDITOR.dom.domObject.prototype ); 167