This repository has been archived by the owner on Jun 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Introduced notification plugin. Closes #189.
- Loading branch information
Showing
2 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/** | ||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
*/ | ||
|
||
/** | ||
* @module ui/notification | ||
*/ | ||
|
||
/* globals window */ | ||
|
||
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | ||
|
||
/** | ||
* The Notification plugin. | ||
* | ||
* This plugin sends few base types of notifications: `success`, `info` and `warning`. This notifications need to be | ||
* handled and displayed by plugin responsible for showing UI of the notifications. Using this plugin for dispatching | ||
* notifications makes possible to switch the notifications UI. | ||
* | ||
* Note that every unhandled and not stopped `warning` notification will be displayed as system alert. | ||
* See {@link module:ui/notification~Notification#showWarning}. | ||
* | ||
* @extends module:core/plugin~Plugin | ||
*/ | ||
export default class Notification extends Plugin { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'notification'; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
// Each unhandled and not stopped `show:warning` event is displayed as system alert. | ||
this.on( 'show:warning', ( evt, data ) => { | ||
window.alert( data.message ); | ||
}, { priority: 'lowest' } ); | ||
} | ||
|
||
/** | ||
* Shows success notification. | ||
* | ||
* At default it fires `show:success` event with given data but event namespace can be extended | ||
* by `data.namespace` option e.g. | ||
* | ||
* showSuccess( 'Image is uploaded.', { | ||
* namespace: 'upload:image' | ||
* } ); | ||
* | ||
* will fire `show:success:upload:image` event. | ||
* | ||
* @param {String} message Content of the notification. | ||
* @param {Object} [data={}] Additional data. | ||
* @param {String} [data.namespace] Additional event namespace. | ||
*/ | ||
showSuccess( message, data = {} ) { | ||
this._showNotification( { | ||
message: message, | ||
type: 'success', | ||
namespace: data.namespace | ||
} ); | ||
} | ||
|
||
/** | ||
* Shows info notification. | ||
* | ||
* At default it fires `show:info` event with given data but event namespace can be extended | ||
* by `data.namespace` option e.g. | ||
* | ||
* showInfo( 'Editor is offline.', { | ||
* namespace: 'editor:status' | ||
* } ); | ||
* | ||
* will fire `show:info:editor:status` event. | ||
* | ||
* @param {String} message Content of the notification. | ||
* @param {Object} [data={}] Additional data. | ||
* @param {String} [data.namespace] Additional event namespace. | ||
*/ | ||
showInfo( message, data = {} ) { | ||
this._showNotification( { | ||
message: message, | ||
type: 'info', | ||
namespace: data.namespace | ||
} ); | ||
} | ||
|
||
/** | ||
* Shows warning notification. | ||
* | ||
* At default it fires `show:warning` event with given data but event namespace can be extended | ||
* by `data.namespace` option e.g. | ||
* | ||
* showWarning( 'Image upload error.', { | ||
* namespace: 'upload:image' | ||
* } ); | ||
* | ||
* will fire `show:warning:upload:image` event. | ||
* | ||
* Note that each unhandled and not stopped `warning` notification will be displayed as system alert. | ||
* Plugin responsible for displaying warnings should `stop()` the event to prevent of displaying it as alert: | ||
* | ||
* notifications.on( 'show:warning', ( evt, data ) => { | ||
* // Do something with data. | ||
* | ||
* // Stop this event to prevent of displaying as alert. | ||
* evt.stop(); | ||
* } ); | ||
* | ||
* You can attach many listeners to the same event and `stop()` this event in the listener with the low priority: | ||
* | ||
* notifications.on( 'show:warning', ( evt, data ) => { | ||
* // Show warning in the UI, but not stop it. | ||
* } ); | ||
* | ||
* notifications.on( 'show:warning', ( evt, data ) => { | ||
* // Log warning to some error tracker. | ||
* | ||
* // Stop this event to prevent of displaying as alert. | ||
* evt.stop(); | ||
* }, { priority: 'low' } ); | ||
* | ||
* @param {String} message Content of the notification. | ||
* @param {Object} [data={}] Additional data. | ||
* @param {String} [data.namespace] Additional event namespace. | ||
*/ | ||
showWarning( message, data = {} ) { | ||
this._showNotification( { | ||
message: message, | ||
type: 'warning', | ||
namespace: data.namespace | ||
} ); | ||
} | ||
|
||
/** | ||
* Fires `show` event with specified type, namespace and message. | ||
* | ||
* @private | ||
* @param {Object} data Message data. | ||
* @param {String} data.message Content of the notification. | ||
* @param {'success'|'info'|'warning'} data.type Type of message. | ||
* @param {String} [data.namespace] Additional event namespace. | ||
*/ | ||
_showNotification( data ) { | ||
const event = `show:${ data.type }` + ( data.namespace ? `:${ data.namespace }` : '' ); | ||
|
||
this.fire( event, { | ||
message: data.message, | ||
type: data.type | ||
} ); | ||
} | ||
|
||
/** | ||
* Fired when one of `showSuccess`, `showInfo`, `showWarning` methods is called. | ||
* | ||
* @event show | ||
* @param {Object} data Notification data. | ||
* @param {String} data.message Content of the notification. | ||
* @param {'success'|'info'|'warning'} data.type Type of notification. | ||
*/ | ||
|
||
/** | ||
* Fired when `showSuccess` method is called. | ||
* | ||
* @event show:success | ||
* @param {Object} data Notification data. | ||
* @param {String} data.message Content of the notification. | ||
* @param {'success'} data.type Type of notification. | ||
*/ | ||
|
||
/** | ||
* Fired when `showInfo` method is called. | ||
* | ||
* @event show:info | ||
* @param {Object} data Notification data. | ||
* @param {String} data.message Content of the notification. | ||
* @param {'info'} data.type Type of notification. | ||
*/ | ||
|
||
/** | ||
* Fired when `showWarning` method is called. | ||
* | ||
* When this event won't be handled and stopped by `event.stop()` then data.message of this event will | ||
* be automatically displayed as system alert. | ||
* | ||
* @event show:warning | ||
* @param {Object} data Notification data. | ||
* @param {String} data.message Content of the notification. | ||
* @param {'warning'} data.type Type of notification. | ||
*/ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/** | ||
* Copyright (c) 2016, CKSource - Frederico Knabben. All rights reserved. | ||
*/ | ||
|
||
/* globals window */ | ||
|
||
import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; | ||
import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; | ||
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | ||
import Notification from '../../src/notification/notification'; | ||
|
||
describe( 'Notification', () => { | ||
let editor, notification; | ||
|
||
testUtils.createSinonSandbox(); | ||
|
||
beforeEach( () => { | ||
return VirtualTestEditor.create( { | ||
plugins: [ Notification ] | ||
} ) | ||
.then( newEditor => { | ||
editor = newEditor; | ||
notification = editor.plugins.get( Notification ); | ||
} ); | ||
} ); | ||
|
||
describe( 'init()', () => { | ||
it( 'should create notification plugin', () => { | ||
expect( notification ).to.instanceof( Notification ); | ||
expect( notification ).to.instanceof( Plugin ); | ||
} ); | ||
} ); | ||
|
||
describe( 'showSuccess()', () => { | ||
it( 'should fire `show:success` event with given data', () => { | ||
const spy = testUtils.sinon.spy(); | ||
|
||
notification.on( 'show:success', spy ); | ||
|
||
notification.showSuccess( 'foo bar' ); | ||
|
||
sinon.assert.calledOnce( spy ); | ||
expect( spy.firstCall.args[ 1 ] ).to.deep.equal( { | ||
message: 'foo bar', | ||
type: 'success' | ||
} ); | ||
} ); | ||
|
||
it( 'should fire `show:success` event with additional namespace', () => { | ||
const spy = testUtils.sinon.spy(); | ||
|
||
notification.on( 'show:success:something:else', spy ); | ||
|
||
notification.showSuccess( 'foo bar', { | ||
namespace: 'something:else' | ||
} ); | ||
|
||
sinon.assert.calledOnce( spy ); | ||
expect( spy.firstCall.args[ 1 ] ).to.deep.equal( { | ||
message: 'foo bar', | ||
type: 'success' | ||
} ); | ||
} ); | ||
} ); | ||
|
||
describe( 'showInfo()', () => { | ||
it( 'should fire `show:info` event with given data', () => { | ||
const spy = testUtils.sinon.spy(); | ||
|
||
notification.on( 'show:info', spy ); | ||
|
||
notification.showInfo( 'foo bar' ); | ||
|
||
sinon.assert.calledOnce( spy ); | ||
expect( spy.firstCall.args[ 1 ] ).to.deep.equal( { | ||
message: 'foo bar', | ||
type: 'info' | ||
} ); | ||
} ); | ||
|
||
it( 'should fire `show:info` event with additional namespace', () => { | ||
const spy = testUtils.sinon.spy(); | ||
|
||
notification.on( 'show:info:something:else', spy ); | ||
|
||
notification.showInfo( 'foo bar', { | ||
namespace: 'something:else' | ||
} ); | ||
|
||
sinon.assert.calledOnce( spy ); | ||
expect( spy.firstCall.args[ 1 ] ).to.deep.equal( { | ||
message: 'foo bar', | ||
type: 'info' | ||
} ); | ||
} ); | ||
} ); | ||
|
||
describe( 'showWarning()', () => { | ||
let alertStub; | ||
|
||
beforeEach( () => { | ||
alertStub = testUtils.sinon.stub( window, 'alert' ); | ||
} ); | ||
|
||
it( 'should fire `show:warning` event with given data', () => { | ||
const spy = testUtils.sinon.spy(); | ||
|
||
notification.on( 'show:warning', spy ); | ||
|
||
notification.showWarning( 'foo bar' ); | ||
|
||
sinon.assert.calledOnce( spy ); | ||
expect( spy.firstCall.args[ 1 ] ).to.deep.equal( { | ||
message: 'foo bar', | ||
type: 'warning' | ||
} ); | ||
} ); | ||
|
||
it( 'should fire `show:warning` event with additional namespace', () => { | ||
const spy = testUtils.sinon.spy(); | ||
|
||
notification.on( 'show:warning:something:else', spy ); | ||
|
||
notification.showWarning( 'foo bar', { | ||
namespace: 'something:else' | ||
} ); | ||
|
||
sinon.assert.calledOnce( spy ); | ||
expect( spy.firstCall.args[ 1 ] ).to.deep.equal( { | ||
message: 'foo bar', | ||
type: 'warning' | ||
} ); | ||
} ); | ||
|
||
it( 'should display `warning` message as system alert if is not cached and stopped by other plugins', () => { | ||
notification.showWarning( 'foo bar' ); | ||
|
||
sinon.assert.calledOnce( alertStub ); | ||
expect( alertStub.firstCall.args[ 0 ] ).to.equal( 'foo bar' ); | ||
} ); | ||
|
||
it( 'should not display alert when `warning` message is cached and stopped by other plugins', () => { | ||
notification.on( 'show:warning', evt => { | ||
evt.stop(); | ||
} ); | ||
|
||
notification.showWarning( 'foo bar' ); | ||
|
||
sinon.assert.notCalled( alertStub ); | ||
} ); | ||
} ); | ||
} ); |