Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Commit

Permalink
Monaco-editor support (#299)
Browse files Browse the repository at this point in the history
* New MonacoAdapter class added and plumbed into lib/firepad.js, etc.
* examples/monaco.html added to demonstrate it.
  • Loading branch information
pranjaltale16 authored and mikelehen committed Jun 6, 2018
1 parent b678875 commit 251df18
Show file tree
Hide file tree
Showing 7 changed files with 422 additions and 12 deletions.
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module.exports = function (grunt) {
"lib/client.js",
"lib/editor-client.js",
"lib/ace-adapter.js",
"lib/monaco-adapter.js",
"lib/constants.js",
"lib/entity-manager.js",
"lib/entity.js",
Expand Down
1 change: 1 addition & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<a href="code.html">Code (CodeMirror editor)</a><br />
<a href="ace.html">Code (ACE editor)</a><br />
<a href="monaco.html">Code (Monaco editor)</a><br />
<a href="richtext-simple.html">Rich Text (Simple)</a><br />
<a href="richtext.html">Rich Text</a><br />
<a href="userlist.html">User List</a><br />
Expand Down
70 changes: 70 additions & 0 deletions examples/monaco.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/3.3.0/firebase.js"></script>

<!-- Firepad -->
<link rel="stylesheet" href="./../dist/firepad.css" />
<script src="./../dist/firepad.min.js"></script>

<!-- Loader.js -->
<script src="./../node_modules/monaco-editor/min/vs/loader.js"></script>

<style>
html { height: 100%; }
body { margin: 0; height: 100%; position: relative; }
/* Height / width / positioning can be customized for your use case.
For demo purposes, we make firepad fill the entire browser. */
#firepad {
width: 100%;
height: 100%;
}
</style>

</head>
<body onload="init()">
<div id="firepad"></div>

<script>
function init() {
//// Initialize Firebase.
//// TODO: replace with your Firebase project configuration.
var config = {
apiKey: "AIzaSyC_JdByNm-E1CAJUkePsr-YJZl7W77oL3g",
authDomain: "firepad-tests.firebaseapp.com",
databaseURL: "https://firepad-tests.firebaseio.com"
};
firebase.initializeApp(config);

//// Get Firebase Database reference.
var firepadRef = getExampleRef();

//// Create Monaco and firepad.
require.config({ paths: {'vs': './../node_modules/monaco-editor/min/vs'}});
require(['vs/editor/editor.main'], function() {
editor = monaco.editor.create(document.getElementById('firepad'));
Firepad.fromMonaco(firepadRef, editor);
});

}

// Helper to get hash from end of URL or generate a random one.
function getExampleRef() {
var ref = firebase.database().ref();
var hash = window.location.hash.replace(/#/g, '');
if (hash) {
ref = ref.child(hash);
} else {
ref = ref.push(); // generate unique location.
window.location = window.location + '#' + ref.key; // add it as a hash to the URL.
}
if (typeof console !== 'undefined') {
console.log('Firebase data: ', ref.toString());
}
return ref;
}
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion lib/ace-adapter.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class firepad.ACEAdapter
# Ace 1.2.0+
text = change.lines.join('\n')
start = @indexFromPos change.start

restLength = @lastDocLines.join('\n').length - start
restLength -= text.length if change.action is 'remove'
insert_op = new firepad.TextOperation().retain(start).insert(text).retain(restLength)
Expand Down
55 changes: 47 additions & 8 deletions lib/firepad.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ firepad.Firepad = (function(global) {
var RichTextCodeMirror = firepad.RichTextCodeMirror;
var RichTextToolbar = firepad.RichTextToolbar;
var ACEAdapter = firepad.ACEAdapter;
var MonacoAdapter = firepad.MonacoAdapter;
var FirebaseAdapter = firepad.FirebaseAdapter;
var EditorClient = firepad.EditorClient;
var EntityManager = firepad.EntityManager;
Expand All @@ -16,12 +17,13 @@ firepad.Firepad = (function(global) {
var LIST_TYPE = firepad.LineFormatting.LIST_TYPE;
var CodeMirror = global.CodeMirror;
var ace = global.ace;
var monaco = global.monaco;

function Firepad(ref, place, options) {
if (!(this instanceof Firepad)) { return new Firepad(ref, place, options); }

if (!CodeMirror && !ace) {
throw new Error('Couldn\'t find CodeMirror or ACE. Did you forget to include codemirror.js or ace.js?');
if (!CodeMirror && !ace && !global.monaco) {
throw new Error('Couldn\'t find CodeMirror, ACE or Monaco. Did you forget to include codemirror.js/ace.js or import monaco?');
}

this.zombie_ = false;
Expand All @@ -38,11 +40,27 @@ firepad.Firepad = (function(global) {
if (curValue !== '') {
throw new Error("Can't initialize Firepad with an ACE instance that already contains text.");
}
} else if (global.monaco && place && place instanceof global.monaco.constructor) {
monaco = global.monaco;
this.monaco_ = this.editor_ = place;
curValue = this.monaco_.getValue();
if (curValue !== '') {
throw new Error("Can't initialize Firepad with a Monaco instance that already contains text.");
}
} else {
this.codeMirror_ = this.editor_ = new CodeMirror(place);
}

var editorWrapper = this.codeMirror_ ? this.codeMirror_.getWrapperElement() : this.ace_.container;
var editorWrapper;
if (this.codeMirror_) {
editorWrapper = this.codeMirror_.getWrapperElement();
} else if (this.ace_) {
editorWrapper = this.ace_.container;
} else {
editorWrapper = this.monaco_.getDomNode()
}

// var editorWrapper = this.codeMirror_ ? this.codeMirror_.getWrapperElement() : this.ace_.container;
this.firepadWrapper_ = utils.elt("div", null, { 'class': 'firepad' });
editorWrapper.parentNode.replaceChild(this.firepadWrapper_, editorWrapper);
this.firepadWrapper_.appendChild(editorWrapper);
Expand Down Expand Up @@ -85,8 +103,10 @@ firepad.Firepad = (function(global) {
if (this.codeMirror_) {
this.richTextCodeMirror_ = new RichTextCodeMirror(this.codeMirror_, this.entityManager_, { cssPrefix: 'firepad-' });
this.editorAdapter_ = new RichTextCodeMirrorAdapter(this.richTextCodeMirror_);
} else {
} else if (this.ace_) {
this.editorAdapter_ = new ACEAdapter(this.ace_);
} else {
this.editorAdapter_ = new MonacoAdapter(this.monaco_);
}
this.client_ = new EditorClient(this.firebaseAdapter_, this.editorAdapter_);

Expand All @@ -107,6 +127,9 @@ firepad.Firepad = (function(global) {
if (this.ace_) {
this.editorAdapter_.grabDocumentState();
}
if (this.monaco_) {
this.editorAdapter_.grabDocumentState();
}

var defaultText = self.getOption('defaultText', null);
if (defaultText && self.isHistoryEmpty()) {
Expand Down Expand Up @@ -138,12 +161,22 @@ firepad.Firepad = (function(global) {
// For readability, these are the primary "constructors", even though right now they're just aliases for Firepad.
Firepad.fromCodeMirror = Firepad;
Firepad.fromACE = Firepad;
Firepad.fromMonaco = Firepad;


Firepad.prototype.dispose = function() {
this.zombie_ = true; // We've been disposed. No longer valid to do anything.

// Unwrap the editor.
var editorWrapper = this.codeMirror_ ? this.codeMirror_.getWrapperElement() : this.ace_.container;
// var editorWrapper = this.codeMirror_ ? this.codeMirror_.getWrapperElement() : this.ace_.container;
if (this.codeMirror_) {
editorWrapper = this.codeMirror_.getWrapperElement();
} else if (this.ace_) {
editorWrapper = this.ace_.container;
} else {
editorWrapper = this.monaco_.getDomNode()
}

this.firepadWrapper_.removeChild(editorWrapper);
this.firepadWrapper_.parentNode.replaceChild(editorWrapper, this.firepadWrapper_);

Expand Down Expand Up @@ -171,13 +204,17 @@ firepad.Firepad = (function(global) {
this.assertReady_('getText');
if (this.codeMirror_)
return this.richTextCodeMirror_.getText();
else
else if (this.ace_)
return this.ace_.getSession().getDocument().getValue();
else
return this.monaco_.getModel().getValue();
};

Firepad.prototype.setText = function(textPieces) {
this.assertReady_('setText');
if (this.ace_) {
this.assertReady_('setText');
if (this.monaco_) {
return this.monaco_.getModel().setValue(textPieces);
} else if (this.ace_) {
return this.ace_.getSession().getDocument().setValue(textPieces);
} else {
// HACK: Hide CodeMirror during setText to prevent lots of extra renders.
Expand All @@ -196,6 +233,7 @@ firepad.Firepad = (function(global) {

Firepad.prototype.insertText = function(index, textPieces) {
utils.assert(!this.ace_, "Not supported for ace yet.");
utils.assert(!this.monaco_, "Not supported for monaco yet.");
this.assertReady_('insertText');

// Wrap it in an array if it's not already.
Expand Down Expand Up @@ -534,3 +572,4 @@ firepad.Firepad.Headless = firepad.Headless;
// Export adapters
firepad.Firepad.RichTextCodeMirrorAdapter = firepad.RichTextCodeMirrorAdapter;
firepad.Firepad.ACEAdapter = firepad.ACEAdapter;
firepad.Firepad.MonacoAdapter = firepad.MonacoAdapter;
Loading

0 comments on commit 251df18

Please sign in to comment.