Index: lams_central/web/ckeditor/plugins/image2/dialogs/image2.js =================================================================== diff -u --- lams_central/web/ckeditor/plugins/image2/dialogs/image2.js (revision 0) +++ lams_central/web/ckeditor/plugins/image2/dialogs/image2.js (revision 2b9f93362e5be1cb3a8718e7f8f26bda31bd4a60) @@ -0,0 +1,553 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or http://ckeditor.com/license + */ + +/** + * @fileOverview Image plugin based on Widgets API + */ + +'use strict'; + +CKEDITOR.dialog.add( 'image2', function( editor ) { + + // RegExp: 123, 123px, empty string "" + var regexGetSizeOrEmpty = /(^\s*(\d+)(px)?\s*$)|^$/i, + + lockButtonId = CKEDITOR.tools.getNextId(), + resetButtonId = CKEDITOR.tools.getNextId(), + + lang = editor.lang.image2, + commonLang = editor.lang.common, + + lockResetStyle = 'margin-top:18px;width:40px;height:20px;', + lockResetHtml = new CKEDITOR.template( + '
│ + // │ │
│ │
+ // │ │
│
│ + // │ │
│ │
+ // │ │
│
remains for styling purposes. + // + // 3.
.
+ 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 , only 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 ` can be first (only) child of centering wrapper,
+ // regardless of its type.
+ if ( !( child.name in validChildren ) )
+ return false;
+
+ // If centering wrapper is
can be the child.
+ //
or
or
only when enterMode
+ // is ENTER_(BR|DIV).
+ //
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
+ *
+ * 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 `