Ticket #3002: 3002.patch
File 3002.patch, 61.1 KB (added by , 15 years ago) |
---|
-
_source/core/editor.js
188 188 CKEDITOR.scriptLoader.load( languageFiles, function() 189 189 { 190 190 // Initialize all plugins that have the "beforeInit" and "init" methods defined. 191 var methods = [ 'beforeInit', 'init' ];191 var methods = [ 'beforeInit', 'init', 'afterInit' ]; 192 192 for ( var m = 0 ; m < methods.length ; m++ ) 193 193 { 194 194 for ( var i = 0 ; i < pluginsArray.length ; i++ ) -
_source/core/htmlparser/basicwriter.js
1 /* 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 CKEDITOR.htmlParser.basicWriter = CKEDITOR.tools.createClass( 7 { 8 $ : function() 9 { 10 this._ = 11 { 12 output : [] 13 } 14 }, 15 16 proto : 17 { 18 /** 19 * Writes the tag opening part for a opener tag. 20 * @param {String} tagName The element name for this tag. 21 * @param {Object} attributes The attributes defined for this tag. The 22 * attributes could be used to inspect the tag. 23 * @example 24 * // Writes "<p". 25 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } ); 26 */ 27 openTag : function( tagName, attributes ) 28 { 29 this._.output.push( '<', tagName ); 30 }, 31 32 /** 33 * Writes the tag closing part for a opener tag. 34 * @param {String} tagName The element name for this tag. 35 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag, 36 * like "br" or "img". 37 * @example 38 * // Writes ">". 39 * writer.openTagClose( 'p', false ); 40 * @example 41 * // Writes " />". 42 * writer.openTagClose( 'br', true ); 43 */ 44 openTagClose : function( tagName, isSelfClose ) 45 { 46 if ( isSelfClose ) 47 this._.output.push( ' />' ); 48 else 49 this._.output.push( '>' ); 50 }, 51 52 /** 53 * Writes an attribute. This function should be called after opening the 54 * tag with {@link #openTagClose}. 55 * @param {String} attName The attribute name. 56 * @param {String} attValue The attribute value. 57 * @example 58 * // Writes ' class="MyClass"'. 59 * writer.attribute( 'class', 'MyClass' ); 60 */ 61 attribute : function( attName, attValue ) 62 { 63 this._.output.push( ' ', attName, '="', attValue, '"' ); 64 }, 65 66 /** 67 * Writes a closer tag. 68 * @param {String} tagName The element name for this tag. 69 * @example 70 * // Writes "</p>". 71 * writer.closeTag( 'p' ); 72 */ 73 closeTag : function( tagName ) 74 { 75 this._.output.push( '</', tagName, '>' ); 76 }, 77 78 /** 79 * Writes text. 80 * @param {String} text The text value 81 * @example 82 * // Writes "Hello Word". 83 * writer.text( 'Hello Word' ); 84 */ 85 text : function( text ) 86 { 87 this._.output.push( text ); 88 }, 89 90 /** 91 * Writes a comment. 92 * @param {String} comment The comment text. 93 * @example 94 * // Writes "<!-- My comment -->". 95 * writer.comment( ' My comment ' ); 96 */ 97 comment : function( comment ) 98 { 99 this._.output.push( '<!--', comment, '-->' ); 100 }, 101 102 /** 103 * Writes any kind of data to the ouput. 104 * @example 105 * writer.write( 'This is an <b>example</b>.' ); 106 */ 107 write : function( data ) 108 { 109 this._.output.push( data ); 110 }, 111 112 /** 113 * Empties the current output buffer. 114 * @example 115 * writer.reset(); 116 */ 117 reset : function() 118 { 119 this._.output = []; 120 }, 121 122 /** 123 * Empties the current output buffer. 124 * @param {Boolean} reset Indicates that the {@link reset} function is to 125 * be automatically called after retrieving the HTML. 126 * @returns {String} The HTML written to the writer so far. 127 * @example 128 * var html = writer.getHtml(); 129 */ 130 getHtml : function( reset ) 131 { 132 var html = this._.output.join( '' ); 133 134 if ( reset ) 135 this.reset(); 136 137 return html; 138 } 139 } 140 }); 141 No newline at end of file -
_source/core/htmlparser/comment.js
38 38 * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML. 39 39 * @example 40 40 */ 41 writeHtml : function( writer )41 writeHtml : function( writer, filter ) 42 42 { 43 writer.comment( this.value ); 43 var comment = this.value; 44 45 if ( filter && !( comment = filter.onComment( comment ) ) ) 46 return; 47 48 writer.comment( comment ); 44 49 } 45 50 }; -
_source/core/htmlparser/element.js
13 13 */ 14 14 CKEDITOR.htmlParser.element = function( name, attributes ) 15 15 { 16 if ( attributes._cke_saved_src )17 attributes.src = attributes._cke_saved_src;18 19 if ( attributes._cke_saved_href )20 attributes.href = attributes._cke_saved_href;21 22 // IE outputs style attribute in capital letters. We should convert them23 // back to lower case.24 if ( CKEDITOR.env.ie && attributes.style )25 attributes.style = attributes.style.toLowerCase();26 27 16 /** 28 17 * The element name. 29 18 * @type String … … 71 60 return a < b ? -1 : a > b ? 1 : 0; 72 61 }; 73 62 74 var ckeAttrRegex = /^_cke/,75 ckeNamespaceRegex = /^cke:/,76 ckeStyleWidthRegex = /width\s*:\s*(\d+)/i,77 ckeStyleHeightRegex = /height\s*:\s*(\d+)/i,78 ckeClassRegex = /(?:^|\s+)cke_[^\s]*/g,79 ckePrivateAttrRegex = /^_cke_pa_/;80 81 63 CKEDITOR.htmlParser.element.prototype = 82 64 { 83 65 /** … … 113 95 * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML. 114 96 * @example 115 97 */ 116 writeHtml : function( writer )98 writeHtml : function( writer, filter ) 117 99 { 118 100 var attributes = this.attributes; 119 101 120 // The "_cke_realelement" attribute indicates that the current121 // element is a placeholder for another element.122 if ( attributes._cke_realelement )123 {124 var realFragment = new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( attributes._cke_realelement ) );125 126 // If _cke_resizable is set, and the fake element contains inline CSS width127 // and height; then sync the width and height to the real element.128 if ( attributes._cke_resizable && ( 'style' in attributes ) )129 {130 var match = ckeStyleWidthRegex.exec( attributes.style ),131 width = match ? match[1] : null;132 match = ckeStyleHeightRegex.exec( attributes.style );133 var height = match ? match[1] : null;134 135 var targetElement = realFragment.children[ 0 ];136 if ( targetElement && ( width != null || height != null ) )137 {138 targetElement.attributes.width = width;139 targetElement.attributes.height = height;140 141 // Special case for #2916: If there's an EMBED inside an OBJECT, we need142 // to set the EMBED's dimensions as well.143 if ( targetElement.name == 'cke:object' )144 {145 for ( var i = 0 ; i < targetElement.children.length ; i++ )146 {147 var child = targetElement.children[i];148 if ( child.name == 'cke:embed' )149 {150 child.attributes.width = width;151 child.attributes.height = height;152 break;153 }154 }155 }156 }157 }158 159 realFragment.writeHtml( writer );160 return;161 }162 163 102 // The "_cke_replacedata" indicates that this element is replacing 164 103 // a data snippet, which should be outputted as is. 165 104 if ( attributes._cke_replacedata ) … … 169 108 } 170 109 171 110 // Ignore cke: prefixes when writing HTML. 172 var writeName = this.name.replace( ckeNamespaceRegex, '' ); 111 var element = this, 112 writeName = element.name, 113 a, value; 173 114 174 // Open element tag. 175 writer.openTag( writeName, this.attributes ); 176 177 // Copy all attributes to an array. 178 var attribsArray = []; 179 for ( var a in attributes ) 115 if ( filter ) 180 116 { 181 var value = attributes[ a ]; 117 while ( true ) 118 { 119 if ( !( writeName = filter.onElementName( writeName ) ) ) 120 return; 182 121 183 // If the attribute name is _cke_pa_*, strip away the _cke_pa part. 184 a = a.replace( ckePrivateAttrRegex, '' ); 122 element.name = writeName; 185 123 186 // Ignore all attributes starting with "_cke". 187 if ( ckeAttrRegex.test( a ) ) 188 continue; 124 if ( !( element = filter.onElement( element ) ) ) 125 return; 189 126 190 // Ignore all cke_* CSS classes. 191 if ( a.toLowerCase() == 'class' ) 192 { 193 value = CKEDITOR.tools.ltrim( value.replace( ckeClassRegex, '' ) ); 194 if ( value == '' ) 195 continue; 127 if ( element.name == writeName ) 128 break; 129 130 writeName = element.name; 196 131 } 197 132 198 attribsArray.push( [ a, value ] ); 133 // The element may have been changed, so update the local 134 // references. 135 attributes = element.attributes; 199 136 } 200 137 201 // Sort the attributes by name.202 attribsArray.sort( sortAttribs );138 // Open element tag. 139 writer.openTag( writeName, attributes ); 203 140 204 // Send the attributes. 205 for ( var i = 0, len = attribsArray.length ; i < len ; i++ ) 141 if ( writer.sortAttributes ) 206 142 { 207 var attrib = attribsArray[ i ]; 208 writer.attribute( attrib[0], attrib[1] ); 143 // Copy all attributes to an array. 144 var attribsArray = []; 145 for ( a in attributes ) 146 { 147 value = attributes[ a ]; 148 149 if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) ) 150 continue; 151 152 attribsArray.push( [ a, value ] ); 153 } 154 155 // Sort the attributes by name. 156 attribsArray.sort( sortAttribs ); 157 158 // Send the attributes. 159 for ( var i = 0, len = attribsArray.length ; i < len ; i++ ) 160 { 161 var attrib = attribsArray[ i ]; 162 writer.attribute( attrib[0], attrib[1] ); 163 } 209 164 } 165 else 166 { 167 for ( a in attributes ) 168 { 169 writer.attribute( a, attributes[ a ] ); 170 } 171 } 210 172 211 173 // Close the tag. 212 writer.openTagClose( writeName, this.isEmpty );174 writer.openTagClose( writeName, element.isEmpty ); 213 175 214 if ( ! this.isEmpty )176 if ( !element.isEmpty ) 215 177 { 216 178 // Send children. 217 CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( this, arguments );179 CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments ); 218 180 219 181 // Close the element. 220 182 writer.closeTag( writeName ); -
_source/core/htmlparser/filter.js
1 /* 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 (function() 7 { 8 CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass( 9 { 10 $ : function( rules ) 11 { 12 this._ = 13 { 14 elementNames : [], 15 attributeNames : [], 16 elements : { $length : 0 }, 17 attributes : { $length : 0 } 18 }; 19 20 if ( rules ) 21 this.addRules( rules, 10 ); 22 }, 23 24 proto : 25 { 26 addRules : function( rules, priority ) 27 { 28 if ( typeof priority != 'number' ) 29 priority = 10; 30 31 // Add the elementNames. 32 addItemsToList( this._.elementNames, rules.elementNames, priority ); 33 34 // Add the attributeNames. 35 addItemsToList( this._.attributeNames, rules.attributeNames, priority ); 36 37 // Add the elements. 38 addNamedItems( this._.elements, rules.elements, priority ); 39 40 // Add the attributes. 41 addNamedItems( this._.attributes, rules.attributes, priority ); 42 43 // Add the text. 44 this._.text = transformNamedItem( this._.text, rules.text, priority ) || this._.text; 45 46 // Add the comment. 47 this._.comment = transformNamedItem( this._.comment, rules.comment, priority ) || this._.comment; 48 }, 49 50 onElementName : function( name ) 51 { 52 return filterName( name, this._.elementNames ); 53 }, 54 55 onAttributeName : function( name ) 56 { 57 return filterName( name, this._.attributeNames ); 58 }, 59 60 onText : function( text ) 61 { 62 var textFilter = this._.text; 63 return textFilter ? textFilter.filter( text ) : text; 64 }, 65 66 onComment : function( commentText ) 67 { 68 var textFilter = this._.comment; 69 return textFilter ? textFilter.filter( commentText ) : commentText; 70 }, 71 72 onElement : function( element ) 73 { 74 // We must apply filters set to the specific element name as 75 // well as those set to the generic $ name. So, add both to an 76 // array and process them in a small loop. 77 var filters = [ this._.elements[ element.name ], this._.elements.$ ], 78 filter, ret; 79 80 for ( var i = 0 ; i < 2 ; i++ ) 81 { 82 filter = filters[ i ]; 83 if ( filter ) 84 { 85 ret = filter.filter( element, this ); 86 87 if ( ret === false ) 88 return null; 89 90 if ( ret && ret != element ) 91 return this.onElement( ret );; 92 } 93 } 94 95 return element; 96 }, 97 98 onAttribute : function( element, name, value ) 99 { 100 var filter = this._.attributes[ name ]; 101 102 if ( filter ) 103 { 104 var ret = filter.filter( value, element, this ); 105 106 if ( ret === false ) 107 return false; 108 109 if ( typeof ret != 'undefined' ) 110 return ret; 111 } 112 113 return value; 114 } 115 } 116 }); 117 118 function filterName( name, filters ) 119 { 120 for ( var i = 0 ; name && i < filters.length ; i++ ) 121 { 122 var filter = filters[ i ]; 123 name = name.replace( filter[ 0 ], filter[ 1 ] ); 124 } 125 return name; 126 } 127 128 function addItemsToList( list, items, priority ) 129 { 130 var i, j, 131 listLength = list.length, 132 itemsLength = items && items.length; 133 134 if ( itemsLength ) 135 { 136 // Find the index to insert the items at. 137 for ( i = 0 ; i < listLength && list[ i ].pri < priority ; i++ ) 138 {} 139 140 // Add all new items to the list at the specific index. 141 for ( j = itemsLength - 1 ; j >= 0 ; j-- ) 142 { 143 var item = items[ j ]; 144 item.pri = priority; 145 list.splice( i, 0, item ); 146 } 147 } 148 } 149 150 function addNamedItems( hashTable, items, priority ) 151 { 152 if ( items ) 153 { 154 for ( var name in items ) 155 { 156 var current = hashTable[ name ]; 157 158 hashTable[ name ] = 159 transformNamedItem( 160 current, 161 items[ name ], 162 priority ); 163 164 if ( !current ) 165 hashTable.$length++; 166 } 167 } 168 } 169 170 function transformNamedItem( current, item, priority ) 171 { 172 if ( item ) 173 { 174 item.pri = priority; 175 176 if ( current ) 177 { 178 // If the current item is not an Array, transform it. 179 if ( !current.splice ) 180 { 181 if ( current.pri > priority ) 182 current = [ item, current ]; 183 else 184 current = [ current, item ]; 185 186 current.filter = callItems; 187 } 188 else 189 addItemsToList( current, item, priority ); 190 191 return current; 192 } 193 else 194 { 195 item.filter = item; 196 return item; 197 } 198 } 199 } 200 201 function callItems( currentEntry ) 202 { 203 var isObject = ( typeof currentEntry == 'object' ); 204 205 for ( var i = 0 ; i < this.length ; i++ ) 206 { 207 var item = this[ i ], 208 ret = item.apply( window, arguments ); 209 210 if ( typeof ret != 'undefined' ) 211 { 212 if ( ret === false ) 213 return false; 214 215 if ( isObject && ret != currentEntry ) 216 return ret; 217 } 218 } 219 } 220 })(); 221 222 // "entities" plugin 223 /* 224 { 225 text : function( text ) 226 { 227 // TODO : Process entities. 228 return text.toUpperCase(); 229 } 230 }; 231 */ 232 No newline at end of file -
_source/core/htmlparser/fragment.js
90 90 91 91 parser.onTagOpen = function( tagName, attributes, selfClosing ) 92 92 { 93 // If the tag name is ?xml:namespace, ignore.94 if ( tagName == '?xml:namespace' )95 return;96 97 93 var element = new CKEDITOR.htmlParser.element( tagName, attributes ); 98 94 99 95 // "isEmpty" will be always "false" for unknown elements, so we … … 278 274 * fragment.writeHtml( writer ) 279 275 * alert( writer.getHtml() ); "<p><b>Example</b></p>" 280 276 */ 281 writeHtml : function( writer )277 writeHtml : function( writer, filter ) 282 278 { 283 279 for ( var i = 0, len = this.children.length ; i < len ; i++ ) 284 this.children[i].writeHtml( writer );280 this.children[i].writeHtml( writer, filter ); 285 281 } 286 282 }; 287 283 })(); -
_source/core/htmlparser/text.js
42 42 * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML. 43 43 * @example 44 44 */ 45 writeHtml : function( writer )45 writeHtml : function( writer, filter ) 46 46 { 47 writer.text( this.value ); 47 var text = this.value; 48 49 if ( filter && !( text = filter.onText( text ) ) ) 50 return; 51 52 writer.text( text ); 48 53 } 49 54 }; 50 55 })(); -
_source/core/loader.js
25 25 { 26 26 'core/_bootstrap' : [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ], 27 27 'core/ajax' : [ 'core/xml' ], 28 'core/ckeditor' : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/ tools' ],28 'core/ckeditor' : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ], 29 29 'core/ckeditor_base' : [], 30 30 'core/ckeditor_basic' : [ 'core/editor_basic', 'core/env', 'core/event' ], 31 31 'core/command' : [], … … 54 54 'core/htmlparser/element' : [ 'core/htmlparser', 'core/htmlparser/fragment' ], 55 55 'core/htmlparser/fragment' : [ 'core/htmlparser', 'core/htmlparser/comment', 'core/htmlparser/text' ], 56 56 'core/htmlparser/text' : [ 'core/htmlparser' ], 57 'core/htmlparser/filter' : [ 'core/htmlparser' ], 58 'core/htmlparser/basicwriter': [ 'core/htmlparser' ], 57 59 'core/imagecacher' : [ 'core/dom/element' ], 58 60 'core/lang' : [], 59 61 'core/plugins' : [ 'core/resourcemanager' ], -
_source/plugins/fakeobjects/plugin.js
3 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 4 */ 5 5 6 CKEDITOR.plugins.add( 'fakeobjects' ); 6 (function() 7 { 8 var htmlFilterRules = 9 { 10 elements : 11 { 12 $ : function( element, filter ) 13 { 14 var realHtml = element.attributes._cke_realelement; 15 realFragment = realHtml && new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( realHtml ), filter ), 16 realElement = realFragment && realFragment.children[ 0 ]; 7 17 18 if ( realElement ) 19 { 20 // If we have width/height in the element, we must move it into 21 // the real element. 22 23 var style = element.attributes.style; 24 25 if ( style ) 26 { 27 // Get the width from the style. 28 var match = /(?:$|\s)width\s*:\s*(\d+)/.exec( style ), 29 width = match && match[1]; 30 31 // Get the height from the style. 32 match = /(?:$|\s)height\s*:\s*(\d+)/.exec( style ); 33 var height = match && match[1]; 34 35 if ( width ) 36 realElement.attributes.width = width; 37 38 if ( height ) 39 realElement.attributes.height = height; 40 } 41 } 42 43 return realElement; 44 } 45 } 46 }; 47 48 CKEDITOR.plugins.add( 'fakeobjects', 49 { 50 requires : [ 'htmlwriter' ], 51 52 afterInit : function( editor ) 53 { 54 var dataProcessor = editor.dataProcessor, 55 htmlFilter = dataProcessor && dataProcessor.htmlFilter; 56 57 if ( htmlFilter ) 58 htmlFilter.addRules( htmlFilterRules ); 59 } 60 }); 61 })(); 62 8 63 CKEDITOR.editor.prototype.createFakeElement = function( realElement, className, realElementType, isResizable ) 9 64 { 10 65 var attributes = … … 21 76 return this.document.createElement( 'img', { attributes : attributes } ); 22 77 }; 23 78 79 CKEDITOR.editor.prototype.createFakeParserElement = function( realElement, className, realElementType, isResizable ) 80 { 81 var writer = new CKEDITOR.htmlParser.basicWriter(); 82 83 realElement.writeHtml( writer ); 84 85 var html = writer.getHtml(); 86 87 var attributes = 88 { 89 'class' : className, 90 src : CKEDITOR.getUrl( 'images/spacer.gif' ), 91 _cke_realelement : encodeURIComponent( html ) 92 }; 93 94 if ( realElementType ) 95 attributes._cke_real_element_type = realElementType; 96 97 if ( isResizable ) 98 attributes._cke_resizable = isResizable; 99 100 return new CKEDITOR.htmlParser.element( 'img', attributes ); 101 }; 102 24 103 CKEDITOR.editor.prototype.restoreRealElement = function( fakeElement ) 25 104 { 26 105 var html = decodeURIComponent( fakeElement.getAttribute( '_cke_realelement' ) ); -
_source/plugins/flash/plugin.js
3 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 4 */ 5 5 6 CKEDITOR.plugins.add( 'flash', 6 (function() 7 7 { 8 init : function( editor ) 8 var flashFilenameRegex = /\.swf(?:$|\?)/i, 9 numberRegex = /^\d+(?:\.\d+)?$/; 10 11 function cssifyLength( length ) 9 12 { 10 var flash = CKEDITOR.plugins.flash, 11 flashFilenameRegex = /\.swf(?:$|\?)/i, 12 numberRegex = /^\d+(?:\.\d+)?$/; 13 if ( numberRegex.test( length ) ) 14 return length + 'px'; 15 return length; 16 } 13 17 14 function cssifyLength( length ) 15 { 16 if ( numberRegex.test( length ) ) 17 return length + 'px'; 18 return length; 19 } 18 function isFlashEmbed( element ) 19 { 20 var attributes = element.attributes; 20 21 21 editor.addCommand( 'flash', new CKEDITOR.dialogCommand( 'flash' ) ); 22 editor.ui.addButton( 'Flash', 23 { 24 label : editor.lang.common.flash, 25 command : 'flash' 26 }); 27 CKEDITOR.dialog.add( 'flash', this.path + 'dialogs/flash.js' ); 22 return ( attributes.type != 'application/x-shockwave-flash' || !flashFilenameRegex.test( attributes.src || '' ) ); 23 } 28 24 29 editor.addCss( 30 'img.cke_flash' + 31 '{' + 32 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/flashlogo.gif' ) + ');' + 33 'background-position: center center;' + 34 'background-repeat: no-repeat;' + 35 'border: 1px solid #a9a9a9;' + 36 'width: 80px;' + 37 'height: 80px;' + 38 '}' 39 ); 25 function createFakeElement( editor, realElement ) 26 { 27 var fakeElement = editor.createFakeParserElement( realElement, 'cke_flash', 'flash', true ), 28 fakeStyle = fakeElement.attributes.style || ''; 40 29 41 editor.on( 'contentDom', function() 42 { 43 var rawObjectNodes = editor.document.$.getElementsByTagName( CKEDITOR.env.ie ? 'object' : 'cke:object' ); 44 for ( var i = rawObjectNodes.length - 1, objectNode ; i >= 0 ; i-- ) 45 { 46 objectNode = new CKEDITOR.dom.element( rawObjectNodes[ i ] ); 47 if ( String( objectNode.getAttribute( 'classid' ) ).toLowerCase() != 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' ) 48 continue; 30 var width = realElement.attributes.width, 31 height = realElement.attributes.height; 49 32 50 var fakeElement = editor.createFakeElement( objectNode, 'cke_flash', 'flash', true ); 51 if ( objectNode.getAttribute( 'width' ) != null ) 52 fakeElement.setStyle( 'width', cssifyLength( objectNode.getAttribute( 'width' ) ) ); 53 if ( objectNode.getAttribute( 'height' ) != null ) 54 fakeElement.setStyle( 'height', cssifyLength( objectNode.getAttribute( 'height' ) ) ); 55 fakeElement.replace( objectNode ); 56 } 33 if ( typeof width != 'undefined' ) 34 fakeStyle = fakeElement.attributes.style = fakeStyle + 'width:' + cssifyLength( width ) + ';'; 57 35 58 var rawEmbedNodes = editor.document.$.getElementsByTagName( CKEDITOR.env.ie ? 'embed' : 'cke:embed' ); 59 for ( var i = rawEmbedNodes.length - 1, embedNode ; i >= 0 ; i-- ) 60 { 61 embedNode = new CKEDITOR.dom.element( rawEmbedNodes[ i ] ); 62 if ( embedNode.getAttribute( 'type' ) != 'application/x-shockwave-flash' 63 && !flashFilenameRegex.test( embedNode.getAttribute( 'src' ) ) ) 64 continue; 65 var fakeElement = editor.createFakeElement( embedNode, 'cke_flash', 'flash', true ); 66 if ( embedNode.getAttribute( 'width' ) != null ) 67 fakeElement.setStyle( 'width', cssifyLength( embedNode.getAttribute( 'width' ) ) ); 68 if ( embedNode.getAttribute( 'height' ) != null ) 69 fakeElement.setStyle( 'height', cssifyLength( embedNode.getAttribute( 'height' ) ) ); 70 fakeElement.replace( embedNode ); 71 } 72 } ); 36 if ( typeof height != 'undefined' ) 37 fakeStyle = fakeElement.attributes.style = fakeStyle + 'height:' + cssifyLength( height ) + ';'; 73 38 74 // If the "menu" plugin is loaded, register the menu items. 75 if ( editor.addMenuItems ) 39 return fakeElement; 40 } 41 42 CKEDITOR.plugins.add( 'flash', 43 { 44 init : function( editor ) 76 45 { 77 editor.addMenuItems( 46 editor.addCommand( 'flash', new CKEDITOR.dialogCommand( 'flash' ) ); 47 editor.ui.addButton( 'Flash', 78 48 { 79 flash : 80 { 81 label : editor.lang.flash.properties, 82 command : 'flash', 83 group : 'flash' 84 } 49 label : editor.lang.common.flash, 50 command : 'flash' 85 51 }); 86 }52 CKEDITOR.dialog.add( 'flash', this.path + 'dialogs/flash.js' ); 87 53 88 // If the "contextmenu" plugin is loaded, register the listeners. 89 if ( editor.contextMenu ) 54 editor.addCss( 55 'img.cke_flash' + 56 '{' + 57 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/flashlogo.gif' ) + ');' + 58 'background-position: center center;' + 59 'background-repeat: no-repeat;' + 60 'border: 1px solid #a9a9a9;' + 61 'width: 80px;' + 62 'height: 80px;' + 63 '}' 64 ); 65 66 // If the "menu" plugin is loaded, register the menu items. 67 if ( editor.addMenuItems ) 68 { 69 editor.addMenuItems( 70 { 71 flash : 72 { 73 label : editor.lang.flash.properties, 74 command : 'flash', 75 group : 'flash' 76 } 77 }); 78 } 79 80 // If the "contextmenu" plugin is loaded, register the listeners. 81 if ( editor.contextMenu ) 82 { 83 editor.contextMenu.addListener( function( element, selection ) 84 { 85 if ( element && element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'flash' ) 86 return { flash : CKEDITOR.TRISTATE_OFF }; 87 }); 88 } 89 }, 90 91 afterInit : function( editor ) 90 92 { 91 editor.contextMenu.addListener( function( element, selection ) 92 { 93 if ( element && element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'flash' ) 94 return { flash : CKEDITOR.TRISTATE_OFF }; 95 }); 96 } 97 }, 93 var dataProcessor = editor.dataProcessor, 94 dataFilter = dataProcessor && dataProcessor.dataFilter; 98 95 99 requires : [ 'fakeobjects' ] 100 } ); 96 if ( dataFilter ) 97 { 98 dataFilter.addRules( 99 { 100 elements : 101 { 102 'cke:object' : function( element ) 103 { 104 var attributes = element.attributes, 105 classId = attributes.classid && String( attributes.classid ).toLowerCase(); 101 106 107 if ( !classId ) 108 { 109 // Look for the inner <embed> 110 for ( var i = 0 ; i < element.children.length ; i++ ) 111 { 112 if ( element.children[ i ].name == 'embed' ) 113 { 114 if ( !isFlashEmbed( element.children[ i ] ) ) 115 return; 116 117 return createFakeElement( editor, element ); 118 } 119 } 120 return; 121 } 122 123 return createFakeElement( editor, element ); 124 }, 125 126 'cke:embed' : function( element ) 127 { 128 if ( !isFlashEmbed( element ) ) 129 return; 130 131 return createFakeElement( editor, element ); 132 } 133 } 134 }, 135 5); 136 } 137 }, 138 139 requires : [ 'fakeobjects' ] 140 }); 141 })(); 142 102 143 CKEDITOR.tools.extend( CKEDITOR.config, 103 144 { 104 145 flashUploadTab : true, -
_source/plugins/htmldataprocessor/plugin.js
3 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 4 */ 5 5 6 CKEDITOR.plugins.add( 'htmldataprocessor', 6 (function() 7 7 { 8 requires : [ 'htmlwriter' ], 8 var defaultDataFilterRules = 9 { 10 elementNames : 11 [ 12 // Elements that cause problems in wysiwyg mode. 13 [ /^(object|embed|param)$/, 'cke:$1' ] 14 ], 9 15 10 init : function( editor, pluginPath ) 16 attributeNames : 17 [ 18 // Event attributes (onXYZ) must not be directly set. They can become 19 // active in the editing area (IE|WebKit). 20 [ /^on/, '_cke_pa_on' ] 21 ] 22 }; 23 24 var defaultHtmlFilterRules = 25 { 26 elementNames : 27 [ 28 // Remove the "cke:" namespace prefix. 29 [ /^cke:/, '' ], 30 31 // Ignore <?xml:namespace> tags. 32 [ /^\?xml:namespace$/, '' ] 33 ], 34 35 attributeNames : 36 [ 37 // Attributes saved for changes and protected attributes. 38 [ /^_cke_(saved|pa)_/, '' ], 39 40 // All "_cke" attributes are to be ignored. 41 [ /^_cke.*/, '' ] 42 ], 43 44 elements : 45 { 46 embed : function( element ) 47 { 48 var parent = element.parent; 49 50 // If the <embed> is child of a <object>, copy the width 51 // and height attributes from it. 52 if ( parent && parent.name == 'object' ) 53 { 54 element.attributes.width = parent.attributes.width; 55 element.attributes.height = parent.attributes.height; 56 } 57 }, 58 59 img : function( element ) 60 { 61 var attribs = element.attributes; 62 63 if ( attribs._cke_saved_src ) 64 delete attribs.src; 65 }, 66 67 a : function( element ) 68 { 69 var attribs = element.attributes; 70 71 if ( attribs._cke_saved_href ) 72 delete attribs.href; 73 } 74 }, 75 76 attributes : 77 { 78 'class' : function( value, element ) 79 { 80 // Remove all class names starting with "cke_". 81 return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false; 82 } 83 } 84 }; 85 86 if ( CKEDITOR.env.ie ) 11 87 { 12 var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor(); 13 14 dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand; 88 // IE outputs style attribute in capital letters. We should convert 89 // them back to lower case. 90 defaultHtmlFilterRules.attributes.style = function( value, element ) 91 { 92 return value.toLowerCase(); 93 } 15 94 } 16 });17 95 18 CKEDITOR.htmlDataProcessor = function() 19 { 20 this.writer = new CKEDITOR.htmlWriter(); 21 }; 96 var protectUrlTagRegex = /<(?:a|area|img).*?\s((?:href|src)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi; 22 97 23 CKEDITOR.htmlDataProcessor.prototype = 24 { 25 toHtml : function( data ) 98 function protectUrls( html ) 26 99 { 27 // The source data is already HTML, so just return it as is. 28 return data; 29 }, 100 return html.replace( protectUrlTagRegex, '$& _cke_saved_$1' ); 101 }; 30 102 31 toDataFormat : function( element )103 CKEDITOR.plugins.add( 'htmldataprocessor', 32 104 { 33 var writer = this.writer, 34 fragment = CKEDITOR.htmlParser.fragment.fromHtml( element.getHtml() ); 105 requires : [ 'htmlwriter' ], 35 106 36 writer.reset(); 107 init : function( editor, pluginPath ) 108 { 109 var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor(); 37 110 38 fragment.writeHtml( writer );111 dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand; 39 112 40 return writer.getHtml( true ); 41 } 42 }; 113 dataProcessor.dataFilter.addRules( defaultDataFilterRules ); 114 dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules ); 115 } 116 }); 43 117 118 CKEDITOR.htmlDataProcessor = function() 119 { 120 this.writer = new CKEDITOR.htmlWriter(); 121 this.dataFilter = new CKEDITOR.htmlParser.filter(); 122 this.htmlFilter = new CKEDITOR.htmlParser.filter(); 123 }; 124 125 CKEDITOR.htmlDataProcessor.prototype = 126 { 127 toHtml : function( data ) 128 { 129 // The source data is already HTML, but we need to clean 130 // it up and apply the filter. 131 132 // Before anything, we must protect the URL attributes as the 133 // browser may changing them when setting the innerHTML later in 134 // the code. 135 data = protectUrls( data ); 136 137 // Call the browser to help us fixing a possibly invalid HTML 138 // structure. 139 var div = document.createElement( 'div' ); 140 div.innerHTML = data; 141 142 // Now use our parser to make further fixes to the structure, as 143 // well as apply the filter. 144 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( div.innerHTML ), 145 writer = new CKEDITOR.htmlParser.basicWriter(); 146 147 fragment.writeHtml( writer, this.dataFilter ); 148 149 return writer.getHtml( true ); 150 }, 151 152 toDataFormat : function( html ) 153 { 154 var writer = this.writer, 155 fragment = CKEDITOR.htmlParser.fragment.fromHtml( html ); 156 157 writer.reset(); 158 159 fragment.writeHtml( writer, this.htmlFilter ); 160 161 return writer.getHtml( true ); 162 } 163 }; 164 })(); 165 44 166 CKEDITOR.config.forceSimpleAmpersand = false; -
_source/plugins/htmlwriter/plugin.js
3 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 4 */ 5 5 6 CKEDITOR.plugins.add( 'htmlwriter' ); 7 6 8 /** 7 9 * Class used to write HTML data. 8 10 * @constructor … … 15 17 * writer.closeTag( 'p' ); 16 18 * alert( writer.getHtml() ); "<p class="MyClass">Hello</p>" 17 19 */ 18 CKEDITOR.htmlWriter = function()20 CKEDITOR.htmlWriter = CKEDITOR.tools.createClass( 19 21 { 20 /** 21 * The characters to be used for each identation step. 22 * @type String 23 * @default "\t" (tab) 24 * @example 25 * // Use two spaces for indentation. 26 * editorInstance.dataProcessor.writer.indentationChars = ' '; 27 */ 28 this.indentationChars = '\t'; 22 base : CKEDITOR.htmlParser.basicWriter, 29 23 30 /** 31 * The characters to be used to close "self-closing" elements, like "br" or 32 * "img". 33 * @type String 34 * @default " />" 35 * @example 36 * // Use HTML4 notation for self-closing elements. 37 * editorInstance.dataProcessor.writer.selfClosingEnd = '>'; 38 */ 39 this.selfClosingEnd = ' />'; 24 $ : function() 25 { 26 // Call the base contructor. 27 this.base(); 40 28 41 /**42 * The characters to be used for line breaks.43 * @type String44 * @default "\n" (LF)45 * @example46 * // Use CRLF for line breaks.47 * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';48 */49 this.lineBreakChars = '\n';29 /** 30 * The characters to be used for each identation step. 31 * @type String 32 * @default "\t" (tab) 33 * @example 34 * // Use two spaces for indentation. 35 * editorInstance.dataProcessor.writer.indentationChars = ' '; 36 */ 37 this.indentationChars = '\t'; 50 38 51 this.forceSimpleAmpersand = false; 39 /** 40 * The characters to be used to close "self-closing" elements, like "br" or 41 * "img". 42 * @type String 43 * @default " />" 44 * @example 45 * // Use HTML4 notation for self-closing elements. 46 * editorInstance.dataProcessor.writer.selfClosingEnd = '>'; 47 */ 48 this.selfClosingEnd = ' />'; 52 49 53 this._ = 54 { 55 output : [], 56 indent : false, 57 indentation : '', 58 rules : {} 59 }; 50 /** 51 * The characters to be used for line breaks. 52 * @type String 53 * @default "\n" (LF) 54 * @example 55 * // Use CRLF for line breaks. 56 * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n'; 57 */ 58 this.lineBreakChars = '\n'; 60 59 61 var dtd = CKEDITOR.dtd;60 this.forceSimpleAmpersand = false; 62 61 63 for ( var e in CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) 64 { 65 this.setRules( e, 66 { 67 indent : true, 68 breakBeforeOpen : true, 69 breakAfterOpen : true, 70 breakBeforeClose : !dtd[ e ][ '#' ], 71 breakAfterClose : true 72 }); 73 } 62 this.sortAttributes = true; 74 63 75 this.setRules( 'br', 76 { 77 breakAfterOpen : true 78 }); 79 }; 64 this._.indent = false; 65 this._.indentation = ''; 66 this._.rules = {}; 80 67 81 CKEDITOR.htmlWriter.prototype = 82 { 83 /** 84 * Writes the tag opening part for a opener tag. 85 * @param {String} tagName The element name for this tag. 86 * @param {Object} attributes The attributes defined for this tag. The 87 * attributes could be used to inspect the tag. 88 * @example 89 * // Writes "<p". 90 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } ); 91 */ 92 openTag : function( tagName, attributes ) 93 { 94 var rules = this._.rules[ tagName ]; 68 var dtd = CKEDITOR.dtd; 95 69 96 if ( this._.indent ) 97 this.indentation(); 98 // Do not break if indenting. 99 else if ( rules && rules.breakBeforeOpen ) 70 for ( var e in CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) 100 71 { 101 this.lineBreak(); 102 this.indentation(); 72 this.setRules( e, 73 { 74 indent : true, 75 breakBeforeOpen : true, 76 breakAfterOpen : true, 77 breakBeforeClose : !dtd[ e ][ '#' ], 78 breakAfterClose : true 79 }); 103 80 } 104 81 105 this._.output.push( '<', tagName ); 82 this.setRules( 'br', 83 { 84 breakAfterOpen : true 85 }); 106 86 }, 107 87 108 /** 109 * Writes the tag closing part for a opener tag. 110 * @param {String} tagName The element name for this tag. 111 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag, 112 * like "br" or "img". 113 * @example 114 * // Writes ">". 115 * writer.openTagClose( 'p', false ); 116 * @example 117 * // Writes " />". 118 * writer.openTagClose( 'br', true ); 119 */ 120 openTagClose : function( tagName, isSelfClose ) 88 proto : 121 89 { 122 var rules = this._.rules[ tagName ]; 123 124 if ( isSelfClose ) 125 this._.output.push( this.selfClosingEnd ); 126 else 90 /** 91 * Writes the tag opening part for a opener tag. 92 * @param {String} tagName The element name for this tag. 93 * @param {Object} attributes The attributes defined for this tag. The 94 * attributes could be used to inspect the tag. 95 * @example 96 * // Writes "<p". 97 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } ); 98 */ 99 openTag : function( tagName, attributes ) 127 100 { 128 this._.output.push( '>' );101 var rules = this._.rules[ tagName ]; 129 102 130 if ( rules && rules.indent ) 131 this._.indentation += this.indentationChars; 132 } 103 if ( this._.indent ) 104 this.indentation(); 105 // Do not break if indenting. 106 else if ( rules && rules.breakBeforeOpen ) 107 { 108 this.lineBreak(); 109 this.indentation(); 110 } 133 111 134 if ( rules && rules.breakAfterOpen ) 135 this.lineBreak(); 136 }, 112 this._.output.push( '<', tagName ); 113 }, 137 114 138 /** 139 * Writes an attribute. This function should be called after opening the 140 * tag with {@link #openTagClose}. 141 * @param {String} attName The attribute name. 142 * @param {String} attValue The attribute value. 143 * @example 144 * // Writes ' class="MyClass"'. 145 * writer.attribute( 'class', 'MyClass' ); 146 */ 147 attribute : function( attName, attValue ) 148 { 149 if ( this.forceSimpleAmpersand ) 150 attValue = attValue.replace( /&/, '&' ); 115 /** 116 * Writes the tag closing part for a opener tag. 117 * @param {String} tagName The element name for this tag. 118 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag, 119 * like "br" or "img". 120 * @example 121 * // Writes ">". 122 * writer.openTagClose( 'p', false ); 123 * @example 124 * // Writes " />". 125 * writer.openTagClose( 'br', true ); 126 */ 127 openTagClose : function( tagName, isSelfClose ) 128 { 129 var rules = this._.rules[ tagName ]; 151 130 152 this._.output.push( ' ', attName, '="', attValue, '"' ); 153 }, 131 if ( isSelfClose ) 132 this._.output.push( this.selfClosingEnd ); 133 else 134 { 135 this._.output.push( '>' ); 154 136 155 /** 156 * Writes a closer tag. 157 * @param {String} tagName The element name for this tag. 158 * @example 159 * // Writes "</p>". 160 * writer.closeTag( 'p' ); 161 */ 162 closeTag : function( tagName ) 163 { 164 var rules = this._.rules[ tagName ]; 137 if ( rules && rules.indent ) 138 this._.indentation += this.indentationChars; 139 } 165 140 166 if ( rules && rules.indent ) 167 this._.indentation = this._.indentation.substr( this.indentationChars.length ); 141 if ( rules && rules.breakAfterOpen ) 142 this.lineBreak(); 143 }, 168 144 169 if ( this._.indent ) 170 this.indentation(); 171 // Do not break if indenting. 172 else if ( rules && rules.breakBeforeClose ) 145 /** 146 * Writes an attribute. This function should be called after opening the 147 * tag with {@link #openTagClose}. 148 * @param {String} attName The attribute name. 149 * @param {String} attValue The attribute value. 150 * @example 151 * // Writes ' class="MyClass"'. 152 * writer.attribute( 'class', 'MyClass' ); 153 */ 154 attribute : function( attName, attValue ) 173 155 { 174 this.lineBreak(); 175 this.indentation(); 176 } 156 if ( this.forceSimpleAmpersand ) 157 attValue = attValue.replace( /&/, '&' ); 177 158 178 this._.output.push( '</', tagName, '>' ); 159 this._.output.push( ' ', attName, '="', attValue, '"' ); 160 }, 179 161 180 if ( rules && rules.breakAfterClose ) 181 this.lineBreak(); 182 }, 183 184 /** 185 * Writes text. 186 * @param {String} text The text value 187 * @example 188 * // Writes "Hello Word". 189 * writer.text( 'Hello Word' ); 190 */ 191 text : function( text ) 192 { 193 if ( this._.indent ) 162 /** 163 * Writes a closer tag. 164 * @param {String} tagName The element name for this tag. 165 * @example 166 * // Writes "</p>". 167 * writer.closeTag( 'p' ); 168 */ 169 closeTag : function( tagName ) 194 170 { 195 this.indentation(); 196 text = CKEDITOR.tools.ltrim( text ); 197 } 171 var rules = this._.rules[ tagName ]; 198 172 199 this._.output.push( text );200 },173 if ( rules && rules.indent ) 174 this._.indentation = this._.indentation.substr( this.indentationChars.length ); 201 175 202 /** 203 * Writes a comment. 204 * @param {String} comment The comment text. 205 * @example 206 * // Writes "<!-- My comment -->". 207 * writer.comment( ' My comment ' ); 208 */ 209 comment : function( comment ) 210 { 211 if ( this._.indent ) 212 this.indentation(); 176 if ( this._.indent ) 177 this.indentation(); 178 // Do not break if indenting. 179 else if ( rules && rules.breakBeforeClose ) 180 { 181 this.lineBreak(); 182 this.indentation(); 183 } 213 184 214 this._.output.push( '<!--', comment, '-->' ); 215 }, 185 this._.output.push( '</', tagName, '>' ); 216 186 217 /** 218 * Writes a line break. It uses the {@link #lineBreakChars} property for it. 219 * @example 220 * // Writes "\n" (e.g.). 221 * writer.lineBreak(); 222 */ 223 lineBreak : function() 224 { 225 if ( this._.output.length > 0 ) 226 this._.output.push( this.lineBreakChars ); 227 this._.indent = true; 228 }, 187 if ( rules && rules.breakAfterClose ) 188 this.lineBreak(); 189 }, 229 190 230 /** 231 * Writes the current indentation chars. It uses the 232 * {@link #indentationChars} property, repeating it for the current 233 * indentation steps. 234 * @example 235 * // Writes "\t" (e.g.). 236 * writer.indentation(); 237 */ 238 indentation : function() 239 { 240 this._.output.push( this._.indentation ); 241 this._.indent = false; 242 }, 191 /** 192 * Writes text. 193 * @param {String} text The text value 194 * @example 195 * // Writes "Hello Word". 196 * writer.text( 'Hello Word' ); 197 */ 198 text : function( text ) 199 { 200 if ( this._.indent ) 201 { 202 this.indentation(); 203 text = CKEDITOR.tools.ltrim( text ); 204 } 243 205 244 /** 245 * Writes any kind of data to the ouput. 246 * @example 247 * writer.write( 'This is an <b>example</b>.' ); 248 */ 249 write : function( data ) 250 { 251 this._.output.push( data ); 252 }, 206 this._.output.push( text ); 207 }, 253 208 254 /** 255 * Empties the current output buffer. 256 * @example 257 * writer.reset(); 258 */ 259 reset : function() 260 { 261 this._.output = []; 262 }, 209 /** 210 * Writes a comment. 211 * @param {String} comment The comment text. 212 * @example 213 * // Writes "<!-- My comment -->". 214 * writer.comment( ' My comment ' ); 215 */ 216 comment : function( comment ) 217 { 218 if ( this._.indent ) 219 this.indentation(); 263 220 264 /** 265 * Empties the current output buffer. 266 * @param {Boolean} reset Indicates that the {@link reset} function is to 267 * be automatically called after retrieving the HTML. 268 * @returns {String} The HTML written to the writer so far. 269 * @example 270 * var html = writer.getHtml(); 271 */ 272 getHtml : function( reset ) 273 { 274 var html = this._.output.join( '' ); 221 this._.output.push( '<!--', comment, '-->' ); 222 }, 275 223 276 if ( reset ) 277 this.reset(); 224 /** 225 * Writes a line break. It uses the {@link #lineBreakChars} property for it. 226 * @example 227 * // Writes "\n" (e.g.). 228 * writer.lineBreak(); 229 */ 230 lineBreak : function() 231 { 232 if ( this._.output.length > 0 ) 233 this._.output.push( this.lineBreakChars ); 234 this._.indent = true; 235 }, 278 236 279 return html; 280 }, 237 /** 238 * Writes the current indentation chars. It uses the 239 * {@link #indentationChars} property, repeating it for the current 240 * indentation steps. 241 * @example 242 * // Writes "\t" (e.g.). 243 * writer.indentation(); 244 */ 245 indentation : function() 246 { 247 this._.output.push( this._.indentation ); 248 this._.indent = false; 249 }, 281 250 282 /** 283 * Sets formatting rules for a give element. The possible rules are: 284 * <ul> 285 * <li><b>indent</b>: indent the element contents.</li> 286 * <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li> 287 * <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li> 288 * <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li> 289 * <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li> 290 * </ul> 291 * 292 * All rules default to "false". 293 * 294 * By default, all elements available in the {@link CKEDITOR.dtd.$block), 295 * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent} 296 * lists have all the above rules set to "true". Additionaly, the "br" 297 * element has the "breakAfterOpen" set to "true". 298 * @param {String} tagName The element name to which set the rules. 299 * @param {Object} rules An object containing the element rules. 300 * @example 301 * // Break line before and after "img" tags. 302 * writer.setRules( 'img', 303 * { 304 * breakBeforeOpen : true 305 * breakAfterOpen : true 306 * }); 307 * @example 308 * // Reset the rules for the "h1" tag. 309 * writer.setRules( 'h1', {} ); 310 */ 311 setRules : function( tagName, rules ) 312 { 313 this._.rules[ tagName ] = rules; 251 /** 252 * Sets formatting rules for a give element. The possible rules are: 253 * <ul> 254 * <li><b>indent</b>: indent the element contents.</li> 255 * <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li> 256 * <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li> 257 * <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li> 258 * <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li> 259 * </ul> 260 * 261 * All rules default to "false". 262 * 263 * By default, all elements available in the {@link CKEDITOR.dtd.$block), 264 * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent} 265 * lists have all the above rules set to "true". Additionaly, the "br" 266 * element has the "breakAfterOpen" set to "true". 267 * @param {String} tagName The element name to which set the rules. 268 * @param {Object} rules An object containing the element rules. 269 * @example 270 * // Break line before and after "img" tags. 271 * writer.setRules( 'img', 272 * { 273 * breakBeforeOpen : true 274 * breakAfterOpen : true 275 * }); 276 * @example 277 * // Reset the rules for the "h1" tag. 278 * writer.setRules( 'h1', {} ); 279 */ 280 setRules : function( tagName, rules ) 281 { 282 this._.rules[ tagName ] = rules; 283 } 314 284 } 315 }; 316 317 CKEDITOR.plugins.add( 'htmlwriter' ); 285 }); -
_source/plugins/link/plugin.js
1 /*1 /* 2 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 4 */ … … 65 65 command.setState( CKEDITOR.TRISTATE_DISABLED ); 66 66 } ); 67 67 68 // Register a contentDom handler for displaying placeholders after mode change.69 editor.on( 'contentDom', function()70 {71 var rawAnchors = editor.document.$.anchors;72 for ( var i = rawAnchors.length - 1, anchor ; i >= 0 ; i-- )73 {74 anchor = new CKEDITOR.dom.element( rawAnchors[ i ] );75 76 // IE BUG: When an <a> tag doesn't have href, IE would return empty string77 // instead of null on getAttribute.78 if ( !anchor.getAttribute( 'href' ) )79 editor.createFakeElement( anchor, 'cke_anchor', 'anchor' ).replace( anchor );80 else81 anchor.addClass( 'cke_anchor' );82 }83 });84 85 68 // If the "menu" plugin is loaded, register the menu items. 86 69 if ( editor.addMenuItems ) 87 70 { … … 137 120 } 138 121 }, 139 122 123 afterInit : function( editor ) 124 { 125 // Register a filter to displaying placeholders after mode change. 126 127 var dataProcessor = editor.dataProcessor, 128 dataFilter = dataProcessor && dataProcessor.dataFilter; 129 130 if ( dataFilter ) 131 { 132 dataFilter.addRules( 133 { 134 elements : 135 { 136 a : function( element ) 137 { 138 var attributes = element.attributes; 139 if ( attributes.name && !attributes.href ) 140 return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' ); 141 } 142 } 143 }); 144 } 145 }, 146 140 147 requires : [ 'fakeobjects' ] 141 148 } ); 142 149 -
_source/plugins/pagebreak/plugin.js
38 38 'height: 5px;' + 39 39 40 40 '}' ); 41 42 // Listen for the "contentDom" event, so the document can be fixed to 43 // display the placeholders. 44 editor.on( 'contentDom', function() 45 { 46 var divs = editor.document.getBody().getElementsByTag( 'div' ); 47 for ( var div, i = 0, length = divs.count() ; i < length ; i++ ) 41 }, 42 43 afterInit : function( editor ) 44 { 45 // Register a filter to displaying placeholders after mode change. 46 47 var dataProcessor = editor.dataProcessor, 48 dataFilter = dataProcessor && dataProcessor.dataFilter; 49 50 if ( dataFilter ) 51 { 52 dataFilter.addRules( 48 53 { 49 div = divs.getItem( i ); 50 if ( div.getStyle( 'page-break-after' ) == 'always' && !/[^\s\u00A0]/.test( div.getText() ) ) 54 elements : 51 55 { 52 editor.createFakeElement( div, 'cke_pagebreak', 'div' ).replace( div ); 56 div : function( element ) 57 { 58 var style = element.attributes.style, 59 child = style && element.children.length == 1 && element.children[ 0 ], 60 childStyle = child && ( child.name == 'span' ) && child.attributes.style; 61 62 if ( childStyle && /page-break-after\s*:\s*always/i.test( style ) && /display\s*:\s*none/i.test( childStyle ) ) 63 return editor.createFakeParserElement( element, 'cke_pagebreak', 'div' ); 64 } 53 65 } 54 } 55 });66 }); 67 } 56 68 }, 69 57 70 requires : [ 'fakeobjects' ] 58 71 }); 59 72 -
_source/plugins/wysiwygarea/plugin.js
10 10 11 11 (function() 12 12 { 13 // Matches all self-closing tags that are not defined as empty elements in 14 // the DTD (like <span/>). 15 var invalidSelfCloseTagsRegex = /(<(?!br|hr|base|meta|link|param|img|area|input|col)([a-zA-Z0-9:]+)[^>]*)\/>/gi; 16 17 // #### protectEvents - START 18 19 // Matches all tags that have event attributes (onXYZ). 20 var tagsWithEventRegex = /<[^\>]+ on\w+\s*=[\s\S]+?\>/g; 21 22 // Matches all event attributes. 23 var eventAttributesRegex = /\s(on\w+)(?=\s*=\s*?('|")[\s\S]*?\2)/g; 24 25 // Matches the protected attribute prefix. 26 var protectedEventsRegex = /_cke_pa_/g; 27 28 var protectEvents = function( html ) 13 function onInsertHtml( evt ) 29 14 { 30 return html.replace( tagsWithEventRegex, protectEvents_ReplaceTags );31 };32 33 var protectEvents_ReplaceTags = function( tagMatch )34 {35 // Appends the "_cke_pa_" prefix to the event name.36 return tagMatch.replace( eventAttributesRegex, ' _cke_pa_$1' );37 };38 39 var protectEventsRestore = function( html )40 {41 return html.replace( protectedEventsRegex, '' ) ;42 };43 44 // #### protectEvents - END45 46 // #### protectAttributes - START47 48 // TODO: Clean and simplify these regexes.49 var protectUrlTagRegex = /<(?:a|area|img)(?=\s).*?\s(?:href|src)=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi,50 protectUrlAttributeRegex = /\s(href|src)(\s*=\s*?('|")[\s\S]*?\3)/gi;51 52 var protectUrls = function( html )53 {54 return html.replace( protectUrlTagRegex, protectUrls_ReplaceTags );55 };56 57 var protectUrls_ReplaceTags = function( tagMatch )58 {59 return tagMatch.replace( protectUrlAttributeRegex, '$& _cke_saved_$1$2');60 };61 62 // #### protectAttributes - END63 64 var onInsertHtml = function( evt )65 {66 15 if ( this.mode == 'wysiwyg' ) 67 16 { 68 var $doc = this.document.$; 17 var $doc = this.document.$, 18 data = evt.data; 69 19 var data = protectHtml( evt.data ); 70 20 21 if ( editor.dataProcessor ) 22 data = editor.dataProcessor.toHtml( data ); 23 71 24 if ( CKEDITOR.env.ie ) 72 25 $doc.selection.createRange().pasteHTML( data ); 73 26 else 74 27 $doc.execCommand( 'inserthtml', false, data ); 75 28 } 76 };77 78 // ### protectCkeTags - START79 var protectCkeTagRegex = /(<\/?)(object|embed|param)/gi80 var protectCkeTags = function( html )81 {82 return html.replace( protectCkeTagRegex, '$1cke:$2' );83 };84 // ### protectCkeTags - END85 86 function protectHtml( html )87 {88 // Prevent event attributes (like "onclick") to89 // execute while editing.90 if ( CKEDITOR.env.ie || CKEDITOR.env.webkit )91 html = protectEvents( html );92 93 // Protect src or href attributes.94 html = protectUrls( html );95 96 // Protect cke prefixed tags.97 html = protectCkeTags( html );98 99 return html;100 29 } 101 30 102 var onInsertElement = function( evt )31 function onInsertElement( evt ) 103 32 { 104 33 if ( this.mode == 'wysiwyg' ) 105 34 { … … 140 69 range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END ); 141 70 selection.selectRanges( [ range ] ); 142 71 } 143 } ;72 } 144 73 145 74 CKEDITOR.plugins.add( 'wysiwygarea', 146 75 { … … 342 271 if ( editor.dataProcessor ) 343 272 data = editor.dataProcessor.toHtml( data ); 344 273 345 // Fix for invalid self-closing tags (see #152).346 // TODO: Check if this fix is really needed as347 // soon as we have the XHTML generator.348 if ( CKEDITOR.env.ie )349 data = data.replace( invalidSelfCloseTagsRegex, '$1></$2>' );350 351 data = protectHtml( data );352 274 data = 353 275 editor.config.docType + 354 276 '<html dir="' + editor.config.contentsLangDirection + '">' + … … 394 316 395 317 getData : function() 396 318 { 397 var data = iframe.$.contentWindow.document.body ;319 var data = iframe.$.contentWindow.document.body.innerHTML; 398 320 399 321 if ( editor.dataProcessor ) 400 data = editor.dataProcessor.toDataFormat( new CKEDITOR.dom.element( data ) ); 401 else 402 data = data.innerHTML; 322 data = editor.dataProcessor.toDataFormat( data ); 403 323 404 // Restore protected attributes.405 data = protectEventsRestore( data );406 407 324 return data; 408 325 }, 409 326 -
_source/tests/plugins/htmldataprocessor/htmldataprocessor.html
40 40 { 41 41 var element = new CKEDITOR.dom.element.createFromHtml( '<div><p>Test</p></div>' ); 42 42 43 assert.areSame( '<p>Test</p>', getDataProcessor().toDataFormat( element ) );43 assert.areSame( '<p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) ); 44 44 }, 45 45 46 46 test_toDataFormat_1b : function() … … 49 49 50 50 // IE adds the XML namespace tag. 51 51 if ( CKEDITOR.env.ie ) 52 assert.areSame( '<?xml:namespace prefix="x" /><x:x>Test</x:x>', getDataProcessor().toDataFormat( element ) );52 assert.areSame( '<?xml:namespace prefix="x" /><x:x>Test</x:x>', getDataProcessor().toDataFormat( element.getHtml() ) ); 53 53 else 54 assert.areSame( '<x:x>Test</x:x>', getDataProcessor().toDataFormat( element ) );54 assert.areSame( '<x:x>Test</x:x>', getDataProcessor().toDataFormat( element.getHtml() ) ); 55 55 }, 56 56 57 57 test_toDataFormat_2a : function() 58 58 { 59 59 var element = new CKEDITOR.dom.element.createFromHtml( '<div><br /><p>Test</p></div>' ); 60 60 61 assert.areSame( '<br /><p>Test</p>', getDataProcessor().toDataFormat( element ) );61 assert.areSame( '<br /><p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) ); 62 62 }, 63 63 64 64 test_toDataFormat_2b : function() … … 67 67 68 68 // IE adds the XML namespace tag. 69 69 if ( CKEDITOR.env.ie ) 70 assert.areSame( '<?xml:namespace prefix="x" /><x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element ) );70 assert.areSame( '<?xml:namespace prefix="x" /><x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) ); 71 71 else 72 assert.areSame( '<x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element ) );72 assert.areSame( '<x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) ); 73 73 }, 74 74 75 75 test_toDataFormat_3 : function() 76 76 { 77 77 var element = new CKEDITOR.dom.element.createFromHtml( '<div><x:x><p>Test</p></div>' ); 78 78 79 assert.areSame( '<x:x><p>Test</p></x:x>', getDataProcessor().toDataFormat( element ) );79 assert.areSame( '<x:x><p>Test</p></x:x>', getDataProcessor().toDataFormat( element.getHtml() ) ); 80 80 }, 81 81 82 82 test_toDataFormat_ticket_2774 : function() … … 85 85 86 86 // IE adds the XML namespace tag. 87 87 if ( CKEDITOR.env.ie ) 88 assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><?xml:namespace prefix="o" /><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element ) );88 assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><?xml:namespace prefix="o" /><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element.getHtml() ) ); 89 89 else 90 assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element ) );90 assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element.getHtml() ) ); 91 91 }, 92 92 93 93 name : document.title -
ckeditor.pack
109 109 '_source/core/htmlparser/text.js', 110 110 '_source/core/htmlparser/fragment.js', 111 111 '_source/core/htmlparser/element.js', 112 '_source/core/htmlparser/filter.js', 113 '_source/core/htmlparser/basicwriter.js', 112 114 '_source/core/ckeditor.js', 113 115 '_source/core/dom/elementpath.js', 114 116 '_source/core/dom/text.js',