source: branches/1.2/workflow/js/fckeditor/editor/_source/internals/fckxhtml.js @ 1349

Revision 1349, 13.2 KB checked in by niltonneto, 15 years ago (diff)

Ticket #561 - Inclusão do módulo Workflow faltante nessa versão.

  • Property svn:executable set to *
Line 
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 * Defines the FCKXHtml object, responsible for the XHTML operations.
22 */
23
24var FCKXHtml = new Object() ;
25
26FCKXHtml.CurrentJobNum = 0 ;
27
28FCKXHtml.GetXHTML = function( node, includeNode, format )
29{
30        FCKXHtmlEntities.Initialize() ;
31       
32        // Set the correct entity to use for empty blocks.
33        this._NbspEntity = ( FCKConfig.ProcessHTMLEntities? 'nbsp' : '#160' ) ;
34
35        // Save the current IsDirty state. The XHTML processor may change the
36        // original HTML, dirtying it.
37        var bIsDirty = FCK.IsDirty() ;
38
39        this._CreateNode = FCKConfig.ForceStrongEm ? FCKXHtml_CreateNode_StrongEm : FCKXHtml_CreateNode_Normal ;
40
41        // Special blocks are blocks of content that remain untouched during the
42        // process. It is used for SCRIPTs and STYLEs.
43        FCKXHtml.SpecialBlocks = new Array() ;
44
45        // Create the XML DOMDocument object.
46        this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
47
48        // Add a root element that holds all child nodes.
49        this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
50
51        FCKXHtml.CurrentJobNum++ ;
52
53        if ( includeNode )
54                this._AppendNode( this.MainNode, node ) ;
55        else
56                this._AppendChildNodes( this.MainNode, node, false ) ;
57
58        // Get the resulting XHTML as a string.
59        var sXHTML = this._GetMainXmlString() ;
60
61        this.XML = null ;
62
63        // Strip the "XHTML" root node.
64        sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ;
65
66        // Remove the trailing <br> added by Gecko.
67        // REMOVE: Maybe the following is not anymore necessary because a similar
68        // check is made on _AppendNode
69        if ( FCKBrowserInfo.IsGecko )
70                sXHTML = sXHTML.replace( /<br\/>$/, '' ) ;
71
72        // Add a space in the tags with no closing tags, like <br/> -> <br />
73        sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
74
75        if ( FCKConfig.ForceSimpleAmpersand )
76                sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
77
78        if ( format )
79                sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
80
81        // Now we put back the SpecialBlocks contents.
82        for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
83        {
84                var oRegex = new RegExp( '___FCKsi___' + i ) ;
85                sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
86        }
87
88        // Replace entities marker with the ampersand.
89        sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
90
91        // Restore the IsDirty state if it was not dirty.
92        if ( !bIsDirty )
93                FCK.ResetIsDirty() ;
94
95        return sXHTML ;
96}
97
98FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
99{
100        try
101        {
102                if ( attributeValue == undefined || attributeValue == null )
103                        attributeValue = '' ;
104                else if ( attributeValue.replace )
105                {
106                        if ( FCKConfig.ForceSimpleAmpersand )
107                                attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
108
109                        // Entities must be replaced in the attribute values.
110                        attributeValue = attributeValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ;
111                }
112
113                // Create the attribute.
114                var oXmlAtt = this.XML.createAttribute( attributeName ) ;
115                oXmlAtt.value = attributeValue ;
116
117                // Set the attribute in the node.
118                xmlNode.attributes.setNamedItem( oXmlAtt ) ;
119        }
120        catch (e)
121        {}
122}
123
124FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
125{
126        // Trim block elements. This is also needed to avoid Firefox leaving extra
127        // BRs at the end of them.
128        if ( isBlockElement )
129                FCKDomTools.TrimNode( htmlNode, true ) ;
130
131        var iCount = 0 ;
132
133        var oNode = htmlNode.firstChild ;
134
135        while ( oNode )
136        {
137                if ( this._AppendNode( xmlNode, oNode ) )
138                        iCount++ ;
139
140                oNode = oNode.nextSibling ;
141        }
142
143        if ( iCount == 0 )
144        {
145                if ( isBlockElement && FCKConfig.FillEmptyBlocks )
146                {
147                        this._AppendEntity( xmlNode, this._NbspEntity ) ;
148                        return xmlNode ;
149                }
150
151                var sNodeName = xmlNode.nodeName ;
152
153                // Some inline elements are required to have something inside (span, strong, etc...).
154                if ( FCKListsLib.InlineChildReqElements[ sNodeName ] )
155                        return null ;
156
157                // We can't use short representation of empty elements that are not marked
158                // as empty in th XHTML DTD.
159                if ( !FCKListsLib.EmptyElements[ sNodeName ] )
160                        xmlNode.appendChild( this.XML.createTextNode('') ) ;
161        }
162
163        return xmlNode ;
164}
165
166FCKXHtml._AppendNode = function( xmlNode, htmlNode )
167{
168        if ( !htmlNode )
169                return false ;
170
171        switch ( htmlNode.nodeType )
172        {
173                // Element Node.
174                case 1 :
175
176                        // Here we found an element that is not the real element, but a
177                        // fake one (like the Flash placeholder image), so we must get the real one.
178                        if ( htmlNode.getAttribute('_fckfakelement') )
179                                return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
180
181                        // Mozilla insert custom nodes in the DOM.
182                        if ( FCKBrowserInfo.IsGecko && htmlNode.hasAttribute('_moz_editor_bogus_node') )
183                                return false ;
184
185                        // This is for elements that are instrumental to FCKeditor and
186                        // must be removed from the final HTML.
187                        if ( htmlNode.getAttribute('_fcktemp') )
188                                return false ;
189
190                        // Get the element name.
191                        var sNodeName = htmlNode.tagName.toLowerCase()  ;
192
193                        if ( FCKBrowserInfo.IsIE )
194                        {
195                                // IE doens't include the scope name in the nodeName. So, add the namespace.
196                                if ( htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
197                                        sNodeName = htmlNode.scopeName.toLowerCase() + ':' + sNodeName ;
198                        }
199                        else
200                        {
201                                if ( sNodeName.StartsWith( 'fck:' ) )
202                                        sNodeName = sNodeName.Remove( 0,4 ) ;
203                        }
204
205                        // Check if the node name is valid, otherwise ignore this tag.
206                        // If the nodeName starts with a slash, it is a orphan closing tag.
207                        // On some strange cases, the nodeName is empty, even if the node exists.
208                        if ( !FCKRegexLib.ElementName.test( sNodeName ) )
209                                return false ;
210
211                        // Remove the <br> if it is a bogus node.
212                        if ( sNodeName == 'br' && htmlNode.getAttribute( 'type', 2 ) == '_moz' )
213                                return false ;
214
215                        // The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
216                        // So here, the "mark" is checked... if the element is Ok, then mark it.
217                        if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
218                                return false ;
219
220                        var oNode = this._CreateNode( sNodeName ) ;
221
222                        // Add all attributes.
223                        FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
224
225                        htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
226
227                        // Tag specific processing.
228                        var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
229
230                        if ( oTagProcessor )
231                                oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
232                        else
233                                oNode = this._AppendChildNodes( oNode, htmlNode, Boolean( FCKListsLib.NonEmptyBlockElements[ sNodeName ] ) ) ;
234
235                        if ( !oNode )
236                                return false ;
237
238                        xmlNode.appendChild( oNode ) ;
239
240                        break ;
241
242                // Text Node.
243                case 3 :
244                        return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;
245
246                // Comment
247                case 8 :
248                        // IE catches the <!DOTYPE ... > as a comment, but it has no
249                        // innerHTML, so we can catch it, and ignore it.
250                        if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
251                                break ;
252
253                        try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
254                        catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
255                        break ;
256
257                // Unknown Node type.
258                default :
259                        xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
260                        break ;
261        }
262        return true ;
263}
264
265function FCKXHtml_CreateNode_StrongEm( nodeName )
266{
267        switch ( nodeName )
268        {
269                case 'b' :
270                        nodeName = 'strong' ;
271                        break ;
272                case 'i' :
273                        nodeName = 'em' ;
274                        break ;
275        }
276        return this.XML.createElement( nodeName ) ;
277}
278
279function FCKXHtml_CreateNode_Normal( nodeName )
280{
281        return this.XML.createElement( nodeName ) ;
282}
283
284// Append an item to the SpecialBlocks array and returns the tag to be used.
285FCKXHtml._AppendSpecialItem = function( item )
286{
287        return '___FCKsi___' + FCKXHtml.SpecialBlocks.AddItem( item ) ;
288}
289
290FCKXHtml._AppendEntity = function( xmlNode, entity )
291{
292        xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
293}
294
295FCKXHtml._AppendTextNode = function( targetNode, textValue )
296{
297        var bHadText = textValue.length > 0 ;
298        if ( bHadText )
299                targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
300        return bHadText ;
301}
302
303// Retrieves a entity (internal format) for a given character.
304function FCKXHtml_GetEntity( character )
305{
306        // We cannot simply place the entities in the text, because the XML parser
307        // will translate & to &amp;. So we use a temporary marker which is replaced
308        // in the end of the processing.
309        var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
310        return '#?-:' + sEntity + ';' ;
311}
312
313// Remove part of an attribute from a node according to a regExp
314FCKXHtml._RemoveAttribute = function( xmlNode, regX, sAttribute )
315{
316        var oAtt = xmlNode.attributes.getNamedItem( sAttribute ) ;
317
318        if ( oAtt && regX.test( oAtt.nodeValue ) )
319        {
320                var sValue = oAtt.nodeValue.replace( regX, '' ) ;
321
322                if ( sValue.length == 0 )
323                        xmlNode.attributes.removeNamedItem( sAttribute ) ;
324                else
325                        oAtt.nodeValue = sValue ;
326        }
327}
328
329// An object that hold tag specific operations.
330FCKXHtml.TagProcessors =
331{
332        img : function( node, htmlNode )
333        {
334                // The "ALT" attribute is required in XHTML.
335                if ( ! node.attributes.getNamedItem( 'alt' ) )
336                        FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
337
338                var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
339                if ( sSavedUrl != null )
340                        FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
341
342                return node ;
343        },
344
345        a : function( node, htmlNode )
346        {
347                // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878).
348                if ( htmlNode.innerHTML.Trim().length == 0 && !htmlNode.name )
349                        return false ;
350
351                var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
352                if ( sSavedUrl != null )
353                        FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
354
355
356                // Anchors with content has been marked with an additional class, now we must remove it.
357                if ( FCKBrowserInfo.IsIE )
358                {
359                        FCKXHtml._RemoveAttribute( node, FCKRegexLib.FCK_Class, 'class' ) ;
360
361                        // Buggy IE, doesn't copy the name of changed anchors.
362                        if ( htmlNode.name )
363                                FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
364                }
365
366                node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
367
368                return node ;
369        },
370
371        script : function( node, htmlNode )
372        {
373                // The "TYPE" attribute is required in XHTML.
374                if ( ! node.attributes.getNamedItem( 'type' ) )
375                        FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
376
377                node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
378
379                return node ;
380        },
381
382        style : function( node, htmlNode )
383        {
384                // The "TYPE" attribute is required in XHTML.
385                if ( ! node.attributes.getNamedItem( 'type' ) )
386                        FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
387
388                node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.innerHTML ) ) ) ;
389
390                return node ;
391        },
392
393        title : function( node, htmlNode )
394        {
395                node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
396
397                return node ;
398        },
399
400        table : function( node, htmlNode )
401        {
402                // There is a trick to show table borders when border=0. We add to the
403                // table class the FCK__ShowTableBorders rule. So now we must remove it.
404
405                if ( FCKBrowserInfo.IsIE )
406                        FCKXHtml._RemoveAttribute( node, FCKRegexLib.FCK_Class, 'class' ) ;
407
408                node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
409
410                return node ;
411        },
412
413        // Fix nested <ul> and <ol>.
414        ol : function( node, htmlNode, targetNode )
415        {
416                if ( htmlNode.innerHTML.Trim().length == 0 )
417                        return false ;
418
419                var ePSibling = targetNode.lastChild ;
420
421                if ( ePSibling && ePSibling.nodeType == 3 )
422                        ePSibling = ePSibling.previousSibling ;
423
424                if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
425                {
426                        htmlNode._fckxhtmljob = null ;
427                        FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
428                        return false ;
429                }
430
431                node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
432
433                return node ;
434        },
435
436        span : function( node, htmlNode )
437        {
438                // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
439                if ( htmlNode.innerHTML.length == 0 )
440                        return false ;
441
442                node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
443
444                return node ;
445        },
446
447        // IE loses contents of iframes, and Gecko does give it back HtmlEncoded
448        // Note: Opera does lose the content and doesn't provide it in the innerHTML string
449        iframe : function( node, htmlNode )
450        {
451                var sHtml = htmlNode.innerHTML ;
452
453                // Gecko does give back the encoded html
454                if ( FCKBrowserInfo.IsGecko )
455                        sHtml = FCKTools.HTMLDecode( sHtml );
456               
457                // Remove the saved urls here as the data won't be processed as nodes
458                sHtml = sHtml.replace( /\s_fcksavedurl="[^"]*"/g, '' ) ;
459
460                node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( sHtml ) ) ) ;
461
462                return node ;
463        }
464} ;
465
466FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;
Note: See TracBrowser for help on using the repository browser.