Datenstand V1.0
This commit is contained in:
32
ckeditor/_source/core/dom/comment.js
Normal file
32
ckeditor/_source/core/dom/comment.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Defines the {@link CKEDITOR.dom.comment} class, which represents
|
||||
* a DOM comment node.
|
||||
*/
|
||||
|
||||
CKEDITOR.dom.comment = CKEDITOR.tools.createClass(
|
||||
{
|
||||
base : CKEDITOR.dom.node,
|
||||
|
||||
$ : function( text, ownerDocument )
|
||||
{
|
||||
if ( typeof text == 'string' )
|
||||
text = ( ownerDocument ? ownerDocument.$ : document ).createComment( text );
|
||||
|
||||
this.base( text );
|
||||
},
|
||||
|
||||
proto :
|
||||
{
|
||||
type : CKEDITOR.NODE_COMMENT,
|
||||
|
||||
getOuterHtml : function()
|
||||
{
|
||||
return '<!--' + this.$.nodeValue + '-->';
|
||||
}
|
||||
}
|
||||
});
|
||||
224
ckeditor/_source/core/dom/document.js
Normal file
224
ckeditor/_source/core/dom/document.js
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Defines the {@link CKEDITOR.dom.document} class, which
|
||||
* represents a DOM document.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a DOM document.
|
||||
* @constructor
|
||||
* @augments CKEDITOR.dom.domObject
|
||||
* @param {Object} domDocument A native DOM document.
|
||||
* @example
|
||||
* var document = new CKEDITOR.dom.document( document );
|
||||
*/
|
||||
CKEDITOR.dom.document = function( domDocument )
|
||||
{
|
||||
CKEDITOR.dom.domObject.call( this, domDocument );
|
||||
};
|
||||
|
||||
// PACKAGER_RENAME( CKEDITOR.dom.document )
|
||||
|
||||
CKEDITOR.dom.document.prototype = new CKEDITOR.dom.domObject();
|
||||
|
||||
CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype,
|
||||
/** @lends CKEDITOR.dom.document.prototype */
|
||||
{
|
||||
/**
|
||||
* Appends a CSS file to the document.
|
||||
* @param {String} cssFileUrl The CSS file URL.
|
||||
* @example
|
||||
* <b>CKEDITOR.document.appendStyleSheet( '/mystyles.css' )</b>;
|
||||
*/
|
||||
appendStyleSheet : function( cssFileUrl )
|
||||
{
|
||||
if ( this.$.createStyleSheet )
|
||||
this.$.createStyleSheet( cssFileUrl );
|
||||
else
|
||||
{
|
||||
var link = new CKEDITOR.dom.element( 'link' );
|
||||
link.setAttributes(
|
||||
{
|
||||
rel :'stylesheet',
|
||||
type : 'text/css',
|
||||
href : cssFileUrl
|
||||
});
|
||||
|
||||
this.getHead().append( link );
|
||||
}
|
||||
},
|
||||
|
||||
appendStyleText : function( cssStyleText )
|
||||
{
|
||||
if ( this.$.createStyleSheet )
|
||||
{
|
||||
var styleSheet = this.$.createStyleSheet( "" );
|
||||
styleSheet.cssText = cssStyleText ;
|
||||
}
|
||||
else
|
||||
{
|
||||
var style = new CKEDITOR.dom.element( 'style', this );
|
||||
style.append( new CKEDITOR.dom.text( cssStyleText, this ) );
|
||||
this.getHead().append( style );
|
||||
}
|
||||
},
|
||||
|
||||
createElement : function( name, attribsAndStyles )
|
||||
{
|
||||
var element = new CKEDITOR.dom.element( name, this );
|
||||
|
||||
if ( attribsAndStyles )
|
||||
{
|
||||
if ( attribsAndStyles.attributes )
|
||||
element.setAttributes( attribsAndStyles.attributes );
|
||||
|
||||
if ( attribsAndStyles.styles )
|
||||
element.setStyles( attribsAndStyles.styles );
|
||||
}
|
||||
|
||||
return element;
|
||||
},
|
||||
|
||||
createText : function( text )
|
||||
{
|
||||
return new CKEDITOR.dom.text( text, this );
|
||||
},
|
||||
|
||||
focus : function()
|
||||
{
|
||||
this.getWindow().focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets and element based on its id.
|
||||
* @param {String} elementId The element id.
|
||||
* @returns {CKEDITOR.dom.element} The element instance, or null if not found.
|
||||
* @example
|
||||
* var element = <b>CKEDITOR.document.getById( 'myElement' )</b>;
|
||||
* alert( element.getId() ); // "myElement"
|
||||
*/
|
||||
getById : function( elementId )
|
||||
{
|
||||
var $ = this.$.getElementById( elementId );
|
||||
return $ ? new CKEDITOR.dom.element( $ ) : null;
|
||||
},
|
||||
|
||||
getByAddress : function( address, normalized )
|
||||
{
|
||||
var $ = this.$.documentElement;
|
||||
|
||||
for ( var i = 0 ; $ && i < address.length ; i++ )
|
||||
{
|
||||
var target = address[ i ];
|
||||
|
||||
if ( !normalized )
|
||||
{
|
||||
$ = $.childNodes[ target ];
|
||||
continue;
|
||||
}
|
||||
|
||||
var currentIndex = -1;
|
||||
|
||||
for (var j = 0 ; j < $.childNodes.length ; j++ )
|
||||
{
|
||||
var candidate = $.childNodes[ j ];
|
||||
|
||||
if ( normalized === true &&
|
||||
candidate.nodeType == 3 &&
|
||||
candidate.previousSibling &&
|
||||
candidate.previousSibling.nodeType == 3 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
|
||||
if ( currentIndex == target )
|
||||
{
|
||||
$ = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ ? new CKEDITOR.dom.node( $ ) : null;
|
||||
},
|
||||
|
||||
getElementsByTag : function( tagName, namespace )
|
||||
{
|
||||
if ( !CKEDITOR.env.ie && namespace )
|
||||
tagName = namespace + ':' + tagName;
|
||||
return new CKEDITOR.dom.nodeList( this.$.getElementsByTagName( tagName ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the <head> element for this document.
|
||||
* @returns {CKEDITOR.dom.element} The <head> element.
|
||||
* @example
|
||||
* var element = <b>CKEDITOR.document.getHead()</b>;
|
||||
* alert( element.getName() ); // "head"
|
||||
*/
|
||||
getHead : function()
|
||||
{
|
||||
var head = this.$.getElementsByTagName( 'head' )[0];
|
||||
head = new CKEDITOR.dom.element( head );
|
||||
|
||||
return (
|
||||
this.getHead = function()
|
||||
{
|
||||
return head;
|
||||
})();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the <body> element for this document.
|
||||
* @returns {CKEDITOR.dom.element} The <body> element.
|
||||
* @example
|
||||
* var element = <b>CKEDITOR.document.getBody()</b>;
|
||||
* alert( element.getName() ); // "body"
|
||||
*/
|
||||
getBody : function()
|
||||
{
|
||||
var body = new CKEDITOR.dom.element( this.$.body );
|
||||
|
||||
return (
|
||||
this.getBody = function()
|
||||
{
|
||||
return body;
|
||||
})();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the DOM document element for this document.
|
||||
* @returns {CKEDITOR.dom.element} The DOM document element.
|
||||
*/
|
||||
getDocumentElement : function()
|
||||
{
|
||||
var documentElement = new CKEDITOR.dom.element( this.$.documentElement );
|
||||
|
||||
return (
|
||||
this.getDocumentElement = function()
|
||||
{
|
||||
return documentElement;
|
||||
})();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the window object that holds this document.
|
||||
* @returns {CKEDITOR.dom.window} The window object.
|
||||
*/
|
||||
getWindow : function()
|
||||
{
|
||||
var win = new CKEDITOR.dom.window( this.$.parentWindow || this.$.defaultView );
|
||||
|
||||
return (
|
||||
this.getWindow = function()
|
||||
{
|
||||
return win;
|
||||
})();
|
||||
}
|
||||
});
|
||||
49
ckeditor/_source/core/dom/documentfragment.js
Normal file
49
ckeditor/_source/core/dom/documentfragment.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
/**
|
||||
* DocumentFragment is a "lightweight" or "minimal" Document object. It is
|
||||
* commonly used to extract a portion of a document's tree or to create a new
|
||||
* fragment of a document. Various operations may take DocumentFragment objects
|
||||
* as arguments and results in all the child nodes of the DocumentFragment being
|
||||
* moved to the child list of this node.
|
||||
*
|
||||
* @param {Object} ownerDocument
|
||||
*/
|
||||
CKEDITOR.dom.documentFragment = function( ownerDocument )
|
||||
{
|
||||
ownerDocument = ownerDocument || CKEDITOR.document;
|
||||
this.$ = ownerDocument.$.createDocumentFragment();
|
||||
};
|
||||
|
||||
CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype,
|
||||
CKEDITOR.dom.element.prototype,
|
||||
{
|
||||
type : CKEDITOR.NODE_DOCUMENT_FRAGMENT,
|
||||
insertAfterNode : function( node )
|
||||
{
|
||||
node = node.$;
|
||||
node.parentNode.insertBefore( this.$, node.nextSibling );
|
||||
}
|
||||
},
|
||||
true,
|
||||
{
|
||||
'append' : 1,
|
||||
'appendBogus' : 1,
|
||||
'getFirst' : 1,
|
||||
'getLast' : 1,
|
||||
'appendTo' : 1,
|
||||
'moveChildren' : 1,
|
||||
'insertBefore' : 1,
|
||||
'insertAfterNode' : 1,
|
||||
'replace' : 1,
|
||||
'trim' : 1,
|
||||
'type' : 1,
|
||||
'ltrim' : 1,
|
||||
'rtrim' : 1,
|
||||
'getDocument' : 1,
|
||||
'getChildCount' : 1,
|
||||
'getChild' : 1,
|
||||
'getChildren' : 1
|
||||
} );
|
||||
251
ckeditor/_source/core/dom/domobject.js
Normal file
251
ckeditor/_source/core/dom/domobject.js
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html 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.
|
||||
* @constructor
|
||||
* @param {Object} nativeDomObject A native DOM object.
|
||||
* @augments CKEDITOR.event
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.dom.domObject = function( nativeDomObject )
|
||||
{
|
||||
if ( nativeDomObject )
|
||||
{
|
||||
/**
|
||||
* The native DOM object represented by this class instance.
|
||||
* @type Object
|
||||
* @example
|
||||
* var element = new CKEDITOR.dom.element( 'span' );
|
||||
* alert( element.$.nodeType ); // "1"
|
||||
*/
|
||||
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 /** @lends CKEDITOR.dom.domObject.prototype */ {
|
||||
|
||||
getPrivate : function()
|
||||
{
|
||||
var priv;
|
||||
|
||||
// Get the main private function from the custom data. Create it if not
|
||||
// defined.
|
||||
if ( !( priv = this.getCustomData( '_' ) ) )
|
||||
this.setCustomData( '_', ( priv = {} ) );
|
||||
|
||||
return priv;
|
||||
},
|
||||
|
||||
/** @ignore */
|
||||
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 );
|
||||
},
|
||||
|
||||
/** @ignore */
|
||||
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.$.removeEventListener )
|
||||
this.$.removeEventListener( eventName, listener, false );
|
||||
else if ( this.$.detachEvent )
|
||||
this.$.detachEvent( 'on' + eventName, listener );
|
||||
|
||||
delete nativeListeners[ eventName ];
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(function( domObjectProto )
|
||||
{
|
||||
var customData = {};
|
||||
|
||||
CKEDITOR.on( 'reset', function()
|
||||
{
|
||||
customData = {};
|
||||
});
|
||||
|
||||
/**
|
||||
* Determines whether the specified object is equal to the current object.
|
||||
* @name CKEDITOR.dom.domObject.prototype.equals
|
||||
* @function
|
||||
* @param {Object} object The object to compare with the current object.
|
||||
* @returns {Boolean} "true" if the object is equal.
|
||||
* @example
|
||||
* var doc = new CKEDITOR.dom.document( document );
|
||||
* alert( doc.equals( CKEDITOR.document ) ); // "true"
|
||||
* alert( doc == CKEDITOR.document ); // "false"
|
||||
*/
|
||||
domObjectProto.equals = function( object )
|
||||
{
|
||||
return ( object && object.$ === this.$ );
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a data slot value for this object. These values are shared by all
|
||||
* instances pointing to that same DOM object.
|
||||
* @name CKEDITOR.dom.domObject.prototype.setCustomData
|
||||
* @function
|
||||
* @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.
|
||||
* @see CKEDITOR.dom.domObject.prototype.getCustomData
|
||||
* @example
|
||||
* var element = new CKEDITOR.dom.element( 'span' );
|
||||
* element.setCustomData( 'hasCustomData', true );
|
||||
*/
|
||||
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.
|
||||
* @name CKEDITOR.dom.domObject.prototype.getCustomData
|
||||
* @function
|
||||
* @param {String} key The key used to identify the data slot.
|
||||
* @returns {Object} This value set to the data slot.
|
||||
* @see CKEDITOR.dom.domObject.prototype.setCustomData
|
||||
* @example
|
||||
* var element = new CKEDITOR.dom.element( 'span' );
|
||||
* alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true'
|
||||
*/
|
||||
domObjectProto.getCustomData = function( key )
|
||||
{
|
||||
var expandoNumber = this.$._cke_expando,
|
||||
dataSlot = expandoNumber && customData[ expandoNumber ];
|
||||
|
||||
return dataSlot && dataSlot[ key ];
|
||||
};
|
||||
|
||||
/**
|
||||
* @name CKEDITOR.dom.domObject.prototype.removeCustomData
|
||||
*/
|
||||
domObjectProto.removeCustomData = function( key )
|
||||
{
|
||||
var expandoNumber = this.$._cke_expando,
|
||||
dataSlot = expandoNumber && customData[ expandoNumber ],
|
||||
retval = dataSlot && dataSlot[ key ];
|
||||
|
||||
if ( typeof retval != 'undefined' )
|
||||
delete dataSlot[ key ];
|
||||
|
||||
return retval || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes any data stored on this object.
|
||||
* To avoid memory leaks we must assure that there are no
|
||||
* references left after the object is no longer needed.
|
||||
* @name CKEDITOR.dom.domObject.prototype.clearCustomData
|
||||
* @function
|
||||
*/
|
||||
domObjectProto.clearCustomData = function()
|
||||
{
|
||||
// Clear all event listeners
|
||||
this.removeAllListeners();
|
||||
|
||||
var expandoNumber = this.$._cke_expando;
|
||||
expandoNumber && delete customData[ expandoNumber ];
|
||||
};
|
||||
|
||||
/**
|
||||
* @name CKEDITOR.dom.domObject.prototype.getCustomData
|
||||
*/
|
||||
domObjectProto.getUniqueId = function()
|
||||
{
|
||||
return this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() );
|
||||
};
|
||||
|
||||
// Implement CKEDITOR.event.
|
||||
CKEDITOR.event.implementOn( domObjectProto );
|
||||
|
||||
})( CKEDITOR.dom.domObject.prototype );
|
||||
1556
ckeditor/_source/core/dom/element.js
Normal file
1556
ckeditor/_source/core/dom/element.js
Normal file
File diff suppressed because it is too large
Load Diff
116
ckeditor/_source/core/dom/elementpath.js
Normal file
116
ckeditor/_source/core/dom/elementpath.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
(function()
|
||||
{
|
||||
// Elements that may be considered the "Block boundary" in an element path.
|
||||
var pathBlockElements = { address:1,blockquote:1,dl:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,li:1,dt:1,dd:1 };
|
||||
|
||||
// Elements that may be considered the "Block limit" in an element path.
|
||||
var pathBlockLimitElements = { body:1,div:1,table:1,tbody:1,tr:1,td:1,th:1,caption:1,form:1 };
|
||||
|
||||
// Check if an element contains any block element.
|
||||
var checkHasBlock = function( element )
|
||||
{
|
||||
var childNodes = element.getChildren();
|
||||
|
||||
for ( var i = 0, count = childNodes.count() ; i < count ; i++ )
|
||||
{
|
||||
var child = childNodes.getItem( i );
|
||||
|
||||
if ( child.type == CKEDITOR.NODE_ELEMENT && CKEDITOR.dtd.$block[ child.getName() ] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
CKEDITOR.dom.elementPath = function( lastNode )
|
||||
{
|
||||
var block = null;
|
||||
var blockLimit = null;
|
||||
var elements = [];
|
||||
|
||||
var e = lastNode;
|
||||
|
||||
while ( e )
|
||||
{
|
||||
if ( e.type == CKEDITOR.NODE_ELEMENT )
|
||||
{
|
||||
if ( !this.lastElement )
|
||||
this.lastElement = e;
|
||||
|
||||
var elementName = e.getName();
|
||||
if ( CKEDITOR.env.ie && e.$.scopeName != 'HTML' )
|
||||
elementName = e.$.scopeName.toLowerCase() + ':' + elementName;
|
||||
|
||||
if ( !blockLimit )
|
||||
{
|
||||
if ( !block && pathBlockElements[ elementName ] )
|
||||
block = e;
|
||||
|
||||
if ( pathBlockLimitElements[ elementName ] )
|
||||
{
|
||||
// DIV is considered the Block, if no block is available (#525)
|
||||
// and if it doesn't contain other blocks.
|
||||
if ( !block && elementName == 'div' && !checkHasBlock( e ) )
|
||||
block = e;
|
||||
else
|
||||
blockLimit = e;
|
||||
}
|
||||
}
|
||||
|
||||
elements.push( e );
|
||||
|
||||
if ( elementName == 'body' )
|
||||
break;
|
||||
}
|
||||
e = e.getParent();
|
||||
}
|
||||
|
||||
this.block = block;
|
||||
this.blockLimit = blockLimit;
|
||||
this.elements = elements;
|
||||
};
|
||||
})();
|
||||
|
||||
CKEDITOR.dom.elementPath.prototype =
|
||||
{
|
||||
/**
|
||||
* Compares this element path with another one.
|
||||
* @param {CKEDITOR.dom.elementPath} otherPath The elementPath object to be
|
||||
* compared with this one.
|
||||
* @returns {Boolean} "true" if the paths are equal, containing the same
|
||||
* number of elements and the same elements in the same order.
|
||||
*/
|
||||
compare : function( otherPath )
|
||||
{
|
||||
var thisElements = this.elements;
|
||||
var otherElements = otherPath && otherPath.elements;
|
||||
|
||||
if ( !otherElements || thisElements.length != otherElements.length )
|
||||
return false;
|
||||
|
||||
for ( var i = 0 ; i < thisElements.length ; i++ )
|
||||
{
|
||||
if ( !thisElements[ i ].equals( otherElements[ i ] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
contains : function( tagNames )
|
||||
{
|
||||
var elements = this.elements;
|
||||
for ( var i = 0 ; i < elements.length ; i++ )
|
||||
{
|
||||
if ( elements[ i ].getName() in tagNames )
|
||||
return elements[ i ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
142
ckeditor/_source/core/dom/event.js
Normal file
142
ckeditor/_source/core/dom/event.js
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Defines the {@link CKEDITOR.dom.event} class, which
|
||||
* represents the a native DOM event object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a native DOM event object.
|
||||
* @constructor
|
||||
* @param {Object} domEvent A native DOM event object.
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.dom.event = function( domEvent )
|
||||
{
|
||||
/**
|
||||
* The native DOM event object represented by this class instance.
|
||||
* @type Object
|
||||
* @example
|
||||
*/
|
||||
this.$ = domEvent;
|
||||
};
|
||||
|
||||
CKEDITOR.dom.event.prototype =
|
||||
{
|
||||
/**
|
||||
* Gets the key code associated to the event.
|
||||
* @returns {Number} The key code.
|
||||
* @example
|
||||
* alert( event.getKey() ); "65" is "a" has been pressed
|
||||
*/
|
||||
getKey : function()
|
||||
{
|
||||
return this.$.keyCode || this.$.which;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a number represeting the combination of the keys pressed during the
|
||||
* event. It is the sum with the current key code and the {@link CKEDITOR.CTRL},
|
||||
* {@link CKEDITOR.SHIFT} and {@link CKEDITOR.ALT} constants.
|
||||
* @returns {Number} The number representing the keys combination.
|
||||
* @example
|
||||
* alert( event.getKeystroke() == 65 ); // "a" key
|
||||
* alert( event.getKeystroke() == CKEDITOR.CTRL + 65 ); // CTRL + "a" key
|
||||
* alert( event.getKeystroke() == CKEDITOR.CTRL + CKEDITOR.SHIFT + 65 ); // CTRL + SHIFT + "a" key
|
||||
*/
|
||||
getKeystroke : function()
|
||||
{
|
||||
var keystroke = this.getKey();
|
||||
|
||||
if ( this.$.ctrlKey || this.$.metaKey )
|
||||
keystroke += CKEDITOR.CTRL;
|
||||
|
||||
if ( this.$.shiftKey )
|
||||
keystroke += CKEDITOR.SHIFT;
|
||||
|
||||
if ( this.$.altKey )
|
||||
keystroke += CKEDITOR.ALT;
|
||||
|
||||
return keystroke;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prevents the original behavior of the event to happen. It can optionally
|
||||
* stop propagating the event in the event chain.
|
||||
* @param {Boolean} [stopPropagation] Stop propagating this event in the
|
||||
* event chain.
|
||||
* @example
|
||||
* var element = CKEDITOR.document.getById( 'myElement' );
|
||||
* element.on( 'click', function( ev )
|
||||
* {
|
||||
* // The DOM event object is passed by the "data" property.
|
||||
* var domEvent = ev.data;
|
||||
* // Prevent the click to chave any effect in the element.
|
||||
* domEvent.preventDefault();
|
||||
* });
|
||||
*/
|
||||
preventDefault : function( stopPropagation )
|
||||
{
|
||||
var $ = this.$;
|
||||
if ( $.preventDefault )
|
||||
$.preventDefault();
|
||||
else
|
||||
$.returnValue = false;
|
||||
|
||||
if ( stopPropagation )
|
||||
this.stopPropagation();
|
||||
},
|
||||
|
||||
stopPropagation : function()
|
||||
{
|
||||
var $ = this.$;
|
||||
if ( $.stopPropagation )
|
||||
$.stopPropagation();
|
||||
else
|
||||
$.cancelBubble = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the DOM node where the event was targeted to.
|
||||
* @returns {CKEDITOR.dom.node} The target DOM node.
|
||||
* @example
|
||||
* var element = CKEDITOR.document.getById( 'myElement' );
|
||||
* element.on( 'click', function( ev )
|
||||
* {
|
||||
* // The DOM event object is passed by the "data" property.
|
||||
* var domEvent = ev.data;
|
||||
* // Add a CSS class to the event target.
|
||||
* domEvent.getTarget().addClass( 'clicked' );
|
||||
* });
|
||||
*/
|
||||
|
||||
getTarget : function()
|
||||
{
|
||||
var rawNode = this.$.target || this.$.srcElement;
|
||||
return rawNode ? new CKEDITOR.dom.node( rawNode ) : null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* CTRL key (1000).
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.CTRL = 1000;
|
||||
|
||||
/**
|
||||
* SHIFT key (2000).
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.SHIFT = 2000;
|
||||
|
||||
/**
|
||||
* ALT key (4000).
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.ALT = 4000;
|
||||
683
ckeditor/_source/core/dom/node.js
Normal file
683
ckeditor/_source/core/dom/node.js
Normal file
@@ -0,0 +1,683 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Defines the {@link CKEDITOR.dom.node} class, which is the base
|
||||
* class for classes that represent DOM nodes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for classes representing DOM nodes. This constructor may return
|
||||
* and instance of classes that inherits this class, like
|
||||
* {@link CKEDITOR.dom.element} or {@link CKEDITOR.dom.text}.
|
||||
* @augments CKEDITOR.dom.domObject
|
||||
* @param {Object} domNode A native DOM node.
|
||||
* @constructor
|
||||
* @see CKEDITOR.dom.element
|
||||
* @see CKEDITOR.dom.text
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.dom.node = function( domNode )
|
||||
{
|
||||
if ( domNode )
|
||||
{
|
||||
switch ( domNode.nodeType )
|
||||
{
|
||||
// Safari don't consider document as element node type. (#3389)
|
||||
case CKEDITOR.NODE_DOCUMENT :
|
||||
return new CKEDITOR.dom.document( domNode );
|
||||
|
||||
case CKEDITOR.NODE_ELEMENT :
|
||||
return new CKEDITOR.dom.element( domNode );
|
||||
|
||||
case CKEDITOR.NODE_TEXT :
|
||||
return new CKEDITOR.dom.text( domNode );
|
||||
}
|
||||
|
||||
// Call the base constructor.
|
||||
CKEDITOR.dom.domObject.call( this, domNode );
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
CKEDITOR.dom.node.prototype = new CKEDITOR.dom.domObject();
|
||||
|
||||
/**
|
||||
* Element node type.
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.NODE_ELEMENT = 1;
|
||||
|
||||
/**
|
||||
* Document node type.
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.NODE_DOCUMENT = 9;
|
||||
|
||||
/**
|
||||
* Text node type.
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.NODE_TEXT = 3;
|
||||
|
||||
/**
|
||||
* Comment node type.
|
||||
* @constant
|
||||
* @example
|
||||
*/
|
||||
CKEDITOR.NODE_COMMENT = 8;
|
||||
|
||||
CKEDITOR.NODE_DOCUMENT_FRAGMENT = 11;
|
||||
|
||||
CKEDITOR.POSITION_IDENTICAL = 0;
|
||||
CKEDITOR.POSITION_DISCONNECTED = 1;
|
||||
CKEDITOR.POSITION_FOLLOWING = 2;
|
||||
CKEDITOR.POSITION_PRECEDING = 4;
|
||||
CKEDITOR.POSITION_IS_CONTAINED = 8;
|
||||
CKEDITOR.POSITION_CONTAINS = 16;
|
||||
|
||||
CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype,
|
||||
/** @lends CKEDITOR.dom.node.prototype */
|
||||
{
|
||||
/**
|
||||
* Makes this node child of another element.
|
||||
* @param {CKEDITOR.dom.element} element The target element to which append
|
||||
* this node.
|
||||
* @returns {CKEDITOR.dom.element} The target element.
|
||||
* @example
|
||||
* var p = new CKEDITOR.dom.element( 'p' );
|
||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
||||
* strong.appendTo( p );
|
||||
*
|
||||
* // result: "<p><strong></strong></p>"
|
||||
*/
|
||||
appendTo : function( element, toStart )
|
||||
{
|
||||
element.append( this, toStart );
|
||||
return element;
|
||||
},
|
||||
|
||||
clone : function( includeChildren, cloneId )
|
||||
{
|
||||
var $clone = this.$.cloneNode( includeChildren );
|
||||
|
||||
if ( !cloneId )
|
||||
{
|
||||
var removeIds = function( node )
|
||||
{
|
||||
if ( node.nodeType != CKEDITOR.NODE_ELEMENT )
|
||||
return;
|
||||
|
||||
node.removeAttribute( 'id', false ) ;
|
||||
node.removeAttribute( '_cke_expando', false ) ;
|
||||
|
||||
var childs = node.childNodes;
|
||||
for ( var i=0 ; i < childs.length ; i++ )
|
||||
removeIds( childs[ i ] );
|
||||
};
|
||||
|
||||
// The "id" attribute should never be cloned to avoid duplication.
|
||||
removeIds( $clone );
|
||||
}
|
||||
|
||||
return new CKEDITOR.dom.node( $clone );
|
||||
},
|
||||
|
||||
hasPrevious : function()
|
||||
{
|
||||
return !!this.$.previousSibling;
|
||||
},
|
||||
|
||||
hasNext : function()
|
||||
{
|
||||
return !!this.$.nextSibling;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts this element after a node.
|
||||
* @param {CKEDITOR.dom.node} node The that will preceed this element.
|
||||
* @returns {CKEDITOR.dom.node} The node preceeding this one after
|
||||
* insertion.
|
||||
* @example
|
||||
* var em = new CKEDITOR.dom.element( 'em' );
|
||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
||||
* strong.insertAfter( em );
|
||||
*
|
||||
* // result: "<em></em><strong></strong>"
|
||||
*/
|
||||
insertAfter : function( node )
|
||||
{
|
||||
node.$.parentNode.insertBefore( this.$, node.$.nextSibling );
|
||||
return node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts this element before a node.
|
||||
* @param {CKEDITOR.dom.node} node The that will be after this element.
|
||||
* @returns {CKEDITOR.dom.node} The node being inserted.
|
||||
* @example
|
||||
* var em = new CKEDITOR.dom.element( 'em' );
|
||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
||||
* strong.insertBefore( em );
|
||||
*
|
||||
* // result: "<strong></strong><em></em>"
|
||||
*/
|
||||
insertBefore : function( node )
|
||||
{
|
||||
node.$.parentNode.insertBefore( this.$, node.$ );
|
||||
return node;
|
||||
},
|
||||
|
||||
insertBeforeMe : function( node )
|
||||
{
|
||||
this.$.parentNode.insertBefore( node.$, this.$ );
|
||||
return node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves a uniquely identifiable tree address for this node.
|
||||
* The tree address returns is an array of integers, with each integer
|
||||
* indicating a child index of a DOM node, starting from
|
||||
* document.documentElement.
|
||||
*
|
||||
* For example, assuming <body> is the second child from <html> (<head>
|
||||
* being the first), and we'd like to address the third child under the
|
||||
* fourth child of body, the tree address returned would be:
|
||||
* [1, 3, 2]
|
||||
*
|
||||
* The tree address cannot be used for finding back the DOM tree node once
|
||||
* the DOM tree structure has been modified.
|
||||
*/
|
||||
getAddress : function( normalized )
|
||||
{
|
||||
var address = [];
|
||||
var $documentElement = this.getDocument().$.documentElement;
|
||||
var node = this.$;
|
||||
|
||||
while ( node && node != $documentElement )
|
||||
{
|
||||
var parentNode = node.parentNode;
|
||||
var currentIndex = -1;
|
||||
|
||||
if ( parentNode )
|
||||
{
|
||||
for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
|
||||
{
|
||||
var candidate = parentNode.childNodes[i];
|
||||
|
||||
if ( normalized &&
|
||||
candidate.nodeType == 3 &&
|
||||
candidate.previousSibling &&
|
||||
candidate.previousSibling.nodeType == 3 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
|
||||
if ( candidate == node )
|
||||
break;
|
||||
}
|
||||
|
||||
address.unshift( currentIndex );
|
||||
}
|
||||
|
||||
node = parentNode;
|
||||
}
|
||||
|
||||
return address;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the document containing this element.
|
||||
* @returns {CKEDITOR.dom.document} The document.
|
||||
* @example
|
||||
* var element = CKEDITOR.document.getById( 'example' );
|
||||
* alert( <b>element.getDocument().equals( CKEDITOR.document )</b> ); // "true"
|
||||
*/
|
||||
getDocument : function()
|
||||
{
|
||||
var document = new CKEDITOR.dom.document( this.$.ownerDocument || this.$.parentNode.ownerDocument );
|
||||
|
||||
return (
|
||||
this.getDocument = function()
|
||||
{
|
||||
return document;
|
||||
})();
|
||||
},
|
||||
|
||||
getIndex : function()
|
||||
{
|
||||
var $ = this.$;
|
||||
|
||||
var currentNode = $.parentNode && $.parentNode.firstChild;
|
||||
var currentIndex = -1;
|
||||
|
||||
while ( currentNode )
|
||||
{
|
||||
currentIndex++;
|
||||
|
||||
if ( currentNode == $ )
|
||||
return currentIndex;
|
||||
|
||||
currentNode = currentNode.nextSibling;
|
||||
}
|
||||
|
||||
return -1;
|
||||
},
|
||||
|
||||
getNextSourceNode : function( startFromSibling, nodeType, guard )
|
||||
{
|
||||
// If "guard" is a node, transform it in a function.
|
||||
if ( guard && !guard.call )
|
||||
{
|
||||
var guardNode = guard;
|
||||
guard = function( node )
|
||||
{
|
||||
return !node.equals( guardNode );
|
||||
};
|
||||
}
|
||||
|
||||
var node = ( !startFromSibling && this.getFirst && this.getFirst() ),
|
||||
parent;
|
||||
|
||||
// Guarding when we're skipping the current element( no children or 'startFromSibling' ).
|
||||
// send the 'moving out' signal even we don't actually dive into.
|
||||
if ( !node )
|
||||
{
|
||||
if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
|
||||
return null;
|
||||
node = this.getNext();
|
||||
}
|
||||
|
||||
while ( !node && ( parent = ( parent || this ).getParent() ) )
|
||||
{
|
||||
// The guard check sends the "true" paramenter to indicate that
|
||||
// we are moving "out" of the element.
|
||||
if ( guard && guard( parent, true ) === false )
|
||||
return null;
|
||||
|
||||
node = parent.getNext();
|
||||
}
|
||||
|
||||
if ( !node )
|
||||
return null;
|
||||
|
||||
if ( guard && guard( node ) === false )
|
||||
return null;
|
||||
|
||||
if ( nodeType && nodeType != node.type )
|
||||
return node.getNextSourceNode( false, nodeType, guard );
|
||||
|
||||
return node;
|
||||
},
|
||||
|
||||
getPreviousSourceNode : function( startFromSibling, nodeType, guard )
|
||||
{
|
||||
if ( guard && !guard.call )
|
||||
{
|
||||
var guardNode = guard;
|
||||
guard = function( node )
|
||||
{
|
||||
return !node.equals( guardNode );
|
||||
};
|
||||
}
|
||||
|
||||
var node = ( !startFromSibling && this.getLast && this.getLast() ),
|
||||
parent;
|
||||
|
||||
// Guarding when we're skipping the current element( no children or 'startFromSibling' ).
|
||||
// send the 'moving out' signal even we don't actually dive into.
|
||||
if ( !node )
|
||||
{
|
||||
if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
|
||||
return null;
|
||||
node = this.getPrevious();
|
||||
}
|
||||
|
||||
while ( !node && ( parent = ( parent || this ).getParent() ) )
|
||||
{
|
||||
// The guard check sends the "true" paramenter to indicate that
|
||||
// we are moving "out" of the element.
|
||||
if ( guard && guard( parent, true ) === false )
|
||||
return null;
|
||||
|
||||
node = parent.getPrevious();
|
||||
}
|
||||
|
||||
if ( !node )
|
||||
return null;
|
||||
|
||||
if ( guard && guard( node ) === false )
|
||||
return null;
|
||||
|
||||
if ( nodeType && node.type != nodeType )
|
||||
return node.getPreviousSourceNode( false, nodeType, guard );
|
||||
|
||||
return node;
|
||||
},
|
||||
|
||||
getPrevious : function( evaluator )
|
||||
{
|
||||
var previous = this.$, retval;
|
||||
do
|
||||
{
|
||||
previous = previous.previousSibling;
|
||||
retval = previous && new CKEDITOR.dom.node( previous );
|
||||
}
|
||||
while ( retval && evaluator && !evaluator( retval ) )
|
||||
return retval;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the node that follows this element in its parent's child list.
|
||||
* @param {Function} evaluator Filtering the result node.
|
||||
* @returns {CKEDITOR.dom.node} The next node or null if not available.
|
||||
* @example
|
||||
* var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b> <i>next</i></div>' );
|
||||
* var first = <b>element.getFirst().getNext()</b>;
|
||||
* alert( first.getName() ); // "i"
|
||||
*/
|
||||
getNext : function( evaluator )
|
||||
{
|
||||
var next = this.$, retval;
|
||||
do
|
||||
{
|
||||
next = next.nextSibling;
|
||||
retval = next && new CKEDITOR.dom.node( next );
|
||||
}
|
||||
while ( retval && evaluator && !evaluator( retval ) )
|
||||
return retval;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the parent element for this node.
|
||||
* @returns {CKEDITOR.dom.element} The parent element.
|
||||
* @example
|
||||
* var node = editor.document.getBody().getFirst();
|
||||
* var parent = node.<b>getParent()</b>;
|
||||
* alert( node.getName() ); // "body"
|
||||
*/
|
||||
getParent : function()
|
||||
{
|
||||
var parent = this.$.parentNode;
|
||||
return ( parent && parent.nodeType == 1 ) ? new CKEDITOR.dom.node( parent ) : null;
|
||||
},
|
||||
|
||||
getParents : function( closerFirst )
|
||||
{
|
||||
var node = this;
|
||||
var parents = [];
|
||||
|
||||
do
|
||||
{
|
||||
parents[ closerFirst ? 'push' : 'unshift' ]( node );
|
||||
}
|
||||
while ( ( node = node.getParent() ) )
|
||||
|
||||
return parents;
|
||||
},
|
||||
|
||||
getCommonAncestor : function( node )
|
||||
{
|
||||
if ( node.equals( this ) )
|
||||
return this;
|
||||
|
||||
if ( node.contains && node.contains( this ) )
|
||||
return node;
|
||||
|
||||
var start = this.contains ? this : this.getParent();
|
||||
|
||||
do
|
||||
{
|
||||
if ( start.contains( node ) )
|
||||
return start;
|
||||
}
|
||||
while ( ( start = start.getParent() ) );
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getPosition : function( otherNode )
|
||||
{
|
||||
var $ = this.$;
|
||||
var $other = otherNode.$;
|
||||
|
||||
if ( $.compareDocumentPosition )
|
||||
return $.compareDocumentPosition( $other );
|
||||
|
||||
// IE and Safari have no support for compareDocumentPosition.
|
||||
|
||||
if ( $ == $other )
|
||||
return CKEDITOR.POSITION_IDENTICAL;
|
||||
|
||||
// Only element nodes support contains and sourceIndex.
|
||||
if ( this.type == CKEDITOR.NODE_ELEMENT && otherNode.type == CKEDITOR.NODE_ELEMENT )
|
||||
{
|
||||
if ( $.contains )
|
||||
{
|
||||
if ( $.contains( $other ) )
|
||||
return CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING;
|
||||
|
||||
if ( $other.contains( $ ) )
|
||||
return CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
|
||||
}
|
||||
|
||||
if ( 'sourceIndex' in $ )
|
||||
{
|
||||
return ( $.sourceIndex < 0 || $other.sourceIndex < 0 ) ? CKEDITOR.POSITION_DISCONNECTED :
|
||||
( $.sourceIndex < $other.sourceIndex ) ? CKEDITOR.POSITION_PRECEDING :
|
||||
CKEDITOR.POSITION_FOLLOWING;
|
||||
}
|
||||
}
|
||||
|
||||
// For nodes that don't support compareDocumentPosition, contains
|
||||
// or sourceIndex, their "address" is compared.
|
||||
|
||||
var addressOfThis = this.getAddress(),
|
||||
addressOfOther = otherNode.getAddress(),
|
||||
minLevel = Math.min( addressOfThis.length, addressOfOther.length );
|
||||
|
||||
// Determinate preceed/follow relationship.
|
||||
for ( var i = 0 ; i <= minLevel - 1 ; i++ )
|
||||
{
|
||||
if ( addressOfThis[ i ] != addressOfOther[ i ] )
|
||||
{
|
||||
if ( i < minLevel )
|
||||
{
|
||||
return addressOfThis[ i ] < addressOfOther[ i ] ?
|
||||
CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Determinate contains/contained relationship.
|
||||
return ( addressOfThis.length < addressOfOther.length ) ?
|
||||
CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING :
|
||||
CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the closes ancestor node of a specified node name.
|
||||
* @param {String} name Node name of ancestor node.
|
||||
* @param {Boolean} includeSelf (Optional) Whether to include the current
|
||||
* node in the calculation or not.
|
||||
* @returns {CKEDITOR.dom.node} Ancestor node.
|
||||
*/
|
||||
getAscendant : function( name, includeSelf )
|
||||
{
|
||||
var $ = this.$;
|
||||
|
||||
if ( !includeSelf )
|
||||
$ = $.parentNode;
|
||||
|
||||
while ( $ )
|
||||
{
|
||||
if ( $.nodeName && $.nodeName.toLowerCase() == name )
|
||||
return new CKEDITOR.dom.node( $ );
|
||||
|
||||
$ = $.parentNode;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
hasAscendant : function( name, includeSelf )
|
||||
{
|
||||
var $ = this.$;
|
||||
|
||||
if ( !includeSelf )
|
||||
$ = $.parentNode;
|
||||
|
||||
while ( $ )
|
||||
{
|
||||
if ( $.nodeName && $.nodeName.toLowerCase() == name )
|
||||
return true;
|
||||
|
||||
$ = $.parentNode;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
move : function( target, toStart )
|
||||
{
|
||||
target.append( this.remove(), toStart );
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes this node from the document DOM.
|
||||
* @param {Boolean} [preserveChildren] Indicates that the children
|
||||
* elements must remain in the document, removing only the outer
|
||||
* tags.
|
||||
* @example
|
||||
* var element = CKEDITOR.dom.element.getById( 'MyElement' );
|
||||
* <b>element.remove()</b>;
|
||||
*/
|
||||
remove : function( preserveChildren )
|
||||
{
|
||||
var $ = this.$;
|
||||
var parent = $.parentNode;
|
||||
|
||||
if ( parent )
|
||||
{
|
||||
if ( preserveChildren )
|
||||
{
|
||||
// Move all children before the node.
|
||||
for ( var child ; ( child = $.firstChild ) ; )
|
||||
{
|
||||
parent.insertBefore( $.removeChild( child ), $ );
|
||||
}
|
||||
}
|
||||
|
||||
parent.removeChild( $ );
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
replace : function( nodeToReplace )
|
||||
{
|
||||
this.insertBefore( nodeToReplace );
|
||||
nodeToReplace.remove();
|
||||
},
|
||||
|
||||
trim : function()
|
||||
{
|
||||
this.ltrim();
|
||||
this.rtrim();
|
||||
},
|
||||
|
||||
ltrim : function()
|
||||
{
|
||||
var child;
|
||||
while ( this.getFirst && ( child = this.getFirst() ) )
|
||||
{
|
||||
if ( child.type == CKEDITOR.NODE_TEXT )
|
||||
{
|
||||
var trimmed = CKEDITOR.tools.ltrim( child.getText() ),
|
||||
originalLength = child.getLength();
|
||||
|
||||
if ( !trimmed )
|
||||
{
|
||||
child.remove();
|
||||
continue;
|
||||
}
|
||||
else if ( trimmed.length < originalLength )
|
||||
{
|
||||
child.split( originalLength - trimmed.length );
|
||||
|
||||
// IE BUG: child.remove() may raise JavaScript errors here. (#81)
|
||||
this.$.removeChild( this.$.firstChild );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
rtrim : function()
|
||||
{
|
||||
var child;
|
||||
while ( this.getLast && ( child = this.getLast() ) )
|
||||
{
|
||||
if ( child.type == CKEDITOR.NODE_TEXT )
|
||||
{
|
||||
var trimmed = CKEDITOR.tools.rtrim( child.getText() ),
|
||||
originalLength = child.getLength();
|
||||
|
||||
if ( !trimmed )
|
||||
{
|
||||
child.remove();
|
||||
continue;
|
||||
}
|
||||
else if ( trimmed.length < originalLength )
|
||||
{
|
||||
child.split( trimmed.length );
|
||||
|
||||
// IE BUG: child.getNext().remove() may raise JavaScript errors here.
|
||||
// (#81)
|
||||
this.$.lastChild.parentNode.removeChild( this.$.lastChild );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !CKEDITOR.env.ie && !CKEDITOR.env.opera )
|
||||
{
|
||||
child = this.$.lastChild;
|
||||
|
||||
if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' )
|
||||
{
|
||||
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).
|
||||
child.parentNode.removeChild( child ) ;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isReadOnly : function()
|
||||
{
|
||||
var current = this;
|
||||
while( current )
|
||||
{
|
||||
if ( current.type == CKEDITOR.NODE_ELEMENT )
|
||||
{
|
||||
if ( current.is( 'body' ) || current.getCustomData( '_cke_notReadOnly' ) )
|
||||
break;
|
||||
|
||||
if ( current.getAttribute( 'contentEditable' ) == 'false' )
|
||||
return current;
|
||||
else if ( current.getAttribute( 'contentEditable' ) == 'true' )
|
||||
break;
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
23
ckeditor/_source/core/dom/nodelist.js
Normal file
23
ckeditor/_source/core/dom/nodelist.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
CKEDITOR.dom.nodeList = function( nativeList )
|
||||
{
|
||||
this.$ = nativeList;
|
||||
};
|
||||
|
||||
CKEDITOR.dom.nodeList.prototype =
|
||||
{
|
||||
count : function()
|
||||
{
|
||||
return this.$.length;
|
||||
},
|
||||
|
||||
getItem : function( index )
|
||||
{
|
||||
var $node = this.$[ index ];
|
||||
return $node ? new CKEDITOR.dom.node( $node ) : null;
|
||||
}
|
||||
};
|
||||
1880
ckeditor/_source/core/dom/range.js
Normal file
1880
ckeditor/_source/core/dom/range.js
Normal file
File diff suppressed because it is too large
Load Diff
163
ckeditor/_source/core/dom/rangelist.js
Normal file
163
ckeditor/_source/core/dom/rangelist.js
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
(function()
|
||||
{
|
||||
/**
|
||||
* Represents a list os CKEDITOR.dom.range objects, which can be easily
|
||||
* iterated sequentially.
|
||||
* @constructor
|
||||
* @param {CKEDITOR.dom.range|Array} [ranges] The ranges contained on this list.
|
||||
* Note that, if an array of ranges is specified, the range sequence
|
||||
* should match its DOM order. This class will not help to sort them.
|
||||
*/
|
||||
CKEDITOR.dom.rangeList = function( ranges )
|
||||
{
|
||||
if ( ranges instanceof CKEDITOR.dom.rangeList )
|
||||
return ranges;
|
||||
|
||||
if ( !ranges )
|
||||
ranges = [];
|
||||
else if ( ranges instanceof CKEDITOR.dom.range )
|
||||
ranges = [ ranges ];
|
||||
|
||||
return CKEDITOR.tools.extend( ranges, mixins );
|
||||
};
|
||||
|
||||
var mixins =
|
||||
/** @lends CKEDITOR.dom.rangeList.prototype */
|
||||
{
|
||||
/**
|
||||
* Creates an instance of the rangeList iterator, it should be used
|
||||
* only when the ranges processing could be DOM intrusive, which
|
||||
* means it may pollute and break other ranges in this list.
|
||||
* Otherwise, it's enough to just iterate over this array in a for loop.
|
||||
* @returns {CKEDITOR.dom.rangeListIterator}
|
||||
*/
|
||||
createIterator : function()
|
||||
{
|
||||
var rangeList = this,
|
||||
bookmarks = [],
|
||||
current;
|
||||
|
||||
/**
|
||||
* @lends CKEDITOR.dom.rangeListIterator.prototype
|
||||
*/
|
||||
return {
|
||||
|
||||
/**
|
||||
* Retrieves the next range in the list.
|
||||
*/
|
||||
getNextRange : function()
|
||||
{
|
||||
current = current == undefined ? 0 : current + 1;
|
||||
|
||||
var range = rangeList[ current ];
|
||||
|
||||
// Multiple ranges might be mangled by each other.
|
||||
if ( range && rangeList.length > 1 )
|
||||
{
|
||||
// Bookmarking all other ranges on the first iteration,
|
||||
// the range correctness after it doesn't matter since we'll
|
||||
// restore them before the next iteration.
|
||||
if ( !current )
|
||||
{
|
||||
// Make sure bookmark correctness by reverse processing.
|
||||
for ( var i = rangeList.length - 1; i > 0; i-- )
|
||||
bookmarks.unshift( rangeList[ i ].createBookmark( true ) );
|
||||
}
|
||||
else
|
||||
range.moveToBookmark( bookmarks.shift() );
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
createBookmarks : function( serializable )
|
||||
{
|
||||
var retval = [], bookmark;
|
||||
for ( var i = 0; i < this.length ; i++ )
|
||||
{
|
||||
retval.push( bookmark = this[ i ].createBookmark( serializable, true) );
|
||||
|
||||
// Updating the container & offset values for ranges
|
||||
// that have been touched.
|
||||
for ( var j = i + 1; j < this.length; j++ )
|
||||
{
|
||||
this[ j ] = updateDirtyRange( bookmark, this[ j ] );
|
||||
this[ j ] = updateDirtyRange( bookmark, this[ j ], true );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
},
|
||||
|
||||
createBookmarks2 : function( normalized )
|
||||
{
|
||||
var bookmarks = [];
|
||||
|
||||
for ( var i = 0 ; i < this.length ; i++ )
|
||||
bookmarks.push( this[ i ].createBookmark2( normalized ) );
|
||||
|
||||
return bookmarks;
|
||||
},
|
||||
|
||||
/**
|
||||
* Move each range in the list to the position specified by a list of bookmarks.
|
||||
* @param {Array} bookmarks The list of bookmarks, each one matching a range in the list.
|
||||
*/
|
||||
moveToBookmarks : function( bookmarks )
|
||||
{
|
||||
for ( var i = 0 ; i < this.length ; i++ )
|
||||
this[ i ].moveToBookmark( bookmarks[ i ] );
|
||||
}
|
||||
};
|
||||
|
||||
// Update the specified range which has been mangled by previous insertion of
|
||||
// range bookmark nodes.(#3256)
|
||||
function updateDirtyRange( bookmark, dirtyRange, checkEnd )
|
||||
{
|
||||
var serializable = bookmark.serializable,
|
||||
container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ],
|
||||
offset = checkEnd ? 'endOffset' : 'startOffset';
|
||||
|
||||
var bookmarkStart = serializable ?
|
||||
dirtyRange.document.getById( bookmark.startNode )
|
||||
: bookmark.startNode;
|
||||
|
||||
var bookmarkEnd = serializable ?
|
||||
dirtyRange.document.getById( bookmark.endNode )
|
||||
: bookmark.endNode;
|
||||
|
||||
if ( container.equals( bookmarkStart.getPrevious() ) )
|
||||
{
|
||||
dirtyRange.startOffset = dirtyRange.startOffset
|
||||
- container.getLength()
|
||||
- bookmarkEnd.getPrevious().getLength();
|
||||
container = bookmarkEnd.getNext();
|
||||
}
|
||||
else if ( container.equals( bookmarkEnd.getPrevious() ) )
|
||||
{
|
||||
dirtyRange.startOffset = dirtyRange.startOffset - container.getLength();
|
||||
container = bookmarkEnd.getNext();
|
||||
}
|
||||
|
||||
container.equals( bookmarkStart.getParent() ) && dirtyRange[ offset ]++;
|
||||
container.equals( bookmarkEnd.getParent() ) && dirtyRange[ offset ]++;
|
||||
|
||||
// Update and return this range.
|
||||
dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ] = container;
|
||||
return dirtyRange;
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* (Virtual Class) Do not call this constructor. This class is not really part
|
||||
* of the API. It just describes the return type of {@link CKEDITOR.dom.rangeList#createIterator}.
|
||||
* @name CKEDITOR.dom.rangeListIterator
|
||||
* @constructor
|
||||
* @example
|
||||
*/
|
||||
123
ckeditor/_source/core/dom/text.js
Normal file
123
ckeditor/_source/core/dom/text.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Defines the {@link CKEDITOR.dom.text} class, which represents
|
||||
* a DOM text node.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a DOM text node.
|
||||
* @constructor
|
||||
* @augments CKEDITOR.dom.node
|
||||
* @param {Object|String} text A native DOM text node or a string containing
|
||||
* the text to use to create a new text node.
|
||||
* @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
|
||||
* the node in case of new node creation. Defaults to the current document.
|
||||
* @example
|
||||
* var nativeNode = document.createTextNode( 'Example' );
|
||||
* var text = CKEDITOR.dom.text( nativeNode );
|
||||
* @example
|
||||
* var text = CKEDITOR.dom.text( 'Example' );
|
||||
*/
|
||||
CKEDITOR.dom.text = function( text, ownerDocument )
|
||||
{
|
||||
if ( typeof text == 'string' )
|
||||
text = ( ownerDocument ? ownerDocument.$ : document ).createTextNode( text );
|
||||
|
||||
// Theoretically, we should call the base constructor here
|
||||
// (not CKEDITOR.dom.node though). But, IE doesn't support expando
|
||||
// properties on text node, so the features provided by domObject will not
|
||||
// work for text nodes (which is not a big issue for us).
|
||||
//
|
||||
// CKEDITOR.dom.domObject.call( this, element );
|
||||
|
||||
/**
|
||||
* The native DOM text node represented by this class instance.
|
||||
* @type Object
|
||||
* @example
|
||||
* var element = new CKEDITOR.dom.text( 'Example' );
|
||||
* alert( element.$.nodeType ); // "3"
|
||||
*/
|
||||
this.$ = text;
|
||||
};
|
||||
|
||||
CKEDITOR.dom.text.prototype = new CKEDITOR.dom.node();
|
||||
|
||||
CKEDITOR.tools.extend( CKEDITOR.dom.text.prototype,
|
||||
/** @lends CKEDITOR.dom.text.prototype */
|
||||
{
|
||||
/**
|
||||
* The node type. This is a constant value set to
|
||||
* {@link CKEDITOR.NODE_TEXT}.
|
||||
* @type Number
|
||||
* @example
|
||||
*/
|
||||
type : CKEDITOR.NODE_TEXT,
|
||||
|
||||
getLength : function()
|
||||
{
|
||||
return this.$.nodeValue.length;
|
||||
},
|
||||
|
||||
getText : function()
|
||||
{
|
||||
return this.$.nodeValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Breaks this text node into two nodes at the specified offset,
|
||||
* keeping both in the tree as siblings. This node then only contains
|
||||
* all the content up to the offset point. A new text node, which is
|
||||
* inserted as the next sibling of this node, contains all the content
|
||||
* at and after the offset point. When the offset is equal to the
|
||||
* length of this node, the new node has no data.
|
||||
* @param {Number} The position at which to split, starting from zero.
|
||||
* @returns {CKEDITOR.dom.text} The new text node.
|
||||
*/
|
||||
split : function( offset )
|
||||
{
|
||||
// If the offset is after the last char, IE creates the text node
|
||||
// on split, but don't include it into the DOM. So, we have to do
|
||||
// that manually here.
|
||||
if ( CKEDITOR.env.ie && offset == this.getLength() )
|
||||
{
|
||||
var next = this.getDocument().createText( '' );
|
||||
next.insertAfter( this );
|
||||
return next;
|
||||
}
|
||||
|
||||
var doc = this.getDocument();
|
||||
var retval = new CKEDITOR.dom.text( this.$.splitText( offset ), doc );
|
||||
|
||||
// IE BUG: IE8 does not update the childNodes array in DOM after splitText(),
|
||||
// we need to make some DOM changes to make it update. (#3436)
|
||||
if ( CKEDITOR.env.ie8 )
|
||||
{
|
||||
var workaround = new CKEDITOR.dom.text( '', doc );
|
||||
workaround.insertAfter( retval );
|
||||
workaround.remove();
|
||||
}
|
||||
|
||||
return retval;
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts characters from indexA up to but not including indexB.
|
||||
* @param {Number} indexA An integer between 0 and one less than the
|
||||
* length of the text.
|
||||
* @param {Number} [indexB] An integer between 0 and the length of the
|
||||
* string. If omitted, extracts characters to the end of the text.
|
||||
*/
|
||||
substring : function( indexA, indexB )
|
||||
{
|
||||
// We need the following check due to a Firefox bug
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=458886
|
||||
if ( typeof indexB != 'number' )
|
||||
return this.$.nodeValue.substr( indexA );
|
||||
else
|
||||
return this.$.nodeValue.substring( indexA, indexB );
|
||||
}
|
||||
});
|
||||
445
ckeditor/_source/core/dom/walker.js
Normal file
445
ckeditor/_source/core/dom/walker.js
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
(function()
|
||||
{
|
||||
// This function is to be called under a "walker" instance scope.
|
||||
function iterate( rtl, breakOnFalse )
|
||||
{
|
||||
// Return null if we have reached the end.
|
||||
if ( this._.end )
|
||||
return null;
|
||||
|
||||
var node,
|
||||
range = this.range,
|
||||
guard,
|
||||
userGuard = this.guard,
|
||||
type = this.type,
|
||||
getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
|
||||
|
||||
// This is the first call. Initialize it.
|
||||
if ( !this._.start )
|
||||
{
|
||||
this._.start = 1;
|
||||
|
||||
// Trim text nodes and optmize the range boundaries. DOM changes
|
||||
// may happen at this point.
|
||||
range.trim();
|
||||
|
||||
// A collapsed range must return null at first call.
|
||||
if ( range.collapsed )
|
||||
{
|
||||
this.end();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the LTR guard function, if necessary.
|
||||
if ( !rtl && !this._.guardLTR )
|
||||
{
|
||||
// Gets the node that stops the walker when going LTR.
|
||||
var limitLTR = range.endContainer,
|
||||
blockerLTR = limitLTR.getChild( range.endOffset );
|
||||
|
||||
this._.guardLTR = function( node, movingOut )
|
||||
{
|
||||
return ( ( !movingOut || !limitLTR.equals( node ) )
|
||||
&& ( !blockerLTR || !node.equals( blockerLTR ) )
|
||||
&& ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || node.getName() != 'body' ) );
|
||||
};
|
||||
}
|
||||
|
||||
// Create the RTL guard function, if necessary.
|
||||
if ( rtl && !this._.guardRTL )
|
||||
{
|
||||
// Gets the node that stops the walker when going LTR.
|
||||
var limitRTL = range.startContainer,
|
||||
blockerRTL = ( range.startOffset > 0 ) && limitRTL.getChild( range.startOffset - 1 );
|
||||
|
||||
this._.guardRTL = function( node, movingOut )
|
||||
{
|
||||
return ( ( !movingOut || !limitRTL.equals( node ) )
|
||||
&& ( !blockerRTL || !node.equals( blockerRTL ) )
|
||||
&& ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || node.getName() != 'body' ) );
|
||||
};
|
||||
}
|
||||
|
||||
// Define which guard function to use.
|
||||
var stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
|
||||
|
||||
// Make the user defined guard function participate in the process,
|
||||
// otherwise simply use the boundary guard.
|
||||
if ( userGuard )
|
||||
{
|
||||
guard = function( node, movingOut )
|
||||
{
|
||||
if ( stopGuard( node, movingOut ) === false )
|
||||
return false;
|
||||
|
||||
return userGuard( node, movingOut );
|
||||
};
|
||||
}
|
||||
else
|
||||
guard = stopGuard;
|
||||
|
||||
if ( this.current )
|
||||
node = this.current[ getSourceNodeFn ]( false, type, guard );
|
||||
else
|
||||
{
|
||||
// Get the first node to be returned.
|
||||
|
||||
if ( rtl )
|
||||
{
|
||||
node = range.endContainer;
|
||||
|
||||
if ( range.endOffset > 0 )
|
||||
{
|
||||
node = node.getChild( range.endOffset - 1 );
|
||||
if ( guard( node ) === false )
|
||||
node = null;
|
||||
}
|
||||
else
|
||||
node = ( guard ( node, true ) === false ) ?
|
||||
null : node.getPreviousSourceNode( true, type, guard );
|
||||
}
|
||||
else
|
||||
{
|
||||
node = range.startContainer;
|
||||
node = node.getChild( range.startOffset );
|
||||
|
||||
if ( node )
|
||||
{
|
||||
if ( guard( node ) === false )
|
||||
node = null;
|
||||
}
|
||||
else
|
||||
node = ( guard ( range.startContainer, true ) === false ) ?
|
||||
null : range.startContainer.getNextSourceNode( true, type, guard ) ;
|
||||
}
|
||||
}
|
||||
|
||||
while ( node && !this._.end )
|
||||
{
|
||||
this.current = node;
|
||||
|
||||
if ( !this.evaluator || this.evaluator( node ) !== false )
|
||||
{
|
||||
if ( !breakOnFalse )
|
||||
return node;
|
||||
}
|
||||
else if ( breakOnFalse && this.evaluator )
|
||||
return false;
|
||||
|
||||
node = node[ getSourceNodeFn ]( false, type, guard );
|
||||
}
|
||||
|
||||
this.end();
|
||||
return this.current = null;
|
||||
}
|
||||
|
||||
function iterateToLast( rtl )
|
||||
{
|
||||
var node, last = null;
|
||||
|
||||
while ( ( node = iterate.call( this, rtl ) ) )
|
||||
last = node;
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
CKEDITOR.dom.walker = CKEDITOR.tools.createClass(
|
||||
{
|
||||
/**
|
||||
* Utility class to "walk" the DOM inside a range boundaries. If
|
||||
* necessary, partially included nodes (text nodes) are broken to
|
||||
* reflect the boundaries limits, so DOM and range changes may happen.
|
||||
* Outside changes to the range may break the walker.
|
||||
*
|
||||
* The walker may return nodes that are not totaly included into the
|
||||
* range boundaires. Let's take the following range representation,
|
||||
* where the square brackets indicate the boundaries:
|
||||
*
|
||||
* [<p>Some <b>sample] text</b>
|
||||
*
|
||||
* While walking forward into the above range, the following nodes are
|
||||
* returned: <p>, "Some ", <b> and "sample". Going
|
||||
* backwards instead we have: "sample" and "Some ". So note that the
|
||||
* walker always returns nodes when "entering" them, but not when
|
||||
* "leaving" them. The guard function is instead called both when
|
||||
* entering and leaving nodes.
|
||||
*
|
||||
* @constructor
|
||||
* @param {CKEDITOR.dom.range} range The range within which walk.
|
||||
*/
|
||||
$ : function( range )
|
||||
{
|
||||
this.range = range;
|
||||
|
||||
/**
|
||||
* A function executed for every matched node, to check whether
|
||||
* it's to be considered into the walk or not. If not provided, all
|
||||
* matched nodes are considered good.
|
||||
* If the function returns "false" the node is ignored.
|
||||
* @name CKEDITOR.dom.walker.prototype.evaluator
|
||||
* @property
|
||||
* @type Function
|
||||
*/
|
||||
// this.evaluator = null;
|
||||
|
||||
/**
|
||||
* A function executed for every node the walk pass by to check
|
||||
* whether the walk is to be finished. It's called when both
|
||||
* entering and exiting nodes, as well as for the matched nodes.
|
||||
* If this function returns "false", the walking ends and no more
|
||||
* nodes are evaluated.
|
||||
* @name CKEDITOR.dom.walker.prototype.guard
|
||||
* @property
|
||||
* @type Function
|
||||
*/
|
||||
// this.guard = null;
|
||||
|
||||
/** @private */
|
||||
this._ = {};
|
||||
},
|
||||
|
||||
// statics :
|
||||
// {
|
||||
// /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
|
||||
// * @param {CKEDITOR.dom.node} startNode The node from wich the walk
|
||||
// * will start.
|
||||
// * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
|
||||
// * in the walk. No more nodes are retrieved after touching or
|
||||
// * passing it. If not provided, the walker stops at the
|
||||
// * <body> closing boundary.
|
||||
// * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the
|
||||
// * provided nodes.
|
||||
// */
|
||||
// createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
|
||||
// {
|
||||
// var range = new CKEDITOR.dom.range();
|
||||
// if ( startNode )
|
||||
// range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
|
||||
// else
|
||||
// range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ;
|
||||
//
|
||||
// if ( endNode )
|
||||
// range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
|
||||
// else
|
||||
// range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
|
||||
//
|
||||
// return new CKEDITOR.dom.walker( range );
|
||||
// }
|
||||
// },
|
||||
//
|
||||
proto :
|
||||
{
|
||||
/**
|
||||
* Stop walking. No more nodes are retrieved if this function gets
|
||||
* called.
|
||||
*/
|
||||
end : function()
|
||||
{
|
||||
this._.end = 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the next node (at right).
|
||||
* @returns {CKEDITOR.dom.node} The next node or null if no more
|
||||
* nodes are available.
|
||||
*/
|
||||
next : function()
|
||||
{
|
||||
return iterate.call( this );
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the previous node (at left).
|
||||
* @returns {CKEDITOR.dom.node} The previous node or null if no more
|
||||
* nodes are available.
|
||||
*/
|
||||
previous : function()
|
||||
{
|
||||
return iterate.call( this, true );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check all nodes at right, executing the evaluation fuction.
|
||||
* @returns {Boolean} "false" if the evaluator function returned
|
||||
* "false" for any of the matched nodes. Otherwise "true".
|
||||
*/
|
||||
checkForward : function()
|
||||
{
|
||||
return iterate.call( this, false, true ) !== false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check all nodes at left, executing the evaluation fuction.
|
||||
* @returns {Boolean} "false" if the evaluator function returned
|
||||
* "false" for any of the matched nodes. Otherwise "true".
|
||||
*/
|
||||
checkBackward : function()
|
||||
{
|
||||
return iterate.call( this, true, true ) !== false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes a full walk forward (to the right), until no more nodes
|
||||
* are available, returning the last valid node.
|
||||
* @returns {CKEDITOR.dom.node} The last node at the right or null
|
||||
* if no valid nodes are available.
|
||||
*/
|
||||
lastForward : function()
|
||||
{
|
||||
return iterateToLast.call( this );
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes a full walk backwards (to the left), until no more nodes
|
||||
* are available, returning the last valid node.
|
||||
* @returns {CKEDITOR.dom.node} The last node at the left or null
|
||||
* if no valid nodes are available.
|
||||
*/
|
||||
lastBackward : function()
|
||||
{
|
||||
return iterateToLast.call( this, true );
|
||||
},
|
||||
|
||||
reset : function()
|
||||
{
|
||||
delete this.current;
|
||||
this._ = {};
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Anything whose display computed style is block, list-item, table,
|
||||
* table-row-group, table-header-group, table-footer-group, table-row,
|
||||
* table-column-group, table-column, table-cell, table-caption, or whose node
|
||||
* name is hr, br (when enterMode is br only) is a block boundary.
|
||||
*/
|
||||
var blockBoundaryDisplayMatch =
|
||||
{
|
||||
block : 1,
|
||||
'list-item' : 1,
|
||||
table : 1,
|
||||
'table-row-group' : 1,
|
||||
'table-header-group' : 1,
|
||||
'table-footer-group' : 1,
|
||||
'table-row' : 1,
|
||||
'table-column-group' : 1,
|
||||
'table-column' : 1,
|
||||
'table-cell' : 1,
|
||||
'table-caption' : 1
|
||||
},
|
||||
blockBoundaryNodeNameMatch = { hr : 1 };
|
||||
|
||||
CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames )
|
||||
{
|
||||
var nodeNameMatches = CKEDITOR.tools.extend( {},
|
||||
blockBoundaryNodeNameMatch, customNodeNames || {} );
|
||||
|
||||
return blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] ||
|
||||
nodeNameMatches[ this.getName() ];
|
||||
};
|
||||
|
||||
CKEDITOR.dom.walker.blockBoundary = function( customNodeNames )
|
||||
{
|
||||
return function( node , type )
|
||||
{
|
||||
return ! ( node.type == CKEDITOR.NODE_ELEMENT
|
||||
&& node.isBlockBoundary( customNodeNames ) );
|
||||
};
|
||||
};
|
||||
|
||||
CKEDITOR.dom.walker.listItemBoundary = function()
|
||||
{
|
||||
return this.blockBoundary( { br : 1 } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the to-be-evaluated node is a bookmark node OR bookmark node
|
||||
* inner contents.
|
||||
* @param {Boolean} contentOnly Whether only test againt the text content of
|
||||
* bookmark node instead of the element itself(default).
|
||||
* @param {Boolean} isReject Whether should return 'false' for the bookmark
|
||||
* node instead of 'true'(default).
|
||||
*/
|
||||
CKEDITOR.dom.walker.bookmark = function( contentOnly, isReject )
|
||||
{
|
||||
function isBookmarkNode( node )
|
||||
{
|
||||
return ( node && node.getName
|
||||
&& node.getName() == 'span'
|
||||
&& node.hasAttribute('_cke_bookmark') );
|
||||
}
|
||||
|
||||
return function( node )
|
||||
{
|
||||
var isBookmark, parent;
|
||||
// Is bookmark inner text node?
|
||||
isBookmark = ( node && !node.getName && ( parent = node.getParent() )
|
||||
&& isBookmarkNode( parent ) );
|
||||
// Is bookmark node?
|
||||
isBookmark = contentOnly ? isBookmark : isBookmark || isBookmarkNode( node );
|
||||
return isReject ^ isBookmark;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the node is a text node containing only whitespaces characters.
|
||||
* @param isReject
|
||||
*/
|
||||
CKEDITOR.dom.walker.whitespaces = function( isReject )
|
||||
{
|
||||
return function( node )
|
||||
{
|
||||
var isWhitespace = node && ( node.type == CKEDITOR.NODE_TEXT )
|
||||
&& !CKEDITOR.tools.trim( node.getText() );
|
||||
return isReject ^ isWhitespace;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the node is invisible in wysiwyg mode.
|
||||
* @param isReject
|
||||
*/
|
||||
CKEDITOR.dom.walker.invisible = function( isReject )
|
||||
{
|
||||
var whitespace = CKEDITOR.dom.walker.whitespaces();
|
||||
return function( node )
|
||||
{
|
||||
// Nodes that take no spaces in wysiwyg:
|
||||
// 1. White-spaces but not including NBSP;
|
||||
// 2. Empty inline elements, e.g. <b></b> we're checking here
|
||||
// 'offsetHeight' instead of 'offsetWidth' for properly excluding
|
||||
// all sorts of empty paragraph, e.g. <br />.
|
||||
var isInvisible = whitespace( node ) || node.is && !node.$.offsetHeight;
|
||||
return isReject ^ isInvisible;
|
||||
};
|
||||
};
|
||||
|
||||
var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/,
|
||||
isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
|
||||
isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ),
|
||||
fillerEvaluator = function( element )
|
||||
{
|
||||
return isNotBookmark( element ) && isNotWhitespaces( element );
|
||||
};
|
||||
|
||||
// Check if there's a filler node at the end of an element, and return it.
|
||||
CKEDITOR.dom.element.prototype.getBogus = function ()
|
||||
{
|
||||
var tail = this.getLast( fillerEvaluator );
|
||||
if ( tail && ( !CKEDITOR.env.ie ? tail.is && tail.is( 'br' )
|
||||
: tail.getText && tailNbspRegex.test( tail.getText() ) ) )
|
||||
{
|
||||
return tail;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
})();
|
||||
96
ckeditor/_source/core/dom/window.js
Normal file
96
ckeditor/_source/core/dom/window.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Defines the {@link CKEDITOR.dom.document} class, which
|
||||
* represents a DOM document.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a DOM window.
|
||||
* @constructor
|
||||
* @augments CKEDITOR.dom.domObject
|
||||
* @param {Object} domWindow A native DOM window.
|
||||
* @example
|
||||
* var document = new CKEDITOR.dom.window( window );
|
||||
*/
|
||||
CKEDITOR.dom.window = function( domWindow )
|
||||
{
|
||||
CKEDITOR.dom.domObject.call( this, domWindow );
|
||||
};
|
||||
|
||||
CKEDITOR.dom.window.prototype = new CKEDITOR.dom.domObject();
|
||||
|
||||
CKEDITOR.tools.extend( CKEDITOR.dom.window.prototype,
|
||||
/** @lends CKEDITOR.dom.window.prototype */
|
||||
{
|
||||
/**
|
||||
* Moves the selection focus to this window.
|
||||
* @function
|
||||
* @example
|
||||
* var win = new CKEDITOR.dom.window( window );
|
||||
* <b>win.focus()</b>;
|
||||
*/
|
||||
focus : function()
|
||||
{
|
||||
// Webkit is sometimes failed to focus iframe, blur it first(#3835).
|
||||
if ( CKEDITOR.env.webkit && this.$.parent )
|
||||
this.$.parent.focus();
|
||||
this.$.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the width and height of this window's viewable area.
|
||||
* @function
|
||||
* @returns {Object} An object with the "width" and "height"
|
||||
* properties containing the size.
|
||||
* @example
|
||||
* var win = new CKEDITOR.dom.window( window );
|
||||
* var size = <b>win.getViewPaneSize()</b>;
|
||||
* alert( size.width );
|
||||
* alert( size.height );
|
||||
*/
|
||||
getViewPaneSize : function()
|
||||
{
|
||||
var doc = this.$.document,
|
||||
stdMode = doc.compatMode == 'CSS1Compat';
|
||||
return {
|
||||
width : ( stdMode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
|
||||
height : ( stdMode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the current position of the window's scroll.
|
||||
* @function
|
||||
* @returns {Object} An object with the "x" and "y" properties
|
||||
* containing the scroll position.
|
||||
* @example
|
||||
* var win = new CKEDITOR.dom.window( window );
|
||||
* var pos = <b>win.getScrollPosition()</b>;
|
||||
* alert( pos.x );
|
||||
* alert( pos.y );
|
||||
*/
|
||||
getScrollPosition : function()
|
||||
{
|
||||
var $ = this.$;
|
||||
|
||||
if ( 'pageXOffset' in $ )
|
||||
{
|
||||
return {
|
||||
x : $.pageXOffset || 0,
|
||||
y : $.pageYOffset || 0
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var doc = $.document;
|
||||
return {
|
||||
x : doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
|
||||
y : doc.documentElement.scrollTop || doc.body.scrollTop || 0
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user