mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-26 10:16:01 +01:00
use inline styles
This commit is contained in:
@@ -56,7 +56,7 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
|
||||
this.contentWidth = 0;
|
||||
this.scrollLeft = 0;
|
||||
|
||||
this.textAreaHandler = new TextAreaHandler(browser, this._getStrategy(), this.textArea, this._context.model, this._context.configuration.editor, () => this.viewHelper.flushAnyAccumulatedEvents());
|
||||
this.textAreaHandler = new TextAreaHandler(browser, this._getStrategy(), this.textArea, this._context.model, () => this.viewHelper.flushAnyAccumulatedEvents());
|
||||
|
||||
this._toDispose = [];
|
||||
this._toDispose.push(this.textAreaHandler.onKeyDown((e) => this.viewController.emitKeyDown(<IKeyboardEvent>e._actual)));
|
||||
|
||||
@@ -11,10 +11,6 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IClipboardEvent, ICompositionEvent, IKeyboardEventWrapper, ISimpleModel, ITextAreaWrapper, ITypeData, TextAreaState, TextAreaStrategy, createTextAreaState } from 'vs/editor/common/controller/textAreaState';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { EndOfLinePreference, InternalEditorOptions } from 'vs/editor/common/editorCommon';
|
||||
import { TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||
|
||||
const enum ReadFromTextArea {
|
||||
Type,
|
||||
@@ -75,7 +71,6 @@ export class TextAreaHandler extends Disposable {
|
||||
private Browser: IBrowser;
|
||||
private textArea: ITextAreaWrapper;
|
||||
private model: ISimpleModel;
|
||||
private config: InternalEditorOptions;
|
||||
private flushAnyAccumulatedEvents: () => void;
|
||||
|
||||
private selection: Range;
|
||||
@@ -94,12 +89,11 @@ export class TextAreaHandler extends Disposable {
|
||||
|
||||
private _nextCommand: ReadFromTextArea;
|
||||
|
||||
constructor(Browser: IBrowser, strategy: TextAreaStrategy, textArea: ITextAreaWrapper, model: ISimpleModel, config: InternalEditorOptions, flushAnyAccumulatedEvents: () => void) {
|
||||
constructor(Browser: IBrowser, strategy: TextAreaStrategy, textArea: ITextAreaWrapper, model: ISimpleModel, flushAnyAccumulatedEvents: () => void) {
|
||||
super();
|
||||
this.Browser = Browser;
|
||||
this.textArea = textArea;
|
||||
this.model = model;
|
||||
this.config = config;
|
||||
this.flushAnyAccumulatedEvents = flushAnyAccumulatedEvents;
|
||||
this.selection = new Range(1, 1, 1, 1);
|
||||
this.selections = [new Range(1, 1, 1, 1)];
|
||||
@@ -328,14 +322,10 @@ export class TextAreaHandler extends Disposable {
|
||||
// ------------- Clipboard operations
|
||||
|
||||
private _ensureClipboardGetsEditorSelection(e: IClipboardEvent): void {
|
||||
let whatToCopy = this._getPlainTextToCopy();
|
||||
let whatToCopy = this.model.getPlainTextToCopy(this.selections, this.Browser.enableEmptySelectionClipboard);
|
||||
if (e.canUseTextData()) {
|
||||
if (this.config.contribInfo.richTextClipboard) {
|
||||
let whatRichTextToCopy = this._getHTMLToCopy();
|
||||
e.setTextData(whatToCopy, whatRichTextToCopy === undefined ? whatToCopy : whatRichTextToCopy);
|
||||
} else {
|
||||
e.setTextData(whatToCopy);
|
||||
}
|
||||
let whatHTMLToCopy = this.model.getHTMLToCopy(this.selections, this.Browser.enableEmptySelectionClipboard);
|
||||
e.setTextData(whatToCopy, whatHTMLToCopy);
|
||||
} else {
|
||||
this.setTextAreaState('copy or cut', this.textAreaState.fromText(whatToCopy), false);
|
||||
}
|
||||
@@ -353,86 +343,4 @@ export class TextAreaHandler extends Disposable {
|
||||
this.lastCopiedValueIsFromEmptySelection = (selections.length === 1 && selections[0].isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
private _getPlainTextToCopy(): string {
|
||||
let newLineCharacter = this.model.getEOL();
|
||||
let selections = this.selections;
|
||||
|
||||
if (selections.length === 1) {
|
||||
let range: Range = selections[0];
|
||||
if (range.isEmpty()) {
|
||||
if (this.Browser.enableEmptySelectionClipboard) {
|
||||
let modelLineNumber = this.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
|
||||
return this.model.getModelLineContent(modelLineNumber) + newLineCharacter;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return this.model.getValueInRange(range, EndOfLinePreference.TextDefined);
|
||||
} else {
|
||||
selections = selections.slice(0).sort(Range.compareRangesUsingStarts);
|
||||
let result: string[] = [];
|
||||
for (let i = 0; i < selections.length; i++) {
|
||||
result.push(this.model.getValueInRange(selections[i], EndOfLinePreference.TextDefined));
|
||||
}
|
||||
|
||||
return result.join(newLineCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
private _getHTMLToCopy(): string | undefined {
|
||||
if (!this.config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let selections = this.selections;
|
||||
|
||||
let rules: string[] = [];
|
||||
let colorMap = TokenizationRegistry.getColorMap();
|
||||
for (let i = 1, len = colorMap.length; i < len; i++) {
|
||||
let color = colorMap[i];
|
||||
if (/^(?:[0-9a-fA-F]{3}){1,2}$/.test(color)) {
|
||||
color = '#' + color;
|
||||
}
|
||||
rules[i] = `.mtk${i} { color: ${color}; }`;
|
||||
}
|
||||
rules.push('.mtki { font-style: italic; }');
|
||||
rules.push('.mtkb { font-weight: bold; }');
|
||||
rules.push('.mtku { text-decoration: underline; }');
|
||||
|
||||
let output = `<style>${rules.join('\n')}</style>`;
|
||||
output += '<div class="monaco-editor-background">';
|
||||
|
||||
if (selections.length === 1) {
|
||||
let range: Range = selections[0];
|
||||
for (let i = 0, lineCount = range.endLineNumber - range.startLineNumber; i <= lineCount; i++) {
|
||||
let viewLineRenderingData = this.model.getViewLineRenderingData(range, range.startLineNumber + i);
|
||||
let lineContent = viewLineRenderingData.content;
|
||||
let startOffset = i === 0 ? range.startColumn - 1 : 0;
|
||||
let endOffset = i === lineCount ? range.endColumn - 1 : lineContent.length;
|
||||
lineContent = viewLineRenderingData.content.substring(startOffset, endOffset);
|
||||
|
||||
let r = renderViewLine(new RenderLineInput(
|
||||
(this.config.fontInfo.isMonospace && !this.config.viewInfo.disableMonospaceOptimizations),
|
||||
lineContent,
|
||||
viewLineRenderingData.mightContainRTL,
|
||||
0,
|
||||
viewLineRenderingData.tokens,
|
||||
[],
|
||||
viewLineRenderingData.tabSize,
|
||||
this.config.fontInfo.spaceWidth,
|
||||
endOffset,
|
||||
'none',
|
||||
false
|
||||
));
|
||||
|
||||
output += `<div>${r.html}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
output += '</div>';
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
export interface IClipboardEvent {
|
||||
canUseTextData(): boolean;
|
||||
@@ -57,7 +56,8 @@ export interface ISimpleModel {
|
||||
getValueInRange(range: Range, eol: EndOfLinePreference): string;
|
||||
getModelLineContent(lineNumber: number): string;
|
||||
getLineCount(): number;
|
||||
getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;
|
||||
getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
|
||||
coordinatesConverter: {
|
||||
convertViewPositionToModelPosition(viewPosition: Position): Position;
|
||||
|
||||
@@ -8,11 +8,115 @@ import * as strings from 'vs/base/common/strings';
|
||||
import { IState, ITokenizationSupport, TokenizationRegistry, LanguageId } from 'vs/editor/common/modes';
|
||||
import { NULL_STATE, nullTokenize2 } from 'vs/editor/common/modes/nullMode';
|
||||
import { LineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { CharacterMapping } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
|
||||
|
||||
export function tokenizeToString(text: string, languageId: string): string {
|
||||
return _tokenizeToString(text, _getSafeTokenizationSupport(languageId));
|
||||
}
|
||||
|
||||
export function tokenizeLineToHTML(text: string, viewLineTokens: ViewLineToken[], rules: { [key: string]: string }, options: { startOffset: number, endOffset: number, tabSize: number, containsRTL: boolean }): string {
|
||||
let tabSize = options.tabSize;
|
||||
let containsRTL = options.containsRTL;
|
||||
|
||||
let result = `<div>`;
|
||||
const characterMapping = new CharacterMapping(text.length + 1, viewLineTokens.length);
|
||||
|
||||
let charIndex = options.startOffset;
|
||||
let tabsCharDelta = 0;
|
||||
let charOffsetInPart = 0;
|
||||
|
||||
for (let tokenIndex = 0, lenJ = viewLineTokens.length; tokenIndex < lenJ; tokenIndex++) {
|
||||
const token = viewLineTokens[tokenIndex];
|
||||
const tokenEndIndex = token.endIndex;
|
||||
|
||||
if (token.endIndex < options.startOffset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const tokenType = token.type;
|
||||
let partContentCnt = 0;
|
||||
let partContent = '';
|
||||
|
||||
for (; charIndex < tokenEndIndex && charIndex < options.endOffset; charIndex++) {
|
||||
characterMapping.setPartData(charIndex, tokenIndex, charOffsetInPart);
|
||||
const charCode = text.charCodeAt(charIndex);
|
||||
|
||||
switch (charCode) {
|
||||
case CharCode.Tab:
|
||||
let insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;
|
||||
tabsCharDelta += insertSpacesCount - 1;
|
||||
charOffsetInPart += insertSpacesCount - 1;
|
||||
while (insertSpacesCount > 0) {
|
||||
partContent += ' ';
|
||||
partContentCnt++;
|
||||
insertSpacesCount--;
|
||||
}
|
||||
break;
|
||||
|
||||
case CharCode.Space:
|
||||
partContent += ' ';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.LessThan:
|
||||
partContent += '<';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.GreaterThan:
|
||||
partContent += '>';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.Ampersand:
|
||||
partContent += '&';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.Null:
|
||||
partContent += '�';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.UTF8_BOM:
|
||||
case CharCode.LINE_SEPARATOR_2028:
|
||||
partContent += '\ufffd';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.CarriageReturn:
|
||||
// zero width space, because carriage return would introduce a line break
|
||||
partContent += '​';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
default:
|
||||
partContent += String.fromCharCode(charCode);
|
||||
partContentCnt++;
|
||||
}
|
||||
|
||||
charOffsetInPart++;
|
||||
}
|
||||
|
||||
characterMapping.setPartLength(tokenIndex, partContentCnt);
|
||||
let style = tokenType.split(' ').map(type => rules[type]).join('');
|
||||
if (containsRTL) {
|
||||
result += `<span dir="ltr" style="${style}">${partContent}</span>`;
|
||||
} else {
|
||||
result += `<span style="${style}">${partContent}</span>`;
|
||||
}
|
||||
|
||||
if (token.endIndex > options.endOffset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result += `</div>`;
|
||||
return result;
|
||||
}
|
||||
|
||||
function _getSafeTokenizationSupport(languageId: string): ITokenizationSupport {
|
||||
let tokenizationSupport = TokenizationRegistry.get(languageId);
|
||||
if (tokenizationSupport) {
|
||||
|
||||
@@ -87,6 +87,9 @@ export interface IViewModel extends IEventEmitter {
|
||||
getModelLineContent(modelLineNumber: number): string;
|
||||
getModelLineMaxColumn(modelLineNumber: number): number;
|
||||
validateModelPosition(modelPosition: IPosition): Position;
|
||||
|
||||
getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
}
|
||||
|
||||
export class ViewLineRenderingData {
|
||||
|
||||
@@ -11,6 +11,8 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';
|
||||
import { ViewModelCursors } from 'vs/editor/common/viewModel/viewModelCursors';
|
||||
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
|
||||
import { ViewLineRenderingData, ViewModelDecoration, IViewModel, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
|
||||
@@ -558,4 +560,97 @@ export class ViewModel extends EventEmitter implements IViewModel {
|
||||
public validateModelPosition(position: editorCommon.IPosition): Position {
|
||||
return this.model.validatePosition(position);
|
||||
}
|
||||
|
||||
public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
let newLineCharacter = this.getEOL();
|
||||
|
||||
if (ranges.length === 1) {
|
||||
let range: Range = ranges[0];
|
||||
if (range.isEmpty()) {
|
||||
if (enableEmptySelectionClipboard) {
|
||||
let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
|
||||
return this.getModelLineContent(modelLineNumber) + newLineCharacter;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return this.getValueInRange(range, editorCommon.EndOfLinePreference.TextDefined);
|
||||
} else {
|
||||
ranges = ranges.slice(0).sort(Range.compareRangesUsingStarts);
|
||||
let result: string[] = [];
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
result.push(this.getValueInRange(ranges[i], editorCommon.EndOfLinePreference.TextDefined));
|
||||
}
|
||||
|
||||
return result.join(newLineCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
let rules: { [key: string]: string } = {};
|
||||
let colorMap = TokenizationRegistry.getColorMap();
|
||||
for (let i = 1, len = colorMap.length; i < len; i++) {
|
||||
let color = colorMap[i];
|
||||
if (/^(?:[0-9a-fA-F]{3}){1,2}$/.test(color)) {
|
||||
color = '#' + color;
|
||||
}
|
||||
rules[`mtk${i}`] = `color: ${color};`;
|
||||
}
|
||||
rules['mtki'] = 'font-style: italic;';
|
||||
rules['mtkb'] = 'font-weight: bold;';
|
||||
rules['mtku'] = 'text-decoration: underline;';
|
||||
|
||||
let defaultForegroundColor = /^(?:[0-9a-fA-F]{3}){1,2}$/.test(colorMap[1]) ? '#' + colorMap[1] : colorMap[1];
|
||||
let defaultBackgroundColor = /^(?:[0-9a-fA-F]{3}){1,2}$/.test(colorMap[2]) ? '#' + colorMap[2] : colorMap[2];
|
||||
|
||||
let output = `<div style="color: ${defaultForegroundColor}; background-color: ${defaultBackgroundColor}">`;
|
||||
|
||||
if (ranges.length === 1) {
|
||||
let range: Range = ranges[0];
|
||||
|
||||
if (range.isEmpty()) {
|
||||
if (enableEmptySelectionClipboard) {
|
||||
let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
|
||||
let viewLineStart = new Position(range.startLineNumber, 1);
|
||||
let viewLineEnd = new Position(range.startLineNumber, this.getLineMaxColumn(range.startLineNumber));
|
||||
let startOffset = this.coordinatesConverter.convertViewPositionToModelPosition(viewLineStart).column - 1;
|
||||
let endOffset = this.coordinatesConverter.convertViewPositionToModelPosition(viewLineEnd).column - 1;
|
||||
let viewLineRenderingData = this.getViewLineRenderingData(new Range(viewLineStart.lineNumber, viewLineStart.column, viewLineEnd.lineNumber, viewLineEnd.column), modelLineNumber);
|
||||
let html = tokenizeLineToHTML(this.getModelLineContent(modelLineNumber),
|
||||
viewLineRenderingData.tokens,
|
||||
rules,
|
||||
{
|
||||
startOffset: startOffset,
|
||||
endOffset: endOffset,
|
||||
tabSize: this.getTabSize(),
|
||||
containsRTL: this.model.mightContainRTL()
|
||||
});
|
||||
output += `${html}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
for (let i = 0, lineCount = range.endLineNumber - range.startLineNumber; i <= lineCount; i++) {
|
||||
let viewLineRenderingData = this.getViewLineRenderingData(range, range.startLineNumber + i);
|
||||
let lineContent = viewLineRenderingData.content;
|
||||
let startOffset = i === 0 ? range.startColumn - 1 : 0;
|
||||
let endOffset = i === lineCount ? range.endColumn - 1 : lineContent.length;
|
||||
|
||||
let html = tokenizeLineToHTML(lineContent, viewLineRenderingData.tokens, rules,
|
||||
{
|
||||
startOffset: startOffset,
|
||||
endOffset: endOffset,
|
||||
tabSize: this.getTabSize(),
|
||||
containsRTL: this.model.mightContainRTL()
|
||||
});
|
||||
output += `${html}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output += '</div>';
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
|
||||
@editorContribution
|
||||
class CopyRichTextController extends Disposable implements editorCommon.IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.copyRichText';
|
||||
|
||||
public static get(editor: editorCommon.ICommonCodeEditor): CopyRichTextController {
|
||||
return editor.getContribution<CopyRichTextController>(CopyRichTextController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _modeService: IModeService;
|
||||
private _handler: (event: any) => void;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IModeService modeService: IModeService,
|
||||
) {
|
||||
super();
|
||||
this._editor = editor;
|
||||
this._modeService = modeService;
|
||||
this._handler = (e: ClipboardEvent) => {
|
||||
if (e.target instanceof HTMLElement) {
|
||||
const target = <HTMLElement>e.target;
|
||||
if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) {
|
||||
let richText = e.clipboardData.getData('text/html');
|
||||
if (richText) {
|
||||
let themeId = this._editor.getConfiguration().viewInfo.theme;
|
||||
let color: string;
|
||||
if (/vs-dark($| )/.test(themeId)) {
|
||||
color = 'color: #BBB;background: #1E1E1E;';
|
||||
} if (/vs($| )/.test(themeId)) {
|
||||
color = 'color: #333;background: #fffffe;';
|
||||
} else {
|
||||
color = 'color: #fff;background: #000;';
|
||||
}
|
||||
|
||||
e.clipboardData.setData('text/html', `<style>.monaco-editor-background { ${color} }</style>\n${richText}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('copy', this._handler);
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return CopyRichTextController.ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
document.removeEventListener('copy', this._handler);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
|
||||
|
||||
@editorContribution
|
||||
class CopyRichTextController extends Disposable implements editorCommon.IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.copyRichText';
|
||||
|
||||
public static get(editor: editorCommon.ICommonCodeEditor): CopyRichTextController {
|
||||
return editor.getContribution<CopyRichTextController>(CopyRichTextController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _themeService: IThemeService;
|
||||
private _modeService: IModeService;
|
||||
private _handler: (event: any) => void;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IModeService modeService: IModeService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
super();
|
||||
this._editor = editor;
|
||||
this._themeService = themeService;
|
||||
this._modeService = modeService;
|
||||
this._handler = (e: ClipboardEvent) => {
|
||||
if (e.target instanceof HTMLElement) {
|
||||
const target = <HTMLElement>e.target;
|
||||
if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) {
|
||||
let richText = e.clipboardData.getData('text/html');
|
||||
if (richText) {
|
||||
let theme = this._themeService.getColorTheme();
|
||||
let globalSettings = theme.settings.filter(s => !s.scope);
|
||||
if (globalSettings.length > 0) {
|
||||
let backgroundColor = globalSettings[0].settings.background;
|
||||
e.clipboardData.setData('text/html', `<style>.monaco-editor-background { background-color: ${backgroundColor} }</style>\n${richText}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.document.addEventListener('copy', this._handler);
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return CopyRichTextController.ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
window.document.removeEventListener('copy', this._handler);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import 'vs/editor/contrib/quickOpen/browser/quickOutline';
|
||||
import 'vs/editor/contrib/quickOpen/browser/gotoLine';
|
||||
import 'vs/editor/contrib/quickOpen/browser/quickCommand';
|
||||
import 'vs/editor/contrib/inspectTokens/browser/inspectTokens';
|
||||
import 'vs/editor/contrib/clipboard/browser/standaloneRichClipboard';
|
||||
|
||||
import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase';
|
||||
import { createMonacoEditorAPI } from 'vs/editor/browser/standalone/standaloneEditor';
|
||||
|
||||
@@ -11,7 +11,6 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { TextAreaWrapper } from 'vs/editor/browser/controller/input/textAreaWrapper';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
// To run this test, open imeTester.html
|
||||
|
||||
@@ -55,8 +54,12 @@ class SingleLineTestModel implements ISimpleModel {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {
|
||||
return null;
|
||||
public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +104,7 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr:
|
||||
|
||||
let model = new SingleLineTestModel('some text');
|
||||
|
||||
let handler = new TextAreaHandler(browser, strategy, textAreaWrapper, model, null, () => { });
|
||||
let handler = new TextAreaHandler(browser, strategy, textAreaWrapper, model, () => { });
|
||||
|
||||
input.onfocus = () => {
|
||||
handler.setHasFocus(true);
|
||||
@@ -185,4 +188,4 @@ const TESTS = [
|
||||
TESTS.forEach((t) => {
|
||||
document.body.appendChild(doCreateTest(TextAreaStrategy.NVDA, t.description, t.in, t.out));
|
||||
document.body.appendChild(doCreateTest(TextAreaStrategy.IENarrator, t.description, t.in, t.out));
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,6 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
|
||||
import { MockTextAreaWrapper } from 'vs/editor/test/common/mocks/mockTextAreaWrapper';
|
||||
import { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
suite('TextAreaState', () => {
|
||||
|
||||
@@ -474,7 +473,11 @@ class SimpleModel implements ISimpleModel {
|
||||
return this._lines.length;
|
||||
}
|
||||
|
||||
public getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {
|
||||
return null;
|
||||
public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import 'vs/base/common/errors';
|
||||
// Editor
|
||||
import 'vs/editor/contrib/accessibility/browser/accessibility';
|
||||
import 'vs/editor/contrib/defineKeybinding/browser/defineKeybinding';
|
||||
import 'vs/editor/contrib/clipboard/electron-browser/richClipboard';
|
||||
import 'vs/editor/contrib/inspectTMScopes/electron-browser/inspectTMScopes';
|
||||
import 'vs/editor/contrib/selectionClipboard/electron-browser/selectionClipboard';
|
||||
import 'vs/editor/browser/editor.all';
|
||||
|
||||
Reference in New Issue
Block a user