mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 09:35:39 -05:00
Adds aria labels to all input ui (#1136)
* adds aria-label to inputs for connection * formatting * add ariaLabels to all checkboxes/inputboxes/dropdowns
This commit is contained in:
@@ -12,6 +12,7 @@ export interface ICheckboxOptions {
|
||||
enabled?: boolean;
|
||||
checked?: boolean;
|
||||
onChange?: (val: boolean) => void;
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
export class Checkbox extends Widget {
|
||||
@@ -27,6 +28,10 @@ export class Checkbox extends Widget {
|
||||
this._el = document.createElement('input');
|
||||
this._el.type = 'checkbox';
|
||||
|
||||
if (opts.ariaLabel) {
|
||||
this._el.setAttribute('aria-label', opts.ariaLabel);
|
||||
}
|
||||
|
||||
this.onchange(this._el, e => {
|
||||
this._onChange.fire(this.checked);
|
||||
});
|
||||
|
||||
@@ -43,7 +43,8 @@ export function createOptionElement(option: sqlops.ServiceOption, rowContainer:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ariaLabel: option.displayName
|
||||
});
|
||||
optionWidget.value = optionValue;
|
||||
inputElement = this.findElement(rowContainer, 'input');
|
||||
@@ -55,7 +56,8 @@ export function createOptionElement(option: sqlops.ServiceOption, rowContainer:
|
||||
optionWidget = new InputBox(rowContainer.getHTMLElement(), contextViewService, {
|
||||
validationOptions: {
|
||||
validation: (value: string) => (!value && option.isRequired) ? ({ type: MessageType.ERROR, content: option.displayName + missingErrorMessage }) : null
|
||||
}
|
||||
},
|
||||
ariaLabel: option.displayName
|
||||
});
|
||||
optionWidget.value = optionValue;
|
||||
if (option.valueType === ServiceOptionType.password) {
|
||||
|
||||
@@ -104,7 +104,9 @@ export class AutoOAuthDialog extends Modal {
|
||||
});
|
||||
|
||||
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
|
||||
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: label
|
||||
});
|
||||
});
|
||||
});
|
||||
return inputBox;
|
||||
|
||||
@@ -34,6 +34,11 @@ import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
// in case that other non-Azure sign in is to be used
|
||||
const firewallHelpUri = 'https://aka.ms/sqlopsfirewallhelp';
|
||||
|
||||
const LocalizedStrings = {
|
||||
FROM: localize('from', 'From'),
|
||||
TO: localize('to', 'To')
|
||||
};
|
||||
|
||||
export class FirewallRuleDialog extends Modal {
|
||||
public viewModel: FirewallRuleViewModel;
|
||||
private _createButton: Button;
|
||||
@@ -140,19 +145,23 @@ export class FirewallRuleDialog extends Modal {
|
||||
subnetIPRangeSection = subnetIPRangeContainer.getHTMLElement();
|
||||
subnetIPRangeContainer.div({ 'class': 'dialog-input-section' }, (inputContainer) => {
|
||||
inputContainer.div({ 'class': 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(localize('from', 'From'));
|
||||
labelContainer.innerHtml(LocalizedStrings.FROM);
|
||||
});
|
||||
|
||||
inputContainer.div({ 'class': 'dialog-input' }, (inputCellContainer) => {
|
||||
this._fromRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
this._fromRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: LocalizedStrings.FROM
|
||||
});
|
||||
});
|
||||
|
||||
inputContainer.div({ 'class': 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(localize('to', 'To'));
|
||||
labelContainer.innerHtml(LocalizedStrings.TO);
|
||||
});
|
||||
|
||||
inputContainer.div({ 'class': 'dialog-input' }, (inputCellContainer) => {
|
||||
this._toRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
this._toRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: LocalizedStrings.TO
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -207,7 +207,7 @@ export class ConnectionWidget {
|
||||
container.element('tr', {}, (rowContainer) => {
|
||||
rowContainer.element('td');
|
||||
rowContainer.element('td', { class: cellContainerClass }, (inputCellContainer) => {
|
||||
checkbox = new Checkbox(inputCellContainer.getHTMLElement(), { label, checked: isChecked });
|
||||
checkbox = new Checkbox(inputCellContainer.getHTMLElement(), { label, checked: isChecked, ariaLabel: label });
|
||||
});
|
||||
});
|
||||
return checkbox;
|
||||
|
||||
@@ -62,8 +62,11 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
|
||||
ngOnInit() {
|
||||
this._inited = true;
|
||||
|
||||
let placeholderLabel = this._config.context === 'database' ? nls.localize('seachObjects', 'Search by name of type (a:, t:, v:, f:, or sp:)') : nls.localize('searchDatabases', 'Search databases');
|
||||
|
||||
let inputOptions: IInputOptions = {
|
||||
placeholder: this._config.context === 'database' ? nls.localize('seachObjects', 'Search by name of type (a:, t:, v:, f:, or sp:)') : nls.localize('searchDatabases', 'Search databases')
|
||||
placeholder: placeholderLabel,
|
||||
ariaLabel: placeholderLabel
|
||||
};
|
||||
this._input = new InputBox(this._inputContainer.nativeElement, this._bootstrap.contextViewService, inputOptions);
|
||||
this._register(this._input.onDidChange(e => {
|
||||
|
||||
@@ -207,7 +207,10 @@ export class BackupComponent {
|
||||
let self = this;
|
||||
this.addFooterButtons();
|
||||
|
||||
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this._bootstrapService.contextViewService, { placeholder: this.recoveryModel });
|
||||
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this._bootstrapService.contextViewService, {
|
||||
placeholder: this.recoveryModel,
|
||||
ariaLabel: this.recoveryModelLabel
|
||||
});
|
||||
// Set backup type
|
||||
this.backupTypeSelectBox = new SelectBox([], '', this._bootstrapService.contextViewService);
|
||||
this.backupTypeSelectBox.render(this.backupTypeElement.nativeElement);
|
||||
@@ -216,39 +219,46 @@ export class BackupComponent {
|
||||
this.copyOnlyCheckBox = new Checkbox(this.copyOnlyElement.nativeElement, {
|
||||
label: this.copyOnlyLabel,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: this.copyOnlyLabel
|
||||
});
|
||||
|
||||
// Encryption checkbox
|
||||
this.encryptCheckBox = new Checkbox(this.encryptElement.nativeElement, {
|
||||
label: this.encryptionLabel,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => self.onChangeEncrypt()
|
||||
onChange: (viaKeyboard) => self.onChangeEncrypt(),
|
||||
ariaLabel: this.encryptionLabel
|
||||
});
|
||||
|
||||
// Verify backup checkbox
|
||||
this.verifyCheckBox = new Checkbox(this.verifyElement.nativeElement, {
|
||||
label: this.verifyContainerLabel,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: this.verifyContainerLabel
|
||||
});
|
||||
|
||||
// Perform checksum checkbox
|
||||
this.checksumCheckBox = new Checkbox(this.checksumElement.nativeElement, {
|
||||
label: this.checksumContainerLabel,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: this.checksumContainerLabel
|
||||
});
|
||||
|
||||
// Continue on error checkbox
|
||||
this.continueOnErrorCheckBox = new Checkbox(this.continueOnErrorElement.nativeElement, {
|
||||
label: this.continueOnErrorContainerLabel,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: this.continueOnErrorContainerLabel
|
||||
});
|
||||
|
||||
// Set backup name
|
||||
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this._bootstrapService.contextViewService);
|
||||
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this._bootstrapService.contextViewService, {
|
||||
ariaLabel: this.backupNameLabel
|
||||
});
|
||||
|
||||
// Set backup path list
|
||||
this.pathListBox = new ListBox([], '', this._bootstrapService.contextViewService, this._bootstrapService.clipboardService);
|
||||
@@ -279,10 +289,14 @@ export class BackupComponent {
|
||||
{
|
||||
validationOptions: {
|
||||
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: this.mediaNameRequiredError }) : null
|
||||
}
|
||||
});
|
||||
},
|
||||
ariaLabel: this.newMediaSetNameLabel
|
||||
}
|
||||
);
|
||||
|
||||
this.mediaDescriptionBox = new InputBox(this.mediaDescriptionElement.nativeElement, this._bootstrapService.contextViewService);
|
||||
this.mediaDescriptionBox = new InputBox(this.mediaDescriptionElement.nativeElement, this._bootstrapService.contextViewService, {
|
||||
ariaLabel: this.newMediaSetDescriptionLabel
|
||||
});
|
||||
|
||||
// Set backup retain days
|
||||
let invalidInputMessage = localize('backupComponent.invalidInput', 'Invalid input. Value must be greater than or equal 0.');
|
||||
@@ -300,7 +314,8 @@ export class BackupComponent {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ariaLabel: this.setBackupRetainDaysLabel
|
||||
});
|
||||
|
||||
// Disable elements
|
||||
|
||||
@@ -40,6 +40,7 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
||||
interface FileListElement {
|
||||
logicalFileName: string;
|
||||
@@ -48,6 +49,11 @@ interface FileListElement {
|
||||
restoreAs: string;
|
||||
}
|
||||
|
||||
const LocalizedStrings = {
|
||||
BACKFILEPATH: localize('backupFilePath', "Backup file path"),
|
||||
TARGETDATABASE: localize('targetDatabase', 'Target database')
|
||||
};
|
||||
|
||||
export class RestoreDialog extends Modal {
|
||||
public viewModel: RestoreViewModel;
|
||||
|
||||
@@ -176,12 +182,13 @@ export class RestoreDialog extends Modal {
|
||||
validationOptions: {
|
||||
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: errorMessage }) : null
|
||||
},
|
||||
placeholder: localize('multipleBackupFilePath', 'Please enter one or more file paths separated by commas')
|
||||
placeholder: localize('multipleBackupFilePath', 'Please enter one or more file paths separated by commas'),
|
||||
ariaLabel: LocalizedStrings.BACKFILEPATH
|
||||
};
|
||||
|
||||
filePathContainer.div({ class: 'dialog-input-section' }, (inputContainer) => {
|
||||
inputContainer.div({ class: 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(localize('backupFilePath', "Backup file path"));
|
||||
labelContainer.safeInnerHtml(LocalizedStrings.BACKFILEPATH);
|
||||
});
|
||||
|
||||
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
|
||||
@@ -218,7 +225,7 @@ export class RestoreDialog extends Modal {
|
||||
|
||||
destinationContainer.div({ class: 'dialog-input-section' }, (inputContainer) => {
|
||||
inputContainer.div({ class: 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(localize('targetDatabase', 'Target database'));
|
||||
labelContainer.innerHtml(LocalizedStrings.TARGETDATABASE);
|
||||
});
|
||||
|
||||
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
|
||||
@@ -226,7 +233,8 @@ export class RestoreDialog extends Modal {
|
||||
inputCellContainer.style('width', '100%');
|
||||
this._databaseDropdown = new Dropdown(inputCellContainer.getHTMLElement(), this._contextViewService, this._themeService,
|
||||
{
|
||||
strictSelection: false
|
||||
strictSelection: false,
|
||||
ariaLabel: LocalizedStrings.TARGETDATABASE
|
||||
}
|
||||
);
|
||||
this._databaseDropdown.onValueChange(s => {
|
||||
@@ -514,7 +522,8 @@ export class RestoreDialog extends Modal {
|
||||
checkbox = new Checkbox(inputCellContainer.getHTMLElement(), {
|
||||
label: label,
|
||||
checked: isChecked,
|
||||
onChange: onCheck
|
||||
onChange: onCheck,
|
||||
ariaLabel: label
|
||||
});
|
||||
});
|
||||
return checkbox;
|
||||
@@ -537,13 +546,16 @@ export class RestoreDialog extends Modal {
|
||||
|
||||
private createInputBoxHelper(container: Builder, label: string, options?: IInputOptions): InputBox {
|
||||
let inputBox: InputBox;
|
||||
let ariaOptions = {
|
||||
ariaLabel: label
|
||||
};
|
||||
container.div({ class: 'dialog-input-section' }, (inputContainer) => {
|
||||
inputContainer.div({ class: 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(label);
|
||||
labelContainer.safeInnerHtml(label);
|
||||
});
|
||||
|
||||
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
|
||||
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, options);
|
||||
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, mixin(ariaOptions, options));
|
||||
});
|
||||
});
|
||||
return inputBox;
|
||||
|
||||
@@ -94,7 +94,9 @@ export class FileBrowserDialog extends Modal {
|
||||
tableWrapper.element('table', { class: 'file-table-content' }, (tableContainer) => {
|
||||
let pathLabel = localize('filebrowser.filepath', 'Selected path');
|
||||
let pathBuilder = DialogHelper.appendRow(tableContainer, pathLabel, 'file-input-label', 'file-input-box');
|
||||
this._filePathInputBox = new InputBox(pathBuilder.getHTMLElement(), this._contextViewService);
|
||||
this._filePathInputBox = new InputBox(pathBuilder.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: pathLabel
|
||||
});
|
||||
|
||||
this._fileFilterSelectBox = new SelectBox(['*'], '*', this._contextViewService);
|
||||
let filterLabel = localize('fileFilter', 'Files of type');
|
||||
|
||||
@@ -118,14 +118,16 @@ export class ChartViewerComponent implements OnInit, OnDestroy, IChartViewAction
|
||||
// Note: must use 'self' for callback
|
||||
this.labelFirstColumnCheckBox = new Checkbox(this.labelFirstColumnElement.nativeElement, {
|
||||
label: this.labelFirstColumnLabel,
|
||||
onChange: () => this.onLabelFirstColumnChanged()
|
||||
onChange: () => this.onLabelFirstColumnChanged(),
|
||||
ariaLabel: this.labelFirstColumnLabel
|
||||
});
|
||||
|
||||
// Init label first column checkbox
|
||||
// Note: must use 'self' for callback
|
||||
this.columnsAsLabelsCheckBox = new Checkbox(this.columnsAsLabelsElement.nativeElement, {
|
||||
label: this.columnsAsLabelsLabel,
|
||||
onChange: () => this.columnsAsLabelsChanged()
|
||||
onChange: () => this.columnsAsLabelsChanged(),
|
||||
ariaLabel: this.columnsAsLabelsLabel
|
||||
});
|
||||
|
||||
// Init legend dropdown
|
||||
|
||||
@@ -77,8 +77,8 @@ export class ServerGroupDialog extends Modal {
|
||||
this._bodyBuilder = builder;
|
||||
});
|
||||
// Connection Group Name
|
||||
let serverGroupNameLabel = localize('connectionGroupName', 'Server group name');
|
||||
this._bodyBuilder.div({ class: 'dialog-label' }, (labelContainer) => {
|
||||
let serverGroupNameLabel = localize('connectionGroupName', 'Server group name');
|
||||
labelContainer.innerHtml(serverGroupNameLabel);
|
||||
});
|
||||
this._bodyBuilder.div({ class: 'input-divider' }, (inputCellContainer) => {
|
||||
@@ -86,17 +86,20 @@ export class ServerGroupDialog extends Modal {
|
||||
this._groupNameInputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
validationOptions: {
|
||||
validation: (value: string) => !value && !this._skipGroupNameValidation ? ({ type: MessageType.ERROR, content: errorMessage }) : null
|
||||
}
|
||||
},
|
||||
ariaLabel: serverGroupNameLabel
|
||||
});
|
||||
});
|
||||
|
||||
// Connection Group Description
|
||||
let groupDescriptionLabel = localize('groupDescription', 'Group description');
|
||||
this._bodyBuilder.div({ class: 'dialog-label' }, (labelContainer) => {
|
||||
let groupDescriptionLabel = localize('groupDescription', 'Group description');
|
||||
labelContainer.innerHtml(groupDescriptionLabel);
|
||||
});
|
||||
this._bodyBuilder.div({ class: 'input-divider' }, (inputCellContainer) => {
|
||||
this._groupDescriptionInputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
this._groupDescriptionInputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: groupDescriptionLabel
|
||||
});
|
||||
});
|
||||
|
||||
// Connection Group Color
|
||||
|
||||
@@ -28,6 +28,7 @@ import { warn } from 'sql/base/common/log';
|
||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export class ConnectionViewlet extends Viewlet implements IConnectionsViewlet {
|
||||
|
||||
@@ -88,12 +89,14 @@ export class ConnectionViewlet extends Viewlet implements IConnectionsViewlet {
|
||||
this._viewletContainer = viewletContainer;
|
||||
viewletContainer.div({ class: 'search-box' }, (searchBoxContainer) => {
|
||||
this._searchBoxContainer = searchBoxContainer;
|
||||
let searchServerString = localize('Search server names', 'Search server names');
|
||||
this._searchBox = new InputBox(
|
||||
searchBoxContainer.getHTMLElement(),
|
||||
null,
|
||||
{
|
||||
placeholder: 'Search server names',
|
||||
actions: [this._clearSearchAction]
|
||||
placeholder: searchServerString,
|
||||
actions: [this._clearSearchAction],
|
||||
ariaLabel: searchServerString
|
||||
}
|
||||
);
|
||||
this._searchTerm = '';
|
||||
|
||||
@@ -444,9 +444,11 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
||||
super();
|
||||
this._toDispose = [];
|
||||
this.$databaseListDropdown = $('.databaseListDropdown');
|
||||
let selectString = nls.localize("selectDatabase", "Select Database");
|
||||
this._dropdown = new Dropdown(this.$databaseListDropdown.getHTMLElement(), contextViewProvider, themeService, {
|
||||
strictSelection: true,
|
||||
placeholder: nls.localize("selectDatabase", "Select Database")
|
||||
placeholder: selectString,
|
||||
ariaLabel: selectString
|
||||
});
|
||||
this._dropdown.onValueChange(s => this.databaseSelected(s));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user