X-Git-Url: https://scm.cri.ensmp.fr/git/ckeditor.git/blobdiff_plain/256592bf803e851aa7fc953e08a6e9e58d970f8c..871bad8291b6dbc29d489d95d185458caab25158:/skins/ckeditor/_source/plugins/bbcode/plugin.js diff --git a/skins/ckeditor/_source/plugins/bbcode/plugin.js b/skins/ckeditor/_source/plugins/bbcode/plugin.js new file mode 100644 index 0000000..9ea7232 --- /dev/null +++ b/skins/ckeditor/_source/plugins/bbcode/plugin.js @@ -0,0 +1,931 @@ +/* +Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +(function() +{ + CKEDITOR.on( 'dialogDefinition', function( ev ) + { + var tab, name = ev.data.name, + definition = ev.data.definition; + + if ( name == 'link' ) + { + definition.removeContents( 'target' ); + definition.removeContents( 'upload' ); + definition.removeContents( 'advanced' ); + tab = definition.getContents( 'info' ); + tab.remove( 'emailSubject' ); + tab.remove( 'emailBody' ); + } + else if ( name == 'image' ) + { + definition.removeContents( 'advanced' ); + tab = definition.getContents( 'Link' ); + tab.remove( 'cmbTarget' ); + tab = definition.getContents( 'info' ); + tab.remove( 'txtAlt' ); + tab.remove( 'basic' ); + } + }); + + 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' }, + convertMap = { 'strong' : 'b' , 'b' : 'b', 'u': 'u', 'em' : 'i', 'i': 'i', 'code' : 'code', 'li' : '*' }, + tagnameMap = { 'strong' : 'b', 'em' : 'i', 'u' : 'u', 'li' : '*', 'ul' : 'list', 'ol' : 'list', 'code' : 'code', 'a' : 'link', 'img' : 'img', 'blockquote' : 'quote' }, + stylesMap = { 'color' : 'color', 'size' : 'font-size' }, + attributesMap = { 'url' : 'href', 'email' : 'mailhref', 'quote': 'cite', 'list' : 'listType' }; + + // List of block-like tags. + var dtd = CKEDITOR.dtd, + blockLikeTags = CKEDITOR.tools.extend( { table:1 }, dtd.$block, dtd.$listItem, dtd.$tableContent, dtd.$list ); + + var semicolonFixRegex = /\s*(?:;\s*|$)/; + function serializeStyleText( stylesObject ) + { + var styleText = ''; + for ( var style in stylesObject ) + { + var styleVal = stylesObject[ style ], + text = ( style + ':' + styleVal ).replace( semicolonFixRegex, ';' ); + + styleText += text; + } + return styleText; + } + + function parseStyleText( styleText ) + { + var retval = {}; + ( styleText || '' ) + .replace( /"/g, '"' ) + .replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) + { + retval[ name.toLowerCase() ] = value; + } ); + return retval; + } + + function RGBToHex( cssStyle ) + { + return cssStyle.replace( /(?:rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\))/gi, function( match, red, green, blue ) + { + red = parseInt( red, 10 ).toString( 16 ); + green = parseInt( green, 10 ).toString( 16 ); + blue = parseInt( blue, 10 ).toString( 16 ); + var color = [red, green, blue] ; + + // Add padding zeros if the hex value is less than 0x10. + for ( var i = 0 ; i < color.length ; i++ ) + color[i] = String( '0' + color[i] ).slice( -2 ) ; + + return '#' + color.join( '' ) ; + }); + } + + // Maintain the map of smiley-to-description. + var smileyMap = {"smiley":":)","sad":":(","wink":";)","laugh":":D","cheeky":":P","blush":":*)","surprise":":-o","indecision":":|","angry":">:(","angel":"o:)","cool":"8-)","devil":">:-)","crying":";(","kiss":":-*" }, + smileyReverseMap = {}, + smileyRegExp = []; + + // Build regexp for the list of smiley text. + for ( var i in smileyMap ) + { + smileyReverseMap[ smileyMap[ i ] ] = i; + smileyRegExp.push( smileyMap[ i ].replace( /\(|\)|\:|\/|\*|\-|\|/g, function( match ) { return '\\' + match; } ) ); + } + + smileyRegExp = new RegExp( smileyRegExp.join( '|' ), 'g' ); + + var decodeHtml = ( function () + { + var regex = [], + entities = + { + nbsp : '\u00A0', // IE | FF + shy : '\u00AD', // IE + gt : '\u003E', // IE | FF | -- | Opera + lt : '\u003C' // IE | FF | Safari | Opera + }; + + for ( var entity in entities ) + regex.push( entity ); + + regex = new RegExp( '&(' + regex.join( '|' ) + ');', 'g' ); + + return function( html ) + { + return html.replace( regex, function( match, entity ) + { + return entities[ entity ]; + }); + }; + })(); + + CKEDITOR.BBCodeParser = function() + { + this._ = + { + bbcPartsRegex : /(?:\[([^\/\]=]*?)(?:=([^\]]*?))?\])|(?:\[\/([a-z]{1,16})\])/ig + }; + }; + + CKEDITOR.BBCodeParser.prototype = + { + parse : function( bbcode ) + { + var parts, + part, + lastIndex = 0; + + while ( ( parts = this._.bbcPartsRegex.exec( bbcode ) ) ) + { + var tagIndex = parts.index; + if ( tagIndex > lastIndex ) + { + var text = bbcode.substring( lastIndex, tagIndex ); + this.onText( text, 1 ); + } + + lastIndex = this._.bbcPartsRegex.lastIndex; + + /* + "parts" is an array with the following items: + 0 : The entire match for opening/closing tags and line-break; + 1 : line-break; + 2 : open of tag excludes option; + 3 : tag option; + 4 : close of tag; + */ + + part = ( parts[ 1 ] || parts[ 3 ] || '' ).toLowerCase(); + // Unrecognized tags should be delivered as a simple text (#7860). + if ( part && !bbcodeMap[ part ] ) + { + this.onText( parts[ 0 ] ); + continue; + } + + // Opening tag + if ( parts[ 1 ] ) + { + var tagName = bbcodeMap[ part ], + attribs = {}, + styles = {}, + optionPart = parts[ 2 ]; + + if ( optionPart ) + { + if ( part == 'list' ) + { + if ( !isNaN( optionPart ) ) + optionPart = 'decimal'; + else if ( /^[a-z]+$/.test( optionPart ) ) + optionPart = 'lower-alpha'; + else if ( /^[A-Z]+$/.test( optionPart ) ) + optionPart = 'upper-alpha'; + } + + if ( stylesMap[ part ] ) + { + // Font size represents percentage. + if ( part == 'size' ) + optionPart += '%'; + + styles[ stylesMap[ part ] ] = optionPart; + attribs.style = serializeStyleText( styles ); + } + else if ( attributesMap[ part ] ) + attribs[ attributesMap[ part ] ] = optionPart; + } + + // Two special handling - image and email, protect them + // as "span" with an attribute marker. + if ( part == 'email' || part == 'img' ) + attribs[ 'bbcode' ] = part; + + this.onTagOpen( tagName, attribs, CKEDITOR.dtd.$empty[ tagName ] ); + } + // Closing tag + else if ( parts[ 3 ] ) + this.onTagClose( bbcodeMap[ part ] ); + } + + if ( bbcode.length > lastIndex ) + this.onText( bbcode.substring( lastIndex, bbcode.length ), 1 ); + } + }; + + /** + * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string. + * @param {String} source The HTML to be parsed, filling the fragment. + * @param {Number} [fixForBody=false] Wrap body with specified element if needed. + * @returns CKEDITOR.htmlParser.fragment The fragment created. + * @example + * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( 'Sample Text' ); + * alert( fragment.children[0].name ); "b" + * alert( fragment.children[1].value ); " Text" + */ + CKEDITOR.htmlParser.fragment.fromBBCode = function( source ) + { + var parser = new CKEDITOR.BBCodeParser(), + fragment = new CKEDITOR.htmlParser.fragment(), + pendingInline = [], + pendingBrs = 0, + currentNode = fragment, + returnPoint; + + function checkPending( newTagName ) + { + if ( pendingInline.length > 0 ) + { + for ( var i = 0 ; i < pendingInline.length ; i++ ) + { + var pendingElement = pendingInline[ i ], + pendingName = pendingElement.name, + pendingDtd = CKEDITOR.dtd[ pendingName ], + currentDtd = currentNode.name && CKEDITOR.dtd[ currentNode.name ]; + + if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) ) + { + // Get a clone for the pending element. + pendingElement = pendingElement.clone(); + + // Add it to the current node and make it the current, + // so the new element will be added inside of it. + pendingElement.parent = currentNode; + currentNode = pendingElement; + + // Remove the pending element (back the index by one + // to properly process the next entry). + pendingInline.splice( i, 1 ); + i--; + } + } + } + } + + function checkPendingBrs( tagName, closing ) + { + var len = currentNode.children.length, + previous = len > 0 && currentNode.children[ len - 1 ], + lineBreakParent = !previous && BBCodeWriter.getRule( tagnameMap[ currentNode.name ], 'breakAfterOpen' ), + lineBreakPrevious = previous && previous.type == CKEDITOR.NODE_ELEMENT && BBCodeWriter.getRule( tagnameMap[ previous.name ], 'breakAfterClose' ), + lineBreakCurrent = tagName && BBCodeWriter.getRule( tagnameMap[ tagName ], closing ? 'breakBeforeClose' : 'breakBeforeOpen' ); + + if ( pendingBrs && ( lineBreakParent || lineBreakPrevious || lineBreakCurrent ) ) + pendingBrs--; + + // 1. Either we're at the end of block, where it requires us to compensate the br filler + // removing logic (from htmldataprocessor). + // 2. Or we're at the end of pseudo block, where it requires us to compensate + // the bogus br effect. + if ( pendingBrs && tagName in blockLikeTags ) + pendingBrs++; + + while ( pendingBrs && pendingBrs-- ) + currentNode.children.push( previous = new CKEDITOR.htmlParser.element( 'br' ) ); + } + + function addElement( node, target ) + { + checkPendingBrs( node.name, 1 ); + + target = target || currentNode || fragment; + + var len = target.children.length, + previous = len > 0 && target.children[ len - 1 ] || null; + + node.previous = previous; + node.parent = target; + + target.children.push( node ); + + if ( node.returnPoint ) + { + currentNode = node.returnPoint; + delete node.returnPoint; + } + } + + parser.onTagOpen = function( tagName, attributes, selfClosing ) + { + var element = new CKEDITOR.htmlParser.element( tagName, attributes ); + + // This is a tag to be removed if empty, so do not add it immediately. + if ( CKEDITOR.dtd.$removeEmpty[ tagName ] ) + { + pendingInline.push( element ); + return; + } + + var currentName = currentNode.name; + + var currentDtd = currentName + && ( CKEDITOR.dtd[ currentName ] + || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ); + + // If the element cannot be child of the current element. + if ( currentDtd && !currentDtd[ tagName ] ) + { + var reApply = false, + addPoint; // New position to start adding nodes. + + // If the element name is the same as the current element name, + // then just close the current one and append the new one to the + // parent. This situation usually happens with

,

  • ,
    and + //
    , specially in IE. Do not enter in this if block in this case. + if ( tagName == currentName ) + addElement( currentNode, currentNode.parent ); + else if ( tagName in CKEDITOR.dtd.$listItem ) + { + parser.onTagOpen( 'ul', {} ); + addPoint = currentNode; + reApply = true; + } + else + { + addElement( currentNode, currentNode.parent ); + + // The current element is an inline element, which + // cannot hold the new one. Put it in the pending list, + // and try adding the new one after it. + pendingInline.unshift( currentNode ); + reApply = true; + } + + if ( addPoint ) + currentNode = addPoint; + // Try adding it to the return point, or the parent element. + else + currentNode = currentNode.returnPoint || currentNode.parent; + + if ( reApply ) + { + parser.onTagOpen.apply( this, arguments ); + return; + } + } + + checkPending( tagName ); + checkPendingBrs( tagName ); + + element.parent = currentNode; + element.returnPoint = returnPoint; + returnPoint = 0; + + if ( element.isEmpty ) + addElement( element ); + else + currentNode = element; + }; + + parser.onTagClose = function( tagName ) + { + // Check if there is any pending tag to be closed. + for ( var i = pendingInline.length - 1 ; i >= 0 ; i-- ) + { + // If found, just remove it from the list. + if ( tagName == pendingInline[ i ].name ) + { + pendingInline.splice( i, 1 ); + return; + } + } + + var pendingAdd = [], + newPendingInline = [], + candidate = currentNode; + + while ( candidate.type && candidate.name != tagName ) + { + // If this is an inline element, add it to the pending list, if we're + // really closing one of the parents element later, they will continue + // after it. + if ( !candidate._.isBlockLike ) + newPendingInline.unshift( candidate ); + + // This node should be added to it's parent at this point. But, + // it should happen only if the closing tag is really closing + // one of the nodes. So, for now, we just cache it. + pendingAdd.push( candidate ); + + candidate = candidate.parent; + } + + if ( candidate.type ) + { + // Add all elements that have been found in the above loop. + for ( i = 0 ; i < pendingAdd.length ; i++ ) + { + var node = pendingAdd[ i ]; + addElement( node, node.parent ); + } + + currentNode = candidate; + + + addElement( candidate, candidate.parent ); + + // The parent should start receiving new nodes now, except if + // addElement changed the currentNode. + if ( candidate == currentNode ) + currentNode = currentNode.parent; + + pendingInline = pendingInline.concat( newPendingInline ); + } + }; + + parser.onText = function( text ) + { + var currentDtd = CKEDITOR.dtd[ currentNode.name ]; + if ( !currentDtd || currentDtd[ '#' ] ) + { + checkPendingBrs(); + checkPending(); + + text.replace(/([\r\n])|[^\r\n]*/g, function( piece, lineBreak ) + { + if ( lineBreak !== undefined && lineBreak.length ) + pendingBrs++; + else if ( piece.length ) + { + var lastIndex = 0; + + // Create smiley from text emotion. + piece.replace( smileyRegExp, function( match, index ) + { + addElement( new CKEDITOR.htmlParser.text( piece.substring( lastIndex, index ) ), currentNode ); + addElement( new CKEDITOR.htmlParser.element( 'smiley', { 'desc': smileyReverseMap[ match ] } ), currentNode ); + lastIndex = index + match.length; + }); + + if ( lastIndex != piece.length ) + addElement( new CKEDITOR.htmlParser.text( piece.substring( lastIndex, piece.length ) ), currentNode ); + } + }); + } + }; + + // Parse it. + parser.parse( CKEDITOR.tools.htmlEncode( source ) ); + + // Close all hanging nodes. + while ( currentNode.type ) + { + var parent = currentNode.parent, + node = currentNode; + + addElement( node, parent ); + currentNode = parent; + } + + return fragment; + }; + + CKEDITOR.htmlParser.BBCodeWriter = CKEDITOR.tools.createClass( + { + $ : function() + { + this._ = + { + output : [], + rules : [] + }; + + // List and list item. + this.setRules( 'list', + { + breakBeforeOpen : 1, + breakAfterOpen : 1, + breakBeforeClose : 1, + breakAfterClose : 1 + } ); + + this.setRules( '*', + { + breakBeforeOpen : 1, + breakAfterOpen : 0, + breakBeforeClose : 1, + breakAfterClose : 0 + } ); + + this.setRules( 'quote', + { + breakBeforeOpen : 1, + breakAfterOpen : 0, + breakBeforeClose : 0, + breakAfterClose : 1 + } ); + }, + + proto : + { + /** + * Sets formatting rules for a given tag. The possible rules are: + * + * + * All rules default to "false". Each call to the function overrides + * already present rules, leaving the undefined untouched. + * + * @param {String} tagName The tag name to which set the rules. + * @param {Object} rules An object containing the element rules. + * @example + * // Break line before and after "img" tags. + * writer.setRules( 'list', + * { + * breakBeforeOpen : true + * breakAfterOpen : true + * }); + */ + setRules : function( tagName, rules ) + { + var currentRules = this._.rules[ tagName ]; + + if ( currentRules ) + CKEDITOR.tools.extend( currentRules, rules, true ); + else + this._.rules[ tagName ] = rules; + }, + + getRule : function( tagName, ruleName ) + { + return this._.rules[ tagName ] && this._.rules[ tagName ][ ruleName ]; + }, + + openTag : function( tag, attributes ) + { + if ( tag in bbcodeMap ) + { + if ( this.getRule( tag, 'breakBeforeOpen' ) ) + this.lineBreak( 1 ); + + this.write( '[', tag ); + var option = attributes.option; + option && this.write( '=', option ); + this.write( ']' ); + + if ( this.getRule( tag, 'breakAfterOpen' ) ) + this.lineBreak( 1 ); + } + else if ( tag == 'br' ) + this._.output.push( '\n' ); + }, + + openTagClose : function() { }, + attribute : function() { }, + + closeTag : function( tag ) + { + if ( tag in bbcodeMap ) + { + if ( this.getRule( tag, 'breakBeforeClose' ) ) + this.lineBreak( 1 ); + + tag != '*' && this.write( '[/', tag, ']' ); + + if ( this.getRule( tag, 'breakAfterClose' ) ) + this.lineBreak( 1 ); + } + }, + + text : function( text ) + { + this.write( text ); + }, + + /** + * Writes a comment. + * @param {String} comment The comment text. + * @example + * // Writes "<!-- My comment -->". + * writer.comment( ' My comment ' ); + */ + comment : function() {}, + + /* + * Output line-break for formatting. + */ + lineBreak : function() + { + // Avoid line break when: + // 1) Previous tag already put one. + // 2) We're at output start. + if ( !this._.hasLineBreak && this._.output.length ) + { + this.write( '\n' ); + this._.hasLineBreak = 1; + } + }, + + write : function() + { + this._.hasLineBreak = 0; + var data = Array.prototype.join.call( arguments, '' ); + this._.output.push( data ); + }, + + reset : function() + { + this._.output = []; + this._.hasLineBreak = 0; + }, + + getHtml : function( reset ) + { + var bbcode = this._.output.join( '' ); + + if ( reset ) + this.reset(); + + return decodeHtml ( bbcode ); + } + } + }); + + var BBCodeWriter = new CKEDITOR.htmlParser.BBCodeWriter(); + + CKEDITOR.plugins.add( 'bbcode', + { + requires : [ 'htmldataprocessor', 'entities' ], + beforeInit : function( editor ) + { + // Adapt some critical editor configuration for better support + // of BBCode environment. + var config = editor.config; + CKEDITOR.tools.extend( config, + { + enterMode : CKEDITOR.ENTER_BR, + basicEntities: false, + entities : false, + fillEmptyBlocks : false + }, true ); + }, + init : function( editor ) + { + var config = editor.config; + + function BBCodeToHtml( code ) + { + var fragment = CKEDITOR.htmlParser.fragment.fromBBCode( code ), + writer = new CKEDITOR.htmlParser.basicWriter(); + + fragment.writeHtml( writer, dataFilter ); + return writer.getHtml( true ); + } + + var dataFilter = new CKEDITOR.htmlParser.filter(); + dataFilter.addRules( + { + elements : + { + 'blockquote' : function( element ) + { + var quoted = new CKEDITOR.htmlParser.element( 'div' ); + quoted.children = element.children; + element.children = [ quoted ]; + var citeText = element.attributes.cite; + if ( citeText ) + { + var cite = new CKEDITOR.htmlParser.element( 'cite' ); + cite.add( new CKEDITOR.htmlParser.text( citeText.replace( /^"|"$/g, '' ) ) ); + delete element.attributes.cite; + element.children.unshift( cite ); + } + }, + 'span' : function( element ) + { + var bbcode; + if ( ( bbcode = element.attributes.bbcode ) ) + { + if ( bbcode == 'img' ) + { + element.name = 'img'; + element.attributes.src = element.children[ 0 ].value; + element.children = []; + } + else if ( bbcode == 'email' ) + { + element.name = 'a'; + element.attributes.href = 'mailto:' + element.children[ 0 ].value; + } + + delete element.attributes.bbcode; + } + }, + 'ol' : function ( element ) + { + if ( element.attributes.listType ) + { + if ( element.attributes.listType != 'decimal' ) + element.attributes.style = 'list-style-type:' + element.attributes.listType; + } + else + element.name = 'ul'; + + delete element.attributes.listType; + }, + a : function( element ) + { + if ( !element.attributes.href ) + element.attributes.href = element.children[ 0 ].value; + }, + 'smiley' : function( element ) + { + element.name = 'img'; + + var description = element.attributes.desc, + image = config.smiley_images[ CKEDITOR.tools.indexOf( config.smiley_descriptions, description ) ], + src = CKEDITOR.tools.htmlEncode( config.smiley_path + image ); + + element.attributes = + { + src : src, + 'data-cke-saved-src' : src, + title : description, + alt : description + }; + } + } + } ); + + editor.dataProcessor.htmlFilter.addRules( + { + elements : + { + $ : function( element ) + { + var attributes = element.attributes, + style = parseStyleText( attributes.style ), + value; + + var tagName = element.name; + if ( tagName in convertMap ) + tagName = convertMap[ tagName ]; + else if ( tagName == 'span' ) + { + if ( ( value = style.color ) ) + { + tagName = 'color'; + value = RGBToHex( value ); + } + else if ( ( value = style[ 'font-size' ] ) ) + { + var percentValue = value.match( /(\d+)%$/ ); + if ( percentValue ) + { + value = percentValue[ 1 ]; + tagName = 'size'; + } + } + } + else if ( tagName == 'ol' || tagName == 'ul' ) + { + if ( ( value = style[ 'list-style-type'] ) ) + { + switch ( value ) + { + case 'lower-alpha': + value = 'a'; + break; + case 'upper-alpha': + value = 'A'; + break; + } + } + else if ( tagName == 'ol' ) + value = 1; + + tagName = 'list'; + } + else if ( tagName == 'blockquote' ) + { + try + { + var cite = element.children[ 0 ], + quoted = element.children[ 1 ], + citeText = cite.name == 'cite' && cite.children[ 0 ].value; + + if ( citeText ) + { + value = '"' + citeText + '"'; + element.children = quoted.children; + } + + } + catch( er ) + { + } + + tagName = 'quote'; + } + else if ( tagName == 'a' ) + { + if ( ( value = attributes.href ) ) + { + if ( value.indexOf( 'mailto:' ) !== -1 ) + { + tagName = 'email'; + // [email] should have a single text child with email address. + element.children = [ new CKEDITOR.htmlParser.text( value.replace( 'mailto:', '' ) ) ]; + value = ''; + } + else + { + var singleton = element.children.length == 1 && element.children[ 0 ]; + if ( singleton + && singleton.type == CKEDITOR.NODE_TEXT + && singleton.value == value ) + value = ''; + + tagName = 'url'; + } + } + } + else if ( tagName == 'img' ) + { + element.isEmpty = 0; + + // Translate smiley (image) to text emotion. + var src = attributes[ 'data-cke-saved-src' ]; + if ( src && src.indexOf( editor.config.smiley_path ) != -1 ) + return new CKEDITOR.htmlParser.text( smileyMap[ attributes.alt ] ); + else + element.children = [ new CKEDITOR.htmlParser.text( src ) ]; + } + + element.name = tagName; + value && ( element.attributes.option = value ); + + return null; + }, + + // Remove any bogus br from the end of a pseudo block, + // e.g.
    some text

    paragraph

    + br : function( element ) + { + var next = element.next; + if ( next && next.name in blockLikeTags ) + return false; + } + } + }, 1 ); + + editor.dataProcessor.writer = BBCodeWriter; + + editor.on( 'beforeSetMode', function( evt ) + { + evt.removeListener(); + var wysiwyg = editor._.modes[ 'wysiwyg' ]; + wysiwyg.loadData = CKEDITOR.tools.override( wysiwyg.loadData, function( org ) + { + return function( data ) + { + return ( org.call( this, BBCodeToHtml( data ) ) ); + }; + } ); + } ); + }, + + afterInit : function( editor ) + { + var filters; + if ( editor._.elementsPath ) + { + // Eliminate irrelevant elements from displaying, e.g body and p. + if ( ( filters = editor._.elementsPath.filters ) ) + filters.push( function( element ) + { + var htmlName = element.getName(), + name = tagnameMap[ htmlName ] || false; + + // Specialized anchor presents as email. + if ( name == 'link' && element.getAttribute( 'href' ).indexOf( 'mailto:' ) === 0 ) + name = 'email'; + // Styled span could be either size or color. + else if ( htmlName == 'span' ) + { + if ( element.getStyle( 'font-size' ) ) + name = 'size'; + else if ( element.getStyle( 'color' ) ) + name = 'color'; + } + else if ( name == 'img' ) + { + var src = element.data( 'cke-saved-src' ); + if ( src && src.indexOf( editor.config.smiley_path ) === 0 ) + name = 'smiley'; + } + + return name; + }); + } + } + } ); + +})();