2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
8 CKEDITOR
.on( 'dialogDefinition', function( ev
)
10 var tab
, name
= ev
.data
.name
,
11 definition
= ev
.data
.definition
;
15 definition
.removeContents( 'target' );
16 definition
.removeContents( 'upload' );
17 definition
.removeContents( 'advanced' );
18 tab
= definition
.getContents( 'info' );
19 tab
.remove( 'emailSubject' );
20 tab
.remove( 'emailBody' );
22 else if ( name
== 'image' )
24 definition
.removeContents( 'advanced' );
25 tab
= definition
.getContents( 'Link' );
26 tab
.remove( 'cmbTarget' );
27 tab
= definition
.getContents( 'info' );
28 tab
.remove( 'txtAlt' );
29 tab
.remove( 'basic' );
33 var bbcodeMap
= { 'b' : 'strong', 'u': 'u', 'i' : 'em', 'color' : 'span', 'size' : 'span', 'quote' : 'blockquote', 'code' : 'code', 'url' : 'a', 'email' : 'span', 'img' : 'span', '*' : 'li', 'list' : 'ol' },
34 convertMap
= { 'strong' : 'b' , 'b' : 'b', 'u': 'u', 'em' : 'i', 'i': 'i', 'code' : 'code', 'li' : '*' },
35 tagnameMap
= { 'strong' : 'b', 'em' : 'i', 'u' : 'u', 'li' : '*', 'ul' : 'list', 'ol' : 'list', 'code' : 'code', 'a' : 'link', 'img' : 'img', 'blockquote' : 'quote' },
36 stylesMap
= { 'color' : 'color', 'size' : 'font-size' },
37 attributesMap
= { 'url' : 'href', 'email' : 'mailhref', 'quote': 'cite', 'list' : 'listType' };
39 // List of block-like tags.
40 var dtd
= CKEDITOR
.dtd
,
41 blockLikeTags
= CKEDITOR
.tools
.extend( { table
:1 }, dtd
.$block
, dtd
.$listItem
, dtd
.$tableContent
, dtd
.$list
);
43 var semicolonFixRegex
= /\s*(?:;\s*|$)/;
44 function serializeStyleText( stylesObject
)
47 for ( var style
in stylesObject
)
49 var styleVal
= stylesObject
[ style
],
50 text
= ( style
+ ':' + styleVal
).replace( semicolonFixRegex
, ';' );
57 function parseStyleText( styleText
)
61 .replace( /"/g, '"' )
62 .replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match
, name
, value
)
64 retval
[ name
.toLowerCase() ] = value
;
69 function RGBToHex( cssStyle
)
71 return cssStyle
.replace( /(?:rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\))/gi, function( match
, red
, green
, blue
)
73 red
= parseInt( red
, 10 ).toString( 16 );
74 green
= parseInt( green
, 10 ).toString( 16 );
75 blue
= parseInt( blue
, 10 ).toString( 16 );
76 var color
= [red
, green
, blue
] ;
78 // Add padding zeros if the hex value is less than 0x10.
79 for ( var i
= 0 ; i
< color
.length
; i
++ )
80 color
[i
] = String( '0' + color
[i
] ).slice( -2 ) ;
82 return '#' + color
.join( '' ) ;
86 // Maintain the map of smiley-to-description.
87 var smileyMap
= {"smiley":":)","sad":":(","wink":";)","laugh":":D","cheeky":":P","blush":":*)","surprise":":-o","indecision":":|","angry":">:(","angel":"o:)","cool":"8-)","devil":">:-)","crying":";(","kiss":":-*" },
88 smileyReverseMap
= {},
91 // Build regexp for the list of smiley text.
92 for ( var i
in smileyMap
)
94 smileyReverseMap
[ smileyMap
[ i
] ] = i
;
95 smileyRegExp
.push( smileyMap
[ i
].replace( /\(|\)|\:|\/|\*|\-|\|/g, function( match
) { return '\\' + match
; } ) );
98 smileyRegExp
= new RegExp( smileyRegExp
.join( '|' ), 'g' );
100 var decodeHtml
= ( function ()
105 nbsp
: '\u00A0', // IE | FF
106 shy
: '\u00AD', // IE
107 gt
: '\u003E', // IE | FF | -- | Opera
108 lt
: '\u003C' // IE | FF | Safari | Opera
111 for ( var entity
in entities
)
112 regex
.push( entity
);
114 regex
= new RegExp( '&(' + regex
.join( '|' ) + ');', 'g' );
116 return function( html
)
118 return html
.replace( regex
, function( match
, entity
)
120 return entities
[ entity
];
125 CKEDITOR
.BBCodeParser = function()
129 bbcPartsRegex
: /(?:\[([^\/\]=]*?)(?:=([^\]]*?))?\])|(?:\[\/([a-z]{1,16})\])/ig
133 CKEDITOR
.BBCodeParser
.prototype =
135 parse : function( bbcode
)
141 while ( ( parts
= this._
.bbcPartsRegex
.exec( bbcode
) ) )
143 var tagIndex
= parts
.index
;
144 if ( tagIndex
> lastIndex
)
146 var text
= bbcode
.substring( lastIndex
, tagIndex
);
147 this.onText( text
, 1 );
150 lastIndex
= this._
.bbcPartsRegex
.lastIndex
;
153 "parts" is an array with the following items:
154 0 : The entire match for opening/closing tags and line-break;
156 2 : open of tag excludes option;
161 part
= ( parts
[ 1 ] || parts
[ 3 ] || '' ).toLowerCase();
162 // Unrecognized tags should be delivered as a simple text (#7860).
163 if ( part
&& !bbcodeMap
[ part
] )
165 this.onText( parts
[ 0 ] );
172 var tagName
= bbcodeMap
[ part
],
175 optionPart
= parts
[ 2 ];
179 if ( part
== 'list' )
181 if ( !isNaN( optionPart
) )
182 optionPart
= 'decimal';
183 else if ( /^[a-z]+$/.test( optionPart
) )
184 optionPart
= 'lower-alpha';
185 else if ( /^[A-Z]+$/.test( optionPart
) )
186 optionPart
= 'upper-alpha';
189 if ( stylesMap
[ part
] )
191 // Font size represents percentage.
192 if ( part
== 'size' )
195 styles
[ stylesMap
[ part
] ] = optionPart
;
196 attribs
.style
= serializeStyleText( styles
);
198 else if ( attributesMap
[ part
] )
199 attribs
[ attributesMap
[ part
] ] = optionPart
;
202 // Two special handling - image and email, protect them
203 // as "span" with an attribute marker.
204 if ( part
== 'email' || part
== 'img' )
205 attribs
[ 'bbcode' ] = part
;
207 this.onTagOpen( tagName
, attribs
, CKEDITOR
.dtd
.$empty
[ tagName
] );
210 else if ( parts
[ 3 ] )
211 this.onTagClose( bbcodeMap
[ part
] );
214 if ( bbcode
.length
> lastIndex
)
215 this.onText( bbcode
.substring( lastIndex
, bbcode
.length
), 1 );
220 * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.
221 * @param {String} source The HTML to be parsed, filling the fragment.
222 * @param {Number} [fixForBody=false] Wrap body with specified element if needed.
223 * @returns CKEDITOR.htmlParser.fragment The fragment created.
225 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
226 * alert( fragment.children[0].name ); "b"
227 * alert( fragment.children[1].value ); " Text"
229 CKEDITOR
.htmlParser
.fragment
.fromBBCode = function( source
)
231 var parser
= new CKEDITOR
.BBCodeParser(),
232 fragment
= new CKEDITOR
.htmlParser
.fragment(),
235 currentNode
= fragment
,
238 function checkPending( newTagName
)
240 if ( pendingInline
.length
> 0 )
242 for ( var i
= 0 ; i
< pendingInline
.length
; i
++ )
244 var pendingElement
= pendingInline
[ i
],
245 pendingName
= pendingElement
.name
,
246 pendingDtd
= CKEDITOR
.dtd
[ pendingName
],
247 currentDtd
= currentNode
.name
&& CKEDITOR
.dtd
[ currentNode
.name
];
249 if ( ( !currentDtd
|| currentDtd
[ pendingName
] ) && ( !newTagName
|| !pendingDtd
|| pendingDtd
[ newTagName
] || !CKEDITOR
.dtd
[ newTagName
] ) )
251 // Get a clone for the pending element.
252 pendingElement
= pendingElement
.clone();
254 // Add it to the current node and make it the current,
255 // so the new element will be added inside of it.
256 pendingElement
.parent
= currentNode
;
257 currentNode
= pendingElement
;
259 // Remove the pending element (back the index by one
260 // to properly process the next entry).
261 pendingInline
.splice( i
, 1 );
268 function checkPendingBrs( tagName
, closing
)
270 var len
= currentNode
.children
.length
,
271 previous
= len
> 0 && currentNode
.children
[ len
- 1 ],
272 lineBreakParent
= !previous
&& BBCodeWriter
.getRule( tagnameMap
[ currentNode
.name
], 'breakAfterOpen' ),
273 lineBreakPrevious
= previous
&& previous
.type
== CKEDITOR
.NODE_ELEMENT
&& BBCodeWriter
.getRule( tagnameMap
[ previous
.name
], 'breakAfterClose' ),
274 lineBreakCurrent
= tagName
&& BBCodeWriter
.getRule( tagnameMap
[ tagName
], closing
? 'breakBeforeClose' : 'breakBeforeOpen' );
276 if ( pendingBrs
&& ( lineBreakParent
|| lineBreakPrevious
|| lineBreakCurrent
) )
279 // 1. Either we're at the end of block, where it requires us to compensate the br filler
280 // removing logic (from htmldataprocessor).
281 // 2. Or we're at the end of pseudo block, where it requires us to compensate
282 // the bogus br effect.
283 if ( pendingBrs
&& tagName
in blockLikeTags
)
286 while ( pendingBrs
&& pendingBrs
-- )
287 currentNode
.children
.push( previous
= new CKEDITOR
.htmlParser
.element( 'br' ) );
290 function addElement( node
, target
)
292 checkPendingBrs( node
.name
, 1 );
294 target
= target
|| currentNode
|| fragment
;
296 var len
= target
.children
.length
,
297 previous
= len
> 0 && target
.children
[ len
- 1 ] || null;
299 node
.previous
= previous
;
300 node
.parent
= target
;
302 target
.children
.push( node
);
304 if ( node
.returnPoint
)
306 currentNode
= node
.returnPoint
;
307 delete node
.returnPoint
;
311 parser
.onTagOpen = function( tagName
, attributes
, selfClosing
)
313 var element
= new CKEDITOR
.htmlParser
.element( tagName
, attributes
);
315 // This is a tag to be removed if empty, so do not add it immediately.
316 if ( CKEDITOR
.dtd
.$removeEmpty
[ tagName
] )
318 pendingInline
.push( element
);
322 var currentName
= currentNode
.name
;
324 var currentDtd
= currentName
325 && ( CKEDITOR
.dtd
[ currentName
]
326 || ( currentNode
._
.isBlockLike
? CKEDITOR
.dtd
.div
: CKEDITOR
.dtd
.span
) );
328 // If the element cannot be child of the current element.
329 if ( currentDtd
&& !currentDtd
[ tagName
] )
332 addPoint
; // New position to start adding nodes.
334 // If the element name is the same as the current element name,
335 // then just close the current one and append the new one to the
336 // parent. This situation usually happens with <p>, <li>, <dt> and
337 // <dd>, specially in IE. Do not enter in this if block in this case.
338 if ( tagName
== currentName
)
339 addElement( currentNode
, currentNode
.parent
);
340 else if ( tagName
in CKEDITOR
.dtd
.$listItem
)
342 parser
.onTagOpen( 'ul', {} );
343 addPoint
= currentNode
;
348 addElement( currentNode
, currentNode
.parent
);
350 // The current element is an inline element, which
351 // cannot hold the new one. Put it in the pending list,
352 // and try adding the new one after it.
353 pendingInline
.unshift( currentNode
);
358 currentNode
= addPoint
;
359 // Try adding it to the return point, or the parent element.
361 currentNode
= currentNode
.returnPoint
|| currentNode
.parent
;
365 parser
.onTagOpen
.apply( this, arguments
);
370 checkPending( tagName
);
371 checkPendingBrs( tagName
);
373 element
.parent
= currentNode
;
374 element
.returnPoint
= returnPoint
;
377 if ( element
.isEmpty
)
378 addElement( element
);
380 currentNode
= element
;
383 parser
.onTagClose = function( tagName
)
385 // Check if there is any pending tag to be closed.
386 for ( var i
= pendingInline
.length
- 1 ; i
>= 0 ; i
-- )
388 // If found, just remove it from the list.
389 if ( tagName
== pendingInline
[ i
].name
)
391 pendingInline
.splice( i
, 1 );
397 newPendingInline
= [],
398 candidate
= currentNode
;
400 while ( candidate
.type
&& candidate
.name
!= tagName
)
402 // If this is an inline element, add it to the pending list, if we're
403 // really closing one of the parents element later, they will continue
405 if ( !candidate
._
.isBlockLike
)
406 newPendingInline
.unshift( candidate
);
408 // This node should be added to it's parent at this point. But,
409 // it should happen only if the closing tag is really closing
410 // one of the nodes. So, for now, we just cache it.
411 pendingAdd
.push( candidate
);
413 candidate
= candidate
.parent
;
416 if ( candidate
.type
)
418 // Add all elements that have been found in the above loop.
419 for ( i
= 0 ; i
< pendingAdd
.length
; i
++ )
421 var node
= pendingAdd
[ i
];
422 addElement( node
, node
.parent
);
425 currentNode
= candidate
;
428 addElement( candidate
, candidate
.parent
);
430 // The parent should start receiving new nodes now, except if
431 // addElement changed the currentNode.
432 if ( candidate
== currentNode
)
433 currentNode
= currentNode
.parent
;
435 pendingInline
= pendingInline
.concat( newPendingInline
);
439 parser
.onText = function( text
)
441 var currentDtd
= CKEDITOR
.dtd
[ currentNode
.name
];
442 if ( !currentDtd
|| currentDtd
[ '#' ] )
447 text
.replace(/([\r\n])|[^\r\n]*/g, function( piece
, lineBreak
)
449 if ( lineBreak
!== undefined && lineBreak
.length
)
451 else if ( piece
.length
)
455 // Create smiley from text emotion.
456 piece
.replace( smileyRegExp
, function( match
, index
)
458 addElement( new CKEDITOR
.htmlParser
.text( piece
.substring( lastIndex
, index
) ), currentNode
);
459 addElement( new CKEDITOR
.htmlParser
.element( 'smiley', { 'desc': smileyReverseMap
[ match
] } ), currentNode
);
460 lastIndex
= index
+ match
.length
;
463 if ( lastIndex
!= piece
.length
)
464 addElement( new CKEDITOR
.htmlParser
.text( piece
.substring( lastIndex
, piece
.length
) ), currentNode
);
471 parser
.parse( CKEDITOR
.tools
.htmlEncode( source
) );
473 // Close all hanging nodes.
474 while ( currentNode
.type
)
476 var parent
= currentNode
.parent
,
479 addElement( node
, parent
);
480 currentNode
= parent
;
486 CKEDITOR
.htmlParser
.BBCodeWriter
= CKEDITOR
.tools
.createClass(
496 // List and list item.
497 this.setRules( 'list',
501 breakBeforeClose
: 1,
509 breakBeforeClose
: 1,
513 this.setRules( 'quote',
517 breakBeforeClose
: 0,
525 * Sets formatting rules for a given tag. The possible rules are:
527 * <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>
528 * <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>
529 * <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>
530 * <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>
533 * All rules default to "false". Each call to the function overrides
534 * already present rules, leaving the undefined untouched.
536 * @param {String} tagName The tag name to which set the rules.
537 * @param {Object} rules An object containing the element rules.
539 * // Break line before and after "img" tags.
540 * writer.setRules( 'list',
542 * breakBeforeOpen : true
543 * breakAfterOpen : true
546 setRules : function( tagName
, rules
)
548 var currentRules
= this._
.rules
[ tagName
];
551 CKEDITOR
.tools
.extend( currentRules
, rules
, true );
553 this._
.rules
[ tagName
] = rules
;
556 getRule : function( tagName
, ruleName
)
558 return this._
.rules
[ tagName
] && this._
.rules
[ tagName
][ ruleName
];
561 openTag : function( tag
, attributes
)
563 if ( tag
in bbcodeMap
)
565 if ( this.getRule( tag
, 'breakBeforeOpen' ) )
568 this.write( '[', tag
);
569 var option
= attributes
.option
;
570 option
&& this.write( '=', option
);
573 if ( this.getRule( tag
, 'breakAfterOpen' ) )
576 else if ( tag
== 'br' )
577 this._
.output
.push( '\n' );
580 openTagClose : function() { },
581 attribute : function() { },
583 closeTag : function( tag
)
585 if ( tag
in bbcodeMap
)
587 if ( this.getRule( tag
, 'breakBeforeClose' ) )
590 tag
!= '*' && this.write( '[/', tag
, ']' );
592 if ( this.getRule( tag
, 'breakAfterClose' ) )
597 text : function( text
)
604 * @param {String} comment The comment text.
606 * // Writes "<!-- My comment -->".
607 * writer.comment( ' My comment ' );
609 comment : function() {},
612 * Output line-break for formatting.
614 lineBreak : function()
616 // Avoid line break when:
617 // 1) Previous tag already put one.
618 // 2) We're at output start.
619 if ( !this._
.hasLineBreak
&& this._
.output
.length
)
622 this._
.hasLineBreak
= 1;
628 this._
.hasLineBreak
= 0;
629 var data
= Array
.prototype.join
.call( arguments
, '' );
630 this._
.output
.push( data
);
636 this._
.hasLineBreak
= 0;
639 getHtml : function( reset
)
641 var bbcode
= this._
.output
.join( '' );
646 return decodeHtml ( bbcode
);
651 var BBCodeWriter
= new CKEDITOR
.htmlParser
.BBCodeWriter();
653 CKEDITOR
.plugins
.add( 'bbcode',
655 requires
: [ 'htmldataprocessor', 'entities' ],
656 beforeInit : function( editor
)
658 // Adapt some critical editor configuration for better support
659 // of BBCode environment.
660 var config
= editor
.config
;
661 CKEDITOR
.tools
.extend( config
,
663 enterMode
: CKEDITOR
.ENTER_BR
,
664 basicEntities
: false,
666 fillEmptyBlocks
: false
669 init : function( editor
)
671 var config
= editor
.config
;
673 function BBCodeToHtml( code
)
675 var fragment
= CKEDITOR
.htmlParser
.fragment
.fromBBCode( code
),
676 writer
= new CKEDITOR
.htmlParser
.basicWriter();
678 fragment
.writeHtml( writer
, dataFilter
);
679 return writer
.getHtml( true );
682 var dataFilter
= new CKEDITOR
.htmlParser
.filter();
687 'blockquote' : function( element
)
689 var quoted
= new CKEDITOR
.htmlParser
.element( 'div' );
690 quoted
.children
= element
.children
;
691 element
.children
= [ quoted
];
692 var citeText
= element
.attributes
.cite
;
695 var cite
= new CKEDITOR
.htmlParser
.element( 'cite' );
696 cite
.add( new CKEDITOR
.htmlParser
.text( citeText
.replace( /^"|"$/g, '' ) ) );
697 delete element
.attributes
.cite
;
698 element
.children
.unshift( cite
);
701 'span' : function( element
)
704 if ( ( bbcode
= element
.attributes
.bbcode
) )
706 if ( bbcode
== 'img' )
708 element
.name
= 'img';
709 element
.attributes
.src
= element
.children
[ 0 ].value
;
710 element
.children
= [];
712 else if ( bbcode
== 'email' )
715 element
.attributes
.href
= 'mailto:' + element
.children
[ 0 ].value
;
718 delete element
.attributes
.bbcode
;
721 'ol' : function ( element
)
723 if ( element
.attributes
.listType
)
725 if ( element
.attributes
.listType
!= 'decimal' )
726 element
.attributes
.style
= 'list-style-type:' + element
.attributes
.listType
;
731 delete element
.attributes
.listType
;
733 a : function( element
)
735 if ( !element
.attributes
.href
)
736 element
.attributes
.href
= element
.children
[ 0 ].value
;
738 'smiley' : function( element
)
740 element
.name
= 'img';
742 var description
= element
.attributes
.desc
,
743 image
= config
.smiley_images
[ CKEDITOR
.tools
.indexOf( config
.smiley_descriptions
, description
) ],
744 src
= CKEDITOR
.tools
.htmlEncode( config
.smiley_path
+ image
);
749 'data-cke-saved-src' : src
,
757 editor
.dataProcessor
.htmlFilter
.addRules(
761 $ : function( element
)
763 var attributes
= element
.attributes
,
764 style
= parseStyleText( attributes
.style
),
767 var tagName
= element
.name
;
768 if ( tagName
in convertMap
)
769 tagName
= convertMap
[ tagName
];
770 else if ( tagName
== 'span' )
772 if ( ( value
= style
.color
) )
775 value
= RGBToHex( value
);
777 else if ( ( value
= style
[ 'font-size' ] ) )
779 var percentValue
= value
.match( /(\d+)%$/ );
782 value
= percentValue
[ 1 ];
787 else if ( tagName
== 'ol' || tagName
== 'ul' )
789 if ( ( value
= style
[ 'list-style-type'] ) )
801 else if ( tagName
== 'ol' )
806 else if ( tagName
== 'blockquote' )
810 var cite
= element
.children
[ 0 ],
811 quoted
= element
.children
[ 1 ],
812 citeText
= cite
.name
== 'cite' && cite
.children
[ 0 ].value
;
816 value
= '"' + citeText
+ '"';
817 element
.children
= quoted
.children
;
827 else if ( tagName
== 'a' )
829 if ( ( value
= attributes
.href
) )
831 if ( value
.indexOf( 'mailto:' ) !== -1 )
834 // [email] should have a single text child with email address.
835 element
.children
= [ new CKEDITOR
.htmlParser
.text( value
.replace( 'mailto:', '' ) ) ];
840 var singleton
= element
.children
.length
== 1 && element
.children
[ 0 ];
842 && singleton
.type
== CKEDITOR
.NODE_TEXT
843 && singleton
.value
== value
)
850 else if ( tagName
== 'img' )
854 // Translate smiley (image) to text emotion.
855 var src
= attributes
[ 'data-cke-saved-src' ];
856 if ( src
&& src
.indexOf( editor
.config
.smiley_path
) != -1 )
857 return new CKEDITOR
.htmlParser
.text( smileyMap
[ attributes
.alt
] );
859 element
.children
= [ new CKEDITOR
.htmlParser
.text( src
) ];
862 element
.name
= tagName
;
863 value
&& ( element
.attributes
.option
= value
);
868 // Remove any bogus br from the end of a pseudo block,
869 // e.g. <div>some text<br /><p>paragraph</p></div>
870 br : function( element
)
872 var next
= element
.next
;
873 if ( next
&& next
.name
in blockLikeTags
)
879 editor
.dataProcessor
.writer
= BBCodeWriter
;
881 editor
.on( 'beforeSetMode', function( evt
)
883 evt
.removeListener();
884 var wysiwyg
= editor
._
.modes
[ 'wysiwyg' ];
885 wysiwyg
.loadData
= CKEDITOR
.tools
.override( wysiwyg
.loadData
, function( org
)
887 return function( data
)
889 return ( org
.call( this, BBCodeToHtml( data
) ) );
895 afterInit : function( editor
)
898 if ( editor
._
.elementsPath
)
900 // Eliminate irrelevant elements from displaying, e.g body and p.
901 if ( ( filters
= editor
._
.elementsPath
.filters
) )
902 filters
.push( function( element
)
904 var htmlName
= element
.getName(),
905 name
= tagnameMap
[ htmlName
] || false;
907 // Specialized anchor presents as email.
908 if ( name
== 'link' && element
.getAttribute( 'href' ).indexOf( 'mailto:' ) === 0 )
910 // Styled span could be either size or color.
911 else if ( htmlName
== 'span' )
913 if ( element
.getStyle( 'font-size' ) )
915 else if ( element
.getStyle( 'color' ) )
918 else if ( name
== 'img' )
920 var src
= element
.data( 'cke-saved-src' );
921 if ( src
&& src
.indexOf( editor
.config
.smiley_path
) === 0 )