diff --git a/frontend/src/Metamaps/JIT.js b/frontend/src/Metamaps/JIT.js
index 6549d823..73c1b600 100644
--- a/frontend/src/Metamaps/JIT.js
+++ b/frontend/src/Metamaps/JIT.js
@@ -37,6 +37,10 @@ const JIT = {
tempInit: false,
tempNode: null,
tempNode2: null,
+ mouseDownPix: {},
+ dragFlag : 0,
+ dragTolerance: 0,
+ virtualPointer: {},
events: {
topicDrag: 'Metamaps:JIT:events:topicDrag',
@@ -754,77 +758,127 @@ const JIT = {
Control.deselectAllNodes()
}, // escKeyHandler
onDragMoveTopicHandler: function (node, eventInfo, e) {
- const self = JIT
+ var self = JIT
- // this is used to send nodes that are moving to
- // other realtime collaborators on the same map
- const positionsToSend = {}
- let topic
-
- const authorized = Active.Map && Active.Map.authorizeToEdit(Active.Mapper)
+ var authorized = Active.Map && Active.Map.authorizeToEdit(Active.Mapper)
if (node && !node.nodeFrom) {
- const pos = eventInfo.getPos()
+ var pos = eventInfo.getPos(),
+ EDGE_THICKNESS = 30 /** Metamaps.Visualize.mGraph.canvas.scaleOffsetX*/,
+ SHIFT = 2 / Metamaps.Visualize.mGraph.canvas.scaleOffsetX,
+ PERIOD = 5;
+
+ //self.virtualPointer = pos;
// if it's a left click, or a touch, move the node
- if (e.touches || (e.button === 0 && !e.altKey && !e.ctrlKey && !e.shiftKey && (e.buttons === 0 || e.buttons === 1 || e.buttons === undefined))) {
+ if (e.touches || (e.button === 0 && !e.altKey && !e.ctrlKey && (e.buttons === 0 || e.buttons === 1 || e.buttons === undefined))) {
+
+ var width = Metamaps.Visualize.mGraph.canvas.getSize().width,
+ height = Metamaps.Visualize.mGraph.canvas.getSize().height,
+ xPix = Metamaps.Util.coordsToPixels(pos).x,
+ yPix = Metamaps.Util.coordsToPixels(pos).y;
+
+ if(self.dragFlag === 0){
+ self.mouseDownPix = Metamaps.Util.coordsToPixels(eventInfo.getPos());
+ self.dragFlag = 1;
+ }
+
+ if(Metamaps.Util.getDistance(Metamaps.Util.coordsToPixels(pos),self.mouseDownPix) > 2 && !self.dragTolerance){
+ self.dragTolerance = 1;
+ }
+
+ if(xPix < EDGE_THICKNESS && self.dragTolerance ){
+ clearInterval(self.dragLeftEdge);
+ clearInterval(self.dragRightEdge);
+ clearInterval(self.dragTopEdge);
+ clearInterval(self.dragBottomEdge);
+ self.virtualPointer = {x:Metamaps.Util.pixelsToCoords({x:EDGE_THICKNESS,y:yPix}).x - SHIFT,y:pos.y};
+ Metamaps.Visualize.mGraph.canvas.translate(SHIFT,0);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+
+ self.dragLeftEdge = setInterval( function(){
+ self.virtualPointer = {x:Metamaps.Util.pixelsToCoords({x:EDGE_THICKNESS,y:yPix}).x - SHIFT,y:pos.y};
+ Metamaps.Visualize.mGraph.canvas.translate(SHIFT,0);
+ self.updateTopicPositions(node,self.virtualPointer);
+ Visualize.mGraph.plot();
+ } , PERIOD);
+
+ }
+ if(width - xPix < EDGE_THICKNESS && self.dragTolerance){
+ clearInterval(self.dragLeftEdge);
+ clearInterval(self.dragRightEdge);
+ clearInterval(self.dragTopEdge);
+ clearInterval(self.dragBottomEdge);
+ self.virtualPointer = {x:Metamaps.Util.pixelsToCoords({x:width - EDGE_THICKNESS,y:yPix}).x + SHIFT,y:pos.y};
+ Metamaps.Visualize.mGraph.canvas.translate(-SHIFT,0);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+
+ self.dragRightEdge = setInterval( function(){
+ self.virtualPointer = {x:Metamaps.Util.pixelsToCoords({x:width - EDGE_THICKNESS,y:yPix}).x + SHIFT,y:pos.y};
+ Metamaps.Visualize.mGraph.canvas.translate(-SHIFT,0);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+ } , PERIOD);
+ }
+ if(yPix < EDGE_THICKNESS && self.dragTolerance){
+ clearInterval(self.dragLeftEdge);
+ clearInterval(self.dragRightEdge);
+ clearInterval(self.dragTopEdge);
+ clearInterval(self.dragBottomEdge);
+ self.virtualPointer = {x:pos.x,y:Metamaps.Util.pixelsToCoords({x:xPix,y:EDGE_THICKNESS}).y - SHIFT};
+ Metamaps.Visualize.mGraph.canvas.translate(0,SHIFT);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+
+ self.dragTopEdge = setInterval( function(){
+ self.virtualPointer = {x:pos.x,y:Metamaps.Util.pixelsToCoords({x:xPix,y:EDGE_THICKNESS}).y - SHIFT};
+ Metamaps.Visualize.mGraph.canvas.translate(0,SHIFT);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+ } , PERIOD);
+ }
+ if(height - yPix < EDGE_THICKNESS && self.dragTolerance){
+ clearInterval(self.dragLeftEdge);
+ clearInterval(self.dragRightEdge);
+ clearInterval(self.dragTopEdge);
+ clearInterval(self.dragBottomEdge);
+ self.virtualPointer = {x:pos.x,y:Metamaps.Util.pixelsToCoords({x:xPix,y:height - EDGE_THICKNESS}).y + SHIFT};
+ Metamaps.Visualize.mGraph.canvas.translate(0,-SHIFT);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+
+ self.dragBottomEdge = setInterval( function(){
+ self.virtualPointer = {x:pos.x,y:Metamaps.Util.pixelsToCoords({x:xPix,y:height - EDGE_THICKNESS}).y + SHIFT};
+ Metamaps.Visualize.mGraph.canvas.translate(0,-SHIFT);
+ self.updateTopicPositions(node, self.virtualPointer);
+ Visualize.mGraph.plot();
+ } , PERIOD);
+ }
+
+ if(xPix >= EDGE_THICKNESS && width - xPix >= EDGE_THICKNESS && yPix >= EDGE_THICKNESS && height - yPix >= EDGE_THICKNESS){
+ clearInterval(self.dragLeftEdge);
+ clearInterval(self.dragRightEdge);
+ clearInterval(self.dragTopEdge);
+ clearInterval(self.dragBottomEdge);
+
+ self.updateTopicPositions(node,pos);
+ Visualize.mGraph.plot()
+ }
+
// if the node dragged isn't already selected, select it
- const whatToDo = self.handleSelectionBeforeDragging(node, e)
+ var whatToDo = self.handleSelectionBeforeDragging(node, e)
if (node.pos.rho || node.pos.rho === 0) {
// this means we're in topic view
- const rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y)
- const theta = Math.atan2(pos.y, pos.x)
+ var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y)
+ var theta = Math.atan2(pos.y, pos.x)
node.pos.setp(theta, rho)
- } else if (whatToDo === 'only-drag-this-one') {
- node.pos.setc(pos.x, pos.y)
-
- if (Active.Map) {
- topic = node.getData('topic')
- // we use the topic ID not the node id
- // because we can't depend on the node id
- // to be the same as on other collaborators
- // maps
- positionsToSend[topic.id] = pos
- $(document).trigger(JIT.events.topicDrag, [positionsToSend])
- }
} else {
- const len = Selected.Nodes.length
-
- // first define offset for each node
- const xOffset = []
- const yOffset = []
- for (let i = 0; i < len; i += 1) {
- const n = Selected.Nodes[i]
- xOffset[i] = n.pos.x - node.pos.x
- yOffset[i] = n.pos.y - node.pos.y
- } // for
-
- for (let i = 0; i < len; i += 1) {
- const n = Selected.Nodes[i]
- const x = pos.x + xOffset[i]
- const y = pos.y + yOffset[i]
- n.pos.setc(x, y)
-
- if (Active.Map) {
- topic = n.getData('topic')
- // we use the topic ID not the node id
- // because we can't depend on the node id
- // to be the same as on other collaborators
- // maps
- positionsToSend[topic.id] = n.pos
- }
- } // for
-
- if (Active.Map) {
- $(document).trigger(JIT.events.topicDrag, [positionsToSend])
- }
- } // if
-
- if (whatToDo === 'deselect') {
- Control.deselectNode(node)
+ //self.updateTopicPositions(node,pos);
}
- Visualize.mGraph.plot()
- } else if ((e.button === 2 || (e.button === 0 && e.altKey) || e.buttons === 2) && authorized) {
- // if it's a right click or holding down alt, start synapse creation ->third option is for firefox
+ }
+ // if it's a right click or holding down alt, start synapse creation ->third option is for firefox
+ else if ((e.button === 2 || (e.button === 0 && e.altKey) || e.buttons === 2) && authorized) {
if (JIT.tempInit === false) {
JIT.tempNode = node
JIT.tempInit = true
@@ -832,7 +886,7 @@ const JIT = {
Create.newTopic.hide()
Create.newSynapse.hide()
// set the draw synapse start positions
- const l = Selected.Nodes.length
+ var l = Selected.Nodes.length
if (l > 0) {
for (let i = l - 1; i >= 0; i -= 1) {
const n = Selected.Nodes[i]
@@ -874,8 +928,8 @@ const JIT = {
n.setData('dim', 25, 'current')
})
// pop up node creation :)
- const myX = e.clientX - 110
- const myY = e.clientY - 30
+ var myX = e.clientX - 110
+ var myY = e.clientY - 30
$('#new_topic').css('left', myX + 'px')
$('#new_topic').css('top', myY + 'px')
Create.newTopic.x = eventInfo.getPos().x
@@ -887,9 +941,11 @@ const JIT = {
y: pos.y
}
}
- } else if ((e.button === 2 || (e.button === 0 && e.altKey) || e.buttons === 2) && Active.Topic) {
+ }
+ else if ((e.button === 2 || (e.button === 0 && e.altKey) || e.buttons === 2) && Active.Topic) {
GlobalUI.notifyUser('Cannot create in Topic view.')
- } else if ((e.button === 2 || (e.button === 0 && e.altKey) || e.buttons === 2) && !authorized) {
+ }
+ else if ((e.button === 2 || (e.button === 0 && e.altKey) || e.buttons === 2) && !authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
}
}
@@ -905,9 +961,21 @@ const JIT = {
Visualize.mGraph.plot()
}, // onDragCancelHandler
onDragEndTopicHandler: function (node, eventInfo, e) {
- let midpoint = {}
- let pixelPos
- let mapping
+ var self = JIT;
+ var midpoint = {}, pixelPos, mapping
+
+ clearInterval(self.dragLeftEdge);
+ clearInterval(self.dragRightEdge);
+ clearInterval(self.dragTopEdge);
+ clearInterval(self.dragBottomEdge);
+
+ delete self.dragLeftEdge;
+ delete self.dragRightEdge;
+ delete self.dragTopEdge;
+ delete self.dragBottomEdge;
+
+ self.dragFlag = 0;
+ self.dragTolerance = 0;
if (JIT.tempInit && JIT.tempNode2 === null) {
// this means you want to add a new topic, and then a synapse
@@ -1002,7 +1070,44 @@ const JIT = {
Control.deselectAllNodes()
}
}
- }, // canvasClickHandler
+ }, // canvasClickHandler
+ updateTopicPositions: function (node, pos){
+ var len = Selected.Nodes.length;
+ var topic;
+ // this is used to send nodes that are moving to
+ // other realtime collaborators on the same map
+ var positionsToSend = {};
+
+ // first define offset for each node
+ var xOffset = []
+ var yOffset = []
+ for (var i = 0; i < len; i += 1) {
+ var n = Selected.Nodes[i]
+ xOffset[i] = n.pos.x - node.pos.x
+ yOffset[i] = n.pos.y - node.pos.y
+ } // for
+
+ for (var i = 0; i < len; i += 1) {
+ var n = Selected.Nodes[i]
+ var x = pos.x + xOffset[i]
+ var y = pos.y + yOffset[i]
+ n.pos.setc(x, y)
+
+ if (Active.Map) {
+ topic = n.getData('topic')
+ // we use the topic ID not the node id
+ // because we can't depend on the node id
+ // to be the same as on other collaborators
+ // maps
+ positionsToSend[topic.id] = n.pos
+ }
+ } // for
+
+ if (Active.Map) {
+ $(document).trigger(JIT.events.topicDrag, [positionsToSend])
+ }
+ },
+
nodeDoubleClickHandler: function (node, e) {
TopicCard.showCard(node)
}, // nodeDoubleClickHandler
@@ -1027,19 +1132,23 @@ const JIT = {
// 2 others are selected only and shift, so additionally select this one
// 3 others are selected only, no shift: drag only this one
// 4 this node and others were selected, so drag them (just return false)
- // return value: deselect node again after?
if (Selected.Nodes.length === 0) {
+ Control.selectNode(node, e)
return 'only-drag-this-one'
}
if (Selected.Nodes.indexOf(node) === -1) {
if (e.shiftKey) {
Control.selectNode(node, e)
- return 'nothing'
+ return 'move-all-incuding-this-one'
} else {
+ Control.deselectAllEdges()
+ Control.deselectAllNodes()
+ Control.selectNode(node, e)
return 'only-drag-this-one'
}
}
- return 'nothing' // case 4?
+ return 'move-all'; // case 4?
+
}, // handleSelectionBeforeDragging
getNodeXY: function (node) {
if (typeof node.pos.x === 'number' && typeof node.pos.y === 'number') {
diff --git a/frontend/src/Metamaps/Listeners.js b/frontend/src/Metamaps/Listeners.js
index cbd138fd..8b4d6616 100644
--- a/frontend/src/Metamaps/Listeners.js
+++ b/frontend/src/Metamaps/Listeners.js
@@ -7,6 +7,7 @@ import Mobile from './Mobile'
import Realtime from './Realtime'
import Selected from './Selected'
import Topic from './Topic'
+import Util from './Util'
import Visualize from './Visualize'
import { Search } from './GlobalUI'
@@ -108,16 +109,19 @@ const Listeners = {
})
$(window).resize(function () {
- if (Visualize && Visualize.mGraph) Visualize.mGraph.canvas.resize($(window).width(), $(window).height())
+ if (Visualize && Visualize.mGraph) {
+ Util.resizeCanvas(Visualize.mGraph.canvas)
+ }
+
if (Active.Map && Realtime.inConversation) Realtime.positionVideos()
Mobile.resizeTitle()
})
},
- centerAndReveal: function(nodes, opts) {
+ centerAndReveal: function (nodes, opts) {
if (nodes.length < 1) return
var node = nodes[nodes.length - 1]
if (opts.center && opts.reveal) {
- Topic.centerOn(node.id, function() {
+ Topic.centerOn(node.id, function () {
Topic.fetchRelatives(nodes)
})
} else if (opts.center) {
diff --git a/frontend/src/Metamaps/Realtime/events.js b/frontend/src/Metamaps/Realtime/events.js
index 20265154..a1fabf04 100644
--- a/frontend/src/Metamaps/Realtime/events.js
+++ b/frontend/src/Metamaps/Realtime/events.js
@@ -1,54 +1,53 @@
/* EVENTS SENDABLE */
-export const REQUEST_LIVE_MAPS = 'REQUEST_LIVE_MAPS'
-export const JOIN_MAP = 'JOIN_MAP'
-export const LEAVE_MAP = 'LEAVE_MAP'
-export const CHECK_FOR_CALL = 'CHECK_FOR_CALL'
-export const ACCEPT_CALL = 'ACCEPT_CALL'
-export const DENY_CALL = 'DENY_CALL'
-export const DENY_INVITE = 'DENY_INVITE'
-export const INVITE_TO_JOIN = 'INVITE_TO_JOIN'
-export const INVITE_A_CALL = 'INVITE_A_CALL'
-export const JOIN_CALL = 'JOIN_CALL'
-export const LEAVE_CALL = 'LEAVE_CALL'
-export const SEND_MAPPER_INFO = 'SEND_MAPPER_INFO'
-export const SEND_COORDS = 'SEND_COORDS'
-export const CREATE_MESSAGE = 'CREATE_MESSAGE'
-export const DRAG_TOPIC = 'DRAG_TOPIC'
-export const CREATE_TOPIC = 'CREATE_TOPIC'
-export const UPDATE_TOPIC = 'UPDATE_TOPIC'
-export const REMOVE_TOPIC = 'REMOVE_TOPIC'
-export const DELETE_TOPIC = 'DELETE_TOPIC'
-export const CREATE_SYNAPSE = 'CREATE_SYNAPSE'
-export const UPDATE_SYNAPSE = 'UPDATE_SYNAPSE'
-export const REMOVE_SYNAPSE = 'REMOVE_SYNAPSE'
-export const DELETE_SYNAPSE = 'DELETE_SYNAPSE'
-export const UPDATE_MAP = 'UPDATE_MAP'
+module.exports = {
+ JOIN_MAP: 'JOIN_MAP',
+ CHECK_FOR_CALL: 'CHECK_FOR_CALL',
+ LEAVE_MAP: 'LEAVE_MAP',
+ ACCEPT_CALL: 'ACCEPT_CALL',
+ DENY_CALL: 'DENY_CALL',
+ DENY_INVITE: 'DENY_INVITE',
+ INVITE_TO_JOIN: 'INVITE_TO_JOIN',
+ INVITE_A_CALL: 'INVITE_A_CALL',
+ JOIN_CALL: 'JOIN_CALL',
+ LEAVE_CALL: 'LEAVE_CALL',
+ SEND_MAPPER_INFO: 'SEND_MAPPER_INFO',
+ SEND_COORDS: 'SEND_COORDS',
+ CREATE_MESSAGE: 'CREATE_MESSAGE',
+ DRAG_TOPIC: 'DRAG_TOPIC',
+ CREATE_TOPIC: 'CREATE_TOPIC',
+ UPDATE_TOPIC: 'UPDATE_TOPIC',
+ REMOVE_TOPIC: 'REMOVE_TOPIC',
+ DELETE_TOPIC: 'DELETE_TOPIC',
+ CREATE_SYNAPSE: 'CREATE_SYNAPSE',
+ UPDATE_SYNAPSE: 'UPDATE_SYNAPSE',
+ REMOVE_SYNAPSE: 'REMOVE_SYNAPSE',
+ DELETE_SYNAPSE: 'DELETE_SYNAPSE',
+ UPDATE_MAP: 'UPDATE_MAP',
-/* EVENTS RECEIVABLE */
-export const INVITED_TO_CALL = 'INVITED_TO_CALL'
-export const INVITED_TO_JOIN = 'INVITED_TO_JOIN'
-export const CALL_ACCEPTED = 'CALL_ACCEPTED'
-export const CALL_DENIED = 'CALL_DENIED'
-export const INVITE_DENIED = 'INVITE_DENIED'
-export const CALL_IN_PROGRESS = 'CALL_IN_PROGRESS'
-export const CALL_STARTED = 'CALL_STARTED'
-export const MAPPER_JOINED_CALL = 'MAPPER_JOINED_CALL'
-export const MAPPER_LEFT_CALL = 'MAPPER_LEFT_CALL'
-export const MAPPER_LIST_UPDATED = 'MAPPER_LIST_UPDATED'
-export const NEW_MAPPER = 'NEW_MAPPER'
-export const LOST_MAPPER = 'LOST_MAPPER'
-export const MESSAGE_CREATED = 'MESSAGE_CREATED'
-export const TOPIC_DRAGGED = 'TOPIC_DRAGGED'
-export const TOPIC_CREATED = 'TOPIC_CREATED'
-export const TOPIC_UPDATED = 'TOPIC_UPDATED'
-export const TOPIC_REMOVED = 'TOPIC_REMOVED'
-export const TOPIC_DELETED = 'TOPIC_DELETED'
-export const SYNAPSE_CREATED = 'SYNAPSE_CREATED'
-export const SYNAPSE_UPDATED = 'SYNAPSE_UPDATED'
-export const SYNAPSE_REMOVED = 'SYNAPSE_REMOVED'
-export const SYNAPSE_DELETED = 'SYNAPSE_DELETED'
-export const PEER_COORDS_UPDATED = 'PEER_COORDS_UPDATED'
-export const MAP_UPDATED = 'MAP_UPDATED'
-export const LIVE_MAPS_RECEIVED = 'LIVE_MAPS_RECEIVED'
-export const MAP_WENT_LIVE = 'MAP_WENT_LIVE'
-export const MAP_CEASED_LIVE = 'MAP_CEASED_LIVE'
+ /* EVENTS RECEIVABLE */
+ JUNTO_UPDATED: 'JUNTO_UPDATED',
+ INVITED_TO_CALL: 'INVITED_TO_CALL',
+ INVITED_TO_JOIN: 'INVITED_TO_JOIN',
+ CALL_ACCEPTED: 'CALL_ACCEPTED',
+ CALL_DENIED: 'CALL_DENIED',
+ INVITE_DENIED: 'INVITE_DENIED',
+ CALL_IN_PROGRESS: 'CALL_IN_PROGRESS',
+ CALL_STARTED: 'CALL_STARTED',
+ MAPPER_JOINED_CALL: 'MAPPER_JOINED_CALL',
+ MAPPER_LEFT_CALL: 'MAPPER_LEFT_CALL',
+ MAPPER_LIST_UPDATED: 'MAPPER_LIST_UPDATED',
+ NEW_MAPPER: 'NEW_MAPPER',
+ LOST_MAPPER: 'LOST_MAPPER',
+ MESSAGE_CREATED: 'MESSAGE_CREATED',
+ TOPIC_DRAGGED: 'TOPIC_DRAGGED',
+ TOPIC_CREATED: 'TOPIC_CREATED',
+ TOPIC_UPDATED: 'TOPIC_UPDATED',
+ TOPIC_REMOVED: 'TOPIC_REMOVED',
+ TOPIC_DELETED: 'TOPIC_DELETED',
+ SYNAPSE_CREATED: 'SYNAPSE_CREATED',
+ SYNAPSE_UPDATED: 'SYNAPSE_UPDATED',
+ SYNAPSE_REMOVED: 'SYNAPSE_REMOVED',
+ SYNAPSE_DELETED: 'SYNAPSE_DELETED',
+ PEER_COORDS_UPDATED: 'PEER_COORDS_UPDATED',
+ MAP_UPDATED: 'MAP_UPDATED'
+}
diff --git a/frontend/src/Metamaps/Realtime/index.js b/frontend/src/Metamaps/Realtime/index.js
index e891263c..7982618a 100644
--- a/frontend/src/Metamaps/Realtime/index.js
+++ b/frontend/src/Metamaps/Realtime/index.js
@@ -27,6 +27,7 @@ import Views from '../Views'
import Visualize from '../Visualize'
import {
+ JUNTO_UPDATED,
INVITED_TO_CALL,
INVITED_TO_JOIN,
CALL_ACCEPTED,
@@ -34,9 +35,9 @@ import {
INVITE_DENIED,
CALL_IN_PROGRESS,
CALL_STARTED,
+ MAPPER_LIST_UPDATED,
MAPPER_JOINED_CALL,
MAPPER_LEFT_CALL,
- MAPPER_LIST_UPDATED,
NEW_MAPPER,
LOST_MAPPER,
MESSAGE_CREATED,
@@ -50,13 +51,11 @@ import {
SYNAPSE_REMOVED,
SYNAPSE_DELETED,
PEER_COORDS_UPDATED,
- LIVE_MAPS_RECEIVED,
- MAP_WENT_LIVE,
- MAP_CEASED_LIVE,
MAP_UPDATED
} from './events'
import {
+ juntoUpdated,
invitedToCall,
invitedToJoin,
callAccepted,
@@ -64,9 +63,9 @@ import {
inviteDenied,
callInProgress,
callStarted,
+ mapperListUpdated,
mapperJoinedCall,
mapperLeftCall,
- mapperListUpdated,
peerCoordsUpdated,
newMapper,
lostMapper,
@@ -81,13 +80,9 @@ import {
synapseRemoved,
synapseDeleted,
mapUpdated,
- liveMapsReceived,
- mapWentLive,
- mapCeasedLive
} from './receivable'
import {
- requestLiveMaps,
joinMap,
leaveMap,
checkForCall,
@@ -98,8 +93,8 @@ import {
inviteACall,
joinCall,
leaveCall,
- sendMapperInfo,
sendCoords,
+ sendMapperInfo,
createMessage,
dragTopic,
createTopic,
@@ -114,6 +109,7 @@ import {
} from './sendable'
let Realtime = {
+ juntoState: { connectedPeople: {}, liveMaps: {} },
videoId: 'video-wrapper',
socket: null,
webrtc: null,
@@ -499,12 +495,11 @@ let Realtime = {
}
const sendables = [
- ['requestLiveMaps',requestLiveMaps],
['joinMap',joinMap],
['leaveMap',leaveMap],
['checkForCall',checkForCall],
['acceptCall',acceptCall],
- ['denyAll',denyCall],
+ ['denyCall',denyCall],
['denyInvite',denyInvite],
['inviteToJoin',inviteToJoin],
['inviteACall',inviteACall],
@@ -529,6 +524,7 @@ sendables.forEach(sendable => {
})
const subscribeToEvents = (Realtime, socket) => {
+ socket.on(JUNTO_UPDATED, juntoUpdated(Realtime))
socket.on(INVITED_TO_CALL, invitedToCall(Realtime))
socket.on(INVITED_TO_JOIN, invitedToJoin(Realtime))
socket.on(CALL_ACCEPTED, callAccepted(Realtime))
@@ -536,9 +532,9 @@ const subscribeToEvents = (Realtime, socket) => {
socket.on(INVITE_DENIED, inviteDenied(Realtime))
socket.on(CALL_IN_PROGRESS, callInProgress(Realtime))
socket.on(CALL_STARTED, callStarted(Realtime))
+ socket.on(MAPPER_LIST_UPDATED, mapperListUpdated(Realtime))
socket.on(MAPPER_JOINED_CALL, mapperJoinedCall(Realtime))
socket.on(MAPPER_LEFT_CALL, mapperLeftCall(Realtime))
- socket.on(MAPPER_LIST_UPDATED, mapperListUpdated(Realtime))
socket.on(PEER_COORDS_UPDATED, peerCoordsUpdated(Realtime))
socket.on(NEW_MAPPER, newMapper(Realtime))
socket.on(LOST_MAPPER, lostMapper(Realtime))
@@ -553,9 +549,6 @@ const subscribeToEvents = (Realtime, socket) => {
socket.on(SYNAPSE_REMOVED, synapseRemoved(Realtime))
socket.on(SYNAPSE_DELETED, synapseDeleted(Realtime))
socket.on(MAP_UPDATED, mapUpdated(Realtime))
- socket.on(LIVE_MAPS_RECEIVED, liveMapsReceived(Realtime))
- socket.on(MAP_WENT_LIVE, mapWentLive(Realtime))
- socket.on(MAP_CEASED_LIVE, mapCeasedLive(Realtime))
}
export default Realtime
diff --git a/frontend/src/Metamaps/Realtime/receivable.js b/frontend/src/Metamaps/Realtime/receivable.js
index bf974bbe..477736c5 100644
--- a/frontend/src/Metamaps/Realtime/receivable.js
+++ b/frontend/src/Metamaps/Realtime/receivable.js
@@ -1,7 +1,11 @@
+/* global $ */
+
/*
everthing in this file happens as a result of websocket events
*/
+import { JUNTO_UPDATED } from './events'
+
import Active from '../Active'
import GlobalUI from '../GlobalUI'
import Control from '../Control'
@@ -12,6 +16,11 @@ import Synapse from '../Synapse'
import Util from '../Util'
import Visualize from '../Visualize'
+export const juntoUpdated = self => state => {
+ self.juntoState = state
+ $(document).trigger(JUNTO_UPDATED)
+}
+
export const synapseRemoved = self => data => {
var synapse = Metamaps.Synapses.get(data.mappableid)
if (synapse) {
@@ -239,13 +248,13 @@ export const lostMapper = self => data => {
export const mapperListUpdated = self => data => {
// data.userid
// data.username
- // data.userimage
+ // data.avatar
self.mappersOnMap[data.userid] = {
id: data.userid,
name: data.username,
username: data.username,
- image: data.userimage,
+ image: data.avatar,
color: Util.getPastelColor(),
inConversation: data.userinconversation,
coords: {
@@ -259,14 +268,14 @@ export const mapperListUpdated = self => data => {
if (data.userinconversation) self.room.chat.mapperJoinedCall(data.userid)
// create a div for the collaborators compass
- self.createCompass(data.username, data.userid, data.userimage, self.mappersOnMap[data.userid].color)
+ self.createCompass(data.username, data.userid, data.avatar, self.mappersOnMap[data.userid].color)
}
}
export const newMapper = self => data => {
// data.userid
// data.username
- // data.userimage
+ // data.avatar
// data.coords
var firstOtherPerson = Object.keys(self.mappersOnMap).length === 0
@@ -274,13 +283,12 @@ export const newMapper = self => data => {
id: data.userid,
name: data.username,
username: data.username,
- image: data.userimage,
+ image: data.avatar,
color: Util.getPastelColor(),
- realtime: true,
coords: {
x: 0,
y: 0
- },
+ }
}
// create an item for them in the realtime box
@@ -289,7 +297,7 @@ export const newMapper = self => data => {
self.room.chat.addParticipant(self.mappersOnMap[data.userid])
// create a div for the collaborators compass
- self.createCompass(data.username, data.userid, data.userimage, self.mappersOnMap[data.userid].color)
+ self.createCompass(data.username, data.userid, data.avatar, self.mappersOnMap[data.userid].color)
var notifyMessage = data.username + ' just joined the map'
if (firstOtherPerson) {
@@ -324,7 +332,7 @@ export const invitedToCall = self => inviter => {
self.soundId = self.room.chat.sound.play('sessioninvite')
var username = self.mappersOnMap[inviter].name
- var notifyText = '

'
+ var notifyText = '

'
notifyText += username + ' is inviting you to a conversation. Join live?'
notifyText += '
'
notifyText += '
'
@@ -391,6 +399,3 @@ export const callStarted = self => () => {
self.room.conversationInProgress()
}
-export const liveMapsReceived = self => () => {}
-export const mapWentLive = self => () => {}
-export const mapCeasedLive = self => () => {}
diff --git a/frontend/src/Metamaps/Realtime/sendable.js b/frontend/src/Metamaps/Realtime/sendable.js
index a1ce2ea7..71abc35c 100644
--- a/frontend/src/Metamaps/Realtime/sendable.js
+++ b/frontend/src/Metamaps/Realtime/sendable.js
@@ -2,7 +2,6 @@ import Active from '../Active'
import GlobalUI from '../GlobalUI'
import {
- REQUEST_LIVE_MAPS,
JOIN_MAP,
LEAVE_MAP,
CHECK_FOR_CALL,
@@ -28,15 +27,11 @@ import {
UPDATE_MAP
} from './events'
-export const requestLiveMaps = self => () => {
- self.socket.emit(REQUEST_LIVE_MAPS)
-}
-
export const joinMap = self => () => {
self.socket.emit(JOIN_MAP, {
userid: Active.Mapper.id,
username: Active.Mapper.get('name'),
- userimage: Active.Mapper.get('image'),
+ avatar: Active.Mapper.get('image'),
mapid: Active.Map.id,
map: Active.Map.attributes
})
@@ -55,7 +50,7 @@ export const sendMapperInfo = self => userid => {
var update = {
userToNotify: userid,
username: Active.Mapper.get('name'),
- userimage: Active.Mapper.get('image'),
+ avatar: Active.Mapper.get('image'),
userid: Active.Mapper.id,
userinconversation: self.inConversation,
mapid: Active.Map.id
diff --git a/frontend/src/Metamaps/Util.js b/frontend/src/Metamaps/Util.js
index 48a89b1d..49797ab4 100644
--- a/frontend/src/Metamaps/Util.js
+++ b/frontend/src/Metamaps/Util.js
@@ -1,3 +1,5 @@
+/* global $ */
+
import { Parser, HtmlRenderer } from 'commonmark'
import Visualize from './Visualize'
@@ -138,6 +140,25 @@ const Util = {
// use safe: true to filter xss
return new HtmlRenderer({ safe: true })
.render(new Parser().parse(text))
+ },
+ logCanvasAttributes: function(canvas){
+ return {
+ scaleX: canvas.scaleOffsetX,
+ scaleY: canvas.scaleOffsetY,
+ centreCoords: Util.pixelsToCoords({ x: canvas.canvases[0].size.width / 2, y: canvas.canvases[0].size.height / 2 }),
+ };
+ },
+ resizeCanvas: function(canvas){
+ // Store the current canvas attributes, i.e. scale and map-coordinate at the centre of the user's screen
+ const oldAttr = Util.logCanvasAttributes(canvas);
+
+ // Resize the canvas to fill the new window size. Based on how JIT works, this also resets the map back to scale 1 and tranlations = 0
+ canvas.resize($(window).width(), $(window).height())
+
+ // Return the map to the original scale, and then put the previous central map-coordinate back to the centre of user's newly resized screen
+ canvas.scale(oldAttr.scaleX, oldAttr.scaleY)
+ const newAttr = Util.logCanvasAttributes(canvas);
+ canvas.translate(newAttr.centreCoords.x - oldAttr.centreCoords.x, newAttr.centreCoords.y - oldAttr.centreCoords.y)
}
}
diff --git a/frontend/src/Metamaps/Views/ChatView.js b/frontend/src/Metamaps/Views/ChatView.js
index 8c586a0c..8febe9e1 100644
--- a/frontend/src/Metamaps/Views/ChatView.js
+++ b/frontend/src/Metamaps/Views/ChatView.js
@@ -159,7 +159,7 @@ var Private = {
var date = (m.timestamp.getMonth() + 1) + '/' + m.timestamp.getDate()
date += ' ' + addZero(m.timestamp.getHours()) + ':' + addZero(m.timestamp.getMinutes())
m.timestamp = date
- m.image = m.user_image || 'http://www.hotpepper.ca/wp-content/uploads/2014/11/default_profile_1_200x200.png' // TODO: remove
+ m.image = m.user_image
m.message = linker.link(m.message)
var $html = $(this.messageTemplate(m))
this.$messages.append($html)
diff --git a/frontend/src/Metamaps/Views/ExploreMaps.js b/frontend/src/Metamaps/Views/ExploreMaps.js
index e843e7fe..441f3ca2 100644
--- a/frontend/src/Metamaps/Views/ExploreMaps.js
+++ b/frontend/src/Metamaps/Views/ExploreMaps.js
@@ -4,6 +4,8 @@ import React from 'react'
import ReactDOM from 'react-dom' // TODO ensure this isn't a double import
import Active from '../Active'
+import GlobalUI from '../GlobalUI'
+import Realtime from '../Realtime'
import Maps from '../../components/Maps'
/*
@@ -11,6 +13,7 @@ import Maps from '../../components/Maps'
*/
const ExploreMaps = {
+ pending: false,
setCollection: function (collection) {
var self = ExploreMaps
@@ -27,58 +30,79 @@ const ExploreMaps = {
render: function (mapperObj, cb) {
var self = ExploreMaps
+ if (!self.collection) return
+
if (typeof mapperObj === 'function') {
cb = mapperObj
mapperObj = null
}
-
- var exploreObj = {
+
+ var exploreObj = {
currentUser: Active.Mapper,
section: self.collection.id,
maps: self.collection,
+ juntoState: Realtime.juntoState,
moreToLoad: self.collection.page != 'loadedAll',
user: mapperObj,
- loadMore: self.loadMore
+ loadMore: self.loadMore,
+ pending: self.pending,
+ onStar: function (map) {
+ $.post('/maps/' + map.id + '/star')
+ map.set('star_count', map.get('star_count') + 1)
+ if (Metamaps.Stars) Metamaps.Stars.push({ user_id: Active.Mapper.id, map_id: map.id })
+ Metamaps.Maps.Starred.add(map)
+ GlobalUI.notifyUser('Map is now starred')
+ self.render()
+ },
+ onRequest: function (map) {
+ $.post({
+ url: `/maps/${map.id}/access_request`
+ })
+ GlobalUI.notifyUser('You will be notified by email if request accepted')
+ }
}
ReactDOM.render(
React.createElement(Maps, exploreObj),
document.getElementById('explore')
- )
-
+ ).resize()
+
if (cb) cb()
- Metamaps.Loading.hide()
},
loadMore: function () {
var self = ExploreMaps
-
if (self.collection.page != "loadedAll") {
self.collection.getMaps()
+ self.pending = true
}
- else self.render()
+ self.render()
},
handleSuccess: function (cb) {
var self = ExploreMaps
-
+ self.pending = false
if (self.collection && self.collection.id === 'mapper') {
self.fetchUserThenRender(cb)
} else {
self.render(cb)
+ Metamaps.Loading.hide()
}
},
handleError: function () {
console.log('error loading maps!') // TODO
+ Metamaps.Loading.hide()
},
fetchUserThenRender: function (cb) {
var self = ExploreMaps
-
+
// first load the mapper object and then call the render function
$.ajax({
url: '/users/' + self.collection.mapperId + '/details.json',
success: function (response) {
self.render(response, cb)
+ Metamaps.Loading.hide()
},
error: function () {
self.render(cb)
+ Metamaps.Loading.hide()
}
})
}
diff --git a/frontend/src/Metamaps/Views/index.js b/frontend/src/Metamaps/Views/index.js
index d13482d0..39104b18 100644
--- a/frontend/src/Metamaps/Views/index.js
+++ b/frontend/src/Metamaps/Views/index.js
@@ -1,7 +1,18 @@
+/* global $ */
+
import ExploreMaps from './ExploreMaps'
import ChatView from './ChatView'
import VideoView from './VideoView'
import Room from './Room'
+import { JUNTO_UPDATED } from '../Realtime/events'
-const Views = { ExploreMaps, ChatView, VideoView, Room }
+const Views = {
+ init: () => {
+ $(document).on(JUNTO_UPDATED, () => ExploreMaps.render())
+ },
+ ExploreMaps,
+ ChatView,
+ VideoView,
+ Room
+}
export default Views
diff --git a/frontend/src/Metamaps/index.js b/frontend/src/Metamaps/index.js
index 44bbfdb6..bf2e2d60 100644
--- a/frontend/src/Metamaps/index.js
+++ b/frontend/src/Metamaps/index.js
@@ -88,7 +88,7 @@ document.addEventListener('DOMContentLoaded', function () {
if (Metamaps.currentSection === 'explore') {
const capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1)
- Metamaps.Views.ExploreMaps.setCollection(Metamaps.Maps[capitalize])
+ Views.ExploreMaps.setCollection(Metamaps.Maps[capitalize])
if (Metamaps.currentPage === 'mapper') {
Views.ExploreMaps.fetchUserThenRender()
} else {
diff --git a/frontend/src/components/Maps/MapCard.js b/frontend/src/components/Maps/MapCard.js
index 3a1557ee..efa3d59f 100644
--- a/frontend/src/components/Maps/MapCard.js
+++ b/frontend/src/components/Maps/MapCard.js
@@ -1,8 +1,60 @@
import React, { Component, PropTypes } from 'react'
+import { find, values } from 'lodash'
+
+const IN_CONVERSATION = 1 // shared with /realtime/reducer.js
+
+const MapperList = (props) => {
+ return
+ - LIVE
+ { props.mappers.map(mapper =>
{ mapper.username } ) }
+
+}
+
+class Menu extends Component {
+
+ constructor(props) {
+ super(props)
+ this.state = { open: false }
+ }
+
+ toggle = () => {
+ this.setState({ open: !this.state.open })
+ return true
+ }
+
+ render = () => {
+ const { currentUser, map, onStar, onRequest } = this.props
+ const style = { display: this.state.open ? 'block' : 'none' }
+
+ return
+
+
+ - { this.toggle() && onStar(map) }}>Star Map
+ { !map.authorizeToEdit(currentUser) && - { this.toggle() && onRequest(map) }}>Request Access
}
+
+
+ }
+}
+Menu.propTypes = {
+ currentUser: PropTypes.object.isRequired,
+ map: PropTypes.object.isRequired,
+ onStar: PropTypes.func.isRequired,
+ onRequest: PropTypes.func.isRequired
+}
+
class MapCard extends Component {
render = () => {
- const { map, currentUser } = this.props
+ const { map, juntoState, currentUser, onRequest, onStar } = this.props
+
+ const hasMap = juntoState.liveMaps[map.id]
+ const hasConversation = hasMap && find(values(hasMap), v => v === IN_CONVERSATION)
+ const hasMapper = hasMap && !hasConversation
+ const mapperList = hasMap && Object.keys(hasMap).map(id => juntoState.connectedPeople[id])
function capitalize (string) {
return string.charAt(0).toUpperCase() + string.slice(1)
@@ -19,49 +71,51 @@ class MapCard extends Component {
return (
)
}
@@ -69,7 +123,10 @@ class MapCard extends Component {
MapCard.propTypes = {
map: PropTypes.object.isRequired,
- currentUser: PropTypes.object
+ juntoState: PropTypes.object,
+ currentUser: PropTypes.object,
+ onStar: PropTypes.func.isRequired,
+ onRequest: PropTypes.func.isRequired
}
export default MapCard
diff --git a/frontend/src/components/Maps/index.js b/frontend/src/components/Maps/index.js
index 670f5aaf..df59b446 100644
--- a/frontend/src/components/Maps/index.js
+++ b/frontend/src/components/Maps/index.js
@@ -1,4 +1,5 @@
import React, { Component, PropTypes } from 'react'
+import { throttle } from 'lodash'
import Header from './Header'
import MapperCard from './MapperCard'
import MapCard from './MapCard'
@@ -15,19 +16,10 @@ class Maps extends Component {
componentDidMount() {
window && window.addEventListener('resize', this.resize)
+ this.refs.maps.addEventListener('scroll', throttle(this.scroll, 500, { leading: true, trailing: false }))
this.resize()
}
- componentDidUpdate(oldProps) {
- const { maps, user, currentUser } = this.props
- const oldMaps = oldProps.maps
- const oldUser = oldProps.user
- const oldCurrentUser = oldProps.currentUser
- const numCards = maps.length + (user || currentUser ? 1 : 0)
- const oldNumCards = oldMaps.length + (oldUser || oldCurrentUser ? 1 : 0)
- if (numCards !== oldNumCards) this.resize()
- }
-
componentWillUnmount() {
window && window.removeEventListener('resize', this.resize)
}
@@ -40,22 +32,26 @@ class Maps extends Component {
this.setState({ mapsWidth })
}
+ scroll = () => {
+ const { loadMore, moreToLoad, pending } = this.props
+ const { maps } = this.refs
+ if (moreToLoad && !pending && maps.scrollTop + maps.offsetHeight > maps.scrollHeight - 300 ) {
+ loadMore()
+ }
+ }
+
render = () => {
- const { maps, currentUser, section, user, moreToLoad, loadMore } = this.props
+ const { maps, currentUser, juntoState, section, user, moreToLoad, loadMore, onStar, onRequest } = this.props
const style = { width: this.state.mapsWidth + 'px' }
return (
-
+
{ user ?
: null }
{ currentUser && !user ?
: null }
- { maps.models.map(map =>
) }
+ { maps.models.map(map =>
) }
- {!moreToLoad ? null : [
-
,
-
- ]}
{
- if (event === JOIN_MAP) {
- if (!state.liveMaps[data.mapid]) {
- state.liveMaps[data.mapid] = data.map // { name: '', desc: '', numTopics: '' }
- state.liveMaps[data.mapid].mapper_count = 1
- io.sockets.emit(MAP_WENT_LIVE, state.liveMaps[data.mapid])
- }
- else {
- state.liveMaps[data.mapid].mapper_count++
- }
- }
- else if (event === LEAVE_MAP) {
- const mapid = socket.mapid
- if (state.liveMaps[mapid] && state.liveMaps[mapid].mapper_count == 1) {
- delete state.liveMaps[mapid]
- io.sockets.emit(MAP_CEASED_LIVE, { id: mapid })
- }
- else if (state.liveMaps[mapid]) {
- state.liveMaps[mapid].mapper_count--
- }
- }
-}
+module.exports = function (io, store) {
+ store.subscribe(() => {
+ console.log(store.getState())
+ io.sockets.emit(JUNTO_UPDATED, store.getState())
+ })
-module.exports = function (io, state) {
io.on('connection', function (socket) {
- socket.on(REQUEST_LIVE_MAPS, function (activeUser) {
- //constrain response to maps visible to user
- var maps = Object.keys(state.liveMaps).map(function(key) { return state.liveMaps[key] })
- socket.emit(LIVE_MAPS_RECEIVED, maps)
- })
+ io.sockets.emit(JUNTO_UPDATED, store.getState())
- socket.on(JOIN_MAP, data => adjustAndBroadcast(io, socket, state, JOIN_MAP, data))
- socket.on(LEAVE_MAP, () => adjustAndBroadcast(io, socket, state, LEAVE_MAP))
- socket.on('disconnect', () => adjustAndBroadcast(io, socket, state, LEAVE_MAP))
+ socket.on(JOIN_MAP, data => store.dispatch({ type: JOIN_MAP, payload: data }))
+ socket.on(LEAVE_MAP, () => store.dispatch({ type: LEAVE_MAP, payload: socket }))
+ socket.on(JOIN_CALL, data => store.dispatch({ type: JOIN_CALL, payload: data }))
+ socket.on(LEAVE_CALL, () => store.dispatch({ type: LEAVE_CALL, payload: socket }))
+ socket.on('disconnect', () => store.dispatch({ type: 'DISCONNECT', payload: socket }))
socket.on(UPDATE_TOPIC, function (data) {
socket.broadcast.emit(TOPIC_UPDATED, data)
diff --git a/realtime/junto.js b/realtime/junto.js
index aa7f6152..f97efdbc 100644
--- a/realtime/junto.js
+++ b/realtime/junto.js
@@ -1,4 +1,4 @@
-import {
+const {
INVITED_TO_CALL,
INVITED_TO_JOIN,
CALL_ACCEPTED,
@@ -17,11 +17,11 @@ import {
INVITE_A_CALL,
JOIN_CALL,
LEAVE_CALL
-} from '../frontend/src/Metamaps/Realtime/events'
+} = require('../frontend/src/Metamaps/Realtime/events')
const { mapRoom, userMapRoom } = require('./rooms')
-module.exports = function (io, state) {
+module.exports = function (io, store) {
io.on('connection', function (socket) {
socket.on(CHECK_FOR_CALL, function (data) {
@@ -39,6 +39,8 @@ module.exports = function (io, state) {
socket.on(ACCEPT_CALL, function (data) {
socket.broadcast.in(userMapRoom(data.inviter, data.mapid)).emit(CALL_ACCEPTED, data.invited)
+ // convert this so that it broadcasts to all sockets and includes the map id
+ // and who's participating
socket.broadcast.in(mapRoom(data.mapid)).emit(CALL_STARTED)
})
@@ -51,12 +53,15 @@ module.exports = function (io, state) {
})
socket.on(JOIN_CALL, function (data) {
+ // convert this so that it broadcasts to all sockets and includes the map id
+ // and info about who joined
socket.broadcast.in(mapRoom(data.mapid)).emit(MAPPER_JOINED_CALL, data.id)
})
socket.on(LEAVE_CALL, function (data) {
+ // convert this so that it broadcasts to all sockets and includes the map id
+ // and info about who joined
socket.broadcast.in(mapRoom(data.mapid)).emit(MAPPER_LEFT_CALL, data.id)
})
})
}
-
diff --git a/realtime/map.js b/realtime/map.js
index d0c85a10..5e153209 100644
--- a/realtime/map.js
+++ b/realtime/map.js
@@ -1,5 +1,4 @@
-
-import {
+const {
MAPPER_LIST_UPDATED,
NEW_MAPPER,
LOST_MAPPER,
@@ -13,19 +12,19 @@ import {
JOIN_MAP,
LEAVE_MAP,
- SEND_MAPPER_INFO,
SEND_COORDS,
+ SEND_MAPPER_INFO,
CREATE_MESSAGE,
DRAG_TOPIC,
CREATE_TOPIC,
REMOVE_TOPIC,
CREATE_SYNAPSE,
REMOVE_SYNAPSE
-} from '../frontend/src/Metamaps/Realtime/events'
+} = require('../frontend/src/Metamaps/Realtime/events')
const { mapRoom, userMapRoom } = require('./rooms')
-module.exports = function (io, state) {
+module.exports = function (io, store) {
io.on('connection', function (socket) {
// this will ping everyone on a map that there's a person just joined the map
@@ -33,11 +32,11 @@ module.exports = function (io, state) {
socket.mapid = data.mapid
socket.userid = data.userid
socket.username = data.username
- socket.userimage = data.userimage
+ socket.avatar = data.avatar
var newUser = {
userid: data.userid,
username: data.username,
- userimage: data.userimage
+ avatar: data.avatar
}
socket.join(mapRoom(data.mapid))
socket.join(userMapRoom(data.userid, data.mapid))
@@ -63,7 +62,7 @@ module.exports = function (io, state) {
userid: data.userid,
username: data.username,
userinconversation: data.userinconversation,
- userimage: data.userimage
+ avatar: data.avatar
}
socket.broadcast.in(userMapRoom(data.userToNotify, data.mapid)).emit(MAPPER_LIST_UPDATED, existingUser)
})
diff --git a/realtime/realtime-server.js b/realtime/realtime-server.js
index 7cdcd6bf..9b07cfc3 100644
--- a/realtime/realtime-server.js
+++ b/realtime/realtime-server.js
@@ -6,13 +6,14 @@ map = require('./map'),
global = require('./global'),
stunservers = [{"url": "stun:stun.l.google.com:19302"}]
-var state = {
- connectedPeople: {},
- liveMaps: {}
-}
-signalling(io, stunservers, state)
-junto(io, state)
-map(io, state)
-global(io, state)
-io.listen(5001)
+const { createStore } = require('redux')
+const reducer = require('./reducer')
+let store = createStore(reducer)
+
+global(io, store)
+signalling(io, stunservers, store)
+junto(io, store)
+map(io, store)
+
+io.listen(5001)
diff --git a/realtime/reducer.js b/realtime/reducer.js
new file mode 100644
index 00000000..183ee081
--- /dev/null
+++ b/realtime/reducer.js
@@ -0,0 +1,75 @@
+const { omit, omitBy, isNil, mapValues } = require('lodash')
+const {
+ JOIN_MAP,
+ LEAVE_MAP,
+ JOIN_CALL,
+ LEAVE_CALL
+} = require('../frontend/src/Metamaps/Realtime/events')
+
+const NOT_IN_CONVERSATION = 0
+const IN_CONVERSATION = 1
+
+const addMapperToMap = (map, userId) => { return Object.assign({}, map, { [userId]: NOT_IN_CONVERSATION })}
+
+const reducer = (state = { connectedPeople: {}, liveMaps: {} }, action) => {
+ const { type, payload } = action
+ const { connectedPeople, liveMaps } = state
+ const map = payload && liveMaps[payload.mapid]
+ const mapWillEmpty = map && Object.keys(map).length === 1
+ const callWillFinish = map && (type === LEAVE_CALL || type === 'DISCONNECT') && Object.keys(map).length === 2
+
+ switch (type) {
+ case JOIN_MAP:
+ return Object.assign({}, state, {
+ connectedPeople: Object.assign({}, connectedPeople, {
+ [payload.userid]: {
+ id: payload.userid,
+ username: payload.username,
+ avatar: payload.avatar
+ }
+ }),
+ liveMaps: Object.assign({}, liveMaps, {
+ [payload.mapid]: addMapperToMap(map || {}, payload.userid)
+ })
+ })
+ case LEAVE_MAP:
+ // if the map will empty, remove it from liveMaps, if the map will not empty, just remove the mapper
+ const newLiveMaps = mapWillEmpty
+ ? omit(liveMaps, payload.mapid)
+ : Object.assign({}, liveMaps, { [payload.mapid]: omit(map, payload.userid) })
+
+ return {
+ connectedPeople: omit(connectedPeople, payload.userid),
+ liveMaps: omitBy(newLiveMaps, isNil)
+ }
+ case JOIN_CALL:
+ // update the user (payload.id is user id) in the given map to be marked in the conversation
+ return Object.assign({}, state, {
+ liveMaps: Object.assign({}, liveMaps, {
+ [payload.mapid]: Object.assign({}, map, {
+ [payload.id]: IN_CONVERSATION
+ })
+ })
+ })
+ case LEAVE_CALL:
+ const newMap = callWillFinish
+ ? mapValues(map, () => NOT_IN_CONVERSATION)
+ : Object.assign({}, map, { [payload.userid]: NOT_IN_CONVERSATION })
+
+ return Object.assign({}, state, {
+ liveMaps: Object.assign({}, liveMaps, { map: newMap })
+ })
+ case 'DISCONNECT':
+ const mapWithoutUser = omit(map, payload.userid)
+ const newMapWithoutUser = callWillFinish ? mapValues(mapWithoutUser, () => NOT_IN_CONVERSATION) : mapWithoutUser
+ const newLiveMapsWithoutUser = mapWillEmpty ? omit(liveMaps, payload.mapid) : Object.assign({}, liveMaps, { [payload.mapid]: newMapWithoutUser })
+ return {
+ connectedPeople: omit(connectedPeople, payload.userid),
+ liveMaps: omitBy(newLiveMapsWithoutUser, isNil)
+ }
+ default:
+ return state
+ }
+}
+
+module.exports = reducer
diff --git a/realtime/rooms.js b/realtime/rooms.js
index 6276e3f9..30d56d1b 100644
--- a/realtime/rooms.js
+++ b/realtime/rooms.js
@@ -1,4 +1,3 @@
-
module.exports = {
mapRoom: mapId => `maps/${mapId}`,
userMapRoom: (mapperId, mapId) => `mappers/${mapperId}/maps/${mapId}`,
diff --git a/realtime/signal.js b/realtime/signal.js
index c14ce392..39283709 100644
--- a/realtime/signal.js
+++ b/realtime/signal.js
@@ -1,4 +1,4 @@
-var uuid = require('node-uuid')
+const uuid = require('node-uuid')
// based off of https://github.com/andyet/signalmaster
// since it was updated to socket.io 1.3.7
@@ -12,7 +12,6 @@ function safeCb(cb) {
}
module.exports = function(io, stunservers, state) {
-
io.on('connection', function (socket) {
socket.resources = {
screen: false,