Pārlūkot izejas kodu

Merge pull request #766 from AbdealiJK/ajk/csv

Add delimiter dropdown for CSVWidget
Steven Silvester 8 gadi atpakaļ
vecāks
revīzija
9e2610ede4

+ 80 - 7
src/csvwidget/widget.ts

@@ -17,9 +17,11 @@ import {
   ABCWidgetFactory, IDocumentModel, IDocumentContext
 } from '../docregistry';
 
+import * as d3Dsv from 'd3-dsv';
+
 import {
-  csvParse
-} from 'd3-dsv';
+  PanelLayout
+} from 'phosphor/lib/ui/panel';
 
 
 /**
@@ -27,6 +29,21 @@ import {
  */
 const CSV_CLASS = 'jp-CSVWidget';
 
+/**
+ * The class name added to a csv toolbar widget.
+ */
+const CSV_TOOLBAR_CLASS = 'jp-CSVWidget-toolbar';
+
+/**
+ * The class name added to a csv toolbar's dropdown element.
+ */
+const CSV_TOOLBAR_DROPDOWN_CLASS = 'jp-CSVWidget-toolbarDropdown';
+
+/**
+ * The class name added to a csv table widget.
+ */
+const CSV_TABLE_CLASS = 'jp-CSVWidget-table';
+
 
 /**
  * A widget for csv tables.
@@ -42,6 +59,19 @@ class CSVWidget extends Widget {
     this.node.tabIndex = -1;
     this.addClass(CSV_CLASS);
 
+    this.layout = new PanelLayout();
+    this._toolbar = new Widget({ node: createDelimiterSwitcherNode() });
+    this._toolbar.addClass(CSV_TOOLBAR_CLASS);
+    this._table = new Widget();
+    this._table.addClass(CSV_TABLE_CLASS);
+
+    let layout = this.layout as PanelLayout;
+    layout.addWidget(this._toolbar);
+    layout.addWidget(this._table);
+
+    let select = this._toolbar.node.getElementsByClassName(
+      CSV_TOOLBAR_DROPDOWN_CLASS)[0] as HTMLSelectElement;
+
     if (context.model.toString()) {
       this.update();
     }
@@ -54,6 +84,13 @@ class CSVWidget extends Widget {
     context.contentsModelChanged.connect(() => {
       this.update();
     });
+
+    // Change delimiter on a change in the dropdown.
+    select.addEventListener('change', event => {
+      let value = select.value as string;
+      this.delimiter = select.value;
+      this.update();
+    });
   }
 
   /**
@@ -77,14 +114,15 @@ class CSVWidget extends Widget {
       return;
     }
     let content = this._context.model.toString();
-    this.renderTable(content);
+    let delimiter = this.delimiter as string;
+    this.renderTable(content, delimiter);
   }
 
   /**
    * Render an html table from a csv string.
    */
-  renderTable(content: string) {
-    let parsed = csvParse(content);
+  renderTable(content: string, delimiter: string) {
+    let parsed = d3Dsv.dsvFormat(delimiter).parse(content);
     let table = document.createElement('table');
     let header = document.createElement('tr');
     for (let name of parsed.columns) {
@@ -102,11 +140,46 @@ class CSVWidget extends Widget {
       }
       table.appendChild(tr);
     }
-    this.node.textContent = '';
-    this.node.appendChild(table);
+    this._table.node.textContent = '';
+    this._table.node.appendChild(table);
+  }
+
+  /**
+   * Handle `'activate-request'` messages.
+   */
+  protected onActivateRequest(msg: Message): void {
+    this.node.focus();
   }
 
   private _context: IDocumentContext<IDocumentModel>;
+  private delimiter: string = ",";
+  private _toolbar: Widget = null;
+  private _table: Widget = null;
+}
+
+
+/**
+ * Create the node for the delimiter switcher.
+ */
+function createDelimiterSwitcherNode(): HTMLElement {
+  let div = document.createElement('div');
+  let label = document.createElement('span');
+  label.textContent = 'Delimiter:';
+  let select = document.createElement('select');
+  for (let delim of [',', ';', '\t']) {
+    let option = document.createElement('option');
+    option.value = delim;
+    if (delim === '\t') {
+      option.textContent = '\\t';
+    } else {
+      option.textContent = delim;
+    }
+    select.appendChild(option);
+  }
+  select.className = CSV_TOOLBAR_DROPDOWN_CLASS;
+  div.appendChild(label);
+  div.appendChild(select);
+  return div;
 }
 
 

+ 46 - 4
src/default-theme/csvwidget.less

@@ -4,18 +4,60 @@
 |----------------------------------------------------------------------------*/
 
 .jp-CSVWidget {
+  display: flex;
+  flex-direction: column;
+}
+
+.jp-CSVWidget-toolbar {
+    display: flex;
+    flex: 0 0 auto;
+    flex-direction: row;
+    border-bottom: 1px solid #E0E0E0;
+    height: 32px;
+}
+
+.jp-CSVWidget-toolbar span {
+    color: #757575;
+    font-size: 13px;
+    line-height: 32px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+.jp-CSVWidget-toolbar select {
+    background: #FFFFFF;
+}
+
+.jp-CSVWidget-toolbar .jp-CSVWidget-toolbarDropdown {
+    flex: 0 0 auto;
+    padding-left: 8px;
+    padding-right: 8px;
+    vertical-align: middle;
+    border: 1px solid #BDBDBD;
+    border-radius: 0;
+    outline: none;
+    width: 70px;
+    font-size: 13px;
+    line-height: 23px;
+    color: #616161;
+    margin-top: 4px;
+    margin-bottom: 4px;
+}
+
+
+.jp-CSVWidget-table {
+  flex: 1 1 auto;
   padding: 1em;
   overflow: auto;
 }
 
-
-.jp-CSVWidget th,
-.jp-CSVWidget td {
+.jp-CSVWidget-table th,
+.jp-CSVWidget-table td {
   border: 1px solid black;
   padding: 0.2em 0.5em;
 }
 
-.jp-CSVWidget table {
+.jp-CSVWidget-table table {
   border: 1px solid black;
   border-collapse: collapse;
 }

+ 1 - 0
src/notebook/notebook/widgetfactory.ts

@@ -87,6 +87,7 @@ class NotebookWidgetFactory extends ABCWidgetFactory<NotebookPanel, INotebookMod
     panel.context = context;
     ToolbarItems.populateDefaults(panel);
     this.widgetCreated.emit(panel);
+    console.log(panel.content.childAt(0).editor);
     return panel;
   }
 

+ 82 - 64
typings/d3-dsv/d3-dsv.d.ts

@@ -1,69 +1,87 @@
-// Type definitions for d3-dsv
-// Project: https://www.npmjs.com/package/d3-dsv
-// Definitions by: Jason Swearingen <https://jasonswearingen.github.io>
+// Type definitions for D3JS d3-dsv module v1.0.1
+// Project: https://github.com/d3/d3-dsv/
+// Definitions by: Tom Wanzek <https://github.com/tomwanzek>, Alex Ford <https://github.com/gustavderdrache>, Boris Yankov <https://github.com/borisyankov>
 // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+// Taken from: https://github.com/tomwanzek/d3-v4-definitelytyped/blob/master/src/d3-dsv/index.d.ts
 
-
-//commonjs loader
 declare module "d3-dsv" {
 
-	/** A parser and formatter for DSV (CSV and TSV) files.
-Extracted from D3. */
-export
-    var loader: (
-        /** the symbol used to seperate cells in the row.*/
-        delimiter: string,
-        /** example: "text/plain" */
-        encoding?: string) => _d3dsv.D3Dsv;
-    export
-	function csvParse(content: string): any;
+// ------------------------------------------------------------------------------------------
+// Shared Types and Interfaces
+// ------------------------------------------------------------------------------------------
+
+export interface DSVRowString {
+    [key: string]: string;
+}
+
+export interface DSVRowAny {
+    [key: string]: any;
+}
+
+export interface DSVParsedArray<T> extends Array<T> {
+    columns: Array<string>;
+}
+
+// ------------------------------------------------------------------------------------------
+// CSV Parsers and Formatters
+// ------------------------------------------------------------------------------------------
+
+// csvParse(...) ============================================================================
+
+export function csvParse(csvString: string): DSVParsedArray<DSVRowString>;
+export function csvParse<ParsedRow extends DSVRowAny>(csvString: string, row: (rawRow: DSVRowString, index: number, columns: Array<string>) => ParsedRow): DSVParsedArray<ParsedRow>;
+
+// csvParseRows(...) ========================================================================
+
+export function csvParseRows(csvString: string): Array<Array<string>>;
+export function csvParseRows<ParsedRow extends DSVRowAny>(csvString: string, row: (rawRow: Array<string>, index: number) => ParsedRow): Array<ParsedRow>;
+
+// csvFormat(...) ============================================================================
+
+export function csvFormat(rows: Array<DSVRowAny>): string;
+export function csvFormat(rows: Array<DSVRowAny>, columns: Array<string>): string;
+
+// csvFormatRows(...) ========================================================================
+
+export function csvFormatRows(rows: Array<Array<string>>): string;
+
+// ------------------------------------------------------------------------------------------
+// TSV Parsers and Formatters
+// ------------------------------------------------------------------------------------------
+
+// tsvParse(...) ============================================================================
+
+export function tsvParse(tsvString: string): DSVParsedArray<DSVRowString>;
+export function tsvParse<MappedRow extends DSVRowAny>(tsvString: string, row: (rawRow: DSVRowString, index: number, columns: Array<string>) => MappedRow): DSVParsedArray<MappedRow>;
+
+// tsvParseRows(...) ========================================================================
+
+export function tsvParseRows(tsvString: string): Array<Array<string>>;
+export function tsvParseRows<MappedRow extends DSVRowAny>(tsvString: string, row: (rawRow: Array<string>, index: number) => MappedRow): Array<MappedRow>;
+
+// tsvFormat(...) ============================================================================
+
+export function tsvFormat(rows: Array<DSVRowAny>): string;
+export function tsvFormat(rows: Array<DSVRowAny>, columns: Array<string>): string;
+
+// tsvFormatRows(...) ========================================================================
+
+export function tsvFormatRows(rows: Array<Array<string>>): string;
+
+// ------------------------------------------------------------------------------------------
+// DSV Generalized Parsers and Formatters
+// ------------------------------------------------------------------------------------------
+
+export interface DSV {
+    parse(dsvString: string): DSVParsedArray<DSVRowString>;
+    parse<ParsedRow extends DSVRowAny>(dsvString: string, row: (rawRow: DSVRowString, index: number, columns: Array<string>) => ParsedRow): DSVParsedArray<ParsedRow>;
+    parseRows(dsvString: string): Array<Array<string>>;
+    parseRows<ParsedRow extends DSVRowAny>(dsvString: string, row: (rawRow: Array<string>, index: number) => ParsedRow): Array<ParsedRow>;
+    format(rows: Array<DSVRowAny>): string;
+    format(rows: Array<DSVRowAny>, columns: Array<string>): string;
+    formatRows(rows: Array<Array<string>>): string;
+}
+
+export function dsvFormat(delimiter: string): DSV;
+
 }
-declare module _d3dsv {
-	/** A parser and formatter for DSV (CSV and TSV) files.
-Extracted from D3. */
-	export class D3Dsv {
-		/** Parses the specified string, which is the contents of a CSV file, returning an array of objects representing the parsed rows. 
-		The string is assumed to be RFC4180-compliant. 
-		Unlike the parseRows method, this method requires that the first line of the CSV file contains a comma-separated list of column names; 
-		these column names become the attributes on the returned objects. 
-		For example, consider the following CSV file:
-
-Year,Make,Model,Length
-1997,Ford,E350,2.34
-2000,Mercury,Cougar,2.38
-
-The resulting JavaScript array is:
-
-[  {"Year": "1997", "Make": "Ford", "Model": "E350", "Length": "2.34"},
-  {"Year": "2000", "Make": "Mercury", "Model": "Cougar", "Length": "2.38"} ]
-		 */
-		public parse<TRow>(
-			table: string, 
-			/** coerce cells (strings) into different types or modify them. return null to strip this row from the output results. */
-			accessor?: (row: any) => TRow
-			): TRow[];
-		/** Parses the specified string, which is the contents of a CSV file, returning an array of arrays representing the parsed rows. The string is assumed to be RFC4180-compliant. Unlike the parse method, this method treats the header line as a standard row, and should be used whenever the CSV file does not contain a header. Each row is represented as an array rather than an object. Rows may have variable length. For example, consider the following CSV file:
-
-1997,Ford,E350,2.34
-2000,Mercury,Cougar,2.38
-The resulting JavaScript array is:
-
-[  ["1997", "Ford", "E350", "2.34"],
-  ["2000", "Mercury", "Cougar", "2.38"] ]
-Note that the values themselves are always strings; they will not be automatically converted to numbers. See parse for details.*/
-		public parseRows<TRow>(
-			table: string,
-			/** coerce cells (strings) into different types or modify them. return null to strip this row from the output results.*/
-			accessor?: (row: string[]) => TRow
-			): TRow[];
-		/** Converts the specified array of rows into comma-separated values format, returning a string. This operation is the reverse of parse. Each row will be separated by a newline (\n), and each column within each row will be separated by a comma (,). Values that contain either commas, double-quotes (") or newlines will be escaped using double-quotes.
-
-Each row should be an object, and all object properties will be converted into fields. For greater control over which properties are converted, convert the rows into arrays containing only the properties that should be converted and use formatRows. */
-		public format(rows: any[]): string;
-		/** Converts the specified array of rows into comma-separated values format, returning a string. This operation is the reverse of parseRows. Each row will be separated by a newline (\n), and each column within each row will be separated by a comma (,). Values that contain either commas, double-quotes (") or newlines will be escaped using double-quotes. */
-		public formatRows(rows: any[]): string;
-
-
-	}
-
-}