Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge 07cce57 into 1128cb8
Browse files Browse the repository at this point in the history
  • Loading branch information
oskarwrobel committed Jun 26, 2018
2 parents 1128cb8 + 07cce57 commit 843bf35
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/imagetextalternative/imagetextalternativeui.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default class ImageTextAlternativeUI extends Plugin {
} );

// Reposition the balloon or hide the form if an image widget is no longer selected.
this.listenTo( view, 'render', () => {
this.listenTo( editor.ui, 'update', () => {
if ( !isImageWidgetSelected( viewDocument.selection ) ) {
this._hideForm( true );
} else if ( this._isVisible ) {
Expand Down
26 changes: 10 additions & 16 deletions src/imagetoolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ export default class ImageToolbar extends Plugin {
this._toolbar.fillFromConfig( toolbarConfig, editor.ui.componentFactory );

// Show balloon panel each time image widget is selected.
this.listenTo( editor.editing.view, 'render', () => {
this.listenTo( editor.ui, 'update', () => {
this._checkIsVisible();
} );

// There is no render method after focus is back in editor, we need to check if balloon panel should be visible.
// UI#update is not fired after focus is back in editor, we need to check if balloon panel should be visible.
this.listenTo( editor.ui.focusTracker, 'change:isFocused', () => {
this._checkIsVisible();
}, { priority: 'low' } );
Expand All @@ -111,14 +111,10 @@ export default class ImageToolbar extends Plugin {
_checkIsVisible() {
const editor = this.editor;

if ( !editor.ui.focusTracker.isFocused ) {
if ( !editor.ui.focusTracker.isFocused || !isImageWidgetSelected( editor.editing.view.document.selection ) ) {
this._hideToolbar();
} else {
if ( isImageWidgetSelected( editor.editing.view.document.selection ) ) {
this._showToolbar();
} else {
this._hideToolbar();
}
this._showToolbar();
}
}

Expand All @@ -132,14 +128,12 @@ export default class ImageToolbar extends Plugin {

if ( this._isVisible ) {
repositionContextualBalloon( editor );
} else {
if ( !this._balloon.hasView( this._toolbar ) ) {
this._balloon.add( {
view: this._toolbar,
position: getBalloonPositionData( editor ),
balloonClassName
} );
}
} else if ( !this._balloon.hasView( this._toolbar ) ) {
this._balloon.add( {
view: this._toolbar,
position: getBalloonPositionData( editor ),
balloonClassName
} );
}
}

Expand Down
43 changes: 34 additions & 9 deletions tests/image/imageediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
* For licensing, see LICENSE.md.
*/

/* global document, Event */

import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
import ImageEditing from '../../src/image/imageediting';
import ImageLoadObserver from '../../src/image/imageloadobserver';
import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
Expand All @@ -12,7 +15,7 @@ import { isImageWidget } from '../../src/image/utils';
import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';

describe( 'ImageEditing', () => {
let editor, model, document, view, viewDocument;
let editor, model, doc, view, viewDocument;

beforeEach( () => {
return VirtualTestEditor
Expand All @@ -22,7 +25,7 @@ describe( 'ImageEditing', () => {
.then( newEditor => {
editor = newEditor;
model = editor.model;
document = model.document;
doc = model.document;
view = editor.editing.view;
viewDocument = view.document;
} );
Expand All @@ -48,6 +51,28 @@ describe( 'ImageEditing', () => {
expect( view.getObserver( ImageLoadObserver ) ).to.be.instanceOf( ImageLoadObserver );
} );

// See https://github.com/ckeditor/ckeditor5-image/issues/142.
it( 'should update the ui after image has been loaded in the DOM', () => {
const element = document.createElement( 'div' );
document.body.appendChild( element );

ClassicTestEditor.create( element, {
plugins: [ ImageEditing ]
} ).then( editor => {
editor.data.set( '<figure class="image"><img src="foo.png" alt="bar" /></figure>' );

const spy = sinon.spy();

editor.ui.on( 'update', spy );

element.querySelector( 'img' ).dispatchEvent( new Event( 'load' ) );

sinon.assert.calledOnce( spy );

return editor.destroy().then( () => element.remove() );
} );
} );

describe( 'conversion in data pipeline', () => {
describe( 'model to view', () => {
it( 'should convert', () => {
Expand Down Expand Up @@ -120,7 +145,7 @@ describe( 'ImageEditing', () => {
'srcset=\'{ "foo":"bar" }\'>' +
'</image>' );

const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );
model.change( writer => {
writer.removeAttribute( 'srcset', image );
} );
Expand Down Expand Up @@ -400,7 +425,7 @@ describe( 'ImageEditing', () => {

it( 'should convert attribute change', () => {
setModelData( model, '<image src="foo.png" alt="alt text"></image>' );
const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );

model.change( writer => {
writer.setAttribute( 'alt', 'new text', image );
Expand All @@ -413,7 +438,7 @@ describe( 'ImageEditing', () => {

it( 'should convert attribute removal', () => {
setModelData( model, '<image src="foo.png" alt="alt text"></image>' );
const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );

model.change( writer => {
writer.removeAttribute( 'alt', image );
Expand All @@ -425,7 +450,7 @@ describe( 'ImageEditing', () => {

it( 'should not convert change if is already consumed', () => {
setModelData( model, '<image src="foo.png" alt="alt text"></image>' );
const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );

editor.editing.downcastDispatcher.on( 'attribute:alt:image', ( evt, data, conversionApi ) => {
conversionApi.consumable.consume( data.item, 'attribute:alt' );
Expand Down Expand Up @@ -463,7 +488,7 @@ describe( 'ImageEditing', () => {
'srcset=\'{ "foo":"bar" }\'>' +
'</image>' );

const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );
model.change( writer => {
writer.removeAttribute( 'srcset', image );
} );
Expand Down Expand Up @@ -492,7 +517,7 @@ describe( 'ImageEditing', () => {

it( 'should remove sizes and srcsset attribute when srcset attribute is removed from model', () => {
setModelData( model, '<image src="foo.png" srcset=\'{ "data": "small.png 148w, big.png 1024w" }\'></image>' );
const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );

model.change( writer => {
writer.removeAttribute( 'srcset', image );
Expand All @@ -512,7 +537,7 @@ describe( 'ImageEditing', () => {
'srcset=\'{ "data": "small.png 148w, big.png 1024w", "width": "1024" }\'>' +
'</image>'
);
const image = document.getRoot().getChild( 0 );
const image = doc.getRoot().getChild( 0 );

model.change( writer => {
writer.removeAttribute( 'srcset', image );
Expand Down
8 changes: 5 additions & 3 deletions tests/imagetextalternative/imagetextalternativeui.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ describe( 'ImageTextAlternative', () => {
expect( balloon.visibleView ).to.equal( lastView );
} );

describe( 'integration with the editor selection (#render event)', () => {
describe( 'integration with the editor selection (ui#update event)', () => {
it( 'should re-position the form', () => {
setData( model, '[<image src=""></image>]' );
button.fire( 'execute' );

const spy = sinon.spy( balloon, 'updatePosition' );

editor.editing.view.fire( 'render' );
editor.ui.fire( 'update' );
sinon.assert.calledOnce( spy );
} );

Expand All @@ -174,11 +174,13 @@ describe( 'ImageTextAlternative', () => {
const removeSpy = sinon.spy( balloon, 'remove' );
const focusSpy = sinon.spy( editor.editing.view, 'focus' );

// EnqueueChange automatically fires #render event.
model.enqueueChange( 'transparent', writer => {
writer.remove( doc.selection.getFirstRange() );
} );

// Because the update event is throttled we need to "flush" it.
editor.ui.fire( 'update' );

sinon.assert.calledWithExactly( removeSpy, form );
sinon.assert.calledOnce( focusSpy );
} );
Expand Down
33 changes: 24 additions & 9 deletions tests/imagetoolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import View from '@ckeditor/ckeditor5-ui/src/view';
import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';

describe( 'ImageToolbar', () => {
let editor, model, doc, editingView, plugin, toolbar, balloon, editorElement;
let editor, model, doc, plugin, toolbar, balloon, editorElement;

beforeEach( () => {
editorElement = global.document.createElement( 'div' );
Expand All @@ -36,7 +36,6 @@ describe( 'ImageToolbar', () => {
doc = model.document;
plugin = editor.plugins.get( ImageToolbar );
toolbar = plugin._toolbar;
editingView = editor.editing.view;
balloon = editor.plugins.get( 'ContextualBalloon' );
} );
} );
Expand Down Expand Up @@ -79,6 +78,9 @@ describe( 'ImageToolbar', () => {

setData( model, '[<image src=""></image>]' );

// "Flush" throttled update event.
editor.ui.fire( 'update' );

sinon.assert.calledWithMatch( spy, {
view: toolbar,
balloonClassName: 'ck-toolbar-container'
Expand Down Expand Up @@ -112,17 +114,18 @@ describe( 'ImageToolbar', () => {
} );
} );

describe( 'integration with the editor selection (#change event)', () => {
describe( 'integration with the editor selection', () => {
beforeEach( () => {
editor.ui.focusTracker.isFocused = true;
} );

it( 'should show the toolbar on render when the image is selected', () => {
it( 'should show the toolbar on ui#update when the image is selected', () => {
setData( model, '<paragraph>[foo]</paragraph><image src=""></image>' );

expect( balloon.visibleView ).to.be.null;

editingView.change( () => {} );
editor.ui.fire( 'update' );

expect( balloon.visibleView ).to.be.null;

model.change( writer => {
Expand All @@ -132,16 +135,22 @@ describe( 'ImageToolbar', () => {
);
} );

// "Flush" throttled update event.
editor.ui.fire( 'update' );
expect( balloon.visibleView ).to.equal( toolbar );

// Make sure successive change does not throw, e.g. attempting
// to insert the toolbar twice.
editingView.change( () => {} );
editor.ui.fire( 'update' );
expect( balloon.visibleView ).to.equal( toolbar );
} );

it( 'should not engage when the toolbar is in the balloon yet invisible', () => {
setData( model, '[<image src=""></image>]' );

// "Flush" throttled update event.
editor.ui.fire( 'update' );

expect( balloon.visibleView ).to.equal( toolbar );

const lastView = new View();
Expand All @@ -156,13 +165,17 @@ describe( 'ImageToolbar', () => {

expect( balloon.visibleView ).to.equal( lastView );

editingView.change( () => {} );
editor.ui.fire( 'update' );

expect( balloon.visibleView ).to.equal( lastView );
} );

it( 'should hide the toolbar on render if the image is de–selected', () => {
it( 'should hide the toolbar on ui#update if the image is de–selected', () => {
setData( model, '<paragraph>foo</paragraph>[<image src=""></image>]' );

// "Flush" throttled update event.
editor.ui.fire( 'update' );

expect( balloon.visibleView ).to.equal( toolbar );

model.change( writer => {
Expand All @@ -172,11 +185,13 @@ describe( 'ImageToolbar', () => {
);
} );

// "Flush" throttled update event.
editor.ui.fire( 'update' );
expect( balloon.visibleView ).to.be.null;

// Make sure successive change does not throw, e.g. attempting
// to remove the toolbar twice.
editingView.change( () => {} );
editor.ui.fire( 'update' );
expect( balloon.visibleView ).to.be.null;
} );
} );
Expand Down
6 changes: 6 additions & 0 deletions tests/manual/tickets/142/1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p><button class="start">Insert image</button></p>

<div id="editor">
<p>lorem ipsum</p>
<p>foo <a href="foo">bar</a> biz</p>
</div>
41 changes: 41 additions & 0 deletions tests/manual/tickets/142/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* global document, console, window, setTimeout */

import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
import Enter from '@ckeditor/ckeditor5-enter/src/enter';
import Typing from '@ckeditor/ckeditor5-typing/src/typing';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Link from '@ckeditor/ckeditor5-link/src/link';
import Image from '../../../../src/image';
import ImageCaption from '../../../../src/imagecaption';

ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ Enter, Typing, Paragraph, Link, Image, ImageCaption ],
toolbar: [],
} )
.then( editor => {
window.editor = editor;

const doc = editor.model.document;

document.querySelector( '.start' ).addEventListener( 'click', () => {
let image;

editor.model.change( writer => {
image = writer.createElement( 'image', { src: 'sample-small.jpg' } );
writer.insert( image, doc.getRoot().getChild( 0 ), 'after' );
} );

setTimeout( () => {
editor.ui.view.element.querySelector( 'img' ).src = '../../sample.jpg';
}, 3000 );
} );
} )
.catch( err => {
console.error( err.stack );
} );
4 changes: 4 additions & 0 deletions tests/manual/tickets/142/1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Update the UI after image load [#142](https://github.com/ckeditor/ckeditor5-image/issues/142)

1. Click **Insert image** then quickly select the link in the content (the link editing balloon should show up).
2. Observe if the balloon remains attached to the link after replacing image source to the biggest one (replacing source is made using DOM API).
Binary file added tests/manual/tickets/142/sample-small.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/manual/tickets/142/sample.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 843bf35

Please sign in to comment.