index.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. ILayoutRestorer,
  5. JupyterLab,
  6. JupyterLabPlugin
  7. } from '@jupyterlab/application';
  8. import { InstanceTracker, IThemeManager, Dialog } from '@jupyterlab/apputils';
  9. import {
  10. CSVViewer,
  11. TextRenderConfig,
  12. CSVViewerFactory,
  13. TSVViewerFactory
  14. } from '@jupyterlab/csvviewer';
  15. import { IDocumentWidget } from '@jupyterlab/docregistry';
  16. import { DataGrid } from '@phosphor/datagrid';
  17. import { IMainMenu, IEditMenu } from '@jupyterlab/mainmenu';
  18. /**
  19. * The name of the factories that creates widgets.
  20. */
  21. const FACTORY_CSV = 'CSVTable';
  22. const FACTORY_TSV = 'TSVTable';
  23. /**
  24. * The CSV file handler extension.
  25. */
  26. const csv: JupyterLabPlugin<void> = {
  27. activate: activateCsv,
  28. id: '@jupyterlab/csvviewer-extension:csv',
  29. requires: [ILayoutRestorer, IThemeManager, IMainMenu],
  30. autoStart: true
  31. };
  32. /**
  33. * The TSV file handler extension.
  34. */
  35. const tsv: JupyterLabPlugin<void> = {
  36. activate: activateTsv,
  37. id: '@jupyterlab/csvviewer-extension:tsv',
  38. requires: [ILayoutRestorer, IThemeManager, IMainMenu],
  39. autoStart: true
  40. };
  41. /**
  42. * Connect menu entries for find and go to line.
  43. */
  44. function addMenuEntries(
  45. mainMenu: IMainMenu,
  46. tracker: InstanceTracker<IDocumentWidget<CSVViewer>>
  47. ) {
  48. // Add find capability to the edit menu.
  49. mainMenu.editMenu.findReplacers.add({
  50. tracker,
  51. find: (widget: IDocumentWidget<CSVViewer>) => {
  52. return Dialog.prompt<string>(
  53. 'Search Text',
  54. widget.content.searchService.searchText
  55. ).then(value => {
  56. if (value.button.accept) {
  57. widget.content.searchService.find(value.value);
  58. }
  59. });
  60. }
  61. } as IEditMenu.IFindReplacer<IDocumentWidget<CSVViewer>>);
  62. // Add go to line capability to the edit menu.
  63. mainMenu.editMenu.goToLiners.add({
  64. tracker,
  65. goToLine: (widget: IDocumentWidget<CSVViewer>) => {
  66. return Dialog.prompt<number>('Go to Line', 0).then(value => {
  67. if (value.button.accept) {
  68. widget.content.goToLine(value.value);
  69. }
  70. });
  71. }
  72. } as IEditMenu.IGoToLiner<IDocumentWidget<CSVViewer>>);
  73. }
  74. /**
  75. * Activate cssviewer extension for CSV files
  76. */
  77. function activateCsv(
  78. app: JupyterLab,
  79. restorer: ILayoutRestorer,
  80. themeManager: IThemeManager,
  81. mainMenu: IMainMenu
  82. ): void {
  83. const factory = new CSVViewerFactory({
  84. name: FACTORY_CSV,
  85. fileTypes: ['csv'],
  86. defaultFor: ['csv'],
  87. readOnly: true
  88. });
  89. const tracker = new InstanceTracker<IDocumentWidget<CSVViewer>>({
  90. namespace: 'csvviewer'
  91. });
  92. // The current styles for the data grids.
  93. let style: DataGrid.IStyle = Private.LIGHT_STYLE;
  94. let rendererConfig: TextRenderConfig = Private.LIGHT_TEXT_CONFIG;
  95. // Handle state restoration.
  96. restorer.restore(tracker, {
  97. command: 'docmanager:open',
  98. args: widget => ({ path: widget.context.path, factory: FACTORY_CSV }),
  99. name: widget => widget.context.path
  100. });
  101. app.docRegistry.addWidgetFactory(factory);
  102. let ft = app.docRegistry.getFileType('csv');
  103. factory.widgetCreated.connect((sender, widget) => {
  104. // Track the widget.
  105. tracker.add(widget);
  106. // Notify the instance tracker if restore data needs to update.
  107. widget.context.pathChanged.connect(() => {
  108. tracker.save(widget);
  109. });
  110. if (ft) {
  111. widget.title.iconClass = ft.iconClass;
  112. widget.title.iconLabel = ft.iconLabel;
  113. }
  114. // Set the theme for the new widget.
  115. widget.content.style = style;
  116. widget.content.rendererConfig = rendererConfig;
  117. });
  118. // Keep the themes up-to-date.
  119. const updateThemes = () => {
  120. const isLight = themeManager.isLight(themeManager.theme);
  121. style = isLight ? Private.LIGHT_STYLE : Private.DARK_STYLE;
  122. rendererConfig = isLight
  123. ? Private.LIGHT_TEXT_CONFIG
  124. : Private.DARK_TEXT_CONFIG;
  125. tracker.forEach(grid => {
  126. grid.content.style = style;
  127. grid.content.rendererConfig = rendererConfig;
  128. });
  129. };
  130. themeManager.themeChanged.connect(updateThemes);
  131. addMenuEntries(mainMenu, tracker);
  132. }
  133. /**
  134. * Activate cssviewer extension for TSV files
  135. */
  136. function activateTsv(
  137. app: JupyterLab,
  138. restorer: ILayoutRestorer,
  139. themeManager: IThemeManager,
  140. mainMenu: IMainMenu
  141. ): void {
  142. const factory = new TSVViewerFactory({
  143. name: FACTORY_TSV,
  144. fileTypes: ['tsv'],
  145. defaultFor: ['tsv'],
  146. readOnly: true
  147. });
  148. const tracker = new InstanceTracker<IDocumentWidget<CSVViewer>>({
  149. namespace: 'tsvviewer'
  150. });
  151. // The current styles for the data grids.
  152. let style: DataGrid.IStyle = Private.LIGHT_STYLE;
  153. let rendererConfig: TextRenderConfig = Private.LIGHT_TEXT_CONFIG;
  154. // Handle state restoration.
  155. restorer.restore(tracker, {
  156. command: 'docmanager:open',
  157. args: widget => ({ path: widget.context.path, factory: FACTORY_TSV }),
  158. name: widget => widget.context.path
  159. });
  160. app.docRegistry.addWidgetFactory(factory);
  161. let ft = app.docRegistry.getFileType('tsv');
  162. factory.widgetCreated.connect((sender, widget) => {
  163. // Track the widget.
  164. tracker.add(widget);
  165. // Notify the instance tracker if restore data needs to update.
  166. widget.context.pathChanged.connect(() => {
  167. tracker.save(widget);
  168. });
  169. if (ft) {
  170. widget.title.iconClass = ft.iconClass;
  171. widget.title.iconLabel = ft.iconLabel;
  172. }
  173. // Set the theme for the new widget.
  174. widget.content.style = style;
  175. widget.content.rendererConfig = rendererConfig;
  176. });
  177. // Keep the themes up-to-date.
  178. const updateThemes = () => {
  179. const isLight = themeManager.isLight(themeManager.theme);
  180. style = isLight ? Private.LIGHT_STYLE : Private.DARK_STYLE;
  181. rendererConfig = isLight
  182. ? Private.LIGHT_TEXT_CONFIG
  183. : Private.DARK_TEXT_CONFIG;
  184. tracker.forEach(grid => {
  185. grid.content.style = style;
  186. grid.content.rendererConfig = rendererConfig;
  187. });
  188. };
  189. themeManager.themeChanged.connect(updateThemes);
  190. addMenuEntries(mainMenu, tracker);
  191. }
  192. /**
  193. * Export the plugins as default.
  194. */
  195. const plugins: JupyterLabPlugin<any>[] = [csv, tsv];
  196. export default plugins;
  197. /**
  198. * A namespace for private data.
  199. */
  200. namespace Private {
  201. /**
  202. * The light theme for the data grid.
  203. */
  204. export const LIGHT_STYLE: DataGrid.IStyle = {
  205. ...DataGrid.defaultStyle,
  206. voidColor: '#F3F3F3',
  207. backgroundColor: 'white',
  208. headerBackgroundColor: '#EEEEEE',
  209. gridLineColor: 'rgba(20, 20, 20, 0.15)',
  210. headerGridLineColor: 'rgba(20, 20, 20, 0.25)',
  211. rowBackgroundColor: i => (i % 2 === 0 ? '#F5F5F5' : 'white')
  212. };
  213. /**
  214. * The dark theme for the data grid.
  215. */
  216. export const DARK_STYLE: DataGrid.IStyle = {
  217. voidColor: 'black',
  218. backgroundColor: '#111111',
  219. headerBackgroundColor: '#424242',
  220. gridLineColor: 'rgba(235, 235, 235, 0.15)',
  221. headerGridLineColor: 'rgba(235, 235, 235, 0.25)',
  222. rowBackgroundColor: i => (i % 2 === 0 ? '#212121' : '#111111')
  223. };
  224. /**
  225. * The light config for the data grid renderer.
  226. */
  227. export const LIGHT_TEXT_CONFIG: TextRenderConfig = {
  228. textColor: '#111111',
  229. matchBackgroundColor: '#FFFFE0',
  230. currentMatchBackgroundColor: '#FFFF00',
  231. horizontalAlignment: 'right'
  232. };
  233. /**
  234. * The dark config for the data grid renderer.
  235. */
  236. export const DARK_TEXT_CONFIG: TextRenderConfig = {
  237. textColor: '#F5F5F5',
  238. matchBackgroundColor: '#838423',
  239. currentMatchBackgroundColor: '#A3807A',
  240. horizontalAlignment: 'right'
  241. };
  242. }