This commit is contained in:
Connor Turland 2014-10-27 12:03:55 -04:00
parent cbf71ca2da
commit f58db49bc1
6 changed files with 446 additions and 65 deletions

View file

@ -1,3 +1,7 @@
## 2.6
- Backbone.js in use for client side models
- Realtime depends entirely on sockets for transmitting changes, rather than server using redis to push
## 2.5 ## 2.5
- Initial release - Initial release

View file

@ -3,8 +3,10 @@ Metamaps.JIT = {
mouseMove: 'Metamaps:JIT:events:mouseMove', mouseMove: 'Metamaps:JIT:events:mouseMove',
topicDrag: 'Metamaps:JIT:events:topicDrag', topicDrag: 'Metamaps:JIT:events:topicDrag',
newTopic: 'Metamaps:JIT:events:newTopic', newTopic: 'Metamaps:JIT:events:newTopic',
deleteTopic: 'Metamaps:JIT:events:deleteTopic',
removeTopic: 'Metamaps:JIT:events:removeTopic', removeTopic: 'Metamaps:JIT:events:removeTopic',
newSynapse: 'Metamaps:JIT:events:newSynapse', newSynapse: 'Metamaps:JIT:events:newSynapse',
deleteSynapse: 'Metamaps:JIT:events:deleteSynapse',
removeSynapse: 'Metamaps:JIT:events:removeSynapse', removeSynapse: 'Metamaps:JIT:events:removeSynapse',
pan: 'Metamaps:JIT:events:pan', pan: 'Metamaps:JIT:events:pan',
zoom: 'Metamaps:JIT:events:zoom', zoom: 'Metamaps:JIT:events:zoom',
@ -915,7 +917,24 @@ Metamaps.JIT = {
tempInit = false; tempInit = false;
} else if (!tempInit && node && !node.nodeFrom) { } else if (!tempInit && node && !node.nodeFrom) {
// this means you dragged an existing node, autosave that to the database // this means you dragged an existing node, autosave that to the database
if (Metamaps.Active.Map) {
// check whether to save mappings
var checkWhetherToSave = function() {
var map = Metamaps.Active.Map;
var mapper = Metamaps.Active.Mapper;
// this case
// covers when it is a public map owned by you
// and also when it's a private map
var activeMappersMap = map.authorizePermissionChange(mapper);
var commonsMap = map.get('permission') === 'commons';
var realtimeOn = Metamaps.Realtime.status;
// don't save if commons map, and you have realtime off,
// even if you're map creator
return map && mapper && ((commonsMap && realtimeOn) || (activeMappersMap && !commonsMap));
}
if (checkWhetherToSave()) {
mapping = node.getData('mapping'); mapping = node.getData('mapping');
mapping.save({ mapping.save({
xloc: node.getPos().x, xloc: node.getPos().x,

View file

@ -65,7 +65,7 @@ Metamaps.Selected = {
var self = Metamaps.Selected; var self = Metamaps.Selected;
self.Nodes = []; self.Nodes = [];
self.edges = []; self.Edges = [];
}, },
Nodes: [], Nodes: [],
Edges: [] Edges: []
@ -111,6 +111,36 @@ Metamaps.Backbone.init = function () {
toJSON: function (options) { toJSON: function (options) {
return _.omit(this.attributes, this.blacklist); return _.omit(this.attributes, this.blacklist);
}, },
save: function (key, val, options) {
var attrs;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
var newOptions = options || {};
var s = newOptions.success;
var permBefore = this.get('permission');
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt);
model.trigger('saved');
if (permBefore === 'private' && model.get('permission') !== 'private') {
model.trigger('noLongerPrivate');
}
else if (permBefore !== 'private' && model.get('permission') === 'private') {
model.trigger('nowPrivate');
}
};
return Backbone.Model.prototype.save.call(this, attrs, newOptions);
},
initialize: function () { initialize: function () {
if (this.isNew()) { if (this.isNew()) {
this.set({ this.set({
@ -121,13 +151,27 @@ Metamaps.Backbone.init = function () {
}); });
} }
this.on('changeByOther', this.updateCardView);
this.on('change', this.updateNodeView);
this.on('saved', this.savedEvent);
this.on('nowPrivate', function(){
var removeTopicData = {
topicid: this.id
};
$(document).trigger(Metamaps.JIT.events.removeTopic, [removeTopicData]);
});
this.on('noLongerPrivate', function(){
var newTopicData = {
mappingid: this.getMapping().id,
topicid: this.id
};
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData]);
});
this.on('change:metacode_id', Metamaps.Filter.checkMetacodes, this); this.on('change:metacode_id', Metamaps.Filter.checkMetacodes, this);
var updateName = function () {
if (this.get('node')) this.get('node').name = this.get('name');
if (Metamaps.Visualize) Metamaps.Visualize.mGraph.plot();
};
this.on('change:name', updateName, this);
}, },
authorizeToEdit: function (mapper) { authorizeToEdit: function (mapper) {
if (mapper && (this.get('permission') === "commons" || this.get('user_id') === mapper.get('id'))) return true; if (mapper && (this.get('permission') === "commons" || this.get('user_id') === mapper.get('id'))) return true;
@ -183,6 +227,41 @@ Metamaps.Backbone.init = function () {
return node; return node;
}, },
savedEvent: function() {
Metamaps.Realtime.sendTopicChange(this);
},
updateViews: function() {
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic;
var node = this.get('node');
// update topic card, if this topic is the one open there
if (onPageWithTopicCard && this == Metamaps.TopicCard.openTopicCard) {
Metamaps.TopicCard.showCard(node);
}
// update the node on the map
if (onPageWithTopicCard && node) {
node.name = this.get('name');
Metamaps.Visualize.mGraph.plot();
}
},
updateCardView: function() {
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic;
var node = this.get('node');
// update topic card, if this topic is the one open there
if (onPageWithTopicCard && this == Metamaps.TopicCard.openTopicCard) {
Metamaps.TopicCard.showCard(node);
}
},
updateNodeView: function() {
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic;
var node = this.get('node');
// update the node on the map
if (onPageWithTopicCard && node) {
node.name = this.get('name');
Metamaps.Visualize.mGraph.plot();
}
}
}); });
self.TopicCollection = Backbone.Collection.extend({ self.TopicCollection = Backbone.Collection.extend({
@ -196,6 +275,36 @@ Metamaps.Backbone.init = function () {
toJSON: function (options) { toJSON: function (options) {
return _.omit(this.attributes, this.blacklist); return _.omit(this.attributes, this.blacklist);
}, },
save: function (key, val, options) {
var attrs;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
var newOptions = options || {};
var s = newOptions.success;
var permBefore = this.get('permission');
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt);
model.trigger('saved');
if (permBefore === 'private' && model.get('permission') !== 'private') {
model.trigger('noLongerPrivate');
}
else if (permBefore !== 'private' && model.get('permission') === 'private') {
model.trigger('nowPrivate');
}
};
return Backbone.Model.prototype.save.call(this, attrs, newOptions);
},
initialize: function () { initialize: function () {
if (this.isNew()) { if (this.isNew()) {
this.set({ this.set({
@ -204,6 +313,24 @@ Metamaps.Backbone.init = function () {
"category": "from-to" "category": "from-to"
}); });
} }
this.on('changeByOther', this.updateCardView);
this.on('change', this.updateEdgeView);
this.on('saved', this.savedEvent);
this.on('noLongerPrivate', function(){
var newSynapseData = {
mappingid: this.getMapping().id,
synapseid: this.id
};
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData]);
});
this.on('nowPrivate', function(){
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
synapseid: this.id
}]);
});
this.on('change:desc', Metamaps.Filter.checkSynapses, this); this.on('change:desc', Metamaps.Filter.checkSynapses, this);
}, },
prepareLiForFilter: function () { prepareLiForFilter: function () {
@ -277,6 +404,31 @@ Metamaps.Backbone.init = function () {
return edge; return edge;
}, },
savedEvent: function() {
Metamaps.Realtime.sendSynapseChange(this);
},
updateViews: function() {
this.updateCardView();
this.updateEdgeView();
},
updateCardView: function() {
var onPageWithSynapseCard = Metamaps.Active.Map || Metamaps.Active.Topic;
var edge = this.get('edge');
// update synapse card, if this synapse is the one open there
if (onPageWithSynapseCard && edge == Metamaps.SynapseCard.openSynapseCard) {
Metamaps.SynapseCard.showCard(edge);
}
},
updateEdgeView: function() {
var onPageWithSynapseCard = Metamaps.Active.Map || Metamaps.Active.Topic;
var edge = this.get('edge');
// update the edge on the map
if (onPageWithSynapseCard && edge) {
Metamaps.Visualize.mGraph.plot();
}
}
}); });
self.SynapseCollection = Backbone.Collection.extend({ self.SynapseCollection = Backbone.Collection.extend({
@ -850,7 +1002,6 @@ Metamaps.TopicCard = {
$('.metacodeSelect li li').click(metacodeLiClick); $('.metacodeSelect li li').click(metacodeLiClick);
var bipName = $(showCard).find('.best_in_place_name'); var bipName = $(showCard).find('.best_in_place_name');
bipName.best_in_place();
bipName.bind("best_in_place:activate", function () { bipName.bind("best_in_place:activate", function () {
var $el = bipName.find('textarea'); var $el = bipName.find('textarea');
var el = $el[0]; var el = $el[0];
@ -872,12 +1023,14 @@ Metamaps.TopicCard = {
bipName.bind("ajax:success", function () { bipName.bind("ajax:success", function () {
var name = Metamaps.Util.decodeEntities($(this).html()); var name = Metamaps.Util.decodeEntities($(this).html());
topic.set("name", name); topic.set("name", name);
topic.trigger('saved');
}); });
$(showCard).find('.best_in_place_desc').bind("ajax:success", function () { $(showCard).find('.best_in_place_desc').bind("ajax:success", function () {
this.innerHTML = this.innerHTML.replace(/\r/g, '') this.innerHTML = this.innerHTML.replace(/\r/g, '')
var desc = $(this).html(); var desc = $(this).html();
topic.set("desc", desc); topic.set("desc", desc);
topic.trigger('saved');
}); });
} }
@ -1108,6 +1261,7 @@ Metamaps.SynapseCard = {
} else { } else {
synapse.set("desc", desc); synapse.set("desc", desc);
} }
synapse.trigger('saved');
Metamaps.Control.selectEdge(synapse.get('edge')); Metamaps.Control.selectEdge(synapse.get('edge'));
Metamaps.Visualize.mGraph.plot(); Metamaps.Visualize.mGraph.plot();
}); });
@ -1333,7 +1487,7 @@ Metamaps.Visualize = {
if (self.type == "RGraph") { if (self.type == "RGraph") {
self.mGraph.graph.eachNode(function (n) { self.mGraph.graph.eachNode(function (n) {
topic = Metamaps.Topics.get(n.id); topic = Metamaps.Topics.get(n.id);
topic.set('node', n); topic.set({ node: n }, { silent: true });
topic.updateNode(); topic.updateNode();
n.eachAdjacency(function (edge) { n.eachAdjacency(function (edge) {
@ -1343,7 +1497,7 @@ Metamaps.Visualize = {
l = edge.getData('synapseIDs').length; l = edge.getData('synapseIDs').length;
for (i = 0; i < l; i++) { for (i = 0; i < l; i++) {
synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i]); synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i]);
synapse.set('edge', edge); synapse.set({ edge: edge }, { silent: true });
synapse.updateEdge(); synapse.updateEdge();
} }
} }
@ -1358,7 +1512,7 @@ Metamaps.Visualize = {
self.mGraph.graph.eachNode(function (n) { self.mGraph.graph.eachNode(function (n) {
topic = Metamaps.Topics.get(n.id); topic = Metamaps.Topics.get(n.id);
topic.set('node', n); topic.set({ node: n }, { silent: true });
topic.updateNode(); topic.updateNode();
mapping = topic.getMapping(); mapping = topic.getMapping();
@ -1369,7 +1523,7 @@ Metamaps.Visualize = {
l = edge.getData('synapseIDs').length; l = edge.getData('synapseIDs').length;
for (i = 0; i < l; i++) { for (i = 0; i < l; i++) {
synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i]); synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i]);
synapse.set('edge', edge); synapse.set({ edge: edge }, { silent: true });
synapse.updateEdge(); synapse.updateEdge();
} }
} }
@ -1510,6 +1664,7 @@ Metamaps.Util = {
return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2)); return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2));
}, },
coordsToPixels: function (coords) { coordsToPixels: function (coords) {
if (Metamaps.Visualize.mGraph) {
var canvas = Metamaps.Visualize.mGraph.canvas, var canvas = Metamaps.Visualize.mGraph.canvas,
s = canvas.getSize(), s = canvas.getSize(),
p = canvas.getPos(), p = canvas.getPos(),
@ -1522,6 +1677,13 @@ Metamaps.Util = {
y: (coords.y / (1/sy)) + p.y + s.height/2 + oy y: (coords.y / (1/sy)) + p.y + s.height/2 + oy
}; };
return pixels; return pixels;
}
else {
return {
x: 0,
y: 0
};
}
}, },
pixelsToCoords: function (pixels) { pixelsToCoords: function (pixels) {
var canvas = Metamaps.Visualize.mGraph.canvas, var canvas = Metamaps.Visualize.mGraph.canvas,
@ -1597,10 +1759,10 @@ Metamaps.Realtime = {
init: function () { init: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var turnOn = function () { var reenableRealtime = function () {
self.turnOn(true); self.reenableRealtime();
} };
$(".rtOn").click(turnOn); $(".rtOn").click(reenableRealtime);
$(".rtOff").click(self.turnOff); $(".rtOff").click(self.turnOff);
$('.sidebarCollaborateIcon').click(self.toggleBox); $('.sidebarCollaborateIcon').click(self.toggleBox);
@ -1612,7 +1774,9 @@ Metamaps.Realtime = {
var railsEnv = $('body').data('env'); var railsEnv = $('body').data('env');
var whichToConnect = railsEnv === 'development' ? self.stringForLocalhost : self.stringForHeroku; var whichToConnect = railsEnv === 'development' ? self.stringForLocalhost : self.stringForHeroku;
self.socket = io.connect(whichToConnect); self.socket = io.connect(whichToConnect);
self.socket.on('connect', function () {
self.startActiveMap(); self.startActiveMap();
});
}, },
toggleBox: function (event) { toggleBox: function (event) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -1650,31 +1814,34 @@ Metamaps.Realtime = {
startActiveMap: function () { startActiveMap: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var mapperm = Metamaps.Active.Map && Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper); if (Metamaps.Active.Map) {
var commonsMap = Metamaps.Active.Map.get('permission') === 'commons';
var start = function() { if (commonsMap) {
if (mapperm) {
self.turnOn(); self.turnOn();
self.setupSocket(); self.setupSocket();
} }
} }
if (!self.socket.connected) {
self.socket.socket.connect();
}
self.socket.on('connect', function () {
start();
});
}, },
endActiveMap: function () { endActiveMap: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
$(document).off(Metamaps.JIT.events.mouseMove); $(document).off(Metamaps.JIT.events.mouseMove);
self.socket.disconnect();
self.socket.removeAllListeners(); self.socket.removeAllListeners();
self.socket.emit('endMapperNotify');
$(".collabCompass").remove(); $(".collabCompass").remove();
self.status = false; self.status = false;
}, },
reenableRealtime: function() {
var confirmString = "The layout of your map has fallen out of sync with the saved copy. ";
confirmString += "To save your changes without overwriting the map, hit 'Cancel' and ";
confirmString += "then use 'Save to new map'. ";
confirmString += "Do you want to discard your changes and enable realtime?";
var c = confirm(confirmString);
if (c) {
Metamaps.Router.maps(Metamaps.Active.Map.id);
}
},
turnOn: function (notify) { turnOn: function (notify) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -1742,6 +1909,14 @@ Metamaps.Realtime = {
// update mapper compass position // update mapper compass position
socket.on('maps-' + Metamaps.Active.Map.id + '-updatePeerCoords', self.updatePeerCoords); socket.on('maps-' + Metamaps.Active.Map.id + '-updatePeerCoords', self.updatePeerCoords);
// deletions
socket.on('deleteTopicFromServer', self.removeTopic);
socket.on('deleteSynapseFromServer', self.removeSynapse);
socket.on('topicChangeFromServer', self.topicChange);
socket.on('synapseChangeFromServer', self.synapseChange);
socket.on('mapChangeFromServer', self.mapChange);
// local event listeners that trigger events // local event listeners that trigger events
var sendCoords = function (event, coords) { var sendCoords = function (event, coords) {
self.sendCoords(coords); self.sendCoords(coords);
@ -1773,6 +1948,11 @@ Metamaps.Realtime = {
}; };
$(document).on(Metamaps.JIT.events.newTopic, sendNewTopic); $(document).on(Metamaps.JIT.events.newTopic, sendNewTopic);
var sendDeleteTopic = function (event, data) {
self.sendDeleteTopic(data);
};
$(document).on(Metamaps.JIT.events.deleteTopic, sendDeleteTopic);
var sendRemoveTopic = function (event, data) { var sendRemoveTopic = function (event, data) {
self.sendRemoveTopic(data); self.sendRemoveTopic(data);
}; };
@ -1783,6 +1963,11 @@ Metamaps.Realtime = {
}; };
$(document).on(Metamaps.JIT.events.newSynapse, sendNewSynapse); $(document).on(Metamaps.JIT.events.newSynapse, sendNewSynapse);
var sendDeleteSynapse = function (event, data) {
self.sendDeleteSynapse(data);
};
$(document).on(Metamaps.JIT.events.deleteSynapse, sendDeleteSynapse);
var sendRemoveSynapse = function (event, data) { var sendRemoveSynapse = function (event, data) {
self.sendRemoveSynapse(data); self.sendRemoveSynapse(data);
}; };
@ -1849,7 +2034,7 @@ Metamaps.Realtime = {
$('.realtimeMapperList ul').append(mapperListItem); $('.realtimeMapperList ul').append(mapperListItem);
// create a div for the collaborators compass // 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.userimage, self.mappersOnMap[data.userid].color, !self.status);
} }
}, },
newPeerOnMap: function (data) { newPeerOnMap: function (data) {
@ -1883,7 +2068,7 @@ Metamaps.Realtime = {
$('.realtimeMapperList ul').append(mapperListItem); $('.realtimeMapperList ul').append(mapperListItem);
// create a div for the collaborators compass // 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.userimage, self.mappersOnMap[data.userid].color, !self.status);
Metamaps.GlobalUI.notifyUser(data.username + ' just joined the map'); Metamaps.GlobalUI.notifyUser(data.username + ' just joined the map');
@ -1899,7 +2084,7 @@ Metamaps.Realtime = {
socket.emit('updateNewMapperList', update); socket.emit('updateNewMapperList', update);
} }
}, },
createCompass: function(name, id, image, color) { createCompass: function(name, id, image, color, hide) {
var str = '<img width="28" height="28" src="'+image+'" /><p>'+name+'</p>'; var str = '<img width="28" height="28" src="'+image+'" /><p>'+name+'</p>';
str += '<div id="compassArrow'+id+'" class="compassArrow"></div>'; str += '<div id="compassArrow'+id+'" class="compassArrow"></div>';
$('#compass' + id).remove(); $('#compass' + id).remove();
@ -1907,6 +2092,9 @@ Metamaps.Realtime = {
id: 'compass' + id, id: 'compass' + id,
class: 'collabCompass' class: 'collabCompass'
}).html(str).appendTo('#wrapper'); }).html(str).appendTo('#wrapper');
if (hide) {
$('#compass' + id).hide();
}
$('#compass' + id + ' img').css({ $('#compass' + id + ' img').css({
'border': '2px solid ' + color 'border': '2px solid ' + color
}); });
@ -2071,6 +2259,75 @@ Metamaps.Realtime = {
Metamaps.Visualize.mGraph.plot(); Metamaps.Visualize.mGraph.plot();
} }
}, },
sendTopicChange: function (topic) {
var self = Metamaps.Realtime;
var socket = self.socket;
var data = {
topicId: topic.id
}
socket.emit('topicChangeFromClient', data);
},
topicChange: function (data) {
var topic = Metamaps.Topics.get(data.topicId);
if (topic) {
var node = topic.get('node');
topic.fetch({
success: function (model) {
model.set({ node: node });
model.trigger('changeByOther');
}
});
}
},
sendSynapseChange: function (synapse) {
var self = Metamaps.Realtime;
var socket = self.socket;
var data = {
synapseId: synapse.id
}
socket.emit('synapseChangeFromClient', data);
},
synapseChange: function (data) {
var synapse = Metamaps.Synapses.get(data.synapseId);
if (synapse) {
// edge reset necessary because fetch causes model reset
var edge = synapse.get('edge');
synapse.fetch({
success: function (model) {
model.set({ edge: edge });
model.trigger('changeByOther');
}
});
}
},
sendMapChange: function (map) {
var self = Metamaps.Realtime;
var socket = self.socket;
var data = {
mapId: map.id
}
socket.emit('mapChangeFromClient', data);
},
mapChange: function (data) {
/*var map = Metamaps.Topics.get(data.topicId);
if (map) {
var node = topic.get('node');
topic.fetch({
success: function (model) {
// must be set using silent:true otherwise
// will trigger a change event and an infinite
// loop with other clients of change events
model.set({ node: node });
}
});
}*/
},
// newTopic // newTopic
sendNewTopic: function (data) { sendNewTopic: function (data) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2085,6 +2342,11 @@ Metamaps.Realtime = {
newTopic: function (data) { newTopic: function (data) {
var topic, mapping, mapper, mapperCallback, cancel; var topic, mapping, mapper, mapperCallback, cancel;
var self = Metamaps.Realtime;
var socket = self.socket;
if (!self.status) return;
function test() { function test() {
if (topic && mapping && mapper) { if (topic && mapping && mapper) {
Metamaps.Topic.renderTopic(mapping, topic, false, false); Metamaps.Topic.renderTopic(mapping, topic, false, false);
@ -2126,24 +2388,45 @@ Metamaps.Realtime = {
test(); test();
}, },
// removeTopic // removeTopic
sendDeleteTopic: function (data) {
var self = Metamaps.Realtime;
var socket = self.socket;
if (Metamaps.Active.Map) {
socket.emit('deleteTopicFromClient', data);
}
},
// removeTopic
sendRemoveTopic: function (data) { sendRemoveTopic: function (data) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var socket = self.socket; var socket = self.socket;
if (Metamaps.Active.Map && self.status) { if (Metamaps.Active.Map) {
data.mapid = Metamaps.Active.Map.id; data.mapid = Metamaps.Active.Map.id;
socket.emit('removeTopic', data); socket.emit('removeTopic', data);
} }
}, },
removeTopic: function (data) { removeTopic: function (data) {
var self = Metamaps.Realtime;
var socket = self.socket;
if (!self.status) return;
var topic = Metamaps.Topics.get(data.topicid);
if (topic) {
var node = topic.get('node');
var mapping = topic.getMapping();
Metamaps.Control.hideNode(node.id);
Metamaps.Topics.remove(topic);
Metamaps.Mappings.remove(mapping);
}
}, },
// newSynapse // newSynapse
sendNewSynapse: function (data) { sendNewSynapse: function (data) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var socket = self.socket; var socket = self.socket;
if (Metamaps.Active.Map && self.status) { if (Metamaps.Active.Map) {
data.mapperid = Metamaps.Active.Mapper.id; data.mapperid = Metamaps.Active.Mapper.id;
data.mapid = Metamaps.Active.Map.id; data.mapid = Metamaps.Active.Map.id;
socket.emit('newSynapse', data); socket.emit('newSynapse', data);
@ -2152,6 +2435,11 @@ Metamaps.Realtime = {
newSynapse: function (data) { newSynapse: function (data) {
var topic1, topic2, node1, node2, synapse, mapping, cancel; var topic1, topic2, node1, node2, synapse, mapping, cancel;
var self = Metamaps.Realtime;
var socket = self.socket;
if (!self.status) return;
function test() { function test() {
if (synapse && mapping && mapper) { if (synapse && mapping && mapper) {
topic1 = synapse.getTopic1(); topic1 = synapse.getTopic1();
@ -2196,18 +2484,49 @@ Metamaps.Realtime = {
}); });
test(); test();
}, },
// deleteSynapse
sendDeleteSynapse: function (data) {
var self = Metamaps.Realtime;
var socket = self.socket;
if (Metamaps.Active.Map) {
data.mapid = Metamaps.Active.Map.id;
socket.emit('deleteSynapseFromClient', data);
}
},
// removeSynapse // removeSynapse
sendRemoveSynapse: function (data) { sendRemoveSynapse: function (data) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
var socket = self.socket; var socket = self.socket;
if (Metamaps.Active.Map && self.status) { if (Metamaps.Active.Map) {
data.mapid = Metamaps.Active.Map.id; data.mapid = Metamaps.Active.Map.id;
socket.emit('removeSynapse', data); socket.emit('removeSynapse', data);
} }
}, },
removeSynapse: function (data) { removeSynapse: function (data) {
var self = Metamaps.Realtime;
var socket = self.socket;
if (!self.status) return;
var synapse = Metamaps.Synapses.get(data.synapseid);
if (synapse) {
var edge = synapse.get('edge');
var mapping = synapse.getMapping();
if (edge.getData("mappings").length - 1 === 0) {
Metamaps.Control.hideEdge(edge);
}
var index = _.indexOf(edge.getData("synapses"), synapse);
edge.getData("mappings").splice(index, 1);
edge.getData("synapses").splice(index, 1);
if (edge.getData("displayIndex")) {
delete edge.data.$displayIndex;
}
Metamaps.Synapses.remove(synapse);
Metamaps.Mappings.remove(mapping);
}
}, },
}; // end Metamaps.Realtime }; // end Metamaps.Realtime
@ -2267,8 +2586,14 @@ Metamaps.Control = {
}, },
deleteNode: function (nodeid) { // refers to deleting topics permanently deleteNode: function (nodeid) { // refers to deleting topics permanently
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid); var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid);
Metamaps.Control.deselectNode(node); var topic = node.getData('topic');
Metamaps.Topics.get(nodeid).destroy(); var topicid = topic.id;
var mapping = node.getData('mapping');
topic.destroy();
Metamaps.Mappings.remove(mapping);
$(document).trigger(Metamaps.JIT.events.deleteTopic, [{
topicid: topicid
}]);
Metamaps.Control.hideNode(nodeid); Metamaps.Control.hideNode(nodeid);
}, },
removeSelectedNodes: function () { // refers to removing topics permanently from a map removeSelectedNodes: function () { // refers to removing topics permanently from a map
@ -2289,8 +2614,14 @@ Metamaps.Control = {
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid); var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid);
if (mapperm) { if (mapperm) {
Metamaps.Control.deselectNode(node); var topic = node.getData('topic');
node.getData('mapping').destroy(); var topicid = topic.id;
var mapping = node.getData('mapping');
mapping.destroy();
Metamaps.Topics.remove(topic);
$(document).trigger(Metamaps.JIT.events.removeTopic, [{
topicid: topicid
}]);
Metamaps.Control.hideNode(nodeid); Metamaps.Control.hideNode(nodeid);
} }
}, },
@ -2306,9 +2637,10 @@ Metamaps.Control = {
}, },
hideNode: function (nodeid) { hideNode: function (nodeid) {
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid); var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid);
var graph = Metamaps.Visualize.mGraph;
if (nodeid == Metamaps.Visualize.mGraph.root) { // && Metamaps.Visualize.type === "RGraph" if (nodeid == Metamaps.Visualize.mGraph.root) { // && Metamaps.Visualize.type === "RGraph"
alert("You can't hide this topic, it is the root of your graph."); var newroot = _.find(graph.graph.nodes, function(n){ return n.id !== nodeid; });
return; graph.root = newroot ? newroot.id : null;
} }
Metamaps.Control.deselectNode(node); Metamaps.Control.deselectNode(node);
@ -2383,8 +2715,6 @@ Metamaps.Control = {
}, },
deleteEdge: function (edge) { deleteEdge: function (edge) {
// TODO make it so that you select which one, of multiple possible synapses you want to delete
if (edge.getData("synapses").length - 1 === 0) { if (edge.getData("synapses").length - 1 === 0) {
Metamaps.Control.hideEdge(edge); Metamaps.Control.hideEdge(edge);
} }
@ -2393,6 +2723,7 @@ Metamaps.Control = {
var synapse = edge.getData("synapses")[index]; var synapse = edge.getData("synapses")[index];
var mapping = edge.getData("mappings")[index]; var mapping = edge.getData("mappings")[index];
var synapseid = synapse.id;
synapse.destroy(); synapse.destroy();
// the server will destroy the mapping, we just need to remove it here // the server will destroy the mapping, we just need to remove it here
@ -2402,6 +2733,9 @@ Metamaps.Control = {
if (edge.getData("displayIndex")) { if (edge.getData("displayIndex")) {
delete edge.data.$displayIndex; delete edge.data.$displayIndex;
} }
$(document).trigger(Metamaps.JIT.events.deleteSynapse, [{
synapseid: synapseid
}]);
}, },
removeSelectedEdges: function () { removeSelectedEdges: function () {
var l = Metamaps.Selected.Edges.length, var l = Metamaps.Selected.Edges.length,
@ -2418,8 +2752,6 @@ Metamaps.Control = {
}, },
removeEdge: function (edge) { removeEdge: function (edge) {
// TODO make it so that you select which one, of multiple possible synapses you want
if (edge.getData("mappings").length - 1 === 0) { if (edge.getData("mappings").length - 1 === 0) {
Metamaps.Control.hideEdge(edge); Metamaps.Control.hideEdge(edge);
} }
@ -2428,6 +2760,7 @@ Metamaps.Control = {
var synapse = edge.getData("synapses")[index]; var synapse = edge.getData("synapses")[index];
var mapping = edge.getData("mappings")[index]; var mapping = edge.getData("mappings")[index];
var synapseid = synapse.id;
mapping.destroy(); mapping.destroy();
Metamaps.Synapses.remove(synapse); Metamaps.Synapses.remove(synapse);
@ -2437,6 +2770,9 @@ Metamaps.Control = {
if (edge.getData("displayIndex")) { if (edge.getData("displayIndex")) {
delete edge.data.$displayIndex; delete edge.data.$displayIndex;
} }
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
synapseid: synapseid
}]);
}, },
hideSelectedEdges: function () { hideSelectedEdges: function () {
var edge, var edge,
@ -3857,6 +4193,7 @@ Metamaps.Map.InfoBox = {
var name = $(this).html(); var name = $(this).html();
$('.mapName').html(name); $('.mapName').html(name);
Metamaps.Active.Map.set('name', name); Metamaps.Active.Map.set('name', name);
Metamaps.Active.Map.trigger('saved');
}); });
$('.yourMap .mapPermission').unbind().click(self.onPermissionClick); $('.yourMap .mapPermission').unbind().click(self.onPermissionClick);

View file

@ -3,14 +3,13 @@
div.uv-icon.uv-bottom-left { div.uv-icon.uv-bottom-left {
background-image:url(feedback_sprite.png); background-image:url(feedback_sprite.png);
background-color:#222222;
color:#FFFFFF; color:#FFFFFF;
cursor:pointer; cursor:pointer;
height:108px; height:108px;
left:0; left:0;
margin-left:0px; margin-left:0px;
text-indent:-100000px; text-indent:-100000px;
top:25%; top:65%;
width:25px; width:25px;
z-index:100000; z-index:100000;
opacity: 1; opacity: 1;

View file

@ -75,7 +75,7 @@ class MapsController < ApplicationController
@map = Map.find(params[:id]).authorize_to_show(@current) @map = Map.find(params[:id]).authorize_to_show(@current)
if not @map if not @map
redirect_to root_url and return redirect_to root_url, notice: "Access denied. That map is private." and return
end end
respond_to do |format| respond_to do |format|
@ -98,7 +98,7 @@ class MapsController < ApplicationController
@map = Map.find(params[:id]).authorize_to_show(@current) @map = Map.find(params[:id]).authorize_to_show(@current)
if not @map if not @map
redirect_to root_url and return redirect_to root_url, notice: "Access denied. That map is private." and return
end end
@allmappers = @map.contributors @allmappers = @map.contributors

View file

@ -66,8 +66,7 @@ function start() {
socket.broadcast.emit('maps-' + data.mapid + '-newmapper', newUser); socket.broadcast.emit('maps-' + data.mapid + '-newmapper', newUser);
}); });
// this will ping everyone on a map that there's a person just left the map var end = function () {
socket.on('disconnect', function () {
var socketUserName, socketUserID; var socketUserName, socketUserID;
socket.get('userid', function (err, id) { socket.get('userid', function (err, id) {
socketUserID = id; socketUserID = id;
@ -82,7 +81,10 @@ function start() {
socket.get('mapid', function (err, mapid) { socket.get('mapid', function (err, mapid) {
socket.broadcast.emit('maps-' + mapid + '-lostmapper', data); socket.broadcast.emit('maps-' + mapid + '-lostmapper', data);
}); });
}); };
// this will ping everyone on a map that there's a person just left the map
socket.on('disconnect', end);
socket.on('endMapperNotify', end);
// this will ping everyone on a map that someone just turned on realtime // this will ping everyone on a map that someone just turned on realtime
socket.on('notifyStartRealtime', function (data) { socket.on('notifyStartRealtime', function (data) {
@ -127,6 +129,22 @@ function start() {
socket.broadcast.emit('maps-' + mapId + '-newTopic', data); socket.broadcast.emit('maps-' + mapId + '-newTopic', data);
}); });
socket.on('topicChangeFromClient', function (data) {
socket.broadcast.emit('topicChangeFromServer', data);
});
socket.on('synapseChangeFromClient', function (data) {
socket.broadcast.emit('synapseChangeFromServer', data);
});
socket.on('mapChangeFromClient', function (data) {
socket.broadcast.emit('mapChangeFromServer', data);
});
socket.on('deleteTopicFromClient', function (data) {
socket.broadcast.emit('deleteTopicFromServer', data);
});
socket.on('removeTopic', function (data) { socket.on('removeTopic', function (data) {
var mapId = data.mapid; var mapId = data.mapid;
delete data.mapid; delete data.mapid;
@ -141,6 +159,10 @@ function start() {
socket.broadcast.emit('maps-' + mapId + '-newSynapse', data); socket.broadcast.emit('maps-' + mapId + '-newSynapse', data);
}); });
socket.on('deleteSynapseFromClient', function (data) {
socket.broadcast.emit('deleteSynapseFromServer', data);
});
socket.on('removeSynapse', function (data) { socket.on('removeSynapse', function (data) {
var mapId = data.mapid; var mapId = data.mapid;
delete data.mapid; delete data.mapid;