Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/text.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2021-01-23 19:32:53 +0300
committerJulius Härtl <jus@bitgrid.net>2021-01-26 10:34:18 +0300
commit7c7623222aeffdbf7ed2f513592d63b243f9dcbb (patch)
treecc100a49d65563ff83806f0e0fda28422590853e /src
parent886fd14249a02659b482b1aa6ba2b540bc9360e7 (diff)
Track authors by step rather than transaction
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'src')
-rw-r--r--src/components/EditorWrapper.vue22
-rw-r--r--src/components/SessionList.vue2
-rw-r--r--src/extensions/UserColor.js14
-rw-r--r--src/extensions/tracking/TrackState.js59
-rw-r--r--src/extensions/tracking/models.js14
-rw-r--r--src/mixins/store.js5
-rw-r--r--src/services/PollingBackend.js2
-rw-r--r--src/store.js7
8 files changed, 49 insertions, 76 deletions
diff --git a/src/components/EditorWrapper.vue b/src/components/EditorWrapper.vue
index 9cea69aef..50c1ebf4c 100644
--- a/src/components/EditorWrapper.vue
+++ b/src/components/EditorWrapper.vue
@@ -74,7 +74,6 @@
import Vue from 'vue'
import escapeHtml from 'escape-html'
import moment from '@nextcloud/moment'
-import { mapState } from 'vuex'
import { SyncService, ERROR_TYPE, IDLE_TIMEOUT } from './../services/SyncService'
import { endpointUrl, getRandomGuestName } from './../helpers'
@@ -175,9 +174,9 @@ export default {
}
},
computed: {
- ...mapState({
- showAuthorAnnotations: state => state.showAuthorAnnotations,
- }),
+ showAuthorAnnotations() {
+ return this.$store.state.showAuthorAnnotations
+ },
lastSavedStatus() {
let status = (this.dirtyStateIndicator ? '*' : '')
if (!this.isMobile) {
@@ -342,7 +341,7 @@ export default {
steps.map(item => Step.fromJSON(schema, item.step)),
steps.map(item => item.clientID),
)
- tr.setMeta('clientID', steps[0].clientID)
+ tr.setMeta('clientID', steps.map(item => item.clientID))
view.dispatch(tr)
},
}),
@@ -379,14 +378,11 @@ export default {
.on('sync', ({ steps, document }) => {
this.hasConnectionIssue = false
try {
- for (let i = 0; i < steps.length; i++) {
- // FIXME: seems pretty bad performance wise (maybe grouping the steps by user in the backend would be good)
- this.tiptap.extensions.options.collaboration.update({
- version: document.currentVersion,
- steps: [steps[i]],
- editor: this.tiptap,
- })
- }
+ this.tiptap.extensions.options.collaboration.update({
+ version: document.currentVersion,
+ steps,
+ editor: this.tiptap,
+ })
this.syncService.state = this.tiptap.state
this.updateLastSavedStatus()
} catch (e) {
diff --git a/src/components/SessionList.vue b/src/components/SessionList.vue
index a05c25a6c..1415057dc 100644
--- a/src/components/SessionList.vue
+++ b/src/components/SessionList.vue
@@ -109,7 +109,7 @@ export default {
return this.$store.state.showAuthorAnnotations
},
set(value) {
- this.$store.commit('setShowAuthorAnnotations', value)
+ this.$store.dispatch('setShowAuthorAnnotations', value)
},
},
editorsTooltip() {
diff --git a/src/extensions/UserColor.js b/src/extensions/UserColor.js
index e3e4350c1..6ae68a0e6 100644
--- a/src/extensions/UserColor.js
+++ b/src/extensions/UserColor.js
@@ -60,20 +60,16 @@ export default class UserColor extends Extension {
let { tracked, decos } = instance
let tState = this.getState(oldState).tracked
if (tr.docChanged) {
+ if (!tr.getMeta('clientID')) {
+ // we have an undefined client id for own transactions
+ tr.setMeta('clientID', tr.steps.map(i => this.spec.clientID))
+ }
tracked = tracked.applyTransform(tr)
- const clientID = tr.getMeta('clientID') ? tr.getMeta('clientID') : this.spec.clientID
- tracked = tracked.applyCommit(clientID, new Date(tr.time), {
- clientID,
- color: this.spec.color(clientID),
- name: this.spec.name(clientID),
- })
tState = tracked
}
decos = tState.blameMap
- .filter(span => typeof tState.commits[span.commit]?.author?.color !== 'undefined')
.map(span => {
- const commit = tState.commits[span.commit]
- const clientID = commit.author.clientID
+ const clientID = span.author
return Decoration.inline(span.from, span.to, {
class: 'author-annotation',
style: 'background-color: ' + this.spec.color(clientID) + '66;',
diff --git a/src/extensions/tracking/TrackState.js b/src/extensions/tracking/TrackState.js
index 6a6d33d57..8193ecacb 100644
--- a/src/extensions/tracking/TrackState.js
+++ b/src/extensions/tracking/TrackState.js
@@ -20,32 +20,34 @@
*
*/
-import { Span, Commit } from './models'
+import { Span } from './models'
/*
* This code is heavily inspired by the change tracking example of prosemirror
* https://github.com/ProseMirror/website/blob/master/example/track/index.js
*/
-function updateBlameMap(map, transform, id) {
- const result = []; const mapping = transform.mapping
+function updateBlameMap(map, transform, clientIDs) {
+ const result = []
+ const mapping = transform.mapping
for (let i = 0; i < map.length; i++) {
const span = map[i]
- const from = mapping.map(span.from, 1); const to = mapping.map(span.to, -1)
- if (from < to) result.push(new Span(from, to, span.commit))
+ const from = mapping.map(span.from, 1)
+ const to = mapping.map(span.to, -1)
+ if (from < to) result.push(new Span(from, to, span.author))
}
for (let i = 0; i < mapping.maps.length; i++) {
const map = mapping.maps[i]; const after = mapping.slice(i + 1)
map.forEach((_s, _e, start, end) => {
- insertIntoBlameMap(result, after.map(start, 1), after.map(end, -1), id)
+ insertIntoBlameMap(result, after.map(start, 1), after.map(end, -1), clientIDs[i])
})
}
return result
}
-function insertIntoBlameMap(map, from, to, commit) {
+function insertIntoBlameMap(map, from, to, author) {
if (from >= to) {
return
}
@@ -53,11 +55,11 @@ function insertIntoBlameMap(map, from, to, commit) {
let next
for (; pos < map.length; pos++) {
next = map[pos]
- if (next.commit === commit) {
+ if (next.author === author) {
if (next.to >= from) break
- } else if (next.to > from) { // Different commit, not before
+ } else if (next.to > from) { // Different author, not before
if (next.from < from) { // Sticks out to the left (loop below will handle right side)
- const left = new Span(next.from, from, next.commit)
+ const left = new Span(next.from, from, next.author)
if (next.to > to) map.splice(pos++, 0, left)
else map[pos++] = left
}
@@ -67,7 +69,7 @@ function insertIntoBlameMap(map, from, to, commit) {
// eslint-ignore
while ((next = map[pos])) {
- if (next.commit === commit) {
+ if (next.author === author) {
if (next.from > to) break
from = Math.min(from, next.from)
to = Math.max(to, next.to)
@@ -75,7 +77,7 @@ function insertIntoBlameMap(map, from, to, commit) {
} else {
if (next.from >= to) break
if (next.to > to) {
- map[pos] = new Span(to, next.to, next.commit)
+ map[pos] = new Span(to, next.to, next.author)
break
} else {
map.splice(pos, 1)
@@ -83,45 +85,26 @@ function insertIntoBlameMap(map, from, to, commit) {
}
}
- map.splice(pos, 0, new Span(from, to, commit))
+ map.splice(pos, 0, new Span(from, to, author))
}
export default class TrackState {
- constructor(blameMap, commits, uncommittedSteps, uncommittedMaps) {
+ constructor(blameMap) {
// The blame map is a data structure that lists a sequence of
- // document ranges, along with the commit that inserted them. This
+ // document ranges, along with the author that inserted them. This
// can be used to, for example, highlight the part of the document
- // that was inserted by a commit.
+ // that was inserted by a author.
this.blameMap = blameMap
- // The commit history, as an array of objects.
- this.commits = commits
- // Inverted steps and their maps corresponding to the changes that
- // have been made since the last commit.
- this.uncommittedSteps = uncommittedSteps
- this.uncommittedMaps = uncommittedMaps
}
// Apply a transform to this state
applyTransform(transform) {
- // Invert the steps in the transaction, to be able to save them in
- // the next commit
- const inverted
- = transform.steps.map((step, i) => step.invert(transform.docs[i]))
- const newBlame = updateBlameMap(this.blameMap, transform, this.commits.length)
+ const clientID = transform.getMeta('clientID') ?? transform.steps.map(item => 'self')
+ const newBlame = updateBlameMap(this.blameMap, transform, clientID)
// Create a new state—since these are part of the editor state, a
// persistent data structure, they must not be mutated.
- return new TrackState(newBlame, this.commits,
- this.uncommittedSteps.concat(inverted),
- this.uncommittedMaps.concat(transform.mapping.maps))
- }
-
- // When a transaction is marked as a commit, this is used to put any
- // uncommitted steps into a new commit.
- applyCommit(message, time, author) {
- if (this.uncommittedSteps.length === 0) return this
- const commit = new Commit(message, time, this.uncommittedSteps, this.uncommittedMaps, author)
- return new TrackState(this.blameMap, this.commits.concat(commit), [], [])
+ return new TrackState(newBlame)
}
}
diff --git a/src/extensions/tracking/models.js b/src/extensions/tracking/models.js
index fbcacdb65..1c628f780 100644
--- a/src/extensions/tracking/models.js
+++ b/src/extensions/tracking/models.js
@@ -22,21 +22,9 @@
export class Span {
- constructor(from, to, commit) {
+ constructor(from, to, author) {
this.from = from
this.to = to
- this.commit = commit
- }
-
-}
-
-export class Commit {
-
- constructor(message, time, steps, maps, author) {
- this.message = message
- this.time = time
- this.steps = steps
- this.maps = maps
this.author = author
}
diff --git a/src/mixins/store.js b/src/mixins/store.js
index fb73617b6..1cf36314b 100644
--- a/src/mixins/store.js
+++ b/src/mixins/store.js
@@ -28,6 +28,11 @@ import store from '../store'
* are mounted in other apps e.g. viewer
*/
export default {
+ data() {
+ return {
+ $store: store,
+ }
+ },
beforeMount() {
if (typeof this.$store === 'undefined') {
this.$store = store
diff --git a/src/services/PollingBackend.js b/src/services/PollingBackend.js
index 42349451d..e93ad20ab 100644
--- a/src/services/PollingBackend.js
+++ b/src/services/PollingBackend.js
@@ -76,7 +76,7 @@ class PollingBackend {
}
connect() {
- this.fetcher = setInterval(this._fetchSteps.bind(this), 0)
+ this.fetcher = setInterval(this._fetchSteps.bind(this), 50)
document.addEventListener('visibilitychange', this.visibilitychange.bind(this))
}
diff --git a/src/store.js b/src/store.js
index a2d84806d..53a8a22ac 100644
--- a/src/store.js
+++ b/src/store.js
@@ -33,11 +33,16 @@ const store = new Vuex.Store({
showAuthorAnnotations: persistentStorage.getItem('showAuthorAnnotations') === 'true',
},
mutations: {
- setShowAuthorAnnotations(state, value) {
+ SET_SHOW_AUTHOR_ANNOTATIONS(state, value) {
state.showAuthorAnnotations = value
persistentStorage.setItem('showAuthorAnnotations', '' + value)
},
},
+ actions: {
+ setShowAuthorAnnotations({ commit }, value) {
+ store.commit('SET_SHOW_AUTHOR_ANNOTATIONS', value)
+ },
+ },
})
export default store