2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
7 * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base
8 * for other classes representing DOM objects.
12 * Represents a DOM object. This class is not intended to be used directly. It
13 * serves as the base class for other classes representing specific DOM
16 * @param {Object} nativeDomObject A native DOM object.
17 * @augments CKEDITOR.event
20 CKEDITOR
.dom
.domObject = function( nativeDomObject
)
22 if ( nativeDomObject
)
25 * The native DOM object represented by this class instance.
28 * var element = new CKEDITOR.dom.element( 'span' );
29 * alert( element.$.nodeType ); // "1"
31 this.$ = nativeDomObject
;
35 CKEDITOR
.dom
.domObject
.prototype = (function()
37 // Do not define other local variables here. We want to keep the native
38 // listener closures as clean as possible.
40 var getNativeListener = function( domObject
, eventName
)
42 return function( domEvent
)
44 // In FF, when reloading the page with the editor focused, it may
45 // throw an error because the CKEDITOR global is not anymore
46 // available. So, we check it here first. (#2923)
47 if ( typeof CKEDITOR
!= 'undefined' )
48 domObject
.fire( eventName
, new CKEDITOR
.dom
.event( domEvent
) );
52 return /** @lends CKEDITOR.dom.domObject.prototype */ {
54 getPrivate : function()
58 // Get the main private function from the custom data. Create it if not
60 if ( !( priv
= this.getCustomData( '_' ) ) )
61 this.setCustomData( '_', ( priv
= {} ) );
67 on : function( eventName
)
69 // We customize the "on" function here. The basic idea is that we'll have
70 // only one listener for a native event, which will then call all listeners
73 // Get the listeners holder object.
74 var nativeListeners
= this.getCustomData( '_cke_nativeListeners' );
76 if ( !nativeListeners
)
79 this.setCustomData( '_cke_nativeListeners', nativeListeners
);
82 // Check if we have a listener for that event.
83 if ( !nativeListeners
[ eventName
] )
85 var listener
= nativeListeners
[ eventName
] = getNativeListener( this, eventName
);
87 if ( this.$.attachEvent
)
88 this.$.attachEvent( 'on' + eventName
, listener
);
89 else if ( this.$.addEventListener
)
90 this.$.addEventListener( eventName
, listener
, !!CKEDITOR
.event
.useCapture
);
93 // Call the original implementation.
94 return CKEDITOR
.event
.prototype.on
.apply( this, arguments
);
98 removeListener : function( eventName
)
100 // Call the original implementation.
101 CKEDITOR
.event
.prototype.removeListener
.apply( this, arguments
);
103 // If we don't have listeners for this event, clean the DOM up.
104 if ( !this.hasListeners( eventName
) )
106 var nativeListeners
= this.getCustomData( '_cke_nativeListeners' );
107 var listener
= nativeListeners
&& nativeListeners
[ eventName
];
110 if ( this.$.detachEvent
)
111 this.$.detachEvent( 'on' + eventName
, listener
);
112 else if ( this.$.removeEventListener
)
113 this.$.removeEventListener( eventName
, listener
, false );
115 delete nativeListeners
[ eventName
];
121 * Removes any listener set on this object.
122 * To avoid memory leaks we must assure that there are no
123 * references left after the object is no longer needed.
125 removeAllListeners : function()
127 var nativeListeners
= this.getCustomData( '_cke_nativeListeners' );
128 for ( var eventName
in nativeListeners
)
130 var listener
= nativeListeners
[ eventName
];
131 if ( this.$.detachEvent
)
132 this.$.detachEvent( 'on' + eventName
, listener
);
133 else if ( this.$.removeEventListener
)
134 this.$.removeEventListener( eventName
, listener
, false );
136 delete nativeListeners
[ eventName
];
142 (function( domObjectProto
)
146 CKEDITOR
.on( 'reset', function()
152 * Determines whether the specified object is equal to the current object.
153 * @name CKEDITOR.dom.domObject.prototype.equals
155 * @param {Object} object The object to compare with the current object.
156 * @returns {Boolean} "true" if the object is equal.
158 * var doc = new CKEDITOR.dom.document( document );
159 * alert( doc.equals( CKEDITOR.document ) ); // "true"
160 * alert( doc == CKEDITOR.document ); // "false"
162 domObjectProto
.equals = function( object
)
164 return ( object
&& object
.$ === this.$ );
168 * Sets a data slot value for this object. These values are shared by all
169 * instances pointing to that same DOM object.
170 * <strong>Note:</strong> The created data slot is only guarantied to be available on this unique dom node,
171 * thus any wish to continue access it from other element clones (either created by clone node or from innerHtml)
172 * will fail, for such usage, please use {@link CKEDITOR.dom.element::setAttribute} instead.
173 * @name CKEDITOR.dom.domObject.prototype.setCustomData
175 * @param {String} key A key used to identify the data slot.
176 * @param {Object} value The value to set to the data slot.
177 * @returns {CKEDITOR.dom.domObject} This DOM object instance.
178 * @see CKEDITOR.dom.domObject.prototype.getCustomData
180 * var element = new CKEDITOR.dom.element( 'span' );
181 * element.setCustomData( 'hasCustomData', true );
183 domObjectProto
.setCustomData = function( key
, value
)
185 var expandoNumber
= this.getUniqueId(),
186 dataSlot
= customData
[ expandoNumber
] || ( customData
[ expandoNumber
] = {} );
188 dataSlot
[ key
] = value
;
194 * Gets the value set to a data slot in this object.
195 * @name CKEDITOR.dom.domObject.prototype.getCustomData
197 * @param {String} key The key used to identify the data slot.
198 * @returns {Object} This value set to the data slot.
199 * @see CKEDITOR.dom.domObject.prototype.setCustomData
201 * var element = new CKEDITOR.dom.element( 'span' );
202 * alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true'
204 domObjectProto
.getCustomData = function( key
)
206 var expandoNumber
= this.$[ 'data-cke-expando' ],
207 dataSlot
= expandoNumber
&& customData
[ expandoNumber
];
209 return dataSlot
&& dataSlot
[ key
];
213 * @name CKEDITOR.dom.domObject.prototype.removeCustomData
215 domObjectProto
.removeCustomData = function( key
)
217 var expandoNumber
= this.$[ 'data-cke-expando' ],
218 dataSlot
= expandoNumber
&& customData
[ expandoNumber
],
219 retval
= dataSlot
&& dataSlot
[ key
];
221 if ( typeof retval
!= 'undefined' )
222 delete dataSlot
[ key
];
224 return retval
|| null;
228 * Removes any data stored on this object.
229 * To avoid memory leaks we must assure that there are no
230 * references left after the object is no longer needed.
231 * @name CKEDITOR.dom.domObject.prototype.clearCustomData
234 domObjectProto
.clearCustomData = function()
236 // Clear all event listeners
237 this.removeAllListeners();
239 var expandoNumber
= this.$[ 'data-cke-expando' ];
240 expandoNumber
&& delete customData
[ expandoNumber
];
244 * Gets an ID that can be used to identiquely identify this DOM object in
245 * the running session.
246 * @name CKEDITOR.dom.domObject.prototype.getUniqueId
248 * @returns {Number} A unique ID.
250 domObjectProto
.getUniqueId = function()
252 return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR
.tools
.getNextNumber() );
255 // Implement CKEDITOR.event.
256 CKEDITOR
.event
.implementOn( domObjectProto
);
258 })( CKEDITOR
.dom
.domObject
.prototype );