index.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. IServiceManager, createServiceManager
  5. } from 'jupyter-js-services';
  6. import {
  7. FileBrowserWidget, FileBrowserModel
  8. } from 'jupyterlab/lib/filebrowser';
  9. import {
  10. DocumentManager
  11. } from 'jupyterlab/lib/docmanager';
  12. import {
  13. DocumentRegistry, TextModelFactory
  14. } from 'jupyterlab/lib/docregistry';
  15. import {
  16. EditorWidgetFactory
  17. } from 'jupyterlab/lib/editorwidget/widget';
  18. import {
  19. showDialog, okButton
  20. } from 'jupyterlab/lib/dialog';
  21. import {
  22. DockPanel
  23. } from 'phosphor-dockpanel';
  24. import {
  25. KeymapManager
  26. } from 'phosphor-keymap';
  27. import {
  28. Menu, MenuItem
  29. } from 'phosphor-menus';
  30. import {
  31. SplitPanel
  32. } from 'phosphor-splitpanel';
  33. import {
  34. Widget
  35. } from 'phosphor-widget';
  36. import 'jupyterlab/lib/index.css';
  37. import 'jupyterlab/lib/theme.css';
  38. function main(): void {
  39. createServiceManager().then(manager => {
  40. createApp(manager);
  41. });
  42. }
  43. function createApp(manager: IServiceManager): void {
  44. let widgets: Widget[] = [];
  45. let activeWidget: Widget;
  46. let opener = {
  47. open: (widget: Widget) => {
  48. if (widgets.indexOf(widget) === -1) {
  49. dock.insertTabAfter(widget);
  50. widgets.push(widget);
  51. }
  52. dock.selectWidget(widget);
  53. activeWidget = widget;
  54. widget.disposed.connect((w: Widget) => {
  55. let index = widgets.indexOf(w);
  56. widgets.splice(index, 1);
  57. });
  58. }
  59. };
  60. let docRegistry = new DocumentRegistry();
  61. let docManager = new DocumentManager({
  62. registry: docRegistry,
  63. manager,
  64. opener
  65. });
  66. let mFactory = new TextModelFactory();
  67. let wFactory = new EditorWidgetFactory();
  68. docRegistry.addModelFactory(mFactory);
  69. docRegistry.addWidgetFactory(wFactory, {
  70. displayName: 'Editor',
  71. modelName: 'text',
  72. fileExtensions: ['*'],
  73. defaultFor: ['*'],
  74. preferKernel: false,
  75. canStartKernel: true
  76. });
  77. let fbModel = new FileBrowserModel({ manager });
  78. let fbWidget = new FileBrowserWidget({
  79. model: fbModel,
  80. manager: docManager,
  81. opener
  82. });
  83. let panel = new SplitPanel();
  84. panel.id = 'main';
  85. panel.addChild(fbWidget);
  86. SplitPanel.setStretch(fbWidget, 0);
  87. let dock = new DockPanel();
  88. panel.addChild(dock);
  89. SplitPanel.setStretch(dock, 1);
  90. dock.spacing = 8;
  91. document.addEventListener('focus', event => {
  92. for (let i = 0; i < widgets.length; i++) {
  93. let widget = widgets[i];
  94. if (widget.node.contains(event.target as HTMLElement)) {
  95. activeWidget = widget;
  96. break;
  97. }
  98. }
  99. });
  100. let keymapManager = new KeymapManager();
  101. keymapManager.add([{
  102. sequence: ['Enter'],
  103. selector: '.jp-DirListing',
  104. handler: () => {
  105. fbWidget.open();
  106. }
  107. }, {
  108. sequence: ['Ctrl N'], // Add emacs keybinding for select next.
  109. selector: '.jp-DirListing',
  110. handler: () => {
  111. fbWidget.selectNext();
  112. }
  113. }, {
  114. sequence: ['Ctrl P'], // Add emacs keybinding for select previous.
  115. selector: '.jp-DirListing',
  116. handler: () => {
  117. fbWidget.selectPrevious();
  118. }
  119. }, {
  120. sequence: ['Accel S'],
  121. selector: '.jp-CodeMirrorWidget',
  122. handler: () => {
  123. let context = docManager.contextForWidget(activeWidget);
  124. context.save();
  125. }
  126. }]);
  127. window.addEventListener('keydown', (event) => {
  128. keymapManager.processKeydownEvent(event);
  129. });
  130. let contextMenu = new Menu([
  131. new MenuItem({
  132. text: '&Open',
  133. icon: 'fa fa-folder-open-o',
  134. shortcut: 'Ctrl+O',
  135. handler: () => { fbWidget.open(); }
  136. }),
  137. new MenuItem({
  138. text: '&Rename',
  139. icon: 'fa fa-edit',
  140. shortcut: 'Ctrl+R',
  141. handler: () => { fbWidget.rename(); }
  142. }),
  143. new MenuItem({
  144. text: '&Delete',
  145. icon: 'fa fa-remove',
  146. shortcut: 'Ctrl+D',
  147. handler: () => { fbWidget.delete(); }
  148. }),
  149. new MenuItem({
  150. text: 'Duplicate',
  151. icon: 'fa fa-copy',
  152. handler: () => { fbWidget.duplicate(); }
  153. }),
  154. new MenuItem({
  155. text: 'Cut',
  156. icon: 'fa fa-cut',
  157. shortcut: 'Ctrl+X',
  158. handler: () => { fbWidget.cut(); }
  159. }),
  160. new MenuItem({
  161. text: '&Copy',
  162. icon: 'fa fa-copy',
  163. shortcut: 'Ctrl+C',
  164. handler: () => { fbWidget.copy(); }
  165. }),
  166. new MenuItem({
  167. text: '&Paste',
  168. icon: 'fa fa-paste',
  169. shortcut: 'Ctrl+V',
  170. handler: () => { fbWidget.paste(); }
  171. }),
  172. new MenuItem({
  173. text: 'Download',
  174. icon: 'fa fa-download',
  175. handler: () => { fbWidget.download(); }
  176. }),
  177. new MenuItem({
  178. text: 'Shutdown Kernel',
  179. icon: 'fa fa-stop-circle-o',
  180. handler: () => { fbWidget.shutdownKernels(); }
  181. }),
  182. new MenuItem({
  183. text: 'Dialog Demo',
  184. handler: () => { dialogDemo(); }
  185. }),
  186. new MenuItem({
  187. text: 'Info Demo',
  188. handler: () => {
  189. let msg = 'The quick brown fox jumped over the lazy dog';
  190. showDialog({
  191. title: 'Cool Title',
  192. body: msg,
  193. buttons: [okButton]
  194. });
  195. }
  196. })
  197. ]);
  198. // Add a context menu to the dir listing.
  199. let node = fbWidget.node.getElementsByClassName('jp-DirListing-content')[0];
  200. node.addEventListener('contextmenu', (event: MouseEvent) => {
  201. event.preventDefault();
  202. let x = event.clientX;
  203. let y = event.clientY;
  204. contextMenu.popup(x, y);
  205. });
  206. panel.attach(document.body);
  207. window.onresize = () => panel.update();
  208. }
  209. /**
  210. * Create a non-functional dialog demo.
  211. */
  212. function dialogDemo(): void {
  213. let body = document.createElement('div');
  214. let input = document.createElement('input');
  215. input.value = 'Untitled.ipynb';
  216. let selector = document.createElement('select');
  217. let option0 = document.createElement('option');
  218. option0.value = 'python';
  219. option0.text = 'Python 3';
  220. selector.appendChild(option0);
  221. let option1 = document.createElement('option');
  222. option1.value = 'julia';
  223. option1.text = 'Julia';
  224. selector.appendChild(option1);
  225. body.appendChild(input);
  226. body.appendChild(selector);
  227. showDialog({
  228. title: 'Create new notebook'
  229. });
  230. }
  231. window.onload = main;