?? fckdomtools.js
字號:
?/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Utility functions to work with the DOM.
*/
var FCKDomTools =
{
MoveChildren : function( source, target, toTargetStart )
{
if ( source == target )
return ;
var eChild ;
if ( toTargetStart )
{
while ( (eChild = source.lastChild) )
target.insertBefore( source.removeChild( eChild ), target.firstChild ) ;
}
else
{
while ( (eChild = source.firstChild) )
target.appendChild( source.removeChild( eChild ) ) ;
}
},
MoveNode : function( source, target, toTargetStart )
{
if ( toTargetStart )
target.insertBefore( FCKDomTools.RemoveNode( source ), target.firstChild ) ;
else
target.appendChild( FCKDomTools.RemoveNode( source ) ) ;
},
// Remove blank spaces from the beginning and the end of the contents of a node.
TrimNode : function( node )
{
this.LTrimNode( node ) ;
this.RTrimNode( node ) ;
},
LTrimNode : function( node )
{
var eChildNode ;
while ( (eChildNode = node.firstChild) )
{
if ( eChildNode.nodeType == 3 )
{
var sTrimmed = eChildNode.nodeValue.LTrim() ;
var iOriginalLength = eChildNode.nodeValue.length ;
if ( sTrimmed.length == 0 )
{
node.removeChild( eChildNode ) ;
continue ;
}
else if ( sTrimmed.length < iOriginalLength )
{
eChildNode.splitText( iOriginalLength - sTrimmed.length ) ;
node.removeChild( node.firstChild ) ;
}
}
break ;
}
},
RTrimNode : function( node )
{
var eChildNode ;
while ( (eChildNode = node.lastChild) )
{
if ( eChildNode.nodeType == 3 )
{
var sTrimmed = eChildNode.nodeValue.RTrim() ;
var iOriginalLength = eChildNode.nodeValue.length ;
if ( sTrimmed.length == 0 )
{
// If the trimmed text node is empty, just remove it.
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#81).
eChildNode.parentNode.removeChild( eChildNode ) ;
continue ;
}
else if ( sTrimmed.length < iOriginalLength )
{
// If the trimmed text length is less than the original
// length, strip all spaces from the end by splitting
// the text and removing the resulting useless node.
eChildNode.splitText( sTrimmed.length ) ;
// Use "node.lastChild.parentNode" instead of "node" to avoid IE bug (#81).
node.lastChild.parentNode.removeChild( node.lastChild ) ;
}
}
break ;
}
if ( !FCKBrowserInfo.IsIE && !FCKBrowserInfo.IsOpera )
{
eChildNode = node.lastChild ;
if ( eChildNode && eChildNode.nodeType == 1 && eChildNode.nodeName.toLowerCase() == 'br' )
{
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).
eChildNode.parentNode.removeChild( eChildNode ) ;
}
}
},
RemoveNode : function( node, excludeChildren )
{
if ( excludeChildren )
{
// Move all children before the node.
var eChild ;
while ( (eChild = node.firstChild) )
node.parentNode.insertBefore( node.removeChild( eChild ), node ) ;
}
return node.parentNode.removeChild( node ) ;
},
GetFirstChild : function( node, childNames )
{
// If childNames is a string, transform it in a Array.
if ( typeof ( childNames ) == 'string' )
childNames = [ childNames ] ;
var eChild = node.firstChild ;
while( eChild )
{
if ( eChild.nodeType == 1 && eChild.tagName.Equals.apply( eChild.tagName, childNames ) )
return eChild ;
eChild = eChild.nextSibling ;
}
return null ;
},
GetLastChild : function( node, childNames )
{
// If childNames is a string, transform it in a Array.
if ( typeof ( childNames ) == 'string' )
childNames = [ childNames ] ;
var eChild = node.lastChild ;
while( eChild )
{
if ( eChild.nodeType == 1 && ( !childNames || eChild.tagName.Equals( childNames ) ) )
return eChild ;
eChild = eChild.previousSibling ;
}
return null ;
},
/*
* Gets the previous element (nodeType=1) in the source order. Returns
* "null" If no element is found.
* @param {Object} currentNode The node to start searching from.
* @param {Boolean} ignoreSpaceTextOnly Sets how text nodes will be
* handled. If set to "true", only white spaces text nodes
* will be ignored, while non white space text nodes will stop
* the search, returning null. If "false" or omitted, all
* text nodes are ignored.
* @param {string[]} stopSearchElements An array of element names that
* will cause the search to stop when found, returning null.
* May be omitted (or null).
* @param {string[]} ignoreElements An array of element names that
* must be ignored during the search.
*/
GetPreviousSourceElement : function( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements )
{
if ( !currentNode )
return null ;
if ( stopSearchElements && currentNode.nodeType == 1 && currentNode.nodeName.IEquals( stopSearchElements ) )
return null ;
if ( currentNode.previousSibling )
currentNode = currentNode.previousSibling ;
else
return this.GetPreviousSourceElement( currentNode.parentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
while ( currentNode )
{
if ( currentNode.nodeType == 1 )
{
if ( stopSearchElements && currentNode.nodeName.IEquals( stopSearchElements ) )
break ;
if ( !ignoreElements || !currentNode.nodeName.IEquals( ignoreElements ) )
return currentNode ;
}
else if ( ignoreSpaceTextOnly && currentNode.nodeType == 3 && currentNode.nodeValue.RTrim().length > 0 )
break ;
if ( currentNode.lastChild )
currentNode = currentNode.lastChild ;
else
return this.GetPreviousSourceElement( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
}
return null ;
},
/*
* Gets the next element (nodeType=1) in the source order. Returns
* "null" If no element is found.
* @param {Object} currentNode The node to start searching from.
* @param {Boolean} ignoreSpaceTextOnly Sets how text nodes will be
* handled. If set to "true", only white spaces text nodes
* will be ignored, while non white space text nodes will stop
* the search, returning null. If "false" or omitted, all
* text nodes are ignored.
* @param {string[]} stopSearchElements An array of element names that
* will cause the search to stop when found, returning null.
* May be omitted (or null).
* @param {string[]} ignoreElements An array of element names that
* must be ignored during the search.
*/
GetNextSourceElement : function( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements, startFromSibling )
{
while( ( currentNode = this.GetNextSourceNode( currentNode, startFromSibling ) ) ) // Only one "=".
{
if ( currentNode.nodeType == 1 )
{
if ( stopSearchElements && currentNode.nodeName.IEquals( stopSearchElements ) )
break ;
if ( ignoreElements && currentNode.nodeName.IEquals( ignoreElements ) )
return this.GetNextSourceElement( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
return currentNode ;
}
else if ( ignoreSpaceTextOnly && currentNode.nodeType == 3 && currentNode.nodeValue.RTrim().length > 0 )
break ;
}
return null ;
},
/*
* Get the next DOM node available in source order.
*/
GetNextSourceNode : function( currentNode, startFromSibling, nodeType, stopSearchNode )
{
if ( !currentNode )
return null ;
var node ;
if ( !startFromSibling && currentNode.firstChild )
node = currentNode.firstChild ;
else
{
if ( stopSearchNode && currentNode == stopSearchNode )
return null ;
node = currentNode.nextSibling ;
if ( !node && ( !stopSearchNode || stopSearchNode != currentNode.parentNode ) )
return this.GetNextSourceNode( currentNode.parentNode, true, nodeType, stopSearchNode ) ;
}
if ( nodeType && node && node.nodeType != nodeType )
return this.GetNextSourceNode( node, false, nodeType, stopSearchNode ) ;
return node ;
},
/*
* Get the next DOM node available in source order.
*/
GetPreviousSourceNode : function( currentNode, startFromSibling, nodeType, stopSearchNode )
{
if ( !currentNode )
return null ;
var node ;
if ( !startFromSibling && currentNode.lastChild )
node = currentNode.lastChild ;
else
{
if ( stopSearchNode && currentNode == stopSearchNode )
return null ;
node = currentNode.previousSibling ;
if ( !node && ( !stopSearchNode || stopSearchNode != currentNode.parentNode ) )
return this.GetPreviousSourceNode( currentNode.parentNode, true, nodeType, stopSearchNode ) ;
}
if ( nodeType && node && node.nodeType != nodeType )
return this.GetPreviousSourceNode( node, false, nodeType, stopSearchNode ) ;
return node ;
},
// Inserts a element after a existing one.
InsertAfterNode : function( existingNode, newNode )
{
return existingNode.parentNode.insertBefore( newNode, existingNode.nextSibling ) ;
},
GetParents : function( node )
{
var parents = new Array() ;
while ( node )
{
parents.unshift( node ) ;
node = node.parentNode ;
}
return parents ;
},
GetCommonParents : function( node1, node2 )
{
var p1 = this.GetParents( node1 ) ;
var p2 = this.GetParents( node2 ) ;
var retval = [] ;
for ( var i = 0 ; i < p1.length ; i++ )
{
if ( p1[i] == p2[i] )
retval.push( p1[i] ) ;
}
return retval ;
},
GetCommonParentNode : function( node1, node2, tagList )
{
var tagMap = {} ;
if ( ! tagList.pop )
tagList = [ tagList ] ;
while ( tagList.length > 0 )
tagMap[tagList.pop().toLowerCase()] = 1 ;
var commonParents = this.GetCommonParents( node1, node2 ) ;
var currentParent = null ;
while ( ( currentParent = commonParents.pop() ) )
{
if ( tagMap[currentParent.nodeName.toLowerCase()] )
return currentParent ;
}
return null ;
},
GetIndexOf : function( node )
{
var currentNode = node.parentNode ? node.parentNode.firstChild : null ;
var currentIndex = -1 ;
while ( currentNode )
{
currentIndex++ ;
if ( currentNode == node )
return currentIndex ;
currentNode = currentNode.nextSibling ;
}
return -1 ;
},
PaddingNode : null,
EnforcePaddingNode : function( doc, tagName )
{
// In IE it can happen when the page is reloaded that doc or doc.body is null, so exit here
try
{
if ( !doc || !doc.body )
return ;
}
catch (e)
{
return ;
}
this.CheckAndRemovePaddingNode( doc, tagName, true ) ;
try
{
if ( doc.body.lastChild && ( doc.body.lastChild.nodeType != 1
|| doc.body.lastChild.tagName.toLowerCase() == tagName.toLowerCase() ) )
return ;
}
catch (e)
{
return ;
}
var node = doc.createElement( tagName ) ;
if ( FCKBrowserInfo.IsGecko && FCKListsLib.NonEmptyBlockElements[ tagName ] )
FCKTools.AppendBogusBr( node ) ;
this.PaddingNode = node ;
if ( doc.body.childNodes.length == 1
&& doc.body.firstChild.nodeType == 1
&& doc.body.firstChild.tagName.toLowerCase() == 'br'
&& ( doc.body.firstChild.getAttribute( '_moz_dirty' ) != null
|| doc.body.firstChild.getAttribute( 'type' ) == '_moz' ) )
doc.body.replaceChild( node, doc.body.firstChild ) ;
else
doc.body.appendChild( node ) ;
},
CheckAndRemovePaddingNode : function( doc, tagName, dontRemove )
{
var paddingNode = this.PaddingNode ;
if ( ! paddingNode )
return ;
// If the padding node is changed, remove its status as a padding node.
try
{
if ( paddingNode.parentNode != doc.body
|| paddingNode.tagName.toLowerCase() != tagName
|| ( paddingNode.childNodes.length > 1 )
|| ( paddingNode.firstChild && paddingNode.firstChild.nodeValue != '\xa0'
&& String(paddingNode.firstChild.tagName).toLowerCase() != 'br' ) )
{
this.PaddingNode = null ;
return ;
}
}
catch (e)
{
this.PaddingNode = null ;
return ;
}
// Now we're sure the padding node exists, and it is unchanged, and it
// isn't the only node in doc.body, remove it.
if ( !dontRemove )
{
if ( paddingNode.parentNode.childNodes.length > 1 )
paddingNode.parentNode.removeChild( paddingNode ) ;
this.PaddingNode = null ;
}
},
HasAttribute : function( element, attributeName )
{
if ( element.hasAttribute )
return element.hasAttribute( attributeName ) ;
else
{
var att = element.attributes[ attributeName ] ;
return ( att != undefined && att.specified ) ;
}
},
/**
* Checks if an element has "specified" attributes.
*/
HasAttributes : function( element )
{
var attributes = element.attributes ;
for ( var i = 0 ; i < attributes.length ; i++ )
{
if ( FCKBrowserInfo.IsIE && attributes[i].nodeName == 'class' )
{
// IE has a strange bug. If calling removeAttribute('className'),
// the attributes collection will still contain the "class"
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -