JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.1
[ckeditor.git] / _source / core / dom / domobject.js
1 /*\r
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 /**\r
7  * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base\r
8  *              for other classes representing DOM objects.\r
9  */\r
10 \r
11 /**\r
12  * Represents a DOM object. This class is not intended to be used directly. It\r
13  * serves as the base class for other classes representing specific DOM\r
14  * objects.\r
15  * @constructor\r
16  * @param {Object} nativeDomObject A native DOM object.\r
17  * @augments CKEDITOR.event\r
18  * @example\r
19  */\r
20 CKEDITOR.dom.domObject = function( nativeDomObject )\r
21 {\r
22         if ( nativeDomObject )\r
23         {\r
24                 /**\r
25                  * The native DOM object represented by this class instance.\r
26                  * @type Object\r
27                  * @example\r
28                  * var element = new CKEDITOR.dom.element( 'span' );\r
29                  * alert( element.$.nodeType );  // "1"\r
30                  */\r
31                 this.$ = nativeDomObject;\r
32         }\r
33 };\r
34 \r
35 CKEDITOR.dom.domObject.prototype = (function()\r
36 {\r
37         // Do not define other local variables here. We want to keep the native\r
38         // listener closures as clean as possible.\r
39 \r
40         var getNativeListener = function( domObject, eventName )\r
41         {\r
42                 return function( domEvent )\r
43                 {\r
44                         // In FF, when reloading the page with the editor focused, it may\r
45                         // throw an error because the CKEDITOR global is not anymore\r
46                         // available. So, we check it here first. (#2923)\r
47                         if ( typeof CKEDITOR != 'undefined' )\r
48                                 domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) );\r
49                 };\r
50         };\r
51 \r
52         return /** @lends CKEDITOR.dom.domObject.prototype */ {\r
53 \r
54                 getPrivate : function()\r
55                 {\r
56                         var priv;\r
57 \r
58                         // Get the main private function from the custom data. Create it if not\r
59                         // defined.\r
60                         if ( !( priv = this.getCustomData( '_' ) ) )\r
61                                 this.setCustomData( '_', ( priv = {} ) );\r
62 \r
63                         return priv;\r
64                 },\r
65 \r
66                 /** @ignore */\r
67                 on  : function( eventName )\r
68                 {\r
69                         // We customize the "on" function here. The basic idea is that we'll have\r
70                         // only one listener for a native event, which will then call all listeners\r
71                         // set to the event.\r
72 \r
73                         // Get the listeners holder object.\r
74                         var nativeListeners = this.getCustomData( '_cke_nativeListeners' );\r
75 \r
76                         if ( !nativeListeners )\r
77                         {\r
78                                 nativeListeners = {};\r
79                                 this.setCustomData( '_cke_nativeListeners', nativeListeners );\r
80                         }\r
81 \r
82                         // Check if we have a listener for that event.\r
83                         if ( !nativeListeners[ eventName ] )\r
84                         {\r
85                                 var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName );\r
86 \r
87                                 if ( this.$.addEventListener )\r
88                                         this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );\r
89                                 else if ( this.$.attachEvent )\r
90                                         this.$.attachEvent( 'on' + eventName, listener );\r
91                         }\r
92 \r
93                         // Call the original implementation.\r
94                         return CKEDITOR.event.prototype.on.apply( this, arguments );\r
95                 },\r
96 \r
97                 /** @ignore */\r
98                 removeListener : function( eventName )\r
99                 {\r
100                         // Call the original implementation.\r
101                         CKEDITOR.event.prototype.removeListener.apply( this, arguments );\r
102 \r
103                         // If we don't have listeners for this event, clean the DOM up.\r
104                         if ( !this.hasListeners( eventName ) )\r
105                         {\r
106                                 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );\r
107                                 var listener = nativeListeners && nativeListeners[ eventName ];\r
108                                 if ( listener )\r
109                                 {\r
110                                         if ( this.$.removeEventListener )\r
111                                                 this.$.removeEventListener( eventName, listener, false );\r
112                                         else if ( this.$.detachEvent )\r
113                                                 this.$.detachEvent( 'on' + eventName, listener );\r
114 \r
115                                         delete nativeListeners[ eventName ];\r
116                                 }\r
117                         }\r
118                 }\r
119         };\r
120 })();\r
121 \r
122 (function( domObjectProto )\r
123 {\r
124         var customData = {};\r
125 \r
126         /**\r
127          * Determines whether the specified object is equal to the current object.\r
128          * @name CKEDITOR.dom.domObject.prototype.equals\r
129          * @function\r
130          * @param {Object} object The object to compare with the current object.\r
131          * @returns {Boolean} "true" if the object is equal.\r
132          * @example\r
133          * var doc = new CKEDITOR.dom.document( document );\r
134          * alert( doc.equals( CKEDITOR.document ) );  // "true"\r
135          * alert( doc == CKEDITOR.document );         // "false"\r
136          */\r
137         domObjectProto.equals = function( object )\r
138         {\r
139                 return ( object && object.$ === this.$ );\r
140         };\r
141 \r
142         /**\r
143          * Sets a data slot value for this object. These values are shared by all\r
144          * instances pointing to that same DOM object.\r
145          * @name CKEDITOR.dom.domObject.prototype.setCustomData\r
146          * @function\r
147          * @param {String} key A key used to identify the data slot.\r
148          * @param {Object} value The value to set to the data slot.\r
149          * @returns {CKEDITOR.dom.domObject} This DOM object instance.\r
150          * @see CKEDITOR.dom.domObject.prototype.getCustomData\r
151          * @example\r
152          * var element = new CKEDITOR.dom.element( 'span' );\r
153          * element.setCustomData( 'hasCustomData', true );\r
154          */\r
155         domObjectProto.setCustomData = function( key, value )\r
156         {\r
157                 var expandoNumber = this.getUniqueId(),\r
158                         dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );\r
159 \r
160                 dataSlot[ key ] = value;\r
161 \r
162                 return this;\r
163         };\r
164 \r
165         /**\r
166          * Gets the value set to a data slot in this object.\r
167          * @name CKEDITOR.dom.domObject.prototype.getCustomData\r
168          * @function\r
169          * @param {String} key The key used to identify the data slot.\r
170          * @returns {Object} This value set to the data slot.\r
171          * @see CKEDITOR.dom.domObject.prototype.setCustomData\r
172          * @example\r
173          * var element = new CKEDITOR.dom.element( 'span' );\r
174          * alert( element.getCustomData( 'hasCustomData' ) );  // e.g. 'true'\r
175          */\r
176         domObjectProto.getCustomData = function( key )\r
177         {\r
178                 var expandoNumber = this.$._cke_expando,\r
179                         dataSlot = expandoNumber && customData[ expandoNumber ];\r
180 \r
181                 return dataSlot && dataSlot[ key ];\r
182         };\r
183 \r
184         domObjectProto.removeCustomData = function( key )\r
185         {\r
186                 var expandoNumber = this.$._cke_expando,\r
187                         dataSlot = expandoNumber && customData[ expandoNumber ],\r
188                         retval = dataSlot && dataSlot[ key ];\r
189 \r
190                 if ( typeof retval != 'undefined' )\r
191                         delete dataSlot[ key ];\r
192 \r
193                 return retval || null;\r
194         };\r
195 \r
196         domObjectProto.getUniqueId = function()\r
197         {\r
198                 return this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() );\r
199         };\r
200 \r
201         // Implement CKEDITOR.event.\r
202         CKEDITOR.event.implementOn( domObjectProto );\r
203 \r
204 })( CKEDITOR.dom.domObject.prototype );\r