plugin.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. 'use strict';
  4. import {
  5. FileBrowserWidget, FileHandler
  6. } from 'jupyter-js-filebrowser';
  7. import {
  8. IAppShell, ICommandPalette, ICommandRegistry, IShortcutManager
  9. } from 'phosphide';
  10. import {
  11. SimpleCommand
  12. } from 'phosphor-command';
  13. import {
  14. Container, Token
  15. } from 'phosphor-di';
  16. import {
  17. Property
  18. } from 'phosphor-properties';
  19. import {
  20. TabPanel
  21. } from 'phosphor-tabs';
  22. import {
  23. Widget
  24. } from 'phosphor-widget';
  25. import {
  26. IFileBrowserWidget
  27. } from '../index';
  28. import {
  29. IFileOpener, IFileHandler
  30. } from './index';
  31. /**
  32. * Register the plugin contributions.
  33. */
  34. export
  35. function resolve(container: Container): Promise<void> {
  36. return container.resolve({
  37. requires: [IAppShell, IFileOpener, IFileBrowserWidget, ICommandPalette, ICommandRegistry, IShortcutManager],
  38. create: (appShell: IAppShell, opener: IFileOpener, browser: IFileBrowserWidget, palette: ICommandPalette, registry: ICommandRegistry, shortcuts: IShortcutManager): void => {
  39. // Create a command to add a new empty text file.
  40. // This requires an id and an instance of a command object.
  41. let newTextFileId = 'file-operations:new-text-file';
  42. let newTextFileCommand = new SimpleCommand({
  43. handler: () => {
  44. browser.newUntitled('file', '.txt').then(
  45. contents => opener.open(contents.path)
  46. );
  47. }
  48. });
  49. // Add the command to the command registry, shortcut manager
  50. // and command palette plugins.
  51. registry.add([
  52. {
  53. id: newTextFileId,
  54. command: newTextFileCommand
  55. }
  56. ]);
  57. shortcuts.add([
  58. {
  59. sequence: ['Ctrl O'],
  60. selector: '*',
  61. command: newTextFileId
  62. }
  63. ]);
  64. palette.add([
  65. {
  66. id: newTextFileId,
  67. args: void 0
  68. }
  69. ]);
  70. // Add the command for a new notebook.
  71. let newNotebookId = 'file-operations:new-notebook';
  72. let newNotebookCommand = new SimpleCommand({
  73. handler: () => {
  74. browser.newUntitled('notebook').then(
  75. contents => opener.open(contents.path)
  76. );
  77. }
  78. });
  79. registry.add([
  80. {
  81. id: newNotebookId,
  82. command: newNotebookCommand
  83. }
  84. ]);
  85. shortcuts.add([
  86. {
  87. sequence: ['Ctrl Shift N'],
  88. selector: '*',
  89. command: newNotebookId
  90. }
  91. ]);
  92. palette.add([
  93. {
  94. id: newNotebookId,
  95. args: void 0
  96. }
  97. ]);
  98. browser.widgetFactory = path => {
  99. return opener.open(path);
  100. }
  101. }
  102. });
  103. }
  104. export
  105. function register(container: Container): void {
  106. container.register(IFileOpener, {
  107. requires: [IAppShell, IFileBrowserWidget],
  108. create: (appShell, browserProvider): IFileOpener => {
  109. return new FileOpener(appShell, browserProvider);
  110. }
  111. });
  112. }
  113. /**
  114. * An implementation on an IFileOpener.
  115. */
  116. class FileOpener implements IFileOpener {
  117. /**
  118. * Construct a new file opener.
  119. */
  120. constructor(appShell: IAppShell, browser: IFileBrowserWidget) {
  121. this._appShell = appShell;
  122. browser.openRequested.connect(this._openRequested,
  123. this);
  124. }
  125. /**
  126. * Register a file handler.
  127. */
  128. register(handler: IFileHandler): void {
  129. this._handlers.push(handler);
  130. }
  131. /**
  132. * Register a default file handler.
  133. */
  134. registerDefault(handler: IFileHandler): void {
  135. if (this._defaultHandler !== null) {
  136. throw Error('Default handler already registered');
  137. }
  138. this._handlers.push(handler);
  139. this._defaultHandler = handler;
  140. }
  141. /**
  142. * Open a file and add it to the application shell.
  143. */
  144. open(path: string): Widget {
  145. if (this._handlers.length === 0) {
  146. return;
  147. }
  148. let ext = '.' + path.split('.').pop();
  149. let handlers: IFileHandler[] = [];
  150. // Look for matching file extensions.
  151. for (let h of this._handlers) {
  152. if (h.fileExtensions.indexOf(ext) !== -1) handlers.push(h);
  153. }
  154. // If there was only one match, use it.
  155. if (handlers.length === 1) {
  156. return this._open(handlers[0], path);
  157. // If there were no matches, use default handler.
  158. } else if (handlers.length === 0) {
  159. if (this._defaultHandler !== null) {
  160. return this._open(this._defaultHandler, path);
  161. } else {
  162. throw new Error(`Could not open file '${path}'`);
  163. }
  164. // There are more than one possible handlers.
  165. } else {
  166. // TODO: Ask the user to choose one.
  167. return this._open(handlers[0], path);
  168. }
  169. }
  170. /**
  171. * Handle an `openRequested` signal by invoking the appropriate handler.
  172. */
  173. private _openRequested(browser: FileBrowserWidget, path: string): void {
  174. this.open(path);
  175. }
  176. /**
  177. * Open a file and add it to the application shell and give it focus.
  178. */
  179. private _open(handler: IFileHandler, path: string): Widget {
  180. let widget = handler.open(path);
  181. if (!widget.isAttached) {
  182. this._appShell.addToMainArea(widget);
  183. }
  184. let stack = widget.parent;
  185. if (!stack) {
  186. return;
  187. }
  188. let tabs = stack.parent;
  189. if (tabs instanceof TabPanel) {
  190. tabs.currentWidget = widget;
  191. }
  192. return widget;
  193. }
  194. private _handlers: IFileHandler[] = [];
  195. private _appShell: IAppShell = null;
  196. private _defaultHandler: IFileHandler = null;
  197. }