source: sandbox/filemanager/tp/fckeditor/editor/_source/internals/fckxhtml.js @ 1575

Revision 1575, 17.2 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Implentação, melhorias do modulo gerenciador de arquivos

  • Property svn:executable set to *
Line 
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 * 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        FCKDomTools.CheckAndRemovePaddingNode( FCKTools.GetElementDocument( node ), FCKConfig.EnterMode ) ;
31        FCKXHtmlEntities.Initialize() ;
32
33        // Set the correct entity to use for empty blocks.
34        this._NbspEntity = ( FCKConfig.ProcessHTMLEntities? 'nbsp' : '#160' ) ;
35
36        // Save the current IsDirty state. The XHTML processor may change the
37        // original HTML, dirtying it.
38        var bIsDirty = FCK.IsDirty() ;
39
40        // Special blocks are blocks of content that remain untouched during the
41        // process. It is used for SCRIPTs and STYLEs.
42        FCKXHtml.SpecialBlocks = new Array() ;
43
44        // Create the XML DOMDocument object.
45        this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
46
47        // Add a root element that holds all child nodes.
48        this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
49
50        FCKXHtml.CurrentJobNum++ ;
51
52//      var dTimer = new Date() ;
53
54        if ( includeNode )
55                this._AppendNode( this.MainNode, node ) ;
56        else
57                this._AppendChildNodes( this.MainNode, node, false ) ;
58
59        /**
60         * FCKXHtml._AppendNode() marks DOM element objects it has
61         * processed by adding a property called _fckxhtmljob,
62         * setting it equal to the value of FCKXHtml.CurrentJobNum.
63         * On Internet Explorer, if an element object has such a
64         * property,  it will show up in the object's attributes
65         * NamedNodeMap, and the corresponding Attr object in
66         * that collection  will have is specified property set
67         * to true.  This trips up code elsewhere that checks to
68         * see if an element is free of attributes before proceeding
69         * with an edit operation (c.f. FCK.Style.RemoveFromRange())
70         *
71         * refs #2156 and #2834
72         */
73        if ( FCKBrowserInfo.IsIE )
74                FCKXHtml._RemoveXHtmlJobProperties( node ) ;
75
76        // Get the resulting XHTML as a string.
77        var sXHTML = this._GetMainXmlString() ;
78
79//      alert( 'Time: ' + ( ( ( new Date() ) - dTimer ) ) + ' ms' ) ;
80
81        this.XML = null ;
82
83        // Safari adds xmlns="http://www.w3.org/1999/xhtml" to the root node (#963)
84        if ( FCKBrowserInfo.IsSafari )
85                sXHTML = sXHTML.replace( /^<xhtml.*?>/, '<xhtml>' ) ;
86
87        // Strip the "XHTML" root node.
88        sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ;
89
90        // According to the doctype set the proper end for self-closing tags
91        // HTML: <br>
92        // XHTML: Add a space, like <br/> -> <br />
93        if (FCKConfig.DocType.length > 0 && FCKRegexLib.HtmlDocType.test( FCKConfig.DocType ) )
94                sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, '>');
95        else
96                sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
97
98        if ( FCKConfig.ForceSimpleAmpersand )
99                sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
100
101        if ( format )
102                sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
103
104        // Now we put back the SpecialBlocks contents.
105        for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
106        {
107                var oRegex = new RegExp( '___FCKsi___' + i ) ;
108                sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
109        }
110
111        // Replace entities marker with the ampersand.
112        sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
113
114        // Restore the IsDirty state if it was not dirty.
115        if ( !bIsDirty )
116                FCK.ResetIsDirty() ;
117
118        FCKDomTools.EnforcePaddingNode( FCKTools.GetElementDocument( node ), FCKConfig.EnterMode ) ;
119        return sXHTML ;
120}
121
122FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
123{
124        try
125        {
126                if ( attributeValue == undefined || attributeValue == null )
127                        attributeValue = '' ;
128                else if ( attributeValue.replace )
129                {
130                        if ( FCKConfig.ForceSimpleAmpersand )
131                                attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
132
133                        // Entities must be replaced in the attribute values.
134                        attributeValue = attributeValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ;
135                }
136
137                // Create the attribute.
138                var oXmlAtt = this.XML.createAttribute( attributeName ) ;
139                oXmlAtt.value = attributeValue ;
140
141                // Set the attribute in the node.
142                xmlNode.attributes.setNamedItem( oXmlAtt ) ;
143        }
144        catch (e)
145        {}
146}
147
148FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
149{
150        var oNode = htmlNode.firstChild ;
151
152        while ( oNode )
153        {
154                this._AppendNode( xmlNode, oNode ) ;
155                oNode = oNode.nextSibling ;
156        }
157
158        // Trim block elements. This is also needed to avoid Firefox leaving extra
159        // BRs at the end of them.
160        if ( isBlockElement && htmlNode.tagName && htmlNode.tagName.toLowerCase() != 'pre' )
161        {
162                FCKDomTools.TrimNode( xmlNode ) ;
163
164                if ( FCKConfig.FillEmptyBlocks )
165                {
166                        var lastChild = xmlNode.lastChild ;
167                        if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName == 'br' )
168                                this._AppendEntity( xmlNode, this._NbspEntity ) ;
169                }
170        }
171
172        // If the resulting node is empty.
173        if ( xmlNode.childNodes.length == 0 )
174        {
175                if ( isBlockElement && FCKConfig.FillEmptyBlocks )
176                {
177                        this._AppendEntity( xmlNode, this._NbspEntity ) ;
178                        return xmlNode ;
179                }
180
181                var sNodeName = xmlNode.nodeName ;
182
183                // Some inline elements are required to have something inside (span, strong, etc...).
184                if ( FCKListsLib.InlineChildReqElements[ sNodeName ] )
185                        return null ;
186
187                // We can't use short representation of empty elements that are not marked
188                // as empty in th XHTML DTD.
189                if ( !FCKListsLib.EmptyElements[ sNodeName ] )
190                        xmlNode.appendChild( this.XML.createTextNode('') ) ;
191        }
192
193        return xmlNode ;
194}
195
196FCKXHtml._AppendNode = function( xmlNode, htmlNode )
197{
198        if ( !htmlNode )
199                return false ;
200
201        switch ( htmlNode.nodeType )
202        {
203                // Element Node.
204                case 1 :
205                        // If we detect a <br> inside a <pre> in Gecko, turn it into a line break instead.
206                        // This is a workaround for the Gecko bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=92921
207                        if ( FCKBrowserInfo.IsGecko
208                                        && htmlNode.tagName.toLowerCase() == 'br'
209                                        && htmlNode.parentNode.tagName.toLowerCase() == 'pre' )
210                        {
211                                var val = '\r' ;
212                                if ( htmlNode == htmlNode.parentNode.firstChild )
213                                        val += '\r' ;
214                                return FCKXHtml._AppendNode( xmlNode, this.XML.createTextNode( val ) ) ;
215                        }
216
217                        // Here we found an element that is not the real element, but a
218                        // fake one (like the Flash placeholder image), so we must get the real one.
219                        if ( htmlNode.getAttribute('_fckfakelement') )
220                                return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
221
222                        // Ignore bogus BR nodes in the DOM.
223                        if ( FCKBrowserInfo.IsGecko &&
224                                        ( htmlNode.hasAttribute('_moz_editor_bogus_node') || htmlNode.getAttribute( 'type' ) == '_moz' ) )
225                        {
226                                if ( htmlNode.nextSibling )
227                                        return false ;
228                                else
229                                {
230                                        htmlNode.removeAttribute( '_moz_editor_bogus_node' ) ;
231                                        htmlNode.removeAttribute( 'type' ) ;
232                                }
233                        }
234
235                        // This is for elements that are instrumental to FCKeditor and
236                        // must be removed from the final HTML.
237                        if ( htmlNode.getAttribute('_fcktemp') )
238                                return false ;
239
240                        // Get the element name.
241                        var sNodeName = htmlNode.tagName.toLowerCase()  ;
242
243                        if ( FCKBrowserInfo.IsIE )
244                        {
245                                // IE doens't include the scope name in the nodeName. So, add the namespace.
246                                if ( htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
247                                        sNodeName = htmlNode.scopeName.toLowerCase() + ':' + sNodeName ;
248                        }
249                        else
250                        {
251                                if ( sNodeName.StartsWith( 'fck:' ) )
252                                        sNodeName = sNodeName.Remove( 0,4 ) ;
253                        }
254
255                        // Check if the node name is valid, otherwise ignore this tag.
256                        // If the nodeName starts with a slash, it is a orphan closing tag.
257                        // On some strange cases, the nodeName is empty, even if the node exists.
258                        if ( !FCKRegexLib.ElementName.test( sNodeName ) )
259                                return false ;
260
261                        // The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
262                        // So here, the "mark" is checked... if the element is Ok, then mark it.
263                        if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
264                                return false ;
265
266                        var oNode = this.XML.createElement( sNodeName ) ;
267
268                        // Add all attributes.
269                        FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
270
271                        htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
272
273                        // Tag specific processing.
274                        var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
275
276                        if ( oTagProcessor )
277                                oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
278                        else
279                                oNode = this._AppendChildNodes( oNode, htmlNode, Boolean( FCKListsLib.NonEmptyBlockElements[ sNodeName ] ) ) ;
280
281                        if ( !oNode )
282                                return false ;
283
284                        xmlNode.appendChild( oNode ) ;
285
286                        break ;
287
288                // Text Node.
289                case 3 :
290                        if ( htmlNode.parentNode && htmlNode.parentNode.nodeName.IEquals( 'pre' ) )
291                                return this._AppendTextNode( xmlNode, htmlNode.nodeValue ) ;
292                        return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;
293
294                // Comment
295                case 8 :
296                        // IE catches the <!DOTYPE ... > as a comment, but it has no
297                        // innerHTML, so we can catch it, and ignore it.
298                        if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
299                                break ;
300
301                        try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
302                        catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
303                        break ;
304
305                // Unknown Node type.
306                default :
307                        xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
308                        break ;
309        }
310        return true ;
311}
312
313// Append an item to the SpecialBlocks array and returns the tag to be used.
314FCKXHtml._AppendSpecialItem = function( item )
315{
316        return '___FCKsi___' + ( FCKXHtml.SpecialBlocks.push( item ) - 1 ) ;
317}
318
319FCKXHtml._AppendEntity = function( xmlNode, entity )
320{
321        xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
322}
323
324FCKXHtml._AppendTextNode = function( targetNode, textValue )
325{
326        var bHadText = textValue.length > 0 ;
327        if ( bHadText )
328                targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
329        return bHadText ;
330}
331
332// Retrieves a entity (internal format) for a given character.
333function FCKXHtml_GetEntity( character )
334{
335        // We cannot simply place the entities in the text, because the XML parser
336        // will translate & to &amp;. So we use a temporary marker which is replaced
337        // in the end of the processing.
338        var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
339        return '#?-:' + sEntity + ';' ;
340}
341
342// An object that hold tag specific operations.
343FCKXHtml.TagProcessors =
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                        // Buggy IE, doesn't copy the name of changed anchors.
360                        if ( htmlNode.name )
361                                FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
362                }
363
364                node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
365
366                return node ;
367        },
368
369        area : function( node, htmlNode )
370        {
371                var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
372                if ( sSavedUrl != null )
373                        FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
374
375                // IE ignores the "COORDS" and "SHAPE" attribute so we must add it manually.
376                if ( FCKBrowserInfo.IsIE )
377                {
378                        if ( ! node.attributes.getNamedItem( 'coords' ) )
379                        {
380                                var sCoords = htmlNode.getAttribute( 'coords', 2 ) ;
381                                if ( sCoords && sCoords != '0,0,0' )
382                                        FCKXHtml._AppendAttribute( node, 'coords', sCoords ) ;
383                        }
384
385                        if ( ! node.attributes.getNamedItem( 'shape' ) )
386                        {
387                                var sShape = htmlNode.getAttribute( 'shape', 2 ) ;
388                                if ( sShape && sShape.length > 0 )
389                                        FCKXHtml._AppendAttribute( node, 'shape', sShape.toLowerCase() ) ;
390                        }
391                }
392
393                return node ;
394        },
395
396        body : function( node, htmlNode )
397        {
398                node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
399                // Remove spellchecker attributes added for Firefox when converting to HTML code (Bug #1351).
400                node.removeAttribute( 'spellcheck' ) ;
401                return node ;
402        },
403
404        // IE loses contents of iframes, and Gecko does give it back HtmlEncoded
405        // Note: Opera does lose the content and doesn't provide it in the innerHTML string
406        iframe : function( node, htmlNode )
407        {
408                var sHtml = htmlNode.innerHTML ;
409
410                // Gecko does give back the encoded html
411                if ( FCKBrowserInfo.IsGecko )
412                        sHtml = FCKTools.HTMLDecode( sHtml );
413
414                // Remove the saved urls here as the data won't be processed as nodes
415                sHtml = sHtml.replace( /\s_fcksavedurl="[^"]*"/g, '' ) ;
416
417                node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( sHtml ) ) ) ;
418
419                return node ;
420        },
421
422        img : function( node, htmlNode )
423        {
424                // The "ALT" attribute is required in XHTML.
425                if ( ! node.attributes.getNamedItem( 'alt' ) )
426                        FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
427
428                var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
429                if ( sSavedUrl != null )
430                        FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
431
432                // Bug #768 : If the width and height are defined inline CSS,
433                // don't define it again in the HTML attributes.
434                if ( htmlNode.style.width )
435                        node.removeAttribute( 'width' ) ;
436                if ( htmlNode.style.height )
437                        node.removeAttribute( 'height' ) ;
438
439                return node ;
440        },
441
442        // Fix orphaned <li> nodes (Bug #503).
443        li : function( node, htmlNode, targetNode )
444        {
445                // If the XML parent node is already a <ul> or <ol>, then add the <li> as usual.
446                if ( targetNode.nodeName.IEquals( ['ul', 'ol'] ) )
447                        return FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
448
449                var newTarget = FCKXHtml.XML.createElement( 'ul' ) ;
450
451                // Reset the _fckxhtmljob so the HTML node is processed again.
452                htmlNode._fckxhtmljob = null ;
453
454                // Loop through all sibling LIs, adding them to the <ul>.
455                do
456                {
457                        FCKXHtml._AppendNode( newTarget, htmlNode ) ;
458
459                        // Look for the next element following this <li>.
460                        do
461                        {
462                                htmlNode = FCKDomTools.GetNextSibling( htmlNode ) ;
463
464                        } while ( htmlNode && htmlNode.nodeType == 3 && htmlNode.nodeValue.Trim().length == 0 )
465
466                }       while ( htmlNode && htmlNode.nodeName.toLowerCase() == 'li' )
467
468                return newTarget ;
469        },
470
471        // Fix nested <ul> and <ol>.
472        ol : function( node, htmlNode, targetNode )
473        {
474                if ( htmlNode.innerHTML.Trim().length == 0 )
475                        return false ;
476
477                var ePSibling = targetNode.lastChild ;
478
479                if ( ePSibling && ePSibling.nodeType == 3 )
480                        ePSibling = ePSibling.previousSibling ;
481
482                if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
483                {
484                        htmlNode._fckxhtmljob = null ;
485                        FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
486                        return false ;
487                }
488
489                node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
490
491                return node ;
492        },
493
494        pre : function ( node, htmlNode )
495        {
496                var firstChild = htmlNode.firstChild ;
497
498                if ( firstChild && firstChild.nodeType == 3 )
499                        node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( '\r\n' ) ) ) ;
500
501                FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
502
503                return node ;
504        },
505
506        script : function( node, htmlNode )
507        {
508                // The "TYPE" attribute is required in XHTML.
509                if ( ! node.attributes.getNamedItem( 'type' ) )
510                        FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
511
512                node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
513
514                return node ;
515        },
516
517        span : function( node, htmlNode )
518        {
519                // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
520                if ( htmlNode.innerHTML.length == 0 )
521                        return false ;
522
523                node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
524
525                return node ;
526        },
527
528        style : function( node, htmlNode )
529        {
530                // The "TYPE" attribute is required in XHTML.
531                if ( ! node.attributes.getNamedItem( 'type' ) )
532                        FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
533
534                var cssText = htmlNode.innerHTML ;
535                if ( FCKBrowserInfo.IsIE )      // Bug #403 : IE always appends a \r\n to the beginning of StyleNode.innerHTML
536                        cssText = cssText.replace( /^(\r\n|\n|\r)/, '' ) ;
537
538                node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( cssText ) ) ) ;
539
540                return node ;
541        },
542
543        title : function( node, htmlNode )
544        {
545                node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
546
547                return node ;
548        }
549} ;
550
551FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;
Note: See TracBrowser for help on using the repository browser.