Initial commit.

This commit is contained in:
Michael MacFadden
2019-03-03 22:18:50 -06:00
commit c743f8df2a
28 changed files with 1868 additions and 0 deletions

2
example/README.md Normal file
View File

@@ -0,0 +1,2 @@
# Monaco Collaborative Extensions Example
This directory contains a vanilla javascript example of using this library. Simply run `npm run dist` and then open the index.html in a web browser.

View File

@@ -0,0 +1,84 @@
var editorContents = `var observableProto;
/**
* Represents a push-style collection.
*/
var Observable = Rx.Observable = (function () {
function makeSubscribe(self, subscribe) {
return function (o) {
var oldOnError = o.onError;
o.onError = function (e) {
makeStackTraceLong(e, self);
oldOnError.call(o, e);
};
return subscribe.call(self, o);
};
}
function Observable() {
if (Rx.config.longStackSupport && hasStacks) {
var oldSubscribe = this._subscribe;
var e = tryCatch(thrower)(new Error()).e;
this.stack = e.stack.substring(e.stack.indexOf('\\n') + 1);
this._subscribe = makeSubscribe(this, oldSubscribe);
}
}
observableProto = Observable.prototype;
/**
* Determines whether the given object is an Observable
* @param {Any} An object to determine whether it is an Observable
* @returns {Boolean} true if an Observable, else false.
*/
Observable.isObservable = function (o) {
return o && isFunction(o.subscribe);
};
/**
* Subscribes an o to the observable sequence.
* @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence.
* @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence.
* @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence.
* @returns {Diposable} A disposable handling the subscriptions and unsubscriptions.
*/
observableProto.subscribe = observableProto.forEach = function (oOrOnNext, onError, onCompleted) {
return this._subscribe(typeof oOrOnNext === 'object' ?
oOrOnNext :
observerCreate(oOrOnNext, onError, onCompleted));
};
/**
* Subscribes to the next value in the sequence with an optional "this" argument.
* @param {Function} onNext The function to invoke on each element in the observable sequence.
* @param {Any} [thisArg] Object to use as this when executing callback.
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
*/
observableProto.subscribeOnNext = function (onNext, thisArg) {
return this._subscribe(observerCreate(typeof thisArg !== 'undefined' ? function(x) { onNext.call(thisArg, x); } : onNext));
};
/**
* Subscribes to an exceptional condition in the sequence with an optional "this" argument.
* @param {Function} onError The function to invoke upon exceptional termination of the observable sequence.
* @param {Any} [thisArg] Object to use as this when executing callback.
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
*/
observableProto.subscribeOnError = function (onError, thisArg) {
return this._subscribe(observerCreate(null, typeof thisArg !== 'undefined' ? function(e) { onError.call(thisArg, e); } : onError));
};
/**
* Subscribes to the next value in the sequence with an optional "this" argument.
* @param {Function} onCompleted The function to invoke upon graceful termination of the observable sequence.
* @param {Any} [thisArg] Object to use as this when executing callback.
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
*/
observableProto.subscribeOnCompleted = function (onCompleted, thisArg) {
return this._subscribe(observerCreate(null, null, typeof thisArg !== 'undefined' ? function() { onCompleted.call(thisArg); } : onCompleted));
};
return Observable;
})();`;

19
example/example.css Normal file
View File

@@ -0,0 +1,19 @@
.body {
margin: 0;
}
.editors {
display: flex;
flex-direction: row;
flex: 1;
}
.editor-column {
flex: 1;
}
.editor {
height: 500px;
border: 1px solid grey;
margin-right: 20px;
}

80
example/example.js Normal file
View File

@@ -0,0 +1,80 @@
const sourceUser = {
id: "source",
label: "Source User",
color: "orange"
};
const staticUser = {
id: "static",
label: "Static User",
color: "blue"
};
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' }});
require(['vs/editor/editor.main', 'MonacoCollabExt'], function(m, MonacoCollabExt) {
//
// Create the target editor where events will be played into.
//
const target = monaco.editor.create(document.getElementById("target-editor"), {
value: editorContents,
theme: "vs-dark'",
language: 'javascript'
});
const remoteCursorManager = new MonacoCollabExt.RemoteCursorManager({
editor: target,
tooltips: true,
tooltipDuration: 2
});
const sourceUserCursor = remoteCursorManager.addCursor(sourceUser.id, sourceUser.color, sourceUser.label);
const staticUserCursor = remoteCursorManager.addCursor(staticUser.id, staticUser.color, staticUser.label);
const remoteSelectionManager = new MonacoCollabExt.RemoteSelectionManager({editor: target});
remoteSelectionManager.addSelection(sourceUser.id, sourceUser.color);
remoteSelectionManager.addSelection(staticUser.id, staticUser.color);
const targetContentManager = new MonacoCollabExt.EditorContentManager({
editor: target
});
//
// Faked other user.
//
staticUserCursor.setOffset(50);
remoteSelectionManager.setSelectionOffsets(staticUser.id, 40, 50);
//
// Create the source editor were events will be generated.
//
const source = monaco.editor.create(document.getElementById("source-editor"), {
value: editorContents,
theme: "vs-dark'",
language: 'javascript'
});
source.onDidChangeCursorPosition(e => {
const offset = source.getModel().getOffsetAt(e.position);
sourceUserCursor.setOffset(offset);
});
source.onDidChangeCursorSelection(e => {
const startOffset = source.getModel().getOffsetAt(e.selection.getStartPosition());
const endOffset = source.getModel().getOffsetAt(e.selection.getEndPosition());
remoteSelectionManager.setSelectionOffsets(sourceUser.id, startOffset, endOffset);
});
const sourceContentManager = new MonacoCollabExt.EditorContentManager({
editor: source,
onInsert(index, text) {
targetContentManager.insert(index, text);
},
onReplace(index, length, text) {
targetContentManager.replace(index, length, text);
},
onDelete(index, length) {
targetContentManager.delete(index, length);
}
});
});

29
example/index.html Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor/min/vs/editor/editor.main.css"/>
<link rel="stylesheet" href="../dist/css/monaco-collab-ext.css">
<link rel="stylesheet" href="./example.css">
</head>
<body>
<div class="editors">
<div class="editor-column">
<div class="editor" id="source-editor"></div>
</div>
<div class="editor-column">
<div class="editor" id="target-editor"></div>
</div>
</div>
<script src="editor_contents.js"></script>
<script>var require = {paths: {'vs': '../node_modules/monaco-editor/min/vs'}};</script>
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
<script src="../node_modules/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
<script src="../node_modules/monaco-editor/min/vs/editor/editor.main.js"></script>
<script src="../dist/umd/monaco-collab-ext.js"></script>
<script src="./example.js"></script>
</body>
</html>