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 , only can be the child.
- //
- if ( el.name == 'p' ) {
- if ( !isLinkedOrStandaloneImage( child ) )
- return false;
- }
- // Centering can hold
or
, depending on enterMode.
- else {
- // If a is the first (only) child, it must have a class.
- // ...
- if ( child.name == 'figure' ) {
- if ( !child.hasClass( captionedClass ) )
- return false;
- } else {
- // Centering
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 (http://dev.ckeditor.com/ticket/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() {
- 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 (http://dev.ckeditor.com/ticket/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 ),
- displayTextField = this.getContentElement( 'info', 'linkDisplayText' ).getElement().getParent().getParent();
-
- // Widget cannot be enclosed in a link, i.e.
- // foo bar
- if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) ) {
- this.setupContent( widget.data.link || {} );
-
- // Hide the display text in case of linking image2 widget.
- displayTextField.hide();
- } else {
- // Make sure that display text is visible, as it might be hidden by image2 integration
- // before.
- displayTextField.show();
- 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.
- // foo bar
- 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 (http://dev.ckeditor.com/ticket/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 (http://dev.ckeditor.com/ticket/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.
- *
- * Read more in the [documentation](#!/guide/dev_captionedimage) and see the
- * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html).
- *
- * // Changes the class to "captionedImage".
- * config.image2_captionedClass = 'captionedImage';
- *
- * @cfg {String} [image2_captionedClass='image']
- * @member CKEDITOR.config
- */
-CKEDITOR.config.image2_captionedClass = 'image';
-
-/**
- * Determines whether dimension inputs should be automatically filled when the image URL changes in the Enhanced Image
- * plugin dialog window.
- *
- * Read more in the [documentation](#!/guide/dev_captionedimage) and see the
- * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html).
- *
- * config.image2_prefillDimensions = false;
- *
- * @since 4.5
- * @cfg {Boolean} [image2_prefillDimensions=true]
- * @member CKEDITOR.config
- */
-
-/**
- * Disables the image resizer. By default the resizer is enabled.
- *
- * Read more in the [documentation](#!/guide/dev_captionedimage) and see the
- * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html).
- *
- * config.image2_disableResizer = true;
- *
- * @since 4.5
- * @cfg {Boolean} [image2_disableResizer=false]
- * @member CKEDITOR.config
- */
-
-/**
- * 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 `