diff --git a/examples/quill-cursors/index.html b/examples/quill-cursors/index.html
new file mode 100644
index 00000000..1e63961c
--- /dev/null
+++ b/examples/quill-cursors/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/quill-cursors/index.js b/examples/quill-cursors/index.js
new file mode 100644
index 00000000..3b14ac9f
--- /dev/null
+++ b/examples/quill-cursors/index.js
@@ -0,0 +1,78 @@
+/* global Y, Quill, QuillCursors */
+
+Quill.register('modules/cursors', QuillCursors)
+
+let y = new Y('quill-0', {
+ connector: {
+ name: 'websockets-client',
+ url: 'http://127.0.0.1:1234'
+ }
+})
+let users = y.define('users', Y.Array)
+let myUserInfo = new Y.Map()
+myUserInfo.set('name', 'dada')
+myUserInfo.set('color', 'red')
+users.push([myUserInfo])
+
+let quill = new Quill('#quill-container', {
+ modules: {
+ toolbar: [
+ [{ header: [1, 2, false] }],
+ ['bold', 'italic', 'underline'],
+ ['image', 'code-block'],
+ [{ color: [] }, { background: [] }], // Snow theme fills in values
+ [{ script: 'sub' }, { script: 'super' }],
+ ['link', 'image'],
+ ['link', 'code-block'],
+ [{ list: 'ordered' }, { list: 'bullet' }]
+ ],
+ cursors: {
+ hideDelay: 500
+ }
+ },
+ placeholder: 'Compose an epic...',
+ theme: 'snow' // or 'bubble'
+})
+
+let cursors = quill.getModule('cursors')
+
+function drawCursors () {
+ cursors.clearCursors()
+ users.map((user, userId) => {
+ if (user !== myUserInfo) {
+ let relativeRange = user.get('range')
+ let lastUpdated = new Date(user.get('last updated'))
+ if (lastUpdated != null && new Date() - lastUpdated < 20000 && relativeRange != null) {
+ let start = Y.utils.fromRelativePosition(y, relativeRange.start).offset
+ let end = Y.utils.fromRelativePosition(y, relativeRange.end).offset
+ let range = { index: start, length: end - start }
+ cursors.setCursor(userId + '', range, user.get('name'), user.get('color'))
+ }
+ }
+ })
+}
+
+users.observeDeep(drawCursors)
+drawCursors()
+
+quill.on('selection-change', function (range) {
+ if (range != null) {
+ myUserInfo.set('range', {
+ start: Y.utils.getRelativePosition(yText, range.index),
+ end: Y.utils.getRelativePosition(yText, range.index + range.length)
+ })
+ } else {
+ myUserInfo.delete('range')
+ }
+ myUserInfo.set('last updated', new Date().toString())
+})
+
+let yText = y.define('quill', Y.Text)
+let quillBinding = new Y.QuillBinding(yText, quill)
+
+window.quillBinding = quillBinding
+window.yText = yText
+window.y = y
+window.quill = quill
+window.users = users
+window.cursors = cursors
diff --git a/examples/quill/index.html b/examples/quill/index.html
index 0f881d27..27a1964b 100644
--- a/examples/quill/index.html
+++ b/examples/quill/index.html
@@ -2,9 +2,9 @@
-
-
-
+
+
+
diff --git a/examples/quill/index.js b/examples/quill/index.js
index 8e2ab6e9..87ec0de9 100644
--- a/examples/quill/index.js
+++ b/examples/quill/index.js
@@ -1,6 +1,6 @@
/* global Y, Quill */
-let y = new Y('htmleditor10', {
+let y = new Y('quill-cursors-0', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
diff --git a/package-lock.json b/package-lock.json
index 112a1bcb..c8facecd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3337,6 +3337,16 @@
"quill-delta": "3.6.2"
}
},
+ "quill-cursors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/quill-cursors/-/quill-cursors-1.0.2.tgz",
+ "integrity": "sha512-mWkhOA9TvdFklG1QwVAOS70hOSpiHiJ+eoIbSeEXI6no6wNQLavYo3eWYHXgvi6Z5/SjS0oSn+NLdpYuXgdA8Q==",
+ "dev": true,
+ "requires": {
+ "rangefix": "0.2.5",
+ "tinycolor2": "1.4.1"
+ }
+ },
"quill-delta": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.2.tgz",
@@ -3395,6 +3405,12 @@
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
"dev": true
},
+ "rangefix": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/rangefix/-/rangefix-0.2.5.tgz",
+ "integrity": "sha1-vOeMkhsjWCuuIR9ZdGSlkf0alPk=",
+ "dev": true
+ },
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -4033,6 +4049,15 @@
"duplexer": "0.1.1"
}
},
+ "string_decoder": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ },
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@@ -4044,15 +4069,6 @@
"strip-ansi": "3.0.1"
}
},
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "dev": true,
- "requires": {
- "safe-buffer": "5.1.1"
- }
- },
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
@@ -4168,6 +4184,12 @@
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
+ "tinycolor2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
+ "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=",
+ "dev": true
+ },
"to-fast-properties": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
diff --git a/package.json b/package.json
index 1290580a..b53df6ef 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,7 @@
"concurrently": "^3.4.0",
"cutest": "^0.1.9",
"quill": "^1.3.5",
+ "quill-cursors": "^1.0.2",
"rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-inject": "^2.0.0",