commandpalette.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /* -----------------------------------------------------------------------------
  2. | Copyright (c) Jupyter Development Team.
  3. | Distributed under the terms of the Modified BSD License.
  4. |----------------------------------------------------------------------------*/
  5. import { Token } from '@lumino/coreutils';
  6. import { IDisposable } from '@lumino/disposable';
  7. import { Message } from '@lumino/messaging';
  8. import { CommandPalette, Widget, Panel } from '@lumino/widgets';
  9. /* tslint:disable */
  10. /**
  11. * The command palette token.
  12. */
  13. export const ICommandPalette = new Token<ICommandPalette>(
  14. '@jupyterlab/apputils:ICommandPalette'
  15. );
  16. /* tslint:enable */
  17. /**
  18. * The options for creating a command palette item.
  19. */
  20. export interface IPaletteItem extends CommandPalette.IItemOptions {}
  21. /**
  22. * The interface for a Jupyter Lab command palette.
  23. */
  24. export interface ICommandPalette {
  25. /**
  26. * The placeholder text of the command palette's search input.
  27. */
  28. placeholder: string;
  29. /**
  30. * Activate the command palette for user input.
  31. */
  32. activate(): void;
  33. /**
  34. * Add a command item to the command palette.
  35. *
  36. * @param options - The options for creating the command item.
  37. *
  38. * @returns A disposable that will remove the item from the palette.
  39. */
  40. addItem(options: IPaletteItem): IDisposable;
  41. }
  42. /**
  43. * Wrap the command palette in a modal to make it more usable.
  44. */
  45. export class ModalCommandPalette extends Panel {
  46. constructor(options: ModalCommandPalette.IOptions) {
  47. super();
  48. this.addClass('jp-ModalCommandPalette');
  49. this.id = 'modal-command-palette';
  50. this._commandPalette = options.commandPalette;
  51. this.addWidget(this._commandPalette);
  52. this._commandPalette.commands.commandExecuted.connect(() => {
  53. if (this.isAttached && this.isVisible) {
  54. this.hideAndReset();
  55. }
  56. });
  57. this.hideAndReset();
  58. }
  59. get palette(): CommandPalette {
  60. return this._commandPalette;
  61. }
  62. set palette(value: CommandPalette) {
  63. this._commandPalette = value;
  64. this.addWidget(value);
  65. this.hideAndReset();
  66. }
  67. attach(): void {
  68. Widget.attach(this, document.body);
  69. }
  70. detach(): void {
  71. Widget.detach(this);
  72. }
  73. /**
  74. * Hide the modal command palette and reset its search.
  75. */
  76. hideAndReset(): void {
  77. this.hide();
  78. this._commandPalette.inputNode.value = '';
  79. this._commandPalette.refresh();
  80. }
  81. /**
  82. * Handle incoming events.
  83. */
  84. handleEvent(event: Event): void {
  85. switch (event.type) {
  86. case 'keydown':
  87. this._evtKeydown(event as KeyboardEvent);
  88. break;
  89. case 'focus':
  90. // if the focus shifted outside of this DOM element, hide and reset.
  91. const target = event.target as HTMLElement;
  92. if (!this.node.contains(target as HTMLElement)) {
  93. event.stopPropagation();
  94. this.hideAndReset();
  95. }
  96. break;
  97. case 'contextmenu':
  98. event.preventDefault();
  99. event.stopPropagation();
  100. break;
  101. default:
  102. break;
  103. }
  104. }
  105. /**
  106. * A message handler invoked on an `'after-attach'` message.
  107. */
  108. protected onAfterAttach(msg: Message): void {
  109. this.node.addEventListener('keydown', this, true);
  110. this.node.addEventListener('contextmenu', this, true);
  111. }
  112. /**
  113. * A message handler invoked on an `'after-detach'` message.
  114. */
  115. protected onAfterDetach(msg: Message): void {
  116. this.node.removeEventListener('keydown', this, true);
  117. this.node.removeEventListener('contextmenu', this, true);
  118. }
  119. protected onBeforeHide(msg: Message): void {
  120. document.removeEventListener('focus', this, true);
  121. }
  122. protected onAfterShow(msg: Message): void {
  123. document.addEventListener('focus', this, true);
  124. }
  125. /**
  126. * A message handler invoked on an `'activate-request'` message.
  127. */
  128. protected onActivateRequest(msg: Message): void {
  129. if (this.isAttached) {
  130. this.show();
  131. this._commandPalette.activate();
  132. }
  133. }
  134. /**
  135. * Handle the `'keydown'` event for the widget.
  136. */
  137. protected _evtKeydown(event: KeyboardEvent): void {
  138. // Check for escape key
  139. switch (event.keyCode) {
  140. case 27: // Escape.
  141. event.stopPropagation();
  142. event.preventDefault();
  143. this.hideAndReset();
  144. break;
  145. default:
  146. break;
  147. }
  148. }
  149. private _commandPalette: CommandPalette;
  150. }
  151. export namespace ModalCommandPalette {
  152. export interface IOptions {
  153. commandPalette: CommandPalette;
  154. }
  155. }