Skip to content

Commit

Permalink
Merge branch 'master' into i/8699-dropdown-shadow
Browse files Browse the repository at this point in the history
  • Loading branch information
oleq committed Jan 12, 2021
2 parents ffbee5f + 343a715 commit 6fc38c0
Show file tree
Hide file tree
Showing 30 changed files with 766 additions and 187 deletions.
2 changes: 1 addition & 1 deletion docs/_snippets/features/wproofreader.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div id="snippet-wproofreader">
<p>Typos hapen. We striving to correct them. Hover on the marked words for instant correction suggestions or click the dialog icon in the bottom right corner to have the whole text proofread at once.</p>
<p>Typos hapen. We striving to correct them. Hover on the marked words for instant correction suggestions or click the dialoge icon in the bottom right corner to have the whole text proofread at once.</p>
<p>You can also paste your own text here to have its spelling and grammar checked.</p>
</div>
2 changes: 2 additions & 0 deletions docs/_snippets/features/wproofreader.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ ClassicEditor
'mediaEmbed',
'insertTable',
'|',
'wproofreader',
'|',
'undo',
'redo'
],
Expand Down
23 changes: 15 additions & 8 deletions docs/features/spelling-and-grammar-checking.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ menu-title: Spelling and grammar checking
The spell checker for CKEditor 5 is a commercial solution provided by our partner, [WebSpellChecker](https://webspellchecker.com/). You can report any issues in its [GitHub repository](https://github.com/WebSpellChecker/wproofreader). The license can be purchased [here](https://ckeditor.com/contact/).
</info-box>

[WProofreader](https://webspellchecker.com/wsc-proofreader) is an innovative proofreading tool that combines the functionality of "spell check as you type" and "spell check in a dialog" in a modern, distraction-free UI. Spelling and grammar suggestions are available on hover with no clicking needed.
[WProofreader](https://webspellchecker.com/wsc-proofreader) is an innovative, multi-language proofreading tool that combines the functionality of "spell check as you type" and "spell check in a dialog" in a modern, distraction-free UI. Spelling and grammar suggestions are available on hover with no clicking needed or as a convenient dialog, both with additional in-place replacement suggestions.

Readily available settings include several rules of including or ommiting certain cases. You can choose from a set if predefined languages (more may be added as language packs) and manage additional dictionaries. Words can be added to the user dictionary directly from the suggestion card, too.

If needed, the spellchecker can be easily disabled and enabled again with a click.

## Demo

Click in the editor below to enable the spelling and grammar checking. Hover an underlined word to display the proofreader suggestions for any of the spelling and grammar mistakes found.
See the spelling and grammar checking in the editor below.

The proofreader badge in the bottom right corner shows you the number of mistakes detected. Hover on an underlined word to display the proofreader suggestions for any of the spelling and grammar mistakes found. If you want to see an overview of all spelling and grammar mistakes, click the "Proofread in dialog" option in the toolbar dropdown. You can access the proofreader settings from the toolbar, too.

The proofreader badge in the bottom right-hand corner shows you the number of mistakes detected. It also gives you access to proofreader settings. If you want to see an overview of all spelling and grammar mistakes, click the "Proofread in dialog" icon in the badge.
<info-box>
The toolbar button has been introduced in version 2.x of the WProofreader. Read more about configuring UI items in the {@link features/toolbar toolbar guide}. If you are still using version 1.x, the available settings and dialog options are located in the bottom-right indicator.
</info-box>

{@snippet features/wproofreader}

Expand All @@ -33,16 +41,15 @@ WProofreader is delivered as a CKEditor 5 plugin, so it could be combined into a
npm install --save @webspellchecker/wproofreader-ckeditor5
```

Then, add it to your plugin list:
Then, add it to your plugin list and the toolbar configuration:

```js
import WProofreader from '@webspellchecker/wproofreader-ckeditor5/src/wproofreader';
// ...

ClassicEditor
.create( editorElement, {
plugins: [ ..., WProofreader ],
// ...
toolbar: [ ..., 'wproofreader' ]
} )
.then( ... )
.catch( ... );
Expand All @@ -62,11 +69,11 @@ Add the following configuration to your editor:

```js
import WProofreader from '@webspellchecker/wproofreader-ckeditor5/src/wproofreader';
// ...

ClassicEditor
.create( editorElement, {
plugins: [ ..., WProofreader ],
toolbar: [ ..., 'wproofreader' ]
wproofreader: {
serviceId: 'your-service-ID',
srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
Expand All @@ -84,11 +91,11 @@ You will need to add the following configuration to your editor:

```js
import WProofreader from '@webspellchecker/wproofreader-ckeditor5/src/wproofreader';
// ...

ClassicEditor
.create( editorElement, {
plugins: [ ..., WProofreader ],
toolbar: [ ..., 'wproofreader' ]
wproofreader: {
serviceProtocol: 'https',
serviceHost: 'localhost',
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@
},
"devDependencies": {
"@ckeditor/ckeditor5-comments": ">=24.0.0",
"@ckeditor/ckeditor5-dev-docs": "^23.2.0",
"@ckeditor/ckeditor5-dev-env": "^23.2.0",
"@ckeditor/ckeditor5-dev-docs": "^24.0.0",
"@ckeditor/ckeditor5-dev-env": "^24.0.0",
"@ckeditor/ckeditor5-dev-tests": "^23.3.0",
"@ckeditor/ckeditor5-dev-utils": "^23.2.0",
"@ckeditor/ckeditor5-dev-webpack-plugin": "^23.2.0",
"@ckeditor/ckeditor5-dev-utils": "^24.0.0",
"@ckeditor/ckeditor5-dev-webpack-plugin": "^24.0.0",
"@ckeditor/ckeditor5-export-pdf": ">=1.0.0",
"@ckeditor/ckeditor5-export-word": ">=1.0.0",
"@ckeditor/ckeditor5-inspector": "^2.2.1",
"@ckeditor/ckeditor5-pagination": ">=1.0.0",
"@ckeditor/ckeditor5-react": "^3.0.0",
"@ckeditor/ckeditor5-real-time-collaboration": ">=24.0.0",
"@ckeditor/ckeditor5-track-changes": ">=24.0.0",
"@webspellchecker/wproofreader-ckeditor5": "^1.0.5",
"@webspellchecker/wproofreader-ckeditor5": "^2.0.1",
"@wiris/mathtype-ckeditor5": "^7.24.0",
"babel-standalone": "^6.26.0",
"cli-table": "^0.3.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ ClassicEditor
} )
.then( editor => {
window.editor = editor;

// eslint-disable-next-line no-undef
setTimeout( () => window.attachTourBalloon( {
target: window.findToolbarItem( editor.ui.view.toolbar, item => item.label && item.label === 'Block quote' ),
text: 'Click to insert a block quote.'
} ) );
} )
.catch( err => {
console.error( err );
Expand Down
3 changes: 2 additions & 1 deletion packages/ckeditor5-html-embed/src/htmlembed.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import HtmlEmbedEditing from './htmlembedediting';
import HtmlEmbedUI from './htmlembedui';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';

/**
* The HTML embed feature.
Expand All @@ -25,7 +26,7 @@ export default class HtmlEmbed extends Plugin {
* @inheritDoc
*/
static get requires() {
return [ HtmlEmbedEditing, HtmlEmbedUI ];
return [ HtmlEmbedEditing, HtmlEmbedUI, Widget ];
}

/**
Expand Down
5 changes: 3 additions & 2 deletions packages/ckeditor5-html-embed/tests/htmlembed.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import HtmlEmbed from '../src/htmlembed';
import HtmlEmbedUI from '../src/htmlembedui';
import HtmlEmbedEditing from '../src/htmlembedediting';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';

describe( 'HtmlEmbed', () => {
it( 'should require HtmlEmbedEditing and HtmlEmbedUI', () => {
expect( HtmlEmbed.requires ).to.deep.equal( [ HtmlEmbedEditing, HtmlEmbedUI ] );
it( 'should require HtmlEmbedEditing, HtmlEmbedUI and Widget', () => {
expect( HtmlEmbed.requires ).to.deep.equal( [ HtmlEmbedEditing, HtmlEmbedUI, Widget ] );
} );

it( 'should be named', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/ckeditor5-link/src/linkcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export default class LinkCommand extends Command {
writer.setSelection( writer.createPositionAfter( linkRange.end.nodeBefore ) );
}
// If not then insert text node with `linkHref` attribute in place of caret.
// However, since selection in collapsed, attribute value will be used as data for text node.
// However, since selection is collapsed, attribute value will be used as data for text node.
// So, if `href` is empty, do not create text node.
else if ( href !== '' ) {
const attributes = toMap( selection.getAttributes() );
Expand Down
7 changes: 7 additions & 0 deletions packages/ckeditor5-link/src/linkimageediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ function downcastImageLinkManualDecorator( manualDecorators, decorator ) {
const viewFigure = conversionApi.mapper.toViewElement( data.item );
const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );

// The <a> element was removed by the time this converter is executed.
// It may happen when the base `linkHref` and decorator attributes are removed
// at the same time (see #8401).
if ( !linkInImage ) {
return;
}

for ( const [ key, val ] of toMap( attributes ) ) {
conversionApi.writer.setAttribute( key, val, linkInImage );
}
Expand Down
75 changes: 75 additions & 0 deletions packages/ckeditor5-link/tests/linkimageediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,81 @@ describe( 'LinkImageEditing', () => {
'</p>'
);
} );

// See #8401.
it( 'should downcast without error if the image already has no link', () => {
setModelData( model,
'[<image alt="bar" src="sample.jpg"></image>]'
);

editor.execute( 'link', 'https://cksource.com', {
linkIsDownloadable: true,
linkIsExternal: true,
linkIsGallery: true
} );

// Attributes will be removed along with the link, but the downcast will be fired.
// The lack of link should not affect the downcasting.
expect( () => {
editor.execute( 'unlink', 'https://cksource.com', {
linkIsDownloadable: true,
linkIsExternal: true,
linkIsGallery: true
} );
} ).to.not.throw();

expect( editor.getData() ).to.equal(
'<figure class="image">' +
'<img src="sample.jpg" alt="bar">' +
'</figure>'
);
} );

// See #8401.
describe( 'order of model updates', () => {
it( 'should not affect converters - base link attributes first', () => {
setModelData( model,
'[<image src="https://cksource.com"></image>]'
);

model.change( writer => {
const ranges = model.schema.getValidRanges( model.document.selection.getRanges(), 'linkIsDownloadable' );

for ( const range of ranges ) {
// The `linkHref` should be processed first - this is the default order of `LinkCommand`.
writer.setAttribute( 'linkHref', 'url', range );
writer.setAttribute( 'linkIsDownloadable', true, range );
}
} );

expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
'<image linkHref="url" linkIsDownloadable="true" src="https://cksource.com"></image>'
);
} );

it( 'should not affect converters - decorators first', () => {
setModelData( model,
'[<image src="https://cksource.com"></image>]'
);

model.change( writer => {
const ranges = model.schema.getValidRanges( model.document.selection.getRanges(), 'linkIsDownloadable' );

for ( const range of ranges ) {
// Here we force attributes to be set on a model in a different order
// to force unusual order of downcast converters down the line.
// Normally, the `linkHref` gets processed first, as it is just the first property assigned
// to the model by `LinkCommand`.
writer.setAttribute( 'linkIsDownloadable', true, range );
writer.setAttribute( 'linkHref', 'url', range );
}
} );

expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
'<image linkHref="url" linkIsDownloadable="true" src="https://cksource.com"></image>'
);
} );
} );
} );
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
*/

.ck.ck-character-grid {
max-width: 100%;

& .ck-character-grid__tiles {
display: grid;
grid-template-columns: repeat( 10, 1fr );
}
}
12 changes: 6 additions & 6 deletions packages/ckeditor5-table/src/converters/tableproperties.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export function upcastStyleToAttribute( conversion, modelElement, modelAttribute
*/
export function upcastBorderStyles( conversion, viewElementName ) {
conversion.for( 'upcast' ).add( dispatcher => dispatcher.on( 'element:' + viewElementName, ( evt, data, conversionApi ) => {
// If the element was not converted by element-to-element converter,
// we should not try to convert the style. See #8393.
if ( !data.modelRange ) {
return;
}

// TODO: this is counter-intuitive: ie.: if only `border-top` is defined then `hasStyle( 'border' )` also returns true.
// TODO: this might needs to be fixed in styles normalizer.
const stylesToConsume = [
Expand All @@ -60,12 +66,6 @@ export function upcastBorderStyles( conversion, viewElementName ) {
return;
}

// This can happen when the upcasted table is nested table. As to why it happens, it remains a mystery.
// Take a look at https://github.com/ckeditor/ckeditor5/issues/6177.
if ( !data.modelRange ) {
data = Object.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );
}

const modelElement = [ ...data.modelRange.getItems( { shallow: true } ) ].pop();

conversionApi.consumable.consume( data.viewItem, matcherPattern );
Expand Down
34 changes: 20 additions & 14 deletions packages/ckeditor5-table/src/tableproperties/tablepropertiesui.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ export default class TablePropertiesUI extends Plugin {
*/
_createPropertiesView() {
const editor = this.editor;
const viewDocument = editor.editing.view.document;
const config = editor.config.get( 'table.tableProperties' );
const borderColorsConfig = normalizeColorOptions( config.borderColors );
const localizedBorderColors = getLocalizedColorOptions( editor.locale, borderColorsConfig );
Expand Down Expand Up @@ -185,15 +184,6 @@ export default class TablePropertiesUI extends Plugin {
cancel();
} );

// Reposition the balloon or hide the form if a table is no longer selected.
this.listenTo( editor.ui, 'update', () => {
if ( !getTableWidgetAncestor( viewDocument.selection ) ) {
this._hideView();
} else if ( this._isViewVisible ) {
repositionContextualBalloon( editor, 'table' );
}
} );

// Close on click outside of balloon panel element.
clickOutsideHandler( {
emitter: view,
Expand Down Expand Up @@ -282,6 +272,10 @@ export default class TablePropertiesUI extends Plugin {
_showView() {
const editor = this.editor;

this.listenTo( editor.ui, 'update', () => {
this._updateView();
} );

// Update the view with the model values.
this._fillViewFormFromCommandValues();

Expand All @@ -303,10 +297,6 @@ export default class TablePropertiesUI extends Plugin {
* @protected
*/
_hideView() {
if ( !this._isViewInBalloon ) {
return;
}

const editor = this.editor;

this.stopListening( editor.ui, 'update' );
Expand All @@ -322,6 +312,22 @@ export default class TablePropertiesUI extends Plugin {
this.editor.editing.view.focus();
}

/**
* Repositions the {@link #_balloon} or hides the {@link #view} if a table is no longer selected.
*
* @protected
*/
_updateView() {
const editor = this.editor;
const viewDocument = editor.editing.view.document;

if ( !getTableWidgetAncestor( viewDocument.selection ) ) {
this._hideView();
} else if ( this._isViewVisible ) {
repositionContextualBalloon( editor, 'table' );
}
}

/**
* Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.
*
Expand Down
2 changes: 1 addition & 1 deletion packages/ckeditor5-table/tests/tableclipboard-paste.js
Original file line number Diff line number Diff line change
Expand Up @@ -3968,7 +3968,7 @@ describe( 'table clipboard', () => {
);

assertEqualMarkup( getModelData( model, { withoutSelection: true } ), modelTable( [
[ '<paragraph>Test</paragraph><paragraph></paragraph>' ]
[ '<paragraph>Test</paragraph>' ]
] ) );
} );
} );
Expand Down
Loading

0 comments on commit 6fc38c0

Please sign in to comment.