Skip to content

Commit

Permalink
hack to make monaco-editor works inside another custom element
Browse files Browse the repository at this point in the history
  • Loading branch information
eterna2 committed Nov 12, 2017
1 parent 6dcafe1 commit 74c7c79
Show file tree
Hide file tree
Showing 7 changed files with 477 additions and 16 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ You can still view the demo at the [`monaco-editor` Github page](https://Polymer
## Very important note on external dependencies when building/bundling your app
`monaco-editor` loads most of the required modules dynamically, hence `polymer-build` will not be able to properly detect these external modules. You will need to manually add `bower_components/monaco-editor/node_modules/monaco-editor/min/vs/**/*` into the `extraDependencies` to ensure these modules are exported together.

## Important note on "hack" to allow Monaco Editor to work inside a custom element
Monaco Editor only works properly in the light DOM and there are a few functions that access or check on `document.body`. The selection is also dependent on `document.caretPositionFromPoint` or its variant. Hence, there are only a few solutions:

- make a pull request and update the source code: but the source code seems to reside somewhere in [Visual Studio Code repo](https://github.com/Microsoft/vscode) instead of a proper `monaco-editor-core` repo,
- attach the element (which Monaco Editor will be anchoring to) in the `document.body`, and try to sync the position, size, and style with the `monaco-editor` custom element,
- create an iFrame and attach the iFrame to the `monaco-editor` custom element's shadowRoot.

The current approach now is, if the parent node of the `monaco-editor` is in the light DOM (it is not inside another custom element), the anchoring element will be insert as a slot (so that it remains in the light DOM), otherwise an iFrame will be created. In this case, a `monaco`, and `editor` proxy object will be created so that the some functions will be proxied into the iFrame.

## Disclaimers
PolymerVis is a personal project and is NOT in any way affliated with Microsoft, Polymer or Google.

Expand Down
6 changes: 4 additions & 2 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
"description": "A Polymer 2.0 element for Monaco Editor, an browser-based code editor.",
"main": "monaco-elements.html",
"dependencies": {
"polymer": "Polymer/polymer#^2.0.0"
"polymer": "Polymer/polymer#^2.0.0",
"polymer-vis": "PolymerVis/polymer-vis#^2.0.1"
},
"devDependencies": {
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#^2.0.0",
"web-component-tester": "Polymer/web-component-tester#^6.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0",
"vega-element": "PolymerVis/vega-element#^2.0.3"
"vega-element": "PolymerVis/vega-element#^2.0.3",
"paper-button": "PolymerElements/paper-button#^2.0.0"
},
"resolutions": {
"polymer": "^2.0.0"
Expand Down
69 changes: 69 additions & 0 deletions demo/iframe.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="./wrapper-view.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>
<wrapper-view></wrapper-view>
</template>
</dom-bind>

<script>
</script>

</body>
</html>
98 changes: 98 additions & 0 deletions demo/wrapper-view.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<!--
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<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="wrapper-view">
<template>
<style>
:host {
display: block;

padding: 10px 20px;
}
monaco-editor {
height: 600px;
width: 600px;
}
paper-button {
background-color: #A5D6A7;
}
paper-button.off {
color: #888;
background-color: #ccc;
}
</style>
<monaco-schemas keys="vega-lite" schemas="{{schemas}}"></monaco-schemas>
<paper-button id="minimap"
on-tap="toggleMinimap">Toggle Minimap</paper-button>
<paper-button id="theme"
on-tap="toggleTheme">Toggle Theme</paper-button>
<monaco-editor
minimap="[[minimap]]"
theme="[[theme]]"
json-validate
language="json"
json-schemas="[[schemas]]">
<div slot="monaco-value">{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"description": "A simple bar chart with embedded data.",
"data": {
"values": [
{"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
{"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
{"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
]
},
"mark": "bar",
"encoding": {
"x": {"field": "a", "type": "ordinal"},
"y": {"field": "b", "type": "quantitative"}
}
}</div>
</monaco-editor>

</template>

<script>
class WrapperView extends Polymer.Element {
static get is() {
return 'wrapper-view';
}
static get properties() {
return {
theme: {
type: String,
value: 'vs'
},
minimap: {
type: Boolean,
value: false,
observer: 'minimapChanged'
}
};
}
minimapChanged(v) {
this.$.minimap.classList.toggle('off', v);
}
toggleMinimap() {
this.set('minimap', !this.minimap);
}
toggleTheme() {
this.set('theme', this.theme === 'vs' ? 'vs-dark' : 'vs');
}
}

window.customElements.define(WrapperView.is, WrapperView);
</script>
</dom-module>
28 changes: 28 additions & 0 deletions monaco-editor-iframe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0;url=demo/" />
<link rel="import" href="./bower_components/polymer/polymer-element.html">
<link rel="import" href="./bower_components/polymer/lib/elements/dom-bind.html">
<link rel="import" href="./monaco-editor.html">
<title>monaco-editor</title>
<style>
#editor {
width: 100%;
height: 100%;
}
</style>
</head>

<body>
<div id="editor"></div>
<script>
window.addEventListener('message', receiveMessage, false);
parent.postMessage('ready', parent.document.location.href);
function receiveMessage(event) {
console.log(event);
}
</script>
</body>
</html>
Loading

0 comments on commit 74c7c79

Please sign in to comment.