mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) close sort&filter menu when clicking Save/Revert buttons
Summary: - close sort&filter menu when clicking Save/Revert buttons - also closes when clicking Apply/Cancel from a nested filter menu Test Plan: - updated existing test to match new spec - added new test to cover new behaviour Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2799
This commit is contained in:
parent
570baa95a5
commit
8056bb0069
@ -650,8 +650,8 @@ BaseView.prototype.getLastDataRowIndex = function() {
|
|||||||
/**
|
/**
|
||||||
* Creates and opens ColumnFilterMenu for a given field, and returns its PopupControl.
|
* Creates and opens ColumnFilterMenu for a given field, and returns its PopupControl.
|
||||||
*/
|
*/
|
||||||
BaseView.prototype.createFilterMenu = function(openCtl, field) {
|
BaseView.prototype.createFilterMenu = function(openCtl, field, onClose) {
|
||||||
return createFilterMenu(openCtl, this._sectionFilter, field, this._filteredRowSource, this.tableModel.tableData);
|
return createFilterMenu(openCtl, this._sectionFilter, field, this._filteredRowSource, this.tableModel.tableData, onClose);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
2
app/client/declarations.d.ts
vendored
2
app/client/declarations.d.ts
vendored
@ -60,7 +60,7 @@ declare module "app/client/components/BaseView" {
|
|||||||
|
|
||||||
constructor(gristDoc: GristDoc, viewSectionModel: any);
|
constructor(gristDoc: GristDoc, viewSectionModel: any);
|
||||||
public setCursorPos(cursorPos: CursorPos): void;
|
public setCursorPos(cursorPos: CursorPos): void;
|
||||||
public createFilterMenu(ctl: IOpenController, field: ViewFieldRec): HTMLElement;
|
public createFilterMenu(ctl: IOpenController, field: ViewFieldRec, onClose?: () => void): HTMLElement;
|
||||||
public buildTitleControls(): DomArg;
|
public buildTitleControls(): DomArg;
|
||||||
public getLoadingDonePromise(): Promise<void>;
|
public getLoadingDonePromise(): Promise<void>;
|
||||||
public onResize(): void;
|
public onResize(): void;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {allInclusive, ColumnFilter, isEquivalentFilter} from 'app/client/models/ColumnFilter';
|
import {allInclusive, ColumnFilter, isEquivalentFilter} from 'app/client/models/ColumnFilter';
|
||||||
|
import {ColumnFilterMenuModel, IFilterCount} from 'app/client/models/ColumnFilterMenuModel';
|
||||||
import {ViewFieldRec, ViewSectionRec} from 'app/client/models/DocModel';
|
import {ViewFieldRec, ViewSectionRec} from 'app/client/models/DocModel';
|
||||||
import {FilteredRowSource} from 'app/client/models/rowset';
|
import {FilteredRowSource} from 'app/client/models/rowset';
|
||||||
import {SectionFilter} from 'app/client/models/SectionFilter';
|
import {SectionFilter} from 'app/client/models/SectionFilter';
|
||||||
@ -17,9 +18,8 @@ import {menuCssClass, menuDivider} from 'app/client/ui2018/menus';
|
|||||||
import {CellValue} from 'app/common/DocActions';
|
import {CellValue} from 'app/common/DocActions';
|
||||||
import {Computed, Disposable, dom, DomElementMethod, IDisposableOwner, input, makeTestId, styled} from 'grainjs';
|
import {Computed, Disposable, dom, DomElementMethod, IDisposableOwner, input, makeTestId, styled} from 'grainjs';
|
||||||
import identity = require('lodash/identity');
|
import identity = require('lodash/identity');
|
||||||
|
import noop = require('lodash/noop');
|
||||||
import {IOpenController, IPopupOptions, setPopupToCreateDom} from 'popweasel';
|
import {IOpenController, IPopupOptions, setPopupToCreateDom} from 'popweasel';
|
||||||
import {ColumnFilterMenuModel, IFilterCount} from '../models/ColumnFilterMenuModel';
|
|
||||||
|
|
||||||
|
|
||||||
interface IFilterMenuOptions {
|
interface IFilterMenuOptions {
|
||||||
model: ColumnFilterMenuModel;
|
model: ColumnFilterMenuModel;
|
||||||
@ -258,7 +258,7 @@ function buildSummary(label: string, SummaryModelCtor: SummaryModelCreator, mode
|
|||||||
* Returns content for the newly created columnFilterMenu; for use with setPopupToCreateDom().
|
* Returns content for the newly created columnFilterMenu; for use with setPopupToCreateDom().
|
||||||
*/
|
*/
|
||||||
export function createFilterMenu(openCtl: IOpenController, sectionFilter: SectionFilter, field: ViewFieldRec,
|
export function createFilterMenu(openCtl: IOpenController, sectionFilter: SectionFilter, field: ViewFieldRec,
|
||||||
rowSource: FilteredRowSource, tableData: TableData) {
|
rowSource: FilteredRowSource, tableData: TableData, onClose: () => void = noop) {
|
||||||
// Go through all of our shown and hidden rows, and count them up by the values in this column.
|
// Go through all of our shown and hidden rows, and count them up by the values in this column.
|
||||||
const valueGetter = tableData.getRowPropFunc(field.column().colId())!;
|
const valueGetter = tableData.getRowPropFunc(field.column().colId())!;
|
||||||
const labelGetter = tableData.getRowPropFunc(field.displayColModel().colId())!;
|
const labelGetter = tableData.getRowPropFunc(field.displayColModel().colId())!;
|
||||||
@ -280,7 +280,7 @@ export function createFilterMenu(openCtl: IOpenController, sectionFilter: Sectio
|
|||||||
return columnFilterMenu(openCtl, {
|
return columnFilterMenu(openCtl, {
|
||||||
model,
|
model,
|
||||||
valueCounts,
|
valueCounts,
|
||||||
onClose: () => openCtl.close(),
|
onClose: () => { openCtl.close(); onClose(); },
|
||||||
doSave: (reset: boolean = false) => {
|
doSave: (reset: boolean = false) => {
|
||||||
const spec = columnFilter.makeFilterJson();
|
const spec = columnFilter.makeFilterJson();
|
||||||
// If filter is moot and filter bar is hidden, let's remove the filter.
|
// If filter is moot and filter bar is hidden, let's remove the filter.
|
||||||
@ -321,14 +321,19 @@ const defaultPopupOptions: IPopupOptions = {
|
|||||||
trigger: ['click'],
|
trigger: ['click'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface IColumnFilterMenuOptions extends IPopupOptions {
|
||||||
|
// callback for when the content of the menu is closed by clicking the apply or revert buttons
|
||||||
|
onCloseContent?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper to attach the column filter menu.
|
// Helper to attach the column filter menu.
|
||||||
export function attachColumnFilterMenu(viewSection: ViewSectionRec, field: ViewFieldRec,
|
export function attachColumnFilterMenu(viewSection: ViewSectionRec, field: ViewFieldRec,
|
||||||
popupOptions: IPopupOptions): DomElementMethod {
|
popupOptions: IColumnFilterMenuOptions): DomElementMethod {
|
||||||
const options = {...defaultPopupOptions, ...popupOptions};
|
const options = {...defaultPopupOptions, ...popupOptions};
|
||||||
return (elem) => {
|
return (elem) => {
|
||||||
const instance = viewSection.viewInstance();
|
const instance = viewSection.viewInstance();
|
||||||
if (instance && instance.createFilterMenu) { // Should be set if using BaseView
|
if (instance && instance.createFilterMenu) { // Should be set if using BaseView
|
||||||
setPopupToCreateDom(elem, ctl => instance.createFilterMenu(ctl, field), options);
|
setPopupToCreateDom(elem, ctl => instance.createFilterMenu(ctl, field, popupOptions.onCloseContent), options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import {flipColDirection, parseSortColRefs} from 'app/client/lib/sortUtil';
|
import {flipColDirection, parseSortColRefs} from 'app/client/lib/sortUtil';
|
||||||
|
import {reportError} from 'app/client/models/AppModel';
|
||||||
import {ColumnRec, DocModel, ViewFieldRec, ViewRec, ViewSectionRec} from 'app/client/models/DocModel';
|
import {ColumnRec, DocModel, ViewFieldRec, ViewRec, ViewSectionRec} from 'app/client/models/DocModel';
|
||||||
import {CustomComputed} from 'app/client/models/modelUtil';
|
import {CustomComputed} from 'app/client/models/modelUtil';
|
||||||
import {attachColumnFilterMenu} from 'app/client/ui/ColumnFilterMenu';
|
import {attachColumnFilterMenu} from 'app/client/ui/ColumnFilterMenu';
|
||||||
import {addFilterMenu} from 'app/client/ui/FilterBar';
|
import {addFilterMenu} from 'app/client/ui/FilterBar';
|
||||||
import {makeViewLayoutMenu} from 'app/client/ui/ViewLayoutMenu';
|
|
||||||
import {hoverTooltip} from 'app/client/ui/tooltips';
|
import {hoverTooltip} from 'app/client/ui/tooltips';
|
||||||
|
import {makeViewLayoutMenu} from 'app/client/ui/ViewLayoutMenu';
|
||||||
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
|
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
|
||||||
import {colors, vars} from 'app/client/ui2018/cssVars';
|
import {colors, vars} from 'app/client/ui2018/cssVars';
|
||||||
import {icon} from 'app/client/ui2018/icons';
|
import {icon} from 'app/client/ui2018/icons';
|
||||||
@ -43,7 +44,7 @@ export function viewSectionMenu(owner: IDisposableOwner, docModel: DocModel, vie
|
|||||||
|| !use(viewSection.activeFilterBar.isSaved)
|
|| !use(viewSection.activeFilterBar.isSaved)
|
||||||
));
|
));
|
||||||
|
|
||||||
const save = () => doSave(docModel, viewSection);
|
const save = () => { doSave(docModel, viewSection).catch(reportError); };
|
||||||
const revert = () => doRevert(viewSection);
|
const revert = () => doRevert(viewSection);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -58,23 +59,23 @@ export function viewSectionMenu(owner: IDisposableOwner, docModel: DocModel, vie
|
|||||||
cssFilterIconWrapper.cls('-any', anyFilter),
|
cssFilterIconWrapper.cls('-any', anyFilter),
|
||||||
cssFilterIcon('Filter')
|
cssFilterIcon('Filter')
|
||||||
),
|
),
|
||||||
menu(_ctl => [
|
menu(ctl => [
|
||||||
dom.domComputed(use => {
|
dom.domComputed(use => {
|
||||||
use(viewSection.activeSortJson.isSaved); // Rebuild sort panel if sort gets saved. A little hacky.
|
use(viewSection.activeSortJson.isSaved); // Rebuild sort panel if sort gets saved. A little hacky.
|
||||||
return makeSortPanel(viewSection, use(viewSection.activeSortSpec),
|
return makeSortPanel(viewSection, use(viewSection.activeSortSpec),
|
||||||
(row: number) => docModel.columns.getRowModel(row));
|
(row: number) => docModel.columns.getRowModel(row));
|
||||||
}),
|
}),
|
||||||
dom.domComputed(viewSection.filteredFields, fields =>
|
dom.domComputed(viewSection.filteredFields, fields =>
|
||||||
makeFilterPanel(viewSection, fields, popupControls)),
|
makeFilterPanel(viewSection, fields, popupControls, () => ctl.close())),
|
||||||
makeAddFilterButton(viewSection, popupControls),
|
makeAddFilterButton(viewSection, popupControls),
|
||||||
makeFilterBarToggle(viewSection.activeFilterBar),
|
makeFilterBarToggle(viewSection.activeFilterBar),
|
||||||
dom.domComputed(displaySaveObs, displaySave => [
|
dom.domComputed(displaySaveObs, displaySave => [
|
||||||
displaySave ? cssMenuInfoHeader(
|
displaySave ? cssMenuInfoHeader(
|
||||||
cssSaveButton('Save', testId('btn-save'),
|
cssSaveButton('Save', testId('btn-save'),
|
||||||
dom.on('click', save),
|
dom.on('click', () => { save(); ctl.close(); }),
|
||||||
dom.boolAttr('disabled', isReadonly)),
|
dom.boolAttr('disabled', isReadonly)),
|
||||||
basicButton('Revert', testId('btn-revert'),
|
basicButton('Revert', testId('btn-revert'),
|
||||||
dom.on('click', revert))
|
dom.on('click', () => { revert(); ctl.close(); }))
|
||||||
) : null,
|
) : null,
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
@ -180,7 +181,8 @@ export function makeFilterBarToggle(activeFilterBar: CustomComputed<boolean>) {
|
|||||||
|
|
||||||
|
|
||||||
function makeFilterPanel(section: ViewSectionRec, filteredFields: ViewFieldRec[],
|
function makeFilterPanel(section: ViewSectionRec, filteredFields: ViewFieldRec[],
|
||||||
popupControls: WeakMap<ViewFieldRec, PopupControl>) {
|
popupControls: WeakMap<ViewFieldRec, PopupControl>,
|
||||||
|
onCloseContent: () => void) {
|
||||||
const fields = filteredFields.map(field => {
|
const fields = filteredFields.map(field => {
|
||||||
const fieldChanged = Computed.create(null, fromKo(field.activeFilter.isSaved), (_use, isSaved) => !isSaved);
|
const fieldChanged = Computed.create(null, fromKo(field.activeFilter.isSaved), (_use, isSaved) => !isSaved);
|
||||||
return cssMenuText(
|
return cssMenuText(
|
||||||
@ -191,6 +193,7 @@ function makeFilterPanel(section: ViewSectionRec, filteredFields: ViewFieldRec[]
|
|||||||
attachColumnFilterMenu(section, field, {
|
attachColumnFilterMenu(section, field, {
|
||||||
placement: 'bottom-end',
|
placement: 'bottom-end',
|
||||||
trigger: ['click', (_el, popupControl) => popupControls.set(field, popupControl)],
|
trigger: ['click', (_el, popupControl) => popupControls.set(field, popupControl)],
|
||||||
|
onCloseContent,
|
||||||
}),
|
}),
|
||||||
testId('filter-icon'),
|
testId('filter-icon'),
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user