Skip to content

Commit ba639cd

Browse files
authored
Merge pull request #195 from quantopian/varda-column-config
Use editable_row_callback to determine if row should be editable
2 parents 655cc3c + bddad21 commit ba639cd

File tree

9 files changed

+719
-227
lines changed

9 files changed

+719
-227
lines changed

js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "qgrid",
3-
"version": "1.0.6-beta.6",
3+
"version": "1.1.0-beta.0",
44
"description": "An Interactive Grid for Sorting and Filtering DataFrames in Jupyter Notebook",
55
"author": "Quantopian Inc.",
66
"main": "src/index.js",

js/src/qgrid.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,3 +724,8 @@ input.bool-filter-radio {
724724
padding-left: 5px;
725725
margin-left: -4px;
726726
}
727+
728+
.q-grid .slick-sort-indicator-desc,
729+
.q-grid .slick-sort-indicator-asc {
730+
background-image: none;
731+
}

js/src/qgrid.editors.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,17 @@ class SelectEditor {
6363
}
6464

6565
var option_str = "";
66+
67+
this.elem = $("<SELECT tabIndex='0' class='editor-select'>");
68+
6669
for (var i in this.options) {
6770
var opt = $.trim(this.options[i]); // remove any white space including spaces after comma
68-
option_str += "<OPTION value='" + opt + "'>" + opt + "</OPTION>";
71+
var opt_elem = $("<OPTION>");
72+
opt_elem.val(opt);
73+
opt_elem.text(opt);
74+
opt_elem.appendTo(this.elem);
6975
}
70-
this.elem = $("<SELECT tabIndex='0' class='editor-select'>" + option_str + "</SELECT>");
76+
7177
this.elem.appendTo(args.container);
7278
this.elem.focus();
7379
}

js/src/qgrid.filterbase.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class FilterBase {
8989
this.filter_btn.addClass('disabled');
9090

9191
var msg = {
92-
'type': 'get_column_min_max',
92+
'type': 'show_filter_dropdown',
9393
'field': this.field,
9494
'search_val': null
9595
};
@@ -173,7 +173,7 @@ class FilterBase {
173173
}
174174

175175
var msg = {
176-
'type': 'filter_changed',
176+
'type': 'change_filter',
177177
'field': this.field,
178178
'filter_info': this.get_filter_info()
179179
};

js/src/qgrid.textfilter.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ class TextFilter extends filter_base.FilterBase {
201201
this.viewport_timeout = setTimeout(() => {
202202
var vp = args.grid.getViewport();
203203
var msg = {
204-
'type': 'viewport_changed_filter',
204+
'type': 'change_filter_viewport',
205205
'field': this.field,
206206
'top': vp.top,
207207
'bottom': vp.bottom
@@ -311,7 +311,7 @@ class TextFilter extends filter_base.FilterBase {
311311
this.search_string = this.security_search.val();
312312
if (old_search_string != this.search_string) {
313313
var msg = {
314-
'type': 'get_column_min_max',
314+
'type': 'show_filter_dropdown',
315315
'field': this.field,
316316
'search_val': this.search_string
317317
};
@@ -363,7 +363,7 @@ class TextFilter extends filter_base.FilterBase {
363363
this.filter_list = null;
364364
this.send_filter_changed();
365365
var msg = {
366-
'type': 'get_column_min_max',
366+
'type': 'show_filter_dropdown',
367367
'field': this.field,
368368
'search_val': this.search_string
369369
};

js/src/qgrid.widget.js

Lines changed: 93 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class QgridModel extends widgets.DOMWidgetModel {
3636
_view_name : 'QgridView',
3737
_model_module : 'qgrid',
3838
_view_module : 'qgrid',
39-
_model_module_version : '^1.0.6-beta.6',
40-
_view_module_version : '^1.0.6-beta.6',
39+
_model_module_version : '^1.1.0-beta.0',
40+
_view_module_version : '^1.1.0-beta.0',
4141
_df_json: '',
4242
_columns: {}
4343
});
@@ -215,6 +215,9 @@ class QgridView extends widgets.DOMWidgetView {
215215
this.sort_in_progress = false;
216216
this.sort_indicator = null;
217217
this.resizing_column = false;
218+
this.ignore_selection_changed = false;
219+
this.vp_response_expected = false;
220+
this.next_viewport_msg = null;
218221

219222
var number_type_info = {
220223
filter: slider_filter.SliderFilter,
@@ -318,14 +321,7 @@ class QgridView extends widgets.DOMWidgetView {
318321

319322
var type_info = this.type_infos[cur_column.type] || {};
320323

321-
var slick_column = {
322-
name: cur_column.name,
323-
field: cur_column.name,
324-
id: cur_column.name,
325-
sortable: false,
326-
resizable: true,
327-
cssClass: cur_column.type
328-
};
324+
var slick_column = cur_column;
329325

330326
Object.assign(slick_column, type_info);
331327

@@ -345,9 +341,18 @@ class QgridView extends widgets.DOMWidgetView {
345341
this.filter_list.push(cur_filter);
346342
}
347343

344+
if (cur_column.width == null){
345+
delete slick_column.width;
346+
}
347+
348+
if (cur_column.maxWidth == null){
349+
delete slick_column.maxWidth;
350+
}
351+
348352
// don't allow editing index columns
349353
if (cur_column.is_index) {
350354
slick_column.editor = editors.IndexEditor;
355+
351356
slick_column.cssClass += ' idx-col';
352357
if (cur_column.first_index){
353358
slick_column.cssClass += ' first-idx-col';
@@ -358,9 +363,19 @@ class QgridView extends widgets.DOMWidgetView {
358363

359364
slick_column.name = cur_column.index_display_text;
360365
slick_column.level = cur_column.level;
366+
367+
if (this.grid_options.boldIndex) {
368+
slick_column.cssClass += ' idx-col';
369+
}
370+
361371
this.index_columns.push(slick_column);
362372
continue;
363373
}
374+
375+
if (cur_column.editable == false) {
376+
slick_column.editor = null;
377+
}
378+
364379
this.columns.push(slick_column);
365380
}
366381

@@ -431,19 +446,28 @@ class QgridView extends widgets.DOMWidgetView {
431446
if (this.sort_in_progress){
432447
return;
433448
}
434-
this.sort_in_progress = true;
435449

436450
var col_header = $(e.target).closest(".slick-header-column");
437451
if (!col_header.length) {
438452
return;
439453
}
440454

441455
var column = col_header.data("column");
456+
if (column.sortable == false){
457+
return;
458+
}
459+
460+
this.sort_in_progress = true;
461+
442462
if (this.sorted_column == column){
443463
this.sort_ascending = !this.sort_ascending;
444464
} else {
445465
this.sorted_column = column;
446-
this.sort_ascending = true;
466+
if ('defaultSortAsc' in column) {
467+
this.sort_ascending = column.defaultSortAsc;
468+
} else{
469+
this.sort_ascending = true;
470+
}
447471
}
448472

449473
var all_classes = 'fa-sort-asc fa-sort-desc fa fa-spin fa-spinner';
@@ -458,7 +482,7 @@ class QgridView extends widgets.DOMWidgetView {
458482
this.grid_elem.find('.slick-sort-indicator').removeClass(all_classes);
459483
this.sort_indicator.addClass(`fa fa-spinner fa-spin`);
460484
var msg = {
461-
'type': 'sort_changed',
485+
'type': 'change_sort',
462486
'sort_field': this.sorted_column.field,
463487
'sort_ascending': this.sort_ascending
464488
};
@@ -475,29 +499,48 @@ class QgridView extends widgets.DOMWidgetView {
475499
}
476500
this.viewport_timeout = setTimeout(() => {
477501
this.last_vp = this.slick_grid.getViewport();
478-
var msg = {
479-
'type': 'viewport_changed',
480-
'top': this.last_vp.top,
481-
'bottom': this.last_vp.bottom
482-
};
483-
this.send(msg);
502+
var cur_range = this.model.get('_viewport_range');
503+
504+
if (this.last_vp.top != cur_range[0] || this.last_vp.bottom != cur_range[1]) {
505+
var msg = {
506+
'type': 'change_viewport',
507+
'top': this.last_vp.top,
508+
'bottom': this.last_vp.bottom
509+
};
510+
if (this.vp_response_expected){
511+
this.next_viewport_msg = msg
512+
} else {
513+
this.vp_response_expected = true;
514+
this.send(msg);
515+
}
516+
}
484517
this.viewport_timeout = null;
485-
}, 10);
518+
}, 100);
486519
});
487520

488521
// set up callbacks
522+
let editable_rows = this.model.get('_editable_rows');
523+
if (editable_rows && Object.keys(editable_rows).length > 0) {
524+
this.slick_grid.onBeforeEditCell.subscribe((e, args) => {
525+
editable_rows = this.model.get('_editable_rows');
526+
return editable_rows[args.item[this.index_col_name]]
527+
});
528+
}
529+
489530
this.slick_grid.onCellChange.subscribe((e, args) => {
490531
var column = this.columns[args.cell].name;
491532
var data_item = this.slick_grid.getDataItem(args.row);
492533
var msg = {'row_index': data_item.row_index, 'column': column,
493534
'unfiltered_index': data_item[this.index_col_name],
494-
'value': args.item[column], 'type': 'cell_change'};
535+
'value': args.item[column], 'type': 'edit_cell'};
495536
this.send(msg);
496537
});
497538

498539
this.slick_grid.onSelectedRowsChanged.subscribe((e, args) => {
499-
var msg = {'rows': args.rows, 'type': 'selection_changed'};
500-
this.send(msg);
540+
if (!this.ignore_selection_changed) {
541+
var msg = {'rows': args.rows, 'type': 'change_selection'};
542+
this.send(msg);
543+
}
501544
});
502545

503546
setTimeout(() => {
@@ -648,7 +691,17 @@ class QgridView extends widgets.DOMWidgetView {
648691
this.multi_index = this.model.get("_multi_index");
649692
var data_view = this.create_data_view(df_json.data);
650693

651-
if (msg.triggered_by == 'sort_changed' && this.sort_indicator){
694+
if (msg.triggered_by === 'change_viewport'){
695+
if (this.next_viewport_msg) {
696+
this.send(this.next_viewport_msg);
697+
this.next_viewport_msg = null;
698+
return;
699+
} else {
700+
this.vp_response_expected = false;
701+
}
702+
}
703+
704+
if (msg.triggered_by == 'change_sort' && this.sort_indicator){
652705
var asc = this.model.get('_sort_ascending');
653706
this.sort_indicator.removeClass(
654707
'fa-spinner fa-spin fa-sort-asc fa-sort-desc'
@@ -694,7 +747,7 @@ class QgridView extends widgets.DOMWidgetView {
694747
} else if (msg.triggered_by === 'add_row') {
695748
this.slick_grid.scrollRowIntoView(msg.scroll_to_row);
696749
this.slick_grid.setSelectedRows([msg.scroll_to_row]);
697-
} else if (msg.triggered_by === 'viewport_changed' &&
750+
} else if (msg.triggered_by === 'change_viewport' &&
698751
this.last_vp.bottom >= this.df_length) {
699752
this.slick_grid.scrollRowIntoView(this.last_vp.bottom);
700753
}
@@ -704,9 +757,22 @@ class QgridView extends widgets.DOMWidgetView {
704757
});
705758
this.send({
706759
'rows': selected_rows,
707-
'type': 'selection_changed'
760+
'type': 'change_selection'
708761
});
709-
}, 10);
762+
}, 100);
763+
} else if (msg.type == 'toggle_editable') {
764+
if (this.slick_grid.getOptions().editable == false) {
765+
this.slick_grid.setOptions({'editable': true});
766+
} else {
767+
this.slick_grid.setOptions({'editable': false});
768+
}
769+
} else if (msg.type == 'change_selection') {
770+
this.ignore_selection_changed = true;
771+
this.slick_grid.setSelectedRows(msg.rows);
772+
if (msg.rows && msg.rows.length > 0) {
773+
this.slick_grid.scrollRowIntoView(msg.rows[0]);
774+
}
775+
this.ignore_selection_changed = false;
710776
} else if (msg.col_info) {
711777
var filter = this.filters[msg.col_info.name];
712778
filter.handle_msg(msg);

qgrid/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version_info = (1, 0, 6, 'beta', 6)
1+
version_info = (1, 1, 0, 'beta', 0)
22

33
_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}
44

0 commit comments

Comments
 (0)