focusobserver.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module engine/view/observer/focusobserver
  7. */
  8. /* globals setTimeout, clearTimeout */
  9. import DomEventObserver from './domeventobserver';
  10. /**
  11. * {@link module:engine/view/document~Document#event:focus Focus}
  12. * and {@link module:engine/view/document~Document#event:blur blur} events observer.
  13. * Focus observer handle also {@link module:engine/view/rooteditableelement~RootEditableElement#isFocused isFocused} property of the
  14. * {@link module:engine/view/rooteditableelement~RootEditableElement root elements}.
  15. *
  16. * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.
  17. *
  18. * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  19. */
  20. export default class FocusObserver extends DomEventObserver {
  21. constructor( view ) {
  22. super( view );
  23. this.domEventType = [ 'focus', 'blur' ];
  24. this.useCapture = true;
  25. const document = this.document;
  26. document.on( 'focus', () => {
  27. document.isFocused = true;
  28. // Unfortunately native `selectionchange` event is fired asynchronously.
  29. // We need to wait until `SelectionObserver` handle the event and then render. Otherwise rendering will
  30. // overwrite new DOM selection with selection from the view.
  31. // See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.
  32. // Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.
  33. this._renderTimeoutId = setTimeout( () => view.forceRender(), 50 );
  34. } );
  35. document.on( 'blur', ( evt, data ) => {
  36. const selectedEditable = document.selection.editableElement;
  37. if ( selectedEditable === null || selectedEditable === data.target ) {
  38. document.isFocused = false;
  39. // Re-render the document to update view elements.
  40. view.forceRender();
  41. }
  42. } );
  43. /**
  44. * Identifier of the timeout currently used by focus listener to delay rendering execution.
  45. *
  46. * @private
  47. * @member {Number} #_renderTimeoutId
  48. */
  49. }
  50. onDomEvent( domEvent ) {
  51. this.fire( domEvent.type, domEvent );
  52. }
  53. /**
  54. * @inheritDoc
  55. */
  56. destroy() {
  57. if ( this._renderTimeoutId ) {
  58. clearTimeout( this._renderTimeoutId );
  59. }
  60. super.destroy();
  61. }
  62. }
  63. /**
  64. * Fired when one of the editables gets focus.
  65. *
  66. * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.
  67. *
  68. * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the
  69. * {@link module:engine/view/view~View} this event is available by default.
  70. *
  71. * @see module:engine/view/observer/focusobserver~FocusObserver
  72. * @event module:engine/view/document~Document#event:focus
  73. * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.
  74. */
  75. /**
  76. * Fired when one of the editables loses focus.
  77. *
  78. * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.
  79. *
  80. * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the
  81. * {@link module:engine/view/view~View} this event is available by default.
  82. *
  83. * @see module:engine/view/observer/focusobserver~FocusObserver
  84. * @event module:engine/view/document~Document#event:blur
  85. * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.
  86. */