📄 fckstyle.js
字号:
this._Variables[ name ] = value ;
},
/**
* Converting from a PRE block to a non-PRE block in formatting operations.
*/
_FromPre : function( doc, block, newBlock )
{
var innerHTML = block.innerHTML ;
// Trim the first and last linebreaks immediately after and before <pre>, </pre>,
// if they exist.
// This is done because the linebreaks are not rendered.
innerHTML = innerHTML.replace( /(\r\n|\r)/g, '\n' ) ;
innerHTML = innerHTML.replace( /^[ \t]*\n/, '' ) ;
innerHTML = innerHTML.replace( /\n$/, '' ) ;
// 1. Convert spaces or tabs at the beginning or at the end to
innerHTML = innerHTML.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s )
{
if ( match.length == 1 ) // one space, preserve it
return ' ' ;
else if ( offset == 0 ) // beginning of block
return new Array( match.length ).join( ' ' ) + ' ' ;
else // end of block
return ' ' + new Array( match.length ).join( ' ' ) ;
} ) ;
// 2. Convert \n to <BR>.
// 3. Convert contiguous (i.e. non-singular) spaces or tabs to
var htmlIterator = new FCKHtmlIterator( innerHTML ) ;
var results = [] ;
htmlIterator.Each( function( isTag, value )
{
if ( !isTag )
{
value = value.replace( /\n/g, '<br>' ) ;
value = value.replace( /[ \t]{2,}/g,
function ( match )
{
return new Array( match.length ).join( ' ' ) + ' ' ;
} ) ;
}
results.push( value ) ;
} ) ;
newBlock.innerHTML = results.join( '' ) ;
return newBlock ;
},
/**
* Converting from a non-PRE block to a PRE block in formatting operations.
*/
_ToPre : function( doc, block, newBlock )
{
// Handle converting from a regular block to a <pre> block.
var innerHTML = block.innerHTML.Trim() ;
// 1. Delete ANSI whitespaces immediately before and after <BR> because
// they are not visible.
// 2. Mark down any <BR /> nodes here so they can be turned into \n in
// the next step and avoid being compressed.
innerHTML = innerHTML.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '<br />' ) ;
// 3. Compress other ANSI whitespaces since they're only visible as one
// single space previously.
// 4. Convert to spaces since is no longer needed in <PRE>.
// 5. Convert any <BR /> to \n. This must not be done earlier because
// the \n would then get compressed.
var htmlIterator = new FCKHtmlIterator( innerHTML ) ;
var results = [] ;
htmlIterator.Each( function( isTag, value )
{
if ( !isTag )
value = value.replace( /([ \t\n\r]+| )/g, ' ' ) ;
else if ( isTag && value == '<br />' )
value = '\n' ;
results.push( value ) ;
} ) ;
// Assigning innerHTML to <PRE> in IE causes all linebreaks to be
// reduced to spaces.
// Assigning outerHTML to <PRE> in IE doesn't work if the <PRE> isn't
// contained in another node since the node reference is changed after
// outerHTML assignment.
// So, we need some hacks to workaround IE bugs here.
if ( FCKBrowserInfo.IsIE )
{
var temp = doc.createElement( 'div' ) ;
temp.appendChild( newBlock ) ;
newBlock.outerHTML = '<pre>\n' + results.join( '' ) + '</pre>' ;
newBlock = temp.removeChild( temp.firstChild ) ;
}
else
newBlock.innerHTML = results.join( '' ) ;
return newBlock ;
},
/**
* Merge a <pre> block with a previous <pre> block, if available.
*/
_CheckAndMergePre : function( previousBlock, preBlock )
{
// Check if the previous block and the current block are next
// to each other.
if ( previousBlock != FCKDomTools.GetPreviousSourceElement( preBlock, true ) )
return ;
// Merge the previous <pre> block contents into the current <pre>
// block.
//
// Another thing to be careful here is that currentBlock might contain
// a '\n' at the beginning, and previousBlock might contain a '\n'
// towards the end. These new lines are not normally displayed but they
// become visible after merging.
var innerHTML = previousBlock.innerHTML.replace( /\n$/, '' ) + '\n\n' +
preBlock.innerHTML.replace( /^\n/, '' ) ;
// Buggy IE normalizes innerHTML from <pre>, breaking whitespaces.
if ( FCKBrowserInfo.IsIE )
preBlock.outerHTML = '<pre>' + innerHTML + '</pre>' ;
else
preBlock.innerHTML = innerHTML ;
// Remove the previous <pre> block.
//
// The preBlock must not be moved or deleted from the DOM tree. This
// guarantees the FCKDomRangeIterator in _ApplyBlockStyle would not
// get lost at the next iteration.
FCKDomTools.RemoveNode( previousBlock ) ;
},
_CheckAndSplitPre : function( newBlock )
{
var lastNewBlock ;
var cursor = newBlock.firstChild ;
// We are not splitting <br><br> at the beginning of the block, so
// we'll start from the second child.
cursor = cursor && cursor.nextSibling ;
while ( cursor )
{
var next = cursor.nextSibling ;
// If we have two <BR>s, and they're not at the beginning or the end,
// then we'll split up the contents following them into another block.
// Stop processing if we are at the last child couple.
if ( next && next.nextSibling && cursor.nodeName.IEquals( 'br' ) && next.nodeName.IEquals( 'br' ) )
{
// Remove the first <br>.
FCKDomTools.RemoveNode( cursor ) ;
// Move to the node after the second <br>.
cursor = next.nextSibling ;
// Remove the second <br>.
FCKDomTools.RemoveNode( next ) ;
// Create the block that will hold the child nodes from now on.
lastNewBlock = FCKDomTools.InsertAfterNode( lastNewBlock || newBlock, FCKDomTools.CloneElement( newBlock ) ) ;
continue ;
}
// If we split it, then start moving the nodes to the new block.
if ( lastNewBlock )
{
cursor = cursor.previousSibling ;
FCKDomTools.MoveNode(cursor.nextSibling, lastNewBlock ) ;
}
cursor = cursor.nextSibling ;
}
},
/**
* Apply an inline style to a FCKDomRange.
*
* TODO
* - Implement the "#" style handling.
* - Properly handle block containers like <div> and <blockquote>.
*/
_ApplyBlockStyle : function( range, selectIt, updateRange )
{
// Bookmark the range so we can re-select it after processing.
var bookmark ;
if ( selectIt )
bookmark = range.CreateBookmark() ;
var iterator = new FCKDomRangeIterator( range ) ;
iterator.EnforceRealBlocks = true ;
var block ;
var doc = range.Window.document ;
var previousPreBlock ;
while( ( block = iterator.GetNextParagraph() ) ) // Only one =
{
// Create the new node right before the current one.
var newBlock = this.BuildElement( doc ) ;
// Check if we are changing from/to <pre>.
var newBlockIsPre = newBlock.nodeName.IEquals( 'pre' ) ;
var blockIsPre = block.nodeName.IEquals( 'pre' ) ;
var toPre = newBlockIsPre && !blockIsPre ;
var fromPre = !newBlockIsPre && blockIsPre ;
// Move everything from the current node to the new one.
if ( toPre )
newBlock = this._ToPre( doc, block, newBlock ) ;
else if ( fromPre )
newBlock = this._FromPre( doc, block, newBlock ) ;
else // Convering from a regular block to another regular block.
FCKDomTools.MoveChildren( block, newBlock ) ;
// Replace the current block.
block.parentNode.insertBefore( newBlock, block ) ;
FCKDomTools.RemoveNode( block ) ;
// Complete other tasks after inserting the node in the DOM.
if ( newBlockIsPre )
{
if ( previousPreBlock )
this._CheckAndMergePre( previousPreBlock, newBlock ) ; // Merge successive <pre> blocks.
previousPreBlock = newBlock ;
}
else if ( fromPre )
this._CheckAndSplitPre( newBlock ) ; // Split <br><br> in successive <pre>s.
}
// Re-select the original range.
if ( selectIt )
range.SelectBookmark( bookmark ) ;
if ( updateRange )
range.MoveToBookmark( bookmark ) ;
},
/**
* Apply an inline style to a FCKDomRange.
*
* TODO
* - Merge elements, when applying styles to similar elements that enclose
* the entire selection, outputing:
* <span style="color: #ff0000; background-color: #ffffff">XYZ</span>
* instead of:
* <span style="color: #ff0000;"><span style="background-color: #ffffff">XYZ</span></span>
*/
_ApplyInlineStyle : function( range, selectIt, updateRange )
{
var doc = range.Window.document ;
if ( range.CheckIsCollapsed() )
{
// Create the element to be inserted in the DOM.
var collapsedElement = this.BuildElement( doc ) ;
range.InsertNode( collapsedElement ) ;
range.MoveToPosition( collapsedElement, 2 ) ;
range.Select() ;
return ;
}
// The general idea here is navigating through all nodes inside the
// current selection, working on distinct range blocks, defined by the
// DTD compatibility between the style element and the nodes inside the
// ranges.
//
// For example, suppose we have the following selection (where [ and ]
// are the boundaries), and we apply a <b> style there:
//
// <p>Here we [have <b>some</b> text.<p>
// <p>And some here] here.</p>
//
// Two different ranges will be detected:
//
// "have <b>some</b> text."
// "And some here"
//
// Both ranges will be extracted, moved to a <b> element, and
// re-inserted, resulting in the following output:
//
// <p>Here we [<b>have some text.</b><p>
// <p><b>And some here</b>] here.</p>
//
// Note that the <b> element at <b>some</b> is also removed because it
// is not needed anymore.
var elementName = this.Element ;
// Get the DTD definition for the element. Defaults to "span".
var elementDTD = FCK.DTD[ elementName ] || FCK.DTD.span ;
// Create the attribute list to be used later for element comparisons.
var styleAttribs = this._GetAttribsForComparison() ;
var styleNode ;
// Expand the range, if inside inline element boundaries.
range.Expand( 'inline_elements' ) ;
// Bookmark the range so we can re-select it after processing.
var bookmark = range.CreateBookmark( true ) ;
// The style will be applied within the bookmark boundaries.
var startNode = range.GetBookmarkNode( bookmark, true ) ;
var endNode = range.GetBookmarkNode( bookmark, false ) ;
// We'll be reusing the range to apply the styles. So, release it here
// to indicate that it has not been initialized.
range.Release( true ) ;
// Let's start the nodes lookup from the node right after the bookmark
// span.
var currentNode = FCKDomTools.GetNextSourceNode( startNode, true ) ;
while ( currentNode )
{
var applyStyle = false ;
var nodeType = currentNode.nodeType ;
var nodeName = nodeType == 1 ? currentNode.nodeName.toLowerCase() : null ;
// Check if the current node can be a child of the style element.
if ( !nodeName || elementDTD[ nodeName ] )
{
// Check if the style element can be a child of the current
// node parent or if the element is not defined in the DTD.
if ( ( FCK.DTD[ currentNode.parentNode.nodeName.toLowerCase() ] || FCK.DTD.span )[ elementName ] || !FCK.DTD[ elementName ] )
{
// This node will be part of our range, so if it has not
// been started, place its start right before the node.
if ( !range.CheckHasRange() )
range.SetStart( currentNode, 3 ) ;
// Non element nodes, or empty elements can be added
// completely to the range.
if ( nodeType != 1 || currentNode.childNodes.length == 0 )
{
var includedNode = currentNode ;
var parentNode = includedNode.parentNode ;
// This node is about to be included completelly, but,
// if this is the last node in its parent, we must also
// check if the parent itself can be added completelly
// to the range.
while ( includedNode == parentNode.lastChild
&& elementDTD[ parentNode.nodeName.toLowerCase() ] )
{
includedNode = parentNode ;
}
range.SetEnd( includedNode, 4 ) ;
// If the included node is the last node in its parent
// and its parent can't be inside the style node, apply
// the style immediately.
if ( includedNode == includedNode.parentNode.lastChild && !elementDTD[ includedNode.parentNode.nodeName.toLowerCase() ] )
applyStyle = true ;
}
else
{
// Element nodes will not be added directly. We need to
// check their children because the selection could end
// inside the node, so let's place the range end right
// before the element.
range.SetEnd( currentNode, 3 ) ;
}
}
else
applyStyle = true ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -