plugin.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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
  9. } from 'phosphide';
  10. import {
  11. DelegateCommand
  12. } from 'phosphor-command';
  13. import {
  14. Container, Token
  15. } from 'phosphor-di';
  16. import {
  17. Property
  18. } from 'phosphor-properties';
  19. import {
  20. Widget
  21. } from 'phosphor-widget';
  22. import {
  23. IFileBrowserProvider
  24. } from '../index';
  25. import {
  26. IFileOpener, IFileHandler
  27. } from './index';
  28. /**
  29. * Register the plugin contributions.
  30. */
  31. export
  32. function resolve(container: Container): Promise<void> {
  33. return container.resolve(FileOpenerProvider).then(provider => provider.run());
  34. }
  35. export
  36. function register(container: Container): void {
  37. container.register(IFileOpener, FileOpener);
  38. }
  39. class FileOpenerProvider {
  40. /**
  41. * The dependencies required by the file opener.
  42. */
  43. static requires: Token<any>[] = [IAppShell, IFileOpener, IFileBrowserProvider, ICommandPalette, ICommandRegistry];
  44. static create(appShell: IAppShell, opener: IFileOpener, browserProvider: IFileBrowserProvider, palette: ICommandPalette, registry: ICommandRegistry): FileOpenerProvider {
  45. return new FileOpenerProvider(appShell, opener, browserProvider, palette, registry);
  46. }
  47. /**
  48. * Construct a new file opener.
  49. */
  50. constructor(appShell: IAppShell, opener: IFileOpener, browserProvider: IFileBrowserProvider, palette: ICommandPalette, registry: ICommandRegistry) {
  51. this._browser = browserProvider.fileBrowser;
  52. this._registry = registry;
  53. this._palette = palette;
  54. this._appShell = appShell;
  55. this._opener = opener;
  56. }
  57. run() {
  58. let newFileCommandItem = {
  59. id: 'jupyter-plugins:new-text-file',
  60. command: new DelegateCommand(() => {
  61. this._browser.newUntitled('file', '.txt').then(
  62. contents => this._opener.open(contents.path)
  63. );
  64. })
  65. }
  66. let newNotebookCommandItem = {
  67. id: 'jupyter-plugins:new-notebook',
  68. command: new DelegateCommand(() => {
  69. this._browser.newUntitled('notebook').then(
  70. contents => this._opener.open(contents.path)
  71. );
  72. })
  73. }
  74. this._registry.add([newFileCommandItem, newNotebookCommandItem]);
  75. let paletteItems = [{
  76. id: 'jupyter-plugins:new-text-file',
  77. title: 'Text File',
  78. caption: ''
  79. }, {
  80. id: 'jupyter-plugins:new-notebook',
  81. title: 'Notebook',
  82. caption: ''
  83. }];
  84. let section = {
  85. text: 'New...',
  86. items: paletteItems
  87. }
  88. this._palette.add([section]);
  89. }
  90. private _appShell: IAppShell = null;
  91. private _defaultHandler: IFileHandler = null;
  92. private _browser: FileBrowserWidget = null;
  93. private _registry: ICommandRegistry = null;
  94. private _palette: ICommandPalette = null;
  95. private _opener: IFileOpener = null;
  96. }
  97. /**
  98. * An implementation on an IFileOpener.
  99. */
  100. class FileOpener implements IFileOpener {
  101. /**
  102. * The dependencies required by the file opener.
  103. */
  104. static requires: Token<any>[] = [IAppShell, IFileBrowserProvider];
  105. /**
  106. * Create a new file opener instance.
  107. */
  108. static create(appShell: IAppShell, browserProvider: IFileBrowserProvider): IFileOpener {
  109. return new FileOpener(appShell, browserProvider);
  110. }
  111. /**
  112. * Construct a new file opener.
  113. */
  114. constructor(appShell: IAppShell, browserProvider: IFileBrowserProvider) {
  115. this._appShell = appShell;
  116. browserProvider.fileBrowser.openRequested.connect(this._openRequested,
  117. this);
  118. }
  119. /**
  120. * Register a file handler.
  121. */
  122. register(handler: IFileHandler): void {
  123. this._handlers.push(handler);
  124. }
  125. /**
  126. * Register a default file handler.
  127. */
  128. registerDefault(handler: IFileHandler): void {
  129. if (this._defaultHandler !== null) {
  130. throw Error('Default handler already registered');
  131. }
  132. this._handlers.push(handler);
  133. this._defaultHandler = handler;
  134. }
  135. /**
  136. * Open a file and add it to the application shell.
  137. */
  138. open(path: string): Widget {
  139. if (this._handlers.length === 0) {
  140. return;
  141. }
  142. let ext = '.' + path.split('.').pop();
  143. let handlers: IFileHandler[] = [];
  144. // Look for matching file extensions.
  145. for (let h of this._handlers) {
  146. if (h.fileExtensions.indexOf(ext) !== -1) handlers.push(h);
  147. }
  148. // If there was only one match, use it.
  149. if (handlers.length === 1) {
  150. return this._open(handlers[0], path);
  151. // If there were no matches, look for default handler(s).
  152. } else if (handlers.length === 0 && this._defaultHandler !== null) {
  153. return this._open(this._defaultHandler, path);
  154. }
  155. // If there we no matches, do nothing.
  156. if (handlers.length == 0) {
  157. throw new Error(`Could not open file '${path}'`);
  158. // If there was one handler, use it.
  159. } else if (handlers.length === 1) {
  160. return this._open(handlers[0], path);
  161. } else {
  162. // There are more than one possible handlers.
  163. // TODO: Ask the user to choose one.
  164. return this._open(handlers[0], path);
  165. }
  166. }
  167. /**
  168. * Handle an `openRequested` signal by invoking the appropriate handler.
  169. */
  170. private _openRequested(browser: FileBrowserWidget, path: string): void {
  171. this.open(path);
  172. }
  173. /**
  174. * Open a file and add it to the application shell.
  175. */
  176. private _open(handler: IFileHandler, path: string): Widget {
  177. var widget = handler.open(path);
  178. this._appShell.addToMainArea(widget);
  179. return widget;
  180. }
  181. private _handlers: IFileHandler[] = [];
  182. private _appShell: IAppShell = null;
  183. private _defaultHandler: IFileHandler = null;
  184. }