Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Port participant positions logic into GuestPortalBinding
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonio Scandurra authored and jasonrudolph committed Dec 1, 2017
1 parent 35e09a9 commit 4b3379c
Show file tree
Hide file tree
Showing 5 changed files with 286 additions and 139 deletions.
16 changes: 8 additions & 8 deletions lib/editor-binding.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* global ResizeObserver */

const path = require('path')
const {Range, Disposable, CompositeDisposable} = require('atom')
const {Range, Emitter, Disposable, CompositeDisposable} = require('atom')
const normalizeURI = require('./normalize-uri')
const {FollowState} = require('@atom/teletype-client')
const SitePositionsComponent = require('./site-positions-component')
Expand All @@ -10,10 +10,13 @@ function doNothing () {}

module.exports =
class EditorBinding {
constructor ({editor, portal, isHost, didDispose}) {
constructor ({editor, portal, isHost, didResize, didScroll, didDispose}) {
this.editor = editor
this.portal = portal
this.isHost = isHost
this.emitter = new Emitter()
this.emitDidResize = didResize || doNothing
this.emitDidScroll = didScroll || doNothing
this.emitDidDispose = didDispose || doNothing
this.selectionsMarkerLayer = this.editor.selectionsMarkerLayer.bufferMarkerLayer
this.markerLayersBySiteId = new Map()
Expand Down Expand Up @@ -139,24 +142,21 @@ class EditorBinding {
async editorDidChangeScrollTop () {
const {element} = this.editor
await element.component.getNextUpdatePromise()
// TODO: move into portal bindings.
// this.updateActivePositions(this.positionsBySiteId)
this.editorProxy.didScroll()
this.emitDidScroll()
}

async editorDidChangeScrollLeft () {
const {element} = this.editor
await element.component.getNextUpdatePromise()
// TODO: move into portal bindings.
// this.updateActivePositions(this.positionsBySiteId)
this.editorProxy.didScroll()
this.emitDidScroll()
}

async editorDidResize () {
const {element} = this.editor
await element.component.getNextUpdatePromise()
// TODO: move into portal bindings.
// this.updateActivePositions(this.positionsBySiteId)
this.emitDidResize()
}

updateSelectionsForSiteId (siteId, selections) {
Expand Down
72 changes: 71 additions & 1 deletion lib/guest-portal-binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {Errors, FollowState} = require('@atom/teletype-client')
const BufferBinding = require('./buffer-binding')
const EditorBinding = require('./editor-binding')
const EmptyPortalPaneItem = require('./empty-portal-pane-item')
const SitePositionsComponent = require('./site-positions-component')

module.exports =
class GuestPortalBinding {
Expand All @@ -20,13 +21,23 @@ class GuestPortalBinding {
this.subscriptions = new CompositeDisposable()
this.lastEditorProxyChangePromise = Promise.resolve()
this.openEditorProxies = new Set()
this.positionsBySiteId = {}
}

async initialize () {
try {
this.portal = await this.client.joinPortal(this.portalId)
if (!this.portal) return false

this.aboveViewportSitePositionsComponent = this.buildSitePositionsComponent('upper-right')
this.insideViewportSitePositionsComponent = this.buildSitePositionsComponent('middle-right')
this.outsideViewportSitePositionsComponent = this.buildSitePositionsComponent('lower-right')

const workspaceElement = this.workspace.getElement()
workspaceElement.appendChild(this.aboveViewportSitePositionsComponent.element)
workspaceElement.appendChild(this.insideViewportSitePositionsComponent.element)
workspaceElement.appendChild(this.outsideViewportSitePositionsComponent.element)

await this.portal.setDelegate(this)
if (this.openEditorProxies.size === 0) {
await this.openPaneItem(this.getEmptyPortalPaneItem())
Expand Down Expand Up @@ -79,7 +90,39 @@ class GuestPortalBinding {
return this.lastEditorProxyChangePromise
}

updateActivePositions () {}
updateActivePositions (positionsBySiteId) {
const aboveViewportSiteIds = []
const insideViewportSiteIds = []
const outsideViewportSiteIds = []

for (const siteId in positionsBySiteId) {
const {editorProxy, position} = positionsBySiteId[siteId]
const editorBinding = this.editorBindingsByEditorProxy.get(editorProxy)
if (!editorBinding || editorBinding.editor !== this.getActivePaneItem()) {
outsideViewportSiteIds.push(siteId)
} else {
switch (editorBinding.getDirectionFromViewportToPosition(position)) {
case 'upward':
aboveViewportSiteIds.push(siteId)
break
case 'inside':
insideViewportSiteIds.push(siteId)
break
case 'downward':
case 'leftward':
case 'rightward':
outsideViewportSiteIds.push(siteId)
break
}
}
}

const followedSiteId = null // FIXME
this.aboveViewportSitePositionsComponent.update({siteIds: aboveViewportSiteIds, followedSiteId})
this.insideViewportSitePositionsComponent.update({siteIds: insideViewportSiteIds, followedSiteId})
this.outsideViewportSitePositionsComponent.update({siteIds: outsideViewportSiteIds, followedSiteId})
this.positionsBySiteId = positionsBySiteId
}

updateTether (followState, editorProxy, position) {
if (!editorProxy) return
Expand Down Expand Up @@ -122,6 +165,8 @@ class GuestPortalBinding {
editor,
portal: this.portal,
isHost: false,
didScroll: () => this.updateActivePositions(this.positionsBySiteId),
didResize: () => this.updateActivePositions(this.positionsBySiteId),
didDispose: () => {
this.editorBindingsByEditorProxy.delete(editorProxy)
this.editorProxiesByEditor.delete(editor)
Expand Down Expand Up @@ -219,6 +264,16 @@ class GuestPortalBinding {
didChangeActivePaneItem (paneItem) {
if (paneItem !== this.getEmptyPortalPaneItem()) {
const editorProxy = this.editorProxiesByEditor.get(paneItem)
if (editorProxy) {
this.workspace.element.appendChild(this.aboveViewportSitePositionsComponent.element)
this.workspace.element.appendChild(this.insideViewportSitePositionsComponent.element)
this.workspace.element.appendChild(this.outsideViewportSitePositionsComponent.element)
} else {
this.aboveViewportSitePositionsComponent.element.remove()
this.insideViewportSitePositionsComponent.element.remove()
this.outsideViewportSitePositionsComponent.element.remove()
}

this.portal.activateEditorProxy(editorProxy)
}
}
Expand All @@ -239,4 +294,19 @@ class GuestPortalBinding {
onDidChange (callback) {
return this.emitter.on('did-change', callback)
}

buildSitePositionsComponent (position) {
return new SitePositionsComponent({
position,
displayedParticipantsCount: 3,
portal: this.portal,
onSelectSiteId: (siteId) => {
if (siteId === this.portal.getFollowedSiteId()) {
this.portal.unfollow()
} else {
this.portal.follow(siteId)
}
}
})
}
}
99 changes: 6 additions & 93 deletions test/editor-binding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ const SAMPLE_TEXT = fs.readFileSync(path.join(__dirname, 'fixtures', 'sample.js'
const {TextEditor, TextBuffer, Range} = require('atom')
const EditorBinding = require('../lib/editor-binding')
const {buildAtomEnvironment, destroyAtomEnvironments} = require('./helpers/atom-environments')
const {
setEditorHeightInLines,
setEditorWidthInChars,
setEditorScrollTopInLines,
setEditorScrollLeftInChars
} = require('./helpers/editor-helpers')
const {FollowState} = require('@atom/teletype-client')

suite('EditorBinding', function () {
Expand Down Expand Up @@ -347,76 +353,6 @@ suite('EditorBinding', function () {
assert.deepEqual(getCursorClasses(editor), [])
})

test.skip('showing the active position of other collaborators', async () => {
// TODO: move this test into portal binding tests.
const editor = new TextEditor({autoHeight: false})
editor.setText(SAMPLE_TEXT)

const binding = new EditorBinding({editor, portal: new FakePortal()})
const editorProxy = new FakeEditorProxy(binding)
binding.setEditorProxy(editorProxy)

const {
aboveViewportSitePositionsComponent,
insideViewportSitePositionsComponent,
outsideViewportSitePositionsComponent
} = binding
assert(editor.element.contains(aboveViewportSitePositionsComponent.element))
assert(editor.element.contains(insideViewportSitePositionsComponent.element))
assert(editor.element.contains(outsideViewportSitePositionsComponent.element))

attachToDOM(editor.element)

await setEditorHeightInLines(editor, 3)
await setEditorWidthInChars(editor, 5)
await setEditorScrollTopInLines(editor, 5)
await setEditorScrollLeftInChars(editor, 5)

binding.updateActivePositions({
1: {row: 2, column: 5}, // collaborator above visible area
2: {row: 9, column: 5}, // collaborator below visible area
3: {row: 6, column: 1}, // collaborator to the left of visible area
4: {row: 6, column: 15}, // collaborator to the right of visible area
5: {row: 6, column: 6} // collaborator inside of visible area
})

assert.deepEqual(aboveViewportSitePositionsComponent.props.siteIds, [1])
assert.deepEqual(insideViewportSitePositionsComponent.props.siteIds, [5])
assert.deepEqual(outsideViewportSitePositionsComponent.props.siteIds, [2, 3, 4])

await setEditorScrollLeftInChars(editor, 0)

assert.deepEqual(aboveViewportSitePositionsComponent.props.siteIds, [1])
assert.deepEqual(insideViewportSitePositionsComponent.props.siteIds, [3])
assert.deepEqual(outsideViewportSitePositionsComponent.props.siteIds, [2, 4, 5])

await setEditorScrollTopInLines(editor, 2)

assert.deepEqual(aboveViewportSitePositionsComponent.props.siteIds, [])
assert.deepEqual(insideViewportSitePositionsComponent.props.siteIds, [])
assert.deepEqual(outsideViewportSitePositionsComponent.props.siteIds, [1, 2, 3, 4, 5])

await setEditorHeightInLines(editor, 7)

assert.deepEqual(aboveViewportSitePositionsComponent.props.siteIds, [])
assert.deepEqual(insideViewportSitePositionsComponent.props.siteIds, [3])
assert.deepEqual(outsideViewportSitePositionsComponent.props.siteIds, [1, 2, 4, 5])

await setEditorWidthInChars(editor, 10)

assert.deepEqual(aboveViewportSitePositionsComponent.props.siteIds, [])
assert.deepEqual(insideViewportSitePositionsComponent.props.siteIds, [1, 3, 5])
assert.deepEqual(outsideViewportSitePositionsComponent.props.siteIds, [2, 4])

// Selecting a site will follow them.
outsideViewportSitePositionsComponent.props.onSelectSiteId(2)
assert.equal(editorProxy.getFollowedSiteId(), 2)

// Selecting the same site again will unfollow them.
outsideViewportSitePositionsComponent.props.onSelectSiteId(2)
assert.equal(editorProxy.getFollowedSiteId(), null)
})

test('isScrollNeededToViewPosition(position)', async () => {
const editor = new TextEditor({autoHeight: false})
const binding = new EditorBinding({editor, portal: new FakePortal()})
Expand Down Expand Up @@ -509,29 +445,6 @@ suite('EditorBinding', function () {
attachedElements.push(element)
document.body.insertBefore(element, document.body.firstChild)
}

async function setEditorHeightInLines (editor, lines) {
editor.element.style.height = editor.getLineHeightInPixels() * lines + 'px'
return editor.component.getNextUpdatePromise()
}

async function setEditorWidthInChars (editor, chars) {
editor.element.style.width =
editor.component.getGutterContainerWidth() +
chars * editor.getDefaultCharWidth() +
'px'
return editor.component.getNextUpdatePromise()
}

async function setEditorScrollTopInLines (editor, lines) {
editor.element.setScrollTop(editor.getLineHeightInPixels() * lines)
return editor.component.getNextUpdatePromise()
}

async function setEditorScrollLeftInChars (editor, chars) {
editor.element.setScrollLeft(editor.getDefaultCharWidth() * chars)
return editor.component.getNextUpdatePromise()
}
})

class FakeEditorProxy {
Expand Down
Loading

0 comments on commit 4b3379c

Please sign in to comment.