📄 fckstyle.js
字号:
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2008 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 ==
*
* FCKStyle Class: contains a style definition, and all methods to work with
* the style in a document.
*/
/**
* @param {Object} styleDesc A "style descriptor" object, containing the raw
* style definition in the following format:
* '<style name>' : {
* Element : '<element name>',
* Attributes : {
* '<att name>' : '<att value>',
* ...
* },
* Styles : {
* '<style name>' : '<style value>',
* ...
* },
* Overrides : '<element name>'|{
* Element : '<element name>',
* Attributes : {
* '<att name>' : '<att value>'|/<att regex>/
* },
* Styles : {
* '<style name>' : '<style value>'|/<style regex>/
* },
* }
* }
*/
var FCKStyle = function( styleDesc )
{
this.Element = ( styleDesc.Element || 'span' ).toLowerCase() ;
this._StyleDesc = styleDesc ;
}
FCKStyle.prototype =
{
/**
* Get the style type, based on its element name:
* - FCK_STYLE_BLOCK (0): Block Style
* - FCK_STYLE_INLINE (1): Inline Style
* - FCK_STYLE_OBJECT (2): Object Style
*/
GetType : function()
{
var type = this.GetType_$ ;
if ( type != undefined )
return type ;
var elementName = this.Element ;
if ( elementName == '#' || FCKListsLib.StyleBlockElements[ elementName ] )
type = FCK_STYLE_BLOCK ;
else if ( FCKListsLib.StyleObjectElements[ elementName ] )
type = FCK_STYLE_OBJECT ;
else
type = FCK_STYLE_INLINE ;
return ( this.GetType_$ = type ) ;
},
/**
* Apply the style to the current selection.
*/
ApplyToSelection : function( targetWindow )
{
// Create a range for the current selection.
var range = new FCKDomRange( targetWindow ) ;
range.MoveToSelection() ;
this.ApplyToRange( range, true ) ;
},
/**
* Apply the style to a FCKDomRange.
*/
ApplyToRange : function( range, selectIt, updateRange )
{
// ApplyToRange is not valid for FCK_STYLE_OBJECT types.
// Use ApplyToObject instead.
switch ( this.GetType() )
{
case FCK_STYLE_BLOCK :
this.ApplyToRange = this._ApplyBlockStyle ;
break ;
case FCK_STYLE_INLINE :
this.ApplyToRange = this._ApplyInlineStyle ;
break ;
default :
return ;
}
this.ApplyToRange( range, selectIt, updateRange ) ;
},
/**
* Apply the style to an object. Valid for FCK_STYLE_BLOCK types only.
*/
ApplyToObject : function( objectElement )
{
if ( !objectElement )
return ;
this.BuildElement( null, objectElement ) ;
},
/**
* Remove the style from the current selection.
*/
RemoveFromSelection : function( targetWindow )
{
// Create a range for the current selection.
var range = new FCKDomRange( targetWindow ) ;
range.MoveToSelection() ;
this.RemoveFromRange( range, true ) ;
},
/**
* Remove the style from a FCKDomRange. Block type styles will have no
* effect.
*/
RemoveFromRange : function( range, selectIt, updateRange )
{
var bookmark ;
// Create the attribute list to be used later for element comparisons.
var styleAttribs = this._GetAttribsForComparison() ;
var styleOverrides = this._GetOverridesForComparison() ;
// If collapsed, we are removing all conflicting styles from the range
// parent tree.
if ( range.CheckIsCollapsed() )
{
// Bookmark the range so we can re-select it after processing.
var bookmark = range.CreateBookmark( true ) ;
// Let's start from the bookmark <span> parent.
var bookmarkStart = range.GetBookmarkNode( bookmark, true ) ;
var path = new FCKElementPath( bookmarkStart.parentNode ) ;
// While looping through the path, we'll be saving references to
// parent elements if the range is in one of their boundaries. In
// this way, we are able to create a copy of those elements when
// removing a style if the range is in a boundary limit (see #1270).
var boundaryElements = [] ;
// Check if the range is in the boundary limits of an element
// (related to #1270).
var isBoundaryRight = !FCKDomTools.GetNextSibling( bookmarkStart ) ;
var isBoundary = isBoundaryRight || !FCKDomTools.GetPreviousSibling( bookmarkStart ) ;
// This is the last element to be removed in the boundary situation
// described at #1270.
var lastBoundaryElement ;
var boundaryLimitIndex = -1 ;
for ( var i = 0 ; i < path.Elements.length ; i++ )
{
var pathElement = path.Elements[i] ;
if ( this.CheckElementRemovable( pathElement ) )
{
if ( isBoundary
&& !FCKDomTools.CheckIsEmptyElement( pathElement,
function( el )
{
return ( el != bookmarkStart ) ;
} )
)
{
lastBoundaryElement = pathElement ;
// We'll be continuously including elements in the
// boundaryElements array, but only those added before
// setting lastBoundaryElement must be used later, so
// let's mark the current index here.
boundaryLimitIndex = boundaryElements.length - 1 ;
}
else
{
var pathElementName = pathElement.nodeName.toLowerCase() ;
if ( pathElementName == this.Element )
{
// Remove any attribute that conflict with this style, no
// matter their values.
for ( var att in styleAttribs )
{
if ( FCKDomTools.HasAttribute( pathElement, att ) )
{
switch ( att )
{
case 'style' :
this._RemoveStylesFromElement( pathElement ) ;
break ;
case 'class' :
// The 'class' element value must match (#1318).
if ( FCKDomTools.GetAttributeValue( pathElement, att ) != this.GetFinalAttributeValue( att ) )
continue ;
/*jsl:fallthru*/
default :
FCKDomTools.RemoveAttribute( pathElement, att ) ;
}
}
}
}
// Remove overrides defined to the same element name.
this._RemoveOverrides( pathElement, styleOverrides[ pathElementName ] ) ;
// Remove the element if no more attributes are available and it's an inline style element
if ( this.GetType() == FCK_STYLE_INLINE)
this._RemoveNoAttribElement( pathElement ) ;
}
}
else if ( isBoundary )
boundaryElements.push( pathElement ) ;
// Check if we are still in a boundary (at the same side).
isBoundary = isBoundary && ( ( isBoundaryRight && !FCKDomTools.GetNextSibling( pathElement ) ) || ( !isBoundaryRight && !FCKDomTools.GetPreviousSibling( pathElement ) ) ) ;
// If we are in an element that is not anymore a boundary, or
// we are at the last element, let's move things outside the
// boundary (if available).
if ( lastBoundaryElement && ( !isBoundary || ( i == path.Elements.length - 1 ) ) )
{
// Remove the bookmark node from the DOM.
var currentElement = FCKDomTools.RemoveNode( bookmarkStart ) ;
// Build the collapsed group of elements that are not
// removed by this style, but share the boundary.
// (see comment 1 and 2 at #1270)
for ( var j = 0 ; j <= boundaryLimitIndex ; j++ )
{
var newElement = FCKDomTools.CloneElement( boundaryElements[j] ) ;
newElement.appendChild( currentElement ) ;
currentElement = newElement ;
}
// Re-insert the bookmark node (and the collapsed elements)
// in the DOM, in the new position next to the styled element.
if ( isBoundaryRight )
FCKDomTools.InsertAfterNode( lastBoundaryElement, currentElement ) ;
else
lastBoundaryElement.parentNode.insertBefore( currentElement, lastBoundaryElement ) ;
isBoundary = false ;
lastBoundaryElement = null ;
}
}
// Re-select the original range.
if ( selectIt )
range.SelectBookmark( bookmark ) ;
if ( updateRange )
range.MoveToBookmark( bookmark ) ;
return ;
}
// Expand the range, if inside inline element boundaries.
range.Expand( 'inline_elements' ) ;
// Bookmark the range so we can re-select it after processing.
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 ) ;
range.Release( true ) ;
// We need to check the selection boundaries (bookmark spans) to break
// the code in a way that we can properly remove partially selected nodes.
// For example, removing a <b> style from
// <b>This is [some text</b> to show <b>the] problem</b>
// ... where [ and ] represent the selection, must result:
// <b>This is </b>[some text to show the]<b> problem</b>
// The strategy is simple, we just break the partial nodes before the
// removal logic, having something that could be represented this way:
// <b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
// Let's start checking the start boundary.
var path = new FCKElementPath( startNode ) ;
var pathElements = path.Elements ;
var pathElement ;
for ( var i = 1 ; i < pathElements.length ; i++ )
{
pathElement = pathElements[i] ;
if ( pathElement == path.Block || pathElement == path.BlockLimit )
break ;
// If this element can be removed (even partially).
if ( this.CheckElementRemovable( pathElement ) )
FCKDomTools.BreakParent( startNode, pathElement, range ) ;
}
// Now the end boundary.
path = new FCKElementPath( endNode ) ;
pathElements = path.Elements ;
for ( var i = 1 ; i < pathElements.length ; i++ )
{
pathElement = pathElements[i] ;
if ( pathElement == path.Block || pathElement == path.BlockLimit )
break ;
elementName = pathElement.nodeName.toLowerCase() ;
// If this element can be removed (even partially).
if ( this.CheckElementRemovable( pathElement ) )
FCKDomTools.BreakParent( endNode, pathElement, range ) ;
}
// Navigate through all nodes between the bookmarks.
var currentNode = FCKDomTools.GetNextSourceNode( startNode, true ) ;
while ( currentNode )
{
// Cache the next node to be processed. Do it now, because
// currentNode may be removed.
var nextNode = FCKDomTools.GetNextSourceNode( currentNode ) ;
// Remove elements nodes that match with this style rules.
if ( currentNode.nodeType == 1 )
{
var elementName = currentNode.nodeName.toLowerCase() ;
var mayRemove = ( elementName == this.Element ) ;
if ( mayRemove )
{
// Remove any attribute that conflict with this style, no matter
// their values.
for ( var att in styleAttribs )
{
if ( FCKDomTools.HasAttribute( currentNode, att ) )
{
switch ( att )
{
case 'style' :
this._RemoveStylesFromElement( currentNode ) ;
break ;
case 'class' :
// The 'class' element value must match (#1318).
if ( FCKDomTools.GetAttributeValue( currentNode, att ) != this.GetFinalAttributeValue( att ) )
continue ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -