+++ /dev/null
-/*\r
- * FCKeditor - The text editor for Internet - http://www.fckeditor.net\r
- * Copyright (C) 2003-2009 Frederico Caldeira Knabben\r
- *\r
- * == BEGIN LICENSE ==\r
- *\r
- * Licensed under the terms of any of the following licenses at your\r
- * choice:\r
- *\r
- * - GNU General Public License Version 2 or later (the "GPL")\r
- * http://www.gnu.org/licenses/gpl.html\r
- *\r
- * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")\r
- * http://www.gnu.org/licenses/lgpl.html\r
- *\r
- * - Mozilla Public License Version 1.1 or later (the "MPL")\r
- * http://www.mozilla.org/MPL/MPL-1.1.html\r
- *\r
- * == END LICENSE ==\r
- *\r
- * FCKIndentCommand Class: controls block indentation.\r
- */\r
-\r
-var FCKIndentCommand = function( name, offset )\r
-{\r
- this.Name = name ;\r
- this.Offset = offset ;\r
- this.IndentCSSProperty = FCKConfig.ContentLangDirection.IEquals( 'ltr' ) ? 'marginLeft' : 'marginRight' ;\r
-}\r
-\r
-FCKIndentCommand._InitIndentModeParameters = function()\r
-{\r
- if ( FCKConfig.IndentClasses && FCKConfig.IndentClasses.length > 0 )\r
- {\r
- this._UseIndentClasses = true ;\r
- this._IndentClassMap = {} ;\r
- for ( var i = 0 ; i < FCKConfig.IndentClasses.length ;i++ )\r
- this._IndentClassMap[FCKConfig.IndentClasses[i]] = i + 1 ;\r
- this._ClassNameRegex = new RegExp( '(?:^|\\s+)(' + FCKConfig.IndentClasses.join( '|' ) + ')(?=$|\\s)' ) ;\r
- }\r
- else\r
- this._UseIndentClasses = false ;\r
-}\r
-\r
-\r
-FCKIndentCommand.prototype =\r
-{\r
- Execute : function()\r
- {\r
- // Save an undo snapshot before doing anything.\r
- FCKUndo.SaveUndoStep() ;\r
-\r
- var range = new FCKDomRange( FCK.EditorWindow ) ;\r
- range.MoveToSelection() ;\r
- var bookmark = range.CreateBookmark() ;\r
-\r
- // Two cases to handle here: either we're in a list, or not.\r
- // If we're in a list, then the indent/outdent operations would be done on the list nodes.\r
- // Otherwise, apply the operation on the nearest block nodes.\r
- var nearestListBlock = FCKDomTools.GetCommonParentNode( range.StartNode || range.StartContainer ,\r
- range.EndNode || range.EndContainer,\r
- ['ul', 'ol'] ) ;\r
- if ( nearestListBlock )\r
- this._IndentList( range, nearestListBlock ) ;\r
- else\r
- this._IndentBlock( range ) ;\r
-\r
- range.MoveToBookmark( bookmark ) ;\r
- range.Select() ;\r
-\r
- FCK.Focus() ;\r
- FCK.Events.FireEvent( 'OnSelectionChange' ) ;\r
- },\r
-\r
- GetState : function()\r
- {\r
- // Disabled if not WYSIWYG.\r
- if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )\r
- return FCK_TRISTATE_DISABLED ;\r
-\r
- // Initialize parameters if not already initialzed.\r
- if ( FCKIndentCommand._UseIndentClasses == undefined )\r
- FCKIndentCommand._InitIndentModeParameters() ;\r
-\r
- // If we're not in a list, and the starting block's indentation is zero, and the current\r
- // command is the outdent command, then we should return FCK_TRISTATE_DISABLED.\r
- var startContainer = FCKSelection.GetBoundaryParentElement( true ) ;\r
- var endContainer = FCKSelection.GetBoundaryParentElement( false ) ;\r
- var listNode = FCKDomTools.GetCommonParentNode( startContainer, endContainer, ['ul','ol'] ) ;\r
-\r
- if ( listNode )\r
- {\r
- if ( this.Name.IEquals( 'outdent' ) )\r
- return FCK_TRISTATE_OFF ;\r
- var firstItem = FCKTools.GetElementAscensor( startContainer, 'li' ) ;\r
- if ( !firstItem || !firstItem.previousSibling )\r
- return FCK_TRISTATE_DISABLED ;\r
- return FCK_TRISTATE_OFF ;\r
- }\r
- if ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) )\r
- return FCK_TRISTATE_OFF;\r
-\r
- var path = new FCKElementPath( startContainer ) ;\r
- var firstBlock = path.Block || path.BlockLimit ;\r
- if ( !firstBlock )\r
- return FCK_TRISTATE_DISABLED ;\r
-\r
- if ( FCKIndentCommand._UseIndentClasses )\r
- {\r
- var indentClass = firstBlock.className.match( FCKIndentCommand._ClassNameRegex ) ;\r
- var indentStep = 0 ;\r
- if ( indentClass != null )\r
- {\r
- indentClass = indentClass[1] ;\r
- indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;\r
- }\r
- if ( ( this.Name == 'outdent' && indentStep == 0 ) ||\r
- ( this.Name == 'indent' && indentStep == FCKConfig.IndentClasses.length ) )\r
- return FCK_TRISTATE_DISABLED ;\r
- return FCK_TRISTATE_OFF ;\r
- }\r
- else\r
- {\r
- var indent = parseInt( firstBlock.style[this.IndentCSSProperty], 10 ) ;\r
- if ( isNaN( indent ) )\r
- indent = 0 ;\r
- if ( indent <= 0 )\r
- return FCK_TRISTATE_DISABLED ;\r
- return FCK_TRISTATE_OFF ;\r
- }\r
- },\r
-\r
- _IndentBlock : function( range )\r
- {\r
- var iterator = new FCKDomRangeIterator( range ) ;\r
- iterator.EnforceRealBlocks = true ;\r
-\r
- range.Expand( 'block_contents' ) ;\r
- var commonParents = FCKDomTools.GetCommonParents( range.StartContainer, range.EndContainer ) ;\r
- var nearestParent = commonParents[commonParents.length - 1] ;\r
- var block ;\r
-\r
- while ( ( block = iterator.GetNextParagraph() ) )\r
- {\r
- // We don't want to indent subtrees recursively, so only perform the indent operation\r
- // if the block itself is the nearestParent, or the block's parent is the nearestParent.\r
- if ( ! ( block == nearestParent || block.parentNode == nearestParent ) )\r
- continue ;\r
-\r
- if ( FCKIndentCommand._UseIndentClasses )\r
- {\r
- // Transform current class name to indent step index.\r
- var indentClass = block.className.match( FCKIndentCommand._ClassNameRegex ) ;\r
- var indentStep = 0 ;\r
- if ( indentClass != null )\r
- {\r
- indentClass = indentClass[1] ;\r
- indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;\r
- }\r
-\r
- // Operate on indent step index, transform indent step index back to class name.\r
- if ( this.Name.IEquals( 'outdent' ) )\r
- indentStep-- ;\r
- else if ( this.Name.IEquals( 'indent' ) )\r
- indentStep++ ;\r
- indentStep = Math.min( indentStep, FCKConfig.IndentClasses.length ) ;\r
- indentStep = Math.max( indentStep, 0 ) ;\r
- var className = block.className.replace( FCKIndentCommand._ClassNameRegex, '' ) ;\r
- if ( indentStep < 1 )\r
- block.className = className ;\r
- else\r
- block.className = ( className.length > 0 ? className + ' ' : '' ) +\r
- FCKConfig.IndentClasses[indentStep - 1] ;\r
- }\r
- else\r
- {\r
- // Offset distance is assumed to be in pixels for now.\r
- var currentOffset = parseInt( block.style[this.IndentCSSProperty], 10 ) ;\r
- if ( isNaN( currentOffset ) )\r
- currentOffset = 0 ;\r
- currentOffset += this.Offset ;\r
- currentOffset = Math.max( currentOffset, 0 ) ;\r
- currentOffset = Math.ceil( currentOffset / this.Offset ) * this.Offset ;\r
- block.style[this.IndentCSSProperty] = currentOffset ? currentOffset + FCKConfig.IndentUnit : '' ;\r
- if ( block.getAttribute( 'style' ) == '' )\r
- block.removeAttribute( 'style' ) ;\r
- }\r
- }\r
- },\r
-\r
- _IndentList : function( range, listNode )\r
- {\r
- // Our starting and ending points of the range might be inside some blocks under a list item...\r
- // So before playing with the iterator, we need to expand the block to include the list items.\r
- var startContainer = range.StartContainer ;\r
- var endContainer = range.EndContainer ;\r
- while ( startContainer && startContainer.parentNode != listNode )\r
- startContainer = startContainer.parentNode ;\r
- while ( endContainer && endContainer.parentNode != listNode )\r
- endContainer = endContainer.parentNode ;\r
-\r
- if ( ! startContainer || ! endContainer )\r
- return ;\r
-\r
- // Now we can iterate over the individual items on the same tree depth.\r
- var block = startContainer ;\r
- var itemsToMove = [] ;\r
- var stopFlag = false ;\r
- while ( stopFlag == false )\r
- {\r
- if ( block == endContainer )\r
- stopFlag = true ;\r
- itemsToMove.push( block ) ;\r
- block = block.nextSibling ;\r
- }\r
- if ( itemsToMove.length < 1 )\r
- return ;\r
-\r
- // Do indent or outdent operations on the array model of the list, not the list's DOM tree itself.\r
- // The array model demands that it knows as much as possible about the surrounding lists, we need\r
- // to feed it the further ancestor node that is still a list.\r
- var listParents = FCKDomTools.GetParents( listNode ) ;\r
- for ( var i = 0 ; i < listParents.length ; i++ )\r
- {\r
- if ( listParents[i].nodeName.IEquals( ['ul', 'ol'] ) )\r
- {\r
- listNode = listParents[i] ;\r
- break ;\r
- }\r
- }\r
- var indentOffset = this.Name.IEquals( 'indent' ) ? 1 : -1 ;\r
- var startItem = itemsToMove[0] ;\r
- var lastItem = itemsToMove[ itemsToMove.length - 1 ] ;\r
- var markerObj = {} ;\r
-\r
- // Convert the list DOM tree into a one dimensional array.\r
- var listArray = FCKDomTools.ListToArray( listNode, markerObj ) ;\r
-\r
- // Apply indenting or outdenting on the array.\r
- var baseIndent = listArray[lastItem._FCK_ListArray_Index].indent ;\r
- for ( var i = startItem._FCK_ListArray_Index ; i <= lastItem._FCK_ListArray_Index ; i++ )\r
- listArray[i].indent += indentOffset ;\r
- for ( var i = lastItem._FCK_ListArray_Index + 1 ; i < listArray.length && listArray[i].indent > baseIndent ; i++ )\r
- listArray[i].indent += indentOffset ;\r
-\r
- /* For debug use only\r
- var PrintArray = function( listArray, doc )\r
- {\r
- var s = [] ;\r
- for ( var i = 0 ; i < listArray.length ; i++ )\r
- {\r
- for ( var j in listArray[i] )\r
- {\r
- if ( j != 'contents' )\r
- s.push( j + ":" + listArray[i][j] + "; " ) ;\r
- else\r
- {\r
- var docFrag = doc.createDocumentFragment() ;\r
- var tmpNode = doc.createElement( 'span' ) ;\r
- for ( var k = 0 ; k < listArray[i][j].length ; k++ )\r
- docFrag.appendChild( listArray[i][j][k].cloneNode( true ) ) ;\r
- tmpNode.appendChild( docFrag ) ;\r
- s.push( j + ":" + tmpNode.innerHTML + "; ") ;\r
- }\r
- }\r
- s.push( '\n' ) ;\r
- }\r
- alert( s.join('') ) ;\r
- }\r
- PrintArray( listArray, FCK.EditorDocument ) ;\r
- */\r
-\r
- // Convert the array back to a DOM forest (yes we might have a few subtrees now).\r
- // And replace the old list with the new forest.\r
- var newList = FCKDomTools.ArrayToList( listArray ) ;\r
- if ( newList )\r
- listNode.parentNode.replaceChild( newList.listNode, listNode ) ;\r
-\r
- // Clean up the markers.\r
- FCKDomTools.ClearAllMarkers( markerObj ) ;\r
- }\r
-} ;\r