]> git.immae.eu Git - perso/Immae/Projets/packagist/ludivine-ckeditor-component.git/blob - sources/core/dom/domobject.js
Update to 4.7.3
[perso/Immae/Projets/packagist/ludivine-ckeditor-component.git] / sources / core / dom / domobject.js
1 /**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 /**
7 * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base
8 * for other classes representing DOM objects.
9 */
10
11 /**
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
14 * objects.
15 *
16 * @class
17 * @mixins CKEDITOR.event
18 * @constructor Creates a domObject class instance.
19 * @param {Object} nativeDomObject A native DOM object.
20 */
21 CKEDITOR.dom.domObject = function( nativeDomObject ) {
22 if ( nativeDomObject ) {
23 /**
24 * The native DOM object represented by this class instance.
25 *
26 * var element = new CKEDITOR.dom.element( 'span' );
27 * alert( element.$.nodeType ); // '1'
28 *
29 * @readonly
30 * @property {Object}
31 */
32 this.$ = nativeDomObject;
33 }
34 };
35
36 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.
39
40 var getNativeListener = function( domObject, eventName ) {
41 return function( domEvent ) {
42 // In FF, when reloading the page with the editor focused, it may
43 // throw an error because the CKEDITOR global is not anymore
44 // available. So, we check it here first. (http://dev.ckeditor.com/ticket/2923)
45 if ( typeof CKEDITOR != 'undefined' )
46 domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) );
47 };
48 };
49
50 return {
51
52 /**
53 * Gets the private `_` object which is bound to the native
54 * DOM object using {@link #getCustomData}.
55 *
56 * var elementA = new CKEDITOR.dom.element( nativeElement );
57 * elementA.getPrivate().value = 1;
58 * ...
59 * var elementB = new CKEDITOR.dom.element( nativeElement );
60 * elementB.getPrivate().value; // 1
61 *
62 * @returns {Object} The private object.
63 */
64 getPrivate: function() {
65 var priv;
66
67 // Get the main private object from the custom data. Create it if not defined.
68 if ( !( priv = this.getCustomData( '_' ) ) )
69 this.setCustomData( '_', ( priv = {} ) );
70
71 return priv;
72 },
73
74 // Docs inherited from event.
75 on: function( eventName ) {
76 // We customize the "on" function here. The basic idea is that we'll have
77 // only one listener for a native event, which will then call all listeners
78 // set to the event.
79
80 // Get the listeners holder object.
81 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
82
83 if ( !nativeListeners ) {
84 nativeListeners = {};
85 this.setCustomData( '_cke_nativeListeners', nativeListeners );
86 }
87
88 // Check if we have a listener for that event.
89 if ( !nativeListeners[ eventName ] ) {
90 var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName );
91
92 if ( this.$.addEventListener )
93 this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );
94 else if ( this.$.attachEvent )
95 this.$.attachEvent( 'on' + eventName, listener );
96 }
97
98 // Call the original implementation.
99 return CKEDITOR.event.prototype.on.apply( this, arguments );
100 },
101
102 // Docs inherited from event.
103 removeListener: function( eventName ) {
104 // Call the original implementation.
105 CKEDITOR.event.prototype.removeListener.apply( this, arguments );
106
107 // If we don't have listeners for this event, clean the DOM up.
108 if ( !this.hasListeners( eventName ) ) {
109 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
110 var listener = nativeListeners && nativeListeners[ eventName ];
111 if ( listener ) {
112 if ( this.$.removeEventListener )
113 this.$.removeEventListener( eventName, listener, false );
114 else if ( this.$.detachEvent )
115 this.$.detachEvent( 'on' + eventName, listener );
116
117 delete nativeListeners[ eventName ];
118 }
119 }
120 },
121
122 /**
123 * Removes any listener set on this object.
124 *
125 * To avoid memory leaks we must assure that there are no
126 * references left after the object is no longer needed.
127 */
128 removeAllListeners: function() {
129 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
130 for ( var eventName in nativeListeners ) {
131 var listener = nativeListeners[ eventName ];
132 if ( this.$.detachEvent )
133 this.$.detachEvent( 'on' + eventName, listener );
134 else if ( this.$.removeEventListener )
135 this.$.removeEventListener( eventName, listener, false );
136
137 delete nativeListeners[ eventName ];
138 }
139
140 // Remove events from events object so fire() method will not call
141 // listeners (http://dev.ckeditor.com/ticket/11400).
142 CKEDITOR.event.prototype.removeAllListeners.call( this );
143 }
144 };
145 } )();
146
147 ( function( domObjectProto ) {
148 var customData = {};
149
150 CKEDITOR.on( 'reset', function() {
151 customData = {};
152 } );
153
154 /**
155 * Determines whether the specified object is equal to the current object.
156 *
157 * var doc = new CKEDITOR.dom.document( document );
158 * alert( doc.equals( CKEDITOR.document ) ); // true
159 * alert( doc == CKEDITOR.document ); // false
160 *
161 * @param {Object} object The object to compare with the current object.
162 * @returns {Boolean} `true` if the object is equal.
163 */
164 domObjectProto.equals = function( object ) {
165 // Try/Catch to avoid IE permission error when object is from different document.
166 try {
167 return ( object && object.$ === this.$ );
168 } catch ( er ) {
169 return false;
170 }
171 };
172
173 /**
174 * Sets a data slot value for this object. These values are shared by all
175 * instances pointing to that same DOM object.
176 *
177 * **Note:** The created data slot is only guaranteed to be available on this unique DOM node,
178 * thus any wish to continue access to it from other element clones (either created by
179 * clone node or from `innerHtml`) will fail. For such usage please use
180 * {@link CKEDITOR.dom.element#setAttribute} instead.
181 *
182 * **Note**: This method does not work on text nodes prior to Internet Explorer 9.
183 *
184 * var element = new CKEDITOR.dom.element( 'span' );
185 * element.setCustomData( 'hasCustomData', true );
186 *
187 * @param {String} key A key used to identify the data slot.
188 * @param {Object} value The value to set to the data slot.
189 * @returns {CKEDITOR.dom.domObject} This DOM object instance.
190 * @chainable
191 */
192 domObjectProto.setCustomData = function( key, value ) {
193 var expandoNumber = this.getUniqueId(),
194 dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );
195
196 dataSlot[ key ] = value;
197
198 return this;
199 };
200
201 /**
202 * Gets the value set to a data slot in this object.
203 *
204 * var element = new CKEDITOR.dom.element( 'span' );
205 * alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true'
206 * alert( element.getCustomData( 'nonExistingKey' ) ); // null
207 *
208 * @param {String} key The key used to identify the data slot.
209 * @returns {Object} This value set to the data slot.
210 */
211 domObjectProto.getCustomData = function( key ) {
212 var expandoNumber = this.$[ 'data-cke-expando' ],
213 dataSlot = expandoNumber && customData[ expandoNumber ];
214
215 return ( dataSlot && key in dataSlot ) ? dataSlot[ key ] : null;
216 };
217
218 /**
219 * Removes the value in the data slot under the given `key`.
220 *
221 * @param {String} key
222 * @returns {Object} Removed value or `null` if not found.
223 */
224 domObjectProto.removeCustomData = function( key ) {
225 var expandoNumber = this.$[ 'data-cke-expando' ],
226 dataSlot = expandoNumber && customData[ expandoNumber ],
227 retval, hadKey;
228
229 if ( dataSlot ) {
230 retval = dataSlot[ key ];
231 hadKey = key in dataSlot;
232 delete dataSlot[ key ];
233 }
234
235 return hadKey ? retval : null;
236 };
237
238 /**
239 * Removes any data stored in this object.
240 * To avoid memory leaks we must assure that there are no
241 * references left after the object is no longer needed.
242 */
243 domObjectProto.clearCustomData = function() {
244 // Clear all event listeners
245 this.removeAllListeners();
246
247 var expandoNumber = this.$[ 'data-cke-expando' ];
248 expandoNumber && delete customData[ expandoNumber ];
249 };
250
251 /**
252 * Gets an ID that can be used to identify this DOM object in
253 * the running session.
254 *
255 * **Note**: This method does not work on text nodes prior to Internet Explorer 9.
256 *
257 * @returns {Number} A unique ID.
258 */
259 domObjectProto.getUniqueId = function() {
260 return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR.tools.getNextNumber() );
261 };
262
263 // Implement CKEDITOR.event.
264 CKEDITOR.event.implementOn( domObjectProto );
265
266 } )( CKEDITOR.dom.domObject.prototype );