提交 a4bc82cb 编写于 作者: A Alex Dima

Fixes Microsoft/monaco-editor#118: Work around Edge issue when hit-testing view cursors

上级 81ca90f9
......@@ -20,6 +20,7 @@ import {VisibleRange} from 'vs/editor/common/view/renderingContext';
import {EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, EditorMouseEvent} from 'vs/editor/browser/editorDom';
import {StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
import {EditorZoom} from 'vs/editor/common/config/commonEditorConfig';
import {IViewCursorRenderData} from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
/**
* Merges mouse events when mouse move events are throttled
......@@ -102,6 +103,12 @@ export interface IPointerHandlerHelper {
getLineNumberAtVerticalOffset(verticalOffset: number): number;
getVerticalOffsetForLineNumber(lineNumber: number): number;
getWhitespaceAtVerticalOffset(verticalOffset:number): editorCommon.IViewWhitespaceViewportData;
/**
* Get the last rendered information of the cursors.
*/
getLastViewCursorsRenderData(): IViewCursorRenderData[];
shouldSuppressMouseDownOnViewZone(viewZoneId: number): boolean;
shouldSuppressMouseDownOnWidget(widgetId: string): boolean;
......@@ -210,7 +217,8 @@ export class MouseHandler extends ViewEventHandler implements IDisposable {
// --- end event handlers
protected _createMouseTarget(e:EditorMouseEvent, testEventTarget:boolean): editorBrowser.IMouseTarget {
return this.mouseTargetFactory.createMouseTarget(this._layoutInfo, e, testEventTarget);
let lastViewCursorsRenderData = this.viewHelper.getLastViewCursorsRenderData();
return this.mouseTargetFactory.createMouseTarget(this._layoutInfo, lastViewCursorsRenderData, e, testEventTarget);
}
private _getMouseColumn(e:EditorMouseEvent): number {
......
......@@ -12,6 +12,7 @@ import {ViewContext} from 'vs/editor/common/view/viewContext';
import {IPointerHandlerHelper} from 'vs/editor/browser/controller/mouseHandler';
import {EditorMouseEvent} from 'vs/editor/browser/editorDom';
import * as dom from 'vs/base/browser/dom';
import {IViewCursorRenderData} from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
interface IHitTestResult {
position: IPosition;
......@@ -172,21 +173,39 @@ export class MouseTargetFactory {
return false;
}
public createMouseTarget(layoutInfo:EditorLayoutInfo, e:EditorMouseEvent, testEventTarget:boolean): IMouseTarget {
public createMouseTarget(layoutInfo:EditorLayoutInfo, lastViewCursorsRenderData:IViewCursorRenderData[], e:EditorMouseEvent, testEventTarget:boolean): IMouseTarget {
try {
let r = this._unsafeCreateMouseTarget(layoutInfo, e, testEventTarget);
let r = this._unsafeCreateMouseTarget(layoutInfo, lastViewCursorsRenderData, e, testEventTarget);
return r;
} catch (e) {
return this.createMouseTargetFromUnknownTarget(e.target);
}
}
private _unsafeCreateMouseTarget(layoutInfo:EditorLayoutInfo, e:EditorMouseEvent, testEventTarget:boolean): IMouseTarget {
private _unsafeCreateMouseTarget(layoutInfo:EditorLayoutInfo, lastViewCursorsRenderData:IViewCursorRenderData[], e:EditorMouseEvent, testEventTarget:boolean): IMouseTarget {
let mouseVerticalOffset = Math.max(0, this._viewHelper.getScrollTop() + (e.posy - e.editorPos.top));
let mouseContentHorizontalOffset = this._viewHelper.getScrollLeft() + (e.posx - e.editorPos.left) - layoutInfo.contentLeft;
let mouseColumn = this._getMouseColumn(mouseContentHorizontalOffset);
let t = <Element>e.target;
// Edge has a bug when hit-testing the exact position of a cursor,
// instead of returning the correct dom node, it returns the
// first or last rendered view line dom node, therefore help it out
// and first check if we are on top of a cursor
for (let i = 0, len = lastViewCursorsRenderData.length; i < len; i++) {
let d = lastViewCursorsRenderData[i];
if (
d.contentLeft <= mouseContentHorizontalOffset
&& mouseContentHorizontalOffset <= d.contentLeft + d.width
&& d.contentTop <= mouseVerticalOffset
&& mouseVerticalOffset <= d.contentTop + d.height
) {
return this.createMouseTargetFromViewCursor(t, d.position.lineNumber, d.position.column, mouseColumn);
}
}
let path = this.getClassNamePathTo(t, this._viewHelper.viewDomNode);
// Is it a content widget?
......@@ -390,8 +409,9 @@ export class MouseTargetFactory {
let parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (<HTMLElement>parent3).className : null;
if (parent3ClassName === ClassNames.VIEW_LINE) {
let p = this._viewHelper.getPositionFromDOMInfo(<HTMLElement>parent1, range.startOffset);
return {
position: this._viewHelper.getPositionFromDOMInfo(<HTMLElement>parent1, range.startOffset),
position: p,
hitTarget: null
};
} else {
......@@ -404,8 +424,9 @@ export class MouseTargetFactory {
let parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (<HTMLElement>parent2).className : null;
if (parent2ClassName === ClassNames.VIEW_LINE) {
let p = this._viewHelper.getPositionFromDOMInfo(<HTMLElement>startContainer, (<HTMLElement>startContainer).textContent.length);
return {
position: this._viewHelper.getPositionFromDOMInfo(<HTMLElement>startContainer, (<HTMLElement>startContainer).textContent.length),
position: p,
hitTarget: null
};
} else {
......
......@@ -66,6 +66,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
private viewZones: ViewZones;
private contentWidgets: ViewContentWidgets;
private overlayWidgets: ViewOverlayWidgets;
private viewCursors: ViewCursors;
private viewParts: ViewPart[];
private keyboardHandler: KeyboardHandler;
......@@ -251,8 +252,8 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.contentWidgets = new ViewContentWidgets(this._context, this.domNode);
this.viewParts.push(this.contentWidgets);
var viewCursors = new ViewCursors(this._context);
this.viewParts.push(viewCursors);
this.viewCursors = new ViewCursors(this._context);
this.viewParts.push(this.viewCursors);
// Overlay widgets
this.overlayWidgets = new ViewOverlayWidgets(this._context);
......@@ -276,7 +277,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.linesContent.appendChild(this.viewZones.domNode);
this.linesContent.appendChild(this.viewLines.getDomNode());
this.linesContent.appendChild(this.contentWidgets.domNode);
this.linesContent.appendChild(viewCursors.getDomNode());
this.linesContent.appendChild(this.viewCursors.getDomNode());
this.overflowGuardContainer.appendChild(marginViewOverlays.getDomNode());
this.overflowGuardContainer.appendChild(this.linesContentContainer);
this.overflowGuardContainer.appendChild(scrollDecoration.getDomNode());
......@@ -352,6 +353,12 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
}
return this.layoutProvider.getWhitespaceAtVerticalOffset(verticalOffset);
},
getLastViewCursorsRenderData: () => {
if (this._isDisposed) {
throw new Error('ViewImpl.pointerHandler.getLastViewCursorsRenderData: View is disposed');
}
return this.viewCursors.getLastRenderData() || [];
},
shouldSuppressMouseDownOnViewZone: (viewZoneId: number) => {
if (this._isDisposed) {
throw new Error('ViewImpl.pointerHandler.shouldSuppressMouseDownOnViewZone: View is disposed');
......
......@@ -10,6 +10,14 @@ import {Configuration} from 'vs/editor/browser/config/configuration';
import {ViewContext} from 'vs/editor/common/view/viewContext';
import {IRenderingContext, IRestrictedRenderingContext} from 'vs/editor/common/view/renderingContext';
export interface IViewCursorRenderData {
position: IPosition;
contentTop: number;
contentLeft: number;
width: number;
height: number;
}
export class ViewCursor {
private _context:ViewContext;
private _position: IPosition;
......@@ -133,8 +141,9 @@ export class ViewCursor {
return '';
}
public render(ctx:IRestrictedRenderingContext): void {
public render(ctx:IRestrictedRenderingContext): IViewCursorRenderData {
if (this._isInViewport) {
let top = this._positionTop + ctx.viewportTop - ctx.bigNumbersDelta;
let renderContent = this._getRenderedContent();
if (this._lastRenderedContent !== renderContent) {
this._lastRenderedContent = renderContent;
......@@ -143,12 +152,21 @@ export class ViewCursor {
this._domNode.setDisplay('block');
this._domNode.setLeft(this._positionLeft);
this._domNode.setTop(this._positionTop + ctx.viewportTop - ctx.bigNumbersDelta);
this._domNode.setTop(top);
this._domNode.setLineHeight(this._lineHeight);
this._domNode.setHeight(this._lineHeight);
} else {
this._domNode.setDisplay('none');
return {
position: this._position,
contentTop: top,
contentLeft: this._positionLeft,
height: this._lineHeight,
width: 2
};
}
this._domNode.setDisplay('none');
return null;
}
private updatePosition(newPosition:IPosition): void {
......
......@@ -9,7 +9,7 @@ import 'vs/css!./viewCursors';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {ClassNames} from 'vs/editor/browser/editorBrowser';
import {ViewPart} from 'vs/editor/browser/view/viewPart';
import {ViewCursor} from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
import {IViewCursorRenderData, ViewCursor} from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
import {ViewContext} from 'vs/editor/common/view/viewContext';
import {IRenderingContext, IRestrictedRenderingContext} from 'vs/editor/common/view/renderingContext';
import {FastDomNode, createFastDomNode} from 'vs/base/browser/styleMutator';
......@@ -38,6 +38,7 @@ export class ViewCursors extends ViewPart {
private _primaryCursor: ViewCursor;
private _secondaryCursors: ViewCursor[];
private _renderData: IViewCursorRenderData[];
constructor(context: ViewContext) {
super(context);
......@@ -48,6 +49,7 @@ export class ViewCursors extends ViewPart {
this._primaryCursor = new ViewCursor(this._context, false);
this._secondaryCursors = [];
this._renderData = [];
this._domNode = createFastDomNode(document.createElement('div'));
this._updateDomClassName();
......@@ -309,9 +311,17 @@ export class ViewCursors extends ViewPart {
}
public render(ctx: IRestrictedRenderingContext): void {
this._primaryCursor.render(ctx);
this._renderData = [];
this._renderData.push(this._primaryCursor.render(ctx));
for (var i = 0, len = this._secondaryCursors.length; i < len; i++) {
this._secondaryCursors[i].render(ctx);
this._renderData.push(this._secondaryCursors[i].render(ctx));
}
// Keep only data of cursors that are visible
this._renderData = this._renderData.filter(d => !!d);
}
public getLastRenderData(): IViewCursorRenderData[] {
return this._renderData;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册