great progress

This commit is contained in:
Connor Turland 2015-12-11 14:23:41 -05:00
parent 2929547736
commit 089528c46d
20 changed files with 524 additions and 226 deletions

View file

@ -42,14 +42,8 @@ GEM
aws-sdk-v1 (1.66.0) aws-sdk-v1 (1.66.0)
json (~> 1.4) json (~> 1.4)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
aws-sdk (2.1.19)
aws-sdk-resources (= 2.1.19)
aws-sdk-core (2.1.19)
jmespath (~> 1.0)
aws-sdk-resources (2.1.19)
aws-sdk-core (= 2.1.19)
bcrypt (3.1.10) bcrypt (3.1.10)
best_in_place (3.0.3) best_in_place (3.1.0)
actionpack (>= 3.2) actionpack (>= 3.2)
railties (>= 3.2) railties (>= 3.2)
better_errors (2.1.1) better_errors (2.1.1)
@ -59,12 +53,11 @@ GEM
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
builder (3.2.2) builder (3.2.2)
byebug (4.0.5) byebug (8.2.1)
columnize (= 0.9.0) cancancan (1.13.1)
cancancan (1.12.0)
climate_control (0.0.3) climate_control (0.0.3)
activesupport (>= 3.0) activesupport (>= 3.0)
cocaine (0.5.7) cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0) climate_control (>= 0.0.3, < 1.0)
coderay (1.1.0) coderay (1.1.0)
coffee-rails (4.1.0) coffee-rails (4.1.0)
@ -73,8 +66,8 @@ GEM
coffee-script (2.4.1) coffee-script (2.4.1)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.9.1.1) coffee-script-source (1.10.0)
columnize (0.9.0) concurrent-ruby (1.0.0)
debug_inspector (0.0.2) debug_inspector (0.0.2)
devise (3.5.2) devise (3.5.2)
bcrypt (~> 3.0) bcrypt (~> 3.0)
@ -83,7 +76,7 @@ GEM
responders responders
thread_safe (~> 0.1) thread_safe (~> 0.1)
warden (~> 1.2.3) warden (~> 1.2.3)
dotenv (2.0.0) dotenv (2.0.2)
erubis (2.7.0) erubis (2.7.0)
execjs (2.6.0) execjs (2.6.0)
ezcrypto (0.7.2) ezcrypto (0.7.2)
@ -94,7 +87,7 @@ GEM
globalid (0.3.6) globalid (0.3.6)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
i18n (0.7.0) i18n (0.7.0)
jbuilder (2.3.1) jbuilder (2.3.2)
activesupport (>= 3.0.0, < 5) activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2) multi_json (~> 1.2)
jquery-rails (4.0.5) jquery-rails (4.0.5)
@ -112,28 +105,28 @@ GEM
mail (2.6.3) mail (2.6.3)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.6.1) mime-types (2.99)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_portile (0.6.2) mini_portile2 (2.0.0)
minitest (5.8.0) minitest (5.8.3)
multi_json (1.11.2) multi_json (1.11.2)
nokogiri (1.6.6.2) nokogiri (1.6.7)
mini_portile (~> 0.6.0) mini_portile2 (~> 2.0.0.rc2)
oauth (0.4.7) oauth (0.4.7)
orm_adapter (0.5.0) orm_adapter (0.5.0)
paperclip (4.3.0) paperclip (4.3.2)
activemodel (>= 3.2.0) activemodel (>= 3.2.0)
activesupport (>= 3.2.0) activesupport (>= 3.2.0)
cocaine (~> 0.5.5) cocaine (~> 0.5.5)
mime-types mime-types
mimemagic (= 0.3.0) mimemagic (= 0.3.0)
pg (0.18.3) pg (0.18.4)
pry (0.10.1) pry (0.10.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
pry-byebug (3.1.0) pry-byebug (3.3.0)
byebug (~> 4.0) byebug (~> 8.0)
pry (~> 0.10) pry (~> 0.10)
pry-rails (0.3.4) pry-rails (0.3.4)
pry (>= 0.9.10) pry (>= 0.9.10)
@ -174,10 +167,10 @@ GEM
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rake (10.4.2) rake (10.4.2)
redis (3.2.1) redis (3.2.2)
responders (2.1.0) responders (2.1.0)
railties (>= 4.2.0, < 5) railties (>= 4.2.0, < 5)
sass (3.4.18) sass (3.4.19)
sass-rails (5.0.4) sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0) railties (>= 4.0.0, < 5.0)
sass (~> 3.1) sass (~> 3.1)
@ -185,8 +178,9 @@ GEM
sprockets-rails (>= 2.0, < 4.0) sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3) tilt (>= 1.1, < 3)
slop (3.6.0) slop (3.6.0)
sprockets (3.3.4) sprockets (3.5.0)
rack (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (2.3.3) sprockets-rails (2.3.3)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)

View file

@ -206,6 +206,22 @@ Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
} }
}); });
Metamaps.Backbone.Message = Backbone.Model.extend({
urlRoot: '/messages',
blacklist: ['created_at', 'updated_at'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist);
},
prepareLiForFilter: function () {
/*var li = '';
li += '<li data-id="' + this.id.toString() + '">';
li += '<img src="' + this.get("image") + '" data-id="' + this.id.toString() + '"';
li += ' alt="' + this.get('name') + '" />';
li += '<p>' + this.get('name') + '</p></li>';
return li;*/
}
});
Metamaps.Backbone.Mapper = Backbone.Model.extend({ Metamaps.Backbone.Mapper = Backbone.Model.extend({
urlRoot: '/users', urlRoot: '/users',
blacklist: ['created_at', 'updated_at'], blacklist: ['created_at', 'updated_at'],

View file

@ -333,7 +333,6 @@ Metamaps.GlobalUI.Account = {
open: function () { open: function () {
var self = Metamaps.GlobalUI.Account; var self = Metamaps.GlobalUI.Account;
Metamaps.Realtime.close();
Metamaps.Filter.close(); Metamaps.Filter.close();
$('.sidebarAccountIcon .tooltipsUnder').addClass('hide'); $('.sidebarAccountIcon .tooltipsUnder').addClass('hide');

View file

@ -1907,17 +1907,16 @@ Metamaps.Util = {
* *
*/ */
Metamaps.Realtime = { Metamaps.Realtime = {
stringForLocalhost: 'http://localhost:5001', stringForLocalhost: 'http://' + location.host.split(':')[0] + ':5001',
stringForMetamaps: 'http://metamaps.cc:5001', stringForMetamaps: 'http://metamaps.cc:5001',
stringForHeroku: 'http://gentle-savannah-1303.herokuapp.com', stringForHeroku: 'http://gentle-savannah-1303.herokuapp.com',
videoId: 'video-wrapper', videoId: 'video-wrapper',
socket: null, socket: null,
webrtc: null, webrtc: null,
readyToCall: false, readyToCall: false,
isOpen: false,
changing: false,
mappersOnMap: {}, mappersOnMap: {},
status: true, // stores whether realtime is True/On or False/Off, status: true, // stores whether realtime is True/On or False/Off,
broadcastingStatus: false,
localVideo: null, localVideo: null,
init: function () { init: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -1928,14 +1927,12 @@ Metamaps.Realtime = {
var turnOff = function () { var turnOff = function () {
self.turnOff(); self.turnOff();
}; };
var toggleVideo = function () {
self.toggleVideo();
};
$(".rtOn").click(reenableRealtime); $(".rtOn").click(reenableRealtime);
$(".rtOff").click(turnOff); $(".rtOff").click(turnOff);
$(".startVideo").click(toggleVideo);
$('.sidebarCollaborateIcon').click(self.toggleBox);
$('.sidebarCollaborateBox').click(function(event){
event.stopPropagation();
});
$('body').click(self.close);
$(document).on(Metamaps.Views.chatView.events.openTray, function () { $(document).on(Metamaps.Views.chatView.events.openTray, function () {
$('.main').addClass('compressed'); $('.main').addClass('compressed');
@ -1955,7 +1952,7 @@ Metamaps.Realtime = {
localVideoEl: self.videoId, localVideoEl: self.videoId,
remoteVideosEl: '', remoteVideosEl: '',
detectSpeakingEvents: true, detectSpeakingEvents: true,
autoAdjustMic: true, autoAdjustMic: false, //true,
autoRequestMedia: false, autoRequestMedia: false,
localVideo: { localVideo: {
autoplay: true, autoplay: true,
@ -1968,66 +1965,45 @@ Metamaps.Realtime = {
} }
}); });
self.webrtc.on('readyToCall', function () { self.webrtc.on('readyToCall', function () {
console.log('readyToCall');
self.videoInitialized = true;
self.readyToCall = true; self.readyToCall = true;
if (self.localVideo && self.status) { if (self.localVideo && self.status) {
$('#wrapper').append(self.localVideo.view.$container); $('#wrapper').append(self.localVideo.view.$container);
} }
self.socket.emit('videoAdded', {
avatar: Metamaps.Active.Mapper.get('image')
});
self.webrtc.webrtc.peers.forEach(function (p) {
p.pc.addStream(self.webrtc.webrtc.localStream);
p.start();
});
}); });
var var
$video = $('<video></video>').attr('id', self.videoId); $video = $('<video></video>').attr('id', self.videoId);
self.localVideo = { self.localVideo = {
$video: $video, $video: $video,
view: new Metamaps.Views.videoView($video[0], $('body'), 'me', true, { DOUBLE_CLICK_TOLERANCE: 200 }), view: new Metamaps.Views.videoView($video[0], $('body'), 'me', true, {
DOUBLE_CLICK_TOLERANCE: 200,
avatar: Metamaps.Active.Mapper ? Metamaps.Active.Mapper.get('image') : ''
}),
}; };
self.room = new Metamaps.Views.room({ self.room = new Metamaps.Views.room({
webrtc: self.webrtc, webrtc: self.webrtc,
socket: self.socket, socket: self.socket,
username: Metamaps.Active.Mapper.get('name'), username: Metamaps.Active.Mapper ? Metamaps.Active.Mapper.get('name') : '',
image: Metamaps.Active.Mapper.get('image'), image: Metamaps.Active.Mapper ? Metamaps.Active.Mapper.get('image') : '',
room: 'global', room: 'global',
$video: self.localVideo.$video, $video: self.localVideo.$video,
myVideoView: self.localVideo.view, myVideoView: self.localVideo.view,
config: { DOUBLE_CLICK_TOLERANCE: 200 } config: { DOUBLE_CLICK_TOLERANCE: 200 }
}); });
if (Metamaps.Messages) self.room.messages.add(Metamaps.Messages);
self.createChat(); self.createChat();
self.webrtc.startLocalVideo(); //self.webrtc.startLocalVideo();
},
toggleBox: function (event) {
var self = Metamaps.Realtime;
if (self.isOpen) self.close();
else self.open();
event.stopPropagation();
},
open: function () {
var self = Metamaps.Realtime;
Metamaps.GlobalUI.Account.close();
Metamaps.Filter.close();
$('.sidebarCollaborateIcon div').addClass('hide');
if (!self.isOpen && !self.changing) {
self.changing = true;
$('.sidebarCollaborateBox').fadeIn(200, function () {
self.changing = false;
self.isOpen = true;
});
}
},
close: function () {
var self = Metamaps.Realtime;
$(".sidebarCollaborateIcon div").removeClass('hide');
if (!self.changing) {
self.changing = true;
$('.sidebarCollaborateBox').fadeOut(200, function () {
self.changing = false;
self.isOpen = false;
});
}
}, },
startActiveMap: function () { startActiveMap: function () {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2043,6 +2019,7 @@ Metamaps.Realtime = {
else if (publicMap) { else if (publicMap) {
self.attachMapListener(); self.attachMapListener();
} }
self.room.messages.add(Metamaps.Messages);
} }
}, },
endActiveMap: function () { endActiveMap: function () {
@ -2053,6 +2030,8 @@ Metamaps.Realtime = {
self.socket.emit('endMapperNotify'); self.socket.emit('endMapperNotify');
$(".collabCompass").remove(); $(".collabCompass").remove();
self.status = false; self.status = false;
self.stopVideo();
self.room.leave();
}, },
reenableRealtime: function() { reenableRealtime: function() {
var confirmString = "The layout of your map has fallen out of sync with the saved copy. "; var confirmString = "The layout of your map has fallen out of sync with the saved copy. ";
@ -2068,17 +2047,20 @@ Metamaps.Realtime = {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
if (notify) self.sendRealtimeOn(); if (notify) self.sendRealtimeOn();
$(".rtMapperSelf").removeClass('littleRtOff').addClass('littleRtOn'); //$(".rtMapperSelf").removeClass('littleRtOff').addClass('littleRtOn');
$('.rtOn').addClass('active'); //$('.rtOn').addClass('active');
$('.rtOff').removeClass('active'); //$('.rtOff').removeClass('active');
self.status = true; self.status = true;
$(".sidebarCollaborateIcon").addClass("blue"); //$(".sidebarCollaborateIcon").addClass("blue");
$(".collabCompass").show(); $(".collabCompass").show();
if (self.localVideo) $('#wrapper').append(self.localVideo.view.$container); self.localVideo.view.$container.show();
self.room.room = 'map-' + Metamaps.Active.Map.id; self.room.room = 'map-' + Metamaps.Active.Map.id;
self.room.join(function (err, roomDesc) { self.room.join(function (err, roomDesc) {
console.log('joining'); //attachMediaStream(self.webrtc.webrtc.localStream, self.localVideo.$video[0]);
attachMediaStream(self.webrtc.webrtc.localStream, self.localVideo.$video[0]);
for (id in roomDesc.avatars) {
self.webrtc.webrtc.peers.find(function(p) { return p.id === id; }).avatar = roomDesc.avatars[id];
}
function addVideo(v) { function addVideo(v) {
// random position for now // random position for now
@ -2100,16 +2082,46 @@ Metamaps.Realtime = {
} }
}); });
}, },
startVideo: function() {
var
self = Metamaps.Realtime;
if (!self.videoInitialized) {
self.webrtc.startLocalVideo();
}
else {
self.webrtc.resume();
}
self.broadcastingStatus = true;
self.localVideo.view.$container.show();
$(".startVideo").html("stop broadcasting");
},
stopVideo: function () {
var
self = Metamaps.Realtime;
self.webrtc.pause();
self.broadcastingStatus = false;
self.localVideo.view.$container.hide();
$(".startVideo").html("start my video");
},
toggleVideo: function () {
var
self = Metamaps.Realtime;
if (!self.broadcastingStatus) self.startVideo();
else self.stopVideo();
},
turnOff: function (silent) { turnOff: function (silent) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
if (self.status) { if (self.status) {
if (!silent) self.sendRealtimeOff(); if (!silent) self.sendRealtimeOff();
$(".rtMapperSelf").removeClass('littleRtOn').addClass('littleRtOff'); //$(".rtMapperSelf").removeClass('littleRtOn').addClass('littleRtOff');
$('.rtOn').removeClass('active'); //$('.rtOn').removeClass('active');
$('.rtOff').addClass('active'); //$('.rtOff').addClass('active');
self.status = false; self.status = false;
$(".sidebarCollaborateIcon").removeClass("blue"); //$(".sidebarCollaborateIcon").removeClass("blue");
$(".collabCompass").hide(); $(".collabCompass").hide();
$('#' + self.videoId).remove(); $('#' + self.videoId).remove();
} }
@ -2147,6 +2159,9 @@ Metamaps.Realtime = {
// //
socket.on('maps-' + Metamaps.Active.Map.id + '-newTopic', self.newTopic); socket.on('maps-' + Metamaps.Active.Map.id + '-newTopic', self.newTopic);
//
socket.on('maps-' + Metamaps.Active.Map.id + '-newMessage', self.newMessage);
// //
socket.on('maps-' + Metamaps.Active.Map.id + '-removeTopic', self.removeTopic); socket.on('maps-' + Metamaps.Active.Map.id + '-removeTopic', self.removeTopic);
@ -2228,6 +2243,11 @@ Metamaps.Realtime = {
}; };
$(document).on(Metamaps.JIT.events.removeSynapse, sendRemoveSynapse); $(document).on(Metamaps.JIT.events.removeSynapse, sendRemoveSynapse);
var sendNewMessage = function (event, data) {
self.sendNewMessage(data);
};
$(document).on(Metamaps.Views.room.events.newMessage, sendNewMessage);
}, },
attachMapListener: function(){ attachMapListener: function(){
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -2614,6 +2634,21 @@ Metamaps.Realtime = {
}); });
} }
}, },
// newMessage
sendNewMessage: function (data) {
var self = Metamaps.Realtime;
var socket = self.socket;
var message = data.attributes;
message.mapid = Metamaps.Active.Map.id;
socket.emit('newMessage', message);
},
newMessage: function (data) {
var self = Metamaps.Realtime;
var socket = self.socket;
self.room.messages.add(data);
},
// newTopic // newTopic
sendNewTopic: function (data) { sendNewTopic: function (data) {
var self = Metamaps.Realtime; var self = Metamaps.Realtime;
@ -3298,7 +3333,6 @@ Metamaps.Filter = {
var self = Metamaps.Filter; var self = Metamaps.Filter;
Metamaps.GlobalUI.Account.close(); Metamaps.GlobalUI.Account.close();
Metamaps.Realtime.close();
$('.sidebarFilterIcon div').addClass('hide'); $('.sidebarFilterIcon div').addClass('hide');
@ -4469,6 +4503,7 @@ Metamaps.Map = {
Metamaps.Topics = new bb.TopicCollection(data.topics); Metamaps.Topics = new bb.TopicCollection(data.topics);
Metamaps.Synapses = new bb.SynapseCollection(data.synapses); Metamaps.Synapses = new bb.SynapseCollection(data.synapses);
Metamaps.Mappings = new bb.MappingCollection(data.mappings); Metamaps.Mappings = new bb.MappingCollection(data.mappings);
Metamaps.Messages = data.messages;
Metamaps.Backbone.attachCollectionEvents(); Metamaps.Backbone.attachCollectionEvents();
var map = Metamaps.Active.Map; var map = Metamaps.Active.Map;
@ -5265,4 +5300,3 @@ Metamaps.Admin = {
} }
} }
}; };

View file

@ -7,7 +7,7 @@ Metamaps.Views.chatView = (function () {
var Private = { var Private = {
messageHTML: "<div class='chat-message'>" + messageHTML: "<div class='chat-message'>" +
"<div class='chat-message-user'><img src='<%= image %>' title='<%= user %>'/></div>" + "<div class='chat-message-user'><img src='<%= user_image %>' title='<%= user_name %>'/></div>" +
"<div class='chat-message-text'><%= message %></div>" + "<div class='chat-message-text'><%= message %></div>" +
"<div class='chat-message-time'><%= timestamp %></div>" + "<div class='chat-message-time'><%= timestamp %></div>" +
"<div class='clearfloat'></div>" + "<div class='clearfloat'></div>" +
@ -46,9 +46,9 @@ Metamaps.Views.chatView = (function () {
this.$container.append(this.$juntoHeader); this.$container.append(this.$juntoHeader);
this.$container.append(this.$participants); this.$container.append(this.$participants);
this.$container.append(this.$chatHeader); this.$container.append(this.$chatHeader);
this.$container.append(this.$messageInput);
this.$container.append(this.$button); this.$container.append(this.$button);
this.$container.append(this.$messages); this.$container.append(this.$messages);
this.$container.append(this.$messageInput);
}, },
addEventListeners: function() { addEventListeners: function() {
var self = this; var self = this;
@ -116,12 +116,12 @@ Metamaps.Views.chatView = (function () {
var m = _.clone(message.attributes); var m = _.clone(message.attributes);
var today = new Date(); var today = new Date();
m.timestamp = new Date(m.timestamp); m.timestamp = new Date(m.created_at);
var date = (m.timestamp.getMonth() + 1) + '/' + m.timestamp.getDate(); var date = (m.timestamp.getMonth() + 1) + '/' + m.timestamp.getDate();
date += " " + addZero(m.timestamp.getHours()) + ":" + addZero(m.timestamp.getMinutes()); date += " " + addZero(m.timestamp.getHours()) + ":" + addZero(m.timestamp.getMinutes());
m.timestamp = date; m.timestamp = date;
m.image = m.image || 'http://www.hotpepper.ca/wp-content/uploads/2014/11/default_profile_1_200x200.png'; m.image = m.user_image || 'http://www.hotpepper.ca/wp-content/uploads/2014/11/default_profile_1_200x200.png';
m.message = linker.link(m.message); m.message = linker.link(m.message);
var $html = $(this.messageTemplate(m)); var $html = $(this.messageTemplate(m));
this.$messages.append($html); this.$messages.append($html);
@ -138,9 +138,6 @@ Metamaps.Views.chatView = (function () {
handleInputMessage: function() { handleInputMessage: function() {
var message = { var message = {
message: this.$messageInput.val(), message: this.$messageInput.val(),
timestamp: Date.now(),
user: this.mapper.get('name'),
image: this.mapper.get('image')
}; };
this.$messageInput.val(''); this.$messageInput.val('');
$(document).trigger(chatView.events.message + '-' + this.room, [message]); $(document).trigger(chatView.events.message + '-' + this.room, [message]);
@ -247,6 +244,12 @@ Metamaps.Views.chatView = (function () {
}, duration); }, duration);
} }
chatView.prototype.clearMessages = function () {
this.unreadMessages = 0;
this.$unread.hide();
this.$messages.empty();
}
chatView.prototype.close = function () { chatView.prototype.close = function () {
this.$container.css({ this.$container.css({
right: '-300px' right: '-300px'

View file

@ -40,6 +40,8 @@ Metamaps.Views.room = (function () {
this.isActiveRoom = false; this.isActiveRoom = false;
this.webrtc.leaveRoom(); this.webrtc.leaveRoom();
this.chat.removeParticipants(); this.chat.removeParticipants();
this.chat.clearMessages();
this.messages.reset();
} }
room.prototype.setPeopleCount = function(count) { room.prototype.setPeopleCount = function(count) {
@ -76,6 +78,55 @@ Metamaps.Views.room = (function () {
} }
}); });
this.webrtc.on('mute', function (data) {
var v = self.videos[data.id];
if (!v) return;
if (data.name === 'audio') {
v.audioStatus = false;
}
else if (data.name === 'video') {
v.videoStatus = false;
v.$avatar.show();
}
if (!v.audioStatus && !v.videoStatus) v.$container.hide();
});
this.webrtc.on('unmute', function (data) {
var v = self.videos[data.id];
if (!v) return;
if (data.name === 'audio') {
v.audioStatus = true;
}
else if (data.name === 'video') {
v.videoStatus = true;
v.$avatar.hide();
}
v.$container.show();
});
this.socket.on('addVideo', function (data) {
var existingPeer = self.webrtc.webrtc.peers.find(function(p) { return p.id === data.id; });
if (!existingPeer) {
var peer = self.webrtc.webrtc.createPeer({
id: data.id,
type: 'video',
enableDataChannels: true,
receiveMedia: {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
}
});
peer.avatar = data.avatar;
self.webrtc.emit('createdPeer', peer);
peer.start();
// the rest will happen automatically through the 'peerStreamAdded' event and associated event handlers
}
});
var sendChatMessage = function (event, data) { var sendChatMessage = function (event, data) {
self.sendChatMessage(data); self.sendChatMessage(data);
}; };
@ -90,22 +141,46 @@ Metamaps.Views.room = (function () {
var var
id = this.webrtc.getDomId(peer), id = this.webrtc.getDomId(peer),
video = attachMediaStream(peer.stream); video = attachMediaStream(peer.stream);
v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200 }); v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200, avatar: peer.avatar });
if (this._videoAdded) this._videoAdded(v); if (this._videoAdded) this._videoAdded(v);
this.videos[peer.id] = v; this.videos[peer.id] = v;
} }
room.prototype.removeVideo = function (peer) { room.prototype.removeVideo = function (peer) {
console.log(peer); console.log('removeVideo', peer);
var id = typeof peer == 'string' ? peer : peer.id; var id = typeof peer == 'string' ? peer : peer.id;
this.videos[id].remove(); this.videos[id].remove();
delete this.videos[id]; delete this.videos[id];
} }
room.prototype.sendChatMessage = function (data) { room.prototype.sendChatMessage = function (data) {
var self = this;
//this.roomRef.child('messages').push(data); //this.roomRef.child('messages').push(data);
console.log(data);
var m = new Metamaps.Backbone.Message({
message: data.message,
resource_id: Metamaps.Active.Map.id,
resource_type: "Map"
});
m.save(null, {
success: function (model, response) {
self.messages.add(model);
$(document).trigger(room.events.newMessage, [model]);
},
error: function (model, response) {
console.log('error!', response);
} }
});
}
/**
* @class
* @static
*/
room.events = {
newMessage: "Room:newMessage"
};
return room; return room;
})(); })();

View file

@ -127,7 +127,8 @@ Metamaps.Views.videoView = (function () {
$vidContainer.addClass('video-cutoff'); $vidContainer.addClass('video-cutoff');
$vidContainer.append(this.video); $vidContainer.append(this.video);
this.$avatar = $('<img draggable="false" class="collaborator-video-avatar" src="/assets/default_profile.png" width="150" height="150" />'); this.avatar = config.avatar;
this.$avatar = $('<img draggable="false" class="collaborator-video-avatar" src="' + config.avatar + '" width="150" height="150" />');
$vidContainer.append(this.$avatar); $vidContainer.append(this.$avatar);
this.$container.append($vidContainer); this.$container.append($vidContainer);
@ -157,6 +158,11 @@ Metamaps.Views.videoView = (function () {
}); });
} }
videoView.prototype.setAvatar = function (src) {
this.$avatar.attr('src', src);
this.avatar = src;
}
videoView.prototype.remove = function () { videoView.prototype.remove = function () {
this.$container.off(); this.$container.off();
if (this.$parent) this.$parent.off('.video' + this.id); if (this.$parent) this.$parent.off('.video' + this.id);

View file

@ -69,6 +69,8 @@
} }
.chat-box { .chat-box {
position: relative; position: relative;
display: flex;
flex-direction: column;
z-index: 1; z-index: 1;
width: 300px; width: 300px;
float: right; float: right;
@ -141,7 +143,7 @@
} }
.chat-box .participants { .chat-box .participants {
width: 100%; width: 100%;
height: 150px; min-height: 150px;
padding: 16px 0px 0px 0px; padding: 16px 0px 0px 0px;
text-align: left; text-align: left;
color: #f5f5f5; color: #f5f5f5;
@ -203,10 +205,7 @@
background-position-y: -24px; background-position-y: -24px;
} }
.chat-box .chat-input { .chat-box .chat-input {
position: absolute; min-height: 80px;
bottom: 0;
left: 0;
height: 80px;
width: 100%; width: 100%;
padding: 8px 8px 8px 8px; padding: 8px 8px 8px 8px;
font-size: 13px; font-size: 13px;
@ -214,7 +213,6 @@
} }
.chat-box .chat-messages { .chat-box .chat-messages {
width: 100%; width: 100%;
height: 196px;
padding: 16px 0px 0px 0px; padding: 16px 0px 0px 0px;
overflow-y: auto; overflow-y: auto;
} }

View file

@ -78,8 +78,9 @@ class MapsController < ApplicationController
object = m.mappable object = m.mappable
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id))) !object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id)))
} }
@allmessages = @map.messages
respond_with(@allmappers, @allmappings, @allsynapses, @alltopics, @map) respond_with(@allmappers, @allmappings, @allsynapses, @alltopics, @allmessages, @map)
} }
format.json { render json: @map } format.json { render json: @map }
end end
@ -109,6 +110,7 @@ class MapsController < ApplicationController
@json['synapses'] = @allsynapses @json['synapses'] = @allsynapses
@json['mappings'] = @allmappings @json['mappings'] = @allmappings
@json['mappers'] = @allmappers @json['mappers'] = @allmappers
@json['messages'] = @map.messages
respond_to do |format| respond_to do |format|
format.json { render json: @json } format.json { render json: @json }

View file

@ -0,0 +1,62 @@
class MessagesController < ApplicationController
before_filter :require_user, except: [:show]
# GET /messages/1.json
def show
@message = Message.find(params[:id])
respond_to do |format|
format.json { render json: @message }
end
end
# POST /messages
# POST /messages.json
def create
@message = Message.new(message_params)
@message.user = current_user
respond_to do |format|
if @message.save
format.json { render json: @message, status: :created, location: messages_url }
else
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
# PUT /messages/1
# PUT /messages/1.json
def update
@message = Message.find(params[:id])
respond_to do |format|
if @message.update_attributes(message_params)
format.json { head :no_content }
else
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
# DELETE /messages/1
# DELETE /messages/1.json
def destroy
@message = Message.find(params[:id])
@message.destroy
respond_to do |format|
format.json { head :no_content }
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def message_params
#params.require(:message).permit(:id, :resource_id, :message)
params.permit(:id, :resource_id, :resource_type, :message)
end
end

View file

@ -6,6 +6,7 @@ class Map < ActiveRecord::Base
has_many :synapsemappings, -> { Mapping.synapsemapping }, class_name: :Mapping, dependent: :destroy has_many :synapsemappings, -> { Mapping.synapsemapping }, class_name: :Mapping, dependent: :destroy
has_many :topics, through: :topicmappings, source: :mappable, source_type: "Topic" has_many :topics, through: :topicmappings, source: :mappable, source_type: "Topic"
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: "Synapse" has_many :synapses, through: :synapsemappings, source: :mappable, source_type: "Synapse"
has_many :messages, as: :resource, dependent: :destroy
# This method associates the attribute ":image" with a file attachment # This method associates the attribute ":image" with a file attachment
has_attached_file :screenshot, :styles => { has_attached_file :screenshot, :styles => {

54
app/models/message.rb Normal file
View file

@ -0,0 +1,54 @@
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :resource, polymorphic: true
def user_name
self.user.name
end
def user_image
self.user.image.url
end
def as_json(options={})
json = super(:methods =>[:user_name, :user_image])
json
end
##### PERMISSIONS ######
def authorize_to_delete(user)
if (self.user != user)
return false
end
return self
end
# returns false if user not allowed to 'show' Topic, Synapse, or Map
def authorize_to_show(user)
if (self.resource && self.resource.permission == "private" && self.resource.user != user)
return false
end
return self
end
# returns false if user not allowed to 'edit' Topic, Synapse, or Map
def authorize_to_edit(user)
if !user
return false
elsif (self.user != user)
return false
end
return self
end
# returns Boolean if user allowed to view Topic, Synapse, or Map
def authorize_to_view(user)
if (self.resource && self.resource.permission == "private" && self.resource.user != user)
return false
end
return true
end
end

View file

@ -78,7 +78,7 @@ class User < ActiveRecord::Base
if code == joinedwithcode if code == joinedwithcode
update(generation: 0) update(generation: 0)
else else
update(generation: User.find_by_code(joinedwithcode) + 1) update(generation: User.find_by_code(joinedwithcode).generation + 1)
end end
end end

View file

@ -20,6 +20,7 @@
<div class="upperRightUI"> <div class="upperRightUI">
<div class="supportUs upperRightEl openLightbox" data-open="donate">SUPPORT US!</div> <div class="supportUs upperRightEl openLightbox" data-open="donate">SUPPORT US!</div>
<div class="mapElement upperRightEl upperRightMapButtons"> <div class="mapElement upperRightEl upperRightMapButtons">
<div class="startVideo upperRightEl">start my video</div>
<!-- filtering --> <!-- filtering -->
<div class="sidebarFilter upperRightEl"> <div class="sidebarFilter upperRightEl">
<div class="sidebarFilterIcon upperRightIcon"><div class="tooltipsUnder">Filter</div></div> <div class="sidebarFilterIcon upperRightIcon"><div class="tooltipsUnder">Filter</div></div>

View file

@ -13,5 +13,6 @@
Metamaps.Topics = <%= @alltopics.to_json.html_safe %>; Metamaps.Topics = <%= @alltopics.to_json.html_safe %>;
Metamaps.Synapses = <%= @allsynapses.to_json.html_safe %>; Metamaps.Synapses = <%= @allsynapses.to_json.html_safe %>;
Metamaps.Mappings = <%= @allmappings.to_json.html_safe %>; Metamaps.Mappings = <%= @allmappings.to_json.html_safe %>;
Metamaps.Messages = <%= @allmessages.to_json.html_safe %>;
Metamaps.Visualize.type = "ForceDirected"; Metamaps.Visualize.type = "ForceDirected";
</script> </script>

View file

@ -9,6 +9,7 @@ Metamaps::Application.routes.draw do
get 'search/mappers', to: 'main#searchmappers', as: :searchmappers get 'search/mappers', to: 'main#searchmappers', as: :searchmappers
get 'search/synapses', to: 'main#searchsynapses', as: :searchsynapses get 'search/synapses', to: 'main#searchsynapses', as: :searchsynapses
resources :messages, only: [:show, :create, :update, :destroy]
resources :mappings, except: [:index, :new, :edit] resources :mappings, except: [:index, :new, :edit]
resources :metacode_sets, :except => [:show] resources :metacode_sets, :except => [:show]
resources :metacodes, :except => [:show, :destroy] resources :metacodes, :except => [:show, :destroy]

View file

@ -0,0 +1,15 @@
class Messages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.text :message
t.references :user
t.integer :resource_id
t.string :resource_type
t.timestamps
end
add_index :messages, :user_id
add_index :messages, :resource_id
add_index :messages, :resource_type
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151025083043) do ActiveRecord::Schema.define(version: 20151205205831) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -63,6 +63,19 @@ ActiveRecord::Schema.define(version: 20151025083043) do
add_index "maps", ["user_id"], name: "index_maps_on_user_id", using: :btree add_index "maps", ["user_id"], name: "index_maps_on_user_id", using: :btree
create_table "messages", force: :cascade do |t|
t.text "message"
t.integer "user_id"
t.integer "resource_id"
t.string "resource_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "messages", ["resource_id"], name: "index_messages_on_resource_id", using: :btree
add_index "messages", ["resource_type"], name: "index_messages_on_resource_type", using: :btree
add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree
create_table "metacode_sets", force: :cascade do |t| create_table "metacode_sets", force: :cascade do |t|
t.string "name" t.string "name"
t.text "desc" t.text "desc"

View file

@ -3,6 +3,8 @@ var
signalServer = require('./signal'), signalServer = require('./signal'),
stunservers = [{"url": "stun:stun.l.google.com:19302"}]; stunservers = [{"url": "stun:stun.l.google.com:19302"}];
io.set('log', false);
function start() { function start() {
signalServer(io, stunservers); signalServer(io, stunservers);
@ -91,6 +93,13 @@ function start() {
socket.broadcast.emit('maps-' + mapId + '-topicDrag', data); socket.broadcast.emit('maps-' + mapId + '-topicDrag', data);
}); });
socket.on('newMessage', function (data) {
var mapId = data.mapid;
delete data.mapid;
socket.broadcast.emit('maps-' + mapId + '-newMessage', data);
});
socket.on('newTopic', function (data) { socket.on('newTopic', function (data) {
var mapId = data.mapid; var mapId = data.mapid;
delete data.mapid; delete data.mapid;

View file

@ -9,10 +9,12 @@ module.exports = function(io, stunservers) {
function describeRoom(name) { function describeRoom(name) {
var clients = io.sockets.clients(name); var clients = io.sockets.clients(name);
var result = { var result = {
clients: {} clients: {},
avatars: {}
}; };
clients.forEach(function (client) { clients.forEach(function (client) {
result.clients[client.id] = client.resources; result.clients[client.id] = client.resources;
result.avatars[client.id] = client.avatar;
}); });
return result; return result;
} }
@ -38,7 +40,7 @@ module.exports = function(io, stunservers) {
client.resources = { client.resources = {
screen: false, screen: false,
video: true, video: false,
audio: false audio: false
}; };
@ -63,6 +65,18 @@ module.exports = function(io, stunservers) {
}); });
client.on('join', join); client.on('join', join);
client.on('videoAdded', videoAdded);
function videoAdded(data) {
var socketsInRoom = io.sockets.clients(client.room);
client.resources.video = true;
client.avatar = data.avatar;
socketsInRoom.forEach(function(socket) {
if (socket.id !== client.id) {
socket.emit('addVideo', { id: client.id, avatar: data.avatar });
}
});
}
client.on('requestRoomCount', function(name) { client.on('requestRoomCount', function(name) {
client.emit('room_count', { client.emit('room_count', {