Apollo 11 was the spaceflight that landed the first humans, Americans Neil Armstrong and Buzz Aldrin, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.
+
+
Armstrong spent about three and a half two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, Michael Collins, piloted the command spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.
+
+
Broadcasting and quotes
+
+
Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:
+
+
+
One small step for [a] man, one giant leap for mankind.
+
+
+
Apollo 11 effectively ended the Space Race and fulfilled a national goal proposed in 1961 by the late U.S. President John F. Kennedy in a speech before the United States Congress:
+
+
+
[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.
+
+
+
+
+ The Eagle in lunar orbit
+
+
+
Technical details
+
+
Launched by a Saturn V rocket from Kennedy Space Center in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of NASA's Apollo program. The Apollo spacecraft had three parts:
+
+
+
Command Module with a cabin for the three astronauts which was the only part which landed back on Earth
+
Service Module which supported the Command Module with propulsion, electrical power, oxygen and water
+
Lunar Module for landing on the Moon.
+
+
+
After being sent to the Moon by the Saturn V's upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the Sea of Tranquility. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the Pacific Ocean on July 24.
+ if ( hasCaption )
+ wrapper.addClass( alignClasses[ 1 ] );
+ } else if ( align != 'none' )
+ wrapper.addClass( alignClasses[ alignmentsObj[ align ] ] );
+ } else {
+ if ( align == 'center' ) {
+ if ( hasCaption )
+ wrapper.setStyle( 'text-align', 'center' );
+ else
+ wrapper.removeStyle( 'text-align' );
+
+ wrapper.removeStyle( 'float' );
+ }
+ else {
+ if ( align == 'none' )
+ wrapper.removeStyle( 'float' );
+ else
+ wrapper.setStyle( 'float', align );
+
+ wrapper.removeStyle( 'text-align' );
+ }
+ }
+ }
+
+ // Returns a function that creates widgets from all and
+ // elements.
+ //
+ // @param {CKEDITOR.editor} editor
+ // @returns {Function}
+ function upcastWidgetElement( editor ) {
+ var isCenterWrapper = centerWrapperChecker( editor ),
+ captionedClass = editor.config.image2_captionedClass;
+
+ // @param {CKEDITOR.htmlParser.element} el
+ // @param {Object} data
+ return function( el, data ) {
+ var dimensions = { width: 1, height: 1 },
+ name = el.name,
+ image;
+
+ // #11110 Don't initialize on pasted fake objects.
+ if ( el.attributes[ 'data-cke-realelement' ] )
+ return;
+
+ // If a center wrapper is found, there are 3 possible cases:
+ //
+ // 1.
...
.
+ // In this case centering is done with a class set on widget.wrapper.
+ // Simply replace centering wrapper with figure (it's no longer necessary).
+ //
+ // 2.
.
+ // Nothing to do here:
remains for styling purposes.
+ //
+ // 3.
.
+ // Nothing to do here (2.) but that case is only possible in enterMode different
+ // than ENTER_P.
+ if ( isCenterWrapper( el ) ) {
+ if ( name == 'div' ) {
+ var figure = el.getFirst( 'figure' );
+
+ // Case #1.
+ if ( figure ) {
+ el.replaceWith( figure );
+ el = figure;
+ }
+ }
+ // Cases #2 and #3 (handled transparently)
+
+ // If there's a centering wrapper, save it in data.
+ data.align = 'center';
+
+ // Image can be wrapped in link .
+ image = el.getFirst( 'img' ) || el.getFirst( 'a' ).getFirst( 'img' );
+ }
+
+ // No center wrapper has been found.
+ else if ( name == 'figure' && el.hasClass( captionedClass ) )
+ image = el.getFirst( 'img' ) || el.getFirst( 'a' ).getFirst( 'img' );
+
+ // Upcast linked image like .
+ else if ( isLinkedOrStandaloneImage( el ) )
+ image = el.name == 'a' ? el.children[ 0 ] : el;
+
+ if ( !image )
+ return;
+
+ // If there's an image, then cool, we got a widget.
+ // Now just remove dimension attributes expressed with %.
+ for ( var d in dimensions ) {
+ var dimension = image.attributes[ d ];
+
+ if ( dimension && dimension.match( regexPercent ) )
+ delete image.attributes[ d ];
+ }
+
+ return el;
+ };
+ }
+
+ // Returns a function which transforms the widget to the external format
+ // according to the current configuration.
+ //
+ // @param {CKEDITOR.editor}
+ function downcastWidgetElement( editor ) {
+ var alignClasses = editor.config.image2_alignClasses;
+
+ // @param {CKEDITOR.htmlParser.element} el
+ return function( el ) {
+ // In case of , is the element to hold
+ // inline styles or classes (image2_alignClasses).
+ var attrsHolder = el.name == 'a' ? el.getFirst() : el,
+ attrs = attrsHolder.attributes,
+ align = this.data.align;
+
+ // De-wrap the image from resize handle wrapper.
+ // Only block widgets have one.
+ if ( !this.inline ) {
+ var resizeWrapper = el.getFirst( 'span' );
+
+ if ( resizeWrapper )
+ resizeWrapper.replaceWith( resizeWrapper.getFirst( { img: 1, a: 1 } ) );
+ }
+
+ if ( align && align != 'none' ) {
+ var styles = CKEDITOR.tools.parseCssText( attrs.style || '' );
+
+ // When the widget is captioned () and internally centering is done
+ // with widget's wrapper style/class, in the external data representation,
+ // must be wrapped with an element holding an style/class:
+ //
+ //
+ // ...
+ //
+ // or
+ //
+ // ...
+ //
+ //
+ if ( align == 'center' && el.name == 'figure' ) {
+ el = el.wrapWith( new CKEDITOR.htmlParser.element( 'div',
+ alignClasses ? { 'class': alignClasses[ 1 ] } : { style: 'text-align:center' } ) );
+ }
+
+ // If left/right, add float style to the downcasted element.
+ else if ( align in { left: 1, right: 1 } ) {
+ if ( alignClasses )
+ attrsHolder.addClass( alignClasses[ alignmentsObj[ align ] ] );
+ else
+ styles[ 'float' ] = align;
+ }
+
+ // Update element styles.
+ if ( !alignClasses && !CKEDITOR.tools.isEmpty( styles ) )
+ attrs.style = CKEDITOR.tools.writeCssText( styles );
+ }
+
+ return el;
+ };
+ }
+
+ // Returns a function that checks if an element is a centering wrapper.
+ //
+ // @param {CKEDITOR.editor} editor
+ // @returns {Function}
+ function centerWrapperChecker( editor ) {
+ var captionedClass = editor.config.image2_captionedClass,
+ alignClasses = editor.config.image2_alignClasses,
+ validChildren = { figure: 1, a: 1, img: 1 };
+
+ return function( el ) {
+ // Wrapper must be either
or
.
+ if ( !( el.name in { div: 1, p: 1 } ) )
+ return false;
+
+ var children = el.children;
+
+ // Centering wrapper can have only one child.
+ if ( children.length !== 1 )
+ return false;
+
+ var child = children[ 0 ];
+
+ // Only or can be first (only) child of centering wrapper,
+ // regardless of its type.
+ if ( !( child.name in validChildren ) )
+ return false;
+
+ // If centering wrapper is
can hold or only when enterMode
+ // is ENTER_(BR|DIV).
+ //
+ //
+ if ( editor.enterMode == CKEDITOR.ENTER_P )
+ return false;
+
+ // Regardless of enterMode, a child which is not must be
+ // either or .
+ if ( !isLinkedOrStandaloneImage( child ) )
+ return false;
+ }
+ }
+
+ // Centering wrapper got to be... centering. If image2_alignClasses are defined,
+ // check for centering class. Otherwise, check the style.
+ if ( alignClasses ? el.hasClass( alignClasses[ 1 ] ) :
+ CKEDITOR.tools.parseCssText( el.attributes.style || '', true )[ 'text-align' ] == 'center' )
+ return true;
+
+ return false;
+ };
+ }
+
+ // Checks whether element is or .
+ //
+ // @param {CKEDITOR.htmlParser.element}
+ function isLinkedOrStandaloneImage( el ) {
+ if ( el.name == 'img' )
+ return true;
+ else if ( el.name == 'a' )
+ return el.children.length == 1 && el.getFirst( 'img' );
+
+ return false;
+ }
+
+ // Sets width and height of the widget image according to current widget data.
+ //
+ // @param {CKEDITOR.plugins.widget} widget
+ function setDimensions( widget ) {
+ var data = widget.data,
+ dimensions = { width: data.width, height: data.height },
+ image = widget.parts.image;
+
+ for ( var d in dimensions ) {
+ if ( dimensions[ d ] )
+ image.setAttribute( d, dimensions[ d ] );
+ else
+ image.removeAttribute( d );
+ }
+ }
+
+ // Defines all features related to drag-driven image resizing.
+ //
+ // @param {CKEDITOR.plugins.widget} widget
+ function setupResizer( widget ) {
+ var editor = widget.editor,
+ editable = editor.editable(),
+ doc = editor.document,
+
+ // Store the resizer in a widget for testing (#11004).
+ resizer = widget.resizer = doc.createElement( 'span' );
+
+ resizer.addClass( 'cke_image_resizer' );
+ resizer.setAttribute( 'title', editor.lang.image2.resizer );
+ resizer.append( new CKEDITOR.dom.text( '\u200b', doc ) );
+
+ // Inline widgets don't need a resizer wrapper as an image spans the entire widget.
+ if ( !widget.inline ) {
+ var imageOrLink = widget.parts.link || widget.parts.image,
+ oldResizeWrapper = imageOrLink.getParent(),
+ resizeWrapper = doc.createElement( 'span' );
+
+ resizeWrapper.addClass( 'cke_image_resizer_wrapper' );
+ resizeWrapper.append( imageOrLink );
+ resizeWrapper.append( resizer );
+ widget.element.append( resizeWrapper, true );
+
+ // Remove the old wrapper which could came from e.g. pasted HTML
+ // and which could be corrupted (e.g. resizer span has been lost).
+ if ( oldResizeWrapper.is( 'span' ) )
+ oldResizeWrapper.remove();
+ } else
+ widget.wrapper.append( resizer );
+
+ // Calculate values of size variables and mouse offsets.
+ resizer.on( 'mousedown', function( evt ) {
+ var image = widget.parts.image,
+
+ // "factor" can be either 1 or -1. I.e.: For right-aligned images, we need to
+ // subtract the difference to get proper width, etc. Without "factor",
+ // resizer starts working the opposite way.
+ factor = widget.data.align == 'right' ? -1 : 1,
+
+ // The x-coordinate of the mouse relative to the screen
+ // when button gets pressed.
+ startX = evt.data.$.screenX,
+ startY = evt.data.$.screenY,
+
+ // The initial dimensions and aspect ratio of the image.
+ startWidth = image.$.clientWidth,
+ startHeight = image.$.clientHeight,
+ ratio = startWidth / startHeight,
+
+ listeners = [],
+
+ // A class applied to editable during resizing.
+ cursorClass = 'cke_image_s' + ( !~factor ? 'w' : 'e' ),
+
+ nativeEvt, newWidth, newHeight, updateData,
+ moveDiffX, moveDiffY, moveRatio;
+
+ // Save the undo snapshot first: before resizing.
+ editor.fire( 'saveSnapshot' );
+
+ // Mousemove listeners are removed on mouseup.
+ attachToDocuments( 'mousemove', onMouseMove, listeners );
+
+ // Clean up the mousemove listener. Update widget data if valid.
+ attachToDocuments( 'mouseup', onMouseUp, listeners );
+
+ // The entire editable will have the special cursor while resizing goes on.
+ editable.addClass( cursorClass );
+
+ // This is to always keep the resizer element visible while resizing.
+ resizer.addClass( 'cke_image_resizing' );
+
+ // Attaches an event to a global document if inline editor.
+ // Additionally, if classic (`iframe`-based) editor, also attaches the same event to `iframe`'s document.
+ function attachToDocuments( name, callback, collection ) {
+ var globalDoc = CKEDITOR.document,
+ listeners = [];
+
+ if ( !doc.equals( globalDoc ) )
+ listeners.push( globalDoc.on( name, callback ) );
+
+ listeners.push( doc.on( name, callback ) );
+
+ if ( collection ) {
+ for ( var i = listeners.length; i--; )
+ collection.push( listeners.pop() );
+ }
+ }
+
+ // Calculate with first, and then adjust height, preserving ratio.
+ function adjustToX() {
+ newWidth = startWidth + factor * moveDiffX;
+ newHeight = Math.round( newWidth / ratio );
+ }
+
+ // Calculate height first, and then adjust width, preserving ratio.
+ function adjustToY() {
+ newHeight = startHeight - moveDiffY;
+ newWidth = Math.round( newHeight * ratio );
+ }
+
+ // This is how variables refer to the geometry.
+ // Note: x corresponds to moveOffset, this is the position of mouse
+ // Note: o corresponds to [startX, startY].
+ //
+ // +--------------+--------------+
+ // | | |
+ // | I | II |
+ // | | |
+ // +------------- o -------------+ _ _ _
+ // | | | ^
+ // | VI | III | | moveDiffY
+ // | | x _ _ _ _ _ v
+ // +--------------+---------|----+
+ // | |
+ // <------->
+ // moveDiffX
+ function onMouseMove( evt ) {
+ nativeEvt = evt.data.$;
+
+ // This is how far the mouse is from the point the button was pressed.
+ moveDiffX = nativeEvt.screenX - startX;
+ moveDiffY = startY - nativeEvt.screenY;
+
+ // This is the aspect ratio of the move difference.
+ moveRatio = Math.abs( moveDiffX / moveDiffY );
+
+ // Left, center or none-aligned widget.
+ if ( factor == 1 ) {
+ if ( moveDiffX <= 0 ) {
+ // Case: IV.
+ if ( moveDiffY <= 0 )
+ adjustToX();
+
+ // Case: I.
+ else {
+ if ( moveRatio >= ratio )
+ adjustToX();
+ else
+ adjustToY();
+ }
+ } else {
+ // Case: III.
+ if ( moveDiffY <= 0 ) {
+ if ( moveRatio >= ratio )
+ adjustToY();
+ else
+ adjustToX();
+ }
+
+ // Case: II.
+ else
+ adjustToY();
+ }
+ }
+
+ // Right-aligned widget. It mirrors behaviours, so I becomes II,
+ // IV becomes III and vice-versa.
+ else {
+ if ( moveDiffX <= 0 ) {
+ // Case: IV.
+ if ( moveDiffY <= 0 ) {
+ if ( moveRatio >= ratio )
+ adjustToY();
+ else
+ adjustToX();
+ }
+
+ // Case: I.
+ else
+ adjustToY();
+ } else {
+ // Case: III.
+ if ( moveDiffY <= 0 )
+ adjustToX();
+
+ // Case: II.
+ else {
+ if ( moveRatio >= ratio )
+ adjustToX();
+ else
+ adjustToY();
+ }
+ }
+ }
+
+ // Don't update attributes if less than 10.
+ // This is to prevent images to visually disappear.
+ if ( newWidth >= 15 && newHeight >= 15 ) {
+ image.setAttributes( { width: newWidth, height: newHeight } );
+ updateData = true;
+ } else
+ updateData = false;
+ }
+
+ function onMouseUp( evt ) {
+ var l;
+
+ while ( ( l = listeners.pop() ) )
+ l.removeListener();
+
+ // Restore default cursor by removing special class.
+ editable.removeClass( cursorClass );
+
+ // This is to bring back the regular behaviour of the resizer.
+ resizer.removeClass( 'cke_image_resizing' );
+
+ if ( updateData ) {
+ widget.setData( { width: newWidth, height: newHeight } );
+
+ // Save another undo snapshot: after resizing.
+ editor.fire( 'saveSnapshot' );
+ }
+
+ // Don't update data twice or more.
+ updateData = false;
+ }
+ } );
+
+ // Change the position of the widget resizer when data changes.
+ widget.on( 'data', function() {
+ resizer[ widget.data.align == 'right' ? 'addClass' : 'removeClass' ]( 'cke_image_resizer_left' );
+ } );
+ }
+
+ // Integrates widget alignment setting with justify
+ // plugin's commands (execution and refreshment).
+ // @param {CKEDITOR.editor} editor
+ // @param {String} value 'left', 'right', 'center' or 'block'
+ function alignCommandIntegrator( editor ) {
+ var execCallbacks = [],
+ enabled;
+
+ return function( value ) {
+ var command = editor.getCommand( 'justify' + value );
+
+ // Most likely, the justify plugin isn't loaded.
+ if ( !command )
+ return;
+
+ // This command will be manually refreshed along with
+ // other commands after exec.
+ execCallbacks.push( function() {
+ command.refresh( editor, editor.elementPath() );
+ } );
+
+ if ( value in { right: 1, left: 1, center: 1 } ) {
+ command.on( 'exec', function( evt ) {
+ var widget = getFocusedWidget( editor );
+
+ if ( widget ) {
+ widget.setData( 'align', value );
+
+ // Once the widget changed its align, all the align commands
+ // must be refreshed: the event is to be cancelled.
+ for ( var i = execCallbacks.length; i--; )
+ execCallbacks[ i ]();
+
+ evt.cancel();
+ }
+ } );
+ }
+
+ command.on( 'refresh', function( evt ) {
+ var widget = getFocusedWidget( editor ),
+ allowed = { right: 1, left: 1, center: 1 };
+
+ if ( !widget )
+ return;
+
+ // Cache "enabled" on first use. This is because filter#checkFeature may
+ // not be available during plugin's afterInit in the future — a moment when
+ // alignCommandIntegrator is called.
+ if ( enabled == undefined )
+ enabled = editor.filter.checkFeature( editor.widgets.registered.image.features.align );
+
+ // Don't allow justify commands when widget alignment is disabled (#11004).
+ if ( !enabled )
+ this.setState( CKEDITOR.TRISTATE_DISABLED );
+ else {
+ this.setState(
+ ( widget.data.align == value ) ?
+ CKEDITOR.TRISTATE_ON
+ :
+ ( value in allowed ) ?
+ CKEDITOR.TRISTATE_OFF
+ :
+ CKEDITOR.TRISTATE_DISABLED );
+ }
+
+ evt.cancel();
+ } );
+ };
+ }
+
+ function linkCommandIntegrator( editor ) {
+ // Nothing to integrate with if link is not loaded.
+ if ( !editor.plugins.link )
+ return;
+
+ CKEDITOR.on( 'dialogDefinition', function( evt ) {
+ var dialog = evt.data;
+
+ if ( dialog.name == 'link' ) {
+ var def = dialog.definition;
+
+ var onShow = def.onShow,
+ onOk = def.onOk;
+
+ def.onShow = function() {
+ var widget = getFocusedWidget( editor );
+
+ // Widget cannot be enclosed in a link, i.e.
+ // foobar
+ if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) )
+ this.setupContent( widget.data.link || {} );
+ else
+ onShow.apply( this, arguments );
+ };
+
+ // Set widget data if linking the widget using
+ // link dialog (instead of default action).
+ // State shifter handles data change and takes
+ // care of internal DOM structure of linked widget.
+ def.onOk = function() {
+ var widget = getFocusedWidget( editor );
+
+ // Widget cannot be enclosed in a link, i.e.
+ // foobar
+ if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) ) {
+ var data = {};
+
+ // Collect data from fields.
+ this.commitContent( data );
+
+ // Set collected data to widget.
+ widget.setData( 'link', data );
+ } else
+ onOk.apply( this, arguments );
+ };
+ }
+ } );
+
+ // Overwrite default behaviour of unlink command.
+ editor.getCommand( 'unlink' ).on( 'exec', function( evt ) {
+ var widget = getFocusedWidget( editor );
+
+ // Override unlink only when link truly belongs to the widget.
+ // If wrapped inline widget in a link, let default unlink work (#11814).
+ if ( !widget || !widget.parts.link )
+ return;
+
+ widget.setData( 'link', null );
+
+ // Selection (which is fake) may not change if unlinked image in focused widget,
+ // i.e. if captioned image. Let's refresh command state manually here.
+ this.refresh( editor, editor.elementPath() );
+
+ evt.cancel();
+ } );
+
+ // Overwrite default refresh of unlink command.
+ editor.getCommand( 'unlink' ).on( 'refresh', function( evt ) {
+ var widget = getFocusedWidget( editor );
+
+ if ( !widget )
+ return;
+
+ // Note that widget may be wrapped in a link, which
+ // does not belong to that widget (#11814).
+ this.setState( widget.data.link || widget.wrapper.getAscendant( 'a' ) ?
+ CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
+
+ evt.cancel();
+ } );
+ }
+
+ // Returns the focused widget, if of the type specific for this plugin.
+ // If no widget is focused, `null` is returned.
+ //
+ // @param {CKEDITOR.editor}
+ // @returns {CKEDITOR.plugins.widget}
+ function getFocusedWidget( editor ) {
+ var widget = editor.widgets.focused;
+
+ if ( widget && widget.name == 'image' )
+ return widget;
+
+ return null;
+ }
+
+ // Returns a set of widget allowedContent rules, depending
+ // on configurations like config#image2_alignClasses or
+ // config#image2_captionedClass.
+ //
+ // @param {CKEDITOR.editor}
+ // @returns {Object}
+ function getWidgetAllowedContent( editor ) {
+ var alignClasses = editor.config.image2_alignClasses,
+ rules = {
+ // Widget may need
or
centering wrapper.
+ div: {
+ match: centerWrapperChecker( editor )
+ },
+ p: {
+ match: centerWrapperChecker( editor )
+ },
+ img: {
+ attributes: '!src,alt,width,height'
+ },
+ figure: {
+ classes: '!' + editor.config.image2_captionedClass
+ },
+ figcaption: true
+ };
+
+ if ( alignClasses ) {
+ // Centering class from the config.
+ rules.div.classes = alignClasses[ 1 ];
+ rules.p.classes = rules.div.classes;
+
+ // Left/right classes from the config.
+ rules.img.classes = alignClasses[ 0 ] + ',' + alignClasses[ 2 ];
+ rules.figure.classes += ',' + rules.img.classes;
+ } else {
+ // Centering with text-align.
+ rules.div.styles = 'text-align';
+ rules.p.styles = 'text-align';
+
+ rules.img.styles = 'float';
+ rules.figure.styles = 'float,display';
+ }
+
+ return rules;
+ }
+
+ // Returns a set of widget feature rules, depending
+ // on editor configuration. Note that the following may not cover
+ // all the possible cases since requiredContent supports a single
+ // tag only.
+ //
+ // @param {CKEDITOR.editor}
+ // @returns {Object}
+ function getWidgetFeatures( editor ) {
+ var alignClasses = editor.config.image2_alignClasses,
+ features = {
+ dimension: {
+ requiredContent: 'img[width,height]'
+ },
+ align: {
+ requiredContent: 'img' +
+ ( alignClasses ? '(' + alignClasses[ 0 ] + ')' : '{float}' )
+ },
+ caption: {
+ requiredContent: 'figcaption'
+ }
+ };
+
+ return features;
+ }
+
+ // Returns element which is styled, considering current
+ // state of the widget.
+ //
+ // @see CKEDITOR.plugins.widget#applyStyle
+ // @param {CKEDITOR.plugins.widget} widget
+ // @returns {CKEDITOR.dom.element}
+ function getStyleableElement( widget ) {
+ return widget.data.hasCaption ? widget.element : widget.parts.image;
+ }
+} )();
+
+/**
+ * A CSS class applied to the `` element of a captioned image.
+ *
+ * // Changes the class to "captionedImage".
+ * CKEDITOR.config.image2_captionedClass = 'captionedImage';
+ *
+ * @cfg {String} [image2_captionedClass='image']
+ * @member CKEDITOR.config
+ */
+CKEDITOR.config.image2_captionedClass = 'image';
+
+/**
+ * CSS classes applied to aligned images. Useful to take control over the way
+ * the images are aligned, i.e. to customize output HTML and integrate external stylesheets.
+ *
+ * Classes should be defined in an array of three elements, containing left, center, and right
+ * alignment classes, respectively. For example:
+ *
+ * config.image2_alignClasses = [ 'align-left', 'align-center', 'align-right' ];
+ *
+ * **Note**: Once this configuration option is set, the plugin will no longer produce inline
+ * styles for alignment. It means that e.g. the following HTML will be produced:
+ *
+ *
+ *
+ * instead of:
+ *
+ *
+ *
+ * **Note**: Once this configuration option is set, corresponding style definitions
+ * must be supplied to the editor:
+ *
+ * * For [classic editor](#!/guide/dev_framed) it can be done by defining additional
+ * styles in the {@link CKEDITOR.config#contentsCss stylesheets loaded by the editor}. The same
+ * styles must be provided on the target page where the content will be loaded.
+ * * For [inline editor](#!/guide/dev_inline) the styles can be defined directly
+ * with `