]> git.immae.eu Git - perso/Immae/Projets/packagist/ludivine-ckeditor-component.git/blob - sources/plugins/notification/plugin.js
Update to 4.7.3
[perso/Immae/Projets/packagist/ludivine-ckeditor-component.git] / sources / plugins / notification / plugin.js
1 /**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 /**
7 * @fileOverview The "Notification" plugin.
8 *
9 */
10
11 'use strict';
12
13 CKEDITOR.plugins.add( 'notification', {
14 lang: 'az,ca,cs,da,de,de-ch,en,eo,es,es-mx,eu,fr,gl,hr,hu,id,it,ja,km,ko,ku,nb,nl,oc,pl,pt,pt-br,ru,sk,sv,tr,ug,uk,zh,zh-cn', // %REMOVE_LINE_CORE%
15
16 init: function( editor ) {
17 editor._.notificationArea = new Area( editor );
18
19 // Overwrites default `editor.showNotification`.
20 editor.showNotification = function( message, type, progressOrDuration ) {
21 var progress, duration;
22
23 if ( type == 'progress' ) {
24 progress = progressOrDuration;
25 } else {
26 duration = progressOrDuration;
27 }
28
29 var notification = new CKEDITOR.plugins.notification( editor, {
30 message: message,
31 type: type,
32 progress: progress,
33 duration: duration
34 } );
35
36 notification.show();
37
38 return notification;
39 };
40
41 // Close the last notification on ESC.
42 editor.on( 'key', function( evt ) {
43 if ( evt.data.keyCode == 27 ) { /* ESC */
44 var notifications = editor._.notificationArea.notifications;
45
46 if ( !notifications.length ) {
47 return;
48 }
49
50 // As long as this is not a common practice to inform screen-reader users about actions, in this case
51 // this is the best solution (unfortunately there is no standard for accessibility for notifications).
52 // Notification has an `alert` aria role what means that it does not get a focus nor is needed to be
53 // closed (unlike `alertdialog`). However notification will capture ESC key so we need to inform user
54 // why it does not do other actions.
55 say( editor.lang.notification.closed );
56
57 // Hide last.
58 notifications[ notifications.length - 1 ].hide();
59
60 evt.cancel();
61 }
62 } );
63
64 // Send the message to the screen readers.
65 function say( text ) {
66 var message = new CKEDITOR.dom.element( 'div' );
67 message.setStyles( {
68 position: 'fixed',
69 'margin-left': '-9999px'
70 } );
71 message.setAttributes( {
72 'aria-live': 'assertive',
73 'aria-atomic': 'true'
74 } );
75 message.setText( text );
76
77 CKEDITOR.document.getBody().append( message );
78
79 setTimeout( function() {
80 message.remove();
81 }, 100 );
82 }
83 }
84 } );
85
86 /**
87 * Notification class. Notifications are used to display short messages to the user. They might be used to show the result of
88 * asynchronous actions or information about changes in the editor content. It is recommended to use them instead of
89 * alert dialogs. They should **not** be used if a user response is required nor with dialog windows (e.g. in dialog validation).
90 *
91 * There are four types of notifications available, see the {@link #type} property.
92 *
93 * Note that the notification constructor only creates a notification instance. To show it, use the {@link #show} method:
94 *
95 * var notification = new CKEDITOR.plugins.notification( editor, { message: 'Foo' } );
96 * notification.show();
97 *
98 * You can also use the {@link CKEDITOR.editor#showNotification} method:
99 *
100 * editor.showNotification( 'Foo' );
101 *
102 * All of the notification actions: ({@link #show}, {@link #update} and {@link #hide}) fire cancelable events
103 * on the related {@link CKEDITOR.editor} instance so you can integrate editor notifications with your website notifications.
104 *
105 * Refer to the [Notifications](http://docs.ckeditor.com/#!/guide/dev_notifications) article for more information about this feature.
106 *
107 * @since 4.5
108 * @class CKEDITOR.plugins.notification
109 * @constructor Create a notification object. Call {@link #show} to show the created notification.
110 * @param {CKEDITOR.editor} editor The editor instance.
111 * @param {Object} options
112 * @param {String} options.message The message displayed in the notification.
113 * @param {String} [options.type='info'] Notification type, see {@link #type}.
114 * @param {Number} [options.progress=0] If the type is `progress` this may be a progress from 0 to 1.
115 * @param {Number} [options.duration] How long the notification will be visible, see {@link #duration}.
116 */
117 function Notification( editor, options ) {
118 CKEDITOR.tools.extend( this, options, {
119 editor: editor,
120 id: 'cke-' + CKEDITOR.tools.getUniqueId(),
121 area: editor._.notificationArea
122 } );
123
124 if ( !options.type ) {
125 this.type = 'info';
126 }
127
128 this.element = this._createElement();
129
130 // Don't allow dragging on notification (http://dev.ckeditor.com/ticket/13184).
131 editor.plugins.clipboard && CKEDITOR.plugins.clipboard.preventDefaultDropOnElement( this.element );
132 }
133
134 /**
135 * The editor instance.
136 *
137 * @readonly
138 * @property {CKEDITOR.editor} editor
139 */
140
141 /**
142 * Message displayed in the notification.
143 *
144 * @readonly
145 * @property {String} message
146 */
147
148 /**
149 * Notification type. There are four types available:
150 *
151 * * `info` (default) – Information for the user (e.g. "File is uploading.", "ACF modified content."),
152 * * `warning` – Warning or error message (e.g. "This type of file is not supported.",
153 * "You cannot paste the script."),
154 * * `success` – Information that an operation finished successfully (e.g. "File uploaded.", "Data imported.").
155 * * `progress` – Information about the progress of an operation. When the operation is done, the notification
156 * type should be changed to `success`.
157 *
158 * @readonly
159 * @property {String} type
160 */
161
162 /**
163 * If the notification {@link #type} is `'progress'`, this is the progress from `0` to `1`.
164 *
165 * @readonly
166 * @property {Number} progress
167 */
168
169 /**
170 * Notification duration. Determines after how many milliseconds the notification should close automatically.
171 * `0` means that the notification will not close automatically and that the user needs to close it manually.
172 * The default value for `warning` and `progress` notifications is `0`. For `info` and `success` the value can
173 * either be set through the {@link CKEDITOR.config#notification_duration} configuration option or equals `5000`
174 * if the configuration option is not set.
175 *
176 * @readonly
177 * @property {Number} duration
178 */
179
180 /**
181 * Unique notification ID.
182 *
183 * @readonly
184 * @property {Number} id
185 */
186
187 /**
188 * Notification DOM element. There is one element per notification. It is created when the notification is created,
189 * even if it is not shown. If the notification is hidden, the element is detached from the document but not deleted.
190 * It will be reused if the notification is shown again.
191 *
192 * @readonly
193 * @property {CKEDITOR.dom.element} element
194 */
195
196 /**
197 * {@link CKEDITOR.plugins.notification.area Notification area} reference.
198 *
199 * @readonly
200 * @property {CKEDITOR.plugins.notification.area} area
201 */
202
203 Notification.prototype = {
204 /**
205 * Adds the notification element to the notification area. The notification will be hidden automatically if
206 * {@link #duration} is set.
207 *
208 * Fires the {@link CKEDITOR.editor#notificationShow} event.
209 */
210 show: function() {
211 if ( this.editor.fire( 'notificationShow', { notification: this } ) === false ) {
212 return;
213 }
214
215 this.area.add( this );
216
217 this._hideAfterTimeout();
218 },
219
220 /**
221 * Updates the notification object and element.
222 *
223 * Fires the {@link CKEDITOR.editor#notificationUpdate} event.
224 *
225 * @param {Object} options
226 * @param {String} [options.message] {@link #message}
227 * @param {String} [options.type] {@link #type}
228 * @param {Number} [options.progress] {@link #progress}
229 * @param {Number} [options.duration] {@link #duration}
230 * @param {Boolean} [options.important=false] If the update is important, the notification will be shown
231 * if it was hidden and read by screen readers.
232 */
233 update: function( options ) {
234 var show = true;
235
236 if ( this.editor.fire( 'notificationUpdate', { notification: this, options: options } ) === false ) {
237 // The idea of cancelable event is to let user create his own way of displaying notification, so if
238 // `notificationUpdate` event will be canceled there will be no interaction with notification area, but on
239 // the other hand the logic should work anyway so object will be updated (including `element` property).
240 // Note: we can safely update the element's attributes below, because this element is created inside
241 // the constructor. If the notificatinShow event was canceled as well, the element is detached from DOM.
242 show = false;
243 }
244
245 var element = this.element,
246 messageElement = element.findOne( '.cke_notification_message' ),
247 progressElement = element.findOne( '.cke_notification_progress' ),
248 type = options.type;
249
250 element.removeAttribute( 'role' );
251
252 // Change type to progress if `options.progress` is set.
253 if ( options.progress && this.type != 'progress' ) {
254 type = 'progress';
255 }
256
257 if ( type ) {
258 element.removeClass( this._getClass() );
259 element.removeAttribute( 'aria-label' );
260
261 this.type = type;
262
263 element.addClass( this._getClass() );
264 element.setAttribute( 'aria-label', this.type );
265
266 if ( this.type == 'progress' && !progressElement ) {
267 progressElement = this._createProgressElement();
268 progressElement.insertBefore( messageElement );
269 } else if ( this.type != 'progress' && progressElement ) {
270 progressElement.remove();
271 }
272 }
273
274 if ( options.message !== undefined ) {
275 this.message = options.message;
276 messageElement.setHtml( this.message );
277 }
278
279 if ( options.progress !== undefined ) {
280 this.progress = options.progress;
281
282 if ( progressElement ) {
283 progressElement.setStyle( 'width', this._getPercentageProgress() );
284 }
285 }
286
287 if ( show && options.important ) {
288 element.setAttribute( 'role', 'alert' );
289
290 if ( !this.isVisible() ) {
291 this.area.add( this );
292 }
293 }
294
295 // Overwrite even if it is undefined.
296 this.duration = options.duration;
297
298 this._hideAfterTimeout();
299 },
300
301 /**
302 * Removes the notification element from the notification area.
303 *
304 * Fires the {@link CKEDITOR.editor#notificationHide} event.
305 */
306 hide: function() {
307 if ( this.editor.fire( 'notificationHide', { notification: this } ) === false ) {
308 return;
309 }
310
311 this.area.remove( this );
312 },
313
314 /**
315 * Returns `true` if the notification is in the notification area.
316 *
317 * @returns {Boolean} `true` if the notification is in the notification area.
318 */
319 isVisible: function() {
320 return CKEDITOR.tools.indexOf( this.area.notifications, this ) >= 0;
321 },
322
323 /**
324 * Creates the notification DOM element.
325 *
326 * @private
327 * @returns {CKEDITOR.dom.element} Notification DOM element.
328 */
329 _createElement: function() {
330 var notification = this,
331 notificationElement, notificationMessageElement, notificationCloseElement,
332 close = this.editor.lang.common.close;
333
334 notificationElement = new CKEDITOR.dom.element( 'div' );
335 notificationElement.addClass( 'cke_notification' );
336 notificationElement.addClass( this._getClass() );
337 notificationElement.setAttributes( {
338 id: this.id,
339 role: 'alert',
340 'aria-label': this.type
341 } );
342
343 if ( this.type == 'progress' )
344 notificationElement.append( this._createProgressElement() );
345
346 notificationMessageElement = new CKEDITOR.dom.element( 'p' );
347 notificationMessageElement.addClass( 'cke_notification_message' );
348 notificationMessageElement.setHtml( this.message );
349 notificationElement.append( notificationMessageElement );
350
351 notificationCloseElement = CKEDITOR.dom.element.createFromHtml(
352 '<a class="cke_notification_close" href="javascript:void(0)" title="' + close + '" role="button" tabindex="-1">' +
353 '<span class="cke_label">X</span>' +
354 '</a>' );
355 notificationElement.append( notificationCloseElement );
356
357 notificationCloseElement.on( 'click', function() {
358 // Focus editor on close (http://dev.ckeditor.com/ticket/12865)
359 notification.editor.focus();
360
361 notification.hide();
362 } );
363
364 return notificationElement;
365 },
366
367 /**
368 * Gets the notification CSS class.
369 *
370 * @private
371 * @returns {String} Notification CSS class.
372 */
373 _getClass: function() {
374 return ( this.type == 'progress' ) ?
375 'cke_notification_info' :
376 ( 'cke_notification_' + this.type );
377 },
378
379 /**
380 * Creates a progress element for the notification element.
381 *
382 * @private
383 * @returns {CKEDITOR.dom.element} Progress element for the notification element.
384 */
385 _createProgressElement: function() {
386 var element = new CKEDITOR.dom.element( 'span' );
387 element.addClass( 'cke_notification_progress' );
388 element.setStyle( 'width', this._getPercentageProgress() );
389 return element;
390 },
391
392 /**
393 * Gets the progress as a percentage (ex. `0.3` -> `30%`).
394 *
395 * @private
396 * @returns {String} Progress as a percentage.
397 */
398 _getPercentageProgress: function() {
399 return Math.round( ( this.progress || 0 ) * 100 ) + '%';
400 },
401
402 /**
403 * Hides the notification after a timeout.
404 *
405 * @private
406 */
407 _hideAfterTimeout: function() {
408 var notification = this,
409 duration;
410
411 if ( this._hideTimeoutId ) {
412 clearTimeout( this._hideTimeoutId );
413 }
414
415 if ( typeof this.duration == 'number' ) {
416 duration = this.duration;
417 } else if ( this.type == 'info' || this.type == 'success' ) {
418 duration = ( typeof this.editor.config.notification_duration == 'number' ) ?
419 this.editor.config.notification_duration :
420 5000;
421 }
422
423 if ( duration ) {
424 notification._hideTimeoutId = setTimeout( function() {
425 notification.hide();
426 }, duration );
427 }
428 }
429 };
430
431 /**
432 * Notification area is an area where all notifications are put. The area is laid out dynamically.
433 * When the first notification is added, the area is shown and all listeners are added.
434 * When the last notification is removed, the area is hidden and all listeners are removed.
435 *
436 * @since 4.5
437 * @private
438 * @class CKEDITOR.plugins.notification.area
439 * @constructor
440 * @param {CKEDITOR.editor} editor The editor instance.
441 */
442 function Area( editor ) {
443 var that = this;
444
445 this.editor = editor;
446 this.notifications = [];
447 this.element = this._createElement();
448 this._uiBuffer = CKEDITOR.tools.eventsBuffer( 10, this._layout, this );
449 this._changeBuffer = CKEDITOR.tools.eventsBuffer( 500, this._layout, this );
450
451 editor.on( 'destroy', function() {
452 that._removeListeners();
453 that.element.remove();
454 } );
455 }
456
457 /**
458 * The editor instance.
459 *
460 * @readonly
461 * @property {CKEDITOR.editor} editor
462 */
463
464 /**
465 * The array of added notifications.
466 *
467 * @readonly
468 * @property {Array} notifications
469 */
470
471 /**
472 * Notification area DOM element. This element is created when the area object is created. It will be attached to the document
473 * when the first notification is added and removed when the last notification is removed.
474 *
475 * @readonly
476 * @property {CKEDITOR.dom.element} element
477 */
478
479 /**
480 * Notification width. Cached for performance reasons.
481 *
482 * @private
483 * @property {CKEDITOR.dom.element} _notificationWidth
484 */
485
486 /**
487 * Notification margin. Cached for performance reasons.
488 *
489 * @private
490 * @property {CKEDITOR.dom.element} _notificationMargin
491 */
492
493 /**
494 * Event buffer object for UI events to optimize performance.
495 *
496 * @private
497 * @property {Object} _uiBuffer
498 */
499
500 /**
501 * Event buffer object for editor change events to optimize performance.
502 *
503 * @private
504 * @property {Object} _changeBuffer
505 */
506
507 Area.prototype = {
508 /**
509 * Adds the notification to the notification area. If it is the first notification, the area will also be attached to
510 * the document and listeners will be attached.
511 *
512 * Note that the proper way to show a notification is to call the {@link CKEDITOR.plugins.notification#show} method.
513 *
514 * @param {CKEDITOR.plugins.notification} notification Notification to add.
515 */
516 add: function( notification ) {
517 this.notifications.push( notification );
518
519 this.element.append( notification.element );
520
521 if ( this.element.getChildCount() == 1 ) {
522 CKEDITOR.document.getBody().append( this.element );
523 this._attachListeners();
524 }
525
526 this._layout();
527 },
528
529 /**
530 * Removes the notification from the notification area. If it is the last notification, the area will also be
531 * detached from the document and listeners will be detached.
532 *
533 * Note that the proper way to hide a notification is to call the {@link CKEDITOR.plugins.notification#hide} method.
534 *
535 * @param {CKEDITOR.plugins.notification} notification Notification to remove.
536 */
537 remove: function( notification ) {
538 var i = CKEDITOR.tools.indexOf( this.notifications, notification );
539
540 if ( i < 0 ) {
541 return;
542 }
543
544 this.notifications.splice( i, 1 );
545
546 notification.element.remove();
547
548 if ( !this.element.getChildCount() ) {
549 this._removeListeners();
550 this.element.remove();
551 }
552 },
553
554 /**
555 * Creates the notification area element.
556 *
557 * @private
558 * @returns {CKEDITOR.dom.element} Notification area element.
559 */
560 _createElement: function() {
561 var editor = this.editor,
562 config = editor.config,
563 notificationArea = new CKEDITOR.dom.element( 'div' );
564
565 notificationArea.addClass( 'cke_notifications_area' );
566 notificationArea.setAttribute( 'id', 'cke_notifications_area_' + editor.name );
567 notificationArea.setStyle( 'z-index', config.baseFloatZIndex - 2 );
568
569 return notificationArea;
570 },
571
572 /**
573 * Attaches listeners to the notification area.
574 *
575 * @private
576 */
577 _attachListeners: function() {
578 var win = CKEDITOR.document.getWindow(),
579 editor = this.editor;
580
581 win.on( 'scroll', this._uiBuffer.input );
582 win.on( 'resize', this._uiBuffer.input );
583 editor.on( 'change', this._changeBuffer.input );
584 editor.on( 'floatingSpaceLayout', this._layout, this, null, 20 );
585 editor.on( 'blur', this._layout, this, null, 20 );
586 },
587
588 /**
589 * Detaches listeners from the notification area.
590 *
591 * @private
592 */
593 _removeListeners: function() {
594 var win = CKEDITOR.document.getWindow(),
595 editor = this.editor;
596
597 win.removeListener( 'scroll', this._uiBuffer.input );
598 win.removeListener( 'resize', this._uiBuffer.input );
599 editor.removeListener( 'change', this._changeBuffer.input );
600 editor.removeListener( 'floatingSpaceLayout', this._layout );
601 editor.removeListener( 'blur', this._layout );
602 },
603
604 /**
605 * Sets the position of the notification area based on the editor content, toolbar as well as
606 * viewport position and dimensions.
607 *
608 * @private
609 */
610 _layout: function() {
611 var area = this.element,
612 editor = this.editor,
613 contentsRect = editor.ui.contentsElement.getClientRect(),
614 contentsPos = editor.ui.contentsElement.getDocumentPosition(),
615 top,
616 topRect,
617 areaRect = area.getClientRect(),
618 notification,
619 notificationWidth = this._notificationWidth,
620 notificationMargin = this._notificationMargin,
621 win = CKEDITOR.document.getWindow(),
622 scrollPos = win.getScrollPosition(),
623 viewRect = win.getViewPaneSize(),
624 body = CKEDITOR.document.getBody(),
625 bodyPos = body.getDocumentPosition(),
626 cssLength = CKEDITOR.tools.cssLength;
627
628 // Cache for optimization
629 if ( !notificationWidth || !notificationMargin ) {
630 notification = this.element.getChild( 0 );
631 notificationWidth = this._notificationWidth = notification.getClientRect().width;
632 notificationMargin = this._notificationMargin =
633 parseInt( notification.getComputedStyle( 'margin-left' ), 10 ) +
634 parseInt( notification.getComputedStyle( 'margin-right' ), 10 );
635 }
636
637 // Check if toolbar exist and if so, then assign values to it (#491).
638 if ( editor.toolbar ) {
639 top = editor.ui.space( 'top' );
640 topRect = top.getClientRect();
641 }
642
643
644 // --------------------------------------- Horizontal layout ----------------------------------------
645
646 // +---Viewport-------------------------------+ +---Viewport-------------------------------+
647 // | | | |
648 // | +---Toolbar----------------------------+ | | +---Content----------------------------+ |
649 // | | | | | | | |
650 // | +---Content----------------------------+ | | | | |
651 // | | | | | +---Toolbar----------------------+ | |
652 // | | +------Notification------+ | | | | | | |
653 // | | | | OR | +--------------------------------+ | |
654 // | | | | | | | |
655 // | | | | | | +------Notification------+ | |
656 // | | | | | | | |
657 // | | | | | | | |
658 // | +--------------------------------------+ | | +--------------------------------------+ |
659 // +------------------------------------------+ +------------------------------------------+
660 if ( top && top.isVisible() &&
661 topRect.bottom > contentsRect.top &&
662 topRect.bottom < contentsRect.bottom - areaRect.height ) {
663 setBelowToolbar();
664
665 // +---Viewport-------------------------------+
666 // | |
667 // | +---Content----------------------------+ |
668 // | | | |
669 // | | +------Notification------+ | |
670 // | | | |
671 // | | | |
672 // | | | |
673 // | +--------------------------------------+ |
674 // | |
675 // +------------------------------------------+
676 } else if ( contentsRect.top > 0 ) {
677 setTopStandard();
678
679 // +---Content----------------------------+
680 // | |
681 // +---Viewport-------------------------------+
682 // | | | |
683 // | | +------Notification------+ | |
684 // | | | |
685 // | | | |
686 // | | | |
687 // | +--------------------------------------+ |
688 // | |
689 // +------------------------------------------+
690 } else if ( contentsPos.y + contentsRect.height - areaRect.height > scrollPos.y ) {
691 setTopFixed();
692
693 // +---Content----------------------------+ +---Content----------------------------+
694 // | | | |
695 // | | | |
696 // | | | +------Notification------+ |
697 // | | | |
698 // | | OR +--------------------------------------+
699 // +---Viewport-------------------------------+
700 // | | +------Notification------+ | | +---Viewport-------------------------------+
701 // | | | | | |
702 // | +--------------------------------------+ | | |
703 // | | | |
704 // +------------------------------------------+ +------------------------------------------+
705 } else {
706 setBottom();
707 }
708
709 function setTopStandard() {
710 area.setStyles( {
711 position: 'absolute',
712 top: cssLength( contentsPos.y )
713 } );
714 }
715
716 function setBelowToolbar() {
717 area.setStyles( {
718 position: 'fixed',
719 top: cssLength( topRect.bottom )
720 } );
721 }
722
723 function setTopFixed() {
724 area.setStyles( {
725 position: 'fixed',
726 top: 0
727 } );
728 }
729
730 function setBottom() {
731 area.setStyles( {
732 position: 'absolute',
733 top: cssLength( contentsPos.y + contentsRect.height - areaRect.height )
734 } );
735 }
736
737 // ---------------------------------------- Vertical layout -----------------------------------------
738
739 var leftBase = area.getStyle( 'position' ) == 'fixed' ?
740 contentsRect.left :
741 body.getComputedStyle( 'position' ) != 'static' ? contentsPos.x - bodyPos.x : contentsPos.x;
742
743 // Content is narrower than notification
744 if ( contentsRect.width < notificationWidth + notificationMargin ) {
745
746 // +---Viewport-------------------------------+
747 // | |
748 // | +---Content------------+ |
749 // | | | |
750 // | +------Notification------+ | |
751 // | | | |
752 // | +----------------------+ |
753 // | |
754 // +------------------------------------------+
755 if ( contentsPos.x + notificationWidth + notificationMargin > scrollPos.x + viewRect.width ) {
756 setRight();
757
758 // +---Viewport-------------------------------+ +---Viewport--------------------------+
759 // | | | |
760 // | +---Content------------+ | +---Content------------+ |
761 // | | | | | | | |
762 // | | +------Notification------+ | OR | +------Notification------+ |
763 // | | | | | | | |
764 // | +----------------------+ | +----------------------+ |
765 // | | | |
766 // +------------------------------------------+ +-------------------------------------+
767 } else {
768 setLeft();
769 }
770
771 // Content is wider than notification.
772 } else {
773
774 // +--+Viewport+------------------------+
775 // | |
776 // | +---Content-----------------------------------------+
777 // | | | |
778 // | | +-----+Notification+-----+ |
779 // | | | |
780 // | | | |
781 // | | | |
782 // | +---------------------------------------------------+
783 // | |
784 // +------------------------------------+
785 if ( contentsPos.x + notificationWidth + notificationMargin > scrollPos.x + viewRect.width ) {
786 setLeft();
787
788 // +---Viewport-------------------------+
789 // | |
790 // | +---Content----------------------------------------------+
791 // | | | |
792 // | | +------Notification------+ | |
793 // | | | |
794 // | | | |
795 // | +--------------------------------------------------------+
796 // | |
797 // +------------------------------------+
798 } else if ( contentsPos.x + contentsRect.width / 2 +
799 notificationWidth / 2 + notificationMargin > scrollPos.x + viewRect.width ) {
800 setRightFixed();
801
802 // +---Viewport-------------------------+
803 // | |
804 // +---Content----------------------------+ |
805 // | | | |
806 // | +------Notification------+ | |
807 // | | | |
808 // | | | |
809 // +--------------------------------------+ |
810 // | |
811 // +------------------------------------+
812 } else if ( contentsRect.left + contentsRect.width - notificationWidth - notificationMargin < 0 ) {
813 setRight();
814
815 // +---Viewport-------------------------+
816 // | |
817 // +---Content---------------------------------------------+ |
818 // | | | |
819 // | | +------Notification------+ | |
820 // | | | |
821 // | | | |
822 // +-------------------------------------------------------+ |
823 // | |
824 // +------------------------------------+
825 } else if ( contentsRect.left + contentsRect.width / 2 - notificationWidth / 2 < 0 ) {
826 setLeftFixed();
827
828 // +---Viewport-------------------------+
829 // | |
830 // | +---Content----------------------+ |
831 // | | | |
832 // | | +-----Notification-----+ | |
833 // | | | |
834 // | | | |
835 // | +--------------------------------+ |
836 // | |
837 // +------------------------------------+
838 } else {
839 setCenter();
840 }
841 }
842
843 function setLeft() {
844 area.setStyle( 'left', cssLength( leftBase ) );
845 }
846
847 function setLeftFixed() {
848 area.setStyle( 'left', cssLength( leftBase - contentsPos.x + scrollPos.x ) );
849 }
850
851 function setCenter() {
852 area.setStyle( 'left', cssLength( leftBase + contentsRect.width / 2 - notificationWidth / 2 - notificationMargin / 2 ) );
853 }
854
855 function setRight() {
856 area.setStyle( 'left', cssLength( leftBase + contentsRect.width - notificationWidth - notificationMargin ) );
857 }
858
859 function setRightFixed() {
860 area.setStyle( 'left', cssLength( leftBase - contentsPos.x + scrollPos.x + viewRect.width -
861 notificationWidth - notificationMargin ) );
862 }
863 }
864 };
865
866 CKEDITOR.plugins.notification = Notification;
867
868 /**
869 * After how many milliseconds the notification of the `info` and `success`
870 * {@link CKEDITOR.plugins.notification#type type} should close automatically.
871 * `0` means that notifications will not close automatically.
872 * Note that `warning` and `progress` notifications will never close automatically.
873 *
874 * Refer to the [Notifications](http://docs.ckeditor.com/#!/guide/dev_notifications) article
875 * for more information about this feature.
876 *
877 * @since 4.5
878 * @cfg {Number} [notification_duration=5000]
879 * @member CKEDITOR.config
880 */
881
882 /**
883 * Event fired when the {@link CKEDITOR.plugins.notification#show} method is called, before the
884 * notification is shown. If this event is canceled, the notification will not be shown.
885 *
886 * Using this event allows you to fully customize how a notification will be shown. It may be used to integrate
887 * the CKEditor notification system with your web page notifications.
888 *
889 * @since 4.5
890 * @event notificationShow
891 * @member CKEDITOR.editor
892 * @param data
893 * @param {CKEDITOR.plugins.notification} data.notification Notification which will be shown.
894 * @param {CKEDITOR.editor} editor The editor instance.
895 */
896
897 /**
898 * Event fired when the {@link CKEDITOR.plugins.notification#update} method is called, before the
899 * notification is updated. If this event is canceled, the notification will not be shown even if the update was important,
900 * but the object will be updated anyway. Note that canceling this event does not prevent updating {@link #element}
901 * attributes, but if {@link #notificationShow} was canceled as well, this element is detached from the DOM.
902 *
903 * Using this event allows you to fully customize how a notification will be updated. It may be used to integrate
904 * the CKEditor notification system with your web page notifications.
905 *
906 * @since 4.5
907 * @event notificationUpdate
908 * @member CKEDITOR.editor
909 * @param data
910 * @param {CKEDITOR.plugins.notification} data.notification Notification which will be updated.
911 * Note that it contains the data that has not been updated yet.
912 * @param {Object} data.options Update options, see {@link CKEDITOR.plugins.notification#update}.
913 * @param {CKEDITOR.editor} editor The editor instance.
914 */
915
916 /**
917 * Event fired when the {@link CKEDITOR.plugins.notification#hide} method is called, before the
918 * notification is hidden. If this event is canceled, the notification will not be hidden.
919 *
920 * Using this event allows you to fully customize how a notification will be hidden. It may be used to integrate
921 * the CKEditor notification system with your web page notifications.
922 *
923 * @since 4.5
924 * @event notificationHide
925 * @member CKEDITOR.editor
926 * @param data
927 * @param {CKEDITOR.plugins.notification} data.notification Notification which will be hidden.
928 * @param {CKEDITOR.editor} editor The editor instance.
929 */