Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
2,877 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
static/dist/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Collaborative Rich Text Editor with ShareDB | ||
|
||
This is a collaborative rich text editor using [Quill](https://github.com/quilljs/quill) and the [rich-text OT type](https://github.com/ottypes/rich-text). | ||
|
||
In this demo, data is not persisted. To persist data, run a Mongo | ||
server and initialize ShareDB with the | ||
[ShareDBMongo](https://github.com/share/sharedb-mongo) database adapter. | ||
|
||
## Install dependencies | ||
``` | ||
npm install | ||
``` | ||
|
||
## Build JavaScript bundle and run server | ||
``` | ||
npm run build && npm start | ||
``` | ||
|
||
## Run app in browser | ||
Load [http://localhost:8080](http://localhost:8080) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
var ReconnectingWebSocket = require('reconnecting-websocket'); | ||
var sharedb = require('sharedb/lib/client'); | ||
var richText = require('./rich-text'); | ||
var Quill = require('quill'); | ||
var QuillCursors = require('quill-cursors'); | ||
var tinycolor = require('tinycolor2'); | ||
var ObjectID = require('bson-objectid'); | ||
|
||
sharedb.types.register(richText.type); | ||
Quill.register('modules/cursors', QuillCursors); | ||
|
||
var connectionButton = document.getElementById('client-connection'); | ||
connectionButton.addEventListener('click', function() { | ||
toggleConnection(connectionButton); | ||
}); | ||
|
||
var nameInput = document.getElementById('name'); | ||
|
||
var colors = {}; | ||
|
||
var collection = 'examples'; | ||
var id = 'richtext'; | ||
var presenceId = new ObjectID().toString(); | ||
|
||
var socket = new ReconnectingWebSocket('ws://' + window.location.host); | ||
var connection = new sharedb.Connection(socket); | ||
var doc = connection.get(collection, id); | ||
|
||
doc.subscribe(function(err) { | ||
if (err) throw err; | ||
initialiseQuill(doc); | ||
}); | ||
|
||
function initialiseQuill(doc) { | ||
var quill = new Quill('#editor', { | ||
theme: 'bubble', | ||
modules: {cursors: true} | ||
}); | ||
var cursors = quill.getModule('cursors'); | ||
|
||
quill.setContents(doc.data); | ||
|
||
quill.on('text-change', function(delta, oldDelta, source) { | ||
if (source !== 'user') return; | ||
doc.submitOp(delta); | ||
}); | ||
|
||
doc.on('op', function(op, source) { | ||
if (source) return; | ||
quill.updateContents(op); | ||
}); | ||
|
||
var presence = doc.connection.getDocPresence(collection, id); | ||
presence.subscribe(function(error) { | ||
if (error) throw error; | ||
}); | ||
var localPresence = presence.create(presenceId); | ||
|
||
quill.on('selection-change', function(range) { | ||
// Ignore blurring, so that we can see lots of users in the | ||
// same window. In real use, you may want to clear the cursor. | ||
if (!range) return; | ||
// In this particular instance, we can send extra information | ||
// on the presence object. This ability will vary depending on | ||
// type. | ||
range.name = nameInput.value; | ||
localPresence.submit(range, function(error) { | ||
if (error) throw error; | ||
}); | ||
}); | ||
|
||
presence.on('receive', function(id, range) { | ||
colors[id] = colors[id] || tinycolor.random().toHexString(); | ||
var name = (range && range.name) || 'Anonymous'; | ||
cursors.createCursor(id, name, colors[id]); | ||
cursors.moveCursor(id, range); | ||
}); | ||
|
||
return quill; | ||
} | ||
|
||
function toggleConnection(button) { | ||
if (button.classList.contains('connected')) { | ||
button.classList.remove('connected'); | ||
button.textContent = 'Connect'; | ||
disconnect(); | ||
} else { | ||
button.classList.add('connected'); | ||
button.textContent = 'Disconnect'; | ||
connect(); | ||
} | ||
} | ||
|
||
function disconnect() { | ||
doc.connection.close(); | ||
} | ||
|
||
function connect() { | ||
var socket = new ReconnectingWebSocket('ws://' + window.location.host); | ||
doc.connection.bindToSocket(socket); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "sharedb-example-rich-text-presence", | ||
"version": "1.0.0", | ||
"description": "An example of presence using ShareDB and Quill", | ||
"main": "server.js", | ||
"scripts": { | ||
"build": "mkdir -p static/dist/ && ./node_modules/.bin/browserify client.js -o static/dist/bundle.js", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "node server.js" | ||
}, | ||
"author": "Nate Smith", | ||
"contributors": [ | ||
"Avital Oliver <avital@aoliver.org> (https://aoliver.org/)", | ||
"Alec Gibson <alec@reedsy.com>" | ||
], | ||
"license": "MIT", | ||
"dependencies": { | ||
"@teamwork/websocket-json-stream": "^2.0.0", | ||
"bson-objectid": "^1.3.0", | ||
"express": "^4.17.1", | ||
"quill": "^1.3.7", | ||
"quill-cursors": "^2.2.1", | ||
"reconnecting-websocket": "^4.2.0", | ||
"rich-text": "^4.0.0", | ||
"sharedb": "file:../../", | ||
"tinycolor2": "^1.4.1", | ||
"ws": "^7.2.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^16.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
var richText = require('rich-text'); | ||
|
||
richText.type.transformPresence = function(presence, op, isOwnOp) { | ||
if (!presence) { | ||
return null; | ||
} | ||
|
||
var start = presence.index; | ||
var end = presence.index + presence.length; | ||
var delta = new richText.Delta(op); | ||
start = delta.transformPosition(start, !isOwnOp); | ||
end = delta.transformPosition(end, !isOwnOp); | ||
|
||
return Object.assign({}, presence, { | ||
index: start, | ||
length: end - start | ||
}); | ||
}; | ||
|
||
module.exports = richText; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
var http = require('http'); | ||
var express = require('express'); | ||
var ShareDB = require('sharedb'); | ||
var richText = require('./rich-text'); | ||
var WebSocket = require('ws'); | ||
var WebSocketJSONStream = require('@teamwork/websocket-json-stream'); | ||
|
||
ShareDB.types.register(richText.type); | ||
var backend = new ShareDB({presence: true}); | ||
createDoc(startServer); | ||
|
||
// Create initial document then fire callback | ||
function createDoc(callback) { | ||
var connection = backend.connect(); | ||
var doc = connection.get('examples', 'richtext'); | ||
doc.fetch(function(err) { | ||
if (err) throw err; | ||
if (doc.type === null) { | ||
doc.create([{insert: 'Hi!'}], 'rich-text', callback); | ||
return; | ||
} | ||
callback(); | ||
}); | ||
} | ||
|
||
function startServer() { | ||
// Create a web server to serve files and listen to WebSocket connections | ||
var app = express(); | ||
app.use(express.static('static')); | ||
app.use(express.static('node_modules/quill/dist')); | ||
var server = http.createServer(app); | ||
|
||
// Connect any incoming WebSocket connection to ShareDB | ||
var wss = new WebSocket.Server({server: server}); | ||
wss.on('connection', function(ws) { | ||
var stream = new WebSocketJSONStream(ws); | ||
backend.listen(stream); | ||
}); | ||
|
||
server.listen(8080); | ||
console.log('Listening on http://localhost:8080'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<!DOCTYPE html> | ||
<meta charset="utf-8"> | ||
<title>ShareDB Rich Text</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> | ||
<link href="quill.bubble.css" rel="stylesheet"> | ||
<link href="style.css" rel="stylesheet"> | ||
|
||
<div class="controls"> | ||
<input type="text" placeholder="Enter your name..." id="name" /> | ||
<button id="client-connection" class="connected">Disconnect</button> | ||
</div> | ||
|
||
<center> | ||
Open a new window to see another client! | ||
</center> | ||
|
||
<div id="editor"></div> | ||
|
||
<script src="dist/bundle.js"></script> |
Oops, something went wrong.