Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix accessibility issues with query grid #17479

Merged
merged 3 commits into from
Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,12 @@ gulp.task('ext:copy-dependencies', (done) => {
]).pipe(gulp.dest('out/src/views/htmlcontent/src/js/lib'));

gulp.src([
config.paths.project.root + '/node_modules/angular2-slickgrid/components/css/SlickGrid.css',
config.paths.project.root + '/node_modules/angular2-slickgrid/out/css/SlickGrid.css',
config.paths.project.root + '/node_modules/slickgrid/slick.grid.css'
]).pipe(gulp.dest('out/src/views/htmlcontent/src/css'));

gulp.src([
config.paths.project.root + '/node_modules/angular2-slickgrid/index.js',
config.paths.project.root + '/node_modules/angular2-slickgrid/components/**/*.js'
config.paths.project.root + '/node_modules/angular2-slickgrid/out/**/*.js'
], { base: config.paths.project.root + '/node_modules/angular2-slickgrid' }).pipe(gulp.dest('out/src/views/htmlcontent/src/js/lib/angular2-slickgrid'));

return gulp.src([config.paths.project.root + '/node_modules/@angular/**/*'])
Expand Down
9 changes: 9 additions & 0 deletions localization/xliff/enu/constants/localizedConstants.enu.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,15 @@
<trans-unit id="msgMultipleSelectionModeNotSupported">
<source xml:lang="en">Running query is not supported when the editor is in multiple selection mode.</source>
</trans-unit>
<trans-unit id="newColumnWidthPrompt">
<source xml:lang="en">Enter new column width</source>
</trans-unit>
<trans-unit id="columnWidthInvalidNumberError">
<source xml:lang="en">Invalid column width</source>
</trans-unit>
<trans-unit id="columnWidthMustBePositiveError">
<source xml:lang="en">Width cannot be 0 or negative</source>
</trans-unit>
</body>
</file>
</xliff>
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"@vscode/test-electron": "^2.1.5",
"@xmldom/xmldom": "0.8.4",
"angular-in-memory-web-api": "0.1.13",
"angular2-slickgrid": "github:microsoft/angular2-slickgrid#1.2.2-patch1",
"angular2-slickgrid": "github:microsoft/angular2-slickgrid#1.4.6",
"assert": "^1.4.1",
"chai": "^3.5.0",
"coveralls": "^3.0.2",
Expand All @@ -111,7 +111,7 @@
"remap-istanbul": "0.9.6",
"rxjs": "5.0.0-beta.12",
"sinon": "^14.0.0",
"slickgrid": "github:kburtram/SlickGrid#2.3.23-2",
"slickgrid": "github:Microsoft/SlickGrid.ADS#2.3.39",
"systemjs": "0.19.40",
"systemjs-builder": "^0.15.32",
"systemjs-plugin-json": "^0.2.0",
Expand Down Expand Up @@ -783,7 +783,8 @@
"event.selectAll": "ctrl+A",
"event.saveAsJSON": "",
"event.saveAsCSV": "",
"event.saveAsExcel": ""
"event.saveAsExcel": "",
"event.changeColumnWidth": "ctrl+alt+S"
},
"scope": "resource"
},
Expand Down
5 changes: 5 additions & 0 deletions src/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,13 @@ export enum FieldType {

export interface IColumnDefinition {
id?: string;
field?: string;
name: string;
type: FieldType;
width?: number;
cssClass?: string;
focusable?: boolean;
selectable?: boolean;
asyncPostRender?: (cellRef: string, row: number, dataContext: JSON, colDef: any) => void;
formatter?: (row: number, cell: any, value: any, columnDef: any, dataContext: any) => string;
}
Expand Down
20 changes: 17 additions & 3 deletions src/models/sqlOutputContentProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,29 @@ export class SqlOutputContentProvider {
this.copyRequestHandler(uri, batchId, resultsId, selection, includeHeaders),
getConfig: () => this.configRequestHandler(uri),
getLocalizedTexts: () => Promise.resolve(LocalizedConstants),
openLink: (content: string, columnName: string, linkType: string) =>
this.openLinkRequestHandler(content, columnName, linkType),
openLink: (content: string, columnName: string, linkType: string) => this.openLinkRequestHandler(content, columnName, linkType),
saveResults: (batchId: number, resultId: number, format: string, selection: ISlickRange[]) =>
this.saveResultsRequestHandler(uri, batchId, resultId, format, selection),
setEditorSelection: (selection: ISelectionData) => this.editorSelectionRequestHandler(uri, selection),
showError: (message: string) => this.showErrorRequestHandler(message),
showWarning: (message: string) => this.showWarningRequestHandler(message),
sendReadyEvent: async () => await this.sendReadyEvent(uri),
dispose: () => this._panels.delete(uri)
dispose: () => this._panels.delete(uri),
getNewColumnWidth: async (current: number): Promise<number | undefined> => {
const val = await vscode.window.showInputBox({
prompt: LocalizedConstants.newColumnWidthPrompt,
value: current.toString(),
validateInput: async (value: string) => {
if (!Number(value)) {
return LocalizedConstants.columnWidthInvalidNumberError;
} else if (parseInt(value, 10) <= 0) {
return LocalizedConstants.columnWidthMustBePositiveError;
}
return undefined;
}
});
return val === undefined ? undefined : parseInt(val, 10);
}
};
const controller = new WebviewPanelController(this._vscodeWrapper, uri, title, proxy, this.context.extensionPath, this._statusView);
this._panels.set(uri, controller);
Expand Down
1 change: 1 addition & 0 deletions src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface IServerProxy extends Disposable {
showError(message: string): void;
getLocalizedTexts(): Promise<{ [key: string]: any }>;
sendReadyEvent(uri: string): Promise<boolean>;
getNewColumnWidth(current: number): Promise<number | undefined>;
}

export interface IMessageProtocol {
Expand Down
114 changes: 79 additions & 35 deletions src/views/htmlcontent/src/js/components/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ const template = `
<slick-grid #slickgrid id="slickgrid_{{i}}" [columnDefinitions]="dataSet.columnDefinitions"
[ngClass]="i === activeGrid ? 'active' : ''"
[dataRows]="dataSet.dataRows"
(contextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
(onContextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
enableAsyncPostRender="true"
showDataTypeIcon="false"
showHeader="true"
[resized]="dataSet.resized"
(mousedown)="navigateToGrid(i)"
(focusin)="setActiveGrid(i)"
[selectionModel]="selectionModel"
[plugins]="slickgridPlugins"
class="boxCol content vertBox slickgrid">
Expand Down Expand Up @@ -195,14 +196,14 @@ export class AppComponent implements OnInit, AfterViewChecked {
} else {
let activeGrid = this.activeGrid;
let selection = this.slickgrids.toArray()[activeGrid].getSelectedRanges();
selection = this.tryCombineSelections(selection);
selection = this.tryCombineSelectionsForResults(selection);
this.dataService.copyResults(selection, this.renderedDataSets[activeGrid].batchId, this.renderedDataSets[activeGrid].resultId);
}
},
'event.copyWithHeaders': () => {
let activeGrid = this.activeGrid;
let selection = this.slickgrids.toArray()[activeGrid].getSelectedRanges();
selection = this.tryCombineSelections(selection);
selection = this.tryCombineSelectionsForResults(selection);
this.dataService.copyResults(selection, this.renderedDataSets[activeGrid].batchId,
this.renderedDataSets[activeGrid].resultId, true);
},
Expand All @@ -220,6 +221,22 @@ export class AppComponent implements OnInit, AfterViewChecked {
},
'event.saveAsExcel': () => {
this.sendSaveRequest('excel');
},
'event.changeColumnWidth': async () => {
const activeGrid = this.slickgrids.toArray()[this.activeGrid]['_grid'];
if (activeGrid) {
const activeCell = activeGrid.getActiveCell();
const columns = activeGrid.getColumns();
if (!columns[activeCell.cell]?.resizable) {
return;
}
const newWidth = await this.dataService.getNewColumnWidth(columns[activeCell.cell].width);
if (newWidth) {
columns[activeCell.cell].width = newWidth;
activeGrid.setColumns(columns);
activeGrid.setActiveCell(activeCell.row, activeCell.cell);
}
}
}
};

Expand All @@ -246,7 +263,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
hoverText: () => { return Constants.saveCSVLabel; },
functionality: (batchId, resultId, index) => {
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
selection = this.tryCombineSelections(selection);
selection = this.tryCombineSelectionsForResults(selection);
if (selection.length <= 1) {
this.handleContextClick({ type: 'savecsv', batchId: batchId, resultId: resultId, index: index, selection: selection });
} else {
Expand All @@ -260,7 +277,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
hoverText: () => { return Constants.saveJSONLabel; },
functionality: (batchId, resultId, index) => {
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
selection = this.tryCombineSelections(selection);
selection = this.tryCombineSelectionsForResults(selection);
if (selection.length <= 1) {
this.handleContextClick({ type: 'savejson', batchId: batchId, resultId: resultId, index: index, selection: selection });
} else {
Expand All @@ -274,7 +291,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
hoverText: () => { return Constants.saveExcelLabel; },
functionality: (batchId, resultId, index) => {
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
selection = this.tryCombineSelections(selection);
selection = this.tryCombineSelectionsForResults(selection);
if (selection.length <= 1) {
this.handleContextClick({ type: 'saveexcel', batchId: batchId, resultId: resultId, index: index, selection: selection });
} else {
Expand Down Expand Up @@ -381,16 +398,12 @@ export class AppComponent implements OnInit, AfterViewChecked {
let resultSet = event.data;

// Setup a function for generating a promise to lookup result subsets
let loadDataFunction = (offset: number, count: number): Promise<IGridDataRow[]> => {
return self.dataService.getRows(offset, count, resultSet.batchId, resultSet.id).then(rows => {
let gridData: IGridDataRow[] = [];
for (let row = 0; row < rows.rows.length; row++) {
// Push row values onto end of gridData for slickgrid
gridData.push({
values: rows.rows[row]
});
let loadDataFunction = (offset: number, count: number): Promise<any[]> => {
return self.dataService.getRows(offset, count, resultSet.batchId, resultSet.id).then(response => {
if (!response) {
return [];
}
return gridData;
return response.rows;
});
};

Expand Down Expand Up @@ -421,6 +434,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
let linkType = c.isXml ? 'xml' : 'json';
return {
id: i.toString(),
field: i.toString(),
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
? 'XML Showplan'
: Utils.htmlEntities(c.columnName),
Expand All @@ -430,6 +444,16 @@ export class AppComponent implements OnInit, AfterViewChecked {
};
})
};
dataSet.columnDefinitions.unshift({
id: 'rowNumber',
name: '',
field: 'rowNumber',
width: 22,
type: FieldType.Integer,
focusable: true,
selectable: false,
formatter: r => { return `<span class="row-number">${r + 1}</span>`; }
});
self.dataSets.push(dataSet);

// Create a dataSet to render without rows to reduce DOM size
Expand Down Expand Up @@ -556,10 +580,24 @@ export class AppComponent implements OnInit, AfterViewChecked {
}
}

openContextMenu(event: { x: number, y: number }, batchId, resultId, index): void {
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
selection = this.tryCombineSelections(selection);
this.contextMenu.show(event.x, event.y, batchId, resultId, index, selection);
openContextMenu(event: MouseEvent, batchId, resultId, index): void {
let selection: ISlickRange[] = this.slickgrids.toArray()[index].getSelectedRanges();
selection = this.tryCombineSelectionsForResults(selection);
this.contextMenu.show(event.clientX, event.clientY, batchId, resultId, index, selection);
event.preventDefault();
event.stopPropagation();
}

private tryCombineSelectionsForResults(selections: ISlickRange[]): ISlickRange[] {
// need to take row number column in to consideration.
return this.tryCombineSelections(selections).map(range => {
return {
fromCell: range.fromCell - 1,
fromRow: range.fromRow,
toCell: range.toCell - 1,
toRow: range.toRow
};
});
}

private tryCombineSelections(selections: ISlickRange[]): ISlickRange[] {
Expand Down Expand Up @@ -598,7 +636,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
let batchId = this.renderedDataSets[activeGrid].batchId;
let resultId = this.renderedDataSets[activeGrid].resultId;
let selection = this.slickgrids.toArray()[activeGrid].getSelectedRanges();
selection = this.tryCombineSelections(selection);
selection = this.tryCombineSelectionsForResults(selection);
this.dataService.sendSaveRequest(batchId, resultId, format, selection);
}

Expand Down Expand Up @@ -904,6 +942,27 @@ export class AppComponent implements OnInit, AfterViewChecked {
* @returns A boolean representing if the navigation was successful
*/
navigateToGrid(targetIndex: number): boolean {
const result = this.setActiveGrid(targetIndex);
if (!result) { return false; }

// scrolling logic
let resultsWindow = $('#results');
let scrollTop = resultsWindow.scrollTop();
let scrollBottom = scrollTop + resultsWindow.height();
let gridHeight = $(this._el.nativeElement).find('slick-grid').height();
if (scrollBottom < gridHeight * (targetIndex + 1)) {
scrollTop += (gridHeight * (targetIndex + 1)) - scrollBottom;
resultsWindow.scrollTop(scrollTop);
}
if (scrollTop > gridHeight * targetIndex) {
scrollTop = (gridHeight * targetIndex);
resultsWindow.scrollTop(scrollTop);
}

return true;
}

setActiveGrid(targetIndex: number): boolean {
// check if the target index is valid
if (targetIndex >= this.renderedDataSets.length || targetIndex < 0) {
return false;
Expand All @@ -921,21 +980,6 @@ export class AppComponent implements OnInit, AfterViewChecked {
this.slickgrids.toArray()[this.activeGrid].selection = false;
this.slickgrids.toArray()[targetIndex].setActive();
this.activeGrid = targetIndex;

// scrolling logic
let resultsWindow = $('#results');
let scrollTop = resultsWindow.scrollTop();
let scrollBottom = scrollTop + resultsWindow.height();
let gridHeight = $(this._el.nativeElement).find('slick-grid').height();
if (scrollBottom < gridHeight * (targetIndex + 1)) {
scrollTop += (gridHeight * (targetIndex + 1)) - scrollBottom;
resultsWindow.scrollTop(scrollTop);
}
if (scrollTop > gridHeight * targetIndex) {
scrollTop = (gridHeight * targetIndex);
resultsWindow.scrollTop(scrollTop);
}

return true;
}

Expand Down
4 changes: 4 additions & 0 deletions src/views/htmlcontent/src/js/services/data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,8 @@ export class DataService implements OnDestroy {
});
}
}

getNewColumnWidth(currentWidth: number): Promise<number | undefined> {
return this._proxy.getNewColumnWidth(currentWidth);
}
}
Loading