/** * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ 'use strict'; /** * Block style type. * * Read more in the {@link CKEDITOR.style} class documentation. * * @readonly * @property {Number} [=1] * @member CKEDITOR */ CKEDITOR.STYLE_BLOCK = 1; /** * Inline style type. * * Read more in the {@link CKEDITOR.style} class documentation. * * @readonly * @property {Number} [=2] * @member CKEDITOR */ CKEDITOR.STYLE_INLINE = 2; /** * Object style type. * * Read more in the {@link CKEDITOR.style} class documentation. * * @readonly * @property {Number} [=3] * @member CKEDITOR */ CKEDITOR.STYLE_OBJECT = 3; ( function() { var blockElements = { address: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, p: 1, pre: 1, section: 1, header: 1, footer: 1, nav: 1, article: 1, aside: 1, figure: 1, dialog: 1, hgroup: 1, time: 1, meter: 1, menu: 1, command: 1, keygen: 1, output: 1, progress: 1, details: 1, datagrid: 1, datalist: 1 }, objectElements = { a: 1, blockquote: 1, embed: 1, hr: 1, img: 1, li: 1, object: 1, ol: 1, table: 1, td: 1, tr: 1, th: 1, ul: 1, dl: 1, dt: 1, dd: 1, form: 1, audio: 1, video: 1 }; var semicolonFixRegex = /\s*(?:;\s*|$)/, varRegex = /#\((.+?)\)/g; var notBookmark = CKEDITOR.dom.walker.bookmark( 0, 1 ), nonWhitespaces = CKEDITOR.dom.walker.whitespaces( 1 ); /** * A class representing a style instance for the specific style definition. * In this approach, a style is a set of properties, like attributes and styles, * which can be applied to and removed from a {@link CKEDITOR.dom.selection selection} through * {@link CKEDITOR.editor editor} methods: {@link CKEDITOR.editor#applyStyle} and {@link CKEDITOR.editor#removeStyle}, * respectively. * * Three default style types are available: {@link CKEDITOR#STYLE_BLOCK STYLE_BLOCK}, {@link CKEDITOR#STYLE_INLINE STYLE_INLINE}, * and {@link CKEDITOR#STYLE_OBJECT STYLE_OBJECT}. Based on its type, a style heavily changes its behavior. * You can read more about style types in the [Style Types section of the Styles guide](#!/guide/dev_styles-section-style-types). * * It is possible to define a custom style type by subclassing this class by using the {@link #addCustomHandler} method. * However, because of great complexity of the styles handling job, it is only possible in very specific cases. * * ### Usage * * Basic usage: * * // Define a block style. * var style = new CKEDITOR.style( { element: 'h1' } ); * * // Considering the following selection: * //
Foo
Bar^
* // Executing: * editor.applyStyle( style ); * // Will give: * //Foo
Foo
Bar^
* * style.checkActive( editor.elementPath(), editor ); // -> false * * Object style: * * // Define an object style. * var style = new CKEDITOR.style( { element: 'img', attributes: { 'class': 'foo' } } ); * * // Considering the following selection: * //
Foo^
[
]Foo
[
]Foo
get special treatment.
if ( block.is( 'pre' ) ) {
newBlock = this._.enterMode == CKEDITOR.ENTER_BR ? null :
range.document.createElement( this._.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
newBlock && block.copyAttributes( newBlock );
replaceBlock( block, newBlock );
} else {
removeFromElement.call( this, block );
}
}
}
range.moveToBookmark( bookmark );
}
// Replace the original block with new one, with special treatment
// for blocks to make sure content format is well preserved, and merging/splitting adjacent
// when necessary. (#3188)
function replaceBlock( block, newBlock ) {
// Block is to be removed, create a temp element to
// save contents.
var removeBlock = !newBlock;
if ( removeBlock ) {
newBlock = block.getDocument().createElement( 'div' );
block.copyAttributes( newBlock );
}
var newBlockIsPre = newBlock && newBlock.is( 'pre' ),
blockIsPre = block.is( 'pre' ),
isToPre = newBlockIsPre && !blockIsPre,
isFromPre = !newBlockIsPre && blockIsPre;
if ( isToPre )
newBlock = toPre( block, newBlock );
else if ( isFromPre )
// Split big into pieces before start to convert.
newBlock = fromPres( removeBlock ? [ block.getHtml() ] : splitIntoPres( block ), newBlock );
else
block.moveChildren( newBlock );
newBlock.replace( block );
if ( newBlockIsPre ) {
// Merge previous blocks.
mergePre( newBlock );
} else if ( removeBlock ) {
removeNoAttribsElement( newBlock );
}
}
// Merge a block with a previous sibling if available.
function mergePre( preBlock ) {
var previousBlock;
if ( !( ( previousBlock = preBlock.getPrevious( nonWhitespaces ) ) && previousBlock.type == CKEDITOR.NODE_ELEMENT && previousBlock.is( 'pre' ) ) )
return;
// Merge the previous block contents into the current
// block.
//
// Another thing to be careful here is that currentBlock might contain
// a '\n' at the beginning, and previousBlock might contain a '\n'
// towards the end. These new lines are not normally displayed but they
// become visible after merging.
var mergedHtml = replace( previousBlock.getHtml(), /\n$/, '' ) + '\n\n' +
replace( preBlock.getHtml(), /^\n/, '' );
// Krugle: IE normalizes innerHTML from , breaking whitespaces.
if ( CKEDITOR.env.ie )
preBlock.$.outerHTML = '' + mergedHtml + '
';
else
preBlock.setHtml( mergedHtml );
previousBlock.remove();
}
// Split into multiple blocks separated by double line-break.
function splitIntoPres( preBlock ) {
// Exclude the ones at header OR at tail,
// and ignore bookmark content between them.
var duoBrRegex = /(\S\s*)\n(?:\s|(]+data-cke-bookmark.*?\/span>))*\n(?!$)/gi,
pres = [],
splitedHtml = replace( preBlock.getOuterHtml(), duoBrRegex, function( match, charBefore, bookmark ) {
return charBefore + '' + bookmark + '';
} );
splitedHtml.replace( /([\s\S]*?)<\/pre>/gi, function( match, preContent ) {
pres.push( preContent );
} );
return pres;
}
// Wrapper function of String::replace without considering of head/tail bookmarks nodes.
function replace( str, regexp, replacement ) {
var headBookmark = '',
tailBookmark = '';
str = str.replace( /(^]+data-cke-bookmark.*?\/span>)|(]+data-cke-bookmark.*?\/span>$)/gi, function( str, m1, m2 ) {
m1 && ( headBookmark = m1 );
m2 && ( tailBookmark = m2 );
return '';
} );
return headBookmark + str.replace( regexp, replacement ) + tailBookmark;
}
// Converting a list of into blocks with format well preserved.
function fromPres( preHtmls, newBlock ) {
var docFrag;
if ( preHtmls.length > 1 )
docFrag = new CKEDITOR.dom.documentFragment( newBlock.getDocument() );
for ( var i = 0; i < preHtmls.length; i++ ) {
var blockHtml = preHtmls[ i ];
// 1. Trim the first and last line-breaks immediately after and before ,
// they're not visible.
blockHtml = blockHtml.replace( /(\r\n|\r)/g, '\n' );
blockHtml = replace( blockHtml, /^[ \t]*\n/, '' );
blockHtml = replace( blockHtml, /\n$/, '' );
// 2. Convert spaces or tabs at the beginning or at the end to
blockHtml = replace( blockHtml, /^[ \t]+|[ \t]+$/g, function( match, offset ) {
if ( match.length == 1 ) // one space, preserve it
return ' ';
else if ( !offset ) // beginning of block
return CKEDITOR.tools.repeat( ' ', match.length - 1 ) + ' ';
else // end of block
return ' ' + CKEDITOR.tools.repeat( ' ', match.length - 1 );
} );
// 3. Convert \n to
.
// 4. Convert contiguous (i.e. non-singular) spaces or tabs to
blockHtml = blockHtml.replace( /\n/g, '
' );
blockHtml = blockHtml.replace( /[ \t]{2,}/g, function( match ) {
return CKEDITOR.tools.repeat( ' ', match.length - 1 ) + ' ';
} );
if ( docFrag ) {
var newBlockClone = newBlock.clone();
newBlockClone.setHtml( blockHtml );
docFrag.append( newBlockClone );
} else {
newBlock.setHtml( blockHtml );
}
}
return docFrag || newBlock;
}
// Converting from a non-PRE block to a PRE block in formatting operations.
function toPre( block, newBlock ) {
var bogus = block.getBogus();
bogus && bogus.remove();
// First trim the block content.
var preHtml = block.getHtml();
// 1. Trim head/tail spaces, they're not visible.
preHtml = replace( preHtml, /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '' );
// 2. Delete ANSI whitespaces immediately before and after
because
// they are not visible.
preHtml = preHtml.replace( /[ \t\r\n]*(
]*>)[ \t\r\n]*/gi, '$1' );
// 3. Compress other ANSI whitespaces since they're only visible as one
// single space previously.
// 4. Convert to spaces since is no longer needed in .
preHtml = preHtml.replace( /([ \t\n\r]+| )/g, ' ' );
// 5. Convert any
to \n. This must not be done earlier because
// the \n would then get compressed.
preHtml = preHtml.replace( /
]*>/gi, '\n' );
// Krugle: IE normalizes innerHTML to , breaking whitespaces.
if ( CKEDITOR.env.ie ) {
var temp = block.getDocument().createElement( 'div' );
temp.append( newBlock );
newBlock.$.outerHTML = '' + preHtml + '
';
newBlock.copyAttributes( temp.getFirst() );
newBlock = temp.getFirst().remove();
} else {
newBlock.setHtml( preHtml );
}
return newBlock;
}
// Removes a style from an element itself, don't care about its subtree.
function removeFromElement( element, keepDataAttrs ) {
var def = this._.definition,
attributes = def.attributes,
styles = def.styles,
overrides = getOverrides( this )[ element.getName() ],
// If the style is only about the element itself, we have to remove the element.
removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );
// Remove definition attributes/style from the elemnt.
for ( var attName in attributes ) {
// The 'class' element value must match (#1318).
if ( ( attName == 'class' || this._.definition.fullMatch ) && element.getAttribute( attName ) != normalizeProperty( attName, attributes[ attName ] ) )
continue;
// Do not touch data-* attributes (#11011) (#11258).
if ( keepDataAttrs && attName.slice( 0, 5 ) == 'data-' )
continue;
removeEmpty = element.hasAttribute( attName );
element.removeAttribute( attName );
}
for ( var styleName in styles ) {
// Full match style insist on having fully equivalence. (#5018)
if ( this._.definition.fullMatch && element.getStyle( styleName ) != normalizeProperty( styleName, styles[ styleName ], true ) )
continue;
removeEmpty = removeEmpty || !!element.getStyle( styleName );
element.removeStyle( styleName );
}
// Remove overrides, but don't remove the element if it's a block element
removeOverrides( element, overrides, blockElements[ element.getName() ] );
if ( removeEmpty ) {
if ( this._.definition.alwaysRemoveElement )
removeNoAttribsElement( element, 1 );
else {
if ( !CKEDITOR.dtd.$block[ element.getName() ] || this._.enterMode == CKEDITOR.ENTER_BR && !element.hasAttributes() )
removeNoAttribsElement( element );
else
element.renameNode( this._.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
}
}
}
// Removes a style from inside an element. Called on applyStyle to make cleanup
// before apply. During clean up this function keep data-* attribute in contrast
// to removeFromElement.
function removeFromInsideElement( element ) {
var overrides = getOverrides( this ),
innerElements = element.getElementsByTag( this.element ),
innerElement;
for ( var i = innerElements.count(); --i >= 0; ) {
innerElement = innerElements.getItem( i );
// Do not remove elements which are read only (e.g. duplicates inside widgets).
if ( !innerElement.isReadOnly() )
removeFromElement.call( this, innerElement, true );
}
// Now remove any other element with different name that is
// defined to be overriden.
for ( var overrideElement in overrides ) {
if ( overrideElement != this.element ) {
innerElements = element.getElementsByTag( overrideElement );
for ( i = innerElements.count() - 1; i >= 0; i-- ) {
innerElement = innerElements.getItem( i );
// Do not remove elements which are read only (e.g. duplicates inside widgets).
if ( !innerElement.isReadOnly() )
removeOverrides( innerElement, overrides[ overrideElement ] );
}
}
}
}
// Remove overriding styles/attributes from the specific element.
// Note: Remove the element if no attributes remain.
// @param {Object} element
// @param {Object} overrides
// @param {Boolean} Don't remove the element
function removeOverrides( element, overrides, dontRemove ) {
var attributes = overrides && overrides.attributes;
if ( attributes ) {
for ( var i = 0; i < attributes.length; i++ ) {
var attName = attributes[ i ][ 0 ],
actualAttrValue;
if ( ( actualAttrValue = element.getAttribute( attName ) ) ) {
var attValue = attributes[ i ][ 1 ];
// Remove the attribute if:
// - The override definition value is null ;
// - The override definition valie is a string that
// matches the attribute value exactly.
// - The override definition value is a regex that
// has matches in the attribute value.
if ( attValue === null || ( attValue.test && attValue.test( actualAttrValue ) ) || ( typeof attValue == 'string' && actualAttrValue == attValue ) )
element.removeAttribute( attName );
}
}
}
if ( !dontRemove )
removeNoAttribsElement( element );
}
// If the element has no more attributes, remove it.
function removeNoAttribsElement( element, forceRemove ) {
// If no more attributes remained in the element, remove it,
// leaving its children.
if ( !element.hasAttributes() || forceRemove ) {
if ( CKEDITOR.dtd.$block[ element.getName() ] ) {
var previous = element.getPrevious( nonWhitespaces ),
next = element.getNext( nonWhitespaces );
if ( previous && ( previous.type == CKEDITOR.NODE_TEXT || !previous.isBlockBoundary( { br: 1 } ) ) )
element.append( 'br', 1 );
if ( next && ( next.type == CKEDITOR.NODE_TEXT || !next.isBlockBoundary( { br: 1 } ) ) )
element.append( 'br' );
element.remove( true );
} else {
// Removing elements may open points where merging is possible,
// so let's cache the first and last nodes for later checking.
var firstChild = element.getFirst();
var lastChild = element.getLast();
element.remove( true );
if ( firstChild ) {
// Check the cached nodes for merging.
firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.mergeSiblings();
if ( lastChild && !firstChild.equals( lastChild ) && lastChild.type == CKEDITOR.NODE_ELEMENT )
lastChild.mergeSiblings();
}
}
}
}
function getElement( style, targetDocument, element ) {
var el,
elementName = style.element;
// The "*" element name will always be a span for this function.
if ( elementName == '*' )
elementName = 'span';
// Create the element.
el = new CKEDITOR.dom.element( elementName, targetDocument );
// #6226: attributes should be copied before the new ones are applied
if ( element )
element.copyAttributes( el );
el = setupElement( el, style );
// Avoid ID duplication.
if ( targetDocument.getCustomData( 'doc_processing_style' ) && el.hasAttribute( 'id' ) )
el.removeAttribute( 'id' );
else
targetDocument.setCustomData( 'doc_processing_style', 1 );
return el;
}
function setupElement( el, style ) {
var def = style._.definition,
attributes = def.attributes,
styles = CKEDITOR.style.getStyleText( def );
// Assign all defined attributes.
if ( attributes ) {
for ( var att in attributes )
el.setAttribute( att, attributes[ att ] );
}
// Assign all defined styles.
if ( styles )
el.setAttribute( 'style', styles );
return el;
}
function replaceVariables( list, variablesValues ) {
for ( var item in list ) {
list[ item ] = list[ item ].replace( varRegex, function( match, varName ) {
return variablesValues[ varName ];
} );
}
}
// Returns an object that can be used for style matching comparison.
// Attributes names and values are all lowercased, and the styles get
// merged with the style attribute.
function getAttributesForComparison( styleDefinition ) {
// If we have already computed it, just return it.
var attribs = styleDefinition._AC;
if ( attribs )
return attribs;
attribs = {};
var length = 0;
// Loop through all defined attributes.
var styleAttribs = styleDefinition.attributes;
if ( styleAttribs ) {
for ( var styleAtt in styleAttribs ) {
length++;
attribs[ styleAtt ] = styleAttribs[ styleAtt ];
}
}
// Includes the style definitions.
var styleText = CKEDITOR.style.getStyleText( styleDefinition );
if ( styleText ) {
if ( !attribs.style )
length++;
attribs.style = styleText;
}
// Appends the "length" information to the object.
attribs._length = length;
// Return it, saving it to the next request.
return ( styleDefinition._AC = attribs );
}
// Get the the collection used to compare the elements and attributes,
// defined in this style overrides, with other element. All information in
// it is lowercased.
// @param {CKEDITOR.style} style
function getOverrides( style ) {
if ( style._.overrides )
return style._.overrides;
var overrides = ( style._.overrides = {} ),
definition = style._.definition.overrides;
if ( definition ) {
// The override description can be a string, object or array.
// Internally, well handle arrays only, so transform it if needed.
if ( !CKEDITOR.tools.isArray( definition ) )
definition = [ definition ];
// Loop through all override definitions.
for ( var i = 0; i < definition.length; i++ ) {
var override = definition[ i ],
elementName,
overrideEl,
attrs;
// If can be a string with the element name.
if ( typeof override == 'string' )
elementName = override.toLowerCase();
// Or an object.
else {
elementName = override.element ? override.element.toLowerCase() : style.element;
attrs = override.attributes;
}
// We can have more than one override definition for the same
// element name, so we attempt to simply append information to
// it if it already exists.
overrideEl = overrides[ elementName ] || ( overrides[ elementName ] = {} );
if ( attrs ) {
// The returning attributes list is an array, because we
// could have different override definitions for the same
// attribute name.
var overrideAttrs = ( overrideEl.attributes = overrideEl.attributes || [] );
for ( var attName in attrs ) {
// Each item in the attributes array is also an array,
// where [0] is the attribute name and [1] is the
// override value.
overrideAttrs.push( [ attName.toLowerCase(), attrs[ attName ] ] );
}
}
}
}
return overrides;
}
// Make the comparison of attribute value easier by standardizing it.
function normalizeProperty( name, value, isStyle ) {
var temp = new CKEDITOR.dom.element( 'span' );
temp[ isStyle ? 'setStyle' : 'setAttribute' ]( name, value );
return temp[ isStyle ? 'getStyle' : 'getAttribute' ]( name );
}
// Compare two bunch of styles, with the speciality that value 'inherit'
// is treated as a wildcard which will match any value.
// @param {Object/String} source
// @param {Object/String} target
// @returns {Boolean}
function compareCssText( source, target ) {
function filter( string, propertyName ) {
// In case of font-families we'll skip quotes. (#10750)
return propertyName.toLowerCase() == 'font-family' ? string.replace( /["']/g, '' ) : string;
}
if ( typeof source == 'string' )
source = CKEDITOR.tools.parseCssText( source );
if ( typeof target == 'string' )
target = CKEDITOR.tools.parseCssText( target, true );
for ( var name in source ) {
if ( !( name in target ) ) {
return false;
}
if ( !( filter( target[ name ], name ) == filter( source[ name ], name ) ||
source[ name ] == 'inherit' ||
target[ name ] == 'inherit' ) ) {
return false;
}
}
return true;
}
function applyStyleOnSelection( selection, remove, editor ) {
var doc = selection.document,
ranges = selection.getRanges(),
func = remove ? this.removeFromRange : this.applyToRange,
range;
var iterator = ranges.createIterator();
while ( ( range = iterator.getNextRange() ) )
func.call( this, range, editor );
selection.selectRanges( ranges );
doc.removeCustomData( 'doc_processing_style' );
}
} )();
/**
* Generic style command. It applies a specific style when executed.
*
* var boldStyle = new CKEDITOR.style( { element: 'strong' } );
* // Register the "bold" command, which applies the bold style.
* editor.addCommand( 'bold', new CKEDITOR.styleCommand( boldStyle ) );
*
* @class
* @constructor Creates a styleCommand class instance.
* @extends CKEDITOR.commandDefinition
* @param {CKEDITOR.style} style The style to be applied when command is executed.
* @param {Object} [ext] Additional command definition's properties.
*/
CKEDITOR.styleCommand = function( style, ext ) {
this.style = style;
this.allowedContent = style;
this.requiredContent = style;
CKEDITOR.tools.extend( this, ext, true );
};
/**
* @param {CKEDITOR.editor} editor
* @todo
*/
CKEDITOR.styleCommand.prototype.exec = function( editor ) {
editor.focus();
if ( this.state == CKEDITOR.TRISTATE_OFF )
editor.applyStyle( this.style );
else if ( this.state == CKEDITOR.TRISTATE_ON )
editor.removeStyle( this.style );
};
/**
* Manages styles registration and loading. See also {@link CKEDITOR.config#stylesSet}.
*
* // The set of styles for the Styles drop-down list.
* CKEDITOR.stylesSet.add( 'default', [
* // Block Styles
* { name: 'Blue Title', element: 'h3', styles: { 'color': 'Blue' } },
* { name: 'Red Title', element: 'h3', styles: { 'color': 'Red' } },
*
* // Inline Styles
* { name: 'Marker: Yellow', element: 'span', styles: { 'background-color': 'Yellow' } },
* { name: 'Marker: Green', element: 'span', styles: { 'background-color': 'Lime' } },
*
* // Object Styles
* {
* name: 'Image on Left',
* element: 'img',
* attributes: {
* style: 'padding: 5px; margin-right: 5px',
* border: '2',
* align: 'left'
* }
* }
* ] );
*
* @since 3.2
* @class
* @singleton
* @extends CKEDITOR.resourceManager
*/
CKEDITOR.stylesSet = new CKEDITOR.resourceManager( '', 'stylesSet' );
// Backward compatibility (#5025).
CKEDITOR.addStylesSet = CKEDITOR.tools.bind( CKEDITOR.stylesSet.add, CKEDITOR.stylesSet );
CKEDITOR.loadStylesSet = function( name, url, callback ) {
CKEDITOR.stylesSet.addExternal( name, url, '' );
CKEDITOR.stylesSet.load( name, callback );
};
CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
/**
* Registers a function to be called whenever the selection position changes in the
* editing area. The current state is passed to the function. The possible
* states are {@link CKEDITOR#TRISTATE_ON} and {@link CKEDITOR#TRISTATE_OFF}.
*
* // Create a style object for the element.
* var style = new CKEDITOR.style( { element: 'b' } );
* var editor = CKEDITOR.instances.editor1;
* editor.attachStyleStateChange( style, function( state ) {
* if ( state == CKEDITOR.TRISTATE_ON )
* alert( 'The current state for the B element is ON' );
* else
* alert( 'The current state for the B element is OFF' );
* } );
*
* @member CKEDITOR.editor
* @param {CKEDITOR.style} style The style to be watched.
* @param {Function} callback The function to be called.
*/
attachStyleStateChange: function( style, callback ) {
// Try to get the list of attached callbacks.
var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
// If it doesn't exist, it means this is the first call. So, let's create
// all the structure to manage the style checks and the callback calls.
if ( !styleStateChangeCallbacks ) {
// Create the callbacks array.
styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
// Attach to the selectionChange event, so we can check the styles at
// that point.
this.on( 'selectionChange', function( ev ) {
// Loop throw all registered callbacks.
for ( var i = 0; i < styleStateChangeCallbacks.length; i++ ) {
var callback = styleStateChangeCallbacks[ i ];
// Check the current state for the style defined for that callback.
var currentState = callback.style.checkActive( ev.data.path, this ) ?
CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
// Call the callback function, passing the current state to it.
callback.fn.call( this, currentState );
}
} );
}
// Save the callback info, so it can be checked on the next occurrence of
// selectionChange.
styleStateChangeCallbacks.push( { style: style, fn: callback } );
},
/**
* Applies the style upon the editor's current selection. Shorthand for
* {@link CKEDITOR.style#apply}.
*
* @member CKEDITOR.editor
* @param {CKEDITOR.style} style
*/
applyStyle: function( style ) {
style.apply( this );
},
/**
* Removes the style from the editor's current selection. Shorthand for
* {@link CKEDITOR.style#remove}.
*
* @member CKEDITOR.editor
* @param {CKEDITOR.style} style
*/
removeStyle: function( style ) {
style.remove( this );
},
/**
* Gets the current `stylesSet` for this instance.
*
* editor.getStylesSet( function( stylesDefinitions ) {} );
*
* See also {@link CKEDITOR.editor#stylesSet} event.
*
* @member CKEDITOR.editor
* @param {Function} callback The function to be called with the styles data.
*/
getStylesSet: function( callback ) {
if ( !this._.stylesDefinitions ) {
var editor = this,
// Respect the backwards compatible definition entry
configStyleSet = editor.config.stylesCombo_stylesSet || editor.config.stylesSet;
// The false value means that none styles should be loaded.
if ( configStyleSet === false ) {
callback( null );
return;
}
// #5352 Allow to define the styles directly in the config object
if ( configStyleSet instanceof Array ) {
editor._.stylesDefinitions = configStyleSet;
callback( configStyleSet );
return;
}
// Default value is 'default'.
if ( !configStyleSet )
configStyleSet = 'default';
var partsStylesSet = configStyleSet.split( ':' ),
styleSetName = partsStylesSet[ 0 ],
externalPath = partsStylesSet[ 1 ];
CKEDITOR.stylesSet.addExternal( styleSetName, externalPath ? partsStylesSet.slice( 1 ).join( ':' ) : CKEDITOR.getUrl( 'styles.js' ), '' );
CKEDITOR.stylesSet.load( styleSetName, function( stylesSet ) {
editor._.stylesDefinitions = stylesSet[ styleSetName ];
callback( editor._.stylesDefinitions );
} );
} else {
callback( this._.stylesDefinitions );
}
}
} );
/**
* Indicates that fully selected read-only elements will be included when
* applying the style (for inline styles only).
*
* @since 3.5
* @property {Boolean} [includeReadonly=false]
* @member CKEDITOR.style
*/
/**
* Indicates that any matches element of this style will be eventually removed
* when calling {@link CKEDITOR.editor#removeStyle}.
*
* @since 4.0
* @property {Boolean} [alwaysRemoveElement=false]
* @member CKEDITOR.style
*/
/**
* Disables inline styling on read-only elements.
*
* @since 3.5
* @cfg {Boolean} [disableReadonlyStyling=false]
* @member CKEDITOR.config
*/
/**
* The "styles definition set" to use in the editor. They will be used in the
* styles combo and the style selector of the div container.
*
* The styles may be defined in the page containing the editor, or can be
* loaded on demand from an external file. In the second case, if this setting
* contains only a name, the `styles.js` file will be loaded from the
* CKEditor root folder (what ensures backward compatibility with CKEditor 4.0).
*
* Otherwise, this setting has the `name:url` syntax, making it
* possible to set the URL from which the styles file will be loaded.
* Note that the `name` has to be equal to the name used in
* {@link CKEDITOR.stylesSet#add} while registering the styles set.
*
* **Note**: Since 4.1 it is possible to set `stylesSet` to `false`
* to prevent loading any styles set.
*
* Read more in the [documentation](#!/guide/dev_styles)
* and see the [SDK sample](http://sdk.ckeditor.com/samples/styles.html).
*
* // Do not load any file. The styles set is empty.
* config.stylesSet = false;
*
* // Load the 'mystyles' styles set from the styles.js file.
* config.stylesSet = 'mystyles';
*
* // Load the 'mystyles' styles set from a relative URL.
* config.stylesSet = 'mystyles:/editorstyles/styles.js';
*
* // Load the 'mystyles' styles set from a full URL.
* config.stylesSet = 'mystyles:http://www.example.com/editorstyles/styles.js';
*
* // Load from a list of definitions.
* config.stylesSet = [
* { name: 'Strong Emphasis', element: 'strong' },
* { name: 'Emphasis', element: 'em' },
* ...
* ];
*
* @since 3.3
* @cfg {String/Array/Boolean} [stylesSet='default']
* @member CKEDITOR.config
*/