Subversion Repositories Applications.papyrus

Rev

Rev 1087 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1075 ddelon 1
/*
2
 * FCKeditor - The text editor for internet
3
 * Copyright (C) 2003-2006 Frederico Caldeira Knabben
4
 *
5
 * Licensed under the terms of the GNU Lesser General Public License:
6
 * 		http://www.opensource.org/licenses/lgpl-license.php
7
 *
8
 * For further information visit:
9
 * 		http://www.fckeditor.net/
10
 *
11
 * "Support Open Source software. What about a donation today?"
12
 *
13
 * File Name: fckxhtml.js
14
 * 	Defines the FCKXHtml object, responsible for the XHTML operations.
15
 *
16
 * File Authors:
17
 * 		Frederico Caldeira Knabben (fredck@fckeditor.net)
18
 */
19
 
20
var FCKXHtml = new Object() ;
21
 
22
FCKXHtml.CurrentJobNum = 0 ;
23
 
24
FCKXHtml.GetXHTML = function( node, includeNode, format )
25
{
26
	FCKXHtmlEntities.Initialize() ;
27
 
28
	// Save the current IsDirty state. The XHTML processor may change the
29
	// original HTML, dirtying it.
30
	var bIsDirty = FCK.IsDirty() ;
31
 
32
	this._CreateNode = FCKConfig.ForceStrongEm ? FCKXHtml_CreateNode_StrongEm : FCKXHtml_CreateNode_Normal ;
33
 
34
	// Special blocks are blocks of content that remain untouched during the
35
	// process. It is used for SCRIPTs and STYLEs.
36
	FCKXHtml.SpecialBlocks = new Array() ;
37
 
38
	// Create the XML DOMDocument object.
39
	this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
40
 
41
	// Add a root element that holds all child nodes.
42
	this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
43
 
44
	FCKXHtml.CurrentJobNum++ ;
45
 
46
	if ( includeNode )
47
		this._AppendNode( this.MainNode, node ) ;
48
	else
49
		this._AppendChildNodes( this.MainNode, node, false ) ;
50
 
51
	// Get the resulting XHTML as a string.
52
	var sXHTML = this._GetMainXmlString() ;
53
 
54
	this.XML = null ;
55
 
56
	// Strip the "XHTML" root node.
57
	sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).trim() ;
58
 
59
	// Remove the trailing <br> added by Gecko.
60
	if ( FCKBrowserInfo.IsGecko )
61
		sXHTML = sXHTML.replace( /<br\/>$/, '' ) ;
62
 
63
	// Add a space in the tags with no closing tags, like <br/> -> <br />
64
	sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
65
 
66
	if ( FCKConfig.ForceSimpleAmpersand )
67
		sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
68
 
69
	if ( format )
70
		sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
71
 
72
	// Now we put back the SpecialBlocks contents.
73
	for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
74
	{
75
		var oRegex = new RegExp( '___FCKsi___' + i ) ;
76
		sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
77
	}
78
 
79
	// Replace entities marker with the ampersand.
80
	sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
81
 
82
	// Restore the IsDirty state if it was not dirty.
83
	if ( !bIsDirty )
84
		FCK.ResetIsDirty() ;
85
 
86
	return sXHTML
87
}
88
 
89
FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
90
{
91
	if ( FCKConfig.ForceSimpleAmpersand && attributeValue.replace )
92
		attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
93
 
94
	try
95
	{
96
		// Create the attribute.
97
		var oXmlAtt = this.XML.createAttribute( attributeName ) ;
98
 
99
		oXmlAtt.value = attributeValue ? attributeValue : '' ;
100
 
101
		// Set the attribute in the node.
102
		xmlNode.attributes.setNamedItem( oXmlAtt ) ;
103
	}
104
	catch (e)
105
	{}
106
}
107
 
108
FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
109
{
110
	var iCount = 0 ;
111
 
112
	var oNode = htmlNode.firstChild ;
113
 
114
	while ( oNode )
115
	{
116
		if ( this._AppendNode( xmlNode, oNode ) )
117
			iCount++ ;
118
 
119
		oNode = oNode.nextSibling ;
120
	}
121
 
122
	if ( iCount == 0 )
123
	{
124
		if ( isBlockElement && FCKConfig.FillEmptyBlocks )
125
		{
126
			this._AppendEntity( xmlNode, 'nbsp' ) ;
127
			return ;
128
		}
129
 
130
		// We can't use short representation of empty elements that are not marked
131
		// as empty in th XHTML DTD.
132
		if ( !FCKRegexLib.EmptyElements.test( htmlNode.nodeName ) )
133
			xmlNode.appendChild( this.XML.createTextNode('') ) ;
134
	}
135
}
136
 
137
FCKXHtml._AppendNode = function( xmlNode, htmlNode )
138
{
139
	if ( !htmlNode )
140
		return ;
141
 
142
	switch ( htmlNode.nodeType )
143
	{
144
		// Element Node.
145
		case 1 :
146
 
147
			// Here we found an element that is not the real element, but a
148
			// fake one (like the Flash placeholder image), so we must get the real one.
149
			if ( htmlNode.getAttribute('_fckfakelement') )
150
				return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
151
 
152
			// Mozilla insert custom nodes in the DOM.
153
			if ( FCKBrowserInfo.IsGecko && htmlNode.hasAttribute('_moz_editor_bogus_node') )
154
				return false ;
155
 
156
			// This is for elements that are instrumental to FCKeditor and
157
			// must be removed from the final HTML.
158
			if ( htmlNode.getAttribute('_fcktemp') )
159
				return false ;
160
 
161
			// Get the element name.
162
			var sNodeName = htmlNode.nodeName ;
163
 
164
			//Add namespace:
165
			if ( FCKBrowserInfo.IsIE && htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
166
				sNodeName = htmlNode.scopeName + ':' + sNodeName ;
167
 
168
			// Check if the node name is valid, otherwise ignore this tag.
169
			// If the nodeName starts with a slash, it is a orphan closing tag.
170
			// On some strange cases, the nodeName is empty, even if the node exists.
171
			if ( !FCKRegexLib.ElementName.test( sNodeName ) )
172
				return false ;
173
 
174
			sNodeName = sNodeName.toLowerCase() ;
175
 
176
			if ( FCKBrowserInfo.IsGecko && sNodeName == 'br' && htmlNode.hasAttribute('type') && htmlNode.getAttribute( 'type', 2 ) == '_moz' )
177
				return false ;
178
 
179
			// The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
180
			// So here, the "mark" is checked... if the element is Ok, then mark it.
181
			if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
182
				return false ;
183
 
184
			var oNode = this._CreateNode( sNodeName ) ;
185
 
186
			// Add all attributes.
187
			FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
188
 
189
			htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
190
 
191
			// Tag specific processing.
192
			var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
193
 
194
			if ( oTagProcessor )
195
			{
196
				oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
197
				if ( !oNode ) break ;
198
			}
199
			else
200
				this._AppendChildNodes( oNode, htmlNode, FCKRegexLib.BlockElements.test( sNodeName ) ) ;
201
 
202
			xmlNode.appendChild( oNode ) ;
203
 
204
			break ;
205
 
206
		// Text Node.
207
		case 3 :
208
			this._AppendTextNode( xmlNode, htmlNode.nodeValue.replaceNewLineChars(' ') ) ;
209
			break ;
210
 
211
		// Comment
212
		case 8 :
213
			// IE catches the <!DOTYPE ... > as a comment, but it has no
214
			// innerHTML, so we can catch it, and ignore it.
215
			if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
216
				break ;
217
 
218
			try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
219
			catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
220
			break ;
221
 
222
		// Unknown Node type.
223
		default :
224
			xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
225
			break ;
226
	}
227
	return true ;
228
}
229
 
230
function FCKXHtml_CreateNode_StrongEm( nodeName )
231
{
232
	switch ( nodeName )
233
	{
234
		case 'b' :
235
			nodeName = 'strong' ;
236
			break ;
237
		case 'i' :
238
			nodeName = 'em' ;
239
			break ;
240
	}
241
	return this.XML.createElement( nodeName ) ;
242
}
243
 
244
function FCKXHtml_CreateNode_Normal( nodeName )
245
{
246
	return this.XML.createElement( nodeName ) ;
247
}
248
 
249
// Append an item to the SpecialBlocks array and returns the tag to be used.
250
FCKXHtml._AppendSpecialItem = function( item )
251
{
252
	return '___FCKsi___' + FCKXHtml.SpecialBlocks.AddItem( item ) ;
253
}
254
 
255
FCKXHtml._AppendEntity = function( xmlNode, entity )
256
{
257
	xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
258
}
259
 
260
FCKXHtml._AppendTextNode = function( targetNode, textValue )
261
{
262
	targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
263
	return ;
264
}
265
 
266
// Retrieves a entity (internal format) for a given character.
267
function FCKXHtml_GetEntity( character )
268
{
269
	// We cannot simply place the entities in the text, because the XML parser
270
	// will translate & to &amp;. So we use a temporary marker which is replaced
271
	// in the end of the processing.
272
	var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
273
	return '#?-:' + sEntity + ';' ;
274
}
275
 
276
// An object that hold tag specific operations.
277
FCKXHtml.TagProcessors = new Object() ;
278
 
279
FCKXHtml.TagProcessors['img'] = function( node, htmlNode )
280
{
281
	// The "ALT" attribute is required in XHTML.
282
	if ( ! node.attributes.getNamedItem( 'alt' ) )
283
		FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
284
 
285
	var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
286
	if ( sSavedUrl != null )
287
		FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
288
 
289
	return node ;
290
}
291
 
292
FCKXHtml.TagProcessors['a'] = function( node, htmlNode )
293
{
294
	var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
295
	if ( sSavedUrl != null )
296
		FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
297
 
298
	FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
299
 
300
	// Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878).
301
	if ( node.childNodes.length == 0 && !node.getAttribute( 'name' ) )
302
		return false ;
303
 
304
	return node ;
305
}
306
 
307
FCKXHtml.TagProcessors['script'] = function( node, htmlNode )
308
{
309
	// The "TYPE" attribute is required in XHTML.
310
	if ( ! node.attributes.getNamedItem( 'type' ) )
311
		FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
312
 
313
	node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
314
 
315
	return node ;
316
}
317
 
318
FCKXHtml.TagProcessors['style'] = function( node, htmlNode )
319
{
320
	// The "TYPE" attribute is required in XHTML.
321
	if ( ! node.attributes.getNamedItem( 'type' ) )
322
		FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
323
 
324
	node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.innerHTML ) ) ) ;
325
 
326
	return node ;
327
}
328
 
329
FCKXHtml.TagProcessors['title'] = function( node, htmlNode )
330
{
331
	node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
332
 
333
	return node ;
334
}
335
 
336
FCKXHtml.TagProcessors['table'] = function( node, htmlNode )
337
{
338
	// There is a trick to show table borders when border=0. We add to the
339
	// table class the FCK__ShowTableBorders rule. So now we must remove it.
340
 
341
	var oClassAtt = node.attributes.getNamedItem( 'class' ) ;
342
 
343
	if ( oClassAtt && FCKRegexLib.TableBorderClass.test( oClassAtt.nodeValue ) )
344
	{
345
		var sClass = oClassAtt.nodeValue.replace( FCKRegexLib.TableBorderClass, '' ) ;
346
 
347
		if ( sClass.length == 0 )
348
			node.attributes.removeNamedItem( 'class' ) ;
349
		else
350
			FCKXHtml._AppendAttribute( node, 'class', sClass ) ;
351
	}
352
 
353
	FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
354
 
355
	return node ;
356
}
357
 
358
// Fix nested <ul> and <ol>.
359
FCKXHtml.TagProcessors['ol'] = FCKXHtml.TagProcessors['ul'] = function( node, htmlNode, targetNode )
360
{
361
	if ( htmlNode.innerHTML.trim().length == 0 )
362
		return ;
363
 
364
	var ePSibling = targetNode.lastChild ;
365
 
366
	if ( ePSibling && ePSibling.nodeType == 3 )
367
		ePSibling = ePSibling.previousSibling ;
368
 
369
	if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
370
	{
371
		htmlNode._fckxhtmljob = null ;
372
		FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
373
		return ;
374
	}
375
 
376
	FCKXHtml._AppendChildNodes( node, htmlNode ) ;
377
 
378
	return node ;
379
}
380
 
381
FCKXHtml.TagProcessors['span'] = function( node, htmlNode )
382
{
383
	// Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
384
	if ( htmlNode.innerHTML.length == 0 )
385
		return false ;
386
 
387
	FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
388
 
389
	return node ;
390
}