fckdomrange.js
Summary
Class for working with a selection range, much like the W3C DOM Range, but
it is not intented to be an implementation of the W3C interface.
var FCKDomRange = function( sourceWindow )
{
this.Window = sourceWindow ;
}
FCKDomRange.prototype =
{
TypeName : 'FCKDomRange',
_UpdateElementInfo : function()
{
if ( !this._Range )
this.Release( true ) ;
else
{
var eStart = this._Range.startContainer ;
var eEnd = this._Range.endContainer ;
var oElementPath = new FCKElementPath( eStart ) ;
this.StartContainer = oElementPath.LastElement ;
this.StartBlock = oElementPath.Block ;
this.StartBlockLimit = oElementPath.BlockLimit ;
if ( eStart != eEnd )
oElementPath = new FCKElementPath( eEnd ) ;
this.EndContainer = oElementPath.LastElement ;
this.EndBlock = oElementPath.Block ;
this.EndBlockLimit = oElementPath.BlockLimit ;
}
},
CreateRange : function()
{
return new FCKW3CRange( this.Window.document ) ;
},
DeleteContents : function()
{
if ( this._Range )
{
this._Range.deleteContents() ;
this._UpdateElementInfo() ;
}
},
ExtractContents : function()
{
if ( this._Range )
{
var docFrag = this._Range.extractContents() ;
this._UpdateElementInfo() ;
return docFrag ;
}
},
CheckIsCollapsed : function()
{
if ( this._Range )
return this._Range.collapsed ;
},
Collapse : function( toStart )
{
if ( this._Range )
this._Range.collapse( toStart ) ;
this._UpdateElementInfo() ;
},
Clone : function()
{
var oClone = FCKTools.CloneObject( this ) ;
if ( this._Range )
oClone._Range = this._Range.cloneRange() ;
return oClone ;
},
MoveToNodeContents : function( targetNode )
{
if ( !this._Range )
this._Range = this.CreateRange() ;
this._Range.selectNodeContents( targetNode ) ;
this._UpdateElementInfo() ;
},
MoveToElementStart : function( targetElement )
{
this.SetStart(targetElement,1) ;
this.SetEnd(targetElement,1) ;
},
MoveToElementEditStart : function( targetElement )
{
var child ;
while ( ( child = targetElement.firstChild ) && child.nodeType == 1 && FCKListsLib.EmptyElements[ child.nodeName.toLowerCase() ] == null )
targetElement = child ;
this.MoveToElementStart( targetElement ) ;
},
InsertNode : function( node )
{
if ( this._Range )
this._Range.insertNode( node ) ;
},
CheckIsEmpty : function( ignoreEndBRs )
{
if ( this.CheckIsCollapsed() )
return true ;
var eToolDiv = this.Window.document.createElement( 'div' ) ;
this._Range.cloneContents().AppendTo( eToolDiv ) ;
FCKDomTools.TrimNode( eToolDiv, ignoreEndBRs ) ;
return ( eToolDiv.innerHTML.length == 0 ) ;
},
CheckStartOfBlock : function()
{
var oTestRange = this.Clone() ;
oTestRange.Collapse( true ) ;
oTestRange.SetStart( oTestRange.StartBlock || oTestRange.StartBlockLimit, 1 ) ;
var bIsStartOfBlock = oTestRange.CheckIsEmpty() ;
oTestRange.Release() ;
return bIsStartOfBlock ;
},
CheckEndOfBlock : function( refreshSelection )
{
var oTestRange = this.Clone() ;
oTestRange.Collapse( false ) ;
oTestRange.SetEnd( oTestRange.EndBlock || oTestRange.EndBlockLimit, 2 ) ;
var bIsEndOfBlock = oTestRange.CheckIsCollapsed() ;
if ( !bIsEndOfBlock )
{
var eToolDiv = this.Window.document.createElement( 'div' ) ;
oTestRange._Range.cloneContents().AppendTo( eToolDiv ) ;
FCKDomTools.TrimNode( eToolDiv, true ) ;
bIsEndOfBlock = true ;
var eLastChild = eToolDiv ;
while ( ( eLastChild = eLastChild.lastChild ) )
{
if ( eLastChild.previousSibling || eLastChild.nodeType != 1 || FCKListsLib.InlineChildReqElements[ eLastChild.nodeName.toLowerCase() ] == null )
{
bIsEndOfBlock = false ;
break ;
}
}
}
oTestRange.Release() ;
if ( refreshSelection )
this.Select() ;
return bIsEndOfBlock ;
},
CreateBookmark : function()
{
var oBookmark =
{
StartId : 'fck_dom_range_start_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000),
EndId : 'fck_dom_range_end_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000)
} ;
var oDoc = this.Window.document ;
var eSpan ;
var oClone ;
if ( !this.CheckIsCollapsed() )
{
eSpan = oDoc.createElement( 'span' ) ;
eSpan.id = oBookmark.EndId ;
eSpan.innerHTML = ' ' ;
oClone = this.Clone() ;
oClone.Collapse( false ) ;
oClone.InsertNode( eSpan ) ;
}
eSpan = oDoc.createElement( 'span' ) ;
eSpan.id = oBookmark.StartId ;
eSpan.innerHTML = ' ' ;
oClone = this.Clone() ;
oClone.Collapse( true ) ;
oClone.InsertNode( eSpan ) ;
return oBookmark ;
},
MoveToBookmark : function( bookmark, preserveBookmark )
{
var oDoc = this.Window.document ;
var eStartSpan = oDoc.getElementById( bookmark.StartId ) ;
var eEndSpan = oDoc.getElementById( bookmark.EndId ) ;
this.SetStart( eStartSpan, 3 ) ;
if ( !preserveBookmark )
FCKDomTools.RemoveNode( eStartSpan ) ;
if ( eEndSpan )
{
this.SetEnd( eEndSpan, 3 ) ;
if ( !preserveBookmark )
FCKDomTools.RemoveNode( eEndSpan ) ;
}
else
this.Collapse( true ) ;
this._UpdateElementInfo() ;
},
MoveToPosition : function( targetElement, position )
{
this.SetStart( targetElement, position ) ;
this.Collapse( true ) ;
},
SetStart : function( targetElement, position )
{
var oRange = this._Range ;
if ( !oRange )
oRange = this._Range = this.CreateRange() ;
switch( position )
{
case 1 :
oRange.setStart( targetElement, 0 ) ;
break ;
case 2 :
oRange.setStart( targetElement, targetElement.childNodes.length ) ;
break ;
case 3 :
oRange.setStartBefore( targetElement ) ;
break ;
case 4 :
oRange.setStartAfter( targetElement ) ;
}
this._UpdateElementInfo() ;
},
SetEnd : function( targetElement, position )
{
var oRange = this._Range ;
if ( !oRange )
oRange = this._Range = this.CreateRange() ;
switch( position )
{
case 1 :
oRange.setEnd( targetElement, 0 ) ;
break ;
case 2 :
oRange.setEnd( targetElement, targetElement.childNodes.length ) ;
break ;
case 3 :
oRange.setEndBefore( targetElement ) ;
break ;
case 4 :
oRange.setEndAfter( targetElement ) ;
}
this._UpdateElementInfo() ;
},
Expand : function( unit )
{
var oNode, oSibling ;
switch ( unit )
{
case 'block_contents' :
if ( this.StartBlock )
this.SetStart( this.StartBlock, 1 ) ;
else
{
oNode = this._Range.startContainer ;
if ( oNode.nodeType == 1 )
{
if ( !( oNode = oNode.childNodes[ this._Range.startOffset ] ) )
oNode = oNode.firstChild ;
}
if ( !oNode )
return ;
while ( true )
{
oSibling = oNode.previousSibling ;
if ( !oSibling )
{
if ( oNode.parentNode != this.StartBlockLimit )
oNode = oNode.parentNode ;
else
break ;
}
else if ( oSibling.nodeType != 1 || !(/^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/).test( oSibling.nodeName.toUpperCase() ) )
{
oNode = oSibling ;
}
else
break ;
}
this._Range.setStartBefore( oNode ) ;
}
if ( this.EndBlock )
this.SetEnd( this.EndBlock, 2 ) ;
else
{
oNode = this._Range.endContainer ;
if ( oNode.nodeType == 1 )
oNode = oNode.childNodes[ this._Range.endOffset ] || oNode.lastChild ;
if ( !oNode )
return ;
while ( true )
{
oSibling = oNode.nextSibling ;
if ( !oSibling )
{
if ( oNode.parentNode != this.EndBlockLimit )
oNode = oNode.parentNode ;
else
break ;
}
else if ( oSibling.nodeType != 1 || !(/^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/).test( oSibling.nodeName.toUpperCase() ) )
{
oNode = oSibling ;
}
else
break ;
}
this._Range.setEndAfter( oNode ) ;
}
this._UpdateElementInfo() ;
break ;
default :
throw( 'Invalid unit "' + unit + '"' ) ;
}
},
SplitBlock : function()
{
if ( !this._Range )
this.MoveToSelection() ;
if ( this.StartBlockLimit == this.EndBlockLimit )
{
var eStartBlock = this.StartBlock ;
var eEndBlock = this.EndBlock ;
if ( FCKConfig.EnterMode != 'br' )
{
if ( !eStartBlock )
{
eStartBlock = this._FixBlock( true ) ;
eEndBlock = this.EndBlock ;
}
if ( !eEndBlock )
eEndBlock = this._FixBlock( false ) ;
}
var bIsStartOfBlock = ( eStartBlock != null && this.CheckStartOfBlock() ) ;
var bIsEndOfBlock = ( eEndBlock != null && this.CheckEndOfBlock() ) ;
if ( !this.CheckIsEmpty() )
this.DeleteContents() ;
if ( eStartBlock && eEndBlock && eStartBlock == eEndBlock )
{
if ( bIsStartOfBlock )
{
this.MoveToPosition( eStartBlock, 3 ) ;
eStartBlock = null ;
}
else if ( bIsEndOfBlock )
{
this.MoveToPosition( eEndBlock, 4 ) ;
eEndBlock = null ;
}
else
{
this.SetEnd( eStartBlock, 2 ) ;
var eDocFrag = this.ExtractContents() ;
FCKDomTools.TrimNode( eDocFrag.RootNode ) ;
eEndBlock = eStartBlock.cloneNode( false ) ;
eDocFrag.AppendTo( eEndBlock ) ;
FCKDomTools.InsertAfterNode( eStartBlock, eEndBlock ) ;
this.MoveToPosition( eStartBlock, 4 ) ;
}
}
if ( FCKBrowserInfo.IsGecko )
{
FCKTools.AppendBogusBr( eStartBlock ) ;
FCKTools.AppendBogusBr( eEndBlock ) ;
}
return {
PreviousBlock : eStartBlock,
NextBlock : eEndBlock,
WasStartOfBlock : bIsStartOfBlock,
WasEndOfBlock : bIsEndOfBlock
} ;
}
return null ;
},
_FixBlock : function( isStart )
{
var oBookmark = this.CreateBookmark() ;
this.Collapse( isStart ) ;
this.Expand( 'block_contents' ) ;
var oFixedBlock = this.Window.document.createElement( FCKConfig.EnterMode ) ;
this.ExtractContents().AppendTo( oFixedBlock ) ;
FCKDomTools.TrimNode( oFixedBlock ) ;
this.InsertNode( oFixedBlock ) ;
this.MoveToBookmark( oBookmark ) ;
return oFixedBlock ;
},
Release : function( preserveWindow )
{
if ( !preserveWindow )
this.Window = null ;
this.StartContainer = null ;
this.StartBlock = null ;
this.StartBlockLimit = null ;
this.EndContainer = null ;
this.EndBlock = null ;
this.EndBlockLimit = null ;
this._Range = null ;
}
} ;
Documentation generated by
JSDoc on Mon May 28 23:41:52 2007