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",