@@ -8,10 +8,23 @@ import { DockLayout, Widget } from '@lumino/widgets';
88
99import { IVariableInspector } from './tokens' ;
1010
11+ import wildcardMatch from 'wildcard-match' ;
12+
1113const TITLE_CLASS = 'jp-VarInspector-title' ;
1214const PANEL_CLASS = 'jp-VarInspector' ;
1315const TABLE_CLASS = 'jp-VarInspector-table' ;
1416const TABLE_BODY_CLASS = 'jp-VarInspector-content' ;
17+ const TABLE_ROW_CLASS = 'jp-VarInspector-table-row' ;
18+ const TABLE_ROW_HIDDEN_CLASS = 'jp-VarInspector-table-row-hidden' ;
19+ const TABLE_TYPE_CLASS = 'jp-VarInspector-type' ;
20+ const TABLE_NAME_CLASS = 'jp-VarInspector-varName' ;
21+ const FILTER_TYPE_CLASS = 'filter-type' ;
22+ const FILTER_INPUT_CLASS = 'filter-input' ;
23+ const FILTER_BUTTON_CLASS = 'filter-button' ;
24+ const FILTER_LIST_CLASS = 'filter-list' ;
25+ const FILTERED_BUTTON_CLASS = 'filtered-variable-button' ;
26+
27+ type FILTER_TYPES = 'type' | 'name' ;
1528
1629/**
1730 * A panel that renders the variables
@@ -21,8 +34,10 @@ export class VariableInspectorPanel
2134 implements IVariableInspector
2235{
2336 private _source : IVariableInspector . IInspectable | null = null ;
37+ private _filteredTable : HTMLDivElement ;
2438 private _table : HTMLTableElement ;
2539 private _title : HTMLElement ;
40+ private _filtered : { type : Array < string > ; name : Array < string > } ;
2641
2742 constructor ( ) {
2843 super ( ) ;
@@ -31,8 +46,136 @@ export class VariableInspectorPanel
3146 this . _title . className = TITLE_CLASS ;
3247 this . _table = Private . createTable ( ) ;
3348 this . _table . className = TABLE_CLASS ;
49+ this . _filteredTable = Private . createFilterTable ( ) ;
3450 this . node . appendChild ( this . _title as HTMLElement ) ;
51+ this . node . appendChild ( this . _filteredTable as HTMLElement ) ;
3552 this . node . appendChild ( this . _table as HTMLElement ) ;
53+ this . _filtered = { type : [ ] , name : [ ] } ;
54+ this . intializeFilteredTable ( ) ;
55+ }
56+
57+ //Sets up the filter table so when the filter button is pressed, a new filter is created
58+ protected intializeFilteredTable ( ) {
59+ const filterType = this . _filteredTable . querySelector (
60+ '.' + FILTER_TYPE_CLASS
61+ ) as HTMLSelectElement ;
62+ const filterInput = this . _filteredTable . querySelector (
63+ '.' + FILTER_INPUT_CLASS
64+ ) as HTMLInputElement ;
65+ const filterButton = this . _filteredTable . querySelector (
66+ '.' + FILTER_BUTTON_CLASS
67+ ) as HTMLButtonElement ;
68+ filterButton . addEventListener ( 'click' , ( ) => {
69+ this . onFilterChange (
70+ filterType . value as FILTER_TYPES ,
71+ filterInput . value ,
72+ true
73+ ) ;
74+ } ) ;
75+ }
76+
77+ // Checks if string is in the filtered array
78+ protected stringInFilter ( string : string , filterType : FILTER_TYPES ) {
79+ // console.log(this._filtered[filterType]);
80+ for ( let i = 0 ; i < this . _filtered [ filterType ] . length ; i ++ ) {
81+ const isMatch = wildcardMatch ( this . _filtered [ filterType ] [ i ] ) ;
82+ if ( isMatch ( string ) ) {
83+ return true ;
84+ }
85+ }
86+ return false ;
87+ }
88+ /*
89+ Either adds a new filter or removes a previously existing filter based
90+ Params:
91+ filterType: By what type the varName is filtering on
92+ varName: The name of the variable we are trying to filter out
93+ isAdding: If we are adding a new filter or removing a previous filter
94+ */
95+
96+ protected onFilterChange (
97+ filterType : FILTER_TYPES ,
98+ varName : string ,
99+ isAdding : boolean
100+ ) {
101+ if ( varName === '' ) {
102+ return ;
103+ }
104+ if ( isAdding ) {
105+ if ( this . _filtered [ filterType ] . includes ( varName ) ) {
106+ return ;
107+ }
108+ this . _filtered [ filterType ] . push ( varName ) ;
109+ const filterList = this . _filteredTable . querySelector (
110+ '.' + FILTER_LIST_CLASS
111+ ) as HTMLUListElement ;
112+ const newFilteredButton = Private . createFilteredButton (
113+ varName ,
114+ filterType
115+ ) ;
116+ newFilteredButton . addEventListener ( 'click' , ( ) => {
117+ const filterText = newFilteredButton . querySelector (
118+ '.filtered-variable-button-text'
119+ ) as HTMLDivElement ;
120+ this . onFilterChange ( filterType , filterText . innerHTML , false ) ;
121+ this . addFilteredOutRows ( ) ;
122+ newFilteredButton . remove ( ) ;
123+ } ) ;
124+ filterList . appendChild ( newFilteredButton ) ;
125+ this . filterOutTable ( ) ;
126+ } else {
127+ this . _filtered [ filterType ] = this . _filtered [ filterType ] . filter (
128+ filter => filter !== varName
129+ ) ;
130+ }
131+ }
132+
133+ /*
134+ Goes through each filtered out row and checks if they should still be filtered
135+ If not, the row becomes visible again
136+ */
137+ protected addFilteredOutRows ( ) {
138+ const rows = this . _table . querySelectorAll (
139+ '.' + TABLE_ROW_HIDDEN_CLASS
140+ ) as NodeListOf < HTMLTableRowElement > ;
141+ for ( let i = 0 ; i < rows . length ; i ++ ) {
142+ const rowName = rows [ i ] . querySelector (
143+ '.' + TABLE_NAME_CLASS
144+ ) as HTMLTableCellElement ;
145+ const rowType = rows [ i ] . querySelector (
146+ '.' + TABLE_TYPE_CLASS
147+ ) as HTMLTableCellElement ;
148+ if (
149+ ! this . stringInFilter ( rowName . innerHTML , 'name' ) &&
150+ ! this . _filtered [ 'type' ] . includes ( rowType . innerHTML )
151+ ) {
152+ rows [ i ] . className = TABLE_ROW_CLASS ;
153+ }
154+ }
155+ }
156+
157+ /*
158+ Goes through each row and checks if the row should be filtered out
159+ A row is filtered out if it matches any of the values in the _filtered object
160+ */
161+ protected filterOutTable ( ) {
162+ const rows = this . _table . querySelectorAll (
163+ '.' + TABLE_ROW_CLASS
164+ ) as NodeListOf < HTMLTableRowElement > ;
165+ for ( let i = 0 ; i < rows . length ; i ++ ) {
166+ const rowName = rows [ i ] . querySelector (
167+ '.' + TABLE_NAME_CLASS
168+ ) as HTMLTableCellElement ;
169+ const rowType = rows [ i ] . querySelector (
170+ '.' + TABLE_TYPE_CLASS
171+ ) as HTMLTableCellElement ;
172+ if (
173+ this . stringInFilter ( rowName . innerHTML , 'name' ) ||
174+ this . _filtered [ 'type' ] . includes ( rowType . innerHTML )
175+ ) {
176+ rows [ i ] . className = TABLE_ROW_HIDDEN_CLASS ;
177+ }
178+ }
36179 }
37180
38181 get source ( ) : IVariableInspector . IInspectable | null {
@@ -99,6 +242,12 @@ export class VariableInspectorPanel
99242 const varType = item . varType ;
100243
101244 row = this . _table . tFoot ! . insertRow ( ) ;
245+ row . className = TABLE_ROW_CLASS ;
246+ if ( this . _filtered [ 'type' ] . includes ( varType ) ) {
247+ row . className = TABLE_ROW_HIDDEN_CLASS ;
248+ } else if ( this . stringInFilter ( name , 'name' ) ) {
249+ row . className = TABLE_ROW_HIDDEN_CLASS ;
250+ }
102251
103252 // Add delete icon and onclick event
104253 let cell = row . insertCell ( 0 ) ;
@@ -130,12 +279,13 @@ export class VariableInspectorPanel
130279 }
131280
132281 cell = row . insertCell ( 2 ) ;
133- cell . className = 'jp-VarInspector-varName' ;
282+ cell . className = TABLE_NAME_CLASS ;
134283 cell . innerHTML = name ;
135284
136285 // Add remaining cells
137286 cell = row . insertCell ( 3 ) ;
138287 cell . innerHTML = varType ;
288+ cell . className = TABLE_TYPE_CLASS ;
139289 cell = row . insertCell ( 4 ) ;
140290 cell . innerHTML = item . varSize ;
141291 cell = row . insertCell ( 5 ) ;
@@ -233,4 +383,59 @@ namespace Private {
233383 title . innerHTML = header ;
234384 return title ;
235385 }
386+
387+ export function createFilterTable ( ) : HTMLDivElement {
388+ const container = document . createElement ( 'div' ) ;
389+ container . className = 'filter-container' ;
390+ const filterType = document . createElement ( 'select' ) ;
391+ filterType . className = FILTER_TYPE_CLASS ;
392+ filterType . selectedIndex = 0 ;
393+ const varTypeOption = document . createElement ( 'option' ) ;
394+ varTypeOption . value = 'type' ;
395+ varTypeOption . innerHTML = 'Type' ;
396+ const nameOption = document . createElement ( 'option' ) ;
397+ nameOption . value = 'name' ;
398+ nameOption . innerHTML = 'Name' ;
399+ filterType . appendChild ( varTypeOption ) ;
400+ filterType . appendChild ( nameOption ) ;
401+ const searchContainer = document . createElement ( 'div' ) ;
402+ searchContainer . className = 'jp-InputGroup filter-search-container' ;
403+ const input = document . createElement ( 'input' ) ;
404+ input . setAttribute ( 'type' , 'text' ) ;
405+ input . setAttribute ( 'placeholder' , 'Filter out variable' ) ;
406+ input . className = FILTER_INPUT_CLASS ;
407+ const filterButton = document . createElement ( 'button' ) ;
408+ const buttonText = document . createTextNode ( 'Filter' ) ;
409+ filterButton . appendChild ( buttonText ) ;
410+ filterButton . className = FILTER_BUTTON_CLASS ;
411+ const list = document . createElement ( 'ul' ) ;
412+ list . className = FILTER_LIST_CLASS ;
413+
414+ searchContainer . appendChild ( filterType ) ;
415+ searchContainer . appendChild ( input ) ;
416+ searchContainer . appendChild ( filterButton ) ;
417+ container . appendChild ( searchContainer ) ;
418+ container . appendChild ( list ) ;
419+ return container ;
420+ }
421+
422+ //Creates a button with given filter information displayed on the button
423+ export function createFilteredButton (
424+ filterName : string ,
425+ filterType : FILTER_TYPES
426+ ) : HTMLButtonElement {
427+ const filteredButton = document . createElement ( 'button' ) ;
428+ filteredButton . value = filterType ;
429+ filteredButton . title = filterType ;
430+ const buttonText = document . createElement ( 'div' ) ;
431+ buttonText . className = 'filtered-variable-button-text' ;
432+ buttonText . innerHTML = filterName ;
433+ const icon = closeIcon . element ( {
434+ container : filteredButton
435+ } ) ;
436+ filteredButton . appendChild ( buttonText ) ;
437+ filteredButton . appendChild ( icon ) ;
438+ filteredButton . className = FILTERED_BUTTON_CLASS ;
439+ return filteredButton ;
440+ }
236441}
0 commit comments