Add real-time collab support to code editor
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Garrett Mills 2021-04-22 10:49:31 -05:00
parent 7be3bf5259
commit 48c045e952
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
6 changed files with 647 additions and 2 deletions

View File

@ -22,6 +22,9 @@
"@angular/router": "~10.1.5", "@angular/router": "~10.1.5",
"@angular/service-worker": "~10.1.5", "@angular/service-worker": "~10.1.5",
"@circlon/angular-tree-component": "^10.0.0", "@circlon/angular-tree-component": "^10.0.0",
"@ckeditor/ckeditor5-angular": "^2.0.1",
"@ckeditor/ckeditor5-build-decoupled-document": "^27.0.0",
"@convergencelabs/monaco-collab-ext": "^0.3.2",
"@fortawesome/fontawesome-free": "^5.15.1", "@fortawesome/fontawesome-free": "^5.15.1",
"@ionic-native/core": "^5.0.0", "@ionic-native/core": "^5.0.0",
"@ionic-native/splash-screen": "^5.0.0", "@ionic-native/splash-screen": "^5.0.0",

View File

@ -8,6 +8,9 @@ dependencies:
'@angular/router': 10.1.6_2d3b53e7e463c932a6e73e0760b7a0a2 '@angular/router': 10.1.6_2d3b53e7e463c932a6e73e0760b7a0a2
'@angular/service-worker': 10.1.6_04f723395c0c28a9d9b8a4ace7178ad2 '@angular/service-worker': 10.1.6_04f723395c0c28a9d9b8a4ace7178ad2
'@circlon/angular-tree-component': 10.0.2_04f723395c0c28a9d9b8a4ace7178ad2 '@circlon/angular-tree-component': 10.0.2_04f723395c0c28a9d9b8a4ace7178ad2
'@ckeditor/ckeditor5-angular': 2.0.1_11b9a698fa893a2ce33633beb1aae14b
'@ckeditor/ckeditor5-build-decoupled-document': 27.0.0
'@convergencelabs/monaco-collab-ext': 0.3.2
'@fortawesome/fontawesome-free': 5.15.2 '@fortawesome/fontawesome-free': 5.15.2
'@ionic-native/core': 5.31.1_rxjs@6.6.3 '@ionic-native/core': 5.31.1_rxjs@6.6.3
'@ionic-native/splash-screen': 5.31.1_fba2ce20a1445ab520b44b573ed379a0 '@ionic-native/splash-screen': 5.31.1_fba2ce20a1445ab520b44b573ed379a0
@ -1421,6 +1424,378 @@ packages:
'@angular/core': '>=10.0.0 <11.0.0' '@angular/core': '>=10.0.0 <11.0.0'
resolution: resolution:
integrity: sha512-N8KyIQ89fGEO8OKYYgFtY/PbPhHqs4DK5kNPmpJt4KPssvQMF1gP6m+RGVDKlDVH933aOPsrHQax87Fk6dI8gA== integrity: sha512-N8KyIQ89fGEO8OKYYgFtY/PbPhHqs4DK5kNPmpJt4KPssvQMF1gP6m+RGVDKlDVH933aOPsrHQax87Fk6dI8gA==
/@ckeditor/ckeditor5-adapter-ckfinder/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-2JzedLntHRw2ChQ54tB9pk1XFH4VzFPJLMJXhE3CP2+ANiIKZZTHodcQ7R2BOosIpySQOEppjfi1emZ6AgcLRg==
/@ckeditor/ckeditor5-alignment/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-MEXslAyeLmRwbRicOhIKmdvfreXkorwYEYMTDhJaOO3gll/mqDBbn0ijNsCOm4QgXUT6qqK2sOhxGRL3cDuMcQ==
/@ckeditor/ckeditor5-angular/2.0.1_11b9a698fa893a2ce33633beb1aae14b:
dependencies:
'@angular/common': 10.1.6_@angular+core@10.1.6+rxjs@6.6.3
'@angular/core': 10.1.6_rxjs@6.6.3+zone.js@0.10.3
'@angular/forms': 10.1.6_2d3b53e7e463c932a6e73e0760b7a0a2
'@ckeditor/ckeditor5-watchdog': 23.1.0
tslib: 2.2.0
dev: false
peerDependencies:
'@angular/common': '>=9.0.0'
'@angular/core': '>=9.0.0'
'@angular/forms': '>=9.0.0'
resolution:
integrity: sha512-mK7HI3DAHiU1UqWq+9BPZi7n5hqO3jZpMNBymOeCRzraln4eQ+6/Ne3lgUyea0XawEdRmtjD64SIzH8MotPjNQ==
/@ckeditor/ckeditor5-autoformat/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-SirBT1Reu2I9yXSLrcL4IZDecux0pNLfYdZVfz1PIXr99LOYvF1iqyWdo0dLEj5xEGf77OPoiIIhnOQJA8fZzA==
/@ckeditor/ckeditor5-basic-styles/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-idmD5huRKDFRe1ToyIj5RrnVde00fnEteyVnUWLZPYZr+Y2aye1KFWthmycqKIdNhCXy60ydnhXjy0tVuwHlmw==
/@ckeditor/ckeditor5-block-quote/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-sUSkhEnKDeAjB8EXvrt3zI+pYdnUg228t2Uoe6A0VCeaSynHn+YF9bHL8XSdEMaD1UdDcdRhtNhJL+d+cEdOqA==
/@ckeditor/ckeditor5-build-decoupled-document/27.0.0:
dependencies:
'@ckeditor/ckeditor5-adapter-ckfinder': 27.0.0
'@ckeditor/ckeditor5-alignment': 27.0.0
'@ckeditor/ckeditor5-autoformat': 27.0.0
'@ckeditor/ckeditor5-basic-styles': 27.0.0
'@ckeditor/ckeditor5-block-quote': 27.0.0
'@ckeditor/ckeditor5-ckfinder': 27.0.0
'@ckeditor/ckeditor5-cloud-services': 27.0.0
'@ckeditor/ckeditor5-easy-image': 27.0.0
'@ckeditor/ckeditor5-editor-decoupled': 27.0.0
'@ckeditor/ckeditor5-essentials': 27.0.0
'@ckeditor/ckeditor5-font': 27.0.0
'@ckeditor/ckeditor5-heading': 27.0.0
'@ckeditor/ckeditor5-image': 27.0.0
'@ckeditor/ckeditor5-indent': 27.0.0
'@ckeditor/ckeditor5-link': 27.0.0
'@ckeditor/ckeditor5-list': 27.0.0
'@ckeditor/ckeditor5-media-embed': 27.0.0
'@ckeditor/ckeditor5-paragraph': 27.0.0
'@ckeditor/ckeditor5-paste-from-office': 27.0.0
'@ckeditor/ckeditor5-table': 27.0.0
'@ckeditor/ckeditor5-typing': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-2xVXA1eZ99kMwjfrcWtXYLXGSDObmyQOaXWuzYXWaBgGY5mYL4xJtaFP4Jn/IZYShFqu9Wc43nnh3EjnxegfHw==
/@ckeditor/ckeditor5-ckfinder/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-TyuMYTUv4eiy5dbaxChgn3kaptZWFlnTWOx3CIUPcpURt+h40HFRSANfmOPeKag4COXJaF/0MnmRe/QPJvaNbw==
/@ckeditor/ckeditor5-clipboard/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
'@ckeditor/ckeditor5-widget': 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-oNLLjPWFoTIqdf6BOtKBDu0qUQiIia5TM6acxi5DKx5YdXnwg1GozxYa4x590EhUVIDFe6i0JuZbkALQ2tBI5g==
/@ckeditor/ckeditor5-cloud-services/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-IXc8rOAZoITNyl5c46M9/eVusKQYWXsFojxBvI9WlpxtxIRhXCge2grDyEg/rOeLBt8eJxJxIkuNDbwqMXcAKA==
/@ckeditor/ckeditor5-core/27.0.0:
dependencies:
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-0dtV2eREe3mh1vqG8x4cIYCwFthzA5aOvRdaIQSj6T6JuBR9lO2IiniOpR0CAsiIgpAM9vmggah+Knngbe2gEA==
/@ckeditor/ckeditor5-easy-image/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-RqPJI5pkqaSgDcSCEm47eokteTgniLZFD4j/Y7F7v5tTvUoinn5LaKGv8DttquA4OPiF9kq2h3ZadqRGTpUuYQ==
/@ckeditor/ckeditor5-editor-decoupled/27.0.0:
dependencies:
ckeditor5: 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-aOa2zM64cSyJoigoHeWqAVFyqtrgUey4vaTU7uAvCW/JiIaJwFKyrRUIyrMLRE355AJH7Y7vNWUCmgV+mXMN1w==
/@ckeditor/ckeditor5-engine/27.0.0:
dependencies:
'@ckeditor/ckeditor5-utils': 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-pOOf155t4HY9PFqZbXcEZf/M/foDze6ht60v9QNfBXQ62JNFCbfVm3R8EeFvJ7eQ1xuONx1CmvNbw3he/Ow2IQ==
/@ckeditor/ckeditor5-enter/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-SBfztQEvtpWBf9JZ51ERwjiHBjGfVosOzyMIxLz010HXwswuuPY9NA2nLkYf534Vyu4Y4iPhMv5lgy80XyP/TQ==
/@ckeditor/ckeditor5-essentials/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-yKHiPrCq9t1KysPIoHgth84jYpI4eAeNPrW87/Maauve/Vxir4JyYAwK6hfO6yNmty6h0LAu4M06orABDMh9DA==
/@ckeditor/ckeditor5-font/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-VLmELvzjRMq/pDTfpzQ8dtDuIWmWYe6Y3PuUtHILWyq7BZy8/CKF4Pgd8bhateKVUXezcBFOSxZcIGSPoCGnoA==
/@ckeditor/ckeditor5-heading/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-f+tIYVc05GxM4Y4FIt6NicvkMpF3pfMCnEksYN2A5eir9p7Tpfn5yvgcdDyCBpD69WoHP9IPQNYuqbfVp/7jMA==
/@ckeditor/ckeditor5-image/27.0.0:
dependencies:
'@ckeditor/ckeditor5-ui': 27.0.0
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-N/t/UrGl4eFIpbgtzGIzZDDl1HDBWYpDRFrpieR34QH2A4ZHCN6pO2688pXQlWVfcIacFmJeaNwE0hj/6TZb2g==
/@ckeditor/ckeditor5-indent/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-JKfuLis9zstH+w5tNbYrDe/4nOjZJOgzjjlrlHFLy4pk8I9trDS0mUga89FB9gGL/dBJvmmTU2s5skHlzHJLNA==
/@ckeditor/ckeditor5-link/27.0.0:
dependencies:
'@ckeditor/ckeditor5-ui': 27.0.0
ckeditor5: 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-KK9aRG0bjUGRc1sf5PA7j5xD19Gcr/miA2Zwv/SSNq35sJhPoHchfK9t+BOEZvJU/wY53IeUPcf4M6yZ2J6KLw==
/@ckeditor/ckeditor5-list/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-mIU06LeVahGhQ93wYKwEZcxA+YP8a/OzA3hDBwluqR+9hWGPSttDeD0t+JDaX4HCefVj0f9BvZvkWwRBZeB4nw==
/@ckeditor/ckeditor5-media-embed/27.0.0:
dependencies:
'@ckeditor/ckeditor5-ui': 27.0.0
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-j1W0qKy/+v4E33z8nZgcAtBiftvxNQUWU9VlaJODNbX+qGV4ZucLHeA1FOzV3AQlwrZGcN7+mDQ91uuM5GUHcw==
/@ckeditor/ckeditor5-paragraph/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-CzPSzYed4Hx7R7y8jXcaNUX0ZR8vAdPI3bNG625HaL084gA09cfLjprAEIRVXfFFYMRTUNMUrZesKCIhVS3E4w==
/@ckeditor/ckeditor5-paste-from-office/27.0.0:
dependencies:
ckeditor5: 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-ywvw9pJiLd3aYbnu/vPwmet9/dPa8B7kRljoxz9CiHBf/qN3QMXMd1vAtuVxN2ZtV4HIe36Opw4zINMcz7jiRQ==
/@ckeditor/ckeditor5-select-all/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-JhWQMZYX96sJcqBt1qf7nLUn1IPEgKgffXKeiwwtTlgcQJeMrWMEkolybtlff0bedk+yqzzDlm9MHPUiFZNyiw==
/@ckeditor/ckeditor5-table/27.0.0:
dependencies:
ckeditor5: 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-SM1hStls9vi72WYY2Dm6uP7h5Vbf2M42WtaY7ez2Pwp3+LhGDeBECE2nH9ZovWOiZIsGluV7d0v1WwdZBzr/rg==
/@ckeditor/ckeditor5-typing/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-VKM2eC0eINqpOSz8k6G9Qu0xwCUnhFaYyT9tG64XRifQSGm0+ED4ygkI0o++cwERYYXB8kLKMloC2rHNK9HnQQ==
/@ckeditor/ckeditor5-ui/27.0.0:
dependencies:
'@ckeditor/ckeditor5-utils': 27.0.0
ckeditor5: 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-r+29zRUSBMEBUDRAN+rAxi/xPLxozEj9gLUHSvU0+uTiungq0X/hLj676J+JrIohiDe/DcuvZ/OwDi4n6v8i+g==
/@ckeditor/ckeditor5-undo/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-FLe6MnC5j0L1BQIrRa4gob8W8GxUXQ8uMG+DvLik07TpaU5PXb/CzUIJz7vZgxhbj7tKd8L9AmfcGza9g0S3kA==
/@ckeditor/ckeditor5-upload/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-ZlUpnK2jnMpcjYOz+TFsYQRG5WzXRjGgmsXDNG5gi0mCVwUovErvVFqzEHlXQR1TpKIsxgf5I0uPKPzMXpDOfg==
/@ckeditor/ckeditor5-utils/27.0.0:
dependencies:
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-GYscRP6M73og0DRASbUmelL6SHP77F7XaoI3rZrHIXA+ykOp83v9b6I/5CiJdSvB8t/oHVq/ZoJ6s6CrkVFMEQ==
/@ckeditor/ckeditor5-watchdog/23.1.0:
dependencies:
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-LQSWhsNPDsFPvxU+8O40pu/rPE2U7s4WobPcJm/6qKcM+WkTGdDG4rVuo5sackua3MulUeLGlfZSqFtX6Zsuag==
/@ckeditor/ckeditor5-widget/27.0.0:
dependencies:
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-enter': 27.0.0
'@ckeditor/ckeditor5-typing': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
lodash-es: 4.17.21
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-kgu7EKO7jC4L27etNlbBpk76CKSZJqD9BgST0el+bPvF/cITItSOCVQttKgW/6peu0ROL6dWPjAhnLBjxNi3oA==
/@convergencelabs/monaco-collab-ext/0.3.2:
dependencies:
monaco-editor: 0.23.0
dev: false
resolution:
integrity: sha512-yW5WI+pulIh4/fY5p2A9V8YkghQEfB6t33xqVAXkztjSG7MPBd9izlEtK13t0htVHk2vWj0JYhfWT853Gs60ow==
/@fortawesome/fontawesome-free/5.15.2: /@fortawesome/fontawesome-free/5.15.2:
dev: false dev: false
engines: engines:
@ -3075,6 +3450,26 @@ packages:
webpack: '>=4.0.1' webpack: '>=4.0.1'
resolution: resolution:
integrity: sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw== integrity: sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==
/ckeditor5/27.0.0:
dependencies:
'@ckeditor/ckeditor5-clipboard': 27.0.0
'@ckeditor/ckeditor5-core': 27.0.0
'@ckeditor/ckeditor5-engine': 27.0.0
'@ckeditor/ckeditor5-enter': 27.0.0
'@ckeditor/ckeditor5-paragraph': 27.0.0
'@ckeditor/ckeditor5-select-all': 27.0.0
'@ckeditor/ckeditor5-typing': 27.0.0
'@ckeditor/ckeditor5-ui': 27.0.0
'@ckeditor/ckeditor5-undo': 27.0.0
'@ckeditor/ckeditor5-upload': 27.0.0
'@ckeditor/ckeditor5-utils': 27.0.0
'@ckeditor/ckeditor5-widget': 27.0.0
dev: false
engines:
node: '>=12.0.0'
npm: '>=5.7.1'
resolution:
integrity: sha512-KjAjA/K5sNZ2UOaD3qxYiEv23TUdsZdNgDSMUiMjaFNv7bkoPZ4p8fEM4squzzB6VupLSjDw31WmTPF7Sf0KrA==
/class-utils/0.3.6: /class-utils/0.3.6:
dependencies: dependencies:
arr-union: 3.1.0 arr-union: 3.1.0
@ -6620,6 +7015,10 @@ packages:
dev: false dev: false
resolution: resolution:
integrity: sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA== integrity: sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==
/lodash-es/4.17.21:
dev: false
resolution:
integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
/lodash._baseassign/3.2.0: /lodash._baseassign/3.2.0:
dependencies: dependencies:
lodash._basecopy: 3.0.1 lodash._basecopy: 3.0.1
@ -7104,6 +7503,10 @@ packages:
dev: false dev: false
resolution: resolution:
integrity: sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== integrity: sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
/monaco-editor/0.23.0:
dev: false
resolution:
integrity: sha512-q+CP5zMR/aFiMTE9QlIavGyGicKnG2v/H8qVvybLzeFsARM8f6G9fL0sMST2tyVYCwDKkGamZUI6647A0jR/Lg==
/move-concurrently/1.0.1: /move-concurrently/1.0.1:
dependencies: dependencies:
aproba: 1.2.0 aproba: 1.2.0
@ -10335,6 +10738,10 @@ packages:
/tslib/2.1.0: /tslib/2.1.0:
resolution: resolution:
integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
/tslib/2.2.0:
dev: false
resolution:
integrity: sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
/tslint/5.15.0_typescript@4.0.7: /tslint/5.15.0_typescript@4.0.7:
dependencies: dependencies:
babel-code-frame: 6.26.0 babel-code-frame: 6.26.0
@ -11205,6 +11612,9 @@ specifiers:
'@angular/router': ~10.1.5 '@angular/router': ~10.1.5
'@angular/service-worker': ~10.1.5 '@angular/service-worker': ~10.1.5
'@circlon/angular-tree-component': ^10.0.0 '@circlon/angular-tree-component': ^10.0.0
'@ckeditor/ckeditor5-angular': ^2.0.1
'@ckeditor/ckeditor5-build-decoupled-document': ^27.0.0
'@convergencelabs/monaco-collab-ext': ^0.3.2
'@fortawesome/fontawesome-free': ^5.15.1 '@fortawesome/fontawesome-free': ^5.15.1
'@ionic-native/core': ^5.0.0 '@ionic-native/core': ^5.0.0
'@ionic-native/splash-screen': ^5.0.0 '@ionic-native/splash-screen': ^5.0.0

View File

@ -1,16 +1,50 @@
import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; import {Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {v4} from 'uuid'; import {v4} from 'uuid';
import {ApiService, ResourceNotAvailableOfflineError} from '../../../service/api.service'; import {ApiService, ResourceNotAvailableOfflineError} from '../../../service/api.service';
import {EditorNodeContract} from '../../nodes/EditorNode.contract'; import {EditorNodeContract} from '../../nodes/EditorNode.contract';
import {EditorService} from '../../../service/editor.service'; import {EditorService} from '../../../service/editor.service';
import {EditorComponent} from 'ngx-monaco-editor'; import {EditorComponent} from 'ngx-monaco-editor';
import * as MonacoCollabExt from '@convergencelabs/monaco-collab-ext';
import {FlitterSocketConnection, FlitterSocketServerClientTransaction} from '../../../flitter-socket';
import {debug} from '../../../utility';
import {environment} from "../../../../environments/environment";
export interface RemoteUser {
uuid: string;
uid: string;
display: string;
color: string;
cursor?: any;
selection?: any;
}
export interface RemoteInsertOperation {
type: 'insert';
index: number;
text: string;
}
export interface RemoteReplaceOperation {
type: 'replace';
index: number;
text: string;
length: number;
}
export interface RemoteDeleteOperation {
type: 'delete';
index: number;
length: number;
}
export type RemoteOperation = RemoteInsertOperation | RemoteReplaceOperation | RemoteDeleteOperation;
@Component({ @Component({
selector: 'editor-code', selector: 'editor-code',
templateUrl: './code.component.html', templateUrl: './code.component.html',
styleUrls: ['./code.component.scss'], styleUrls: ['./code.component.scss'],
}) })
export class CodeComponent extends EditorNodeContract implements OnInit { export class CodeComponent extends EditorNodeContract implements OnInit, OnDestroy {
@Input() nodeId: string; @Input() nodeId: string;
@Input() editorUUID?: string; @Input() editorUUID?: string;
@ViewChild('theEditor') theEditor: EditorComponent; @ViewChild('theEditor') theEditor: EditorComponent;
@ -21,6 +55,15 @@ export class CodeComponent extends EditorNodeContract implements OnInit {
public notAvailableOffline = false; public notAvailableOffline = false;
public containerHeight = 540; public containerHeight = 540;
protected cursorManager?: MonacoCollabExt.RemoteCursorManager;
protected selectionManager?: MonacoCollabExt.RemoteSelectionManager;
protected contentManager?: MonacoCollabExt.EditorContentManager;
protected remoteUsers: RemoteUser[] = [];
protected localUser?: RemoteUser;
protected socket?: FlitterSocketConnection;
protected editorGroupID!: string;
public editorOptions = { public editorOptions = {
theme: this.isDark() ? 'vs-dark' : 'vs', theme: this.isDark() ? 'vs-dark' : 'vs',
language: 'javascript', language: 'javascript',
@ -199,9 +242,36 @@ export class CodeComponent extends EditorNodeContract implements OnInit {
ngOnInit() { ngOnInit() {
this.editorService = this.editorService.getEditor(this.editorUUID); this.editorService = this.editorService.getEditor(this.editorUUID);
this.editorService.registerNodeEditor(this.nodeId, this).then(() => { this.editorService.registerNodeEditor(this.nodeId, this).then(() => {
this.editorOptions.readOnly = !this.editorService.canEdit(); this.editorOptions.readOnly = !this.editorService.canEdit();
}); });
const url = `${environment.websocketBase}/api/v1/socket/code/.websocket`;
debug(`Editor socket URL: ${url}`);
if ( !this.editorService.isVersion() ) {
const socket = new FlitterSocketConnection(url);
socket.controller(this);
socket.on_open().then(() => {
debug('Connected to code editor socket', socket);
socket.asyncRequest('subscribe', { resource_id: this.node.Value.Value }).then(([transaction, _, data]) => {
debug('Subscribed to editor group:', data);
if ( data.editor_group_id ) {
this.editorGroupID = data.editor_group_id;
this.socket = socket;
this.localUser = data.local_user;
}
});
});
}
}
ngOnDestroy() {
if ( this.socket ) {
this.socket.socket.close();
}
} }
onMonacoEditorInit(editor) { onMonacoEditorInit(editor) {
@ -218,8 +288,164 @@ export class CodeComponent extends EditorNodeContract implements OnInit {
} }
}; };
editor.onDidChangeCursorPosition(event => {
this.socket?.asyncRequest('update_cursor', {
position: event.position,
uuid: this.localUser?.uuid,
editor_group_id: this.editorGroupID,
});
});
editor.onDidChangeCursorSelection(event => {
this.socket?.asyncRequest('update_selection', {
startPosition: {
lineNumber: event.selection.startLineNumber,
column: event.selection.startColumn,
},
endPosition: {
lineNumber: event.selection.endLineNumber,
column: event.selection.endColumn,
},
uuid: this.localUser?.uuid,
editor_group_id: this.editorGroupID,
});
});
editor.onDidContentSizeChange(updateHeight); editor.onDidContentSizeChange(updateHeight);
updateHeight(); updateHeight();
this.cursorManager = new MonacoCollabExt.RemoteCursorManager({
editor,
tooltips: true,
tooltipDuration: 2,
});
this.selectionManager = new MonacoCollabExt.RemoteSelectionManager({ editor });
this.contentManager = new MonacoCollabExt.EditorContentManager({
editor,
onInsert: (index, text) => {
if ( this.readonly ) {
return;
}
this.socket?.asyncRequest('apply', {
editor_group_id: this.editorGroupID,
operations: [
{
type: 'insert',
index,
text,
},
],
});
},
onReplace: (index, length, text) => {
if ( this.readonly ) {
return;
}
this.socket?.asyncRequest('apply', {
editor_group_id: this.editorGroupID,
operations: [
{
type: 'replace',
index,
text,
length,
},
],
});
},
onDelete: (index, length) => {
if ( this.readonly ) {
return;
}
this.socket?.asyncRequest('apply', {
editor_group_id: this.editorGroupID,
operations: [
{
type: 'delete',
index,
length,
},
],
});
},
});
}
applyOperation(op: RemoteOperation) {
if ( op.type === 'insert' ) {
this.contentManager?.insert(op.index, op.text);
} else if ( op.type === 'replace' ) {
this.contentManager?.replace(op.index, op.length, op.text);
} else if ( op.type === 'delete' ) {
this.contentManager?.delete(op.index, op.length);
}
}
async applyRemoteOperation(transaction: FlitterSocketServerClientTransaction, connection: FlitterSocketConnection) {
const ops: RemoteOperation[] = transaction.incoming.operations || [];
for ( const op of ops ) {
this.applyOperation(op);
}
}
async updateCursorPosition(transaction: FlitterSocketServerClientTransaction, connection: FlitterSocketConnection) {
const position = transaction.incoming.position;
const uuid = transaction.incoming.uuid;
for ( const user of this.remoteUsers ) {
if ( user.uuid === uuid ) {
user.cursor?.setPosition(position);
}
}
}
async updateSelection(transaction: FlitterSocketServerClientTransaction, connection: FlitterSocketConnection) {
const startPosition = transaction.incoming.startPosition;
const endPosition = transaction.incoming.endPosition;
const uuid = transaction.incoming.uuid;
for ( const user of this.remoteUsers ) {
if ( user.uuid === uuid ) {
if ( startPosition && endPosition ) {
user.selection?.setPositions(startPosition, endPosition);
user.selection?.show();
} else {
user.selection?.hide();
}
}
}
}
async setEditorGroupUsers(transaction: FlitterSocketServerClientTransaction, connection: FlitterSocketConnection) {
const remoteUsers: RemoteUser[] = Array.isArray(transaction.incoming?.users) ? transaction.incoming.users : [];
console.log('set editor group users', remoteUsers, transaction);
for ( const user of this.remoteUsers ) {
this.cursorManager?.removeCursor(user.uuid);
user.cursor?.dispose();
delete user.cursor;
this.selectionManager?.removeSelection(user.uuid);
user.selection?.dispose();
delete user.selection;
}
while ( !this.cursorManager ) {
await new Promise(r => setTimeout(r, 500));
}
this.remoteUsers = remoteUsers;
for ( const user of this.remoteUsers ) {
user.cursor = this.cursorManager?.addCursor(user.uuid, user.color, user.display);
user.cursor?.setOffset(0);
user.cursor?.show();
user.selection = this.selectionManager?.addSelection(user.uuid, user.color);
}
} }
public onEditorModelChange($event) { public onEditorModelChange($event) {

View File

@ -135,6 +135,10 @@ export class EditorService {
await this.startEditing(this.currentPageId); await this.startEditing(this.currentPageId);
} }
isVersion() {
return !!this.currentPageVersion;
}
async startEditing(pageId: string, version?: number) { async startEditing(pageId: string, version?: number) {
if ( this.currentPage ) { if ( this.currentPage ) {
await this.stopEditing(); await this.stopEditing();

View File

@ -8,4 +8,5 @@ export const environment = {
starshipUrl: '/auth/starship_oauth/login', starshipUrl: '/auth/starship_oauth/login',
appBase: '/i/', appBase: '/i/',
outputDebug: false, outputDebug: false,
websocketBase: '',
}; };

View File

@ -12,6 +12,7 @@ export const environment = {
starshipUrl: '/link_api/auth/starship_oauth/login', starshipUrl: '/link_api/auth/starship_oauth/login',
appBase: '/', appBase: '/',
outputDebug: true, outputDebug: true,
websocketBase: 'ws://localhost:8000'
}; };
/* /*