Skip to content

Commit

Permalink
Merge pull request #1385 from nextcloud/bugfix/color-performance
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusknorr authored Jan 26, 2021
2 parents 682f363 + d515b99 commit b962965
Show file tree
Hide file tree
Showing 24 changed files with 91 additions and 118 deletions.
6 changes: 3 additions & 3 deletions js/editor-collab.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/editor-collab.js.map

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions js/editor.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/editor.js.map

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions js/files.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/files.js.map

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions js/public.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/public.js.map

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions js/text.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/vendors~editor-collab~editor-guest.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/vendors~editor-collab~editor-guest.js.map

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions js/vendors~editor.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/vendors~editor.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/viewer.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/viewer.js.map

Large diffs are not rendered by default.

22 changes: 9 additions & 13 deletions src/components/EditorWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
},
}),
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/SessionList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export default {
return this.$store.state.showAuthorAnnotations
},
set(value) {
this.$store.commit('setShowAuthorAnnotations', value)
this.$store.dispatch('setShowAuthorAnnotations', value)
},
},
editorsTooltip() {
Expand Down
14 changes: 5 additions & 9 deletions src/extensions/UserColor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;',
Expand Down
59 changes: 21 additions & 38 deletions src/extensions/tracking/TrackState.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,44 +20,46 @@
*
*/

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
}
let pos = 0
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
}
Expand All @@ -67,61 +69,42 @@ 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)
map.splice(pos, 1)
} 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)
}
}
}

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)
}

}
14 changes: 1 addition & 13 deletions src/extensions/tracking/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
5 changes: 5 additions & 0 deletions src/mixins/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/services/PollingBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

Expand Down
7 changes: 6 additions & 1 deletion src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit b962965

Please sign in to comment.