Skip to content

Commit f0a77e1

Browse files
authored
fix accessibility issues with query grid (#17479)
* fix accessibility issues * fix selection and set active grid * fix linting error
1 parent ff4fbdf commit f0a77e1

File tree

11 files changed

+176
-102
lines changed

11 files changed

+176
-102
lines changed

gulpfile.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,12 @@ gulp.task('ext:copy-dependencies', (done) => {
179179
]).pipe(gulp.dest('out/src/views/htmlcontent/src/js/lib'));
180180

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

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

191190
return gulp.src([config.paths.project.root + '/node_modules/@angular/**/*'])

localization/xliff/enu/constants/localizedConstants.enu.xlf

+9
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@
536536
<trans-unit id="msgMultipleSelectionModeNotSupported">
537537
<source xml:lang="en">Running query is not supported when the editor is in multiple selection mode.</source>
538538
</trans-unit>
539+
<trans-unit id="newColumnWidthPrompt">
540+
<source xml:lang="en">Enter new column width</source>
541+
</trans-unit>
542+
<trans-unit id="columnWidthInvalidNumberError">
543+
<source xml:lang="en">Invalid column width</source>
544+
</trans-unit>
545+
<trans-unit id="columnWidthMustBePositiveError">
546+
<source xml:lang="en">Width cannot be 0 or negative</source>
547+
</trans-unit>
539548
</body>
540549
</file>
541550
</xliff>

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
"@vscode/test-electron": "^2.1.5",
9191
"@xmldom/xmldom": "0.8.4",
9292
"angular-in-memory-web-api": "0.1.13",
93-
"angular2-slickgrid": "github:microsoft/angular2-slickgrid#1.2.2-patch1",
93+
"angular2-slickgrid": "github:microsoft/angular2-slickgrid#1.4.6",
9494
"assert": "^1.4.1",
9595
"chai": "^3.5.0",
9696
"coveralls": "^3.0.2",
@@ -111,7 +111,7 @@
111111
"remap-istanbul": "0.9.6",
112112
"rxjs": "5.0.0-beta.12",
113113
"sinon": "^14.0.0",
114-
"slickgrid": "github:kburtram/SlickGrid#2.3.23-2",
114+
"slickgrid": "github:Microsoft/SlickGrid.ADS#2.3.39",
115115
"systemjs": "0.19.40",
116116
"systemjs-builder": "^0.15.32",
117117
"systemjs-plugin-json": "^0.2.0",
@@ -783,7 +783,8 @@
783783
"event.selectAll": "ctrl+A",
784784
"event.saveAsJSON": "",
785785
"event.saveAsCSV": "",
786-
"event.saveAsExcel": ""
786+
"event.saveAsExcel": "",
787+
"event.changeColumnWidth": "ctrl+alt+S"
787788
},
788789
"scope": "resource"
789790
},

src/models/interfaces.ts

+5
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,13 @@ export enum FieldType {
301301

302302
export interface IColumnDefinition {
303303
id?: string;
304+
field?: string;
304305
name: string;
305306
type: FieldType;
307+
width?: number;
308+
cssClass?: string;
309+
focusable?: boolean;
310+
selectable?: boolean;
306311
asyncPostRender?: (cellRef: string, row: number, dataContext: JSON, colDef: any) => void;
307312
formatter?: (row: number, cell: any, value: any, columnDef: any, dataContext: any) => string;
308313
}

src/models/sqlOutputContentProvider.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,29 @@ export class SqlOutputContentProvider {
157157
this.copyRequestHandler(uri, batchId, resultsId, selection, includeHeaders),
158158
getConfig: () => this.configRequestHandler(uri),
159159
getLocalizedTexts: () => Promise.resolve(LocalizedConstants),
160-
openLink: (content: string, columnName: string, linkType: string) =>
161-
this.openLinkRequestHandler(content, columnName, linkType),
160+
openLink: (content: string, columnName: string, linkType: string) => this.openLinkRequestHandler(content, columnName, linkType),
162161
saveResults: (batchId: number, resultId: number, format: string, selection: ISlickRange[]) =>
163162
this.saveResultsRequestHandler(uri, batchId, resultId, format, selection),
164163
setEditorSelection: (selection: ISelectionData) => this.editorSelectionRequestHandler(uri, selection),
165164
showError: (message: string) => this.showErrorRequestHandler(message),
166165
showWarning: (message: string) => this.showWarningRequestHandler(message),
167166
sendReadyEvent: async () => await this.sendReadyEvent(uri),
168-
dispose: () => this._panels.delete(uri)
167+
dispose: () => this._panels.delete(uri),
168+
getNewColumnWidth: async (current: number): Promise<number | undefined> => {
169+
const val = await vscode.window.showInputBox({
170+
prompt: LocalizedConstants.newColumnWidthPrompt,
171+
value: current.toString(),
172+
validateInput: async (value: string) => {
173+
if (!Number(value)) {
174+
return LocalizedConstants.columnWidthInvalidNumberError;
175+
} else if (parseInt(value, 10) <= 0) {
176+
return LocalizedConstants.columnWidthMustBePositiveError;
177+
}
178+
return undefined;
179+
}
180+
});
181+
return val === undefined ? undefined : parseInt(val, 10);
182+
}
169183
};
170184
const controller = new WebviewPanelController(this._vscodeWrapper, uri, title, proxy, this.context.extensionPath, this._statusView);
171185
this._panels.set(uri, controller);

src/protocol.ts

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface IServerProxy extends Disposable {
2121
showError(message: string): void;
2222
getLocalizedTexts(): Promise<{ [key: string]: any }>;
2323
sendReadyEvent(uri: string): Promise<boolean>;
24+
getNewColumnWidth(current: number): Promise<number | undefined>;
2425
}
2526

2627
export interface IMessageProtocol {

src/views/htmlcontent/src/js/components/app.component.ts

+79-35
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ const template = `
6161
<slick-grid #slickgrid id="slickgrid_{{i}}" [columnDefinitions]="dataSet.columnDefinitions"
6262
[ngClass]="i === activeGrid ? 'active' : ''"
6363
[dataRows]="dataSet.dataRows"
64-
(contextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
64+
(onContextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
6565
enableAsyncPostRender="true"
6666
showDataTypeIcon="false"
6767
showHeader="true"
6868
[resized]="dataSet.resized"
6969
(mousedown)="navigateToGrid(i)"
70+
(focusin)="setActiveGrid(i)"
7071
[selectionModel]="selectionModel"
7172
[plugins]="slickgridPlugins"
7273
class="boxCol content vertBox slickgrid">
@@ -195,14 +196,14 @@ export class AppComponent implements OnInit, AfterViewChecked {
195196
} else {
196197
let activeGrid = this.activeGrid;
197198
let selection = this.slickgrids.toArray()[activeGrid].getSelectedRanges();
198-
selection = this.tryCombineSelections(selection);
199+
selection = this.tryCombineSelectionsForResults(selection);
199200
this.dataService.copyResults(selection, this.renderedDataSets[activeGrid].batchId, this.renderedDataSets[activeGrid].resultId);
200201
}
201202
},
202203
'event.copyWithHeaders': () => {
203204
let activeGrid = this.activeGrid;
204205
let selection = this.slickgrids.toArray()[activeGrid].getSelectedRanges();
205-
selection = this.tryCombineSelections(selection);
206+
selection = this.tryCombineSelectionsForResults(selection);
206207
this.dataService.copyResults(selection, this.renderedDataSets[activeGrid].batchId,
207208
this.renderedDataSets[activeGrid].resultId, true);
208209
},
@@ -220,6 +221,22 @@ export class AppComponent implements OnInit, AfterViewChecked {
220221
},
221222
'event.saveAsExcel': () => {
222223
this.sendSaveRequest('excel');
224+
},
225+
'event.changeColumnWidth': async () => {
226+
const activeGrid = this.slickgrids.toArray()[this.activeGrid]['_grid'];
227+
if (activeGrid) {
228+
const activeCell = activeGrid.getActiveCell();
229+
const columns = activeGrid.getColumns();
230+
if (!columns[activeCell.cell]?.resizable) {
231+
return;
232+
}
233+
const newWidth = await this.dataService.getNewColumnWidth(columns[activeCell.cell].width);
234+
if (newWidth) {
235+
columns[activeCell.cell].width = newWidth;
236+
activeGrid.setColumns(columns);
237+
activeGrid.setActiveCell(activeCell.row, activeCell.cell);
238+
}
239+
}
223240
}
224241
};
225242

@@ -246,7 +263,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
246263
hoverText: () => { return Constants.saveCSVLabel; },
247264
functionality: (batchId, resultId, index) => {
248265
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
249-
selection = this.tryCombineSelections(selection);
266+
selection = this.tryCombineSelectionsForResults(selection);
250267
if (selection.length <= 1) {
251268
this.handleContextClick({ type: 'savecsv', batchId: batchId, resultId: resultId, index: index, selection: selection });
252269
} else {
@@ -260,7 +277,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
260277
hoverText: () => { return Constants.saveJSONLabel; },
261278
functionality: (batchId, resultId, index) => {
262279
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
263-
selection = this.tryCombineSelections(selection);
280+
selection = this.tryCombineSelectionsForResults(selection);
264281
if (selection.length <= 1) {
265282
this.handleContextClick({ type: 'savejson', batchId: batchId, resultId: resultId, index: index, selection: selection });
266283
} else {
@@ -274,7 +291,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
274291
hoverText: () => { return Constants.saveExcelLabel; },
275292
functionality: (batchId, resultId, index) => {
276293
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
277-
selection = this.tryCombineSelections(selection);
294+
selection = this.tryCombineSelectionsForResults(selection);
278295
if (selection.length <= 1) {
279296
this.handleContextClick({ type: 'saveexcel', batchId: batchId, resultId: resultId, index: index, selection: selection });
280297
} else {
@@ -381,16 +398,12 @@ export class AppComponent implements OnInit, AfterViewChecked {
381398
let resultSet = event.data;
382399

383400
// Setup a function for generating a promise to lookup result subsets
384-
let loadDataFunction = (offset: number, count: number): Promise<IGridDataRow[]> => {
385-
return self.dataService.getRows(offset, count, resultSet.batchId, resultSet.id).then(rows => {
386-
let gridData: IGridDataRow[] = [];
387-
for (let row = 0; row < rows.rows.length; row++) {
388-
// Push row values onto end of gridData for slickgrid
389-
gridData.push({
390-
values: rows.rows[row]
391-
});
401+
let loadDataFunction = (offset: number, count: number): Promise<any[]> => {
402+
return self.dataService.getRows(offset, count, resultSet.batchId, resultSet.id).then(response => {
403+
if (!response) {
404+
return [];
392405
}
393-
return gridData;
406+
return response.rows;
394407
});
395408
};
396409

@@ -421,6 +434,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
421434
let linkType = c.isXml ? 'xml' : 'json';
422435
return {
423436
id: i.toString(),
437+
field: i.toString(),
424438
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
425439
? 'XML Showplan'
426440
: Utils.htmlEntities(c.columnName),
@@ -430,6 +444,16 @@ export class AppComponent implements OnInit, AfterViewChecked {
430444
};
431445
})
432446
};
447+
dataSet.columnDefinitions.unshift({
448+
id: 'rowNumber',
449+
name: '',
450+
field: 'rowNumber',
451+
width: 22,
452+
type: FieldType.Integer,
453+
focusable: true,
454+
selectable: false,
455+
formatter: r => { return `<span class="row-number">${r + 1}</span>`; }
456+
});
433457
self.dataSets.push(dataSet);
434458

435459
// Create a dataSet to render without rows to reduce DOM size
@@ -556,10 +580,24 @@ export class AppComponent implements OnInit, AfterViewChecked {
556580
}
557581
}
558582

559-
openContextMenu(event: { x: number, y: number }, batchId, resultId, index): void {
560-
let selection = this.slickgrids.toArray()[index].getSelectedRanges();
561-
selection = this.tryCombineSelections(selection);
562-
this.contextMenu.show(event.x, event.y, batchId, resultId, index, selection);
583+
openContextMenu(event: MouseEvent, batchId, resultId, index): void {
584+
let selection: ISlickRange[] = this.slickgrids.toArray()[index].getSelectedRanges();
585+
selection = this.tryCombineSelectionsForResults(selection);
586+
this.contextMenu.show(event.clientX, event.clientY, batchId, resultId, index, selection);
587+
event.preventDefault();
588+
event.stopPropagation();
589+
}
590+
591+
private tryCombineSelectionsForResults(selections: ISlickRange[]): ISlickRange[] {
592+
// need to take row number column in to consideration.
593+
return this.tryCombineSelections(selections).map(range => {
594+
return {
595+
fromCell: range.fromCell - 1,
596+
fromRow: range.fromRow,
597+
toCell: range.toCell - 1,
598+
toRow: range.toRow
599+
};
600+
});
563601
}
564602

565603
private tryCombineSelections(selections: ISlickRange[]): ISlickRange[] {
@@ -598,7 +636,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
598636
let batchId = this.renderedDataSets[activeGrid].batchId;
599637
let resultId = this.renderedDataSets[activeGrid].resultId;
600638
let selection = this.slickgrids.toArray()[activeGrid].getSelectedRanges();
601-
selection = this.tryCombineSelections(selection);
639+
selection = this.tryCombineSelectionsForResults(selection);
602640
this.dataService.sendSaveRequest(batchId, resultId, format, selection);
603641
}
604642

@@ -904,6 +942,27 @@ export class AppComponent implements OnInit, AfterViewChecked {
904942
* @returns A boolean representing if the navigation was successful
905943
*/
906944
navigateToGrid(targetIndex: number): boolean {
945+
const result = this.setActiveGrid(targetIndex);
946+
if (!result) { return false; }
947+
948+
// scrolling logic
949+
let resultsWindow = $('#results');
950+
let scrollTop = resultsWindow.scrollTop();
951+
let scrollBottom = scrollTop + resultsWindow.height();
952+
let gridHeight = $(this._el.nativeElement).find('slick-grid').height();
953+
if (scrollBottom < gridHeight * (targetIndex + 1)) {
954+
scrollTop += (gridHeight * (targetIndex + 1)) - scrollBottom;
955+
resultsWindow.scrollTop(scrollTop);
956+
}
957+
if (scrollTop > gridHeight * targetIndex) {
958+
scrollTop = (gridHeight * targetIndex);
959+
resultsWindow.scrollTop(scrollTop);
960+
}
961+
962+
return true;
963+
}
964+
965+
setActiveGrid(targetIndex: number): boolean {
907966
// check if the target index is valid
908967
if (targetIndex >= this.renderedDataSets.length || targetIndex < 0) {
909968
return false;
@@ -921,21 +980,6 @@ export class AppComponent implements OnInit, AfterViewChecked {
921980
this.slickgrids.toArray()[this.activeGrid].selection = false;
922981
this.slickgrids.toArray()[targetIndex].setActive();
923982
this.activeGrid = targetIndex;
924-
925-
// scrolling logic
926-
let resultsWindow = $('#results');
927-
let scrollTop = resultsWindow.scrollTop();
928-
let scrollBottom = scrollTop + resultsWindow.height();
929-
let gridHeight = $(this._el.nativeElement).find('slick-grid').height();
930-
if (scrollBottom < gridHeight * (targetIndex + 1)) {
931-
scrollTop += (gridHeight * (targetIndex + 1)) - scrollBottom;
932-
resultsWindow.scrollTop(scrollTop);
933-
}
934-
if (scrollTop > gridHeight * targetIndex) {
935-
scrollTop = (gridHeight * targetIndex);
936-
resultsWindow.scrollTop(scrollTop);
937-
}
938-
939983
return true;
940984
}
941985

src/views/htmlcontent/src/js/services/data.service.ts

+4
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,8 @@ export class DataService implements OnDestroy {
163163
});
164164
}
165165
}
166+
167+
getNewColumnWidth(currentWidth: number): Promise<number | undefined> {
168+
return this._proxy.getNewColumnWidth(currentWidth);
169+
}
166170
}

0 commit comments

Comments
 (0)