1/*
2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3 * Copyright (C) 2003-2007 Frederico Caldeira Knabben
4 *
5 * == BEGIN LICENSE ==
6 *
7 * Licensed under the terms of any of the following licenses at your
8 * choice:
9 *
10 *  - GNU General Public License Version 2 or later (the "GPL")
11 *    http://www.gnu.org/licenses/gpl.html
12 *
13 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14 *    http://www.gnu.org/licenses/lgpl.html
15 *
16 *  - Mozilla Public License Version 1.1 or later (the "MPL")
17 *    http://www.mozilla.org/MPL/MPL-1.1.html
18 *
19 * == END LICENSE ==
20 *
21 * FCKJustifyCommand Class: controls block justification.
22 */
23
24var FCKJustifyCommand = function( alignValue )
25{
26	this.AlignValue = alignValue ;
27
28	// Detect whether this is the instance for the default alignment.
29	var contentDir = FCKConfig.ContentLangDirection.toLowerCase() ;
30	this.IsDefaultAlign = ( alignValue == 'left' && contentDir == 'ltr' ) ||
31						  ( alignValue == 'right' && contentDir == 'rtl' ) ;
32
33	// Get the class name to be used by this instance.
34	var cssClassName = this._CssClassName = ( function()
35	{
36		var classes = FCKConfig.JustifyClasses ;
37		if ( classes )
38		{
39			switch ( alignValue )
40			{
41				case 'left' :
42					return classes[0] ;
43				case 'center' :
44					return classes[1] ;
45				case 'right' :
46					return classes[2] ;
47				case 'justify' :
48					return classes[3] ;
49			}
50		}
51		return null ;
52	} )() ;
53
54	if ( cssClassName && cssClassName.length > 0 )
55		this._CssClassRegex = new RegExp( '(?:^|\\s+)' + cssClassName + '(?=$|\\s)' ) ;
56}
57
58FCKJustifyCommand._GetClassNameRegex = function()
59{
60	var regex = FCKJustifyCommand._ClassRegex ;
61	if ( regex != undefined )
62		return regex ;
63
64	var names = [] ;
65
66	var classes = FCKConfig.JustifyClasses ;
67	if ( classes )
68	{
69		for ( var i = 0 ; i < 4 ; i++ )
70		{
71			var className = classes[i] ;
72			if ( className && className.length > 0 )
73				names.push( className ) ;
74		}
75	}
76
77	if ( names.length > 0 )
78		regex = new RegExp( '(?:^|\\s+)(?:' + names.join( '|' ) + ')(?=$|\\s)' ) ;
79	else
80		regex = null ;
81
82	return FCKJustifyCommand._ClassRegex = regex ;
83}
84
85FCKJustifyCommand.prototype =
86{
87	Execute : function()
88	{
89		// Save an undo snapshot before doing anything.
90		FCKUndo.SaveUndoStep() ;
91
92		var range = new FCKDomRange( FCK.EditorWindow ) ;
93		range.MoveToSelection() ;
94
95		var currentState = this.GetState() ;
96		if ( currentState == FCK_TRISTATE_DISABLED )
97			return ;
98
99		// Store a bookmark of the selection since the paragraph iterator might
100		// change the DOM tree and break selections.
101		var bookmark = range.CreateBookmark() ;
102
103		var cssClassName = this._CssClassName ;
104
105		// Apply alignment setting for each paragraph.
106		var iterator = new FCKDomRangeIterator( range ) ;
107		var block ;
108		while ( ( block = iterator.GetNextParagraph() ) )
109		{
110			block.removeAttribute( 'align' ) ;
111
112			if ( cssClassName )
113			{
114				// Remove the any of the alignment classes from the className.
115				var className = block.className.replace( FCKJustifyCommand._GetClassNameRegex(), '' ) ;
116
117				// Append the desired class name.
118				if ( currentState == FCK_TRISTATE_OFF )
119				{
120					if ( className.length > 0 )
121						className += ' ' ;
122					block.className = className + cssClassName ;
123				}
124				else if ( className.length == 0 )
125					FCKDomTools.RemoveAttribute( block, 'class' ) ;
126			}
127			else
128			{
129				var style = block.style ;
130				if ( currentState == FCK_TRISTATE_OFF )
131					style.textAlign = this.AlignValue ;
132				else
133				{
134					style.textAlign = '' ;
135					if ( style.cssText.length == 0 )
136						block.removeAttribute( 'style' ) ;
137				}
138			}
139		}
140
141		// Restore previous selection.
142		range.MoveToBookmark( bookmark ) ;
143		range.Select() ;
144
145		FCK.Focus() ;
146		FCK.Events.FireEvent( 'OnSelectionChange' ) ;
147	},
148
149	GetState : function()
150	{
151		// Disabled if not WYSIWYG.
152		if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
153			return FCK_TRISTATE_DISABLED ;
154
155		// Retrieve the first selected block.
156		var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
157		var firstBlock = path.Block || path.BlockLimit ;
158
159		if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
160			return FCK_TRISTATE_OFF ;
161
162		// Check if the desired style is already applied to the block.
163		var currentAlign ;
164		if ( FCKBrowserInfo.IsIE )
165			currentAlign = firstBlock.currentStyle.textAlign ;
166		else
167			currentAlign = FCK.EditorWindow.getComputedStyle( firstBlock, '' ).getPropertyValue( 'text-align' );
168		currentAlign = currentAlign.replace( /(-moz-|-webkit-|start|auto)/i, '' );
169		if ( ( !currentAlign && this.IsDefaultAlign ) || currentAlign == this.AlignValue )
170			return FCK_TRISTATE_ON ;
171		return FCK_TRISTATE_OFF ;
172	}
173} ;
174