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

Feature: Introduced PendingActions plugin. #127

Merged
merged 18 commits into from
May 15, 2018
Merged

Feature: Introduced PendingActions plugin. #127

merged 18 commits into from
May 15, 2018

Conversation

oskarwrobel
Copy link
Contributor

@oskarwrobel oskarwrobel commented May 10, 2018

Suggested merge commit message (convention)

Feature: Introduced PendingActions plugin. Closes ckeditor/ckeditor5#2934.


This is a very basic implementation that covers all current needs.

It is possible to add pending action with a custom message and change this message. Message is observable.

Besides plugin listens to window#beforeunload event and displays prompt in a case of pending action.

const action = this.editor.plugins.get( 'PendingActions' ).add( 'Custom message' );

action.message = 'New message';

this.editor.plugins.get( 'PendingActions' ).remove( action );

@coveralls
Copy link

coveralls commented May 10, 2018

Coverage Status

Coverage remained the same at 100.0% when pulling 7da48ce on t/126 into 7e7b950 on master.

*/
add( message ) {
if ( typeof message !== 'string' ) {
throw new CKEditorError( 'pendingactions-add-invalid-message: Message has to be a string.' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing docs for the pendingactions-add-invalid-message error.

See

/**
* Cannot load a plugin because one of its dependencies is listed in the `removePlugins` option.
*
* @error plugincollection-required
* @param {Function} plugin The required plugin.
* @param {Function} requiredBy The parent plugin.
*/
throw new CKEditorError(
'plugincollection-required: Cannot load a plugin because one of its dependencies is listed in' +
'the `removePlugins` option.',
{ plugin: RequiredPluginConstructor, requiredBy: PluginConstructor }
);
.

Copy link
Contributor Author

@oskarwrobel oskarwrobel May 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK there is no need to add docs to the error when an additional explanation is not necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you miss the @error JSDoc tag, the error will not appear on the error codes page:

image

After adding:

+/**
+ * Some docs for the error.
+ *
+ * @error pendingactions-add-invalid-message
+ */
throw new CKEditorError( 'pendingactions-add-invalid-message: Message has to be a string.' );

the error appears:

image

One more thing. When I built the docs, I noticed that:

No errors found during the validation.
WARNING: The @type tag does not permit a description; the description will be ignored. File: pendingactions.js, line: 55

Should it be @member instead of @type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we have more errors without docs and probably we should fix them too. I'll add docs to this error. And I'll change @type to @member :) Thx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have more errors without docs

Would be good to verify this and report as a new ticket.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OTOH I still think that additional explanation for this error is not necessary because the error message is clear and we don't need to explain it in the docs. @pjasiun WDYT? Should we always add docs to error or only when error needs an additional explanation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to introduce any additional description. See here – https://github.com/ckeditor/ckeditor5-engine/blob/a721f95601511a6fcbb7d43becb957af64f2d157/src/view/attributeelement.js#L109-L117

We need the proper documentation for the error in docs, so

/**
 * Message has to be a string.
 *
 * @error pendingactions-add-invalid-message
 */

is enough.

Copy link
Contributor Author

@oskarwrobel oskarwrobel May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. But I'm not sure if documentation for this kind of errors is really necessary. We have more undocumented errors. Let's wait for @pjasiun or @Reinmar comment. If we decided to document all errors because we want to have them in generated docs then it's fine and I'll add this doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I checked and each new type of error needs docs. When the error is repeated then docs is not necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

throw new CKEditorError( 'pendingactions-add-invalid-message: Message has to be a string.' );
}

const observable = Object.create( ObservableMixin );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable should be called action, instead of observable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/* istanbul ignore next */
this._domEmitter.listenTo( window, 'beforeunload', ( evtInfo, domEvt ) => {
if ( this.isPending ) {
domEvt.returnValue = this._actions.get( 0 ).message;
Copy link

@pjasiun pjasiun May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since getting the first action looks like a common case, maybe we should have: this.get, which will do this._actions.get or the property first?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More I think about it, more I feel that the plugin should have Collection API. Not everybody feels comfortable with iterators (even you used _actions.get( 0 ), it is more convenient). So as much as I love iterator, I think that get and length should be also provided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In f2f talk we decided to add getter first for getting first pending action from the list.

.then( () => wait( 500 ) )
.then( () => ( action.message = 'Dynamic pending action 80%.' ) )
.then( () => wait( 500 ) )
.then( () => ( action.message = 'Dynamic pending action 1000%.' ) )
Copy link

@pjasiun pjasiun May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1000%?
That Escalated Quickly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const action = pendingActions.add( 'Static pending action.' );

wait( 5000 ).then( () => pendingActions.remove( action ) );
} );
Copy link

@pjasiun pjasiun May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these "static pending actions"? Can't we have only one type of actions in this manual tests (dynamic)? More buttons in manual tests mean more things to click, to test, more code to maintain. If "dynamic" pending actions cover all cases lets make it simple.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/**
* Adds action to the list of pending actions.
*
* Methods returns an object with observable message property. Message can be changed.
Copy link

@pjasiun pjasiun May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method returns an action object with observable message property. The action object can be later used in the remove method. It also allows you to change the message.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it would be useful to put an example here.

/**
* List of editor pending actions.
*
* Any asynchronous action that should be finished before the editor destroy (like file upload) should be registered
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be finished before the editor destroy

This plugin has nothing to do with editing destroy. It is to handle long-lasting actions. To synchronise plugins which execute such action (i.e. file upload) and the editor integration. It gives a developer, who integrates the editor, an easy way to check if there are any pending action whenever such information is needed. All plugins, which register pending action provides also a message what action is ongoing which can be displayed to a user and let him decide if he wants to interrupt the action or wait. This plugin is not able to interrupt actions or manage that in any other way.

if ( this.isPending ) {
domEvt.returnValue = this.first.message;
}
} );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked with @Reinmar and agreed that this logic is not needed with no autosave plugin so we should move it there. If one does not use autosave plugins, he also does not care about closing browser with pending action. Content is not saved anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* All plugins, which register pending action provides also a message what action is ongoing
* which can be displayed to a user and let him decide if he wants to interrupt the action or wait.
*
* This plugin listens to `window#beforeunload` event and displays browser prompt when a pending action is in progress.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not anymore.

* const pendingActions = editor.plugins.get( 'PendingActions' );
* const action = pendingActions.add( 'Upload in progress 0%' );
*
* action.message = 'Upload in progress 10%';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no example how to remove action.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I would move the whole sample to the plugin description.

* action.message = 'Upload in progress 10%';
*
* @param {String} message
* @returns {Object} Observable object that represents a pending action.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to describe properties.

* pendingActions.add( 'Action 2' );
*
* pendingActions.first // Returns 'Action 1'
* Array.from( pendingActions ) // Returns [ 'Action 1', 'Action 2' ]
Copy link

@pjasiun pjasiun May 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this sample shows usage of not only this method by also iterator interface I would move it to the class description.


1. Click `Add pending actions`
2. Check if action message is changing (action should disappear when progress reaches 100%)
3. Try to reload page or close the browser tab when pending action is displayed, you should see a prompt
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not make sense now. We could have some "finish" button to check if it works.

Copy link

@pjasiun pjasiun May 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or you can add onbeforeunload integration to the sample.

@pjasiun pjasiun merged commit e1af648 into master May 15, 2018
@pjasiun pjasiun deleted the t/126 branch May 15, 2018 15:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
4 participants