提交 10bec774 编写于 作者: B Benjamin Pasero

remove old markdown contribution

上级 e9ee991d
......@@ -66,9 +66,7 @@ exports.collectModules = function(args) {
.define('vs/languages/html/common/htmlWorker', ['vs/languages/lib/common/beautify-html']);
// ---- markdown -------------------------------
common.define('vs/languages/markdown/common/markdown', ['vs/languages/html/common/html'])
.combine(worker)
.define('vs/languages/markdown/common/markdownWorker');
common.define('vs/languages/markdown/common/markdown', ['vs/languages/html/common/html']);
// ---- php -----------------------------------
common.define('vs/languages/php/common/php');
......
......@@ -4,34 +4,16 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry';
import ConfigurationRegistry = require('vs/platform/configuration/common/configurationRegistry');
import Platform = require('vs/platform/platform');
ModesRegistry.registerCompatMode({
id: 'markdown',
extensions: ['.md', '.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mdtxt', '.mdtext'],
aliases: ['Markdown', 'markdown'],
mimetypes: ['text/x-web-markdown'],
moduleId: 'vs/languages/markdown/common/markdown',
ctorName: 'MarkdownMode'
});
// Configuration
const configurationRegistry = <ConfigurationRegistry.IConfigurationRegistry>Platform.Registry.as(ConfigurationRegistry.Extensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'markdown',
'order': 20,
'type': 'object',
'title': nls.localize('markdownConfigurationTitle', "Markdown preview configuration"),
'properties': {
'markdown.styles': {
'type': 'array',
'description': nls.localize('styles', "A list of URLs or local paths to CSS style sheets to use from the markdown preview."),
'items': {
'type': 'string'
}
}
}
});
\ No newline at end of file
const register = false;
if (register) {
ModesRegistry.registerCompatMode({
id: 'markdown',
extensions: ['.md', '.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mdtxt', '.mdtext'],
aliases: ['Markdown', 'markdown'],
mimetypes: ['text/x-web-markdown'],
moduleId: 'vs/languages/markdown/common/markdown',
ctorName: 'MarkdownMode'
});
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
body {
font-family: "Segoe WPC", "Segoe UI", ".SFNSDisplay-Light", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
font-size: 14px;
padding-left: 12px;
line-height: 22px;
}
img {
max-width: 100%;
max-height: 100%;
}
a {
color: #4080D0;
text-decoration: none;
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}
h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
}
h1, h2, h3 {
font-weight: normal;
}
a:hover {
color: #4080D0;
text-decoration: underline;
}
table {
border-collapse: collapse;
}
table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}
table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
padding: 5px 10px;
}
table > tbody > tr + tr > td {
border-top: 1px solid;
}
blockquote {
margin: 0 0 0 5px;
padding-left: 10px;
border-left: 5px solid;
}
code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
font-size: 14px;
line-height: 19px;
}
.mac code {
font-size: 12px;
line-height: 18px;
}
code > div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}
/** Theming */
.vs {
color: rgb(30, 30, 30);
}
.vs-dark {
color: #DDD;
}
.hc-black {
color: white;
}
.vs code {
color: #A31515;
}
.vs-dark code {
color: #D7BA7D;
}
.vs code > div {
background-color: rgba(220, 220, 220, 0.4);
}
.vs-dark code > div {
background-color: rgba(10, 10, 10, 0.4);
}
.hc-black code > div {
background-color: rgb(0, 0, 0);
}
.hc-black h1 {
border-color: rgb(0, 0, 0);
}
.vs table > thead > tr > th {
border-color: rgba(0, 0, 0, 0.69);
}
.vs-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, 0.69);
}
.vs h1,
.vs hr,
.vs table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, 0.18);
}
.vs-dark h1,
.vs-dark hr,
.vs-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18);
}
.vs blockquote,
.vs-dark blockquote {
background: rgba(127, 127, 127, 0.1);
border-color: rgba(0, 122, 204, 0.5);
}
.hc-black blockquote {
background: transparent;
border-color: #fff;
}
\ No newline at end of file
......@@ -4,25 +4,29 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import WinJS = require('vs/base/common/winjs.base');
import URI from 'vs/base/common/uri';
import Types = require('vs/editor/common/modes/monarch/monarchTypes');
import Compile = require('vs/editor/common/modes/monarch/monarchCompile');
import Modes = require('vs/editor/common/modes');
import MarkdownWorker = require('vs/languages/markdown/common/markdownWorker');
import {OneWorkerAttr, AllWorkersAttr} from 'vs/platform/thread/common/threadService';
import {htmlTokenTypes} from 'vs/languages/html/common/html';
import markdownTokenTypes = require('vs/languages/markdown/common/markdownTokenTypes');
import {IModeService} from 'vs/editor/common/services/modeService';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IThreadService} from 'vs/platform/thread/common/thread';
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService';
import {AbstractMode, ModeWorkerManager} from 'vs/editor/common/modes/abstractMode';
import {AbstractMode} from 'vs/editor/common/modes/abstractMode';
import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchLexer';
import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry';
import {wireCancellationToken} from 'vs/base/common/async';
export const TOKEN_HEADER_LEAD = 'entity.name.tag';
export const TOKEN_HEADER = 'entity.name.tag';
export const TOKEN_EXT_HEADER = 'entity.other.attribute-name';
export const TOKEN_SEPARATOR = 'meta.separator';
export const TOKEN_QUOTE = 'comment';
export const TOKEN_LIST = 'keyword';
export const TOKEN_BLOCK = 'string';
export const TOKEN_BLOCK_CODE = 'variable.source';
export const language =
<Types.IMonarchLanguage>{
defaultToken: '',
......@@ -46,50 +50,50 @@ export const language =
root: [
// headers (with #)
[/^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/, ['white', markdownTokenTypes.TOKEN_HEADER_LEAD, markdownTokenTypes.TOKEN_HEADER, markdownTokenTypes.TOKEN_HEADER]],
[/^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/, ['white', TOKEN_HEADER_LEAD, TOKEN_HEADER, TOKEN_HEADER]],
// headers (with =)
[/^\s*(=+|\-+)\s*$/, markdownTokenTypes.TOKEN_EXT_HEADER],
[/^\s*(=+|\-+)\s*$/, TOKEN_EXT_HEADER],
// headers (with ***)
[/^\s*((\*[ ]?)+)\s*$/, markdownTokenTypes.TOKEN_SEPARATOR],
[/^\s*((\*[ ]?)+)\s*$/, TOKEN_SEPARATOR],
// quote
[/^\s*>+/, markdownTokenTypes.TOKEN_QUOTE],
[/^\s*>+/, TOKEN_QUOTE],
// list (starting with * or number)
[/^\s*([\*\-+:]|\d+\.)\s/, markdownTokenTypes.TOKEN_LIST],
[/^\s*([\*\-+:]|\d+\.)\s/, TOKEN_LIST],
// code block (4 spaces indent)
[/^(\t|[ ]{4})[^ ].*$/, markdownTokenTypes.TOKEN_BLOCK],
[/^(\t|[ ]{4})[^ ].*$/, TOKEN_BLOCK],
// code block (3 tilde)
[/^\s*~{3}\s*((?:\w|[\/\-#])+)?\s*$/, { token: markdownTokenTypes.TOKEN_BLOCK, next: '@codeblock' }],
[/^\s*~{3}\s*((?:\w|[\/\-#])+)?\s*$/, { token: TOKEN_BLOCK, next: '@codeblock' }],
// github style code blocks (with backticks and language)
[/^\s*```\s*((?:\w|[\/\-#])+)\s*$/, { token: markdownTokenTypes.TOKEN_BLOCK, next: '@codeblockgh', nextEmbedded: '$1' }],
[/^\s*```\s*((?:\w|[\/\-#])+)\s*$/, { token: TOKEN_BLOCK, next: '@codeblockgh', nextEmbedded: '$1' }],
// github style code blocks (with backticks but no language)
[/^\s*`{3}\s*$/, { token: markdownTokenTypes.TOKEN_BLOCK, next: '@codeblock' }],
[/^\s*`{3}\s*$/, { token: TOKEN_BLOCK, next: '@codeblock' }],
// markup within lines
{ include: '@linecontent' },
],
codeblock: [
[/^\s*~{3}\s*$/, { token: markdownTokenTypes.TOKEN_BLOCK, next: '@pop' }],
[/^\s*`{3}\s*$/, { token: markdownTokenTypes.TOKEN_BLOCK, next: '@pop' }],
[/.*$/, markdownTokenTypes.TOKEN_BLOCK_CODE],
[/^\s*~{3}\s*$/, { token: TOKEN_BLOCK, next: '@pop' }],
[/^\s*`{3}\s*$/, { token: TOKEN_BLOCK, next: '@pop' }],
[/.*$/, TOKEN_BLOCK_CODE],
],
// github style code blocks
codeblockgh: [
[/```\s*$/, { token: '@rematch', switchTo: '@codeblockghend', nextEmbedded: '@pop' }],
[/[^`]*$/, markdownTokenTypes.TOKEN_BLOCK_CODE],
[/[^`]*$/, TOKEN_BLOCK_CODE],
],
codeblockghend: [
[/\s*```/, { token: markdownTokenTypes.TOKEN_BLOCK_CODE, next: '@pop' }],
[/\s*```/, { token: TOKEN_BLOCK_CODE, next: '@pop' }],
[/./, '@rematch', '@pop'],
],
......@@ -197,23 +201,18 @@ export const language =
}
};
export class MarkdownMode extends AbstractMode implements Modes.IEmitOutputSupport {
export class MarkdownMode extends AbstractMode {
public static LANG_CONFIG:LanguageConfiguration = {
public static LANG_CONFIG: LanguageConfiguration = {
comments: {
blockComment: ['<!--', '-->',]
},
brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']],
brackets: [['{', '}'], ['[', ']'], ['(', ')'], ['<', '>']],
autoClosingPairs: []
};
public emitOutputSupport: Modes.IEmitOutputSupport;
public configSupport:Modes.IConfigurationSupport;
public tokenizationSupport: Modes.ITokenizationSupport;
private _modeWorkerManager: ModeWorkerManager<MarkdownWorker.MarkdownWorker>;
private _threadService:IThreadService;
constructor(
descriptor: Modes.IModeDescriptor,
@IInstantiationService instantiationService: IInstantiationService,
......@@ -225,12 +224,6 @@ export class MarkdownMode extends AbstractMode implements Modes.IEmitOutputSuppo
super(descriptor.id);
let lexer = Compile.compile(descriptor.id, language);
this._modeWorkerManager = new ModeWorkerManager<MarkdownWorker.MarkdownWorker>(descriptor, 'vs/languages/markdown/common/markdownWorker', 'MarkdownWorker', null, instantiationService);
this._threadService = threadService;
this.emitOutputSupport = this;
this.configSupport = this;
this.tokenizationSupport = createTokenizationSupport(modeService, this, lexer);
LanguageConfigurationRegistry.register(this.getId(), MarkdownMode.LANG_CONFIG);
......@@ -243,26 +236,4 @@ export class MarkdownMode extends AbstractMode implements Modes.IEmitOutputSuppo
}
}, true);
}
private _worker<T>(runner:(worker:MarkdownWorker.MarkdownWorker)=>WinJS.TPromise<T>): WinJS.TPromise<T> {
return this._modeWorkerManager.worker(runner);
}
public configure(options:any): WinJS.TPromise<void> {
if (this._threadService.isInMainThread) {
return this._configureWorkers(options);
} else {
return this._worker((w) => w._doConfigure(options));
}
}
static $_configureWorkers = AllWorkersAttr(MarkdownMode, MarkdownMode.prototype._configureWorkers);
private _configureWorkers(options:any): WinJS.TPromise<void> {
return this._worker((w) => w._doConfigure(options));
}
static $getEmitOutput = OneWorkerAttr(MarkdownMode, MarkdownMode.prototype.getEmitOutput);
public getEmitOutput(resource: URI, absoluteWorkerResourcesPath?: string): WinJS.TPromise<Modes.IEmitOutput> { // TODO@Ben technical debt: worker cannot resolve paths absolute
return this._worker((w) => w.getEmitOutput(resource, absoluteWorkerResourcesPath));
}
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export const TOKEN_HEADER_LEAD = 'entity.name.tag';
export const TOKEN_HEADER = 'entity.name.tag';
export const TOKEN_EXT_HEADER = 'entity.other.attribute-name';
export const TOKEN_SEPARATOR = 'meta.separator';
export const TOKEN_QUOTE = 'comment';
export const TOKEN_LIST = 'keyword';
export const TOKEN_BLOCK = 'string';
export const TOKEN_BLOCK_CODE = 'variable.source';
/*
// old settings
export const TOKEN_HEADER_LEAD = 'white';
export const TOKEN_HEADER = 'keyword.1';
export const TOKEN_EXT_HEADER = 'keyword.header';
export const TOKEN_SEPARATOR = 'keyword.header';
export const TOKEN_QUOTE = 'comment';
export const TOKEN_LIST = 'string.list';
export const TOKEN_BLOCK = 'variable';
export const TOKEN_BLOCK_CODE = 'variable.code';
*/
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import WinJS = require('vs/base/common/winjs.base');
import URI from 'vs/base/common/uri';
import Types = require('vs/base/common/types');
import Modes = require('vs/editor/common/modes');
import Paths = require('vs/base/common/paths');
import Marked = require('vs/base/common/marked/marked');
import {tokenizeToString} from 'vs/editor/common/modes/textToHtmlTokenizer';
import {isMacintosh} from 'vs/base/common/platform';
import {IModeService} from 'vs/editor/common/services/modeService';
import {IResourceService} from 'vs/editor/common/services/resourceService';
import {IMarkerService} from 'vs/platform/markers/common/markers';
enum Theme {
LIGHT,
DARK,
HC_BLACK
}
export class MarkdownWorker {
private static DEFAULT_MODE = 'text/plain';
private cssLinks: string[];
private theme: Theme = Theme.DARK;
// Custom Scrollbar CSS (inlined because of pseudo elements that cannot be made theme aware)
private static LIGHT_SCROLLBAR_CSS: string = [
'<style type="text/css">',
' ::-webkit-scrollbar {',
' width: 14px;',
' height: 14px;',
' }',
'',
' ::-webkit-scrollbar-thumb {',
' background-color: rgba(100, 100, 100, 0.4);',
' }',
'',
' ::-webkit-scrollbar-thumb:hover {',
' background-color: rgba(100, 100, 100, 0.7);',
' }',
'',
' ::-webkit-scrollbar-thumb:active {',
' background-color: rgba(0, 0, 0, 0.6);',
' }',
'</style>'
].join('\n');
private static DARK_SCROLLBAR_CSS: string = [
'<style type="text/css">',
' ::-webkit-scrollbar {',
' width: 14px;',
' height: 14px;',
' }',
'',
' ::-webkit-scrollbar-thumb {',
' background-color: rgba(121, 121, 121, 0.4);',
' }',
'',
' ::-webkit-scrollbar-thumb:hover {',
' background-color: rgba(100, 100, 100, 0.7);',
' }',
'',
' ::-webkit-scrollbar-thumb:active {',
' background-color: rgba(85, 85, 85, 0.8);',
' }',
'</style>'
].join('\n');
private static HC_BLACK_SCROLLBAR_CSS: string = [
'<style type="text/css">',
' ::-webkit-scrollbar {',
' width: 14px;',
' height: 14px;',
' }',
'',
' ::-webkit-scrollbar-thumb {',
' background-color: rgba(111, 195, 223, 0.3);',
' }',
'',
' ::-webkit-scrollbar-thumb:hover {',
' background-color: rgba(111, 195, 223, 0.4);',
' }',
'',
' ::-webkit-scrollbar-thumb:active {',
' background-color: rgba(111, 195, 223, 0.4);',
' }',
'</style>'
].join('\n');
private modeService: IModeService;
private resourceService:IResourceService;
private markerService: IMarkerService;
private _modeId: string;
constructor(
modeId: string,
@IResourceService resourceService: IResourceService,
@IMarkerService markerService: IMarkerService,
@IModeService modeService: IModeService
) {
this._modeId = modeId;
this.resourceService = resourceService;
this.markerService = markerService;
this.modeService = modeService;
}
_doConfigure(options: any): WinJS.TPromise<void> {
if (options && options.theme) {
this.theme = (options.theme === 'vs-dark') ? Theme.DARK : (options.theme === 'vs') ? Theme.LIGHT : Theme.HC_BLACK;
}
if (options && Types.isArray(options.styles)) {
this.cssLinks = options.styles;
}
return WinJS.TPromise.as(void 0);
}
public getEmitOutput(resource: URI, absoluteWorkersResourcePath: string): WinJS.TPromise<Modes.IEmitOutput> { // TODO@Ben technical debt: worker cannot resolve paths absolute
let model = this.resourceService.get(resource);
let cssLinks: string[] = this.cssLinks || [];
// Custom Renderer to fix href in images
let renderer = new Marked.marked.Renderer();
let $this = this;
renderer.image = function(href: string, title: string, text: string): string {
let out = '<img src="' + $this.fixHref(resource, href) + '" alt="' + text + '"';
if (title) {
out += ' title="' + title + '"';
}
out += (this.options && this.options.xhtml) ? '/>' : '>';
return out;
};
// Custom Renderer to open links always in a new tab
let superRenderLink = renderer.link;
renderer.link = function(href: string, title: string, text: string): string {
let link = superRenderLink.call(this, href, title, text);
// We cannot support local anchor tags because the iframe editor does not have a src set
if (href && href[0] === '#') {
link = link.replace('href=', 'localhref=');
} else {
link = link.replace('<a', '<a target="_blank"');
}
return link;
};
let modeService = this.modeService;
// Custom highlighter to use our modes to render code
let highlighter = function(code: string, lang: string, callback?: (error: Error, result: string) => void) {
// Lookup the mode and use the tokenizer to get the HTML
let mimeForLang = modeService.getModeIdForLanguageName(lang) || lang || MarkdownWorker.DEFAULT_MODE;
modeService.getOrCreateMode(mimeForLang).then((mode) => {
callback(null, tokenizeToString(code, mode));
});
};
return new WinJS.Promise((c, e) => {
// Render markdown file contents to HTML
Marked.marked(model.getValue(), {
gfm: true, // GitHub flavored markdown
renderer: renderer,
highlight: highlighter
}, (error: Error, htmlResult: string) => {
// Compute head
let head = [
'<!DOCTYPE html>',
'<html>',
'<head>',
'<meta http-equiv="Content-type" content="text/html;charset=UTF-8">',
(cssLinks.length === 0) ? '<link rel="stylesheet" href="' + absoluteWorkersResourcePath + '/markdown.css" type="text/css" media="screen">' : '',
(cssLinks.length === 0) ? '<link rel="stylesheet" href="' + absoluteWorkersResourcePath + '/tokens.css" type="text/css" media="screen">' : '',
(this.theme === Theme.LIGHT) ? MarkdownWorker.LIGHT_SCROLLBAR_CSS : (this.theme === Theme.DARK) ? MarkdownWorker.DARK_SCROLLBAR_CSS : MarkdownWorker.HC_BLACK_SCROLLBAR_CSS,
cssLinks.map((style) => {
return '<link rel="stylesheet" href="' + this.fixHref(resource, style) + '" type="text/css" media="screen">';
}).join('\n'),
'</head>',
isMacintosh ? '<body class="mac">' : '<body>'
].join('\n');
// Compute body
let body = [
(this.theme === Theme.LIGHT) ? '<div class="monaco-editor vs">' : (this.theme === Theme.DARK) ? '<div class="monaco-editor vs-dark">' : '<div class="monaco-editor hc-black">',
htmlResult,
'</div>',
].join('\n');
// Tail
let tail = [
'</body>',
'</html>'
].join('\n');
c({
head: head,
body: body,
tail: tail
});
});
});
}
private fixHref(resource: URI, href: string): string {
if (href) {
// Return early if href is already a URL
if (URI.parse(href).scheme) {
return href;
}
// Otherwise convert to a file URI by joining the href with the resource location
return URI.file(Paths.join(Paths.dirname(resource.fsPath), href)).toString();
}
return href;
}
}
\ No newline at end of file
此差异已折叠。
......@@ -6,12 +6,10 @@
import {Registry} from 'vs/platform/platform';
import nls = require('vs/nls');
import {TPromise} from 'vs/base/common/winjs.base';
import {Action, IAction} from 'vs/base/common/actions';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {IEditorQuickOpenEntry, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor} from 'vs/workbench/browser/quickopen';
import {StatusbarItemDescriptor, StatusbarAlignment, IStatusbarRegistry, Extensions as StatusExtensions} from 'vs/workbench/browser/parts/statusbar/statusbar';
import {EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions, IEditorInputActionContext, IEditorInputAction, EditorInputActionContributor, EditorInputAction} from 'vs/workbench/browser/parts/editor/baseEditor';
import {EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions} from 'vs/workbench/browser/parts/editor/baseEditor';
import {StringEditorInput} from 'vs/workbench/common/editor/stringEditorInput';
import {StringEditor} from 'vs/workbench/browser/parts/editor/stringEditor';
import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput';
......@@ -24,8 +22,6 @@ import {TextDiffEditor} from 'vs/workbench/browser/parts/editor/textDiffEditor';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {BinaryResourceDiffEditor} from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {IFrameEditor} from 'vs/workbench/browser/parts/editor/iframeEditor';
import {IFrameEditorInput} from 'vs/workbench/common/editor/iframeEditorInput';
import {IConfigurationRegistry, Extensions as ConfigurationExtensions} from 'vs/platform/configuration/common/configurationRegistry';
import {ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus} from 'vs/workbench/browser/parts/editor/editorStatus';
import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry';
......@@ -82,19 +78,6 @@ import {CloseEditorsInGroupAction, CloseEditorsInOtherGroupsAction, CloseAllEdit
]
);
// Register IFrame Editor
(<IEditorRegistry>Registry.as(EditorExtensions.Editors)).registerEditor(
new EditorDescriptor(
IFrameEditor.ID,
nls.localize('iframeEditor', "IFrame Editor"),
'vs/workbench/browser/parts/editor/iframeEditor',
'IFrameEditor'
),
[
new SyncDescriptor(IFrameEditorInput)
]
);
// Register Editor Status
let statusBar = (<IStatusbarRegistry>Registry.as(StatusExtensions.Statusbar));
statusBar.registerStatusbarItem(new StatusbarItemDescriptor(EditorStatus, StatusbarAlignment.RIGHT, 100 /* High Priority */));
......@@ -105,64 +88,6 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeModeAction, Chan
registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEOLAction, ChangeEOLAction.ID, ChangeEOLAction.LABEL), 'Change End of Line Sequence');
registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding');
export class ViewSourceEditorInputAction extends EditorInputAction {
constructor(
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
) {
super('workbench.files.action.viewSourceFromEditor', nls.localize('viewSource', "View Source"), 'iframe-editor-action view-source');
}
public run(event?: any): TPromise<any> {
let iFrameEditorInput = <IFrameEditorInput>this.input;
let sideBySide = !!(event && (event.ctrlKey || event.metaKey));
return this.editorService.openEditor({
resource: iFrameEditorInput.getResource()
}, sideBySide);
}
}
export class RefreshIFrameEditorInputAction extends EditorInputAction {
constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService) {
super('workbench.files.action.refreshIFrameEditor', nls.localize('reload', "Reload"), 'iframe-editor-action refresh');
}
public run(event?: any): TPromise<any> {
let editor = this.editorService.getActiveEditor();
if (editor instanceof IFrameEditor) {
(<IFrameEditor>editor).reload(true);
(<IFrameEditor>editor).focus();
}
return TPromise.as(null);
}
}
let actionBarRegistry = <IActionBarRegistry>Registry.as(ActionBarExtensions.Actionbar);
class IFrameEditorActionContributor extends EditorInputActionContributor {
constructor( @IInstantiationService private instantiationService: IInstantiationService) {
super();
}
public hasActionsForEditorInput(context: IEditorInputActionContext): boolean {
return context.input instanceof IFrameEditorInput;
}
public getActionsForEditorInput(context: IEditorInputActionContext): IEditorInputAction[] {
return [
this.instantiationService.createInstance(RefreshIFrameEditorInputAction),
this.instantiationService.createInstance(ViewSourceEditorInputAction)
];
}
}
// Contribute to IFrame Editor Inputs
actionBarRegistry.registerActionBarContributor(Scope.EDITOR, IFrameEditorActionContributor);
// Register keybinding for "Next Change" & "Previous Change" in visible diff editor
KeybindingsRegistry.registerCommandDesc({
id: 'workbench.action.compareEditor.nextChange',
......@@ -246,6 +171,7 @@ export class QuickOpenActionContributor extends ActionBarContributor {
}
}
const actionBarRegistry = <IActionBarRegistry>Registry.as(ActionBarExtensions.Actionbar);
actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionContributor);
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/iframeeditor';
import nls = require('vs/nls');
import {TPromise} from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
import DOM = require('vs/base/browser/dom');
import {Dimension, Builder, $} from 'vs/base/browser/builder';
import errors = require('vs/base/common/errors');
import {EditorOptions, EditorInput} from 'vs/workbench/common/editor';
import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {IFrameEditorInput} from 'vs/workbench/common/editor/iframeEditorInput';
import {IFrameEditorModel} from 'vs/workbench/common/editor/iframeEditorModel';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {IStorageService} from 'vs/platform/storage/common/storage';
import {Position} from 'vs/platform/editor/common/editor';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
/**
* An implementation of editor for showing HTML content in an IFrame by leveraging the IFrameEditorInput.
*/
export class IFrameEditor extends BaseEditor {
public static ID = 'workbench.editors.iFrameEditor';
private static RESOURCE_PROPERTY = 'resource';
private iframeContainer: Builder;
private iframeBuilder: Builder;
private focusTracker: DOM.IFocusTracker;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@IStorageService private storageService: IStorageService
) {
super(IFrameEditor.ID, telemetryService);
}
public getTitle(): string {
return this.getInput() ? this.getInput().getName() : nls.localize('iframeEditor', "IFrame Viewer");
}
public createEditor(parent: Builder): void {
// Container for IFrame
let iframeContainerElement = document.createElement('div');
iframeContainerElement.className = 'iframe-container';
this.iframeContainer = $(iframeContainerElement);
this.iframeContainer.tabindex(0); // enable focus support from the editor part (do not remove)
// IFrame
this.iframeBuilder = $(this.iframeContainer).element('iframe').addClass('iframe');
this.iframeBuilder.attr({ 'frameborder': '0' });
this.iframeBuilder.removeProperty(IFrameEditor.RESOURCE_PROPERTY);
parent.getHTMLElement().appendChild(iframeContainerElement);
}
public setInput(input: EditorInput, options: EditorOptions): TPromise<void> {
let oldInput = this.getInput();
super.setInput(input, options);
// Detect options
let forceOpen = options && options.forceOpen;
// Same Input
if (!forceOpen && input.matches(oldInput)) {
return TPromise.as<void>(null);
}
// Assert Input
if (!(input instanceof IFrameEditorInput)) {
return TPromise.wrapError<void>('Invalid editor input. IFrame editor requires an input instance of IFrameEditorInput.');
}
// Different Input (Reload)
return this.doSetInput(input, true /* isNewInput */);
}
private doSetInput(input: EditorInput, isNewInput?: boolean): TPromise<void> {
return this.editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel) => {
// Assert Model interface
if (!(resolvedModel instanceof IFrameEditorModel)) {
return TPromise.wrapError<void>('Invalid editor input. IFrame editor requires a model instance of IFrameEditorModel.');
}
// Assert that the current input is still the one we expect. This prevents a race condition when loading takes long and another input was set meanwhile
if (!this.getInput() || this.getInput() !== input) {
return null;
}
// Set IFrame contents
let iframeModel = <IFrameEditorModel>resolvedModel;
let isUpdate = !isNewInput && !!this.iframeBuilder.getProperty(IFrameEditor.RESOURCE_PROPERTY);
let contents = iframeModel.getContents();
// Crazy hack to get keybindings to bubble out of the iframe to us
contents.body = contents.body + this.enableKeybindings();
// Set Contents
try {
this.setFrameContents(iframeModel.resource, isUpdate ? contents.body : [contents.head, contents.body, contents.tail].join('\n'), isUpdate /* body only */);
} catch (error) {
setTimeout(() => this.reload(true /* clear */), 1000); // retry in case of an error which indicates the iframe (only) might be on a different URL
}
// When content is fully replaced, we also need to recreate the focus tracker
if (!isUpdate) {
this.clearFocusTracker();
}
// Track focus on contents and make the editor active when focus is received
if (!this.focusTracker) {
this.focusTracker = DOM.trackFocus((<HTMLIFrameElement>this.iframeBuilder.getHTMLElement()).contentWindow);
this.focusTracker.addFocusListener(() => {
this.editorGroupService.activateGroup(this.position);
});
}
});
}
private setFrameContents(resource: URI, contents: string, isUpdate: boolean): void {
let iframeWindow = (<HTMLIFrameElement>this.iframeBuilder.getHTMLElement()).contentWindow;
// Update body only if this is an update of the same resource (preserves scroll position and does not flicker)
if (isUpdate) {
iframeWindow.document.body.innerHTML = contents;
}
// Write directly to iframe document replacing any previous content
else {
iframeWindow.document.open('text/html', 'replace');
iframeWindow.document.write(contents);
iframeWindow.document.close();
// Reset scroll
iframeWindow.scrollTo(0, 0);
// Associate resource with iframe
this.iframeBuilder.setProperty(IFrameEditor.RESOURCE_PROPERTY, resource.toString());
}
}
private enableKeybindings(): string {
return [
'<script>',
'var ignoredKeys = [9 /* tab */, 32 /* space */, 33 /* page up */, 34 /* page down */, 38 /* up */, 40 /* down */];',
'var ignoredCtrlCmdKeys = [65 /* a */, 67 /* c */];',
'var ignoredShiftKeys = [9 /* tab */];',
'window.document.body.addEventListener("keydown", function(event) {', // Listen to keydown events in the iframe
' try {',
' if (ignoredKeys.some(function(i) { return i === event.keyCode; })) {',
' if (!event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {',
' return;', // we want some single keys to be supported (e.g. Page Down for scrolling)
' }',
' }',
'',
' if (ignoredCtrlCmdKeys.some(function(i) { return i === event.keyCode; })) {',
' if (event.ctrlKey || event.metaKey) {',
' return;', // we want some ctrl/cmd keys to be supported (e.g. Ctrl+C for copy)
' }',
' }',
'',
' if (ignoredShiftKeys.some(function(i) { return i === event.keyCode; })) {',
' if (event.shiftKey) {',
' return;', // we want some shift keys to be supported (e.g. Shift+Tab for copy)
' }',
' }',
'',
' event.preventDefault();', // very important to not get duplicate actions when this one bubbles up!
'',
' var fakeEvent = document.createEvent("KeyboardEvent");', // create a keyboard event
' Object.defineProperty(fakeEvent, "keyCode", {', // we need to set some properties that Chrome wants
' get : function() {',
' return event.keyCode;',
' }',
' });',
' Object.defineProperty(fakeEvent, "which", {',
' get : function() {',
' return event.keyCode;',
' }',
' });',
' Object.defineProperty(fakeEvent, "target", {',
' get : function() {',
' return window && window.parent.document.body;',
' }',
' });',
'',
' fakeEvent.initKeyboardEvent("keydown", true, true, document.defaultView, null, null, event.ctrlKey, event.altKey, event.shiftKey, event.metaKey);', // the API shape of this method is not clear to me, but it works ;)
'',
' window.parent.document.dispatchEvent(fakeEvent);', // dispatch the event onto the parent
' } catch (error) {}',
'});',
// disable dropping into iframe!
'window.document.addEventListener("dragover", function (e) {',
' e.preventDefault();',
'});',
'window.document.addEventListener("drop", function (e) {',
' e.preventDefault();',
'});',
'window.document.body.addEventListener("dragover", function (e) {',
' e.preventDefault();',
'});',
'window.document.body.addEventListener("drop", function (e) {',
' e.preventDefault();',
'});',
'</script>'
].join('\n');
}
public clearInput(): void {
// Reset IFrame
this.clearIFrame();
super.clearInput();
}
private clearIFrame(): void {
this.iframeBuilder.src('about:blank');
this.iframeBuilder.removeProperty(IFrameEditor.RESOURCE_PROPERTY);
// Focus Listener
this.clearFocusTracker();
}
private clearFocusTracker(): void {
if (this.focusTracker) {
this.focusTracker.dispose();
this.focusTracker = null;
}
}
public layout(dimension: Dimension): void {
// Pass on to IFrame Container and IFrame
this.iframeContainer.size(dimension.width, dimension.height);
this.iframeBuilder.size(dimension.width, dimension.height);
}
public focus(): void {
this.iframeContainer.domFocus();
}
public changePosition(position: Position): void {
super.changePosition(position);
// reparenting an IFRAME into another DOM element yields weird results when the contents are made
// of a string and not a URL. to be on the safe side we reload the iframe when the position changes
// and we do it using a timeout of 0 to reload only after the position has been changed in the DOM
setTimeout(() => this.reload(true));
}
/**
* Reloads the contents of the iframe in this editor by reapplying the input.
*/
public reload(clearIFrame?: boolean): void {
if (this.input) {
if (clearIFrame) {
this.clearIFrame();
}
this.doSetInput(this.input).done(null, errors.onUnexpectedError);
}
}
public dispose(): void {
// Destroy Container
this.iframeContainer.destroy();
// Focus Listener
this.clearFocusTracker();
super.dispose();
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .iframe-container .iframe {
box-sizing: border-box;
}
.monaco-workbench .iframe-container.ipad-touch-enabled {
-webkit-overflow-scrolling: touch;
overflow: auto;
}
\ No newline at end of file
......@@ -879,7 +879,7 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti
DOM.EventHelper.stop(e);
// Overlay the editor area with a div to be able to capture all mouse events (helps when iframes are used in any editor)
// Overlay the editor area with a div to be able to capture all mouse events
let overlayDiv = $('div').style({
position: 'absolute',
top: SideBySideEditorControl.EDITOR_TITLE_HEIGHT + 'px',
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {EditorModel, EditorInput} from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
/**
* An editor input to use with the IFrameEditor.
*/
export abstract class IFrameEditorInput extends EditorInput {
public static ID: string = 'workbench.editors.iFrameEditorInput';
private resource: URI;
private name: string;
private description: string;
private cachedModel: EditorModel;
constructor(resource: URI, name: string, description: string) {
super();
this.resource = resource;
this.name = name;
this.description = description;
}
public getTypeId(): string {
return IFrameEditorInput.ID;
}
public getResource(): URI {
return this.resource;
}
public getName(): string {
return this.name;
}
public getDescription(): string {
return this.description;
}
public resolve(refresh?: boolean): TPromise<EditorModel> {
let modelPromise: TPromise<EditorModel>;
// Use Cached Model
if (this.cachedModel && !refresh) {
modelPromise = TPromise.as<EditorModel>(this.cachedModel);
}
// Refresh Cached Model
else if (this.cachedModel && refresh) {
modelPromise = this.cachedModel.load();
}
// Create Model and Load
else {
let model = this.createModel();
modelPromise = model.load();
}
return modelPromise.then((resolvedModel: EditorModel) => {
this.cachedModel = resolvedModel;
return this.cachedModel;
});
}
/**
* Subclasses override this method to provide their own implementation.
*/
protected abstract createModel(): EditorModel;
/**
* Subclasses override this method to create a new input from a given resource.
*/
public abstract createNew(resource: URI): IFrameEditorInput;
public matches(otherInput: any): boolean {
if (super.matches(otherInput) === true) {
return true;
}
if (otherInput instanceof IFrameEditorInput) {
let otherIFrameEditorInput = <IFrameEditorInput>otherInput;
// Otherwise compare by properties
return otherIFrameEditorInput.resource.toString() === this.resource.toString();
}
return false;
}
public dispose(): void {
if (this.cachedModel) {
this.cachedModel.dispose();
this.cachedModel = null;
}
super.dispose();
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import {EditorModel} from 'vs/workbench/common/editor';
export interface IFrameContents {
head: string;
body: string;
tail: string;
}
/**
* An editor model that represents the resolved state for an iframe editor input. After the model has been
* resolved it knows which content to pass to the iframe editor. The contents will be set directly into the
* iframe. The contents have to ensure that e.g. a base URL is set so that relative links or images can be
* resolved.
*/
export class IFrameEditorModel extends EditorModel {
private _resource: URI;
private head: string;
private body: string;
private tail: string;
constructor(resource:URI) {
super();
this._resource = resource;
}
public get resource(): URI {
return this._resource;
}
public setContents(head: string, body: string, tail: string): void {
this.head = head;
this.body = body;
this.tail = tail;
}
public getContents(): IFrameContents {
return {
head: this.head,
body: this.body,
tail: this.tail
};
}
}
\ No newline at end of file
......@@ -169,7 +169,6 @@
outline: 0 !important; /* activity bar indicates focus custom */
}
.monaco-shell .part.editor .iframe-container,
.monaco-shell .part.editor .binary-container {
outline: 0 !important;
}
......
......@@ -17,9 +17,7 @@ import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor';
import {LocalFileChangeEvent, TextFileChangeEvent, VIEWLET_ID, BINARY_FILE_EDITOR_ID, EventType as FileEventType, ITextFileService, AutoSaveMode, ModelState} from 'vs/workbench/parts/files/common/files';
import {FileChangeType, FileChangesEvent, EventType as CommonFileEventType} from 'vs/platform/files/common/files';
import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput';
import {IFrameEditorInput} from 'vs/workbench/common/editor/iframeEditorInput';
import {TextFileEditorModel, CACHE} from 'vs/workbench/parts/files/common/editors/textFileEditorModel';
import {IFrameEditor} from 'vs/workbench/browser/parts/editor/iframeEditor';
import {EventType as WorkbenchEventType, UntitledEditorEvent} from 'vs/workbench/common/events';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
......@@ -228,14 +226,6 @@ export class FileTracker implements IWorkbenchContribution {
}
}
}
// IFrame Editor Input
else if (input instanceof IFrameEditorInput) {
let iFrameInput = <IFrameEditorInput>input;
if (e.contains(iFrameInput.getResource(), FileChangeType.UPDATED)) {
(<IFrameEditor>editor).reload();
}
}
});
}
......@@ -273,8 +263,6 @@ export class FileTracker implements IWorkbenchContribution {
let inputResource: URI;
if (input instanceof FileEditorInput) {
inputResource = (<FileEditorInput>input).getResource();
} else if (input instanceof IFrameEditorInput) {
inputResource = (<IFrameEditorInput>input).getResource();
}
// Editor Input with associated Resource
......@@ -306,16 +294,6 @@ export class FileTracker implements IWorkbenchContribution {
// Reopen File Input
if (input instanceof FileEditorInput) {
editorInput = this.instantiationService.createInstance(FileEditorInput, reopenFileResource, mimeHint || MIME_UNKNOWN, void 0);
}
// Reopen IFrame Input
else if (input instanceof IFrameEditorInput) {
let iFrameInput = <IFrameEditorInput>input;
editorInput = iFrameInput.createNew(reopenFileResource);
}
if (editorInput) {
this.editorService.openEditor(editorInput, editorOptions, editor.position).done(null, errors.onUnexpectedError);
}
}
......@@ -381,11 +359,6 @@ export class FileTracker implements IWorkbenchContribution {
else if (input instanceof FileEditorInput && this.containsResource(<FileEditorInput>input, resource)) {
inputsContainingPath.push(<FileEditorInput>input);
}
// IFrame Input
else if (input instanceof IFrameEditorInput && this.containsResource(<IFrameEditorInput>input, resource)) {
inputsContainingPath.push(<IFrameEditorInput>input);
}
});
inputsContainingPath.forEach((input) => {
......@@ -404,13 +377,10 @@ export class FileTracker implements IWorkbenchContribution {
}
private containsResource(input: FileEditorInput, resource: URI): boolean;
private containsResource(input: IFrameEditorInput, resource: URI): boolean;
private containsResource(input: EditorInput, resource: URI): boolean {
let fileResource: URI;
if (input instanceof FileEditorInput) {
fileResource = (<FileEditorInput>input).getResource();
} else {
fileResource = (<IFrameEditorInput>input).getResource();
}
if (paths.isEqualOrParent(fileResource.fsPath, resource.fsPath)) {
......@@ -452,18 +422,6 @@ export class FileTracker implements IWorkbenchContribution {
return false; // never dispose unsaved models
}
if (this.editorService.getVisibleEditors().some(e => {
if (e.input instanceof IFrameEditorInput) {
let iFrameInputResource = (<IFrameEditorInput>e.input).getResource();
return iFrameInputResource && iFrameInputResource.toString() === textModel.getResource().toString();
}
return false;
})) {
return false; // never dispose models that are used in iframe inputs
}
return true;
}
......
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#656565" points="10,2 7.414,2 8.414,3 9,3 9,3.586 9,4 9,4.414 9,6 12,6 12,13 4,13 4,8 3,8 3,14 13,14 13,5"/><polygon fill="#00539C" points="5,1 3,1 5,3 1,3 1,5 5,5 3,7 5,7 8,4"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#C5C5C5" points="10,2 7.414,2 8.414,3 9,3 9,3.586 9,4 9,4.414 9,6 12,6 12,13 4,13 4,8 3,8 3,14 13,14 13,5"/><polygon fill="#75BEFF" points="5,1 3,1 5,3 1,3 1,5 5,5 3,7 5,7 8,4"/></svg>
\ No newline at end of file
......@@ -75,22 +75,6 @@
background: url('Preview_inverse.svg') center center no-repeat;
}
.monaco-workbench .iframe-editor-action.view-source {
background: url('ViewSource.svg') center center no-repeat;
}
.vs-dark .monaco-workbench .iframe-editor-action.view-source {
background: url('ViewSource_inverse.svg') center center no-repeat;
}
.monaco-workbench .iframe-editor-action.refresh {
background: url('Refresh.svg') center center no-repeat;
}
.vs-dark .monaco-workbench .iframe-editor-action.refresh {
background: url('Refresh_inverse.svg') center center no-repeat;
}
.explorer-viewlet .explorer-open-editors .close-editor-action {
background: url("action-close.svg") center center no-repeat;
}
......@@ -122,7 +106,6 @@
/* High Contrast Theming */
.hc-black .monaco-workbench .explorer-action,
.hc-black .monaco-workbench .quick-open-sidebyside,
.hc-black .monaco-workbench .iframe-editor-action,
.hc-black .monaco-workbench .file-editor-action.action-open-preview {
background: none;
}
......@@ -155,14 +138,6 @@
content: url('SplitEditor_inverse.svg');
}
.hc-black .monaco-workbench .iframe-editor-action.view-source:before {
content: url('ViewSource_inverse.svg');
}
.hc-black .monaco-workbench .iframe-editor-action.refresh:before {
content: url('Refresh_inverse.svg');
}
.hc-black .monaco-workbench .file-editor-action.action-open-preview:before {
content: url('Preview_inverse.svg');
}
......
......@@ -495,7 +495,7 @@ export class DragAndDrop extends treedefaults.DefaultDragAndDrop {
}
const resource = element.getResource();
// Some open editors do not have a resource (markdown preview) so use the name as drag identifier instead #7021
// Some open editors do not have a resource so use the name as drag identifier instead #7021
return resource ? resource.toString() : element.editorInput.getName();
}
......
......@@ -24,7 +24,7 @@ import {IOpenerService} from 'vs/platform/opener/common/opener';
import Webview from './webview';
/**
* An implementation of editor for showing HTML content in an IFrame by leveraging the IFrameEditorInput.
* An implementation of editor for showing HTML content in an IFrame by leveraging the HTML input.
*/
export class HtmlPreviewPart extends BaseEditor {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Registry} from 'vs/platform/platform';
import URI from 'vs/base/common/uri';
import {IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory} from 'vs/workbench/browser/parts/editor/baseEditor';
import {EditorInput} from 'vs/workbench/common/editor';
import {MarkdownEditorInput} from 'vs/workbench/parts/markdown/common/markdownEditorInput';
import {MarkdownFileTracker} from 'vs/workbench/parts/markdown/browser/markdownExtension';
import {IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions} from 'vs/workbench/common/contributions';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
// Register Editor Input Factory
class MarkdownInputFactory implements IEditorInputFactory {
constructor() {}
public serialize(editorInput: EditorInput): string {
let markdownInput = <MarkdownEditorInput>editorInput;
return markdownInput.getResource().toString();
}
public deserialize(instantiationService: IInstantiationService, resourceRaw: string): EditorInput {
return instantiationService.createInstance(MarkdownEditorInput, URI.parse(resourceRaw), void 0, void 0);
}
}
(<IEditorRegistry>Registry.as(EditorExtensions.Editors)).registerEditorInputFactory(MarkdownEditorInput.ID, MarkdownInputFactory);
// Register Markdown File Tracker
(<IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution(
MarkdownFileTracker
);
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import {Registry} from 'vs/platform/platform';
import {IAction} from 'vs/base/common/actions';
import {SyncActionDescriptor} from 'vs/platform/actions/common/actions';
import {Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor} from 'vs/workbench/browser/actionBarRegistry';
import {asFileResource, FileEditorInput} from 'vs/workbench/parts/files/common/files';
import mime = require('vs/base/common/mime');
import {IEditorInputActionContext, IEditorInputAction, EditorInputActionContributor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {OpenPreviewToSideAction, GlobalTogglePreviewMarkdownAction, PreviewMarkdownEditorInputAction, PreviewMarkdownAction} from 'vs/workbench/parts/markdown/browser/markdownActions';
import {MARKDOWN_MIME} from 'vs/workbench/parts/markdown/common/markdown';
import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
class ExplorerViewerActionContributor extends ActionBarContributor {
constructor(@IInstantiationService private instantiationService: IInstantiationService) {
super();
}
public hasSecondaryActions(context: any): boolean {
let element = context.element;
// Contribute only on file resources
let fileResource = asFileResource(element);
if (!fileResource) {
return false;
}
return !fileResource.isDirectory && mime.guessMimeTypes(fileResource.resource.fsPath).indexOf(MARKDOWN_MIME) >= 0;
}
public getSecondaryActions(context: any): IAction[] {
let actions: IAction[] = [];
if (this.hasSecondaryActions(context)) {
let fileResource = asFileResource(context.element);
// Open Markdown
let action = this.instantiationService.createInstance(PreviewMarkdownAction, fileResource.resource);
action.order = 0; // on top of other actions
actions.push(action);
}
return actions;
}
}
class MarkdownFilesActionContributor extends EditorInputActionContributor {
constructor(@IInstantiationService private instantiationService: IInstantiationService) {
super();
}
/* We override toId() to make the caching of actions based on the mime of the input if given */
protected toId(context: IEditorInputActionContext): string {
let id = super.toId(context);
let mime = this.getMimeFromContext(context);
if (mime) {
id += mime;
}
return id;
}
private getMimeFromContext(context: IEditorInputActionContext): string {
if (context && context.input && context.input instanceof FileEditorInput) {
let fileInput = <FileEditorInput>context.input;
return fileInput.getMime();
}
return null;
}
public hasActionsForEditorInput(context: IEditorInputActionContext): boolean {
const input = context.input;
if (input instanceof FileEditorInput) {
const fileResource = input.getResource();
return mime.guessMimeTypes(fileResource.fsPath).indexOf(MARKDOWN_MIME) >= 0;
}
return false;
}
public getActionsForEditorInput(context: IEditorInputActionContext): IEditorInputAction[] {
if (this.hasActionsForEditorInput(context)) {
return [
this.instantiationService.createInstance(PreviewMarkdownEditorInputAction)
];
}
return [];
}
}
// Contribute to viewers and editors of markdown files
let actionBarRegistry = <IActionBarRegistry>Registry.as(ActionBarExtensions.Actionbar);
actionBarRegistry.registerActionBarContributor(Scope.VIEWER, ExplorerViewerActionContributor);
actionBarRegistry.registerActionBarContributor(Scope.EDITOR, MarkdownFilesActionContributor);
let category = nls.localize('markdown', "Markdown");
let workbenchActionsRegistry = <IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalTogglePreviewMarkdownAction, GlobalTogglePreviewMarkdownAction.ID, GlobalTogglePreviewMarkdownAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }), 'Markdown: Toggle Preview', category);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviewToSideAction, OpenPreviewToSideAction.ID, OpenPreviewToSideAction.LABEL, { primary: KeyMod.chord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_V) }), 'Markdown: Open Preview to the Side', category);
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/markdownactions';
import {TPromise} from 'vs/base/common/winjs.base';
import {Action} from 'vs/base/common/actions';
import URI from 'vs/base/common/uri';
import errors = require('vs/base/common/errors');
import nls = require('vs/nls');
import {FileEditorInput} from 'vs/workbench/parts/files/common/files';
import {EditorInputAction} from 'vs/workbench/browser/parts/editor/baseEditor';
import {getUntitledOrFileResource, IEditorContext} from 'vs/workbench/common/editor';
import {MarkdownEditorInput} from 'vs/workbench/parts/markdown/common/markdownEditorInput';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IMessageService, Severity} from 'vs/platform/message/common/message';
export class GlobalTogglePreviewMarkdownAction extends Action {
public static ID = 'workbench.action.markdown.togglePreview';
public static LABEL = nls.localize('toggleMarkdownPreview', "Toggle Preview");
constructor(
id: string,
label: string,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IMessageService private messageService: IMessageService
) {
super(id, label);
}
public run(event?: any): TPromise<any> {
let activeInput = this.editorService.getActiveEditorInput();
// View source if we are in a markdown file already
if (activeInput instanceof MarkdownEditorInput) {
this.editorService.openEditor({
resource: activeInput.getResource()
}).done(null, errors.onUnexpectedError);
}
// Otherwise try to open as markdown preview
else {
let msg: string;
let resource = getUntitledOrFileResource(activeInput);
if (resource) {
let action = this.instantiationService.createInstance(PreviewMarkdownAction, resource);
action.run().done(() => action.dispose(), errors.onUnexpectedError);
} else {
msg = nls.localize('markdownPreviewNoFile', "Open a Markdown file first to show a preview.");
}
if (msg) {
this.messageService.show(Severity.Info, msg);
}
}
return TPromise.as(true);
}
}
export class OpenPreviewToSideAction extends Action {
public static ID = 'workbench.action.markdown.openPreviewSideBySide';
public static LABEL = nls.localize('openPreviewSideBySide', "Open Preview to the Side");
constructor(
id: string,
label: string,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IMessageService private messageService: IMessageService
) {
super(id, label);
}
public run(context?: IEditorContext): TPromise<any> {
let activeInput = this.editorService.getActiveEditorInput();
// Do nothing if already in markdown preview
if (activeInput instanceof MarkdownEditorInput) {
return TPromise.as(true);
}
// Otherwise try to open as markdown preview to the side
else {
let msg: string;
let resource = getUntitledOrFileResource(activeInput);
if (resource) {
let input = this.instantiationService.createInstance(MarkdownEditorInput, resource, void 0, void 0);
return this.editorService.openEditor(input, null, true /* to the side */);
} else {
msg = nls.localize('markdownPreviewNoFile', "Open a Markdown file first to show a preview.");
}
if (msg) {
this.messageService.show(Severity.Info, msg);
}
}
return TPromise.as(true);
}
}
export class PreviewMarkdownAction extends Action {
private markdownResource: URI;
constructor(
markdownResource: URI,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
super('workbench.markdown.action.previewFromExplorer', nls.localize('openPreview', "Open Preview"));
this.markdownResource = markdownResource;
}
public run(context?: IEditorContext): TPromise<any> {
let input = this.instantiationService.createInstance(MarkdownEditorInput, this.markdownResource, void 0, void 0);
return this.editorService.openEditor(input);
}
}
export class PreviewMarkdownEditorInputAction extends EditorInputAction {
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
super('workbench.markdown.action.previewFromEditor', nls.localize('openPreview', "Open Preview"));
this.class = 'markdown-action action-preview';
this.order = 100; // far end
}
public run(context: IEditorContext): TPromise<any> {
let input = <FileEditorInput>this.input;
const event = context ? context.event : null;
let sideBySide = !!(event && (event.ctrlKey || event.metaKey));
let markdownInput = this.instantiationService.createInstance(MarkdownEditorInput, input.getResource(), void 0, void 0);
return this.editorService.openEditor(markdownInput, null, sideBySide);
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import types = require('vs/base/common/types');
import URI from 'vs/base/common/uri';
import {EventType} from 'vs/base/common/events';
import {FileChangeType, FileChangesEvent, EventType as FileEventType} from 'vs/platform/files/common/files';
import paths = require('vs/base/common/paths');
import {getBaseThemeId} from 'vs/platform/theme/common/themes';
import {IWorkbenchContribution} from 'vs/workbench/common/contributions';
import {IFrameEditor} from 'vs/workbench/browser/parts/editor/iframeEditor';
import {MarkdownEditorInput} from 'vs/workbench/parts/markdown/common/markdownEditorInput';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
import {IConfigurationService, IConfigurationServiceEvent} from 'vs/platform/configuration/common/configuration';
import {IModelService} from 'vs/editor/common/services/modelService';
import {IEventService} from 'vs/platform/event/common/event';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IModeService} from 'vs/editor/common/services/modeService';
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
interface ILanguageConfiguration {
markdown: {
styles: string[];
};
}
// This extension tracks markdown files for changes to update markdown editors and inputs accordingly.
export class MarkdownFileTracker implements IWorkbenchContribution {
private static RELOAD_MARKDOWN_DELAY = 300; // delay before reloading markdown preview after user typing
private fileChangeListener: IDisposable;
private configFileChangeListener: IDisposable;
private themeChangeListener: IDisposable;
private editorInputChangeListener: IDisposable;
private markdownConfigurationThumbprint: string;
private markdownConfigurationPaths: string[];
private reloadTimeout: number;
private hasModelListenerOnResourcePath: { [resource: string]: boolean; };
constructor(
@IModeService private modeService: IModeService,
@IEventService private eventService: IEventService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@IConfigurationService private configurationService: IConfigurationService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IModelService private modelService: IModelService,
@IInstantiationService private instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService
) {
this.markdownConfigurationPaths = [];
this.hasModelListenerOnResourcePath = Object.create(null);
this.configureMode(themeService.getTheme());
this.registerListeners();
}
private registerListeners(): void {
this.fileChangeListener = this.eventService.addListener2(FileEventType.FILE_CHANGES, (e: FileChangesEvent) => this.onFileChanges(e));
this.configFileChangeListener = this.configurationService.onDidUpdateConfiguration(e => this.onConfigFileChange(e));
// reload markdown editors when their resources change
this.editorInputChangeListener = this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged());
// initially read the config for CSS styles in preview
this.readMarkdownConfiguration(this.configurationService.getConfiguration<ILanguageConfiguration>());
// listen to theme changes
this.themeChangeListener = this.themeService.onDidThemeChange(themeId => {
this.configureMode(themeId);
this.reloadMarkdownEditors(true);
});
}
private onEditorsChanged(): void {
let input = this.editorService.getActiveEditorInput();
if (input instanceof MarkdownEditorInput) {
let markdownResource = input.getResource();
let editorModel = this.modelService.getModel(markdownResource);
if (editorModel && !this.hasModelListenerOnResourcePath[markdownResource.toString()]) {
let toUnbind: IDisposable[] = [];
let unbind = () => {
toUnbind = dispose(toUnbind);
this.hasModelListenerOnResourcePath[markdownResource.toString()] = false;
};
// Listen on changes to the underlying resource of the markdown preview
toUnbind.push(editorModel.onDidChangeContent(() => {
if (this.reloadTimeout) {
window.clearTimeout(this.reloadTimeout);
}
this.reloadTimeout = setTimeout(() => {
if (!this.reloadMarkdownEditors(false, markdownResource)) {
unbind();
}
}, MarkdownFileTracker.RELOAD_MARKDOWN_DELAY);
}));
// Mark as being listened
this.hasModelListenerOnResourcePath[markdownResource.toString()] = true;
// Unbind when input or model gets disposed
toUnbind.push(input.addListener2(EventType.DISPOSE, unbind));
toUnbind.push(editorModel.onWillDispose(unbind));
}
}
}
private configureMode(theme: string): void {
if (theme) {
let baseTheme = getBaseThemeId(theme);
this.modeService.configureMode('text/x-web-markdown', { theme: baseTheme });
}
}
public getId(): string {
return 'vs.markdown.filetracker';
}
private onConfigFileChange(e: IConfigurationServiceEvent): void {
// reload markdown editors if styles change
if (this.readMarkdownConfiguration(e.config)) {
this.reloadMarkdownEditors(true);
}
}
private readMarkdownConfiguration(languageConfiguration: ILanguageConfiguration): boolean {
let oldMarkdownConfigurationThumbprint = this.markdownConfigurationThumbprint;
let newMarkdownConfigurationThumbprint: string;
// Reset old
this.markdownConfigurationThumbprint = null;
this.markdownConfigurationPaths = [];
if (languageConfiguration) {
let markdownConfiguration = languageConfiguration.markdown;
if (markdownConfiguration && types.isArray(markdownConfiguration.styles)) {
newMarkdownConfigurationThumbprint = markdownConfiguration.styles.join('');
let styles: string[] = markdownConfiguration.styles.map((style: string) => paths.makePosixAbsolute(paths.normalize(style)));
this.markdownConfigurationPaths = styles;
}
}
// Remember as current
this.markdownConfigurationThumbprint = newMarkdownConfigurationThumbprint;
return (oldMarkdownConfigurationThumbprint !== newMarkdownConfigurationThumbprint);
}
private onFileChanges(e: FileChangesEvent): void {
// If any of the markdown CSS styles have updated, reload all markdown editors
if (this.markdownConfigurationPaths.length && e.containsAny(this.markdownConfigurationPaths.map((p) => this.contextService.toResource(p)), FileChangeType.UPDATED)) {
this.reloadMarkdownEditors(true);
}
}
private reloadMarkdownEditors(clearIFrame: boolean, resource?: URI): boolean {
let didReload = false;
let editors = this.editorService.getVisibleEditors();
editors.forEach((editor) => {
// Only applicable to markdown editor inputs in iframe editors
let input = editor.input;
if (input instanceof MarkdownEditorInput && editor instanceof IFrameEditor) {
if (!resource || resource.toString() === input.getResource().toString()) {
(<IFrameEditor>editor).reload(clearIFrame);
didReload = true;
}
}
});
return didReload;
}
public dispose(): void {
if (this.fileChangeListener) {
this.fileChangeListener.dispose();
this.fileChangeListener = null;
}
if (this.configFileChangeListener) {
this.configFileChangeListener.dispose();
this.configFileChangeListener = null;
}
if (this.editorInputChangeListener) {
this.editorInputChangeListener.dispose();
this.editorInputChangeListener = null;
}
}
}
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0.414 0 16 16" enable-background="new 0.414 0 16 16"><path fill="#F6F6F6" d="M12.363 4c-.252-2.244-2.139-4-4.449-4-2.481 0-4.5 2.019-4.5 4.5 0 .6.12 1.188.35 1.735l-3.764 3.765 2.414 2.414 3-2.999v6.585h11v-12h-4.051z"/><rect x="12.414" y="10" fill="#424242" width="1" height="3"/><rect x="10.414" y="11" fill="#424242" width="1" height="2"/><rect x="8.414" y="12" fill="#424242" width="1" height="1"/><rect x="8.414" y="9" fill="#424242" width="2" height="1"/><path fill="#424242" d="M12.363 5c-.039.347-.112.681-.226 1h2.276v8h-7v-5.05c-.342-.039-.676-.112-1-.228v6.278h9v-10h-3.05z"/><path fill="#424242" d="M10.708 8h1.706v-1h-.762c-.257.384-.585.712-.944 1z"/><path fill="#424242" d="M11.414 4.5c0-1.933-1.567-3.5-3.5-3.5s-3.5 1.567-3.5 3.5c0 .711.215 1.369.579 1.922l-3.579 3.578 1 1 3.579-3.578c.552.363 1.211.578 1.921.578 1.933 0 3.5-1.567 3.5-3.5zm-5.999 0c0-1.381 1.119-2.5 2.5-2.5s2.5 1.119 2.5 2.5-1.12 2.5-2.5 2.5-2.5-1.119-2.5-2.5z"/><path fill="#F0EFF1" d="M12.138 6c-.126.354-.279.693-.485 1h.762v1h-1.706c-.771.616-1.734 1-2.795 1-.169 0-.333-.031-.5-.05v5.05h7v-8h-2.276zm-3.724 3h2v1h-2v-1zm1 4h-1v-1h1v1zm2 0h-1v-2h1v2zm2 0h-1v-3h1v3z"/><circle fill="#F0EFF1" cx="7.914" cy="4.5" r="2.5"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0.414 0 16 16" enable-background="new 0.414 0 16 16"><path fill="#252626" d="M12.363 4c-.252-2.244-2.139-4-4.449-4-2.481 0-4.5 2.019-4.5 4.5 0 .6.12 1.188.35 1.735l-3.764 3.765 2.414 2.414 3-2.999v6.585h11v-12h-4.051z"/><rect x="12.414" y="10" fill="#C5C5C5" width="1" height="3"/><rect x="10.414" y="11" fill="#C5C5C5" width="1" height="2"/><rect x="8.414" y="12" fill="#C5C5C5" width="1" height="1"/><rect x="8.414" y="9" fill="#C5C5C5" width="2" height="1"/><path fill="#C5C5C5" d="M12.363 5c-.039.347-.112.681-.226 1h2.276v8h-7v-5.05c-.342-.039-.676-.112-1-.228v6.278h9v-10h-3.05z"/><path fill="#C5C5C5" d="M10.708 8h1.706v-1h-.762c-.257.384-.585.712-.944 1z"/><path fill="#C5C5C5" d="M11.414 4.5c0-1.933-1.567-3.5-3.5-3.5s-3.5 1.567-3.5 3.5c0 .711.215 1.369.579 1.922l-3.579 3.578 1 1 3.579-3.578c.552.363 1.211.578 1.921.578 1.933 0 3.5-1.567 3.5-3.5zm-5.999 0c0-1.381 1.119-2.5 2.5-2.5s2.5 1.119 2.5 2.5-1.12 2.5-2.5 2.5-2.5-1.119-2.5-2.5z"/><path fill="#2B282E" d="M12.138 6c-.126.354-.279.693-.485 1h.762v1h-1.706c-.771.616-1.734 1-2.795 1-.169 0-.333-.031-.5-.05v5.05h7v-8h-2.276zm-3.724 3h2v1h-2v-1zm1 4h-1v-1h1v1zm2 0h-1v-2h1v2zm2 0h-1v-3h1v3z"/><circle fill="#2B282E" cx="7.914" cy="4.5" r="2.5"/></svg>
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Editor Actions */
.vs .monaco-workbench .markdown-action.action-preview {
background: url('Preview.svg') center center no-repeat;
}
.vs-dark .monaco-workbench .markdown-action.action-preview {
background: url('Preview_inverse.svg') center center no-repeat;
}
/* High Contrast Theming */
.hc-black .monaco-workbench .markdown-action.action-preview,
.hc-black .monaco-workbench .markdown-action.view-source,
.hc-black .monaco-workbench .markdown-action.refresh {
background: none;
}
.hc-black .monaco-workbench .markdown-action.action-preview:before,
.hc-black .monaco-workbench .markdown-action.view-source:before,
.hc-black .monaco-workbench .markdown-action.refresh:before {
position: absolute;
top: 12px;
left: 8px;
height: 16px;
width: 16px;
}
.hc-black .monaco-workbench .markdown-action.action-preview:before {
content: url('Preview_inverse.svg');
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export const MARKDOWN_MIME = 'text/x-web-markdown';
export const MARKDOWN_MODE_ID = 'markdown';
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import URI from 'vs/base/common/uri';
import paths = require('vs/base/common/paths');
import labels = require('vs/base/common/labels');
import {IFrameEditorInput} from 'vs/workbench/common/editor/iframeEditorInput';
import {MarkdownEditorModel} from 'vs/workbench/parts/markdown/common/markdownEditorModel';
import {EditorModel} from 'vs/workbench/common/editor';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
/**
* An editor input to show a rendered version of a markdown file.
*/
export class MarkdownEditorInput extends IFrameEditorInput {
public static ID: string = 'vs.markdown';
constructor(
resource: URI,
label: string,
description: string,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
) {
super(resource, label || nls.localize('preview', "Preview '{0}'", paths.basename(resource.fsPath)), description || labels.getPathLabel(paths.dirname(resource.fsPath), contextService));
}
public createNew(resource: URI): MarkdownEditorInput {
return this.instantiationService.createInstance(MarkdownEditorInput, resource, void 0, void 0);
}
public getTypeId(): string {
return MarkdownEditorInput.ID;
}
protected createModel(): EditorModel {
return this.instantiationService.createInstance(MarkdownEditorModel, this.getResource());
}
public matches(otherInput: any): boolean {
if (!(otherInput instanceof MarkdownEditorInput)) {
return false;
}
return super.matches(otherInput);
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import nls = require('vs/nls');
import URI from 'vs/base/common/uri';
import paths = require('vs/base/common/paths');
import {IFrameEditorModel} from 'vs/workbench/common/editor/iframeEditorModel';
import {EditorModel} from 'vs/workbench/common/editor';
import {IModel} from 'vs/editor/common/editorCommon';
import {IEmitOutput} from 'vs/editor/common/modes';
import {isLightTheme} from 'vs/platform/theme/common/themes';
import {MARKDOWN_MIME, MARKDOWN_MODE_ID} from 'vs/workbench/parts/markdown/common/markdown';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
interface IMarkdownWorkerOutput extends IEmitOutput {
head: string;
body: string;
tail: string;
}
/**
* The editor model for markdown inputs. Using a library to convert markdown text into HTML from a resource with the provided path.
*/
export class MarkdownEditorModel extends IFrameEditorModel {
constructor(
resource: URI,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IThemeService private themeService: IThemeService
) {
super(resource);
}
public load(): TPromise<EditorModel> {
let isCanceled = false;
let codeEditorModel: IModel;
// Create a new promise here to be able to return this model even in case of an error
return new TPromise<EditorModel>((c, e) => {
// On Error: Show error to user as rendered HTML
let onError = (error: Error) => {
try {
let theme = this.themeService.getTheme();
let usesLightTheme = isLightTheme(theme);
let markdownError = nls.localize('markdownError', "Unable to open '{0}' for Markdown rendering. Please make sure the file exists and that it is a valid Markdown file.", paths.basename(this.resource.fsPath));
this.setContents('<html><head><style type="text/css">body {color: ' + (usesLightTheme ? 'black' : 'white') + '; font-family: "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback"; font-size: 13px; margin: 0; line-height: 1.4em; padding-left: 20px;}</style></head><body>', markdownError, '</body></html>');
c(this);
} catch (error) {
e(error); // be very careful that this promise always completes
}
};
// On Success: Show output as rendered HTML
let onSuccess = (model: IModel) => {
try {
let mode = model.getMode();
let absoluteWorkerResourcesPath = require.toUrl('vs/languages/markdown/common'); // TODO@Ben technical debt: worker cannot resolve path absolute
if (mode && !!mode.emitOutputSupport && mode.getId() === MARKDOWN_MODE_ID) {
(<any>mode).emitOutputSupport.getEmitOutput(this.resource, absoluteWorkerResourcesPath).then((output: IMarkdownWorkerOutput) => {
this.setContents(output.head, output.body, output.tail);
c(this);
}, onError);
} else {
onError(null); // mode does not support output
}
} catch (error) {
onError(error); // be very careful that this promise always completes
}
};
// Resolve the text editor model using editor service to benefit from the local editor model cache
this.editorService.resolveEditorModel({
resource: this.resource,
mime: MARKDOWN_MIME
}).then((model) => {
if (isCanceled) {
return;
}
codeEditorModel = <IModel>model.textEditorModel;
return codeEditorModel.whenModeIsReady();
}).then(() => {
if (isCanceled) {
return;
}
onSuccess(codeEditorModel);
}, onError);
}, () => {
isCanceled = true;
});
}
}
\ No newline at end of file
......@@ -50,9 +50,6 @@ import 'vs/workbench/parts/output/browser/output.contribution';
import 'vs/workbench/parts/terminal/electron-browser/terminal.contribution';
// import 'vs/workbench/parts/markdown/browser/markdown.contribution';
// import 'vs/workbench/parts/markdown/browser/markdownActions.contribution';
import 'vs/workbench/browser/workbench';
import 'vs/workbench/parts/tasks/electron-browser/task.contribution';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册