⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fckstyle.js

📁 一个用javascript写的可视化编辑器
💻 JS
📖 第 1 页 / 共 4 页
字号:

		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 &nbsp;
		innerHTML = innerHTML.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s )
				{
					if ( match.length == 1 )	// one space, preserve it
						return '&nbsp;' ;
					else if ( offset == 0 )		// beginning of block
						return new Array( match.length ).join( '&nbsp;' ) + ' ' ;
					else				// end of block
						return ' ' + new Array( match.length ).join( '&nbsp;' ) ;
				} ) ;

		// 2. Convert \n to <BR>.
		// 3. Convert contiguous (i.e. non-singular) spaces or tabs to &nbsp;
		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( '&nbsp;' ) + ' ' ;
							} ) ;
				}
				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 &nbsp; to spaces since &nbsp; 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]+|&nbsp;)/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 + -