monaco-editor-core
Version:
A browser based code editor
140 lines (139 loc) • 5.73 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as dom from '../../dom.js';
import { EventType, Gesture } from '../../touch.js';
import * as arrays from '../../../common/arrays.js';
import { Emitter } from '../../../common/event.js';
import { Disposable } from '../../../common/lifecycle.js';
import { isMacintosh } from '../../../common/platform.js';
export class SelectBoxNative extends Disposable {
constructor(options, selected, styles, selectBoxOptions) {
super();
this.selected = 0;
this.selectBoxOptions = selectBoxOptions || Object.create(null);
this.options = [];
this.selectElement = document.createElement('select');
this.selectElement.className = 'monaco-select-box';
if (typeof this.selectBoxOptions.ariaLabel === 'string') {
this.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel);
}
if (typeof this.selectBoxOptions.ariaDescription === 'string') {
this.selectElement.setAttribute('aria-description', this.selectBoxOptions.ariaDescription);
}
this._onDidSelect = this._register(new Emitter());
this.styles = styles;
this.registerListeners();
this.setOptions(options, selected);
}
registerListeners() {
this._register(Gesture.addTarget(this.selectElement));
[EventType.Tap].forEach(eventType => {
this._register(dom.addDisposableListener(this.selectElement, eventType, (e) => {
this.selectElement.focus();
}));
});
this._register(dom.addStandardDisposableListener(this.selectElement, 'click', (e) => {
dom.EventHelper.stop(e, true);
}));
this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => {
this.selectElement.title = e.target.value;
this._onDidSelect.fire({
index: e.target.selectedIndex,
selected: e.target.value
});
}));
this._register(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => {
let showSelect = false;
if (isMacintosh) {
if (e.keyCode === 18 /* KeyCode.DownArrow */ || e.keyCode === 16 /* KeyCode.UpArrow */ || e.keyCode === 10 /* KeyCode.Space */) {
showSelect = true;
}
}
else {
if (e.keyCode === 18 /* KeyCode.DownArrow */ && e.altKey || e.keyCode === 10 /* KeyCode.Space */ || e.keyCode === 3 /* KeyCode.Enter */) {
showSelect = true;
}
}
if (showSelect) {
// Space, Enter, is used to expand select box, do not propagate it (prevent action bar action run)
e.stopPropagation();
}
}));
}
get onDidSelect() {
return this._onDidSelect.event;
}
setOptions(options, selected) {
if (!this.options || !arrays.equals(this.options, options)) {
this.options = options;
this.selectElement.options.length = 0;
this.options.forEach((option, index) => {
this.selectElement.add(this.createOption(option.text, index, option.isDisabled));
});
}
if (selected !== undefined) {
this.select(selected);
}
}
select(index) {
if (this.options.length === 0) {
this.selected = 0;
}
else if (index >= 0 && index < this.options.length) {
this.selected = index;
}
else if (index > this.options.length - 1) {
// Adjust index to end of list
// This could make client out of sync with the select
this.select(this.options.length - 1);
}
else if (this.selected < 0) {
this.selected = 0;
}
this.selectElement.selectedIndex = this.selected;
if ((this.selected < this.options.length) && typeof this.options[this.selected].text === 'string') {
this.selectElement.title = this.options[this.selected].text;
}
else {
this.selectElement.title = '';
}
}
focus() {
if (this.selectElement) {
this.selectElement.tabIndex = 0;
this.selectElement.focus();
}
}
blur() {
if (this.selectElement) {
this.selectElement.tabIndex = -1;
this.selectElement.blur();
}
}
setFocusable(focusable) {
this.selectElement.tabIndex = focusable ? 0 : -1;
}
render(container) {
container.classList.add('select-container');
container.appendChild(this.selectElement);
this.setOptions(this.options, this.selected);
this.applyStyles();
}
applyStyles() {
// Style native select
if (this.selectElement) {
this.selectElement.style.backgroundColor = this.styles.selectBackground ?? '';
this.selectElement.style.color = this.styles.selectForeground ?? '';
this.selectElement.style.borderColor = this.styles.selectBorder ?? '';
}
}
createOption(value, index, disabled) {
const option = document.createElement('option');
option.value = value;
option.text = value;
option.disabled = !!disabled;
return option;
}
}