From 7adcb81e4f83f98c468889aaa5a85558ba88c770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Mon, 25 Jan 2016 17:45:33 +0100 Subject: Initial commit --- sources/core/focusmanager.js | 273 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 sources/core/focusmanager.js (limited to 'sources/core/focusmanager.js') diff --git a/sources/core/focusmanager.js b/sources/core/focusmanager.js new file mode 100644 index 00000000..b9c779bf --- /dev/null +++ b/sources/core/focusmanager.js @@ -0,0 +1,273 @@ +/** + * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or http://ckeditor.com/license + */ + +/** + * @fileOverview Defines the {@link CKEDITOR.focusManager} class, which is used + * to handle the focus in editor instances. + */ + +( function() { + /** + * Manages the focus activity in an editor instance. This class is to be + * used mainly by UI element coders when adding interface elements that need + * to set the focus state of the editor. + * + * var focusManager = new CKEDITOR.focusManager( editor ); + * focusManager.focus(); + * + * @class + * @constructor Creates a focusManager class instance. + * @param {CKEDITOR.editor} editor The editor instance. + */ + CKEDITOR.focusManager = function( editor ) { + if ( editor.focusManager ) + return editor.focusManager; + + /** + * Indicates that the editor instance has focus. + * + * alert( CKEDITOR.instances.editor1.focusManager.hasFocus ); // e.g. true + */ + this.hasFocus = false; + + /** + * Indicates the currently focused DOM element that makes the editor activated. + * + * @property {CKEDITOR.dom.domObject} + */ + this.currentActive = null; + + /** + * Object used to store private stuff. + * + * @private + */ + this._ = { + editor: editor + }; + + return this; + }; + + var SLOT_NAME = 'focusmanager', + SLOT_NAME_LISTENERS = 'focusmanager_handlers'; + + /** + * Object used to store private stuff. + * + * @private + * @class + * @singleton + */ + CKEDITOR.focusManager._ = { + /** + * The delay (in milliseconds) to deactivate the editor when a UI DOM element has lost focus. + * + * @private + * @property {Number} [blurDelay=200] + * @member CKEDITOR.focusManager._ + */ + blurDelay: 200 + }; + + CKEDITOR.focusManager.prototype = { + + /** + * Indicates that this editor instance is activated (due to a DOM focus change). + * The `activated` state is a symbolic indicator of an active user + * interaction session. + * + * **Note:** This method will not introduce UI focus + * impact on DOM, it is here to record the editor UI focus state internally. + * If you want to make the cursor blink inside the editable, use + * {@link CKEDITOR.editor#method-focus} instead. + * + * var editor = CKEDITOR.instances.editor1; + * editor.focusManage.focus( editor.editable() ); + * + * @param {CKEDITOR.dom.element} [currentActive] The new value of the {@link #currentActive} property. + * @member CKEDITOR.focusManager + */ + focus: function( currentActive ) { + if ( this._.timer ) + clearTimeout( this._.timer ); + + if ( currentActive ) + this.currentActive = currentActive; + + if ( !( this.hasFocus || this._.locked ) ) { + // If another editor has the current focus, we first "blur" it. In + // this way the events happen in a more logical sequence, like: + // "focus 1" > "blur 1" > "focus 2" + // ... instead of: + // "focus 1" > "focus 2" > "blur 1" + var current = CKEDITOR.currentInstance; + current && current.focusManager.blur( 1 ); + + this.hasFocus = true; + + var ct = this._.editor.container; + ct && ct.addClass( 'cke_focus' ); + this._.editor.fire( 'focus' ); + } + }, + + /** + * Prevents from changing the focus manager state until the next {@link #unlock} is called. + * + * @member CKEDITOR.focusManager + */ + lock: function() { + this._.locked = 1; + }, + + /** + * Restores the automatic focus management if {@link #lock} is called. + * + * @member CKEDITOR.focusManager + */ + unlock: function() { + delete this._.locked; + }, + + /** + * Used to indicate that the editor instance has been deactivated by the specified + * element which has just lost focus. + * + * **Note:** This function acts asynchronously with a delay of 100ms to + * avoid temporary deactivation. Use the `noDelay` parameter instead + * to deactivate immediately. + * + * var editor = CKEDITOR.instances.editor1; + * editor.focusManager.blur(); + * + * @param {Boolean} [noDelay=false] Immediately deactivate the editor instance synchronously. + * @member CKEDITOR.focusManager + */ + blur: function( noDelay ) { + if ( this._.locked ) + return; + + function doBlur() { + if ( this.hasFocus ) { + this.hasFocus = false; + + var ct = this._.editor.container; + ct && ct.removeClass( 'cke_focus' ); + this._.editor.fire( 'blur' ); + } + } + + if ( this._.timer ) + clearTimeout( this._.timer ); + + var delay = CKEDITOR.focusManager._.blurDelay; + if ( noDelay || !delay ) + doBlur.call( this ); + else { + this._.timer = CKEDITOR.tools.setTimeout( function() { + delete this._.timer; + doBlur.call( this ); + }, delay, this ); + } + }, + + /** + * Registers a UI DOM element to the focus manager, which will make the focus manager "hasFocus" + * once the input focus is relieved on the element. + * This method is designed to be used by plugins to expand the jurisdiction of the editor focus. + * + * @param {CKEDITOR.dom.element} element The container (topmost) element of one UI part. + * @param {Boolean} isCapture If specified, {@link CKEDITOR.event#useCapture} will be used when listening to the focus event. + * @member CKEDITOR.focusManager + */ + add: function( element, isCapture ) { + var fm = element.getCustomData( SLOT_NAME ); + if ( !fm || fm != this ) { + // If this element is already taken by another instance, dismiss it first. + fm && fm.remove( element ); + + var focusEvent = 'focus', + blurEvent = 'blur'; + + // Bypass the element's internal DOM focus change. + if ( isCapture ) { + + // Use "focusin/focusout" events instead of capture phase in IEs, + // which fires synchronously. + if ( CKEDITOR.env.ie ) { + focusEvent = 'focusin'; + blurEvent = 'focusout'; + } else { + CKEDITOR.event.useCapture = 1; + } + } + + var listeners = { + blur: function() { + if ( element.equals( this.currentActive ) ) + this.blur(); + }, + focus: function() { + this.focus( element ); + } + }; + + element.on( focusEvent, listeners.focus, this ); + element.on( blurEvent, listeners.blur, this ); + + if ( isCapture ) + CKEDITOR.event.useCapture = 0; + + element.setCustomData( SLOT_NAME, this ); + element.setCustomData( SLOT_NAME_LISTENERS, listeners ); + } + }, + + /** + * Dismisses an element from the focus manager delegations added by {@link #add}. + * + * @param {CKEDITOR.dom.element} element The element to be removed from the focus manager. + * @member CKEDITOR.focusManager + */ + remove: function( element ) { + element.removeCustomData( SLOT_NAME ); + var listeners = element.removeCustomData( SLOT_NAME_LISTENERS ); + element.removeListener( 'blur', listeners.blur ); + element.removeListener( 'focus', listeners.focus ); + } + + }; + +} )(); + +/** + * Fired when the editor instance receives the input focus. + * + * editor.on( 'focus', function( e ) { + * alert( 'The editor named ' + e.editor.name + ' is now focused' ); + * } ); + * + * @event focus + * @member CKEDITOR.editor + * @param {CKEDITOR.editor} editor The editor instance. + */ + +/** + * Fired when the editor instance loses the input focus. + * + * **Note:** This event will **NOT** be triggered when focus is moved internally, e.g. from + * an editable to another part of the editor UI like a dialog window. + * If you are interested only in the focus state of the editable, listen to the `focus` + * and `blur` events of the {@link CKEDITOR.editable} instead. + * + * editor.on( 'blur', function( e ) { + * alert( 'The editor named ' + e.editor.name + ' lost the focus' ); + * } ); + * + * @event blur + * @member CKEDITOR.editor + * @param {CKEDITOR.editor} editor The editor instance. + */ -- cgit v1.2.3