Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cursors with new presence API in share #3

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
60d3371
Cursor spike
aslakhellesoy Oct 11, 2013
28a8dcb
move cursor up one line
aslakhellesoy Dec 3, 2013
9d72388
Show multiple cursors. Still buggy
aslakhellesoy Dec 4, 2013
5207b4c
use the new cursor api in share/livedb
enjalot Apr 10, 2014
4f5e081
minor stylistic changes
enjalot Apr 10, 2014
9e9b3bc
point to git for packages
enjalot Apr 10, 2014
da612d9
Removed some old event propogation and supressed some cursor events
josephg Apr 11, 2014
b1917b5
Merge branch 'master' into newcursors
aslakhellesoy Apr 11, 2014
d54d0b2
Merge in fixes from master
aslakhellesoy Apr 12, 2014
08070e7
Formatting
aslakhellesoy Apr 12, 2014
548e187
Fix warnings
aslakhellesoy Apr 12, 2014
9ff6aa5
Semicolons
aslakhellesoy Apr 12, 2014
f963653
Simplify
aslakhellesoy Apr 12, 2014
a284b4c
Cleanup
aslakhellesoy Apr 12, 2014
58e8bad
Use a Cursor object to manage state
aslakhellesoy Apr 14, 2014
6723860
Merge with master - upgrade to CM4
aslakhellesoy Apr 14, 2014
09e241e
Make owner same hight as text
aslakhellesoy Apr 15, 2014
2329559
Hide name after 5 seconds of inactivity - to make text legible
aslakhellesoy Apr 15, 2014
2171cac
Reformat code
aslakhellesoy Apr 15, 2014
1830d8a
Remove unneeded d3 dependency. Remove broken timeout code
aslakhellesoy Apr 15, 2014
f4a0e03
Set default background to grey
aslakhellesoy Apr 15, 2014
8473e7f
Update dependencies and build script
aslakhellesoy May 30, 2014
418cf56
Bump jsdom
aslakhellesoy May 30, 2014
ff99689
Smaller owner text. Remove d3.
aslakhellesoy May 31, 2014
a3fd780
Allow selectionColor to be set
aslakhellesoy Jun 2, 2014
6a401ca
More configuration options
aslakhellesoy Jun 2, 2014
3afe1ad
Add a small dot that displays when cursor is idle
aslakhellesoy Jun 2, 2014
939e3e5
Fix bug whre other person typing would not move caret. Depend on lodash.
aslakhellesoy Jun 2, 2014
08c5491
Show owner below caret
aslakhellesoy Jun 3, 2014
3137d8e
Prevent events from being handled when recovering from inconsistent s…
aslakhellesoy Jun 16, 2014
d9dfe32
presence is passed in
aslakhellesoy Jul 6, 2014
761051a
Comment about better cursors
aslakhellesoy Jul 9, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
# Share-CodeMirror [![Build Status](https://secure.travis-ci.org/share/share-codemirror.png)](http://travis-ci.org/share/share-codemirror) [![Dependencies](https://david-dm.org/share/share-codemirror.png)](https://david-dm.org/share/share-codemirror) [![devDependency Status](https://david-dm.org/share/share-codemirror/dev-status.png)](https://david-dm.org/share/share-codemirror#info=devDependencies)
CodeMirror bindings for ShareJS >= 0.7.x.

## Dependencies

You need [lodash](http://lodash.com/) loaded before this library.

## Usage

```javascript
var cm = CodeMirror.fromTextArea(elem);
shareDoc.attachCodeMirror(cm);

var ctx = shareDoc.createContext();
shareDoc.attachCodeMirror(cm, ctx);
shareDoc.attachCodeMirrorCursor(cm, ctx);
```

That's it. You now have 2-way sync between your ShareJS and CodeMirror.
That's it. You now have 2-way sync between your ShareJS and CodeMirror.

### Configuration

The `attachCodeMirrorCursor` takes an optional 3rd `options` argument where the
following options may be set:

* `inactiveTimeout` - how long the "name" part of a cursor is visible after inactivity
* `color` - the color of the cursor
* `selectionColor` - the color of text selection
* `textColor` - the color of the "name" text

These attributes can also be set on a per-user basis with presence properties:

```javascript
shareDoc.setPresenceProperty("name", name);
shareDoc.setPresenceProperty("color", color);
shareDoc.setPresenceProperty("selectionColor", selectionColor);
shareDoc.setPresenceProperty("textColor", textColor);
shareDoc.setPresenceProperty("inactiveTimeout", 10000);
```

Share-Codemirror will provide default values for all of these properties if you
don't set them explicitly. You may want to use a color library such as
[TinyColor](http://bgrins.github.io/TinyColor/)
to manipulate colors, for example setting `selectionColor` a bit brighter than
`color`, or finding a legible `textColor` based on `color`.

## Install with Bower

Expand All @@ -22,7 +55,7 @@ bower install share-codemirror
npm install share-codemirror
```

On Node.js you can mount the `scriptsDir` (where `share-codemirror.js` lives) as a static resource
On Node.js you can mount the `scriptsDir` (where `share-codemirror.js` lives) as a static resource
in your web server:

```javascript
Expand All @@ -41,6 +74,7 @@ In the HTML:

```
npm install
npm test
node examples/server.js
# in a couple of browsers...
open http://localhost:7007
Expand Down Expand Up @@ -78,4 +112,3 @@ git push --tags
```

There is no `bower publish` - the existance of a git tag is enough.

123 changes: 73 additions & 50 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -1,66 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/codemirror.css">
<script src="/codemirror.js"></script>
<script src="/channel/bcsocket.js"></script>
<script src="/share.uncompressed.js"></script>
<script src="/share-codemirror.js"></script>
<link rel="stylesheet" href="/codemirror.css">
<script src="/lodash.min.js"></script>
<script src="/codemirror.js"></script>
<script src="/channel/bcsocket.js"></script>
<script src="/share.uncompressed.js"></script>
<script src="/share-codemirror.js"></script>
<script src="/share-codemirror-cursor.js"></script>
<script src="/tinycolor-min.js"></script>

<style>

.user-name {
color: white;
font-size: 10px;
line-height: 1;
padding: 1px 3px;

-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}

.user-cursor {
background: black;
}

#users input {
width: 250px;
}
</style>
</head>
<body>
<textarea id="pad">Connecting...</textarea>
<button id="monkey">Infinite Monkey</button>

<div id="myself">
<input value="">
</div>
<div id="users"></div>
<script>
var elem = document.getElementById('pad');
var cm = CodeMirror.fromTextArea(elem, {
mode: "text/plain"
});
var elem = document.getElementById('pad');
var cm = CodeMirror.fromTextArea(elem, {
mode: "text/plain"
});

var bcs = new BCSocket(null, {reconnect: true});
var sjs = new window.sharejs.Connection(bcs);
sjs.debug = false;

var doc = sjs.get('users', 'sephx');

var s = new BCSocket(null, {reconnect: true});
var sjs = new window.sharejs.Connection(s);
var doc = sjs.get('users', 'sephx');
doc.subscribe();
doc.whenReady(function () {
if (!doc.type) doc.create('text');
if (doc.type && doc.type.name === 'text') {
var ctx = doc.createContext();
doc.attachCodeMirror(cm, ctx);
doc.attachCodeMirrorCursor(cm, ctx, {inactiveTimeout: 2000});

doc.subscribe();
doc.whenReady(function () {
if (!doc.type) doc.create('text');
if (doc.type && doc.type.name === 'text') {
doc.attachCodeMirror(cm);
}
});
// set the color for our session
var sessionIds = Object.keys(ctx.getPresence());
// colorbrewer
var colors = [
"#8dd3c7", "#bebada", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5"
];
var color = colors[sessionIds.length % colors.length];
doc.setPresenceProperty("color", color);

document.getElementById('monkey').onclick = function() {
setInterval(monkeyType, 50);
};
var selectionColor = tinycolor.lighten(color).toHexString();
doc.setPresenceProperty("selectionColor", selectionColor);

function monkeyType() {
var textLength = cm.getValue().length;
var pos = Math.floor(Math.random()*textLength);
var from = cm.posFromIndex(pos);
var editLength = randomInt(10)
if(Math.random() < 0.9) {
// Add text
var text = randomString(editLength);
cm.replaceRange(text, cm.posFromIndex(pos));
} else {
var endIndex = Math.max(pos + editLength, textLength-1);
var to = cm.posFromIndex(endIndex);
cm.replaceRange('', from, to);
}
}
var textColor = tinycolor.mostReadable(color, ['black', 'white']).toHexString();
doc.setPresenceProperty("textColor", textColor);

function randomString(len) {
var chars = "0123456789\nABCDEF\nGHIJKLM\nNOPQRSTUVWXTZ\nabcde\nfghiklmnop\nqrstuvwxyz";
var result = '';
for (var i=0; i<len; i++) {
var rnum = randomInt(chars.length);
result += chars.substring(rnum, rnum+1);
}
return result;
}
var myself = document.getElementById('myself');
myself.style.background = color;
var input = myself.getElementsByTagName("input")[0];
input.value = doc.connection.id;
input.onkeyup = function () {
doc.setPresenceProperty("name", input.value);
};
}
});

function randomInt(max) {
return Math.floor(Math.random()*max);
}

</script>
</body>
Expand Down
12 changes: 11 additions & 1 deletion examples/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ var webserver = connect(
connect["static"](__dirname),
connect["static"](shareCodeMirror.scriptsDir),
connect["static"](__dirname + '/../node_modules/codemirror/lib'),
connect["static"](__dirname + '/../node_modules/tinycolor2/dist'),
connect["static"](__dirname + '/../node_modules/lodash/dist'),
connect["static"](sharejs.scriptsDir)
);

Expand All @@ -19,7 +21,12 @@ var backend = livedb.client(livedbMongo('localhost:27017/test?auto_reconnect', {

var share = sharejs.server.createClient({backend: backend});

webserver.use(browserChannel({webserver: webserver}, function (client) {
var clientsById = {};

webserver.use(browserChannel({webserver: webserver, sessionTimeoutInterval: 5000}, function (client) {
clientsById[client.id] = client;
//client.send({_type: 'connectionId', connectionId: client.id});

var stream = new Duplex({objectMode: true});
stream._write = function (chunk, encoding, callback) {
if (client.state !== 'closed') {
Expand All @@ -35,12 +42,15 @@ webserver.use(browserChannel({webserver: webserver}, function (client) {
stream.push(data);
});
stream.on('error', function (msg) {
console.log('ERROR', msg, client.id);
client.stop();
});
client.on('close', function (reason) {
console.log('CLOSE', reason, client.id);
stream.emit('close');
stream.emit('end');
stream.end();
delete clientsById[client.id];
});
return share.listen(stream);
}));
Expand Down
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "CodeMirror bindings for ShareJS",
"main": "share-codemirror.js",
"scripts": {
"pretest": "cd node_modules/share && npm install",
"pretest": "cd node_modules/share && UGLIFY=../../node_modules/.bin/uglifyjs make webclient/share.uncompressed.js",
"test": "node_modules/.bin/mocha"
},
"repository": {
Expand All @@ -21,14 +21,17 @@
"url": "https://github.com/share/share-codemirror/issues"
},
"devDependencies": {
"share": "v0.7.0-alpha9",
"codemirror": "~4.0.3",
"browserchannel": "~1.2.0",
"codemirror": "~4.2.0",
"connect": "~2.11.0",
"browserchannel": "~1.0.8",
"livedb": "~0.2.6",
"livedb-mongo": "~0.2.5",
"mocha": "~1.14.0",
"jsdom": "~0.8.8",
"istanbul": "~0.1.44"
"istanbul": "~0.2.10",
"jsdom": "~0.10.6",
"livedb": "git://github.com/share/livedb.git#f03086cdf51ffc80c725f105c7236c2997d74eac",
"livedb-mongo": "~0.3.2",
"lodash": "~2.4.1",
"mocha": "~1.20.0",
"share": "git://github.com/share/ShareJS.git#94dd9e0659c9b6953ba888f5dde8ce223a71f2ec",
"tinycolor2": "^0.10.0",
"uglify-js": "~2.4.13"
}
}
Loading