Skip to content

Commit

Permalink
Fixes #3 Support multiple editor instances (#4)
Browse files Browse the repository at this point in the history
* Fixes #3 Support multiple editor instances

* Add typescribe library support

* Use theme if set initially
  • Loading branch information
anandanand84 authored and eterna2 committed Jan 17, 2018
1 parent bd6c398 commit 3fd6ece
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 8 deletions.
69 changes: 69 additions & 0 deletions demo/multiple-editors-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

<title>monaco-editor demo</title>

<script src="../../webcomponentsjs/webcomponents-lite.js"></script>

<link rel="import" href="../../polymer/lib/elements/dom-bind.html">
<link rel="import" href="../../polymer/lib/utils/import-href.html">
<link rel="import" href="../../polymer/lib/elements/custom-style.html">
<link rel="import" href="../../iron-flex-layout/iron-flex-layout-classes.html">

<link rel="import" href="multiple-editors.html">

<custom-style>
<style is="custom-style" include="iron-flex iron-flex-alignment">
body {
padding: 5px;
margin: 0px;
font-family: verdana;
}

monaco-editor {
height: 90vh;
width: 100%;
min-width: 520px;
min-height: 400px;
}

.error {
font-size: 0.7em;
color: #E91E63;
}

button {
background-color: #4CAF50;
border: none;
color: white;
margin: 3px;
padding: 5px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
}
button.off {
background-color: #888;
}

</style>
</custom-style>
</head>

<body>

<dom-bind id="demo">
<template>
<multiple-editors></multiple-editors>
</template>
</dom-bind>

<script>
</script>

</body>
</html>
73 changes: 73 additions & 0 deletions demo/multiple-editors.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<link rel="import" href="../../polymer/polymer-element.html">
<link rel="import" href="../../paper-button/paper-button.html">
<link rel="import" href="../monaco-editor.html">
<link rel="import" href="../monaco-schemas.html">
<dom-module id="multiple-editors">
<template>
<monaco-editor
folding
minimap
id="monacoeditor1"
name="editor"
theme="vs-dark"
language="typescript"
value="{{_content1}}"></monaco-editor>
<monaco-editor
id="monacoeditor2"
folding
minimap
name="editor"
theme="vs-dark"
language="typescript"
value="{{_content2}}"></monaco-editor>
</template>

<script>
class MultipleEditors extends Polymer.Element {

static get is() {
return 'multiple-editors';
}

static get properties() {
return {
_content1: {
type: String,
value: 'Hello World',
observer: '_onContent1Changed'
},

_content2: {
type: String,
value: 'Hello Moon',
observer: '_onContent2Changed'
}
}
}

/**
* Called every time the element is inserted into the DOM. Useful for
* running setup code, such as fetching resources or rendering.
* Generally, you should try to delay work until this time.
*/
connectedCallback() {
super.connectedCallback();
setTimeout(()=> {
this.$.monacoeditor2.monaco.editor.addTypeScriptLibs([
{url : 'https://cdn.rawgit.com/Microsoft/TypeScript/64b3086f/lib/lib.es6.d.ts', name : 'es6.d.ts'}
])
}, 100)
}

_onContent1Changed() {
console.log(`Content 1 changed: ${this._content1}`);
}

_onContent2Changed() {
console.log(`Content 2 changed: ${this._content2}`);
}
}

customElements.define(MultipleEditors.is, MultipleEditors);
</script>
</dom-module>
3 changes: 3 additions & 0 deletions monaco-editor-iframe.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
width: 100%;
height: 100%;
}
html,body {
margin : 0px;
}
</style>
</head>

Expand Down
112 changes: 106 additions & 6 deletions monaco-editor-iframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
PolymerVis.monaco = PolymerVis.monaco || {};

class MonacoProxy {
constructor(iframe) {
constructor(iframe, editorReference) {
this._iframe_ = iframe;
this._editorReference_ = editorReference;
this.languages.json.jsonDefaults.setDiagnosticsOptions;
}
get languages() {
Expand All @@ -22,6 +23,7 @@
};
}
postMessage(msg) {
msg.editorReference = this._editorReference_;
this._iframe_.contentWindow.postMessage(msg, document.location.href);
}
get editor() {
Expand All @@ -46,17 +48,42 @@
event: 'setTheme',
args: [theme]
});
},
highlightLine: (debugInfo) => {
if(debugInfo){
this.postMessage({
path: ['monaco', 'editor'],
event: 'highlightLine',
args: [debugInfo]
})
}
},
removeHighlights: () => {
this.postMessage({
path: ['monaco', 'editor'],
event: 'removeHighlights',
args: []
})
},
addTypeScriptLibs: (libs) => {
this.postMessage({
path: ['monaco', 'editor'],
event: 'addLibs',
args: [libs]
})
}
};
}
}
}

class EditorProxy {
constructor(iframe) {
constructor(iframe, editorReference) {
this._iframe_ = iframe;
this._editorReference_ = editorReference;
}

postMessage(msg) {
msg.editorReference = this._editorReference_;
this._iframe_.contentWindow.postMessage(msg, document.location.href);
}

Expand Down Expand Up @@ -133,17 +160,44 @@
this.document.head.appendChild(ele);
}

insertStyle() {
var css = `#editor {
width: 100%;
height: 100%;
}
.debug-red {
background : red;
}
.debug-green {
background : green;
}
html,body {
margin : 0px;
}`;
var head = this.document.head;
var style = this.document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(this.document.createTextNode(css));
}
head.appendChild(style);
}

init(libPath, opts) {
this.insertScriptElement({
src: `${libPath}/loader.js`,
onload: () => {
this.insertScriptElement({text: this.loaderOnLoad(libPath, opts)});
this.insertStyle();
}
});
}

loaderOnLoad(libPath, opts = {}) {
return `
var editorReference = "${opts.editorReference}"
var proxy = {};
var queue = [];
Expand All @@ -155,19 +209,39 @@
proxy.monaco = monaco;
var div = document.querySelector('#editor')
proxy.editor = monaco.editor.create(div, ${JSON.stringify(opts)});
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2017,
allowNonTsExtensions: true,
noLib: true
});
// [
// {url : 'https://cdn.rawgit.com/Microsoft/TypeScript/64b3086f/lib/lib.es6.d.ts', name : 'es6.d.ts'},
// {url : 'https://cdn.rawgit.com/anandanand84/technicalindicators/235ff767/declarations/generated.d.ts', name : 'Indicators.d.ts', convert : true}
// ]
proxy.model = proxy.editor.getModel();
proxy.model.onDidChangeContent(() => {
parent.postMessage({event: 'value-changed', details: proxy.model.getValue()}, parent.document.location.href);
parent.postMessage({editorReference: editorReference, event: 'value-changed', details: proxy.model.getValue()}, parent.document.location.href);
});
proxy.editor.onDidFocusEditor(() => {
parent.postMessage({event: 'editor-focused'}, parent.document.location.href);
parent.postMessage({editorReference: editorReference, event: 'editor-focused'}, parent.document.location.href);
});
queue.forEach(e => handler(e));
queue = [];
parent.postMessage({ready: true}, parent.document.location.href);
parent.postMessage({editorReference: editorReference, ready: true}, parent.document.location.href);
resizeHandler();
});
async function loadLibs(libs) {
for(let lib of libs) {
var response = await fetch(lib.url)
var types = await response.text();
if(lib.convert)
types = types.replace(new RegExp('default ', 'g'), '').split('export').join('declare');
monaco.languages.typescript.typescriptDefaults.addExtraLib(types, lib.name);
console.log('Added lib ', lib.name);
}
}
var resizeHandler = ()=> {
if(proxy.editor) {
var clientRects = document.body.getClientRects()[0]
Expand All @@ -190,6 +264,32 @@
proxy.editor.getModel().setValue(args[0]);
return;
}
if(event === 'highlightLine') {
proxy.editor.decorationList = [];
var debugInfo = args[0];
Object.keys(debugInfo).forEach(function (line) {
var lineNo = line - 2;
var status = debugInfo[line] === 0 ? 'debug-red' : 'debug-green';
proxy.editor.decorationList.push({
range: new monaco.Range(lineNo,1,lineNo,1),
options: {
isWholeLine: true,
className: status,
}
});
})
proxy.editor.lastDecorations = proxy.editor.deltaDecorations([], proxy.editor.decorationList);;
}
if(event === 'removeHighlights') {
if(proxy.editor.lastDecorations && proxy.editor.lastDecorations.length > 1) {
proxy.editor.lastDecorations = proxy.editor.deltaDecorations(proxy.editor.lastDecorations, [{ range: new monaco.Range(1,1,1,1), options : { } }]);
}
}
if(event === 'addLibs') {
console.log('loading libs ', args[0])
var libs = args[0];
loadLibs(libs);
}
if (event === 'layout') {
resizeHandler();
}
Expand Down
20 changes: 18 additions & 2 deletions monaco-editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<slot></slot>
</template>
<script>
var editorCounter = 1;
/**
* # `monaco-editor`
* `monaco-editor` is a Polymer 2.0 element for [Monaco Editor](https://microsoft.github.io/monaco-editor/), a browser-based code editor which also powers Visual Studio Code.
Expand Down Expand Up @@ -272,6 +273,19 @@
type: String,
value: 'bottom'
},
/**
* Editor reference id, which is used to synchronize editor with the iframe which is necessary for multiple editors.
* @type {String}
*/
editorReference: {
type: String,
value: function() {
editorCounter = editorCounter + 1;
return 'editor'+editorCounter;
},
reflectToAttribute: true,
readonly: true
},
/**
* Configurations for the editor. For a full list of parameters, visit
* [here](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.ieditorconstructionoptions.html).
Expand Down Expand Up @@ -534,7 +548,8 @@
renderLineHighlight: this.renderLineHighlight,
minimap: {enabled: this.minimap},
readOnly: this.readOnly,
autoIndent: this.autoIndent
autoIndent: this.autoIndent,
theme : this.theme
},
this.options,
opt
Expand Down Expand Up @@ -576,6 +591,7 @@

_initIFrame() {
window.addEventListener('message', ({data}) => {
if(data.editorReference !== this.editorReference) return;
if (data.event === 'value-changed') {
this.set('_syncValue', true);
this.set('value', data.details);
Expand All @@ -589,7 +605,7 @@
iframe.resize(this.clientWidth, this.clientHeight);
iframe.init(
this.libPath,
this._getOptions({value: this.value, language: this.language})
this._getOptions({value: this.value, language: this.language, editorReference : this.editorReference})
);
this._setEditor(iframe.editor);
this._setMonaco(iframe.monaco);
Expand Down

0 comments on commit 3fd6ece

Please sign in to comment.