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