From 7adcb81e4f83f98c468889aaa5a85558ba88c770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Mon, 25 Jan 2016 17:45:33 +0100 Subject: Initial commit --- sources/core/dom/domobject.js | 266 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 sources/core/dom/domobject.js (limited to 'sources/core/dom/domobject.js') diff --git a/sources/core/dom/domobject.js b/sources/core/dom/domobject.js new file mode 100644 index 00000000..21a351d7 --- /dev/null +++ b/sources/core/dom/domobject.js @@ -0,0 +1,266 @@ +/** + * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or http://ckeditor.com/license + */ + +/** + * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base + * for other classes representing DOM objects. + */ + +/** + * Represents a DOM object. This class is not intended to be used directly. It + * serves as the base class for other classes representing specific DOM + * objects. + * + * @class + * @mixins CKEDITOR.event + * @constructor Creates a domObject class instance. + * @param {Object} nativeDomObject A native DOM object. + */ +CKEDITOR.dom.domObject = function( nativeDomObject ) { + if ( nativeDomObject ) { + /** + * The native DOM object represented by this class instance. + * + * var element = new CKEDITOR.dom.element( 'span' ); + * alert( element.$.nodeType ); // '1' + * + * @readonly + * @property {Object} + */ + this.$ = nativeDomObject; + } +}; + +CKEDITOR.dom.domObject.prototype = ( function() { + // Do not define other local variables here. We want to keep the native + // listener closures as clean as possible. + + var getNativeListener = function( domObject, eventName ) { + return function( domEvent ) { + // In FF, when reloading the page with the editor focused, it may + // throw an error because the CKEDITOR global is not anymore + // available. So, we check it here first. (#2923) + if ( typeof CKEDITOR != 'undefined' ) + domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) ); + }; + }; + + return { + + /** + * Gets the private `_` object which is bound to the native + * DOM object using {@link #getCustomData}. + * + * var elementA = new CKEDITOR.dom.element( nativeElement ); + * elementA.getPrivate().value = 1; + * ... + * var elementB = new CKEDITOR.dom.element( nativeElement ); + * elementB.getPrivate().value; // 1 + * + * @returns {Object} The private object. + */ + getPrivate: function() { + var priv; + + // Get the main private object from the custom data. Create it if not defined. + if ( !( priv = this.getCustomData( '_' ) ) ) + this.setCustomData( '_', ( priv = {} ) ); + + return priv; + }, + + // Docs inherited from event. + on: function( eventName ) { + // We customize the "on" function here. The basic idea is that we'll have + // only one listener for a native event, which will then call all listeners + // set to the event. + + // Get the listeners holder object. + var nativeListeners = this.getCustomData( '_cke_nativeListeners' ); + + if ( !nativeListeners ) { + nativeListeners = {}; + this.setCustomData( '_cke_nativeListeners', nativeListeners ); + } + + // Check if we have a listener for that event. + if ( !nativeListeners[ eventName ] ) { + var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName ); + + if ( this.$.addEventListener ) + this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture ); + else if ( this.$.attachEvent ) + this.$.attachEvent( 'on' + eventName, listener ); + } + + // Call the original implementation. + return CKEDITOR.event.prototype.on.apply( this, arguments ); + }, + + // Docs inherited from event. + removeListener: function( eventName ) { + // Call the original implementation. + CKEDITOR.event.prototype.removeListener.apply( this, arguments ); + + // If we don't have listeners for this event, clean the DOM up. + if ( !this.hasListeners( eventName ) ) { + var nativeListeners = this.getCustomData( '_cke_nativeListeners' ); + var listener = nativeListeners && nativeListeners[ eventName ]; + if ( listener ) { + if ( this.$.removeEventListener ) + this.$.removeEventListener( eventName, listener, false ); + else if ( this.$.detachEvent ) + this.$.detachEvent( 'on' + eventName, listener ); + + delete nativeListeners[ eventName ]; + } + } + }, + + /** + * Removes any listener set on this object. + * + * To avoid memory leaks we must assure that there are no + * references left after the object is no longer needed. + */ + removeAllListeners: function() { + var nativeListeners = this.getCustomData( '_cke_nativeListeners' ); + for ( var eventName in nativeListeners ) { + var listener = nativeListeners[ eventName ]; + if ( this.$.detachEvent ) + this.$.detachEvent( 'on' + eventName, listener ); + else if ( this.$.removeEventListener ) + this.$.removeEventListener( eventName, listener, false ); + + delete nativeListeners[ eventName ]; + } + + // Remove events from events object so fire() method will not call + // listeners (#11400). + CKEDITOR.event.prototype.removeAllListeners.call( this ); + } + }; +} )(); + +( function( domObjectProto ) { + var customData = {}; + + CKEDITOR.on( 'reset', function() { + customData = {}; + } ); + + /** + * Determines whether the specified object is equal to the current object. + * + * var doc = new CKEDITOR.dom.document( document ); + * alert( doc.equals( CKEDITOR.document ) ); // true + * alert( doc == CKEDITOR.document ); // false + * + * @param {Object} object The object to compare with the current object. + * @returns {Boolean} `true` if the object is equal. + */ + domObjectProto.equals = function( object ) { + // Try/Catch to avoid IE permission error when object is from different document. + try { + return ( object && object.$ === this.$ ); + } catch ( er ) { + return false; + } + }; + + /** + * Sets a data slot value for this object. These values are shared by all + * instances pointing to that same DOM object. + * + * **Note:** The created data slot is only guaranteed to be available on this unique DOM node, + * thus any wish to continue access to it from other element clones (either created by + * clone node or from `innerHtml`) will fail. For such usage please use + * {@link CKEDITOR.dom.element#setAttribute} instead. + * + * **Note**: This method does not work on text nodes prior to Internet Explorer 9. + * + * var element = new CKEDITOR.dom.element( 'span' ); + * element.setCustomData( 'hasCustomData', true ); + * + * @param {String} key A key used to identify the data slot. + * @param {Object} value The value to set to the data slot. + * @returns {CKEDITOR.dom.domObject} This DOM object instance. + * @chainable + */ + domObjectProto.setCustomData = function( key, value ) { + var expandoNumber = this.getUniqueId(), + dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} ); + + dataSlot[ key ] = value; + + return this; + }; + + /** + * Gets the value set to a data slot in this object. + * + * var element = new CKEDITOR.dom.element( 'span' ); + * alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true' + * alert( element.getCustomData( 'nonExistingKey' ) ); // null + * + * @param {String} key The key used to identify the data slot. + * @returns {Object} This value set to the data slot. + */ + domObjectProto.getCustomData = function( key ) { + var expandoNumber = this.$[ 'data-cke-expando' ], + dataSlot = expandoNumber && customData[ expandoNumber ]; + + return ( dataSlot && key in dataSlot ) ? dataSlot[ key ] : null; + }; + + /** + * Removes the value in the data slot under the given `key`. + * + * @param {String} key + * @returns {Object} Removed value or `null` if not found. + */ + domObjectProto.removeCustomData = function( key ) { + var expandoNumber = this.$[ 'data-cke-expando' ], + dataSlot = expandoNumber && customData[ expandoNumber ], + retval, hadKey; + + if ( dataSlot ) { + retval = dataSlot[ key ]; + hadKey = key in dataSlot; + delete dataSlot[ key ]; + } + + return hadKey ? retval : null; + }; + + /** + * Removes any data stored in this object. + * To avoid memory leaks we must assure that there are no + * references left after the object is no longer needed. + */ + domObjectProto.clearCustomData = function() { + // Clear all event listeners + this.removeAllListeners(); + + var expandoNumber = this.$[ 'data-cke-expando' ]; + expandoNumber && delete customData[ expandoNumber ]; + }; + + /** + * Gets an ID that can be used to identify this DOM object in + * the running session. + * + * **Note**: This method does not work on text nodes prior to Internet Explorer 9. + * + * @returns {Number} A unique ID. + */ + domObjectProto.getUniqueId = function() { + return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR.tools.getNextNumber() ); + }; + + // Implement CKEDITOR.event. + CKEDITOR.event.implementOn( domObjectProto ); + +} )( CKEDITOR.dom.domObject.prototype ); -- cgit v1.2.3