+/**\r
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
+ * For licensing, see LICENSE.md or http://ckeditor.com/license\r
+ */\r
+\r
+/**\r
+ * @fileOverview The "Notification" plugin.\r
+ *\r
+ */\r
+\r
+'use strict';\r
+\r
+CKEDITOR.plugins.add( 'notification', {\r
+ 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
+\r
+ init: function( editor ) {\r
+ editor._.notificationArea = new Area( editor );\r
+\r
+ // Overwrites default `editor.showNotification`.\r
+ editor.showNotification = function( message, type, progressOrDuration ) {\r
+ var progress, duration;\r
+\r
+ if ( type == 'progress' ) {\r
+ progress = progressOrDuration;\r
+ } else {\r
+ duration = progressOrDuration;\r
+ }\r
+\r
+ var notification = new CKEDITOR.plugins.notification( editor, {\r
+ message: message,\r
+ type: type,\r
+ progress: progress,\r
+ duration: duration\r
+ } );\r
+\r
+ notification.show();\r
+\r
+ return notification;\r
+ };\r
+\r
+ // Close the last notification on ESC.\r
+ editor.on( 'key', function( evt ) {\r
+ if ( evt.data.keyCode == 27 ) { /* ESC */\r
+ var notifications = editor._.notificationArea.notifications;\r
+\r
+ if ( !notifications.length ) {\r
+ return;\r
+ }\r
+\r
+ // As long as this is not a common practice to inform screen-reader users about actions, in this case\r
+ // this is the best solution (unfortunately there is no standard for accessibility for notifications).\r
+ // Notification has an `alert` aria role what means that it does not get a focus nor is needed to be\r
+ // closed (unlike `alertdialog`). However notification will capture ESC key so we need to inform user\r
+ // why it does not do other actions.\r
+ say( editor.lang.notification.closed );\r
+\r
+ // Hide last.\r
+ notifications[ notifications.length - 1 ].hide();\r
+\r
+ evt.cancel();\r
+ }\r
+ } );\r
+\r
+ // Send the message to the screen readers.\r
+ function say( text ) {\r
+ var message = new CKEDITOR.dom.element( 'div' );\r
+ message.setStyles( {\r
+ position: 'fixed',\r
+ 'margin-left': '-9999px'\r
+ } );\r
+ message.setAttributes( {\r
+ 'aria-live': 'assertive',\r
+ 'aria-atomic': 'true'\r
+ } );\r
+ message.setText( text );\r
+\r
+ CKEDITOR.document.getBody().append( message );\r
+\r
+ setTimeout( function() {\r
+ message.remove();\r
+ }, 100 );\r
+ }\r
+ }\r
+} );\r
+\r
+/**\r
+ * Notification class. Notifications are used to display short messages to the user. They might be used to show the result of\r
+ * asynchronous actions or information about changes in the editor content. It is recommended to use them instead of\r
+ * alert dialogs. They should **not** be used if a user response is required nor with dialog windows (e.g. in dialog validation).\r
+ *\r
+ * There are four types of notifications available, see the {@link #type} property.\r
+ *\r
+ * Note that the notification constructor only creates a notification instance. To show it, use the {@link #show} method:\r
+ *\r
+ * var notification = new CKEDITOR.plugins.notification( editor, { message: 'Foo' } );\r
+ * notification.show();\r
+ *\r
+ * You can also use the {@link CKEDITOR.editor#showNotification} method:\r
+ *\r
+ * editor.showNotification( 'Foo' );\r
+ *\r
+ * All of the notification actions: ({@link #show}, {@link #update} and {@link #hide}) fire cancelable events\r
+ * on the related {@link CKEDITOR.editor} instance so you can integrate editor notifications with your website notifications.\r
+ *\r
+ * Refer to the [Notifications](http://docs.ckeditor.com/#!/guide/dev_notifications) article for more information about this feature.\r
+ *\r
+ * @since 4.5\r
+ * @class CKEDITOR.plugins.notification\r
+ * @constructor Create a notification object. Call {@link #show} to show the created notification.\r
+ * @param {CKEDITOR.editor} editor The editor instance.\r
+ * @param {Object} options\r
+ * @param {String} options.message The message displayed in the notification.\r
+ * @param {String} [options.type='info'] Notification type, see {@link #type}.\r
+ * @param {Number} [options.progress=0] If the type is `progress` this may be a progress from 0 to 1.\r
+ * @param {Number} [options.duration] How long the notification will be visible, see {@link #duration}.\r
+ */\r
+function Notification( editor, options ) {\r
+ CKEDITOR.tools.extend( this, options, {\r
+ editor: editor,\r
+ id: 'cke-' + CKEDITOR.tools.getUniqueId(),\r
+ area: editor._.notificationArea\r
+ } );\r
+\r
+ if ( !options.type ) {\r
+ this.type = 'info';\r
+ }\r
+\r
+ this.element = this._createElement();\r
+\r
+ // Don't allow dragging on notification (http://dev.ckeditor.com/ticket/13184).\r
+ editor.plugins.clipboard && CKEDITOR.plugins.clipboard.preventDefaultDropOnElement( this.element );\r
+}\r
+\r
+/**\r
+ * The editor instance.\r
+ *\r
+ * @readonly\r
+ * @property {CKEDITOR.editor} editor\r
+ */\r
+\r
+/**\r
+ * Message displayed in the notification.\r
+ *\r
+ * @readonly\r
+ * @property {String} message\r
+ */\r
+\r
+/**\r
+ * Notification type. There are four types available:\r
+ *\r
+ * * `info` (default) – Information for the user (e.g. "File is uploading.", "ACF modified content."),\r
+ * * `warning` – Warning or error message (e.g. "This type of file is not supported.",\r
+ * "You cannot paste the script."),\r
+ * * `success` – Information that an operation finished successfully (e.g. "File uploaded.", "Data imported.").\r
+ * * `progress` – Information about the progress of an operation. When the operation is done, the notification\r
+ * type should be changed to `success`.\r
+ *\r
+ * @readonly\r
+ * @property {String} type\r
+ */\r
+\r
+/**\r
+ * If the notification {@link #type} is `'progress'`, this is the progress from `0` to `1`.\r
+ *\r
+ * @readonly\r
+ * @property {Number} progress\r
+ */\r
+\r
+/**\r
+ * Notification duration. Determines after how many milliseconds the notification should close automatically.\r
+ * `0` means that the notification will not close automatically and that the user needs to close it manually.\r
+ * The default value for `warning` and `progress` notifications is `0`. For `info` and `success` the value can\r
+ * either be set through the {@link CKEDITOR.config#notification_duration} configuration option or equals `5000`\r
+ * if the configuration option is not set.\r
+ *\r
+ * @readonly\r
+ * @property {Number} duration\r
+ */\r
+\r
+/**\r
+ * Unique notification ID.\r
+ *\r
+ * @readonly\r
+ * @property {Number} id\r
+ */\r
+\r
+/**\r
+ * Notification DOM element. There is one element per notification. It is created when the notification is created,\r
+ * even if it is not shown. If the notification is hidden, the element is detached from the document but not deleted.\r
+ * It will be reused if the notification is shown again.\r
+ *\r
+ * @readonly\r
+ * @property {CKEDITOR.dom.element} element\r
+ */\r
+\r
+/**\r
+ * {@link CKEDITOR.plugins.notification.area Notification area} reference.\r
+ *\r
+ * @readonly\r
+ * @property {CKEDITOR.plugins.notification.area} area\r
+ */\r
+\r
+Notification.prototype = {\r
+ /**\r
+ * Adds the notification element to the notification area. The notification will be hidden automatically if\r
+ * {@link #duration} is set.\r
+ *\r
+ * Fires the {@link CKEDITOR.editor#notificationShow} event.\r
+ */\r
+ show: function() {\r
+ if ( this.editor.fire( 'notificationShow', { notification: this } ) === false ) {\r
+ return;\r
+ }\r
+\r
+ this.area.add( this );\r
+\r
+ this._hideAfterTimeout();\r
+ },\r
+\r
+ /**\r
+ * Updates the notification object and element.\r
+ *\r
+ * Fires the {@link CKEDITOR.editor#notificationUpdate} event.\r
+ *\r
+ * @param {Object} options\r
+ * @param {String} [options.message] {@link #message}\r
+ * @param {String} [options.type] {@link #type}\r
+ * @param {Number} [options.progress] {@link #progress}\r
+ * @param {Number} [options.duration] {@link #duration}\r
+ * @param {Boolean} [options.important=false] If the update is important, the notification will be shown\r
+ * if it was hidden and read by screen readers.\r
+ */\r
+ update: function( options ) {\r
+ var show = true;\r
+\r
+ if ( this.editor.fire( 'notificationUpdate', { notification: this, options: options } ) === false ) {\r
+ // The idea of cancelable event is to let user create his own way of displaying notification, so if\r
+ // `notificationUpdate` event will be canceled there will be no interaction with notification area, but on\r
+ // the other hand the logic should work anyway so object will be updated (including `element` property).\r
+ // Note: we can safely update the element's attributes below, because this element is created inside\r
+ // the constructor. If the notificatinShow event was canceled as well, the element is detached from DOM.\r
+ show = false;\r
+ }\r
+\r
+ var element = this.element,\r
+ messageElement = element.findOne( '.cke_notification_message' ),\r
+ progressElement = element.findOne( '.cke_notification_progress' ),\r
+ type = options.type;\r
+\r
+ element.removeAttribute( 'role' );\r
+\r
+ // Change type to progress if `options.progress` is set.\r
+ if ( options.progress && this.type != 'progress' ) {\r
+ type = 'progress';\r
+ }\r
+\r
+ if ( type ) {\r
+ element.removeClass( this._getClass() );\r
+ element.removeAttribute( 'aria-label' );\r
+\r
+ this.type = type;\r
+\r
+ element.addClass( this._getClass() );\r
+ element.setAttribute( 'aria-label', this.type );\r
+\r
+ if ( this.type == 'progress' && !progressElement ) {\r
+ progressElement = this._createProgressElement();\r
+ progressElement.insertBefore( messageElement );\r
+ } else if ( this.type != 'progress' && progressElement ) {\r
+ progressElement.remove();\r
+ }\r
+ }\r
+\r
+ if ( options.message !== undefined ) {\r
+ this.message = options.message;\r
+ messageElement.setHtml( this.message );\r
+ }\r
+\r
+ if ( options.progress !== undefined ) {\r
+ this.progress = options.progress;\r
+\r
+ if ( progressElement ) {\r
+ progressElement.setStyle( 'width', this._getPercentageProgress() );\r
+ }\r
+ }\r
+\r
+ if ( show && options.important ) {\r
+ element.setAttribute( 'role', 'alert' );\r
+\r
+ if ( !this.isVisible() ) {\r
+ this.area.add( this );\r
+ }\r
+ }\r
+\r
+ // Overwrite even if it is undefined.\r
+ this.duration = options.duration;\r
+\r
+ this._hideAfterTimeout();\r
+ },\r
+\r
+ /**\r
+ * Removes the notification element from the notification area.\r
+ *\r
+ * Fires the {@link CKEDITOR.editor#notificationHide} event.\r
+ */\r
+ hide: function() {\r
+ if ( this.editor.fire( 'notificationHide', { notification: this } ) === false ) {\r
+ return;\r
+ }\r
+\r
+ this.area.remove( this );\r
+ },\r
+\r
+ /**\r
+ * Returns `true` if the notification is in the notification area.\r
+ *\r
+ * @returns {Boolean} `true` if the notification is in the notification area.\r
+ */\r
+ isVisible: function() {\r
+ return CKEDITOR.tools.indexOf( this.area.notifications, this ) >= 0;\r
+ },\r
+\r
+ /**\r
+ * Creates the notification DOM element.\r
+ *\r
+ * @private\r
+ * @returns {CKEDITOR.dom.element} Notification DOM element.\r
+ */\r
+ _createElement: function() {\r
+ var notification = this,\r
+ notificationElement, notificationMessageElement, notificationCloseElement,\r
+ close = this.editor.lang.common.close;\r
+\r
+ notificationElement = new CKEDITOR.dom.element( 'div' );\r
+ notificationElement.addClass( 'cke_notification' );\r
+ notificationElement.addClass( this._getClass() );\r
+ notificationElement.setAttributes( {\r
+ id: this.id,\r
+ role: 'alert',\r
+ 'aria-label': this.type\r
+ } );\r
+\r
+ if ( this.type == 'progress' )\r
+ notificationElement.append( this._createProgressElement() );\r
+\r
+ notificationMessageElement = new CKEDITOR.dom.element( 'p' );\r
+ notificationMessageElement.addClass( 'cke_notification_message' );\r
+ notificationMessageElement.setHtml( this.message );\r
+ notificationElement.append( notificationMessageElement );\r
+\r
+ notificationCloseElement = CKEDITOR.dom.element.createFromHtml(\r
+ '<a class="cke_notification_close" href="javascript:void(0)" title="' + close + '" role="button" tabindex="-1">' +\r
+ '<span class="cke_label">X</span>' +\r
+ '</a>' );\r
+ notificationElement.append( notificationCloseElement );\r
+\r
+ notificationCloseElement.on( 'click', function() {\r
+ // Focus editor on close (http://dev.ckeditor.com/ticket/12865)\r
+ notification.editor.focus();\r
+\r
+ notification.hide();\r
+ } );\r
+\r
+ return notificationElement;\r
+ },\r
+\r
+ /**\r
+ * Gets the notification CSS class.\r
+ *\r
+ * @private\r
+ * @returns {String} Notification CSS class.\r
+ */\r
+ _getClass: function() {\r
+ return ( this.type == 'progress' ) ?\r
+ 'cke_notification_info' :\r
+ ( 'cke_notification_' + this.type );\r
+ },\r
+\r
+ /**\r
+ * Creates a progress element for the notification element.\r
+ *\r
+ * @private\r
+ * @returns {CKEDITOR.dom.element} Progress element for the notification element.\r
+ */\r
+ _createProgressElement: function() {\r
+ var element = new CKEDITOR.dom.element( 'span' );\r
+ element.addClass( 'cke_notification_progress' );\r
+ element.setStyle( 'width', this._getPercentageProgress() );\r
+ return element;\r
+ },\r
+\r
+ /**\r
+ * Gets the progress as a percentage (ex. `0.3` -> `30%`).\r
+ *\r
+ * @private\r
+ * @returns {String} Progress as a percentage.\r
+ */\r
+ _getPercentageProgress: function() {\r
+ return Math.round( ( this.progress || 0 ) * 100 ) + '%';\r
+ },\r
+\r
+ /**\r
+ * Hides the notification after a timeout.\r
+ *\r
+ * @private\r
+ */\r
+ _hideAfterTimeout: function() {\r
+ var notification = this,\r
+ duration;\r
+\r
+ if ( this._hideTimeoutId ) {\r
+ clearTimeout( this._hideTimeoutId );\r
+ }\r
+\r
+ if ( typeof this.duration == 'number' ) {\r
+ duration = this.duration;\r
+ } else if ( this.type == 'info' || this.type == 'success' ) {\r
+ duration = ( typeof this.editor.config.notification_duration == 'number' ) ?\r
+ this.editor.config.notification_duration :\r
+ 5000;\r
+ }\r
+\r
+ if ( duration ) {\r
+ notification._hideTimeoutId = setTimeout( function() {\r
+ notification.hide();\r
+ }, duration );\r
+ }\r
+ }\r
+};\r
+\r
+/**\r
+ * Notification area is an area where all notifications are put. The area is laid out dynamically.\r
+ * When the first notification is added, the area is shown and all listeners are added.\r
+ * When the last notification is removed, the area is hidden and all listeners are removed.\r
+ *\r
+ * @since 4.5\r
+ * @private\r
+ * @class CKEDITOR.plugins.notification.area\r
+ * @constructor\r
+ * @param {CKEDITOR.editor} editor The editor instance.\r
+ */\r
+function Area( editor ) {\r
+ var that = this;\r
+\r
+ this.editor = editor;\r
+ this.notifications = [];\r
+ this.element = this._createElement();\r
+ this._uiBuffer = CKEDITOR.tools.eventsBuffer( 10, this._layout, this );\r
+ this._changeBuffer = CKEDITOR.tools.eventsBuffer( 500, this._layout, this );\r
+\r
+ editor.on( 'destroy', function() {\r
+ that._removeListeners();\r
+ that.element.remove();\r
+ } );\r
+}\r
+\r
+/**\r
+ * The editor instance.\r
+ *\r
+ * @readonly\r
+ * @property {CKEDITOR.editor} editor\r
+ */\r
+\r
+/**\r
+ * The array of added notifications.\r
+ *\r
+ * @readonly\r
+ * @property {Array} notifications\r
+ */\r
+\r
+/**\r
+ * Notification area DOM element. This element is created when the area object is created. It will be attached to the document\r
+ * when the first notification is added and removed when the last notification is removed.\r
+ *\r
+ * @readonly\r
+ * @property {CKEDITOR.dom.element} element\r
+ */\r
+\r
+/**\r
+ * Notification width. Cached for performance reasons.\r
+ *\r
+ * @private\r
+ * @property {CKEDITOR.dom.element} _notificationWidth\r
+ */\r
+\r
+/**\r
+ * Notification margin. Cached for performance reasons.\r
+ *\r
+ * @private\r
+ * @property {CKEDITOR.dom.element} _notificationMargin\r
+ */\r
+\r
+/**\r
+ * Event buffer object for UI events to optimize performance.\r
+ *\r
+ * @private\r
+ * @property {Object} _uiBuffer\r
+ */\r
+\r
+/**\r
+ * Event buffer object for editor change events to optimize performance.\r
+ *\r
+ * @private\r
+ * @property {Object} _changeBuffer\r
+ */\r
+\r
+Area.prototype = {\r
+ /**\r
+ * Adds the notification to the notification area. If it is the first notification, the area will also be attached to\r
+ * the document and listeners will be attached.\r
+ *\r
+ * Note that the proper way to show a notification is to call the {@link CKEDITOR.plugins.notification#show} method.\r
+ *\r
+ * @param {CKEDITOR.plugins.notification} notification Notification to add.\r
+ */\r
+ add: function( notification ) {\r
+ this.notifications.push( notification );\r
+\r
+ this.element.append( notification.element );\r
+\r
+ if ( this.element.getChildCount() == 1 ) {\r
+ CKEDITOR.document.getBody().append( this.element );\r
+ this._attachListeners();\r
+ }\r
+\r
+ this._layout();\r
+ },\r
+\r
+ /**\r
+ * Removes the notification from the notification area. If it is the last notification, the area will also be\r
+ * detached from the document and listeners will be detached.\r
+ *\r
+ * Note that the proper way to hide a notification is to call the {@link CKEDITOR.plugins.notification#hide} method.\r
+ *\r
+ * @param {CKEDITOR.plugins.notification} notification Notification to remove.\r
+ */\r
+ remove: function( notification ) {\r
+ var i = CKEDITOR.tools.indexOf( this.notifications, notification );\r
+\r
+ if ( i < 0 ) {\r
+ return;\r
+ }\r
+\r
+ this.notifications.splice( i, 1 );\r
+\r
+ notification.element.remove();\r
+\r
+ if ( !this.element.getChildCount() ) {\r
+ this._removeListeners();\r
+ this.element.remove();\r
+ }\r
+ },\r
+\r
+ /**\r
+ * Creates the notification area element.\r
+ *\r
+ * @private\r
+ * @returns {CKEDITOR.dom.element} Notification area element.\r
+ */\r
+ _createElement: function() {\r
+ var editor = this.editor,\r
+ config = editor.config,\r
+ notificationArea = new CKEDITOR.dom.element( 'div' );\r
+\r
+ notificationArea.addClass( 'cke_notifications_area' );\r
+ notificationArea.setAttribute( 'id', 'cke_notifications_area_' + editor.name );\r
+ notificationArea.setStyle( 'z-index', config.baseFloatZIndex - 2 );\r
+\r
+ return notificationArea;\r
+ },\r
+\r
+ /**\r
+ * Attaches listeners to the notification area.\r
+ *\r
+ * @private\r
+ */\r
+ _attachListeners: function() {\r
+ var win = CKEDITOR.document.getWindow(),\r
+ editor = this.editor;\r
+\r
+ win.on( 'scroll', this._uiBuffer.input );\r
+ win.on( 'resize', this._uiBuffer.input );\r
+ editor.on( 'change', this._changeBuffer.input );\r
+ editor.on( 'floatingSpaceLayout', this._layout, this, null, 20 );\r
+ editor.on( 'blur', this._layout, this, null, 20 );\r
+ },\r
+\r
+ /**\r
+ * Detaches listeners from the notification area.\r
+ *\r
+ * @private\r
+ */\r
+ _removeListeners: function() {\r
+ var win = CKEDITOR.document.getWindow(),\r
+ editor = this.editor;\r
+\r
+ win.removeListener( 'scroll', this._uiBuffer.input );\r
+ win.removeListener( 'resize', this._uiBuffer.input );\r
+ editor.removeListener( 'change', this._changeBuffer.input );\r
+ editor.removeListener( 'floatingSpaceLayout', this._layout );\r
+ editor.removeListener( 'blur', this._layout );\r
+ },\r
+\r
+ /**\r
+ * Sets the position of the notification area based on the editor content, toolbar as well as\r
+ * viewport position and dimensions.\r
+ *\r
+ * @private\r
+ */\r
+ _layout: function() {\r
+ var area = this.element,\r
+ editor = this.editor,\r
+ contentsRect = editor.ui.contentsElement.getClientRect(),\r
+ contentsPos = editor.ui.contentsElement.getDocumentPosition(),\r
+ top,\r
+ topRect,\r
+ areaRect = area.getClientRect(),\r
+ notification,\r
+ notificationWidth = this._notificationWidth,\r
+ notificationMargin = this._notificationMargin,\r
+ win = CKEDITOR.document.getWindow(),\r
+ scrollPos = win.getScrollPosition(),\r
+ viewRect = win.getViewPaneSize(),\r
+ body = CKEDITOR.document.getBody(),\r
+ bodyPos = body.getDocumentPosition(),\r
+ cssLength = CKEDITOR.tools.cssLength;\r
+\r
+ // Cache for optimization\r
+ if ( !notificationWidth || !notificationMargin ) {\r
+ notification = this.element.getChild( 0 );\r
+ notificationWidth = this._notificationWidth = notification.getClientRect().width;\r
+ notificationMargin = this._notificationMargin =\r
+ parseInt( notification.getComputedStyle( 'margin-left' ), 10 ) +\r
+ parseInt( notification.getComputedStyle( 'margin-right' ), 10 );\r
+ }\r
+\r
+ // Check if toolbar exist and if so, then assign values to it (#491).\r
+ if ( editor.toolbar ) {\r
+ top = editor.ui.space( 'top' );\r
+ topRect = top.getClientRect();\r
+ }\r
+\r
+\r
+ // --------------------------------------- Horizontal layout ----------------------------------------\r
+\r
+ // +---Viewport-------------------------------+ +---Viewport-------------------------------+\r
+ // | | | |\r
+ // | +---Toolbar----------------------------+ | | +---Content----------------------------+ |\r
+ // | | | | | | | |\r
+ // | +---Content----------------------------+ | | | | |\r
+ // | | | | | +---Toolbar----------------------+ | |\r
+ // | | +------Notification------+ | | | | | | |\r
+ // | | | | OR | +--------------------------------+ | |\r
+ // | | | | | | | |\r
+ // | | | | | | +------Notification------+ | |\r
+ // | | | | | | | |\r
+ // | | | | | | | |\r
+ // | +--------------------------------------+ | | +--------------------------------------+ |\r
+ // +------------------------------------------+ +------------------------------------------+\r
+ if ( top && top.isVisible() &&\r
+ topRect.bottom > contentsRect.top &&\r
+ topRect.bottom < contentsRect.bottom - areaRect.height ) {\r
+ setBelowToolbar();\r
+\r
+ // +---Viewport-------------------------------+\r
+ // | |\r
+ // | +---Content----------------------------+ |\r
+ // | | | |\r
+ // | | +------Notification------+ | |\r
+ // | | | |\r
+ // | | | |\r
+ // | | | |\r
+ // | +--------------------------------------+ |\r
+ // | |\r
+ // +------------------------------------------+\r
+ } else if ( contentsRect.top > 0 ) {\r
+ setTopStandard();\r
+\r
+ // +---Content----------------------------+\r
+ // | |\r
+ // +---Viewport-------------------------------+\r
+ // | | | |\r
+ // | | +------Notification------+ | |\r
+ // | | | |\r
+ // | | | |\r
+ // | | | |\r
+ // | +--------------------------------------+ |\r
+ // | |\r
+ // +------------------------------------------+\r
+ } else if ( contentsPos.y + contentsRect.height - areaRect.height > scrollPos.y ) {\r
+ setTopFixed();\r
+\r
+ // +---Content----------------------------+ +---Content----------------------------+\r
+ // | | | |\r
+ // | | | |\r
+ // | | | +------Notification------+ |\r
+ // | | | |\r
+ // | | OR +--------------------------------------+\r
+ // +---Viewport-------------------------------+\r
+ // | | +------Notification------+ | | +---Viewport-------------------------------+\r
+ // | | | | | |\r
+ // | +--------------------------------------+ | | |\r
+ // | | | |\r
+ // +------------------------------------------+ +------------------------------------------+\r
+ } else {\r
+ setBottom();\r
+ }\r
+\r
+ function setTopStandard() {\r
+ area.setStyles( {\r
+ position: 'absolute',\r
+ top: cssLength( contentsPos.y )\r
+ } );\r
+ }\r
+\r
+ function setBelowToolbar() {\r
+ area.setStyles( {\r
+ position: 'fixed',\r
+ top: cssLength( topRect.bottom )\r
+ } );\r
+ }\r
+\r
+ function setTopFixed() {\r
+ area.setStyles( {\r
+ position: 'fixed',\r
+ top: 0\r
+ } );\r
+ }\r
+\r
+ function setBottom() {\r
+ area.setStyles( {\r
+ position: 'absolute',\r
+ top: cssLength( contentsPos.y + contentsRect.height - areaRect.height )\r
+ } );\r
+ }\r
+\r
+ // ---------------------------------------- Vertical layout -----------------------------------------\r
+\r
+ var leftBase = area.getStyle( 'position' ) == 'fixed' ?\r
+ contentsRect.left :\r
+ body.getComputedStyle( 'position' ) != 'static' ? contentsPos.x - bodyPos.x : contentsPos.x;\r
+\r
+ // Content is narrower than notification\r
+ if ( contentsRect.width < notificationWidth + notificationMargin ) {\r
+\r
+ // +---Viewport-------------------------------+\r
+ // | |\r
+ // | +---Content------------+ |\r
+ // | | | |\r
+ // | +------Notification------+ | |\r
+ // | | | |\r
+ // | +----------------------+ |\r
+ // | |\r
+ // +------------------------------------------+\r
+ if ( contentsPos.x + notificationWidth + notificationMargin > scrollPos.x + viewRect.width ) {\r
+ setRight();\r
+\r
+ // +---Viewport-------------------------------+ +---Viewport--------------------------+\r
+ // | | | |\r
+ // | +---Content------------+ | +---Content------------+ |\r
+ // | | | | | | | |\r
+ // | | +------Notification------+ | OR | +------Notification------+ |\r
+ // | | | | | | | |\r
+ // | +----------------------+ | +----------------------+ |\r
+ // | | | |\r
+ // +------------------------------------------+ +-------------------------------------+\r
+ } else {\r
+ setLeft();\r
+ }\r
+\r
+ // Content is wider than notification.\r
+ } else {\r
+\r
+ // +--+Viewport+------------------------+\r
+ // | |\r
+ // | +---Content-----------------------------------------+\r
+ // | | | |\r
+ // | | +-----+Notification+-----+ |\r
+ // | | | |\r
+ // | | | |\r
+ // | | | |\r
+ // | +---------------------------------------------------+\r
+ // | |\r
+ // +------------------------------------+\r
+ if ( contentsPos.x + notificationWidth + notificationMargin > scrollPos.x + viewRect.width ) {\r
+ setLeft();\r
+\r
+ // +---Viewport-------------------------+\r
+ // | |\r
+ // | +---Content----------------------------------------------+\r
+ // | | | |\r
+ // | | +------Notification------+ | |\r
+ // | | | |\r
+ // | | | |\r
+ // | +--------------------------------------------------------+\r
+ // | |\r
+ // +------------------------------------+\r
+ } else if ( contentsPos.x + contentsRect.width / 2 +\r
+ notificationWidth / 2 + notificationMargin > scrollPos.x + viewRect.width ) {\r
+ setRightFixed();\r
+\r
+ // +---Viewport-------------------------+\r
+ // | |\r
+ // +---Content----------------------------+ |\r
+ // | | | |\r
+ // | +------Notification------+ | |\r
+ // | | | |\r
+ // | | | |\r
+ // +--------------------------------------+ |\r
+ // | |\r
+ // +------------------------------------+\r
+ } else if ( contentsRect.left + contentsRect.width - notificationWidth - notificationMargin < 0 ) {\r
+ setRight();\r
+\r
+ // +---Viewport-------------------------+\r
+ // | |\r
+ // +---Content---------------------------------------------+ |\r
+ // | | | |\r
+ // | | +------Notification------+ | |\r
+ // | | | |\r
+ // | | | |\r
+ // +-------------------------------------------------------+ |\r
+ // | |\r
+ // +------------------------------------+\r
+ } else if ( contentsRect.left + contentsRect.width / 2 - notificationWidth / 2 < 0 ) {\r
+ setLeftFixed();\r
+\r
+ // +---Viewport-------------------------+\r
+ // | |\r
+ // | +---Content----------------------+ |\r
+ // | | | |\r
+ // | | +-----Notification-----+ | |\r
+ // | | | |\r
+ // | | | |\r
+ // | +--------------------------------+ |\r
+ // | |\r
+ // +------------------------------------+\r
+ } else {\r
+ setCenter();\r
+ }\r
+ }\r
+\r
+ function setLeft() {\r
+ area.setStyle( 'left', cssLength( leftBase ) );\r
+ }\r
+\r
+ function setLeftFixed() {\r
+ area.setStyle( 'left', cssLength( leftBase - contentsPos.x + scrollPos.x ) );\r
+ }\r
+\r
+ function setCenter() {\r
+ area.setStyle( 'left', cssLength( leftBase + contentsRect.width / 2 - notificationWidth / 2 - notificationMargin / 2 ) );\r
+ }\r
+\r
+ function setRight() {\r
+ area.setStyle( 'left', cssLength( leftBase + contentsRect.width - notificationWidth - notificationMargin ) );\r
+ }\r
+\r
+ function setRightFixed() {\r
+ area.setStyle( 'left', cssLength( leftBase - contentsPos.x + scrollPos.x + viewRect.width -\r
+ notificationWidth - notificationMargin ) );\r
+ }\r
+ }\r
+};\r
+\r
+CKEDITOR.plugins.notification = Notification;\r
+\r
+/**\r
+ * After how many milliseconds the notification of the `info` and `success`\r
+ * {@link CKEDITOR.plugins.notification#type type} should close automatically.\r
+ * `0` means that notifications will not close automatically.\r
+ * Note that `warning` and `progress` notifications will never close automatically.\r
+ *\r
+ * Refer to the [Notifications](http://docs.ckeditor.com/#!/guide/dev_notifications) article\r
+ * for more information about this feature.\r
+ *\r
+ * @since 4.5\r
+ * @cfg {Number} [notification_duration=5000]\r
+ * @member CKEDITOR.config\r
+ */\r
+\r
+/**\r
+ * Event fired when the {@link CKEDITOR.plugins.notification#show} method is called, before the\r
+ * notification is shown. If this event is canceled, the notification will not be shown.\r
+ *\r
+ * Using this event allows you to fully customize how a notification will be shown. It may be used to integrate\r
+ * the CKEditor notification system with your web page notifications.\r
+ *\r
+ * @since 4.5\r
+ * @event notificationShow\r
+ * @member CKEDITOR.editor\r
+ * @param data\r
+ * @param {CKEDITOR.plugins.notification} data.notification Notification which will be shown.\r
+ * @param {CKEDITOR.editor} editor The editor instance.\r
+ */\r
+\r
+/**\r
+ * Event fired when the {@link CKEDITOR.plugins.notification#update} method is called, before the\r
+ * notification is updated. If this event is canceled, the notification will not be shown even if the update was important,\r
+ * but the object will be updated anyway. Note that canceling this event does not prevent updating {@link #element}\r
+ * attributes, but if {@link #notificationShow} was canceled as well, this element is detached from the DOM.\r
+ *\r
+ * Using this event allows you to fully customize how a notification will be updated. It may be used to integrate\r
+ * the CKEditor notification system with your web page notifications.\r
+ *\r
+ * @since 4.5\r
+ * @event notificationUpdate\r
+ * @member CKEDITOR.editor\r
+ * @param data\r
+ * @param {CKEDITOR.plugins.notification} data.notification Notification which will be updated.\r
+ * Note that it contains the data that has not been updated yet.\r
+ * @param {Object} data.options Update options, see {@link CKEDITOR.plugins.notification#update}.\r
+ * @param {CKEDITOR.editor} editor The editor instance.\r
+ */\r
+\r
+/**\r
+ * Event fired when the {@link CKEDITOR.plugins.notification#hide} method is called, before the\r
+ * notification is hidden. If this event is canceled, the notification will not be hidden.\r
+ *\r
+ * Using this event allows you to fully customize how a notification will be hidden. It may be used to integrate\r
+ * the CKEditor notification system with your web page notifications.\r
+ *\r
+ * @since 4.5\r
+ * @event notificationHide\r
+ * @member CKEDITOR.editor\r
+ * @param data\r
+ * @param {CKEDITOR.plugins.notification} data.notification Notification which will be hidden.\r
+ * @param {CKEDITOR.editor} editor The editor instance.\r
+ */\r