From 7dae709bf0c1c678dc4054a97753c75bc6295871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 5 Mar 2018 17:18:33 +0100 Subject: [PATCH 1/6] Other: Renamed 'headings' ui component to 'heading'. --- tests/manual/caption.js | 2 +- tests/manual/image.js | 2 +- tests/manual/imagestyle.js | 4 ++-- tests/manual/imageupload.js | 2 +- tests/manual/textalternative.js | 2 +- tests/manual/tickets/110/1.js | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/manual/caption.js b/tests/manual/caption.js index 42683338..ae784888 100644 --- a/tests/manual/caption.js +++ b/tests/manual/caption.js @@ -26,7 +26,7 @@ ClassicEditor Enter, Typing, Paragraph, Heading, Image, ImageToolbar, Undo, Clipboard, ImageCaption, ImageStyle, Bold, Italic, Heading, List ], - toolbar: [ 'headings', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList' ], + toolbar: [ 'heading', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList' ], image: { toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ] } diff --git a/tests/manual/image.js b/tests/manual/image.js index f818b350..2d0a006b 100644 --- a/tests/manual/image.js +++ b/tests/manual/image.js @@ -17,7 +17,7 @@ import ClipboardPlugin from '@ckeditor/ckeditor5-clipboard/src/clipboard'; ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ EnterPlugin, TypingPlugin, ParagraphPlugin, HeadingPlugin, ImagePlugin, UndoPlugin, ClipboardPlugin ], - toolbar: [ 'headings', '|', 'undo', 'redo' ] + toolbar: [ 'heading', '|', 'undo', 'redo' ] } ) .then( editor => { window.editor = editor; diff --git a/tests/manual/imagestyle.js b/tests/manual/imagestyle.js index 64a67317..8e86dcc0 100644 --- a/tests/manual/imagestyle.js +++ b/tests/manual/imagestyle.js @@ -29,7 +29,7 @@ ClassicEditor ClipboardPlugin, ImageStyle ], - toolbar: [ 'headings', '|', 'undo', 'redo' ], + toolbar: [ 'heading', '|', 'undo', 'redo' ], image: { toolbar: [ 'imageStyleFull', 'imageStyleSide' ] } @@ -54,7 +54,7 @@ ClassicEditor ClipboardPlugin, ImageStyle ], - toolbar: [ 'headings', '|', 'undo', 'redo' ], + toolbar: [ 'heading', '|', 'undo', 'redo' ], image: { styles: [ 'imageStyleAlignLeft', 'imageStyleAlignCenter', 'imageStyleAlignRight' ], toolbar: [ 'imageStyleAlignLeft', 'imageStyleAlignCenter', 'imageStyleAlignRight' ] diff --git a/tests/manual/imageupload.js b/tests/manual/imageupload.js index 59706564..1ce25ce3 100644 --- a/tests/manual/imageupload.js +++ b/tests/manual/imageupload.js @@ -30,7 +30,7 @@ ClassicEditor Enter, Typing, Paragraph, Heading, Undo, Bold, Italic, Heading, List, Image, ImageToolbar, Clipboard, ImageCaption, ImageStyle, ImageUpload ], - toolbar: [ 'headings', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList', 'uploadImage' ], + toolbar: [ 'heading', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList', 'uploadImage' ], image: { toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ] } diff --git a/tests/manual/textalternative.js b/tests/manual/textalternative.js index 7c460fff..061ed8cb 100644 --- a/tests/manual/textalternative.js +++ b/tests/manual/textalternative.js @@ -18,7 +18,7 @@ import ImageToolbar from '../../src/imagetoolbar'; ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ EnterPlugin, TypingPlugin, ParagraphPlugin, HeadingPlugin, ImagePlugin, UndoPlugin, ClipboardPlugin, ImageToolbar ], - toolbar: [ 'headings', '|', 'undo', 'redo' ], + toolbar: [ 'heading', '|', 'undo', 'redo' ], image: { toolbar: [ 'imageTextAlternative' ] } diff --git a/tests/manual/tickets/110/1.js b/tests/manual/tickets/110/1.js index 7f297dc1..1e2ce18c 100644 --- a/tests/manual/tickets/110/1.js +++ b/tests/manual/tickets/110/1.js @@ -18,7 +18,7 @@ import ImageToolbar from '../../../../src/imagetoolbar'; ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ EnterPlugin, TypingPlugin, ParagraphPlugin, HeadingPlugin, ImagePlugin, UndoPlugin, ImageToolbar, BalloonToolbar ], - balloonToolbar: [ 'headings', '|', 'undo', 'redo' ], + balloonToolbar: [ 'heading', '|', 'undo', 'redo' ], image: { toolbar: [ 'imageTextAlternative' ] } From ab412a57da3c0643ad25e8b6e91694f0003ce7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Wed, 7 Mar 2018 17:09:44 +0100 Subject: [PATCH 2/6] Other: Rename ImageStyle options, UI components and merge commands into one command. --- docs/_snippets/features/image-style-custom.js | 8 +-- docs/features/image.md | 26 ++++----- src/imagestyle.js | 10 ++-- src/imagestyle/imagestylecommand.js | 46 +++++++++------ src/imagestyle/imagestyleediting.js | 8 +-- src/imagestyle/imagestyleui.js | 10 ++-- src/imagestyle/utils.js | 38 ++++++------ src/imagetoolbar.js | 4 +- tests/imagestyle/imagestylecommand.js | 58 ++++++++++--------- tests/imagestyle/imagestyleediting.js | 18 +++--- tests/imagestyle/imagestyleui.js | 9 +-- tests/imagestyle/utils.js | 24 ++++---- tests/manual/caption.js | 2 +- tests/manual/imagestyle.js | 6 +- tests/manual/imageupload.js | 2 +- 15 files changed, 144 insertions(+), 125 deletions(-) diff --git a/docs/_snippets/features/image-style-custom.js b/docs/_snippets/features/image-style-custom.js index 5e3d6aa9..9b1137f3 100644 --- a/docs/_snippets/features/image-style-custom.js +++ b/docs/_snippets/features/image-style-custom.js @@ -12,16 +12,16 @@ ClassicEditor image: { styles: [ // This option is equal to a situation where no style is applied. - 'imageStyleFull', + 'imageStyle:full', // This represents an image aligned to left. - 'imageStyleAlignLeft', + 'imageStyle:alignLeft', // This represents an image aligned to right. - 'imageStyleAlignRight' + 'imageStyle:alignRight' ], - toolbar: [ 'imageTextAlternative', '|', 'imageStyleAlignLeft', 'imageStyleFull', 'imageStyleAlignRight' ] + toolbar: [ 'imageTextAlternative', '|', 'imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:alignRight' ] }, toolbar: { viewportTopOffset: 60 diff --git a/docs/features/image.md b/docs/features/image.md index cf15b5e1..0dcc6cd3 100644 --- a/docs/features/image.md +++ b/docs/features/image.md @@ -118,17 +118,17 @@ ClassicEditor .create( document.querySelector( '#editor' ), { image: { // You need to configure the image toolbar too, so it uses the new style buttons. - toolbar: [ 'imageTextAlternative', '|', 'imageStyleAlignLeft', 'imageStyleFull', 'imageStyleAlignRight' ], + toolbar: [ 'imageTextAlternative', '|', 'imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:alignRight' ], styles: [ // This option is equal to a situation where no style is applied. - 'imageStyleFull', + 'imageStyle:full', // This represents an image aligned to left. - 'imageStyleAlignLeft', + 'imageStyle:alignLeft', // This represents an image aligned to right. - 'imageStyleAlignRight' + 'imageStyle:alignRight' ] } } ) @@ -136,7 +136,7 @@ ClassicEditor .catch( ... ); ``` -In the code sample above we used predefined image styles – `'imageStyleFull'`, `'imageStyleAlignLeft'` and `'imageStyleAlignRight'`. The latter two apply, respectively, `.image-style-align-left` and `.image-style-align-right` classes to the `
` element. +In the code sample above we used predefined image styles – `'imageStyle:full'`, `'imageStyle:alignLeft'` and `'imageStyle:alignRight'`. The latter two apply, respectively, `.image-style-align-left` and `.image-style-align-right` classes to the `
` element. See the result below: @@ -150,11 +150,11 @@ See the result below: Besides using the {@link module:image/imagestyle/utils~defaultStyles 5 predefined styles}: -* `'imageStyleFull'`, -* `'imageStyleSide'`, -* `'imageStyleAlignLeft'`, -* `'imageStyleAlignCenter'`, -* `'imageStyleAlignRight'` +* `'full'`, +* `'side'`, +* `'alignLeft'`, +* `'alignCenter'`, +* `'alignRight'` you can also define your own styles or modify the existing ones. @@ -194,7 +194,7 @@ ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ Image, ImageToolbar, ImageCaption, ImageStyle ], image: { - toolbar: [ 'imageTextAlternative', '|', 'imageStyleFull', 'imageStyleSide' ] + toolbar: [ 'imageTextAlternative', '|', 'imageStyle:full', 'imageStyle:side' ] } } ) .then( ... ) @@ -211,8 +211,8 @@ The {@link module:image/image~Image} plugin registers: The {@link module:image/imagestyle~ImageStyle} plugin registers: -* A command for each defined style (based on the {@link module:image/image~ImageConfig#styles `image.styles`} configuration option) — e.g. `'imageStyleFull'` and `'imageStyleSide'`, -* A button for each defined style — e.g. `'imageStyleFull'` and `'imageStyleSide'`. +* A command for each defined style (based on the {@link module:image/image~ImageConfig#styles `image.styles`} configuration option) — e.g. `'imageStyle:full'` and `'imageStyle:side'`, +* A button for each defined style — e.g. `'imageStyle:full'` and `'imageStyle:side'`. ## Contribute diff --git a/src/imagestyle.js b/src/imagestyle.js index 43d4dd5a..1d6a1554 100644 --- a/src/imagestyle.js +++ b/src/imagestyle.js @@ -42,7 +42,7 @@ export default class ImageStyle extends Plugin { * The default value is: * * const imageConfig = { - * styles: [ 'imageStyleFull', 'imageStyleSide' ] + * styles: [ 'imageStyle:full', 'imageStyle:side' ] * }; * * which configures two default styles: @@ -65,10 +65,10 @@ export default class ImageStyle extends Plugin { * styles: [ * // This will only customize the icon of the "full" style. * // Note: 'right' is one of default icons provided by the feature. - * { name: 'imageStyleFull', icon: 'right' }, + * { name: 'full', icon: 'right' }, * * // This will customize the icon, title and CSS class of the default "side" style. - * { name: 'imageStyleSide', icon: customIcon, title: 'My side style', class: 'custom-side-image' } + * { name: 'side', icon: customIcon, title: 'My side style', class: 'custom-side-image' } * ] * }; * @@ -96,14 +96,14 @@ export default class ImageStyle extends Plugin { * The feature creates commands based on defined styles, so you can change the style of a selected image by executing * the following command: * - * editor.execute( 'imageStyleSide' ); + * editor.execute( 'imageStyle:side' ); * * The features creates also buttons which execute the commands, so assuming that you use the * default image styles setting you can {@link module:image/image~ImageConfig#toolbar configure the image toolbar} * to contain these options: * * const imageConfig = { - * toolbar: [ 'imageStyleFull', 'imageStyleSide' ] + * toolbar: [ 'imageStyle:full', 'imageStyle:side' ] * }; * * @member {Array.} module:image/image~ImageConfig#styles diff --git a/src/imagestyle/imagestylecommand.js b/src/imagestyle/imagestylecommand.js index f24ef05c..ebdebc13 100644 --- a/src/imagestyle/imagestylecommand.js +++ b/src/imagestyle/imagestylecommand.js @@ -20,27 +20,34 @@ export default class ImageStyleCommand extends Command { * Creates an instance of the image style command. Each command instance is handling one style. * * @param {module:core/editor/editor~Editor} editor The editor instance. - * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style A style to be applied by this command. + * @param {Array.} styles A styles that this command supports. */ - constructor( editor, style ) { + constructor( editor, styles ) { super( editor ); /** - * The value of the command — `true` if a style handled by the command is applied on a currently selected image, - * `false` otherwise. + * A style handled by this command. * * @readonly - * @observable - * @member {Boolean} #value + * @member {Array.} #styles */ + this.styles = styles.reduce( ( styles, style ) => { + styles[ style.name ] = style; + + if ( style.isDefault ) { + this._defaultStyle = style.name; + } + + return styles; + }, {} ); /** - * A style handled by this command. + * Cached name of a default style if present. If there is no default style it defaults to false. * - * @readonly - * @member {module:image/imagestyle/imagestyleediting~ImageStyleFormat} #style + * @type {Boolean|String} + * @private */ - this.style = style; + this._defaultStyle = false; } /** @@ -53,20 +60,25 @@ export default class ImageStyleCommand extends Command { if ( !element ) { this.value = false; - } else if ( this.style.isDefault ) { - this.value = !element.hasAttribute( 'imageStyle' ); + } else if ( element.hasAttribute( 'imageStyle' ) ) { + const attributeValue = element.getAttribute( 'imageStyle' ); + this.value = this.styles[ attributeValue ] ? attributeValue : false; } else { - this.value = ( element.getAttribute( 'imageStyle' ) == this.style.name ); + this.value = this._defaultStyle; } } /** * Executes the command. * + * @param {Object} options + * @param {String} options.value * @fires execute */ - execute() { - if ( this.value ) { + execute( options = {} ) { + const styleName = options.value; + + if ( !this.styles[ styleName ] ) { return; } @@ -76,10 +88,10 @@ export default class ImageStyleCommand extends Command { model.change( writer => { // Default style means that there is no `imageStyle` attribute in the model. // https://github.com/ckeditor/ckeditor5-image/issues/147 - if ( this.style.isDefault ) { + if ( this.styles[ styleName ].isDefault ) { writer.removeAttribute( 'imageStyle', imageElement ); } else { - writer.setAttribute( 'imageStyle', this.style.name, imageElement ); + writer.setAttribute( 'imageStyle', styleName, imageElement ); } } ); } diff --git a/src/imagestyle/imagestyleediting.js b/src/imagestyle/imagestyleediting.js index a12a7af9..bf8713fc 100644 --- a/src/imagestyle/imagestyleediting.js +++ b/src/imagestyle/imagestyleediting.js @@ -44,7 +44,7 @@ export default class ImageStyleEditing extends Plugin { const editing = editor.editing; // Define default configuration. - editor.config.define( 'image.styles', [ 'imageStyleFull', 'imageStyleSide' ] ); + editor.config.define( 'image.styles', [ 'imageStyle:full', 'imageStyle:side' ] ); // Get configuration. const styles = normalizeImageStyles( editor.config.get( 'image.styles' ) ); @@ -61,10 +61,8 @@ export default class ImageStyleEditing extends Plugin { // Converter for figure element from view to model. data.upcastDispatcher.on( 'element:figure', viewToModelStyleAttribute( styles ), { priority: 'low' } ); - // Register separate command for each style. - for ( const style of styles ) { - editor.commands.add( style.name, new ImageStyleCommand( editor, style ) ); - } + // Register imageStyle command. + editor.commands.add( 'imageStyle', new ImageStyleCommand( editor, styles ) ); } } diff --git a/src/imagestyle/imagestyleui.js b/src/imagestyle/imagestyleui.js index f4ec6a94..2c393772 100644 --- a/src/imagestyle/imagestyleui.js +++ b/src/imagestyle/imagestyleui.js @@ -69,8 +69,10 @@ export default class ImageStyleUI extends Plugin { _createButton( style ) { const editor = this.editor; - editor.ui.componentFactory.add( style.name, locale => { - const command = editor.commands.get( style.name ); + const componentName = `imageStyle:${ style.name }`; + + editor.ui.componentFactory.add( componentName, locale => { + const command = editor.commands.get( 'imageStyle' ); const view = new ButtonView( locale ); view.set( { @@ -80,9 +82,9 @@ export default class ImageStyleUI extends Plugin { } ); view.bind( 'isEnabled' ).to( command, 'isEnabled' ); - view.bind( 'isOn' ).to( command, 'value' ); + view.bind( 'isOn' ).to( command, 'value', value => value === style.name ); - this.listenTo( view, 'execute', () => editor.execute( style.name ) ); + this.listenTo( view, 'execute', () => editor.execute( 'imageStyle', { value: style.name } ) ); return view; } ); diff --git a/src/imagestyle/utils.js b/src/imagestyle/utils.js index c3f33e9b..04392bd9 100644 --- a/src/imagestyle/utils.js +++ b/src/imagestyle/utils.js @@ -20,53 +20,53 @@ import rightIcon from '@ckeditor/ckeditor5-core/theme/icons/object-right.svg'; * * Among them, 2 default semantic content styles are available: * - * * `imageStyleFull` is a full–width image without any CSS class, - * * `imageStyleSide` is a side image styled with the `image-style-side` CSS class + * * `full` is a full–width image without any CSS class, + * * `side` is a side image styled with the `image-style-side` CSS class * * There are also 3 styles focused on formatting: * - * * `imageStyleAlignLeft` aligns the image to the left using the `image-style-align-left` class, - * * `imageStyleAlignCenter` centers the image to the left using the `image-style-align-center` class, - * * `imageStyleAlignRight` aligns the image to the right using the `image-style-align-right` class, + * * `alignLeft` aligns the image to the left using the `image-style-align-left` class, + * * `alignCenter` centers the image to the left using the `image-style-align-center` class, + * * `alignRight` aligns the image to the right using the `image-style-align-right` class, * * @member {Object.} */ const defaultStyles = { // This option is equal to situation when no style is applied. - imageStyleFull: { - name: 'imageStyleFull', + full: { + name: 'full', title: 'Full size image', icon: fullWidthIcon, isDefault: true }, // This represents side image. - imageStyleSide: { - name: 'imageStyleSide', + side: { + name: 'side', title: 'Side image', icon: rightIcon, className: 'image-style-side' }, // This style represents an imaged aligned to the left. - imageStyleAlignLeft: { - name: 'imageStyleAlignLeft', + alignLeft: { + name: 'alignLeft', title: 'Left aligned image', icon: leftIcon, className: 'image-style-align-left' }, // This style represents a centered imaged. - imageStyleAlignCenter: { - name: 'imageStyleAlignCenter', + alignCenter: { + name: 'alignCenter', title: 'Centered image', icon: centerIcon, className: 'image-style-align-center' }, // This style represents an imaged aligned to the right. - imageStyleAlignRight: { - name: 'imageStyleAlignRight', + alignRight: { + name: 'alignRight', title: 'Right aligned image', icon: rightIcon, className: 'image-style-align-right' @@ -110,8 +110,10 @@ function _normalizeStyle( style ) { if ( typeof style == 'string' ) { // If it's one of the defaults, just use it. // Clone the style to avoid overriding defaults. - if ( defaultStyles[ style ] ) { - style = Object.assign( {}, defaultStyles[ style ] ); + const styleName = style.indexOf( 'imageStyle:' ) === 0 ? style.substr( 11 ) : style; + + if ( defaultStyles[ styleName ] ) { + style = Object.assign( {}, defaultStyles[ styleName ] ); } // If it's just a name but none of the defaults, warn because probably it's a mistake. else { @@ -122,7 +124,7 @@ function _normalizeStyle( style ) { // Normalize the style anyway to prevent errors. style = { - name: style + name: styleName }; } } diff --git a/src/imagetoolbar.js b/src/imagetoolbar.js index 1c128f6d..8182101c 100644 --- a/src/imagetoolbar.js +++ b/src/imagetoolbar.js @@ -178,10 +178,10 @@ export default class ImageToolbar extends Plugin { * * {@link module:image/imagetextalternative~ImageTextAlternative}. * * Three toolbar items will be available in {@link module:ui/componentfactory~ComponentFactory}: - * `'imageStyleFull'`, `'imageStyleSide'`, and `'imageTextAlternative'` so you can configure the toolbar like this: + * `'imageStyle:full'`, `'imageStyle:side'`, and `'imageTextAlternative'` so you can configure the toolbar like this: * * const imageConfig = { - * toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ] + * toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ] * }; * * Of course, the same buttons can also be used in the diff --git a/tests/imagestyle/imagestylecommand.js b/tests/imagestyle/imagestylecommand.js index 88a14c7b..c156e4f5 100644 --- a/tests/imagestyle/imagestylecommand.js +++ b/tests/imagestyle/imagestylecommand.js @@ -11,14 +11,13 @@ describe( 'ImageStyleCommand', () => { const defaultStyle = { name: 'defaultStyle', title: 'foo bar', icon: 'icon-1', isDefault: true }; const otherStyle = { name: 'otherStyle', title: 'baz', icon: 'icon-2', className: 'other-class-name' }; - let model, defaultStyleCommand, otherStyleCommand; + let model, command; beforeEach( () => { return ModelTestEditor.create() .then( newEditor => { model = newEditor.model; - defaultStyleCommand = new ImageStyleCommand( newEditor, defaultStyle ); - otherStyleCommand = new ImageStyleCommand( newEditor, otherStyle ); + command = new ImageStyleCommand( newEditor, [ defaultStyle, otherStyle ] ); model.schema.register( 'p', { inheritAllFrom: '$block' } ); @@ -34,35 +33,31 @@ describe( 'ImageStyleCommand', () => { it( 'command value should be false if no image is selected', () => { setData( model, '[]' ); - expect( defaultStyleCommand.value ).to.be.false; - expect( otherStyleCommand.value ).to.be.false; + expect( command.value ).to.be.false; } ); it( 'should match default style if no imageStyle attribute is present', () => { setData( model, '[]' ); - expect( defaultStyleCommand.value ).to.be.true; - expect( otherStyleCommand.value ).to.be.false; + expect( command.value ).to.equal( 'defaultStyle' ); } ); it( 'proper command should have true value when imageStyle attribute is present', () => { setData( model, '[]' ); - expect( defaultStyleCommand.value ).to.be.false; - expect( otherStyleCommand.value ).to.be.true; + expect( command.value ).to.equal( 'otherStyle' ); } ); it( 'should have false value if style does not match', () => { setData( model, '[]' ); - expect( defaultStyleCommand.value ).to.be.false; - expect( otherStyleCommand.value ).to.be.false; + expect( command.value ).to.be.false; } ); it( 'should set proper value when executed', () => { setData( model, '[]' ); - otherStyleCommand.execute(); + command.execute( { value: 'otherStyle' } ); expect( getData( model ) ).to.equal( '[]' ); } ); @@ -70,7 +65,23 @@ describe( 'ImageStyleCommand', () => { it( 'should do nothing when attribute already present', () => { setData( model, '[]' ); - otherStyleCommand.execute(); + command.execute( { value: 'otherStyle' } ); + + expect( getData( model ) ).to.equal( '[]' ); + } ); + + it( 'should do nothing attribute is not known', () => { + setData( model, '[]' ); + + command.execute( { value: 'someNotExistingStyle' } ); + + expect( getData( model ) ).to.equal( '[]' ); + } ); + + it( 'should do nothing when value is not passed', () => { + setData( model, '[]' ); + + command.execute(); expect( getData( model ) ).to.equal( '[]' ); } ); @@ -81,7 +92,7 @@ describe( 'ImageStyleCommand', () => { model.change( writer => { expect( writer.batch.deltas ).to.length( 0 ); - otherStyleCommand.execute(); + command.execute( { value: 'otherStyle' } ); expect( writer.batch.deltas ).to.length.above( 0 ); } ); @@ -90,38 +101,33 @@ describe( 'ImageStyleCommand', () => { it( 'should be enabled on image element', () => { setData( model, '[]' ); - expect( defaultStyleCommand.isEnabled ).to.be.true; - expect( otherStyleCommand.isEnabled ).to.be.true; + expect( command.isEnabled ).to.be.true; } ); it( 'should be disabled when not placed on image', () => { setData( model, '[

]' ); - expect( defaultStyleCommand.isEnabled ).to.be.false; - expect( otherStyleCommand.isEnabled ).to.be.false; + expect( command.isEnabled ).to.be.false; } ); it( 'should be disabled when not placed directly on image', () => { setData( model, '[

]' ); - expect( defaultStyleCommand.isEnabled ).to.be.false; - expect( otherStyleCommand.isEnabled ).to.be.false; + expect( command.isEnabled ).to.be.false; } ); it( 'default style should be active after executing it after another style', () => { setData( model, '[]' ); - expect( defaultStyleCommand.value ).to.be.true; - expect( otherStyleCommand.value ).to.be.false; + expect( command.value ).to.equal( 'defaultStyle' ); - otherStyleCommand.execute(); + command.execute( { value: 'otherStyle' } ); expect( getData( model ) ).to.equal( '[]' ); - defaultStyleCommand.execute(); + command.execute( { value: 'defaultStyle' } ); expect( getData( model ) ).to.equal( '[]' ); - expect( defaultStyleCommand.value ).to.be.true; - expect( otherStyleCommand.value ).to.be.false; + expect( command.value ).to.equal( 'defaultStyle' ); } ); } ); diff --git a/tests/imagestyle/imagestyleediting.js b/tests/imagestyle/imagestyleediting.js index d05ce51e..ae8a95fc 100644 --- a/tests/imagestyle/imagestyleediting.js +++ b/tests/imagestyle/imagestyleediting.js @@ -71,7 +71,7 @@ describe( 'ImageStyleEditing', () => { .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyleFull', 'imageStyleSide' ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyle:full', 'imageStyle:side' ] ); } ); } ); @@ -81,10 +81,8 @@ describe( 'ImageStyleEditing', () => { expect( schema.checkAttribute( [ '$root', 'image' ], 'imageStyle' ) ).to.be.true; } ); - it( 'should register separate command for each style', () => { - expect( editor.commands.get( 'fullStyle' ) ).to.be.instanceOf( ImageStyleCommand ); - expect( editor.commands.get( 'sideStyle' ) ).to.be.instanceOf( ImageStyleCommand ); - expect( editor.commands.get( 'dummyStyle' ) ).to.be.instanceOf( ImageStyleCommand ); + it( 'should register a command', () => { + expect( editor.commands.get( 'imageStyle' ) ).to.be.instanceOf( ImageStyleCommand ); } ); it( 'should convert from view to model', () => { @@ -266,7 +264,7 @@ describe( 'ImageStyleEditing', () => { .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyleFull', 'imageStyleSide' ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyle:full', 'imageStyle:side' ] ); } ); } ); @@ -276,14 +274,14 @@ describe( 'ImageStyleEditing', () => { plugins: [ ImageStyleEditing ], image: { styles: [ - 'imageStyleSide' + 'imageStyle:side' ] } } ) .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyleSide' ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyle:side' ] ); } ); } ); @@ -293,14 +291,14 @@ describe( 'ImageStyleEditing', () => { plugins: [ ImageStyleEditing ], image: { styles: [ - { name: 'imageStyleSide' } + { name: 'imageStyle:side' } ] } } ) .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ { name: 'imageStyleSide' } ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ { name: 'imageStyle:side' } ] ); } ); } ); } ); diff --git a/tests/imagestyle/imagestyleui.js b/tests/imagestyle/imagestyleui.js index b7e35c9a..758067c3 100644 --- a/tests/imagestyle/imagestyleui.js +++ b/tests/imagestyle/imagestyleui.js @@ -43,9 +43,10 @@ describe( 'ImageStyleUI', () => { it( 'should register buttons for each style', () => { const spy = sinon.spy( editor, 'execute' ); + const command = editor.commands.get( 'imageStyle' ); + for ( const style of styles ) { - const command = editor.commands.get( style.name ); - const buttonView = editor.ui.componentFactory.create( style.name ); + const buttonView = editor.ui.componentFactory.create( `imageStyle:${ style.name }` ); expect( buttonView ).to.be.instanceOf( ButtonView ); expect( buttonView.label ).to.equal( style.title ); @@ -57,7 +58,7 @@ describe( 'ImageStyleUI', () => { expect( buttonView.isEnabled ).to.be.false; buttonView.fire( 'execute' ); - sinon.assert.calledWithExactly( editor.execute, style.name ); + sinon.assert.calledWithExactly( editor.execute, 'imageStyle', { value: style.name } ); spy.reset(); } @@ -86,7 +87,7 @@ describe( 'ImageStyleUI', () => { .then( newEditor => { editor = newEditor; - const buttonView = editor.ui.componentFactory.create( 'style 1' ); + const buttonView = editor.ui.componentFactory.create( 'imageStyle:style 1' ); expect( buttonView.label ).to.equal( 'Default title' ); } ); diff --git a/tests/imagestyle/utils.js b/tests/imagestyle/utils.js index 1acd8386..9cf45b88 100644 --- a/tests/imagestyle/utils.js +++ b/tests/imagestyle/utils.js @@ -27,7 +27,7 @@ describe( 'ImageStyle utils', () => { { name: 'baz', title: 'Side image', icon: 'custom', className: 'baz-class' }, // Customized default styles. - { name: 'imageStyleFull', icon: 'left', title: 'Custom title' } + { name: 'full', icon: 'left', title: 'Custom title' } ] ); } ); @@ -47,7 +47,7 @@ describe( 'ImageStyle utils', () => { it( 'should extend one of default styles if #name matches', () => { expect( imageStyles[ 3 ] ).to.deep.equal( { - name: 'imageStyleFull', + name: 'full', title: 'Custom title', icon: leftIcon, isDefault: true @@ -57,36 +57,36 @@ describe( 'ImageStyle utils', () => { describe( 'string format', () => { it( 'should use one of default styles if #name matches', () => { - expect( normalizeImageStyles( [ 'imageStyleFull' ] ) ).to.deep.equal( [ { - name: 'imageStyleFull', + expect( normalizeImageStyles( [ 'imageStyle:full' ] ) ).to.deep.equal( [ { + name: 'full', title: 'Full size image', icon: fullWidthIcon, isDefault: true } ] ); - expect( normalizeImageStyles( [ 'imageStyleSide' ] ) ).to.deep.equal( [ { - name: 'imageStyleSide', + expect( normalizeImageStyles( [ 'imageStyle:side' ] ) ).to.deep.equal( [ { + name: 'side', title: 'Side image', icon: rightIcon, className: 'image-style-side' } ] ); - expect( normalizeImageStyles( [ 'imageStyleAlignLeft' ] ) ).to.deep.equal( [ { - name: 'imageStyleAlignLeft', + expect( normalizeImageStyles( [ 'imageStyle:alignLeft' ] ) ).to.deep.equal( [ { + name: 'alignLeft', title: 'Left aligned image', icon: leftIcon, className: 'image-style-align-left' } ] ); - expect( normalizeImageStyles( [ 'imageStyleAlignCenter' ] ) ).to.deep.equal( [ { - name: 'imageStyleAlignCenter', + expect( normalizeImageStyles( [ 'imageStyle:alignCenter' ] ) ).to.deep.equal( [ { + name: 'alignCenter', title: 'Centered image', icon: centerIcon, className: 'image-style-align-center' } ] ); - expect( normalizeImageStyles( [ 'imageStyleAlignRight' ] ) ).to.deep.equal( [ { - name: 'imageStyleAlignRight', + expect( normalizeImageStyles( [ 'imageStyle:alignRight' ] ) ).to.deep.equal( [ { + name: 'alignRight', title: 'Right aligned image', icon: rightIcon, className: 'image-style-align-right' diff --git a/tests/manual/caption.js b/tests/manual/caption.js index ae784888..bc65a0ff 100644 --- a/tests/manual/caption.js +++ b/tests/manual/caption.js @@ -28,7 +28,7 @@ ClassicEditor ], toolbar: [ 'heading', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList' ], image: { - toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ] + toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ] } } ) .then( editor => { diff --git a/tests/manual/imagestyle.js b/tests/manual/imagestyle.js index 8e86dcc0..084ba475 100644 --- a/tests/manual/imagestyle.js +++ b/tests/manual/imagestyle.js @@ -31,7 +31,7 @@ ClassicEditor ], toolbar: [ 'heading', '|', 'undo', 'redo' ], image: { - toolbar: [ 'imageStyleFull', 'imageStyleSide' ] + toolbar: [ 'imageStyle:full', 'imageStyle:side' ] } } ) .then( editor => { @@ -56,8 +56,8 @@ ClassicEditor ], toolbar: [ 'heading', '|', 'undo', 'redo' ], image: { - styles: [ 'imageStyleAlignLeft', 'imageStyleAlignCenter', 'imageStyleAlignRight' ], - toolbar: [ 'imageStyleAlignLeft', 'imageStyleAlignCenter', 'imageStyleAlignRight' ] + styles: [ 'imageStyle:alignLeft', 'imageStyle:alignCenter', 'imageStyle:alignRight' ], + toolbar: [ 'imageStyle:alignLeft', 'imageStyle:alignCenter', 'imageStyle:alignRight' ] } } ) .then( editor => { diff --git a/tests/manual/imageupload.js b/tests/manual/imageupload.js index 1ce25ce3..e67b4b50 100644 --- a/tests/manual/imageupload.js +++ b/tests/manual/imageupload.js @@ -32,7 +32,7 @@ ClassicEditor ], toolbar: [ 'heading', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList', 'uploadImage' ], image: { - toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ] + toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ] } } ) .then( editor => { From 32a02ce5ab7a0f8096dcd3f2e89fea52d035b76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Wed, 7 Mar 2018 17:21:48 +0100 Subject: [PATCH 3/6] Other: Rename 'imageUpload' command to 'uploadImage'. --- src/imageupload/imageuploadediting.js | 6 ++-- src/imageupload/imageuploadui.js | 4 +-- tests/imageupload/imageuploadediting.js | 38 ++++++++++++------------ tests/imageupload/imageuploadprogress.js | 12 ++++---- tests/imageupload/imageuploadui.js | 12 ++++---- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/imageupload/imageuploadediting.js b/src/imageupload/imageuploadediting.js index 487a94d3..1a44a22b 100644 --- a/src/imageupload/imageuploadediting.js +++ b/src/imageupload/imageuploadediting.js @@ -41,8 +41,8 @@ export default class ImageUploadEditing extends Plugin { allowAttributes: [ 'uploadId', 'uploadStatus' ] } ); - // Register imageUpload command. - editor.commands.add( 'imageUpload', new ImageUploadCommand( editor ) ); + // Register uploadImage command. + editor.commands.add( 'uploadImage', new ImageUploadCommand( editor ) ); // Execute imageUpload command when image is dropped or pasted. editor.editing.view.document.on( 'clipboardInput', ( evt, data ) => { @@ -60,7 +60,7 @@ export default class ImageUploadEditing extends Plugin { const insertAt = findOptimalInsertionPosition( targetModelSelection ); if ( isImageType( file ) ) { - editor.execute( 'imageUpload', { file, insertAt } ); + editor.execute( 'uploadImage', { file, insertAt } ); evt.stop(); } diff --git a/src/imageupload/imageuploadui.js b/src/imageupload/imageuploadui.js index 8d5fad62..37974cc6 100644 --- a/src/imageupload/imageuploadui.js +++ b/src/imageupload/imageuploadui.js @@ -29,7 +29,7 @@ export default class ImageUploadUI extends Plugin { // Setup `uploadImage` button. editor.ui.componentFactory.add( 'uploadImage', locale => { const view = new FileDialogButtonView( locale ); - const command = editor.commands.get( 'imageUpload' ); + const command = editor.commands.get( 'uploadImage' ); view.set( { acceptedType: 'image/*', @@ -49,7 +49,7 @@ export default class ImageUploadUI extends Plugin { const insertAt = findOptimalInsertionPosition( editor.model.document.selection ); if ( isImageType( file ) ) { - editor.execute( 'imageUpload', { file, insertAt } ); + editor.execute( 'uploadImage', { file, insertAt } ); } } } ); diff --git a/tests/imageupload/imageuploadediting.js b/tests/imageupload/imageuploadediting.js index 9243446a..8931c870 100644 --- a/tests/imageupload/imageuploadediting.js +++ b/tests/imageupload/imageuploadediting.js @@ -69,11 +69,11 @@ describe( 'ImageUploadEditing', () => { expect( model.schema.checkAttribute( [ '$root', 'image' ], 'uploadId' ) ).to.be.true; } ); - it( 'should register imageUpload command', () => { - expect( editor.commands.get( 'imageUpload' ) ).to.be.instanceOf( ImageUploadCommand ); + it( 'should register uploadImage command', () => { + expect( editor.commands.get( 'uploadImage' ) ).to.be.instanceOf( ImageUploadCommand ); } ); - it( 'should execute imageUpload command when image is pasted', () => { + it( 'should execute uploadImage command when image is pasted', () => { const spy = sinon.spy( editor, 'execute' ); const fileMock = createNativeFileMock(); const dataTransfer = new DataTransfer( { files: [ fileMock ], types: [ 'Files' ] } ); @@ -85,7 +85,7 @@ describe( 'ImageUploadEditing', () => { viewDocument.fire( 'clipboardInput', { dataTransfer, targetRanges: [ targetViewRange ] } ); sinon.assert.calledOnce( spy ); - sinon.assert.calledWith( spy, 'imageUpload' ); + sinon.assert.calledWith( spy, 'uploadImage' ); const id = fileRepository.getLoader( fileMock ).id; expect( getModelData( model ) ).to.equal( @@ -93,7 +93,7 @@ describe( 'ImageUploadEditing', () => { ); } ); - it( 'should execute imageUpload command with an optimized position when image is pasted', () => { + it( 'should execute uploadImage command with an optimized position when image is pasted', () => { const spy = sinon.spy( editor, 'execute' ); const fileMock = createNativeFileMock(); const dataTransfer = new DataTransfer( { files: [ fileMock ], types: [ 'Files' ] } ); @@ -106,7 +106,7 @@ describe( 'ImageUploadEditing', () => { viewDocument.fire( 'clipboardInput', { dataTransfer, targetRanges: [ targetViewRange ] } ); sinon.assert.calledOnce( spy ); - sinon.assert.calledWith( spy, 'imageUpload' ); + sinon.assert.calledWith( spy, 'uploadImage' ); const id = fileRepository.getLoader( fileMock ).id; expect( getModelData( model ) ).to.equal( @@ -114,7 +114,7 @@ describe( 'ImageUploadEditing', () => { ); } ); - it( 'should execute imageUpload command when multiple files image are pasted', () => { + it( 'should execute uploadImage command when multiple files image are pasted', () => { const spy = sinon.spy( editor, 'execute' ); const files = [ createNativeFileMock(), createNativeFileMock() ]; const dataTransfer = new DataTransfer( { files, types: [ 'Files' ] } ); @@ -126,7 +126,7 @@ describe( 'ImageUploadEditing', () => { viewDocument.fire( 'clipboardInput', { dataTransfer, targetRanges: [ targetViewRange ] } ); sinon.assert.calledTwice( spy ); - sinon.assert.calledWith( spy, 'imageUpload' ); + sinon.assert.calledWith( spy, 'uploadImage' ); const id1 = fileRepository.getLoader( files[ 0 ] ).id; const id2 = fileRepository.getLoader( files[ 1 ] ).id; @@ -138,7 +138,7 @@ describe( 'ImageUploadEditing', () => { ); } ); - it( 'should not execute imageUpload command when file is not an image', () => { + it( 'should not execute uploadImage command when file is not an image', () => { const spy = sinon.spy( editor, 'execute' ); const viewDocument = editor.editing.view.document; const fileMock = { @@ -157,7 +157,7 @@ describe( 'ImageUploadEditing', () => { sinon.assert.notCalled( spy ); } ); - it( 'should not execute imageUpload command when there is non-empty HTML content pasted', () => { + it( 'should not execute uploadImage command when there is non-empty HTML content pasted', () => { const spy = sinon.spy( editor, 'execute' ); const fileMock = createNativeFileMock(); const dataTransfer = new DataTransfer( { @@ -213,7 +213,7 @@ describe( 'ImageUploadEditing', () => { it( 'should use read data once it is present', done => { const file = createNativeFileMock(); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); model.once( '_change', () => { expect( getViewData( view ) ).to.equal( @@ -233,7 +233,7 @@ describe( 'ImageUploadEditing', () => { it( 'should replace read data with server response once it is present', done => { const file = createNativeFileMock(); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); model.document.once( 'change', () => { model.document.once( 'change', () => { @@ -264,7 +264,7 @@ describe( 'ImageUploadEditing', () => { }, { priority: 'high' } ); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); nativeReaderMock.mockError( 'Reading error.' ); } ); @@ -280,7 +280,7 @@ describe( 'ImageUploadEditing', () => { }, { priority: 'high' } ); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); nativeReaderMock.abort(); setTimeout( () => { @@ -308,7 +308,7 @@ describe( 'ImageUploadEditing', () => { evt.stop(); }, { priority: 'high' } ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); model.document.once( 'change', () => { model.document.once( 'change', () => { @@ -325,7 +325,7 @@ describe( 'ImageUploadEditing', () => { it( 'should abort upload if image is removed', () => { const file = createNativeFileMock(); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); const abortSpy = testUtils.sinon.spy( loader, 'abort' ); @@ -344,7 +344,7 @@ describe( 'ImageUploadEditing', () => { it( 'should not abort and not restart upload when image is moved', () => { const file = createNativeFileMock(); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); const abortSpy = testUtils.sinon.spy( loader, 'abort' ); const loadSpy = testUtils.sinon.spy( loader, 'read' ); @@ -369,7 +369,7 @@ describe( 'ImageUploadEditing', () => { evt.stop(); }, { priority: 'high' } ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); model.document.once( 'change', () => { // This is called after "manual" remove. @@ -405,7 +405,7 @@ describe( 'ImageUploadEditing', () => { it( 'should create responsive image if server return multiple images', done => { const file = createNativeFileMock(); setModelData( model, '{}foo bar' ); - editor.execute( 'imageUpload', { file } ); + editor.execute( 'uploadImage', { file } ); model.document.once( 'change', () => { model.document.once( 'change', () => { diff --git a/tests/imageupload/imageuploadprogress.js b/tests/imageupload/imageuploadprogress.js index 6bf361b2..895f5bf0 100644 --- a/tests/imageupload/imageuploadprogress.js +++ b/tests/imageupload/imageuploadprogress.js @@ -70,7 +70,7 @@ describe( 'ImageUploadProgress', () => { it( 'should convert image\'s "reading" uploadStatus attribute', () => { setModelData( model, '[]foo' ); - editor.execute( 'imageUpload', { file: createNativeFileMock() } ); + editor.execute( 'uploadImage', { file: createNativeFileMock() } ); expect( getViewData( view ) ).to.equal( '[
' + @@ -81,7 +81,7 @@ describe( 'ImageUploadProgress', () => { it( 'should convert image\'s "uploading" uploadStatus attribute', done => { setModelData( model, '[]foo' ); - editor.execute( 'imageUpload', { file: createNativeFileMock() } ); + editor.execute( 'uploadImage', { file: createNativeFileMock() } ); model.document.once( 'change', () => { expect( getViewData( view ) ).to.equal( @@ -99,7 +99,7 @@ describe( 'ImageUploadProgress', () => { it( 'should update progressbar width on progress', done => { setModelData( model, '[]foo' ); - editor.execute( 'imageUpload', { file: createNativeFileMock() } ); + editor.execute( 'uploadImage', { file: createNativeFileMock() } ); model.document.once( 'change', () => { adapterMock.mockProgress( 40, 100 ); @@ -119,7 +119,7 @@ describe( 'ImageUploadProgress', () => { it( 'should convert image\'s "complete" uploadStatus attribute', done => { setModelData( model, '[]foo' ); - editor.execute( 'imageUpload', { file: createNativeFileMock() } ); + editor.execute( 'uploadImage', { file: createNativeFileMock() } ); model.document.once( 'change', () => { model.document.once( 'change', () => { @@ -143,7 +143,7 @@ describe( 'ImageUploadProgress', () => { uploadProgress.placeholder = base64Sample; setModelData( model, '[]foo' ); - editor.execute( 'imageUpload', { file: createNativeFileMock() } ); + editor.execute( 'uploadImage', { file: createNativeFileMock() } ); expect( getViewData( view ) ).to.equal( '[
' + @@ -158,7 +158,7 @@ describe( 'ImageUploadProgress', () => { }, { priority: 'highest' } ); setModelData( model, '[]foo' ); - editor.execute( 'imageUpload', { file: createNativeFileMock() } ); + editor.execute( 'uploadImage', { file: createNativeFileMock() } ); expect( getViewData( view ) ).to.equal( '[
]

foo

' diff --git a/tests/imageupload/imageuploadui.js b/tests/imageupload/imageuploadui.js index fd06d24e..dbfa5b12 100644 --- a/tests/imageupload/imageuploadui.js +++ b/tests/imageupload/imageuploadui.js @@ -63,7 +63,7 @@ describe( 'ImageUploadUI', () => { it( 'should be disabled while ImageUploadCommand is disabled', () => { const button = editor.ui.componentFactory.create( 'uploadImage' ); - const command = editor.commands.get( 'imageUpload' ); + const command = editor.commands.get( 'uploadImage' ); command.isEnabled = true; @@ -77,7 +77,7 @@ describe( 'ImageUploadUI', () => { // ckeditor5-upload/#77 it( 'should be properly bound with ImageUploadCommand', () => { const button = editor.ui.componentFactory.create( 'uploadImage' ); - const command = editor.commands.get( 'imageUpload' ); + const command = editor.commands.get( 'uploadImage' ); const spy = sinon.spy(); button.render(); @@ -91,14 +91,14 @@ describe( 'ImageUploadUI', () => { sinon.assert.notCalled( spy ); } ); - it( 'should execute imageUpload command', () => { + it( 'should execute uploadImage command', () => { const executeStub = sinon.stub( editor, 'execute' ); const button = editor.ui.componentFactory.create( 'uploadImage' ); const files = [ createNativeFileMock() ]; button.fire( 'done', files ); sinon.assert.calledOnce( executeStub ); - expect( executeStub.firstCall.args[ 0 ] ).to.equal( 'imageUpload' ); + expect( executeStub.firstCall.args[ 0 ] ).to.equal( 'uploadImage' ); expect( executeStub.firstCall.args[ 1 ].file ).to.equal( files[ 0 ] ); } ); @@ -137,7 +137,7 @@ describe( 'ImageUploadUI', () => { ); } ); - it( 'should not execute imageUpload if the file is not an image', () => { + it( 'should not execute uploadImage if the file is not an image', () => { const executeStub = sinon.stub( editor, 'execute' ); const button = editor.ui.componentFactory.create( 'uploadImage' ); const file = { @@ -159,7 +159,7 @@ describe( 'ImageUploadUI', () => { button.fire( 'done', files ); sinon.assert.calledOnce( executeStub ); - expect( executeStub.firstCall.args[ 0 ] ).to.equal( 'imageUpload' ); + expect( executeStub.firstCall.args[ 0 ] ).to.equal( 'uploadImage' ); expect( executeStub.firstCall.args[ 1 ].file ).to.equal( files[ 0 ] ); } ); } ); From 35a94612a7f85a0895e9be38ae5ad7d256191aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Wed, 7 Mar 2018 17:24:01 +0100 Subject: [PATCH 4/6] Fix: The order of private fields in ImageStyleCommand was wrong. --- src/imagestyle/imagestylecommand.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/imagestyle/imagestylecommand.js b/src/imagestyle/imagestylecommand.js index ebdebc13..92f39131 100644 --- a/src/imagestyle/imagestylecommand.js +++ b/src/imagestyle/imagestylecommand.js @@ -25,6 +25,14 @@ export default class ImageStyleCommand extends Command { constructor( editor, styles ) { super( editor ); + /** + * Cached name of a default style if present. If there is no default style it defaults to false. + * + * @type {Boolean|String} + * @private + */ + this._defaultStyle = false; + /** * A style handled by this command. * @@ -40,14 +48,6 @@ export default class ImageStyleCommand extends Command { return styles; }, {} ); - - /** - * Cached name of a default style if present. If there is no default style it defaults to false. - * - * @type {Boolean|String} - * @private - */ - this._defaultStyle = false; } /** From bd8aebb6290df4448233a3e22c35a55c5bb11b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Fri, 9 Mar 2018 16:24:13 +0100 Subject: [PATCH 5/6] API docs fixes. --- docs/features/image.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/features/image.md b/docs/features/image.md index 0dcc6cd3..b4918e83 100644 --- a/docs/features/image.md +++ b/docs/features/image.md @@ -11,10 +11,10 @@ The [`@ckeditor/ckeditor5-image`](https://www.npmjs.com/package/@ckeditor/ckedit * {@link module:image/imagetoolbar~ImageToolbar} adds the image feature's contextual toolbar, * {@link module:image/imagecaption~ImageCaption} adds support for captions, * {@link module:image/imagestyle~ImageStyle} adds support for image styles, -* {@link module:image/imageupload~ImageUpload} adds support for uploading dropped or pasted images (note: it is currently located in the [`@ckeditor/ckeditor5-upload`](https://www.npmjs.com/package/@ckeditor/ckeditor5-upload) package but will be moved to the `@ckeditor/ckeditor5-image` package). +* {@link module:image/imageupload~ImageUpload} adds support for uploading dropped or pasted images (see: {@link features/image-upload Image upload}). - The first four features listed above (so all except the upload support) are enabled by default in all builds. + All features listed above are enabled by default in all builds. ## Base image support @@ -100,7 +100,7 @@ A side image: The actual styling of the images is the developer's job. The editor comes with some default styles, but they will only be applied to images inside the editor. The developer needs to style them on the target pages. - Here you can find the source of the default styles applied by the editor: [`ckeditor5-image/theme/theme.scss`](https://github.com/ckeditor/ckeditor5-image/blob/master/theme/theme.scss). + Here you can find the source of the default styles applied by the editor: [`ckeditor5-image/theme/imagestyle.css`](https://github.com/ckeditor/ckeditor5-image/blob/master/theme/imagestyle.css). Below you can see a demo of the editor with the image styles feature enabled. The default configuration is used. You can change the styles of images through the image's contextual toolbar. From 679c5fa73f8708df882e0002a24246df71d34970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Sun, 11 Mar 2018 18:22:14 +0100 Subject: [PATCH 6/6] Cleaned up the image.styles configuration by getting rid of the 'imageStyle:' prefix from style names. --- docs/_snippets/features/image-style-custom.js | 6 ++--- docs/features/image.md | 19 ++++++++----- src/imagestyle.js | 11 ++++---- src/imagestyle/imagestylecommand.js | 7 +++-- src/imagestyle/imagestyleediting.js | 27 ++++++++++++------- src/imagestyle/utils.js | 9 +++---- tests/imagestyle/imagestyleediting.js | 12 ++++----- tests/imagestyle/utils.js | 18 ++++++++----- 8 files changed, 66 insertions(+), 43 deletions(-) diff --git a/docs/_snippets/features/image-style-custom.js b/docs/_snippets/features/image-style-custom.js index 9b1137f3..3c35c620 100644 --- a/docs/_snippets/features/image-style-custom.js +++ b/docs/_snippets/features/image-style-custom.js @@ -12,13 +12,13 @@ ClassicEditor image: { styles: [ // This option is equal to a situation where no style is applied. - 'imageStyle:full', + 'full', // This represents an image aligned to left. - 'imageStyle:alignLeft', + 'alignLeft', // This represents an image aligned to right. - 'imageStyle:alignRight' + 'alignRight' ], toolbar: [ 'imageTextAlternative', '|', 'imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:alignRight' ] diff --git a/docs/features/image.md b/docs/features/image.md index b4918e83..2d8ad846 100644 --- a/docs/features/image.md +++ b/docs/features/image.md @@ -122,13 +122,13 @@ ClassicEditor styles: [ // This option is equal to a situation where no style is applied. - 'imageStyle:full', + 'full', // This represents an image aligned to left. - 'imageStyle:alignLeft', + 'alignLeft', // This represents an image aligned to right. - 'imageStyle:alignRight' + 'alignRight' ] } } ) @@ -136,7 +136,7 @@ ClassicEditor .catch( ... ); ``` -In the code sample above we used predefined image styles – `'imageStyle:full'`, `'imageStyle:alignLeft'` and `'imageStyle:alignRight'`. The latter two apply, respectively, `.image-style-align-left` and `.image-style-align-right` classes to the `
` element. +In the code sample above we used predefined image styles – `'full'`, `'alignLeft'` and `'alignRight'`. The latter two apply, respectively, `.image-style-align-left` and `.image-style-align-right` classes to the `
` element. See the result below: @@ -162,7 +162,9 @@ you can also define your own styles or modify the existing ones. Reusing (or modifying) predefined styles has this advantage that CKEditor 5 will use its official translations for the defined button titles. -TODO (example)... +You can find advanced examples in the {@link module:image/image~ImageConfig#styles `image.styles`} configuration option's documentation. + +TODO (live example)... ## Image upload @@ -211,7 +213,12 @@ The {@link module:image/image~Image} plugin registers: The {@link module:image/imagestyle~ImageStyle} plugin registers: -* A command for each defined style (based on the {@link module:image/image~ImageConfig#styles `image.styles`} configuration option) — e.g. `'imageStyle:full'` and `'imageStyle:side'`, +* The `'imageStyle'` command that accepts value based on the {@link module:image/image~ImageConfig#styles `image.styles`} configuration option (e.g. `'full'` and `'side'`): + + ```js + editor.execute( 'imageStyle', { value: 'side' } ); + ``` + * A button for each defined style — e.g. `'imageStyle:full'` and `'imageStyle:side'`. ## Contribute diff --git a/src/imagestyle.js b/src/imagestyle.js index 1d6a1554..f5236763 100644 --- a/src/imagestyle.js +++ b/src/imagestyle.js @@ -37,12 +37,11 @@ export default class ImageStyle extends Plugin { /** * Available image styles. - * The option is used by the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing} feature. * * The default value is: * * const imageConfig = { - * styles: [ 'imageStyle:full', 'imageStyle:side' ] + * styles: [ 'full', 'side' ] * }; * * which configures two default styles: @@ -96,11 +95,11 @@ export default class ImageStyle extends Plugin { * The feature creates commands based on defined styles, so you can change the style of a selected image by executing * the following command: * - * editor.execute( 'imageStyle:side' ); + * editor.execute( 'imageStyle' { value: 'side' } ); * - * The features creates also buttons which execute the commands, so assuming that you use the - * default image styles setting you can {@link module:image/image~ImageConfig#toolbar configure the image toolbar} - * to contain these options: + * The feature creates also buttons which execute the command. So, assuming that you use the + * default image styles setting, you can {@link module:image/image~ImageConfig#toolbar configure the image toolbar} + * (or any other toolbar) to contain these options: * * const imageConfig = { * toolbar: [ 'imageStyle:full', 'imageStyle:side' ] diff --git a/src/imagestyle/imagestylecommand.js b/src/imagestyle/imagestylecommand.js index 92f39131..6a2f7c3e 100644 --- a/src/imagestyle/imagestylecommand.js +++ b/src/imagestyle/imagestylecommand.js @@ -26,7 +26,7 @@ export default class ImageStyleCommand extends Command { super( editor ); /** - * Cached name of a default style if present. If there is no default style it defaults to false. + * Cached name of the default style if present. If there is no default style it defaults to `false`. * * @type {Boolean|String} * @private @@ -71,8 +71,11 @@ export default class ImageStyleCommand extends Command { /** * Executes the command. * + * editor.execute( 'imageStyle', { value: 'side' } ); + * * @param {Object} options - * @param {String} options.value + * @param {String} options.value The name of the style (based on the + * {@link module:image/image~ImageConfig#styles `image.styles`} configuration option). * @fires execute */ execute( options = {} ) { diff --git a/src/imagestyle/imagestyleediting.js b/src/imagestyle/imagestyleediting.js index bf8713fc..5e8399fb 100644 --- a/src/imagestyle/imagestyleediting.js +++ b/src/imagestyle/imagestyleediting.js @@ -44,7 +44,7 @@ export default class ImageStyleEditing extends Plugin { const editing = editor.editing; // Define default configuration. - editor.config.define( 'image.styles', [ 'imageStyle:full', 'imageStyle:side' ] ); + editor.config.define( 'image.styles', [ 'full', 'side' ] ); // Get configuration. const styles = normalizeImageStyles( editor.config.get( 'image.styles' ) ); @@ -69,25 +69,34 @@ export default class ImageStyleEditing extends Plugin { /** * Image style format descriptor. * - * import fullWidthIcon from 'path/to/icon.svg`; + * import fullSizeIcon from 'path/to/icon.svg'; * * const imageStyleFormat = { - * name: 'fullSizeImage', - * icon: fullWidthIcon, + * name: 'fullSize', + * icon: fullSizeIcon, * title: 'Full size image', * className: 'image-full-size' * } * * @typedef {Object} module:image/imagestyle/imagestyleediting~ImageStyleFormat + * * @property {String} name The unique name of the style. It will be used to: - * * register the {@link module:core/command~Command command} which will apply this style, - * * store the style's button in the editor {@link module:ui/componentfactory~ComponentFactory}, - * * store the style in the `imageStyle` model attribute. + * + * * store the chosen style in the model by setting the `imageStyle` attribute of the `` element, + * * as a value of the {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute `imageStyle` command}, + * * when registering button for each of the styles (`'imageStyle:{name}'`) in the + * {@link module:ui/componentfactory~ComponentFactory UI components factory} (this functionality is provided by the + * {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugin), + * * @property {Boolean} [isDefault] When set, the style will be used as the default one. * A default style does not apply any CSS class to the view element. + * * @property {String} icon One of the following to be used when creating the style's button: - * * An SVG icon source (as an XML string), - * * One of {@link module:image/imagestyle/utils~defaultIcons} to use a default icon provided by the plugin. + * + * * An SVG icon source (as an XML string), + * * One of {@link module:image/imagestyle/utils~defaultIcons} to use a default icon provided by the plugin. + * * @property {String} title The style's title. + * * @property {String} className The CSS class used to represent the style in view. */ diff --git a/src/imagestyle/utils.js b/src/imagestyle/utils.js index 04392bd9..f80de3b3 100644 --- a/src/imagestyle/utils.js +++ b/src/imagestyle/utils.js @@ -108,18 +108,18 @@ export function normalizeImageStyles( configuredStyles = [] ) { function _normalizeStyle( style ) { // Just the name of the style has been passed. if ( typeof style == 'string' ) { - // If it's one of the defaults, just use it. - // Clone the style to avoid overriding defaults. - const styleName = style.indexOf( 'imageStyle:' ) === 0 ? style.substr( 11 ) : style; + const styleName = style; + // If it's one of the defaults, just use it. if ( defaultStyles[ styleName ] ) { + // Clone the style to avoid overriding defaults. style = Object.assign( {}, defaultStyles[ styleName ] ); } // If it's just a name but none of the defaults, warn because probably it's a mistake. else { log.warn( 'image-style-not-found: There is no such image style of given name.', - { name: style } + { name: styleName } ); // Normalize the style anyway to prevent errors. @@ -128,7 +128,6 @@ function _normalizeStyle( style ) { }; } } - // If an object style has been passed and if the name matches one of the defaults, // extend it with defaults – the user wants to customize a default style. // Note: Don't override the user–defined style object, clone it instead. diff --git a/tests/imagestyle/imagestyleediting.js b/tests/imagestyle/imagestyleediting.js index ae8a95fc..58996b61 100644 --- a/tests/imagestyle/imagestyleediting.js +++ b/tests/imagestyle/imagestyleediting.js @@ -71,7 +71,7 @@ describe( 'ImageStyleEditing', () => { .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyle:full', 'imageStyle:side' ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'full', 'side' ] ); } ); } ); @@ -264,7 +264,7 @@ describe( 'ImageStyleEditing', () => { .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyle:full', 'imageStyle:side' ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'full', 'side' ] ); } ); } ); @@ -274,14 +274,14 @@ describe( 'ImageStyleEditing', () => { plugins: [ ImageStyleEditing ], image: { styles: [ - 'imageStyle:side' + 'side' ] } } ) .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'imageStyle:side' ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ 'side' ] ); } ); } ); @@ -291,14 +291,14 @@ describe( 'ImageStyleEditing', () => { plugins: [ ImageStyleEditing ], image: { styles: [ - { name: 'imageStyle:side' } + { name: 'side' } ] } } ) .then( newEditor => { editor = newEditor; - expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ { name: 'imageStyle:side' } ] ); + expect( newEditor.config.get( 'image.styles' ) ).to.deep.equal( [ { name: 'side' } ] ); } ); } ); } ); diff --git a/tests/imagestyle/utils.js b/tests/imagestyle/utils.js index 9cf45b88..3da975d7 100644 --- a/tests/imagestyle/utils.js +++ b/tests/imagestyle/utils.js @@ -18,7 +18,13 @@ testUtils.createSinonSandbox(); describe( 'ImageStyle utils', () => { let imageStyles; - describe( 'imageStyles()', () => { + describe( 'normalizeImageStyles()', () => { + // Since this function is all about normalizing the config object, make sure it doesn't throw + // if the config is empty (which may happen e.g. if only ImageStyleUI was loaded). + it( 'does not throw when given undefined', () => { + expect( normalizeImageStyles() ).to.deep.equal( [] ); + } ); + describe( 'object format', () => { beforeEach( () => { imageStyles = normalizeImageStyles( [ @@ -57,35 +63,35 @@ describe( 'ImageStyle utils', () => { describe( 'string format', () => { it( 'should use one of default styles if #name matches', () => { - expect( normalizeImageStyles( [ 'imageStyle:full' ] ) ).to.deep.equal( [ { + expect( normalizeImageStyles( [ 'full' ] ) ).to.deep.equal( [ { name: 'full', title: 'Full size image', icon: fullWidthIcon, isDefault: true } ] ); - expect( normalizeImageStyles( [ 'imageStyle:side' ] ) ).to.deep.equal( [ { + expect( normalizeImageStyles( [ 'side' ] ) ).to.deep.equal( [ { name: 'side', title: 'Side image', icon: rightIcon, className: 'image-style-side' } ] ); - expect( normalizeImageStyles( [ 'imageStyle:alignLeft' ] ) ).to.deep.equal( [ { + expect( normalizeImageStyles( [ 'alignLeft' ] ) ).to.deep.equal( [ { name: 'alignLeft', title: 'Left aligned image', icon: leftIcon, className: 'image-style-align-left' } ] ); - expect( normalizeImageStyles( [ 'imageStyle:alignCenter' ] ) ).to.deep.equal( [ { + expect( normalizeImageStyles( [ 'alignCenter' ] ) ).to.deep.equal( [ { name: 'alignCenter', title: 'Centered image', icon: centerIcon, className: 'image-style-align-center' } ] ); - expect( normalizeImageStyles( [ 'imageStyle:alignRight' ] ) ).to.deep.equal( [ { + expect( normalizeImageStyles( [ 'alignRight' ] ) ).to.deep.equal( [ { name: 'alignRight', title: 'Right aligned image', icon: rightIcon,