PageRenderTime 47ms CodeModel.GetById 20ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/EQT_V2/EQT/EQTWebApp/fckeditor/editor/_source/internals/fckstyles.js

http://sgsoft-las.googlecode.com/
JavaScript | 381 lines | 240 code | 74 blank | 67 comment | 63 complexity | fe3d7c522d3a6fb160035c581b25cdb5 MD5 | raw file
Possible License(s): LGPL-2.1
  1/*
  2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
  3 * Copyright (C) 2003-2009 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 * Handles styles in a give document.
 22 */
 23
 24var FCKStyles = FCK.Styles =
 25{
 26	_Callbacks : {},
 27	_ObjectStyles : {},
 28
 29	ApplyStyle : function( style )
 30	{
 31		if ( typeof style == 'string' )
 32			style = this.GetStyles()[ style ] ;
 33
 34		if ( style )
 35		{
 36			if ( style.GetType() == FCK_STYLE_OBJECT )
 37				style.ApplyToObject( FCKSelection.GetSelectedElement() ) ;
 38			else
 39				style.ApplyToSelection( FCK.EditorWindow ) ;
 40
 41			FCK.Events.FireEvent( 'OnSelectionChange' ) ;
 42		}
 43	},
 44
 45	RemoveStyle : function( style )
 46	{
 47		if ( typeof style == 'string' )
 48			style = this.GetStyles()[ style ] ;
 49
 50		if ( style )
 51		{
 52			style.RemoveFromSelection( FCK.EditorWindow ) ;
 53			FCK.Events.FireEvent( 'OnSelectionChange' ) ;
 54		}
 55	},
 56
 57	/**
 58	 * Defines a callback function to be called when the current state of a
 59	 * specific style changes.
 60	 */
 61	AttachStyleStateChange : function( styleName, callback, callbackOwner )
 62	{
 63		var callbacks = this._Callbacks[ styleName ] ;
 64
 65		if ( !callbacks )
 66			callbacks = this._Callbacks[ styleName ] = [] ;
 67
 68		callbacks.push( [ callback, callbackOwner ] ) ;
 69	},
 70
 71	CheckSelectionChanges : function()
 72	{
 73		var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
 74
 75		if ( !startElement )
 76			return ;
 77
 78		// Walks the start node parents path, checking all styles that are being listened.
 79		var path = new FCKElementPath( startElement ) ;
 80		var styles = this.GetStyles() ;
 81
 82		for ( var styleName in styles )
 83		{
 84			var callbacks = this._Callbacks[ styleName ] ;
 85
 86			if ( callbacks )
 87			{
 88				var style = styles[ styleName ] ;
 89				var state = style.CheckActive( path ) ;
 90
 91				if ( state != ( style._LastState || null ) )
 92				{
 93					style._LastState = state ;
 94
 95					for ( var i = 0 ; i < callbacks.length ; i++ )
 96					{
 97						var callback = callbacks[i][0] ;
 98						var callbackOwner = callbacks[i][1] ;
 99
100						callback.call( callbackOwner || window, styleName, state ) ;
101					}
102				}
103			}
104		}
105	},
106
107	CheckStyleInSelection : function( styleName )
108	{
109		return false ;
110	},
111
112	_GetRemoveFormatTagsRegex : function ()
113	{
114		var regex = new RegExp( '^(?:' + FCKConfig.RemoveFormatTags.replace( /,/g,'|' ) + ')$', 'i' ) ;
115
116		return (this._GetRemoveFormatTagsRegex = function()
117		{
118			return regex ;
119		})
120		&& regex  ;
121	},
122
123	/**
124	 * Remove all styles from the current selection.
125	 * TODO:
126	 *  - This is almost a duplication of FCKStyle.RemoveFromRange. We should
127	 *    try to merge things.
128	 */
129	RemoveAll : function()
130	{
131		var range = new FCKDomRange( FCK.EditorWindow ) ;
132		range.MoveToSelection() ;
133
134		if ( range.CheckIsCollapsed() )
135			return ;
136
137			// Expand the range, if inside inline element boundaries.
138		range.Expand( 'inline_elements' ) ;
139
140		// Get the bookmark nodes.
141		// Bookmark the range so we can re-select it after processing.
142		var bookmark = range.CreateBookmark( true ) ;
143
144		// The style will be applied within the bookmark boundaries.
145		var startNode	= range.GetBookmarkNode( bookmark, true ) ;
146		var endNode		= range.GetBookmarkNode( bookmark, false ) ;
147
148		range.Release( true ) ;
149
150		var tagsRegex = this._GetRemoveFormatTagsRegex() ;
151
152		// We need to check the selection boundaries (bookmark spans) to break
153		// the code in a way that we can properly remove partially selected nodes.
154		// For example, removing a <b> style from
155		//		<b>This is [some text</b> to show <b>the] problem</b>
156		// ... where [ and ] represent the selection, must result:
157		//		<b>This is </b>[some text to show the]<b> problem</b>
158		// The strategy is simple, we just break the partial nodes before the
159		// removal logic, having something that could be represented this way:
160		//		<b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
161
162		// Let's start checking the start boundary.
163		var path = new FCKElementPath( startNode ) ;
164		var pathElements = path.Elements ;
165		var pathElement ;
166
167		for ( var i = 1 ; i < pathElements.length ; i++ )
168		{
169			pathElement = pathElements[i] ;
170
171			if ( pathElement == path.Block || pathElement == path.BlockLimit )
172				break ;
173
174			// If this element can be removed (even partially).
175			if ( tagsRegex.test( pathElement.nodeName ) )
176				FCKDomTools.BreakParent( startNode, pathElement, range ) ;
177		}
178
179		// Now the end boundary.
180		path = new FCKElementPath( endNode ) ;
181		pathElements = path.Elements ;
182
183		for ( var i = 1 ; i < pathElements.length ; i++ )
184		{
185			pathElement = pathElements[i] ;
186
187			if ( pathElement == path.Block || pathElement == path.BlockLimit )
188				break ;
189
190			elementName = pathElement.nodeName.toLowerCase() ;
191
192			// If this element can be removed (even partially).
193			if ( tagsRegex.test( pathElement.nodeName ) )
194				FCKDomTools.BreakParent( endNode, pathElement, range ) ;
195		}
196
197		// Navigate through all nodes between the bookmarks.
198		var currentNode = FCKDomTools.GetNextSourceNode( startNode, true, 1 ) ;
199
200		while ( currentNode )
201		{
202			// If we have reached the end of the selection, stop looping.
203			if ( currentNode == endNode )
204				break ;
205
206			// Cache the next node to be processed. Do it now, because
207			// currentNode may be removed.
208			var nextNode = FCKDomTools.GetNextSourceNode( currentNode, false, 1 ) ;
209
210			// Remove elements nodes that match with this style rules.
211			if ( tagsRegex.test( currentNode.nodeName ) )
212				FCKDomTools.RemoveNode( currentNode, true ) ;
213			else
214				FCKDomTools.RemoveAttributes( currentNode, FCKConfig.RemoveAttributesArray );
215
216			currentNode = nextNode ;
217		}
218
219		range.SelectBookmark( bookmark ) ;
220
221		FCK.Events.FireEvent( 'OnSelectionChange' ) ;
222	},
223
224	GetStyle : function( styleName )
225	{
226		return this.GetStyles()[ styleName ] ;
227	},
228
229	GetStyles : function()
230	{
231		var styles = this._GetStyles ;
232		if ( !styles )
233		{
234			styles = this._GetStyles = FCKTools.Merge(
235				this._LoadStylesCore(),
236				this._LoadStylesCustom(),
237				this._LoadStylesXml() ) ;
238		}
239		return styles ;
240	},
241
242	CheckHasObjectStyle : function( elementName )
243	{
244		return !!this._ObjectStyles[ elementName ] ;
245	},
246
247	_LoadStylesCore : function()
248	{
249		var styles = {};
250		var styleDefs = FCKConfig.CoreStyles ;
251
252		for ( var styleName in styleDefs )
253		{
254			// Core styles are prefixed with _FCK_.
255			var style = styles[ '_FCK_' + styleName ] = new FCKStyle( styleDefs[ styleName ] ) ;
256			style.IsCore = true ;
257		}
258		return styles ;
259	},
260
261	_LoadStylesCustom : function()
262	{
263		var styles = {};
264		var styleDefs = FCKConfig.CustomStyles ;
265
266		if ( styleDefs )
267		{
268			for ( var styleName in styleDefs )
269			{
270				var style = styles[ styleName ] = new FCKStyle( styleDefs[ styleName ] ) ;
271				style.Name = styleName ;
272			}
273		}
274
275		return styles ;
276	},
277
278	_LoadStylesXml : function()
279	{
280		var styles = {};
281
282		var stylesXmlPath = FCKConfig.StylesXmlPath ;
283
284		if ( !stylesXmlPath || stylesXmlPath.length == 0 )
285			return styles ;
286
287		// Load the XML file into a FCKXml object.
288		var xml = new FCKXml() ;
289		xml.LoadUrl( stylesXmlPath ) ;
290
291		var stylesXmlObj = FCKXml.TransformToObject( xml.SelectSingleNode( 'Styles' ) ) ;
292
293		// Get the "Style" nodes defined in the XML file.
294		var styleNodes = stylesXmlObj.$Style ;
295
296		// Check that it did contain some valid nodes
297		if ( !styleNodes )
298			return styles ;
299
300		// Add each style to our "Styles" collection.
301		for ( var i = 0 ; i < styleNodes.length ; i++ )
302		{
303			var styleNode = styleNodes[i] ;
304
305			var element = ( styleNode.element || '' ).toLowerCase() ;
306
307			if ( element.length == 0 )
308				throw( 'The element name is required. Error loading "' + stylesXmlPath + '"' ) ;
309
310			var styleDef = {
311				Element : element,
312				Attributes : {},
313				Styles : {},
314				Overrides : []
315			} ;
316
317			// Get the attributes defined for the style (if any).
318			var attNodes = styleNode.$Attribute || [] ;
319
320			// Add the attributes to the style definition object.
321			for ( var j = 0 ; j < attNodes.length ; j++ )
322			{
323				styleDef.Attributes[ attNodes[j].name ] = attNodes[j].value ;
324			}
325
326			// Get the styles defined for the style (if any).
327			var cssStyleNodes = styleNode.$Style || [] ;
328
329			// Add the attributes to the style definition object.
330			for ( j = 0 ; j < cssStyleNodes.length ; j++ )
331			{
332				styleDef.Styles[ cssStyleNodes[j].name ] = cssStyleNodes[j].value ;
333			}
334
335			// Load override definitions.
336			var cssStyleOverrideNodes = styleNode.$Override ;
337			if ( cssStyleOverrideNodes )
338			{
339				for ( j = 0 ; j < cssStyleOverrideNodes.length ; j++ )
340				{
341					var overrideNode = cssStyleOverrideNodes[j] ;
342					var overrideDef =
343					{
344						Element : overrideNode.element
345					} ;
346
347					var overrideAttNode = overrideNode.$Attribute ;
348					if ( overrideAttNode )
349					{
350						overrideDef.Attributes = {} ;
351						for ( var k = 0 ; k < overrideAttNode.length ; k++ )
352						{
353							var overrideAttValue = overrideAttNode[k].value || null ;
354							if ( overrideAttValue )
355							{
356								// Check if the override attribute value is a regular expression.
357								var regexMatch = overrideAttValue && FCKRegexLib.RegExp.exec( overrideAttValue ) ;
358								if ( regexMatch )
359									overrideAttValue = new RegExp( regexMatch[1], regexMatch[2] || '' ) ;
360							}
361							overrideDef.Attributes[ overrideAttNode[k].name ] = overrideAttValue ;
362						}
363					}
364
365					styleDef.Overrides.push( overrideDef ) ;
366				}
367			}
368
369			var style = new FCKStyle( styleDef ) ;
370			style.Name = styleNode.name || element ;
371
372			if ( style.GetType() == FCK_STYLE_OBJECT )
373				this._ObjectStyles[ element ] = true ;
374
375			// Add the style to the "Styles" collection using it's name as the key.
376			styles[ style.Name ] = style ;
377		}
378
379		return styles ;
380	}
381} ;