| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 /* 2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 (function() 7 { 8 // Regex to scan for at the end of blocks, which are actually placeholders. 9 // Safari transforms the to \xa0. (#4172) 10 var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/; 11 12 var protectedSourceMarker = '{cke_protected}'; 13 14 // Return the last non-space child node of the block (#4344). 15 function lastNoneSpaceChild( block ) 16 { 17 var lastIndex = block.children.length, 18 last = block.children[ lastIndex - 1 ]; 19 while ( last && last.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( last.value ) ) 20 last = block.children[ --lastIndex ]; 21 return last; 22 } 23 24 function trimFillers( block, fromSource ) 25 { 26 // If the current node is a block, and if we're converting from source or 27 // we're not in IE then search for and remove any tailing BR node. 28 // 29 // Also, any at the end of blocks are fillers, remove them as well. 30 // (#2886) 31 var children = block.children, lastChild = lastNoneSpaceChild( block ); 32 if ( lastChild ) 33 { 34 if ( ( fromSource || !CKEDITOR.env.ie ) && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br' ) 35 children.pop(); 36 if ( lastChild.type == CKEDITOR.NODE_TEXT && tailNbspRegex.test( lastChild.value ) ) 37 children.pop(); 38 } 39 } 40 41 function blockNeedsExtension( block ) 42 { 43 var lastChild = lastNoneSpaceChild( block ); 44 45 return !lastChild 46 || lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br' 47 // Some of the controls in form needs extension too, 48 // to move cursor at the end of the form. (#4791) 49 || block.name == 'form' && lastChild.name == 'input'; 50 } 51 52 function extendBlockForDisplay( block ) 53 { 54 trimFillers( block, true ); 55 56 if ( blockNeedsExtension( block ) ) 57 { 58 if ( CKEDITOR.env.ie ) 59 block.add( new CKEDITOR.htmlParser.text( '\xa0' ) ); 60 else 61 block.add( new CKEDITOR.htmlParser.element( 'br', {} ) ); 62 } 63 } 64 65 function extendBlockForOutput( block ) 66 { 67 trimFillers( block ); 68 69 if ( blockNeedsExtension( block ) ) 70 block.add( new CKEDITOR.htmlParser.text( '\xa0' ) ); 71 } 72 73 var dtd = CKEDITOR.dtd; 74 75 // Find out the list of block-like tags that can contain <br>. 76 var blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ); 77 for ( var i in blockLikeTags ) 78 { 79 if ( ! ( 'br' in dtd[i] ) ) 80 delete blockLikeTags[i]; 81 } 82 // We just avoid filler in <pre> right now. 83 // TODO: Support filler for <pre>, line break is also occupy line height. 84 delete blockLikeTags.pre; 85 var defaultDataFilterRules = 86 { 87 elements : {}, 88 attributeNames : 89 [ 90 // Event attributes (onXYZ) must not be directly set. They can become 91 // active in the editing area (IE|WebKit). 92 [ ( /^on/ ), '_cke_pa_on' ] 93 ] 94 }; 95 96 var defaultDataBlockFilterRules = { elements : {} }; 97 98 for ( i in blockLikeTags ) 99 defaultDataBlockFilterRules.elements[ i ] = extendBlockForDisplay; 100 101 var defaultHtmlFilterRules = 102 { 103 elementNames : 104 [ 105 // Remove the "cke:" namespace prefix. 106 [ ( /^cke:/ ), '' ], 107 108 // Ignore <?xml:namespace> tags. 109 [ ( /^\?xml:namespace$/ ), '' ] 110 ], 111 112 attributeNames : 113 [ 114 // Attributes saved for changes and protected attributes. 115 [ ( /^_cke_(saved|pa)_/ ), '' ], 116 117 // All "_cke" attributes are to be ignored. 118 [ ( /^_cke.*/ ), '' ], 119 120 [ 'hidefocus', '' ] 121 ], 122 123 elements : 124 { 125 $ : function( element ) 126 { 127 var attribs = element.attributes; 128 129 if ( attribs ) 130 { 131 // Elements marked as temporary are to be ignored. 132 if ( attribs.cke_temp ) 133 return false; 134 135 // Remove duplicated attributes - #3789. 136 var attributeNames = [ 'name', 'href', 'src' ], 137 savedAttributeName; 138 for ( var i = 0 ; i < attributeNames.length ; i++ ) 139 { 140 savedAttributeName = '_cke_saved_' + attributeNames[ i ]; 141 savedAttributeName in attribs && ( delete attribs[ attributeNames[ i ] ] ); 142 } 143 } 144 145 return element; 146 }, 147 148 embed : function( element ) 149 { 150 var parent = element.parent; 151 152 // If the <embed> is child of a <object>, copy the width 153 // and height attributes from it. 154 if ( parent && parent.name == 'object' ) 155 { 156 var parentWidth = parent.attributes.width, 157 parentHeight = parent.attributes.height; 158 parentWidth && ( element.attributes.width = parentWidth ); 159 parentHeight && ( element.attributes.height = parentHeight ); 160 } 161 }, 162 // Restore param elements into self-closing. 163 param : function( param ) 164 { 165 param.children = []; 166 param.isEmpty = true; 167 return param; 168 }, 169 170 // Remove empty link but not empty anchor.(#3829) 171 a : function( element ) 172 { 173 if ( !( element.children.length || 174 element.attributes.name || 175 element.attributes._cke_saved_name ) ) 176 { 177 return false; 178 } 179 }, 180 181 html : function( element ) 182 { 183 delete element.attributes.contenteditable; 184 delete element.attributes[ 'class' ]; 185 }, 186 187 body : function( element ) 188 { 189 delete element.attributes.spellcheck; 190 delete element.attributes.contenteditable; 191 }, 192 193 style : function( element ) 194 { 195 var child = element.children[ 0 ]; 196 child && child.value && ( child.value = CKEDITOR.tools.trim( child.value )); 197 198 if ( !element.attributes.type ) 199 element.attributes.type = 'text/css'; 200 }, 201 202 title : function( element ) 203 { 204 var titleText = element.children[ 0 ]; 205 titleText && ( titleText.value = element.attributes[ '_cke_title' ] || '' ); 206 } 207 }, 208 209 attributes : 210 { 211 'class' : function( value, element ) 212 { 213 // Remove all class names starting with "cke_". 214 return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false; 215 } 216 }, 217 218 comment : function( contents ) 219 { 220 // If this is a comment for protected source. 221 if ( contents.substr( 0, protectedSourceMarker.length ) == protectedSourceMarker ) 222 { 223 // Remove the extra marker for real comments from it. 224 if ( contents.substr( protectedSourceMarker.length, 3 ) == '{C}' ) 225 contents = contents.substr( protectedSourceMarker.length + 3 ); 226 else 227 contents = contents.substr( protectedSourceMarker.length ); 228 229 return new CKEDITOR.htmlParser.cdata( decodeURIComponent( contents ) ); 230 } 231 232 return contents; 233 } 234 }; 235 236 var defaultHtmlBlockFilterRules = { elements : {} }; 237 238 for ( i in blockLikeTags ) 239 defaultHtmlBlockFilterRules.elements[ i ] = extendBlockForOutput; 240 241 if ( CKEDITOR.env.ie ) 242 { 243 // IE outputs style attribute in capital letters. We should convert 244 // them back to lower case. 245 defaultHtmlFilterRules.attributes.style = function( value, element ) 246 { 247 return value.toLowerCase(); 248 }; 249 } 250 251 function protectReadOnly( element ) 252 { 253 element.attributes.contenteditable = "false"; 254 } 255 function unprotectReadyOnly( element ) 256 { 257 delete element.attributes.contenteditable; 258 } 259 // Disable form elements editing mode provided by some browers. (#5746) 260 for ( i in { input : 1, textarea : 1 } ) 261 { 262 defaultDataFilterRules.elements[ i ] = protectReadOnly; 263 defaultHtmlFilterRules.elements[ i ] = unprotectReadyOnly; 264 } 265 266 var protectAttributeRegex = /<(?:a|area|img|input)[\s\S]*?\s((?:href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi; 267 268 var protectElementsRegex = /(?:<style(?=[ >])[^>]*>[\s\S]*<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi, 269 encodedElementsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi; 270 271 var protectElementNamesRegex = /(<\/?)((?:object|embed|param|html|body|head|title)[^>]*>)/gi, 272 unprotectElementNamesRegex = /(<\/?)cke:((?:html|body|head|title)[^>]*>)/gi; 273 274 var protectSelfClosingRegex = /<cke:(param|embed)([^>]*?)\/?>(?!\s*<\/cke:\1)/gi; 275 276 function protectAttributes( html ) 277 { 278 return html.replace( protectAttributeRegex, '$& _cke_saved_$1' ); 279 } 280 281 function protectElements( html ) 282 { 283 return html.replace( protectElementsRegex, function( match ) 284 { 285 return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>'; 286 }); 287 } 288 289 function unprotectElements( html ) 290 { 291 return html.replace( encodedElementsRegex, function( match, encoded ) 292 { 293 return decodeURIComponent( encoded ); 294 }); 295 } 296 297 function protectElementsNames( html ) 298 { 299 return html.replace( protectElementNamesRegex, '$1cke:$2'); 300 } 301 302 function unprotectElementNames( html ) 303 { 304 return html.replace( unprotectElementNamesRegex, '$1$2' ); 305 } 306 307 function protectSelfClosingElements( html ) 308 { 309 return html.replace( protectSelfClosingRegex, '<cke:$1$2></cke:$1>' ); 310 } 311 312 function protectRealComments( html ) 313 { 314 return html.replace( /<!--(?!{cke_protected})[\s\S]+?-->/g, function( match ) 315 { 316 return '<!--' + protectedSourceMarker + 317 '{C}' + 318 encodeURIComponent( match ).replace( /--/g, '%2D%2D' ) + 319 '-->'; 320 }); 321 } 322 323 function unprotectRealComments( html ) 324 { 325 return html.replace( /<!--\{cke_protected\}\{C\}([\s\S]+?)-->/g, function( match, data ) 326 { 327 return decodeURIComponent( data ); 328 }); 329 } 330 331 function protectSource( data, protectRegexes ) 332 { 333 var protectedHtml = [], 334 tempRegex = /<\!--\{cke_temp(comment)?\}(\d*?)-->/g; 335 336 var regexes = 337 [ 338 // Script tags will also be forced to be protected, otherwise 339 // IE will execute them. 340 ( /<script[\s\S]*?<\/script>/gi ), 341 342 // <noscript> tags (get lost in IE and messed up in FF). 343 /<noscript[\s\S]*?<\/noscript>/gi 344 ] 345 .concat( protectRegexes ); 346 347 // First of any other protection, we must protect all comments 348 // to avoid loosing them (of course, IE related). 349 // Note that we use a different tag for comments, as we need to 350 // transform them when applying filters. 351 data = data.replace( (/<!--[\s\S]*?-->/g), function( match ) 352 { 353 return '<!--{cke_tempcomment}' + ( protectedHtml.push( match ) - 1 ) + '-->'; 354 }); 355 356 for ( var i = 0 ; i < regexes.length ; i++ ) 357 { 358 data = data.replace( regexes[i], function( match ) 359 { 360 match = match.replace( tempRegex, // There could be protected source inside another one. (#3869). 361 function( $, isComment, id ) 362 { 363 return protectedHtml[ id ]; 364 } 365 ); 366 return '<!--{cke_temp}' + ( protectedHtml.push( match ) - 1 ) + '-->'; 367 }); 368 } 369 data = data.replace( tempRegex, function( $, isComment, id ) 370 { 371 return '<!--' + protectedSourceMarker + 372 ( isComment ? '{C}' : '' ) + 373 encodeURIComponent( protectedHtml[ id ] ).replace( /--/g, '%2D%2D' ) + 374 '-->'; 375 } 376 ); 377 return data; 378 } 379 380 CKEDITOR.plugins.add( 'htmldataprocessor', 381 { 382 requires : [ 'htmlwriter' ], 383 384 init : function( editor ) 385 { 386 var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor ); 387 388 dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand; 389 390 dataProcessor.dataFilter.addRules( defaultDataFilterRules ); 391 dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules ); 392 dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules ); 393 dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules ); 394 } 395 }); 396 397 CKEDITOR.htmlDataProcessor = function( editor ) 398 { 399 this.editor = editor; 400 401 this.writer = new CKEDITOR.htmlWriter(); 402 this.dataFilter = new CKEDITOR.htmlParser.filter(); 403 this.htmlFilter = new CKEDITOR.htmlParser.filter(); 404 }; 405 406 CKEDITOR.htmlDataProcessor.prototype = 407 { 408 toHtml : function( data, fixForBody ) 409 { 410 // The source data is already HTML, but we need to clean 411 // it up and apply the filter. 412 413 data = protectSource( data, this.editor.config.protectedSource ); 414 415 // Before anything, we must protect the URL attributes as the 416 // browser may changing them when setting the innerHTML later in 417 // the code. 418 data = protectAttributes( data ); 419 420 // Protect elements than can't be set inside a DIV. E.g. IE removes 421 // style tags from innerHTML. (#3710) 422 data = protectElements( data ); 423 424 // Certain elements has problem to go through DOM operation, protect 425 // them by prefixing 'cke' namespace. (#3591) 426 data = protectElementsNames( data ); 427 428 // All none-IE browsers ignore self-closed custom elements, 429 // protecting them into open-close. (#3591) 430 data = protectSelfClosingElements( data ); 431 432 // Call the browser to help us fixing a possibly invalid HTML 433 // structure. 434 var div = new CKEDITOR.dom.element( 'div' ); 435 // Add fake character to workaround IE comments bug. (#3801) 436 div.setHtml( 'a' + data ); 437 data = div.getHtml().substr( 1 ); 438 439 // Unprotect "some" of the protected elements at this point. 440 data = unprotectElementNames( data ); 441 442 data = unprotectElements( data ); 443 444 // Restore the comments that have been protected, in this way they 445 // can be properly filtered. 446 data = unprotectRealComments( data ); 447 448 // Now use our parser to make further fixes to the structure, as 449 // well as apply the filter. 450 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, fixForBody ), 451 writer = new CKEDITOR.htmlParser.basicWriter(); 452 453 fragment.writeHtml( writer, this.dataFilter ); 454 data = writer.getHtml( true ); 455 456 // Protect the real comments again. 457 data = protectRealComments( data ); 458 459 return data; 460 }, 461 462 toDataFormat : function( html, fixForBody ) 463 { 464 var writer = this.writer, 465 fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, fixForBody ); 466 467 writer.reset(); 468 469 fragment.writeHtml( writer, this.htmlFilter ); 470 471 return writer.getHtml( true ); 472 } 473 }; 474 })(); 475 476 /** 477 * Whether to force using "&" instead of "&amp;" in elements attributes 478 * values. It's not recommended to change this setting for compliance with the 479 * W3C XHTML 1.0 standards 480 * (<a href="http://www.w3.org/TR/xhtml1/#C_12">C.12, XHTML 1.0</a>). 481 * @type Boolean 482 * @default false 483 * @example 484 * config.forceSimpleAmpersand = false; 485 */ 486 CKEDITOR.config.forceSimpleAmpersand = false;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |