UNPKG

monaco-editor-core

Version:

A browser based code editor

130 lines (129 loc) 6.7 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { BrowserFeatures } from '../../../base/browser/canIUse.js'; import * as dom from '../../../base/browser/dom.js'; import { EventType, Gesture } from '../../../base/browser/touch.js'; import { mainWindow } from '../../../base/browser/window.js'; import { Disposable } from '../../../base/common/lifecycle.js'; import * as platform from '../../../base/common/platform.js'; import { MouseHandler } from './mouseHandler.js'; import { TextAreaSyntethicEvents } from './textAreaInput.js'; import { EditorMouseEvent, EditorPointerEventFactory } from '../editorDom.js'; /** * Currently only tested on iOS 13/ iPadOS. */ export class PointerEventHandler extends MouseHandler { constructor(context, viewController, viewHelper) { super(context, viewController, viewHelper); this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode)); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e) => this._onContextMenu(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode), false))); this._lastPointerType = 'mouse'; this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'pointerdown', (e) => { const pointerType = e.pointerType; if (pointerType === 'mouse') { this._lastPointerType = 'mouse'; return; } else if (pointerType === 'touch') { this._lastPointerType = 'touch'; } else { this._lastPointerType = 'pen'; } })); // PonterEvents const pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode); this._register(pointerEvents.onPointerMove(this.viewHelper.viewDomNode, (e) => this._onMouseMove(e))); this._register(pointerEvents.onPointerUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e))); this._register(pointerEvents.onPointerLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e))); this._register(pointerEvents.onPointerDown(this.viewHelper.viewDomNode, (e, pointerId) => this._onMouseDown(e, pointerId))); } onTap(event) { if (!event.initialTarget || !this.viewHelper.linesContentDomNode.contains(event.initialTarget)) { return; } event.preventDefault(); this.viewHelper.focusTextArea(); this._dispatchGesture(event, /*inSelectionMode*/ false); } onChange(event) { if (this._lastPointerType === 'touch') { this._context.viewModel.viewLayout.deltaScrollNow(-event.translationX, -event.translationY); } if (this._lastPointerType === 'pen') { this._dispatchGesture(event, /*inSelectionMode*/ true); } } _dispatchGesture(event, inSelectionMode) { const target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false); if (target.position) { this.viewController.dispatchMouse({ position: target.position, mouseColumn: target.position.column, startedOnLineNumbers: false, revealType: 1 /* NavigationCommandRevealType.Minimal */, mouseDownCount: event.tapCount, inSelectionMode, altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, leftButton: false, middleButton: false, onInjectedText: target.type === 6 /* MouseTargetType.CONTENT_TEXT */ && target.detail.injectedText !== null }); } } _onMouseDown(e, pointerId) { if (e.browserEvent.pointerType === 'touch') { return; } super._onMouseDown(e, pointerId); } } class TouchHandler extends MouseHandler { constructor(context, viewController, viewHelper) { super(context, viewController, viewHelper); this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode)); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e) => this._onContextMenu(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode), false))); } onTap(event) { event.preventDefault(); this.viewHelper.focusTextArea(); const target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false); if (target.position) { // Send the tap event also to the <textarea> (for input purposes) const event = document.createEvent('CustomEvent'); event.initEvent(TextAreaSyntethicEvents.Tap, false, true); this.viewHelper.dispatchTextAreaEvent(event); this.viewController.moveTo(target.position, 1 /* NavigationCommandRevealType.Minimal */); } } onChange(e) { this._context.viewModel.viewLayout.deltaScrollNow(-e.translationX, -e.translationY); } } export class PointerHandler extends Disposable { constructor(context, viewController, viewHelper) { super(); const isPhone = platform.isIOS || (platform.isAndroid && platform.isMobile); if (isPhone && BrowserFeatures.pointerEvents) { this.handler = this._register(new PointerEventHandler(context, viewController, viewHelper)); } else if (mainWindow.TouchEvent) { this.handler = this._register(new TouchHandler(context, viewController, viewHelper)); } else { this.handler = this._register(new MouseHandler(context, viewController, viewHelper)); } } getTargetAtClientPoint(clientX, clientY) { return this.handler.getTargetAtClientPoint(clientX, clientY); } }