mirror of
https://github.com/cudr/slate-collaborative.git
synced 2024-10-27 20:34:06 +00:00
Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f65ab040ee | ||
|
3b60f2c6c8 | ||
|
a67986995d | ||
|
1a536f2fa4 | ||
|
322b083f68 | ||
|
ef35812723 | ||
|
d141da4430 | ||
|
24dca9a49c | ||
|
e415684d64 | ||
|
2bd7544977 | ||
|
67218fc8ee | ||
|
e3068d0b48 | ||
|
1106bc1724 | ||
|
829dc2a71b | ||
|
d1d3939c6a | ||
|
ba61211cf6 | ||
|
230117694e | ||
|
b68f5afcf9 | ||
|
cc4449e6dd | ||
|
71ab42d5be | ||
|
05e46faf4f | ||
|
ab3c36ab7d | ||
|
5e0ee3e8d9 | ||
|
a9b20ae99d | ||
|
45b8a16ef5 | ||
|
55b1b2ca5a | ||
|
b49cf33464 | ||
|
1fcfae96e3 | ||
|
f5bd03cf27 | ||
|
c40cdda45d | ||
|
e36c4318e2 | ||
|
be1bb1205e | ||
|
73a363c8b3 |
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Device (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version of slate [e.g. 0.58.0]
|
||||
- Version of slate-collaborative
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
98
CHANGELOG.md
Normal file
98
CHANGELOG.md
Normal file
@ -0,0 +1,98 @@
|
||||
### Changelog
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [v0.7.2](https://github.com/cudr/slate-collaborative/compare/v0.7.1...v0.7.2)
|
||||
|
||||
> 18 January 2021
|
||||
|
||||
- fix dependency update [`#50`](https://github.com/cudr/slate-collaborative/pull/50)
|
||||
- Fix split_node missing properties bug. [`#45`](https://github.com/cudr/slate-collaborative/pull/45)
|
||||
- Always call external onChange. [`#43`](https://github.com/cudr/slate-collaborative/pull/43)
|
||||
- Fix setNodes undefined value since automerge does not handle undefined value correctly. [`#49`](https://github.com/cudr/slate-collaborative/pull/49)
|
||||
- Fix destory [`#48`](https://github.com/cudr/slate-collaborative/pull/48)
|
||||
- Fix cursor delete [`#44`](https://github.com/cudr/slate-collaborative/pull/44)
|
||||
- build(deps): bump react from 16.14.0 to 17.0.1 [`#40`](https://github.com/cudr/slate-collaborative/pull/40)
|
||||
- build(deps-dev): bump husky from 3.1.0 to 4.3.6 [`#46`](https://github.com/cudr/slate-collaborative/pull/46)
|
||||
- build(deps): bump @types/node from 12.7.5 to 14.14.6 [`#42`](https://github.com/cudr/slate-collaborative/pull/42)
|
||||
- build(deps-dev): bump ts-jest from 25.5.1 to 26.4.4 [`#41`](https://github.com/cudr/slate-collaborative/pull/41)
|
||||
- build(deps): bump react-dom from 16.14.0 to 17.0.1 [`#39`](https://github.com/cudr/slate-collaborative/pull/39)
|
||||
- build(deps-dev): bump @commitlint/cli from 9.1.2 to 11.0.0 [`#38`](https://github.com/cudr/slate-collaborative/pull/38)
|
||||
- build(deps): bump slate-react from 0.58.3 to 0.59.0 [`#37`](https://github.com/cudr/slate-collaborative/pull/37)
|
||||
- build(deps): bump slate from 0.58.3 to 0.59.0 [`#36`](https://github.com/cudr/slate-collaborative/pull/36)
|
||||
- build(deps): bump faker from 4.1.0 to 5.1.0 [`#35`](https://github.com/cudr/slate-collaborative/pull/35)
|
||||
- build(deps): bump nodemon from 1.19.4 to 2.0.6 [`#34`](https://github.com/cudr/slate-collaborative/pull/34)
|
||||
- Update issue templates [`cc4449e`](https://github.com/cudr/slate-collaborative/commit/cc4449e6dd35fbf36675a5ac5a7bac61222dad06)
|
||||
- feat: nodemon run example [`71ab42d`](https://github.com/cudr/slate-collaborative/commit/71ab42d5bec04b89819f51a85659a93587f1af67)
|
||||
|
||||
#### [v0.7.1](https://github.com/cudr/slate-collaborative/compare/v0.7.0...v0.7.1)
|
||||
|
||||
> 28 October 2020
|
||||
|
||||
- defensive code for when the document sometimes isn't there on server restarts. [`#26`](https://github.com/cudr/slate-collaborative/pull/26)
|
||||
- fix: socket io namespace message broadcast [`ab3c36a`](https://github.com/cudr/slate-collaborative/commit/ab3c36ab7dd7f24059c5d0864735c5892df98028)
|
||||
|
||||
#### [v0.7.0](https://github.com/cudr/slate-collaborative/compare/v0.6.7...v0.7.0)
|
||||
|
||||
> 2 July 2020
|
||||
|
||||
- Preserve external history option [`#22`](https://github.com/cudr/slate-collaborative/pull/22)
|
||||
- Generate auto-changelog [`#21`](https://github.com/cudr/slate-collaborative/pull/21)
|
||||
- feat: take changelog version from bridge package [`45b8a16`](https://github.com/cudr/slate-collaborative/commit/45b8a16ef57e582a617c7f6284de697a90e16030)
|
||||
|
||||
#### [v0.6.7](https://github.com/cudr/slate-collaborative/compare/v0.6.6...v0.6.7)
|
||||
|
||||
> 22 June 2020
|
||||
|
||||
- feat: add license [`f5bd03c`](https://github.com/cudr/slate-collaborative/commit/f5bd03cf27a1c620c69e6823b433963aea84610e)
|
||||
- feat: modify changelog template [`c40cdda`](https://github.com/cudr/slate-collaborative/commit/c40cdda45d478b733f195058ef7b239bbb476aeb)
|
||||
|
||||
#### [v0.6.6](https://github.com/cudr/slate-collaborative/compare/v0.6.5...v0.6.6)
|
||||
|
||||
> 22 June 2020
|
||||
|
||||
- feat: add auto-changelog [`73a363c`](https://github.com/cudr/slate-collaborative/commit/73a363c8b3c0839046c255774580143eee6e1ee8)
|
||||
|
||||
#### [v0.6.5](https://github.com/cudr/slate-collaborative/compare/v0.6.4...v0.6.5)
|
||||
|
||||
> 22 June 2020
|
||||
|
||||
#### [v0.6.4](https://github.com/cudr/slate-collaborative/compare/v0.6.3...v0.6.4)
|
||||
|
||||
> 22 June 2020
|
||||
|
||||
- feat: add auto-changelog [`c66c01a`](https://github.com/cudr/slate-collaborative/commit/c66c01ac07d6e3ca59db765f45ce53868e103f31)
|
||||
- feat: add auto-changelog [`ca8b4b7`](https://github.com/cudr/slate-collaborative/commit/ca8b4b741c79381e41319bf58a6980a30128be67)
|
||||
|
||||
#### [v0.6.3](https://github.com/cudr/slate-collaborative/compare/v0.5.1...v0.6.3)
|
||||
|
||||
> 22 June 2020
|
||||
|
||||
- Implement link editor [`#20`](https://github.com/cudr/slate-collaborative/pull/20)
|
||||
- Missing query argument in nspMiddleware [`#16`](https://github.com/cudr/slate-collaborative/pull/16)
|
||||
- feat: add onError cb [`#15`](https://github.com/cudr/slate-collaborative/pull/15)
|
||||
- Changed the backend socket config types fom Element[] to Node[] and m… [`#14`](https://github.com/cudr/slate-collaborative/pull/14)
|
||||
- Fix typing of SyncValue. [`#12`](https://github.com/cudr/slate-collaborative/pull/12)
|
||||
- feat: update to slate 0.58 && fix site build [`6adf408`](https://github.com/cudr/slate-collaborative/commit/6adf4082dc9f81c52c779e23e6bbb8ebe6ef5e9d)
|
||||
- feat: update site styles [`aa2255a`](https://github.com/cudr/slate-collaborative/commit/aa2255a03c605fbb6303298ef1ab462a088239d7)
|
||||
- feat: add auto-changelog [`ff77059`](https://github.com/cudr/slate-collaborative/commit/ff77059a49402931e2d87a6e9b6d11d7549cb4c4)
|
||||
|
||||
#### [v0.5.1](https://github.com/cudr/slate-collaborative/compare/v0.5.0...v0.5.1)
|
||||
|
||||
> 10 May 2020
|
||||
|
||||
- feat: update to slate 0.5x [`#10`](https://github.com/cudr/slate-collaborative/pull/10)
|
||||
- chore(release): 0.5.0 [`a88c5c0`](https://github.com/cudr/slate-collaborative/commit/a88c5c0ec967eeb107d2973f9c72537c537c830a)
|
||||
- chore(release): 0.5.1 [`1711f76`](https://github.com/cudr/slate-collaborative/commit/1711f76f9b802c7d8369936a457f434d4b1f192b)
|
||||
|
||||
#### v0.5.0
|
||||
|
||||
> 10 May 2020
|
||||
|
||||
- feat: refactoring types && handle annotation ops [`#6`](https://github.com/cudr/slate-collaborative/pull/6)
|
||||
- feat: travis-ci [`#3`](https://github.com/cudr/slate-collaborative/pull/3)
|
||||
- Inner annotations [`#2`](https://github.com/cudr/slate-collaborative/pull/2)
|
||||
- feat: mark data [`#1`](https://github.com/cudr/slate-collaborative/pull/1)
|
||||
- feat: update to slate 0.5x [`a557a58`](https://github.com/cudr/slate-collaborative/commit/a557a58bda775107a37054bf4a8a697569308d48)
|
||||
- initial commit [`a817eb1`](https://github.com/cudr/slate-collaborative/commit/a817eb1cebf296495099e67a7939e7a09f0e5b48)
|
||||
- feat: extract CollaborationBackend [`9a59a0a`](https://github.com/cudr/slate-collaborative/commit/9a59a0ac34754f89dd7d8f7943b7073ad042e8bb)
|
@ -31,6 +31,7 @@ Check [detailed example](https://github.com/cudr/slate-collaborative/blob/master
|
||||
onConnect?: () => void // connect callback
|
||||
onDisconnect?: () => void // disconnect callback
|
||||
onError?: (reason: string) => void // error callback
|
||||
preserveExternalHistory?: boolean // preserve slate-history operations form other clients
|
||||
}
|
||||
```
|
||||
|
||||
|
32
changelog-template.hbs
Normal file
32
changelog-template.hbs
Normal file
@ -0,0 +1,32 @@
|
||||
### Changelog
|
||||
|
||||
{{#unless options.hideCredit}}
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
{{/unless}}
|
||||
|
||||
{{#each releases}}
|
||||
{{#if href}}
|
||||
###{{#unless major}}#{{/unless}} [{{title}}]({{href}})
|
||||
{{else}}
|
||||
#### {{title}}
|
||||
{{/if}}
|
||||
|
||||
{{#if tag}}
|
||||
> {{niceDate}}
|
||||
{{/if}}
|
||||
|
||||
{{#if summary}}
|
||||
{{summary}}
|
||||
{{/if}}
|
||||
|
||||
{{#each merges}}
|
||||
- {{#if commit.breaking}}**Breaking change:** {{/if}}{{message}}{{#if href}} [`#{{id}}`]({{href}}){{/if}}
|
||||
{{/each}}
|
||||
{{#each fixes}}
|
||||
- {{#if commit.breaking}}**Breaking change:** {{/if}}{{commit.subject}}{{#each fixes}}{{#if href}} [`#{{id}}`]({{href}}){{/if}}{{/each}}
|
||||
{{/each}}
|
||||
{{#each commits}}
|
||||
- {{#if breaking}}**Breaking change:** {{/if}}{{subject}}{{#if href}} [`{{shorthash}}`]({{href}}){{/if}}
|
||||
{{/each}}
|
||||
|
||||
{{/each}}
|
3
commitlint.config.js
Normal file
3
commitlint.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional']
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"lerna": "2.7.1",
|
||||
"version": "0.5.0",
|
||||
"version": "0.7.2",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true
|
||||
}
|
||||
|
13
package.json
13
package.json
@ -1,11 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "0.6.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Slate collaborative plugin & microservice",
|
||||
"scripts": {
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"changelog": "auto-changelog -p ./packages/bridge/package.json --template changelog-template.hbs && git add CHANGELOG.md",
|
||||
"clean": "rimraf ./packages/**/lib/ && rimraf ./packages/**/tsconfig.tsbuildinfo && lerna clean --yes",
|
||||
"release": "yarn prebuild && yarn build && lerna publish from-package",
|
||||
"release": "yarn prebuild && yarn build && lerna version && lerna publish from-package && yarn changelog",
|
||||
"deploy:site": "git subtree push --prefix packages/example heroku master",
|
||||
"dev": "lerna run --stream build:js && concurrently \"yarn watch\" \"lerna run dev --stream\"",
|
||||
"build": "lerna run build:module --stream",
|
||||
@ -26,7 +27,8 @@
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -36,8 +38,11 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^11.0.0",
|
||||
"@commitlint/config-conventional": "^9.0.1",
|
||||
"auto-changelog": "^2.1.0",
|
||||
"concurrently": "^4.1.2",
|
||||
"husky": "^3.0.5",
|
||||
"husky": "^4.3.6",
|
||||
"lerna": "^3.20.2",
|
||||
"lint-staged": "^9.2.5",
|
||||
"prettier": "^1.18.2",
|
||||
|
9
packages/backend/License.md
Normal file
9
packages/backend/License.md
Normal file
@ -0,0 +1,9 @@
|
||||
The MIT License
|
||||
|
||||
Copyright © 2019–2020, [George Kukushin](https://github.com/cudr)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@slate-collaborative/backend",
|
||||
"version": "0.6.2",
|
||||
"version": "0.7.2",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
@ -26,12 +26,12 @@
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@slate-collaborative/bridge": "0.6.1",
|
||||
"@slate-collaborative/bridge": "^0.7.2",
|
||||
"@types/lodash": "^4.14.150",
|
||||
"@types/socket.io": "^2.1.4",
|
||||
"automerge": "0.14.0",
|
||||
"lodash": "^4.17.15",
|
||||
"slate": "0.58.3",
|
||||
"slate": "0.59.0",
|
||||
"socket.io": "^2.3.0",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
|
@ -31,13 +31,14 @@ export default class SocketIOCollaboration {
|
||||
private io: SocketIO.Server
|
||||
private options: SocketIOCollaborationOptions
|
||||
private backend: AutomergeBackend
|
||||
private autoSaveDoc: (docId: string) => void
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
||||
constructor(options: SocketIOCollaborationOptions) {
|
||||
this.io = io(options.entry, options.connectOpts)
|
||||
this.io = io(options.entry as Server, options.connectOpts)
|
||||
|
||||
this.backend = new AutomergeBackend()
|
||||
|
||||
@ -45,6 +46,15 @@ export default class SocketIOCollaboration {
|
||||
|
||||
this.configure()
|
||||
|
||||
/**
|
||||
* Save document with throttle
|
||||
*/
|
||||
this.autoSaveDoc = throttle(
|
||||
async (docId: string) =>
|
||||
this.backend.getDocument(docId) && this.saveDocument(docId),
|
||||
this.options?.saveFrequency || 2000
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@ -108,24 +118,24 @@ export default class SocketIOCollaboration {
|
||||
const { name } = socket.nsp
|
||||
|
||||
this.backend.createConnection(id, ({ type, payload }: CollabAction) => {
|
||||
socket.emit('msg', { type, payload: { id: conn.id, ...payload } })
|
||||
if (payload.docId === name) {
|
||||
socket.emit('msg', { type, payload: { id: conn.id, ...payload } })
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('msg', this.onMessage(id, name))
|
||||
|
||||
socket.on('disconnect', this.onDisconnect(id, socket))
|
||||
|
||||
socket.join(id, () => {
|
||||
const doc = this.backend.getDocument(name)
|
||||
const doc = this.backend.getDocument(name)
|
||||
|
||||
socket.emit('msg', {
|
||||
type: 'document',
|
||||
payload: Automerge.save<SyncDoc>(doc)
|
||||
})
|
||||
|
||||
this.backend.openConnection(id)
|
||||
socket.emit('msg', {
|
||||
type: 'document',
|
||||
payload: Automerge.save<SyncDoc>(doc)
|
||||
})
|
||||
|
||||
this.backend.openConnection(id)
|
||||
|
||||
this.garbageCursors(name)
|
||||
}
|
||||
|
||||
@ -148,16 +158,6 @@ export default class SocketIOCollaboration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save document with throttle
|
||||
*/
|
||||
|
||||
private autoSaveDoc = throttle(
|
||||
async (docId: string) =>
|
||||
this.backend.getDocument(docId) && this.saveDocument(docId),
|
||||
this.options?.saveFrequency || 2000
|
||||
)
|
||||
|
||||
/**
|
||||
* Save document
|
||||
*/
|
||||
@ -183,6 +183,8 @@ export default class SocketIOCollaboration {
|
||||
*/
|
||||
|
||||
private onDisconnect = (id: string, socket: SocketIO.Socket) => async () => {
|
||||
socket.leave(socket.nsp.name)
|
||||
|
||||
this.backend.closeConnection(id)
|
||||
|
||||
await this.saveDocument(socket.nsp.name)
|
||||
@ -219,7 +221,7 @@ export default class SocketIOCollaboration {
|
||||
garbageCursors = (nsp: string) => {
|
||||
const doc = this.backend.getDocument(nsp)
|
||||
|
||||
if (!doc.cursors) return
|
||||
if (!doc || !doc.cursors) return
|
||||
|
||||
const namespace = this.io.of(nsp)
|
||||
|
||||
|
9
packages/bridge/License.md
Normal file
9
packages/bridge/License.md
Normal file
@ -0,0 +1,9 @@
|
||||
The MIT License
|
||||
|
||||
Copyright © 2019–2020, [George Kukushin](https://github.com/cudr)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@slate-collaborative/bridge",
|
||||
"version": "0.6.1",
|
||||
"version": "0.7.2",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
@ -26,7 +26,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"automerge": "0.14.0",
|
||||
"slate": "0.58.3",
|
||||
"slate": "0.59.0",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -39,7 +39,7 @@
|
||||
"@babel/preset-typescript": "^7.6.0",
|
||||
"@types/jest": "^24.9.0",
|
||||
"jest": "^24.9.0",
|
||||
"ts-jest": "^25.4.0"
|
||||
"ts-jest": "^26.4.4"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
|
@ -9,7 +9,12 @@ const setNode = (doc: SyncValue, op: SetNodeOperation): SyncValue => {
|
||||
const { newProperties } = op
|
||||
|
||||
for (let key in newProperties) {
|
||||
node[key] = newProperties[key]
|
||||
const value = newProperties[key]
|
||||
if (value !== undefined) {
|
||||
node[key] = value
|
||||
} else {
|
||||
delete node[key]
|
||||
}
|
||||
}
|
||||
|
||||
return doc
|
||||
|
@ -8,7 +8,10 @@ const splitNode = (doc: SyncValue, op: SplitNodeOperation): SyncValue => {
|
||||
const [parent, index]: [any, number] = getParent(doc, op.path)
|
||||
|
||||
const target = getChildren(parent)[index]
|
||||
const inject = cloneNode(target)
|
||||
const inject = {
|
||||
...cloneNode(target),
|
||||
...op.properties
|
||||
}
|
||||
|
||||
if (target.text) {
|
||||
target.text.length > op.position &&
|
||||
|
@ -9,7 +9,9 @@ export const insertText = (
|
||||
): SyncValue => {
|
||||
const node = getTarget(doc, op.path)
|
||||
|
||||
node.text.insertAt(op.offset, ...op.text.split(''))
|
||||
const offset = Math.min(node.text.length, op.offset)
|
||||
|
||||
node.text.insertAt(offset, ...op.text.split(''))
|
||||
|
||||
return doc
|
||||
}
|
||||
@ -20,7 +22,9 @@ export const removeText = (
|
||||
): SyncValue => {
|
||||
const node = getTarget(doc, op.path)
|
||||
|
||||
node.text.deleteAt(op.offset, op.text.length)
|
||||
const offset = Math.min(node.text.length, op.offset)
|
||||
|
||||
node.text.deleteAt(offset, op.text.length)
|
||||
|
||||
return doc
|
||||
}
|
||||
|
@ -54,15 +54,13 @@ describe('convert operations to slatejs model', () => {
|
||||
{
|
||||
type: 'remove_node',
|
||||
path: [1],
|
||||
node: {
|
||||
text: '*'
|
||||
}
|
||||
node: createNode('paragraph', 'hello twice!')
|
||||
},
|
||||
{
|
||||
type: 'remove_node',
|
||||
path: [0, 0],
|
||||
node: {
|
||||
text: '*'
|
||||
children: []
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as Automerge from 'automerge'
|
||||
|
||||
const createByType = (type: any) =>
|
||||
const createByType = (type: Automerge.CollectionType) =>
|
||||
type === 'map' ? {} : type === 'list' ? [] : ''
|
||||
|
||||
const opCreate = ({ obj, type }: Automerge.Diff, [map, ops]: any) => {
|
||||
|
@ -5,6 +5,8 @@ import opRemove from './remove'
|
||||
import opSet from './set'
|
||||
import opCreate from './create'
|
||||
|
||||
import { toJS } from '../utils'
|
||||
|
||||
import { SyncDoc } from '../model'
|
||||
|
||||
const byAction = {
|
||||
@ -32,7 +34,9 @@ const toSlateOp = (ops: Automerge.Diff[], doc: SyncDoc) => {
|
||||
[]
|
||||
])
|
||||
|
||||
return defer.flatMap(op => op(tempTree, doc)).filter(op => op)
|
||||
const tempDoc = toJS(doc)
|
||||
|
||||
return defer.flatMap(op => op(tempTree, tempDoc)).filter(op => op)
|
||||
}
|
||||
|
||||
export { toSlateOp }
|
||||
|
@ -1,33 +1,74 @@
|
||||
import * as Automerge from 'automerge'
|
||||
import { Element } from 'slate'
|
||||
|
||||
import { toSlatePath, toJS } from '../utils'
|
||||
import { getTarget } from '../path'
|
||||
|
||||
const removeTextOp = ({ index, path }: Automerge.Diff) => () => ({
|
||||
type: 'remove_text',
|
||||
path: toSlatePath(path).slice(0, path?.length),
|
||||
offset: index,
|
||||
text: '*',
|
||||
marks: []
|
||||
})
|
||||
const removeTextOp = (op: Automerge.Diff) => (map: any, doc: Element) => {
|
||||
try {
|
||||
const { index, path, obj } = op
|
||||
|
||||
const removeNodeOp = ({ index, obj, path }: Automerge.Diff) => (
|
||||
map: any,
|
||||
doc: any
|
||||
) => {
|
||||
const slatePath = toSlatePath(path)
|
||||
if (!map.hasOwnProperty(obj)) {
|
||||
const target = getTarget(doc, [...slatePath, index] as any)
|
||||
const slatePath = toSlatePath(path).slice(0, path?.length)
|
||||
|
||||
map[obj] = target
|
||||
}
|
||||
let node = map[obj]
|
||||
|
||||
return {
|
||||
type: 'remove_node',
|
||||
path: slatePath.length ? slatePath.concat(index) : [index],
|
||||
node: {
|
||||
text: '*'
|
||||
try {
|
||||
node = getTarget(doc, slatePath)
|
||||
} catch (e) {
|
||||
console.error(e, slatePath, op, map, toJS(doc))
|
||||
}
|
||||
|
||||
if (typeof index !== 'number') return
|
||||
|
||||
const text = node?.text?.[index] || '*'
|
||||
|
||||
if (node) {
|
||||
node.text = node?.text ? (node.text.slice(0, index) + node.text.slice(index + 1)) : ''
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'remove_text',
|
||||
path: slatePath,
|
||||
offset: index,
|
||||
text,
|
||||
marks: []
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e, op, map, toJS(doc))
|
||||
}
|
||||
}
|
||||
|
||||
const removeNodeOp = (op: Automerge.Diff) => (
|
||||
map: any,
|
||||
doc: Element
|
||||
) => {
|
||||
try {
|
||||
const { index, obj, path } = op
|
||||
|
||||
const slatePath = toSlatePath(path)
|
||||
|
||||
const parent = getTarget(doc, slatePath)
|
||||
const target = parent?.children?.[index as number] || parent?.[index as number] || { children: [] }
|
||||
|
||||
if (!target) {
|
||||
throw new TypeError('Target is not found!')
|
||||
}
|
||||
|
||||
if (!map.hasOwnProperty(obj)) {
|
||||
map[obj] = target
|
||||
}
|
||||
|
||||
if (!Number.isInteger(index)) {
|
||||
throw new TypeError('Index is not a number')
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'remove_node',
|
||||
path: slatePath.length ? slatePath.concat(index) : [index],
|
||||
node: target
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e, op, map, toJS(doc))
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +79,8 @@ const opRemove = (op: Automerge.Diff, [map, ops]: any) => {
|
||||
if (
|
||||
map.hasOwnProperty(obj) &&
|
||||
typeof map[obj] !== 'string' &&
|
||||
type !== 'text'
|
||||
type !== 'text' &&
|
||||
map?.obj?.length
|
||||
) {
|
||||
map[obj].splice(index, 1)
|
||||
|
||||
@ -49,7 +91,7 @@ const opRemove = (op: Automerge.Diff, [map, ops]: any) => {
|
||||
|
||||
const key = path[path.length - 1]
|
||||
|
||||
if (key === 'cursors') return [map, ops]
|
||||
if (key === 'cursors' || op.key === 'cursors') return [map, ops]
|
||||
|
||||
const fn = key === 'text' ? removeTextOp : removeNodeOp
|
||||
|
||||
|
@ -10,10 +10,10 @@ const setDataOp = (
|
||||
type: 'set_node',
|
||||
path: toSlatePath(path),
|
||||
properties: {
|
||||
[key]: Automerge.getObjectById(doc, obj)?.[key]
|
||||
[key]: toJS(Automerge.getObjectById(doc, obj)?.[key])
|
||||
},
|
||||
newProperties: {
|
||||
[key]: value
|
||||
[key]: map?.[value] || value
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,7 +22,7 @@ const opSet = (op: Automerge.Diff, [map, ops]: any, doc: any) => {
|
||||
const { link, value, path, obj, key } = op
|
||||
|
||||
try {
|
||||
if (path && path[0] !== 'cursors') {
|
||||
if (path && path.length && path[0] !== 'cursors') {
|
||||
ops.push(setDataOp(op, doc))
|
||||
} else if (map[obj]) {
|
||||
map[obj][key as any] = link ? map[value] : value
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Node, Path } from 'slate'
|
||||
import { Element, Node, Path } from 'slate'
|
||||
|
||||
import { SyncValue } from '../model'
|
||||
|
||||
export const isTree = (node: Node): boolean => Boolean(node?.children)
|
||||
|
||||
export const getTarget = (doc: SyncValue, path: Path) => {
|
||||
export const getTarget = (doc: SyncValue | Element, path: Path) => {
|
||||
const iterate = (current: any, idx: number) => {
|
||||
if (!(isTree(current) || current[idx])) {
|
||||
throw new TypeError(
|
||||
@ -30,7 +30,7 @@ export const getParentPath = (
|
||||
}
|
||||
|
||||
export const getParent = (
|
||||
doc: SyncValue,
|
||||
doc: SyncValue | Element,
|
||||
path: Path,
|
||||
level = 1
|
||||
): [any, number] => {
|
||||
|
9
packages/client/License.md
Normal file
9
packages/client/License.md
Normal file
@ -0,0 +1,9 @@
|
||||
The MIT License
|
||||
|
||||
Copyright © 2019–2020, [George Kukushin](https://github.com/cudr)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@slate-collaborative/client",
|
||||
"version": "0.6.2",
|
||||
"version": "0.7.2",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
@ -26,9 +26,10 @@
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@slate-collaborative/bridge": "0.6.1",
|
||||
"@slate-collaborative/bridge": "^0.7.2",
|
||||
"automerge": "0.14.0",
|
||||
"slate": "0.58.3",
|
||||
"slate": "0.59.0",
|
||||
"slate-history": "0.58.3",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Automerge from 'automerge'
|
||||
|
||||
import { Editor, Operation } from 'slate'
|
||||
import { HistoryEditor } from 'slate-history'
|
||||
|
||||
import {
|
||||
toJS,
|
||||
@ -111,7 +112,8 @@ export const AutomergeEditor = {
|
||||
applyOperation: (
|
||||
e: AutomergeEditor,
|
||||
docId: string,
|
||||
data: Automerge.Message
|
||||
data: Automerge.Message,
|
||||
preserveExternalHistory?: boolean
|
||||
) => {
|
||||
try {
|
||||
const current: any = e.docSet.getDoc(docId)
|
||||
@ -126,12 +128,18 @@ export const AutomergeEditor = {
|
||||
e.isRemote = true
|
||||
|
||||
Editor.withoutNormalizing(e, () => {
|
||||
slateOps.forEach((o: Operation) => {
|
||||
e.apply(o)
|
||||
})
|
||||
})
|
||||
if (HistoryEditor.isHistoryEditor(e) && !preserveExternalHistory) {
|
||||
HistoryEditor.withoutSaving(e, () => {
|
||||
slateOps.forEach((o: Operation) => {
|
||||
e.apply(o)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
slateOps.forEach((o: Operation) => e.apply(o))
|
||||
}
|
||||
|
||||
e.onCursor && e.onCursor(updated.cursors)
|
||||
e.onCursor && e.onCursor(updated.cursors)
|
||||
})
|
||||
|
||||
Promise.resolve().then(_ => (e.isRemote = false))
|
||||
}
|
||||
@ -143,8 +151,12 @@ export const AutomergeEditor = {
|
||||
garbageCursor: (e: AutomergeEditor, docId: string) => {
|
||||
const doc = e.docSet.getDoc(docId)
|
||||
|
||||
if (!doc) {
|
||||
return
|
||||
}
|
||||
|
||||
const changed = Automerge.change<SyncDoc>(doc, (d: any) => {
|
||||
delete d.cusors
|
||||
delete d.cursors
|
||||
})
|
||||
|
||||
e.onCursor && e.onCursor(null)
|
||||
|
@ -9,6 +9,7 @@ import { CursorData, CollabAction } from '@slate-collaborative/bridge'
|
||||
export interface AutomergeOptions {
|
||||
docId: string
|
||||
cursorData?: CursorData
|
||||
preserveExternalHistory?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,7 +24,7 @@ const withAutomerge = <T extends Editor>(
|
||||
|
||||
const { onChange } = e
|
||||
|
||||
const { docId, cursorData } = options || {}
|
||||
const { docId, cursorData, preserveExternalHistory } = options || {}
|
||||
|
||||
e.docSet = new Automerge.DocSet()
|
||||
|
||||
@ -76,8 +77,6 @@ const withAutomerge = <T extends Editor>(
|
||||
}
|
||||
|
||||
onChange()
|
||||
|
||||
// console.log('e', e.children)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,7 +96,7 @@ const withAutomerge = <T extends Editor>(
|
||||
e.receiveOperation = data => {
|
||||
if (docId !== data.docId) return
|
||||
|
||||
AutomergeEditor.applyOperation(e, docId, data)
|
||||
AutomergeEditor.applyOperation(e, docId, data, preserveExternalHistory)
|
||||
}
|
||||
|
||||
return e
|
||||
|
@ -122,6 +122,8 @@ const withSocketIO = <T extends AutomergeEditor>(
|
||||
*/
|
||||
|
||||
e.destroy = () => {
|
||||
e.socket.removeListener('disconnect')
|
||||
|
||||
e.socket.close()
|
||||
|
||||
e.closeConnection()
|
||||
|
@ -1,36 +1,28 @@
|
||||
{
|
||||
"name": "@slate-collaborative/example",
|
||||
"version": "0.6.0",
|
||||
"version": "0.7.2",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@emotion/core": "^10.0.17",
|
||||
"@emotion/styled": "^10.0.17",
|
||||
"@slate-collaborative/backend": "^0.6.2",
|
||||
"@slate-collaborative/client": "^0.6.2",
|
||||
"@types/faker": "^4.1.5",
|
||||
"@types/is-url": "^1.2.28",
|
||||
"@types/jest": "24.0.18",
|
||||
"@types/node": "12.7.5",
|
||||
"@types/randomcolor": "^0.5.4",
|
||||
"@types/react-dom": "^16.9.6",
|
||||
"@slate-collaborative/backend": "^0.7.2",
|
||||
"@slate-collaborative/client": "^0.7.2",
|
||||
"concurrently": "^4.1.2",
|
||||
"cross-env": "^6.0.3",
|
||||
"express": "^4.17.1",
|
||||
"faker": "^4.1.0",
|
||||
"is-url": "^1.2.4",
|
||||
"lodash": "^4.17.15",
|
||||
"nodemon": "^1.19.2",
|
||||
"nodemon": "^2.0.6",
|
||||
"randomcolor": "^0.5.4",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-scripts": "3.1.2",
|
||||
"slate": "0.58.3",
|
||||
"slate": "0.59.0",
|
||||
"slate-history": "0.58.3",
|
||||
"slate-react": "0.58.3",
|
||||
"typescript": "^3.8.3"
|
||||
"slate-react": "0.59.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"start": "nodemon server.js",
|
||||
"start:cra": "react-scripts start",
|
||||
"prebuild": "cp -f ./tsconfig.production.json ./tsconfig.json",
|
||||
"build": "cross-env NODE_ENV=production && react-scripts build",
|
||||
@ -54,5 +46,15 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": "12.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/faker": "^4.1.5",
|
||||
"@types/is-url": "^1.2.28",
|
||||
"@types/jest": "24.0.18",
|
||||
"@types/node": "14.14.6",
|
||||
"@types/randomcolor": "^0.5.4",
|
||||
"@types/react-dom": "^16.9.6",
|
||||
"faker": "^5.1.0",
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user