more crazy refactoring

This commit is contained in:
Connor Turland 2017-03-22 22:36:59 -04:00
parent b7a6e615a0
commit 79839a4b48
19 changed files with 2737 additions and 2733 deletions

View file

@ -108,7 +108,7 @@ const ReactApp = {
mobileTitleClick: (e) => self.openMap && self.openMap.InfoBox.toggleBox(e), mobileTitleClick: (e) => self.openMap && self.openMap.InfoBox.toggleBox(e),
openInviteLightbox: () => self.openLightbox('invite'), openInviteLightbox: () => self.openLightbox('invite'),
serverData: self.serverData, serverData: self.serverData,
endActiveMap: mapControl.end, endActiveMap: () => mapControl.end(self.openMap),
launchNewMap: mapControl.launch, launchNewMap: mapControl.launch,
mapId: self.mapId, mapId: self.mapId,
topicId: self.topicId topicId: self.topicId
@ -159,7 +159,7 @@ const ReactApp = {
openTopic: TopicCard.openTopic, openTopic: TopicCard.openTopic,
metacodeSets: self.metacodeSets, metacodeSets: self.metacodeSets,
updateTopic: (topic, obj) => topic.save(obj), updateTopic: (topic, obj) => topic.save(obj),
onTopicFollow: Topic.onTopicFollow // todo onTopicFollow: () => {} // Topic.onTopicFollow // todo
} }
}, },
getTopicProps: function() { getTopicProps: function() {

View file

@ -1,4 +1,4 @@
ReactApp.currentUserReactApp.currentUser/* global $, Hogan, Bloodhound, CanvasLoader */ /* global $, Hogan, Bloodhound, CanvasLoader */
import { browserHistory } from 'react-router' import { browserHistory } from 'react-router'

View file

@ -4,6 +4,7 @@ import Backbone from 'backbone'
import { Howl } from 'howler' import { Howl } from 'howler'
import ReactApp from '../GlobalUI/ReactApp' import ReactApp from '../GlobalUI/ReactApp'
import MessageCollection from '../DataModel/MessageCollection'
const ChatView = (map) => { const ChatView = (map) => {
const toExport = { const toExport = {
@ -12,19 +13,6 @@ const toExport = {
messages: new Backbone.Collection(), messages: new Backbone.Collection(),
conversationLive: false, conversationLive: false,
isParticipating: false, isParticipating: false,
init: function(urls) {
const self = toExport
self.sound = new Howl({
src: urls,
sprite: {
joinmap: [0, 561],
leavemap: [1000, 592],
receivechat: [2000, 318],
sendchat: [3000, 296],
sessioninvite: [4000, 5393, true]
}
})
},
setNewMap: function() { setNewMap: function() {
const self = toExport const self = toExport
self.unreadMessages = 0 self.unreadMessages = 0
@ -118,13 +106,13 @@ const toExport = {
addMessage: (message, isInitial, wasMe) => { addMessage: (message, isInitial, wasMe) => {
const self = toExport const self = toExport
if (!isInitial && !self.isOpen) self.unreadMessages += 1 if (!isInitial && !self.isOpen) self.unreadMessages += 1
if (!wasMe && !isInitial && self.alertSound) self.sound.play('receivechat') if (!wasMe && !isInitial && self.alertSound) ChatView.sound.play('receivechat')
self.messages.add(message) self.messages.add(message)
if (!isInitial && self.isOpen) self.render() if (!isInitial && self.isOpen) self.render()
}, },
sendChatMessage: message => { sendChatMessage: message => {
var self = toExport var self = toExport
if (toExport.alertSound) toExport.sound.play('sendchat') if (toExport.alertSound) ChatView.sound.play('sendchat')
var m = new DataModel.Message({ var m = new DataModel.Message({
message: message.message, message: message.message,
resource_id: map.Active.Map.id, resource_id: map.Active.Map.id,
@ -132,7 +120,7 @@ const toExport = {
}) })
m.save(null, { m.save(null, {
success: function(model, response) { success: function(model, response) {
self.addMessages(new DataModel.MessageCollection(model), false, true) self.addMessages(new MessageCollection(model), false, true)
}, },
error: function(model, response) { error: function(model, response) {
console.log('error!', response) console.log('error!', response)
@ -150,7 +138,6 @@ const toExport = {
} }
return toExport return toExport
} }
/** /**
* @class * @class
* @static * @static
@ -165,5 +152,17 @@ ChatView.events = {
videosOff: 'ChatView:videosOff', videosOff: 'ChatView:videosOff',
videosOn: 'ChatView:videosOn' videosOn: 'ChatView:videosOn'
} }
ChatView.init = function(urls) {
ChatView.sound = new Howl({
src: urls,
sprite: {
joinmap: [0, 561],
leavemap: [1000, 592],
receivechat: [2000, 318],
sendchat: [3000, 296],
sessioninvite: [4000, 5393, true]
}
})
}
export default ChatView export default ChatView

View file

@ -266,7 +266,7 @@ const toExport = {
}) })
toExport.newTopic.beingCreated = true toExport.newTopic.beingCreated = true
toExport.newTopic.name = '' toExport.newTopic.name = ''
//Map.setHasLearnedTopicCreation(true) map.Map.setHasLearnedTopicCreation(true)
}, },
hide: function(force) { hide: function(force) {
if (force || !toExport.newTopic.pinned) { if (force || !toExport.newTopic.pinned) {
@ -277,7 +277,7 @@ const toExport = {
toExport.newTopic.pinned = false toExport.newTopic.pinned = false
} }
if (map.DataModel.Topics.length === 0) { if (map.DataModel.Topics.length === 0) {
Map.setHasLearnedTopicCreation(false) map.Map.setHasLearnedTopicCreation(false)
} }
toExport.newTopic.beingCreated = false toExport.newTopic.beingCreated = false
}, },

View file

@ -6,274 +6,274 @@ import GlobalUI, { ReactApp } from '../GlobalUI'
import Settings from '../Settings' import Settings from '../Settings'
const Filter = (map) => { const Filter = (map) => {
const toExport = { const toExport = {
dataForPresentation: { dataForPresentation: {
metacodes: {}, metacodes: {},
mappers: {}, mappers: {},
synapses: {} synapses: {}
}, },
filters: { filters: {
metacodes: [], metacodes: [],
mappers: [], mappers: [],
synapses: [] synapses: []
}, },
visible: { visible: {
metacodes: [], metacodes: [],
mappers: [], mappers: [],
synapses: [] synapses: []
}, },
reset: function() { reset: function() {
var self = toExport var self = toExport
self.filters.metacodes = [] self.filters.metacodes = []
self.filters.mappers = [] self.filters.mappers = []
self.filters.synapses = [] self.filters.synapses = []
self.visible.metacodes = [] self.visible.metacodes = []
self.visible.mappers = [] self.visible.mappers = []
self.visible.synapses = [] self.visible.synapses = []
self.dataForPresentation.metacodes = {} self.dataForPresentation.metacodes = {}
self.dataForPresentation.mappers = {} self.dataForPresentation.mappers = {}
self.dataForPresentation.synapses = {} self.dataForPresentation.synapses = {}
ReactApp.render() ReactApp.render()
}, },
// an abstraction function for checkMetacodes, checkMappers, checkSynapses to reduce // an abstraction function for checkMetacodes, checkMappers, checkSynapses to reduce
// code redundancy // code redundancy
updateFilters: function(collection, propertyToCheck, correlatedModel, filtersToUse, listToModify) { updateFilters: function(collection, propertyToCheck, correlatedModel, filtersToUse, listToModify) {
var self = toExport var self = toExport
var newList = [] var newList = []
var removed = [] var removed = []
var added = [] var added = []
// the first option enables us to accept // the first option enables us to accept
// ['Topics', 'Synapses'] as 'collection' // ['Topics', 'Synapses'] as 'collection'
if (typeof collection === 'object') { if (typeof collection === 'object') {
DataModel[collection[0]].each(function(model) { map.DataModel[collection[0]].each(function(model) {
var prop = model.get(propertyToCheck) var prop = model.get(propertyToCheck)
if (prop !== null) { if (prop !== null) {
prop = prop.toString() prop = prop.toString()
if (newList.indexOf(prop) === -1) { if (newList.indexOf(prop) === -1) {
newList.push(prop) newList.push(prop)
}
}
})
DataModel[collection[1]].each(function(model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
} else if (typeof collection === 'string') {
DataModel[collection].each(function(model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
}
removed = _.difference(self.filters[filtersToUse], newList)
added = _.difference(newList, self.filters[filtersToUse])
_.each(removed, function(identifier) {
const index = self.visible[filtersToUse].indexOf(identifier)
self.visible[filtersToUse].splice(index, 1)
delete self.dataForPresentation[filtersToUse][identifier]
})
_.each(added, function(identifier) {
const model = DataModel[correlatedModel].get(identifier) ||
DataModel[correlatedModel].find(function(m) {
return m.get(propertyToCheck) === identifier
})
self.dataForPresentation[filtersToUse][identifier] = model.prepareDataForFilter()
self.visible[filtersToUse].push(identifier)
})
// update the list of filters with the new list we just generated
self.filters[filtersToUse] = newList
ReactApp.render()
},
checkMetacodes: function() {
var self = toExport
self.updateFilters('Topics', 'metacode_id', 'Metacodes', 'metacodes', 'metacode')
},
checkMappers: function() {
var self = toExport
if (map.Active.Map) {
self.updateFilters('Mappings', 'user_id', 'Mappers', 'mappers', 'mapper')
} else {
// on topic view
self.updateFilters(['Topics', 'Synapses'], 'user_id', 'Creators', 'mappers', 'mapper')
}
},
checkSynapses: function() {
var self = toExport
self.updateFilters('Synapses', 'desc', 'Synapses', 'synapses', 'synapse')
},
filterAllMetacodes: function(toVisible) {
var self = toExport
self.visible.metacodes = toVisible ? self.filters.metacodes.slice() : []
ReactApp.render()
self.passFilters()
},
filterAllMappers: function(toVisible) {
var self = toExport
self.visible.mappers = toVisible ? self.filters.mappers.slice() : []
ReactApp.render()
self.passFilters()
},
filterAllSynapses: function(toVisible) {
var self = toExport
self.visible.synapses = toVisible ? self.filters.synapses.slice() : []
ReactApp.render()
self.passFilters()
},
// an abstraction function for toggleMetacode, toggleMapper, toggleSynapse
// to reduce code redundancy
// gets called in the context of a list item in a filter box
toggleLi: function(whichToFilter, id) {
var self = toExport
if (self.visible[whichToFilter].indexOf(id) === -1) {
self.visible[whichToFilter].push(id)
} else {
const index = self.visible[whichToFilter].indexOf(id)
self.visible[whichToFilter].splice(index, 1)
}
ReactApp.render()
self.passFilters()
},
toggleMetacode: function(id) {
var self = toExport
self.toggleLi('metacodes', id)
},
toggleMapper: function(id) {
var self = toExport
self.toggleLi('mappers', id)
},
toggleSynapse: function(id) {
var self = toExport
self.toggleLi('synapses', id)
},
passFilters: function() {
var self = toExport
var visible = self.visible
var passesMetacode, passesMapper, passesSynapse
var opacityForFilter = map.Active.Map ? 0 : 0.4
map.DataModel.Topics.each(function(topic) {
var n = topic.get('node')
var metacodeId = topic.get('metacode_id').toString()
if (visible.metacodes.indexOf(metacodeId) === -1) passesMetacode = false
else passesMetacode = true
if (map.Active.Map) {
// when on a map,
// we filter by mapper according to the person who added the
// topic or synapse to the map
let userId = topic.getMapping().get('user_id').toString()
if (visible.mappers.indexOf(userId) === -1) passesMapper = false
else passesMapper = true
} else {
// when on a topic view,
// we filter by mapper according to the person who created the
// topic or synapse
let userId = topic.get('user_id').toString()
if (visible.mappers.indexOf(userId) === -1) passesMapper = false
else passesMapper = true
}
if (passesMetacode && passesMapper) {
if (n) {
n.setData('alpha', 1, 'end')
} else {
console.log(topic)
}
} else {
if (n) {
map.Control.deselectNode(n, true)
n.setData('alpha', opacityForFilter, 'end')
n.eachAdjacency(function(e) {
map.Control.deselectEdge(e, true)
})
} else {
console.log(topic)
}
}
})
// flag all the edges back to 'untouched'
map.DataModel.Synapses.each(function(synapse) {
var e = synapse.get('edge')
e.setData('touched', false)
})
map.DataModel.Synapses.each(function(synapse) {
var e = synapse.get('edge')
var desc
var userId = synapse.get('user_id').toString()
if (e && !e.getData('touched')) {
var synapses = e.getData('synapses')
// if any of the synapses represent by the edge are still unfiltered
// leave the edge visible
passesSynapse = false
for (let i = 0; i < synapses.length; i++) {
desc = synapses[i].get('desc')
if (visible.synapses.indexOf(desc) > -1) passesSynapse = true
}
// if the synapse description being displayed is now being
// filtered, set the displayIndex to the first unfiltered synapse if there is one
var displayIndex = e.getData('displayIndex') ? e.getData('displayIndex') : 0
var displayedSynapse = synapses[displayIndex]
desc = displayedSynapse.get('desc')
if (passesSynapse && visible.synapses.indexOf(desc) === -1) {
// iterate and find an unfiltered one
for (let i = 0; i < synapses.length; i++) {
desc = synapses[i].get('desc')
if (visible.synapses.indexOf(desc) > -1) {
e.setData('displayIndex', i)
break
} }
} }
} })
map.DataModel[collection[1]].each(function(model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
} else if (typeof collection === 'string') {
map.DataModel[collection].each(function(model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
}
removed = _.difference(self.filters[filtersToUse], newList)
added = _.difference(newList, self.filters[filtersToUse])
_.each(removed, function(identifier) {
const index = self.visible[filtersToUse].indexOf(identifier)
self.visible[filtersToUse].splice(index, 1)
delete self.dataForPresentation[filtersToUse][identifier]
})
_.each(added, function(identifier) {
const model = map.DataModel[correlatedModel].get(identifier) ||
map.DataModel[correlatedModel].find(function(m) {
return m.get(propertyToCheck) === identifier
})
self.dataForPresentation[filtersToUse][identifier] = model.prepareDataForFilter()
self.visible[filtersToUse].push(identifier)
})
// update the list of filters with the new list we just generated
self.filters[filtersToUse] = newList
ReactApp.render()
},
checkMetacodes: function() {
var self = toExport
self.updateFilters('Topics', 'metacode_id', 'Metacodes', 'metacodes', 'metacode')
},
checkMappers: function() {
var self = toExport
if (map.Active.Map) {
self.updateFilters('Mappings', 'user_id', 'Mappers', 'mappers', 'mapper')
} else {
// on topic view
self.updateFilters(['Topics', 'Synapses'], 'user_id', 'Creators', 'mappers', 'mapper')
}
},
checkSynapses: function() {
var self = toExport
self.updateFilters('Synapses', 'desc', 'Synapses', 'synapses', 'synapse')
},
filterAllMetacodes: function(toVisible) {
var self = toExport
self.visible.metacodes = toVisible ? self.filters.metacodes.slice() : []
ReactApp.render()
self.passFilters()
},
filterAllMappers: function(toVisible) {
var self = toExport
self.visible.mappers = toVisible ? self.filters.mappers.slice() : []
ReactApp.render()
self.passFilters()
},
filterAllSynapses: function(toVisible) {
var self = toExport
self.visible.synapses = toVisible ? self.filters.synapses.slice() : []
ReactApp.render()
self.passFilters()
},
// an abstraction function for toggleMetacode, toggleMapper, toggleSynapse
// to reduce code redundancy
// gets called in the context of a list item in a filter box
toggleLi: function(whichToFilter, id) {
var self = toExport
if (self.visible[whichToFilter].indexOf(id) === -1) {
self.visible[whichToFilter].push(id)
} else {
const index = self.visible[whichToFilter].indexOf(id)
self.visible[whichToFilter].splice(index, 1)
}
ReactApp.render()
self.passFilters()
},
toggleMetacode: function(id) {
var self = toExport
self.toggleLi('metacodes', id)
},
toggleMapper: function(id) {
var self = toExport
self.toggleLi('mappers', id)
},
toggleSynapse: function(id) {
var self = toExport
self.toggleLi('synapses', id)
},
passFilters: function() {
var self = toExport
var visible = self.visible
var passesMetacode, passesMapper, passesSynapse
var opacityForFilter = map.Active.Map ? 0 : 0.4
map.DataModel.Topics.each(function(topic) {
var n = topic.get('node')
var metacodeId = topic.get('metacode_id').toString()
if (visible.metacodes.indexOf(metacodeId) === -1) passesMetacode = false
else passesMetacode = true
if (map.Active.Map) { if (map.Active.Map) {
// when on a map, // when on a map,
// we filter by mapper according to the person who added the // we filter by mapper according to the person who added the
// topic or synapse to the map // topic or synapse to the map
userId = synapse.getMapping().get('user_id').toString() let userId = topic.getMapping().get('user_id').toString()
} if (visible.mappers.indexOf(userId) === -1) passesMapper = false
if (visible.mappers.indexOf(userId) === -1) passesMapper = false else passesMapper = true
else passesMapper = true
var color = Settings.colors.synapses.normal
if (passesSynapse && passesMapper) {
e.setData('alpha', 1, 'end')
e.setData('color', color, 'end')
} else { } else {
map.Control.deselectEdge(e, true) // when on a topic view,
e.setData('alpha', opacityForFilter, 'end') // we filter by mapper according to the person who created the
// topic or synapse
let userId = topic.get('user_id').toString()
if (visible.mappers.indexOf(userId) === -1) passesMapper = false
else passesMapper = true
} }
e.setData('touched', true) if (passesMetacode && passesMapper) {
} else if (!e) { if (n) {
console.log(synapse) n.setData('alpha', 1, 'end')
} } else {
}) console.log(topic)
}
} else {
if (n) {
map.Control.deselectNode(n, true)
n.setData('alpha', opacityForFilter, 'end')
n.eachAdjacency(function(e) {
map.Control.deselectEdge(e, true)
})
} else {
console.log(topic)
}
}
})
// run the animation // flag all the edges back to 'untouched'
map.Visualize.mGraph.fx.animate({ map.DataModel.Synapses.each(function(synapse) {
modes: ['node-property:alpha', var e = synapse.get('edge')
'edge-property:alpha'], e.setData('touched', false)
duration: 200 })
}) map.DataModel.Synapses.each(function(synapse) {
var e = synapse.get('edge')
var desc
var userId = synapse.get('user_id').toString()
if (e && !e.getData('touched')) {
var synapses = e.getData('synapses')
// if any of the synapses represent by the edge are still unfiltered
// leave the edge visible
passesSynapse = false
for (let i = 0; i < synapses.length; i++) {
desc = synapses[i].get('desc')
if (visible.synapses.indexOf(desc) > -1) passesSynapse = true
}
// if the synapse description being displayed is now being
// filtered, set the displayIndex to the first unfiltered synapse if there is one
var displayIndex = e.getData('displayIndex') ? e.getData('displayIndex') : 0
var displayedSynapse = synapses[displayIndex]
desc = displayedSynapse.get('desc')
if (passesSynapse && visible.synapses.indexOf(desc) === -1) {
// iterate and find an unfiltered one
for (let i = 0; i < synapses.length; i++) {
desc = synapses[i].get('desc')
if (visible.synapses.indexOf(desc) > -1) {
e.setData('displayIndex', i)
break
}
}
}
if (map.Active.Map) {
// when on a map,
// we filter by mapper according to the person who added the
// topic or synapse to the map
userId = synapse.getMapping().get('user_id').toString()
}
if (visible.mappers.indexOf(userId) === -1) passesMapper = false
else passesMapper = true
var color = Settings.colors.synapses.normal
if (passesSynapse && passesMapper) {
e.setData('alpha', 1, 'end')
e.setData('color', color, 'end')
} else {
map.Control.deselectEdge(e, true)
e.setData('alpha', opacityForFilter, 'end')
}
e.setData('touched', true)
} else if (!e) {
console.log(synapse)
}
})
// run the animation
map.Visualize.mGraph.fx.animate({
modes: ['node-property:alpha',
'edge-property:alpha'],
duration: 200
})
}
} }
} return toExport
return toExport
} }
export default Filter export default Filter

View file

@ -3,387 +3,389 @@
import outdent from 'outdent' import outdent from 'outdent'
import { browserHistory } from 'react-router' import { browserHistory } from 'react-router'
import DataModel from '../DataModel'
import GlobalUI, { ReactApp } from '../GlobalUI' import GlobalUI, { ReactApp } from '../GlobalUI'
import Util from '../Util' import Util from '../Util'
const InfoBox = (map) => { const InfoBox = (map) => {
const toExport = { const toExport = {
isOpen: false, isOpen: false,
selectingPermission: false, selectingPermission: false,
changePermissionText: "<div class='tooltips'>As the creator, you can change the permission of this map, and the permission of all the topics and synapses you have authority to change will change as well.</div>", changePermissionText: "<div class='tooltips'>As the creator, you can change the permission of this map, and the permission of all the topics and synapses you have authority to change will change as well.</div>",
nameHTML: outdent` nameHTML: outdent`
<span class="best_in_place best_in_place_name" <span class="best_in_place best_in_place_name"
id="best_in_place_map_{{id}}_name" id="best_in_place_map_{{id}}_name"
data-bip-url="/maps/{{id}}" data-bip-url="/maps/{{id}}"
data-bip-object="map" data-bip-object="map"
data-bip-attribute="name" data-bip-attribute="name"
data-bip-type="textarea" data-bip-type="textarea"
data-bip-activator="#mapInfoName" data-bip-activator="#mapInfoName"
data-bip-value="{{name}}" data-bip-value="{{name}}"
>{{name}}</span>`, >{{name}}</span>`,
descHTML: outdent` descHTML: outdent`
<span class="best_in_place best_in_place_desc" <span class="best_in_place best_in_place_desc"
id="best_in_place_map_{{id}}_desc" id="best_in_place_map_{{id}}_desc"
data-bip-url="/maps/{{id}}" data-bip-url="/maps/{{id}}"
data-bip-object="map" data-bip-object="map"
data-bip-attribute="desc" data-bip-attribute="desc"
data-bip-nil="Click to add description..." data-bip-nil="Click to add description..."
data-bip-type="textarea" data-bip-type="textarea"
data-bip-activator="#mapInfoDesc" data-bip-activator="#mapInfoDesc"
data-bip-value="{{desc}}" data-bip-value="{{desc}}"
>{{desc}}</span>`, >{{desc}}</span>`,
userImageUrl: '', userImageUrl: '',
html: '', html: '',
init: function(serverData, updateThumbnail) { init: function(serverData, updateThumbnail) {
var self = toExport var self = toExport
self.updateThumbnail = updateThumbnail self.updateThumbnail = updateThumbnail
$('.maptoExport').click(function(event) { $('.mapInfoBox').click(function(event) {
event.stopPropagation() event.stopPropagation()
}) })
$('body').click(self.close) $('body').click(self.close)
self.attachEventListeners() self.attachEventListeners()
self.generateBoxHTML = Hogan.compile($('#maptoExportTemplate').html()) self.generateBoxHTML = Hogan.compile($('#mapInfoBoxTemplate').html())
self.userImageUrl = serverData['user.png'] self.userImageUrl = serverData['user.png']
var querystring = window.location.search.replace(/^\?/, '') var querystring = window.location.search.replace(/^\?/, '')
if (querystring === 'new') { if (querystring === 'new') {
self.open() self.open()
$('.maptoExport').addClass('mapRequestTitle') $('.mapInfoBox').addClass('mapRequestTitle')
$('#mapInfoName').trigger('click') $('#mapInfoName').trigger('click')
$('#mapInfoName textarea').focus() $('#mapInfoName textarea').focus()
$('#mapInfoName textarea').select() $('#mapInfoName textarea').select()
}
},
toggleBox: function(event) {
var self = toExport
if (self.isOpen) self.close()
else self.open()
event.stopPropagation()
},
open: function() {
var self = toExport
$('.mapInfoIcon div').addClass('hide')
$('.maptoExport').fadeIn(200, function() {
self.isOpen = true
})
},
close: function() {
var self = toExport
$('.mapInfoIcon div').removeClass('hide')
$('.maptoExport').fadeOut(200, function() {
self.isOpen = false
self.hidePermissionSelect()
$('.mapContributors .tip').hide()
})
},
load: function() {
var self = toExport
var map = map.Active.Map
var obj = map.pick('permission', 'topic_count', 'synapse_count')
var isCreator = map.authorizePermissionChange(map.Active.Mapper)
var canEdit = map.authorizeToEdit(map.Active.Mapper)
var relevantPeople = map.get('permission') === 'commons' ? map.DataModel.Mappers : map.DataModel.Collaborators
var shareable = map.get('permission') !== 'private'
obj['name'] = canEdit ? Hogan.compile(self.nameHTML).render({id: map.id, name: map.get('name')}) : map.get('name')
obj['desc'] = canEdit ? Hogan.compile(self.descHTML).render({id: map.id, desc: map.get('desc')}) : map.get('desc')
obj['map_creator_tip'] = isCreator ? self.changePermissionText : ''
obj['contributor_count'] = relevantPeople.length
obj['contributors_class'] = relevantPeople.length > 1 ? 'multiple' : ''
obj['contributors_class'] += relevantPeople.length === 2 ? ' mTwo' : ''
obj['contributor_image'] = relevantPeople.length > 0 ? relevantPeople.models[0].get('image') : self.userImageUrl
obj['contributor_list'] = self.createContributorList()
obj['user_name'] = isCreator ? 'You' : map.get('user_name')
obj['created_at'] = map.get('created_at_clean')
obj['updated_at'] = map.get('updated_at_clean')
self.html = self.generateBoxHTML.render(obj)
ReactApp.render()
self.attachEventListeners()
},
attachEventListeners: function() {
var self = toExport
$('.maptoExport.canEdit .best_in_place').best_in_place()
// because anyone who can edit the map can change the map title
var bipName = $('.maptoExport .best_in_place_name')
bipName.unbind('best_in_place:activate').bind('best_in_place:activate', function() {
var $el = bipName.find('textarea')
var el = $el[0]
$el.attr('maxlength', '140')
$('.mapInfoName').append('<div class="nameCounter forMap"></div>')
var callback = function(data) {
$('.nameCounter.forMap').html(data.all + '/140')
} }
Countable.live(el, callback) },
}) toggleBox: function(event) {
bipName.unbind('best_in_place:deactivate').bind('best_in_place:deactivate', function() { var self = toExport
$('.nameCounter.forMap').remove()
})
$('.mapInfoName .best_in_place_name').unbind('ajax:success').bind('ajax:success', function() { if (self.isOpen) self.close()
var name = $(this).html() else self.open()
map.Active.Map.set('name', name)
map.Active.Map.trigger('saved')
// mobile menu
$('#header_content').html(name)
$('.maptoExport').removeClass('mapRequestTitle')
document.title = `${name} | Metamaps`
window.history.replaceState('', `${name} | Metamaps`, window.location.pathname)
})
$('.mapInfoDesc .best_in_place_desc').unbind('ajax:success').bind('ajax:success', function() {
var desc = $(this).html()
map.Active.Map.set('desc', desc)
map.Active.Map.trigger('saved')
})
$('.mapInfoDesc .best_in_place_desc, .mapInfoName .best_in_place_name').unbind('keypress').keypress(function(e) {
const ENTER = 13
if (e.which === ENTER) {
$(this).data('bestInPlaceEditor').update()
}
})
$('.yourMap .mapPermission').unbind().click(self.onPermissionClick)
// .yourMap in the unbind/bind is just a namespace for the events
// not a reference to the class .yourMap on the .maptoExport
$('.maptoExport.yourMap').unbind('.yourMap').bind('click.yourMap', self.hidePermissionSelect)
$('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap)
$('.mapInfoThumbnail').unbind().click(self.updateThumbnail)
$('.mapContributors span, #mapContribs').unbind().click(function(event) {
$('.mapContributors .tip').toggle()
event.stopPropagation() event.stopPropagation()
}) },
$('.mapContributors .tip').unbind().click(function(event) { open: function() {
event.stopPropagation() var self = toExport
}) $('.mapInfoIcon div').addClass('hide')
$('.maptoExport').fadeIn(200, function() {
self.isOpen = true
})
},
close: function() {
var self = toExport
$('.mapInfoIcon div').removeClass('hide')
$('.mapInfoBox').fadeOut(200, function() {
self.isOpen = false
self.hidePermissionSelect()
$('.mapContributors .tip').hide()
})
},
load: function() {
var self = toExport
$('.maptoExport').unbind('.hideTip').bind('click.hideTip', function() { var m = map.Active.Map
$('.mapContributors .tip').hide()
})
self.addTypeahead() var obj = m.pick('permission', 'topic_count', 'synapse_count')
},
addTypeahead: function() {
var self = toExport
if (!map.Active.Map) return var isCreator = m.authorizePermissionChange(map.Active.Mapper)
var canEdit = m.authorizeToEdit(map.Active.Mapper)
var relevantPeople = m.get('permission') === 'commons' ? map.DataModel.Mappers : map.DataModel.Collaborators
var shareable = m.get('permission') !== 'private'
// for autocomplete obj['name'] = canEdit ? Hogan.compile(self.nameHTML).render({id: m.id, name: m.get('name')}) : m.get('name')
var collaborators = { obj['desc'] = canEdit ? Hogan.compile(self.descHTML).render({id: m.id, desc: m.get('desc')}) : m.get('desc')
name: 'collaborators', obj['map_creator_tip'] = isCreator ? self.changePermissionText : ''
limit: 9999,
display: function(s) { return s.label }, obj['contributor_count'] = relevantPeople.length
templates: { obj['contributors_class'] = relevantPeople.length > 1 ? 'multiple' : ''
notFound: function(s) { obj['contributors_class'] += relevantPeople.length === 2 ? ' mTwo' : ''
return Hogan.compile($('#collaboratorSearchTemplate').html()).render({ obj['contributor_image'] = relevantPeople.length > 0 ? relevantPeople.models[0].get('image') : self.userImageUrl
value: 'No results', obj['contributor_list'] = self.createContributorList()
label: 'No results',
rtype: 'noresult', obj['user_name'] = isCreator ? 'You' : m.get('user_name')
profile: self.userImageUrl obj['created_at'] = m.get('created_at_clean')
}) obj['updated_at'] = m.get('updated_at_clean')
},
suggestion: function(s) { self.generateBoxHTML = self.generateBoxHTML || Hogan.compile($('#mapInfoBoxTemplate').html())
return Hogan.compile($('#collaboratorSearchTemplate').html()).render(s) self.html = self.generateBoxHTML.render(obj)
ReactApp.render()
self.attachEventListeners()
},
attachEventListeners: function() {
var self = toExport
$('.maptoExport.canEdit .best_in_place').best_in_place()
// because anyone who can edit the map can change the map title
var bipName = $('.maptoExport .best_in_place_name')
bipName.unbind('best_in_place:activate').bind('best_in_place:activate', function() {
var $el = bipName.find('textarea')
var el = $el[0]
$el.attr('maxlength', '140')
$('.mapInfoName').append('<div class="nameCounter forMap"></div>')
var callback = function(data) {
$('.nameCounter.forMap').html(data.all + '/140')
} }
}, Countable.live(el, callback)
source: new Bloodhound({ })
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), bipName.unbind('best_in_place:deactivate').bind('best_in_place:deactivate', function() {
queryTokenizer: Bloodhound.tokenizers.whitespace, $('.nameCounter.forMap').remove()
remote: { })
url: '/search/mappers?term=%QUERY',
wildcard: '%QUERY' $('.mapInfoName .best_in_place_name').unbind('ajax:success').bind('ajax:success', function() {
var name = $(this).html()
map.Active.Map.set('name', name)
map.Active.Map.trigger('saved')
// mobile menu
$('#header_content').html(name)
$('.maptoExport').removeClass('mapRequestTitle')
document.title = `${name} | Metamaps`
window.history.replaceState('', `${name} | Metamaps`, window.location.pathname)
})
$('.mapInfoDesc .best_in_place_desc').unbind('ajax:success').bind('ajax:success', function() {
var desc = $(this).html()
map.Active.Map.set('desc', desc)
map.Active.Map.trigger('saved')
})
$('.mapInfoDesc .best_in_place_desc, .mapInfoName .best_in_place_name').unbind('keypress').keypress(function(e) {
const ENTER = 13
if (e.which === ENTER) {
$(this).data('bestInPlaceEditor').update()
} }
}) })
}
// for adding map collaborators, who will have edit rights $('.yourMap .mapPermission').unbind().click(self.onPermissionClick)
if (map.Active.Mapper && map.Active.Mapper.id === map.Active.Map.get('user_id')) { // .yourMap in the unbind/bind is just a namespace for the events
$('.collaboratorSearchField').typeahead( // not a reference to the class .yourMap on the .maptoExport
{ $('.maptoExport.yourMap').unbind('.yourMap').bind('click.yourMap', self.hidePermissionSelect)
highlight: false
}, $('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap)
[collaborators] $('.mapInfoThumbnail').unbind().click(self.updateThumbnail)
)
$('.collaboratorSearchField').bind('typeahead:select', self.handleResultClick) $('.mapContributors span, #mapContribs').unbind().click(function(event) {
$('.mapContributors .removeCollaborator').click(function() { $('.mapContributors .tip').toggle()
self.removeCollaborator(parseInt($(this).data('id'))) event.stopPropagation()
})
$('.mapContributors .tip').unbind().click(function(event) {
event.stopPropagation()
}) })
}
},
removeCollaborator: function(collaboratorId) {
var self = toExport
map.DataModel.Collaborators.remove(map.DataModel.Collaborators.get(collaboratorId))
var mapperIds = map.DataModel.Collaborators.models.map(function(mapper) { return mapper.id })
$.post('/maps/' + map.Active.Map.id + '/access', { access: mapperIds })
self.updateNumbers()
},
addCollaborator: function(newCollaboratorId) {
var self = toExport
if (map.DataModel.Collaborators.get(newCollaboratorId)) { $('.maptoExport').unbind('.hideTip').bind('click.hideTip', function() {
GlobalUI.notifyUser('That user already has access') $('.mapContributors .tip').hide()
return })
}
function callback(mapper) { self.addTypeahead()
map.DataModel.Collaborators.add(mapper) },
addTypeahead: function() {
var self = toExport
if (!map.Active.Map) return
// for autocomplete
var collaborators = {
name: 'collaborators',
limit: 9999,
display: function(s) { return s.label },
templates: {
notFound: function(s) {
return Hogan.compile($('#collaboratorSearchTemplate').html()).render({
value: 'No results',
label: 'No results',
rtype: 'noresult',
profile: self.userImageUrl
})
},
suggestion: function(s) {
return Hogan.compile($('#collaboratorSearchTemplate').html()).render(s)
}
},
source: new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/mappers?term=%QUERY',
wildcard: '%QUERY'
}
})
}
// for adding map collaborators, who will have edit rights
if (map.Active.Mapper && map.Active.Mapper.id === map.Active.Map.get('user_id')) {
$('.collaboratorSearchField').typeahead(
{
highlight: false
},
[collaborators]
)
$('.collaboratorSearchField').bind('typeahead:select', self.handleResultClick)
$('.mapContributors .removeCollaborator').click(function() {
self.removeCollaborator(parseInt($(this).data('id')))
})
}
},
removeCollaborator: function(collaboratorId) {
var self = toExport
map.DataModel.Collaborators.remove(map.DataModel.Collaborators.get(collaboratorId))
var mapperIds = map.DataModel.Collaborators.models.map(function(mapper) { return mapper.id }) var mapperIds = map.DataModel.Collaborators.models.map(function(mapper) { return mapper.id })
$.post('/maps/' + map.Active.Map.id + '/access', { access: mapperIds }) $.post('/maps/' + map.Active.Map.id + '/access', { access: mapperIds })
var name = map.DataModel.Collaborators.get(newCollaboratorId).get('name')
GlobalUI.notifyUser(name + ' will be notified')
self.updateNumbers() self.updateNumbers()
} },
addCollaborator: function(newCollaboratorId) {
var self = toExport
$.getJSON('/users/' + newCollaboratorId + '.json', callback) if (map.DataModel.Collaborators.get(newCollaboratorId)) {
}, GlobalUI.notifyUser('That user already has access')
handleResultClick: function(event, item) { return
var self = toExport
self.addCollaborator(item.id)
$('.collaboratorSearchField').typeahead('val', '')
},
updateNameDescPerm: function(name, desc, perm) {
$('.maptoExport').removeClass('mapRequestTitle')
$('.mapInfoName .best_in_place_name').html(name)
$('.mapInfoDesc .best_in_place_desc').html(desc)
$('.maptoExport .mapPermission').removeClass('commons public private').addClass(perm)
},
createContributorList: function() {
var relevantPeople = map.Active.Map.get('permission') === 'commons' ? map.DataModel.Mappers : map.DataModel.Collaborators
var activeMapperIsCreator = map.Active.Mapper && map.Active.Mapper.id === map.Active.Map.get('user_id')
var string = ''
string += '<ul>'
relevantPeople.each(function(m) {
var isCreator = map.Active.Map.get('user_id') === m.get('id')
string += '<li><a href="/explore/mapper/' + m.get('id') + '">' + '<img class="rtUserImage" width="25" height="25" src="' + m.get('image') + '" />' + m.get('name')
if (isCreator) string += ' (creator)'
string += '</a>'
if (activeMapperIsCreator && !isCreator) string += '<span class="removeCollaborator" data-id="' + m.get('id') + '"></span>'
string += '</li>'
})
string += '</ul>'
if (activeMapperIsCreator) {
string += '<div class="collabSearchField"><span class="addCollab"></span><input class="collaboratorSearchField" placeholder="Add a collaborator"></input></div>'
}
return string
},
updateNumbers: function() {
if (!map.Active.Map) return
const self = toExport
var relevantPeople = map.Active.Map.get('permission') === 'commons' ? map.DataModel.Mappers : map.DataModel.Collaborators
let contributorsClass = ''
if (relevantPeople.length === 2) {
contributorsClass = 'multiple mTwo'
} else if (relevantPeople.length > 2) {
contributorsClass = 'multiple'
}
let contributorsImage = self.userImageUrl
if (relevantPeople.length > 0) {
// get the first contributor and use their image
contributorsImage = relevantPeople.models[0].get('image')
}
$('.mapContributors img').attr('src', contributorsImage).removeClass('multiple mTwo').addClass(contributorsClass)
$('.mapContributors span').text(relevantPeople.length)
$('.mapContributors .tip').html(self.createContributorList())
self.addTypeahead()
$('.mapContributors .tip').unbind().click(function(event) {
event.stopPropagation()
})
$('.mapTopics').text(map.DataModel.Topics.length)
$('.mapSynapses').text(map.DataModel.Synapses.length)
$('.mapEditedAt').html('<span>Last edited: </span>' + Util.nowDateFormatted())
},
onPermissionClick: function(event) {
var self = toExport
if (!self.selectingPermission) {
self.selectingPermission = true
$(this).addClass('minimize') // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('commons')) {
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('public')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('private')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>')
} }
$('.mapPermission .permissionSelect li').click(self.selectPermission)
function callback(mapper) {
map.DataModel.Collaborators.add(mapper)
var mapperIds = map.DataModel.Collaborators.models.map(function(mapper) { return mapper.id })
$.post('/maps/' + map.Active.Map.id + '/access', { access: mapperIds })
var name = map.DataModel.Collaborators.get(newCollaboratorId).get('name')
GlobalUI.notifyUser(name + ' will be notified')
self.updateNumbers()
}
$.getJSON('/users/' + newCollaboratorId + '.json', callback)
},
handleResultClick: function(event, item) {
var self = toExport
self.addCollaborator(item.id)
$('.collaboratorSearchField').typeahead('val', '')
},
updateNameDescPerm: function(name, desc, perm) {
$('.maptoExport').removeClass('mapRequestTitle')
$('.mapInfoName .best_in_place_name').html(name)
$('.mapInfoDesc .best_in_place_desc').html(desc)
$('.maptoExport .mapPermission').removeClass('commons public private').addClass(perm)
},
createContributorList: function() {
var relevantPeople = map.Active.Map.get('permission') === 'commons' ? map.DataModel.Mappers : map.DataModel.Collaborators
var activeMapperIsCreator = map.Active.Mapper && map.Active.Mapper.id === map.Active.Map.get('user_id')
var string = ''
string += '<ul>'
relevantPeople.each(function(m) {
var isCreator = map.Active.Map.get('user_id') === m.get('id')
string += '<li><a href="/explore/mapper/' + m.get('id') + '">' + '<img class="rtUserImage" width="25" height="25" src="' + m.get('image') + '" />' + m.get('name')
if (isCreator) string += ' (creator)'
string += '</a>'
if (activeMapperIsCreator && !isCreator) string += '<span class="removeCollaborator" data-id="' + m.get('id') + '"></span>'
string += '</li>'
})
string += '</ul>'
if (activeMapperIsCreator) {
string += '<div class="collabSearchField"><span class="addCollab"></span><input class="collaboratorSearchField" placeholder="Add a collaborator"></input></div>'
}
return string
},
updateNumbers: function() {
if (!map.Active.Map) return
const self = toExport
var relevantPeople = map.Active.Map.get('permission') === 'commons' ? map.DataModel.Mappers : map.DataModel.Collaborators
let contributorsClass = ''
if (relevantPeople.length === 2) {
contributorsClass = 'multiple mTwo'
} else if (relevantPeople.length > 2) {
contributorsClass = 'multiple'
}
let contributorsImage = self.userImageUrl
if (relevantPeople.length > 0) {
// get the first contributor and use their image
contributorsImage = relevantPeople.models[0].get('image')
}
$('.mapContributors img').attr('src', contributorsImage).removeClass('multiple mTwo').addClass(contributorsClass)
$('.mapContributors span').text(relevantPeople.length)
$('.mapContributors .tip').html(self.createContributorList())
self.addTypeahead()
$('.mapContributors .tip').unbind().click(function(event) {
event.stopPropagation()
})
$('.mapTopics').text(map.DataModel.Topics.length)
$('.mapSynapses').text(map.DataModel.Synapses.length)
$('.mapEditedAt').html('<span>Last edited: </span>' + Util.nowDateFormatted())
},
onPermissionClick: function(event) {
var self = toExport
if (!self.selectingPermission) {
self.selectingPermission = true
$(this).addClass('minimize') // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('commons')) {
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('public')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('private')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>')
}
$('.mapPermission .permissionSelect li').click(self.selectPermission)
event.stopPropagation()
}
},
hidePermissionSelect: function() {
var self = toExport
self.selectingPermission = false
$('.mapPermission').removeClass('minimize') // this line flips the pull up arrow to a drop down arrow
$('.mapPermission .permissionSelect').remove()
},
selectPermission: function(event) {
var self = toExport
self.selectingPermission = false
var permission = $(this).attr('class')
map.Active.Map.save({
permission: permission
})
map.Active.Map.updateMapWrapper()
const shareable = permission === 'private' ? '' : 'shareable'
$('.mapPermission').removeClass('commons public private minimize').addClass(permission)
$('.mapPermission .permissionSelect').remove()
$('.maptoExport').removeClass('shareable').addClass(shareable)
event.stopPropagation() event.stopPropagation()
} },
}, deleteActiveMap: function() {
hidePermissionSelect: function() { var confirmString = 'Are you sure you want to delete this map? '
var self = toExport confirmString += 'This action is irreversible. It will not delete the topics and synapses on the map.'
self.selectingPermission = false var doIt = window.confirm(confirmString)
$('.mapPermission').removeClass('minimize') // this line flips the pull up arrow to a drop down arrow var m = map.Active.Map
$('.mapPermission .permissionSelect').remove() var mapper = map.Active.Mapper
}, var authorized = map.authorizePermissionChange(mapper)
selectPermission: function(event) {
var self = toExport
self.selectingPermission = false if (doIt && authorized) {
var permission = $(this).attr('class') toExport.close()
map.Active.Map.save({ DataModel.Maps.map.Active.remove(m)
permission: permission DataModel.Maps.Featured.remove(m)
}) DataModel.Maps.Mine.remove(m)
map.Active.Map.updateMapWrapper() DataModel.Maps.Shared.remove(m)
const shareable = permission === 'private' ? '' : 'shareable' m.destroy()
$('.mapPermission').removeClass('commons public private minimize').addClass(permission) browserHistory.push('/')
$('.mapPermission .permissionSelect').remove() GlobalUI.notifyUser('Map eliminated')
$('.maptoExport').removeClass('shareable').addClass(shareable) } else if (!authorized) {
event.stopPropagation() window.alert("Hey now. We can't just go around willy nilly deleting other people's maps now can we? Run off and find something constructive to do, eh?")
}, }
deleteActiveMap: function() {
var confirmString = 'Are you sure you want to delete this map? '
confirmString += 'This action is irreversible. It will not delete the topics and synapses on the map.'
var doIt = window.confirm(confirmString)
var map = map.Active.Map
var mapper = map.Active.Mapper
var authorized = map.authorizePermissionChange(mapper)
if (doIt && authorized) {
toExport.close()
DataModel.Maps.map.Active.remove(map)
DataModel.Maps.Featured.remove(map)
DataModel.Maps.Mine.remove(map)
DataModel.Maps.Shared.remove(map)
map.destroy()
browserHistory.push('/')
GlobalUI.notifyUser('Map eliminated')
} else if (!authorized) {
window.alert("Hey now. We can't just go around willy nilly deleting other people's maps now can we? Run off and find something constructive to do, eh?")
} }
} }
} return toExport
return toExport
} }
export default InfoBox export default InfoBox

File diff suppressed because it is too large Load diff

View file

@ -3,8 +3,12 @@
import SimpleWebRTC from 'simplewebrtc' import SimpleWebRTC from 'simplewebrtc'
import SocketIoConnection from 'simplewebrtc/socketioconnection' import SocketIoConnection from 'simplewebrtc/socketioconnection'
import MessageCollection from '../../DataModel/MessageCollection'
import Util from '../../Util' import Util from '../../Util'
import Views from '../Views' import Views from '../Views'
import ChatView from '../ChatView'
import { ReactApp } from '../../GlobalUI'
import JIT from '../JIT'
import { import {
JUNTO_UPDATED, JUNTO_UPDATED,
@ -25,7 +29,6 @@ import {
} from './events' } from './events'
import { import {
juntoUpdated,
invitedToCall, invitedToCall,
invitedToJoin, invitedToJoin,
callAccepted, callAccepted,
@ -59,49 +62,63 @@ import {
} from './sendable' } from './sendable'
const Realtime = (map) => { const Realtime = (map) => {
const toExport = { const toExport = {
videoId: 'video-wrapper', videoId: 'video-wrapper',
socket: null, webrtc: null,
webrtc: null, readyToCall: false,
readyToCall: false, mappersOnMap: {},
mappersOnMap: {}, chatOpen: false,
disconnected: false, soundId: null,
chatOpen: false, broadcastingStatus: false,
soundId: null, inConversation: false,
broadcastingStatus: false, localVideo: null,
inConversation: false, onSocketConnect: () => {},
localVideo: null, startActiveMap: function() {
'junto_spinner_darkgrey.gif': '', var self = toExport
init: function(serverData) { if (map.Active.Map.authorizeToEdit(map.Active.Mapper)) {
var self = toExport self.addJuntoListeners()
if (Realtime.socket && !Realtime.socket.disconnected) self.onSocketConnect = self._onSocketConnect
self.addJuntoListeners() else self._onSocketConnect()
}
self.socket = new SocketIoConnection({ if (map.Active.Mapper) {
url: serverData['REALTIME_SERVER'], self.setupChat() // chat can happen on public maps too
socketio: { map.Cable.subscribeToMap(map.Active.Map.id) // people with viewing rights can still see live updates
// don't poll forever if in development }
reconnectionAttempts: serverData.RAILS_ENV === 'development' ? 5 : Infinity },
} endActiveMap: function() {
}) var self = toExport
self['junto_spinner_darkgrey.gif'] = serverData['junto_spinner_darkgrey.gif'] $(document).off('.map')
// leave the appropriate rooms to leave
self.socket.on('connect', function() { if (self.inConversation) self.leaveCall()
console.log('connected') self.leaveMap()
if (map.Active.Map && map.Active.Mapper && map.Active.Map.authorizeToEdit(map.Active.Mapper)) { $('.collabCompass').remove()
self.checkForCall() if (self.room) self.room.leave()
self.joinMap() if (!Realtime.socket.disconnected) self.unsubscribeFromEvents()
} map.Cable.unsubscribeFromMap()
subscribeToEvents(self, self.socket) },
self.disconnected = false _onSocketConnect: function() {
}) console.log('testing')
self.socket.on('disconnect', function() { const self = toExport
self.disconnected = true const sendables = [
}) ['joinMap', joinMap],
['leaveMap', leaveMap],
if (map.Active.Mapper) { ['checkForCall', checkForCall],
['acceptCall', acceptCall],
['denyCall', denyCall],
['denyInvite', denyInvite],
['inviteToJoin', inviteToJoin],
['inviteACall', inviteACall],
['joinCall', joinCall],
['leaveCall', leaveCall],
['sendMapperInfo', sendMapperInfo],
['sendCoords', sendCoords],
['dragTopic', dragTopic]
]
sendables.forEach(sendable => {
toExport[sendable[0]] = sendable[1](Realtime.socket, toExport, map)
})
self.webrtc = new SimpleWebRTC({ self.webrtc = new SimpleWebRTC({
connection: self.socket, connection: Realtime.socket,
localVideoEl: self.videoId, localVideoEl: self.videoId,
remoteVideosEl: '', remoteVideosEl: '',
debug: true, debug: true,
@ -127,7 +144,6 @@ const toExport = {
console.log('remote ice failure', peer) console.log('remote ice failure', peer)
// remote ice failure // remote ice failure
}) })
var $video = $('<video></video>').attr('id', self.videoId) var $video = $('<video></video>').attr('id', self.videoId)
self.localVideo = { self.localVideo = {
$video: $video, $video: $video,
@ -136,291 +152,291 @@ const toExport = {
avatar: map.Active.Mapper ? map.Active.Mapper.get('image') : '' avatar: map.Active.Mapper ? map.Active.Mapper.get('image') : ''
}) })
} }
self.room = new Views.Room({ self.room = new Views.Room({
webrtc: self.webrtc, webrtc: self.webrtc,
socket: self.socket, room: 'map-' + map.Active.Map.id,
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 }
}) })
self.room.videoAdded(self.handleVideoAdded) self.room.videoAdded(self.handleVideoAdded)
} // if map.Active.Mapper self.subscribeToEvents()
}, self.turnOn()
addJuntoListeners: function() { self.checkForCall()
var self = toExport self.joinMap()
},
$(document).on(ChatView.events.openTray, function() { addJuntoListeners: function() {
$('.main').addClass('compressed') var self = toExport
self.chatOpen = true $(document).on(ChatView.events.openTray, function() {
self.positionPeerIcons() $('.main').addClass('compressed')
}) self.chatOpen = true
$(document).on(ChatView.events.closeTray, function() { self.positionPeerIcons()
$('.main').removeClass('compressed')
self.chatOpen = false
self.positionPeerIcons()
})
$(document).on(ChatView.events.videosOn, function() {
$('#wrapper').removeClass('hideVideos')
})
$(document).on(ChatView.events.videosOff, function() {
$('#wrapper').addClass('hideVideos')
})
$(document).on(ChatView.events.cursorsOn, function() {
$('#wrapper').removeClass('hideCursors')
})
$(document).on(ChatView.events.cursorsOff, function() {
$('#wrapper').addClass('hideCursors')
})
},
startActiveMap: function() {
var self = toExport
if (map.Active.Map && map.Active.Mapper) {
if (map.Active.Map.authorizeToEdit(map.Active.Mapper)) {
self.turnOn()
self.checkForCall()
self.joinMap()
}
self.setupChat() // chat can happen on public maps too
map.Cable.subscribeToMap(map.Active.Map.id) // people with edit rights can still see live updates
}
},
endActiveMap: function() {
var self = toExport
$(document).off('.map')
// leave the appropriate rooms to leave
if (self.inConversation) self.leaveCall()
self.leaveMap()
$('.collabCompass').remove()
if (self.room) self.room.leave()
map.Cable.unsubscribeFromMap()
},
turnOn: function(notify) {
var self = toExport
$('.collabCompass').show()
self.room.room = 'map-' + map.Active.Map.id
self.activeMapper = {
id: map.Active.Mapper.id,
name: map.Active.Mapper.get('name'),
username: map.Active.Mapper.get('name'),
image: map.Active.Mapper.get('image'),
color: Util.getPastelColor(),
self: true
}
self.localVideo.view.$container.find('.video-cutoff').css({
border: '4px solid ' + self.activeMapper.color
})
self.setupLocalEvents()
},
setupChat: function() {
const self = toExport
map.ChatView.setNewMap()
map.ChatView.addParticipant(self.activeMapper)
map.ChatView.addMessages(new DataModel.MessageCollection(map.DataModel.Messages), true)
},
setupLocalEvents: function() {
var self = toExport
// local event listeners that trigger events
$(document).on(map.JIT.events.zoom + '.map', self.positionPeerIcons)
$(document).on(map.JIT.events.pan + '.map', self.positionPeerIcons)
$(document).on('mousemove.map', function(event) {
var pixels = {
x: event.pageX,
y: event.pageY
}
var coords = Util.pixelsToCoords(map.Visualize.mGraph, pixels)
self.sendCoords(coords)
})
$(document).on(map.JIT.events.topicDrag + '.map', function(event, positions) {
self.dragTopic(positions)
})
},
countOthersInConversation: function() {
var self = toExport
var count = 0
for (var key in self.mappersOnMap) {
if (self.mappersOnMap[key].inConversation) count++
}
return count
},
handleVideoAdded: function(v, id) {
var self = toExport
self.positionVideos()
v.setParent($('#wrapper'))
v.$container.find('.video-cutoff').css({
border: '4px solid ' + self.mappersOnMap[id].color
})
$('#wrapper').append(v.$container)
},
positionVideos: function() {
var self = toExport
var videoIds = Object.keys(self.room.videos)
// var numOfVideos = videoIds.length
// var numOfVideosToPosition = _.filter(videoIds, function(id) {
// return !self.room.videos[id].manuallyPositioned
// }).length
var screenHeight = $(document).height()
var topExtraPadding = 20
var topPadding = 30
var leftPadding = 30
var videoHeight = 150
var videoWidth = 180
var column = 0
var row = 0
var yFormula = function() {
var y = topExtraPadding + (topPadding + videoHeight) * row + topPadding
if (y + videoHeight > screenHeight) {
row = 0
column += 1
y = yFormula()
}
row++
return y
}
var xFormula = function() {
var x = (leftPadding + videoWidth) * column + leftPadding
return x
}
// do self first
var myVideo = toExport.localVideo.view
if (!myVideo.manuallyPositioned) {
myVideo.$container.css({
top: yFormula() + 'px',
left: xFormula() + 'px'
}) })
} $(document).on(ChatView.events.closeTray, function() {
videoIds.forEach(function(id) { $('.main').removeClass('compressed')
var video = self.room.videos[id] self.chatOpen = false
if (!video.manuallyPositioned) { self.positionPeerIcons()
video.$container.css({ })
$(document).on(ChatView.events.videosOn, function() {
$('#wrapper').removeClass('hideVideos')
})
$(document).on(ChatView.events.videosOff, function() {
$('#wrapper').addClass('hideVideos')
})
$(document).on(ChatView.events.cursorsOn, function() {
$('#wrapper').removeClass('hideCursors')
})
$(document).on(ChatView.events.cursorsOff, function() {
$('#wrapper').addClass('hideCursors')
})
},
turnOn: function(notify) {
var self = toExport
$('.collabCompass').show()
self.activeMapper = {
id: map.Active.Mapper.id,
name: map.Active.Mapper.get('name'),
username: map.Active.Mapper.get('name'),
image: map.Active.Mapper.get('image'),
color: Util.getPastelColor(),
self: true
}
self.localVideo.view.$container.find('.video-cutoff').css({
border: '4px solid ' + self.activeMapper.color
})
self.setupLocalEvents()
},
setupChat: function() {
const self = toExport
map.ChatView.setNewMap()
map.ChatView.addParticipant(self.activeMapper)
map.ChatView.addMessages(new MessageCollection(map.DataModel.Messages), true)
},
setupLocalEvents: function() {
var self = toExport
// local event listeners that trigger events
$(document).on(JIT.events.zoom + '.map', self.positionPeerIcons)
$(document).on(JIT.events.pan + '.map', self.positionPeerIcons)
$(document).on('mousemove.map', function(event) {
var pixels = {
x: event.pageX,
y: event.pageY
}
var coords = Util.pixelsToCoords(map.Visualize.mGraph, pixels)
self.sendCoords(coords)
})
$(document).on(JIT.events.topicDrag + '.map', function(event, positions) {
self.dragTopic(positions)
})
},
subscribeToEvents: function() {
// todo scope these event listeners to map
const socket = Realtime.socket
socket.on(INVITED_TO_CALL, invitedToCall(toExport, map))
socket.on(INVITED_TO_JOIN, invitedToJoin(toExport, map))
socket.on(CALL_ACCEPTED, callAccepted(toExport, map))
socket.on(CALL_DENIED, callDenied(toExport, map))
socket.on(INVITE_DENIED, inviteDenied(toExport, map))
socket.on(CALL_IN_PROGRESS, callInProgress(toExport, map))
socket.on(CALL_STARTED, callStarted(toExport, map))
socket.on(MAPPER_LIST_UPDATED, mapperListUpdated(toExport, map))
socket.on(MAPPER_JOINED_CALL, mapperJoinedCall(toExport, map))
socket.on(MAPPER_LEFT_CALL, mapperLeftCall(toExport, map))
socket.on(PEER_COORDS_UPDATED, peerCoordsUpdated(toExport, map))
socket.on(NEW_MAPPER, newMapper(toExport, map))
socket.on(LOST_MAPPER, lostMapper(toExport, map))
socket.on(TOPIC_DRAGGED, topicDragged(toExport, map))
},
unsubscribeFromEvents: function() {
// todo scope these event listeners to map
const socket = Realtime.socket
socket.off(INVITED_TO_JOIN)
socket.off(CALL_ACCEPTED)
socket.off(INVITED_TO_CALL)
socket.off(CALL_DENIED)
socket.off(INVITE_DENIED)
socket.off(CALL_IN_PROGRESS)
socket.off(CALL_STARTED)
socket.off(MAPPER_LIST_UPDATED)
socket.off(MAPPER_JOINED_CALL)
socket.off(MAPPER_LEFT_CALL)
socket.off(PEER_COORDS_UPDATED)
socket.off(NEW_MAPPER)
socket.off(LOST_MAPPER)
socket.off(TOPIC_DRAGGED)
},
countOthersInConversation: function() {
var self = toExport
var count = 0
for (var key in self.mappersOnMap) {
if (self.mappersOnMap[key].inConversation) count++
}
return count
},
handleVideoAdded: function(v, id) {
var self = toExport
self.positionVideos()
v.setParent($('#wrapper'))
v.$container.find('.video-cutoff').css({
border: '4px solid ' + self.mappersOnMap[id].color
})
$('#wrapper').append(v.$container)
},
positionVideos: function() {
var self = toExport
var videoIds = Object.keys(self.room.videos)
// var numOfVideos = videoIds.length
// var numOfVideosToPosition = _.filter(videoIds, function(id) {
// return !self.room.videos[id].manuallyPositioned
// }).length
var screenHeight = $(document).height()
var topExtraPadding = 20
var topPadding = 30
var leftPadding = 30
var videoHeight = 150
var videoWidth = 180
var column = 0
var row = 0
var yFormula = function() {
var y = topExtraPadding + (topPadding + videoHeight) * row + topPadding
if (y + videoHeight > screenHeight) {
row = 0
column += 1
y = yFormula()
}
row++
return y
}
var xFormula = function() {
var x = (leftPadding + videoWidth) * column + leftPadding
return x
}
// do self first
var myVideo = toExport.localVideo.view
if (!myVideo.manuallyPositioned) {
myVideo.$container.css({
top: yFormula() + 'px', top: yFormula() + 'px',
left: xFormula() + 'px' left: xFormula() + 'px'
}) })
} }
}) videoIds.forEach(function(id) {
}, var video = self.room.videos[id]
callEnded: function() { if (!video.manuallyPositioned) {
var self = toExport video.$container.css({
top: yFormula() + 'px',
map.ChatView.conversationEnded() left: xFormula() + 'px'
self.room.leaveVideoOnly() })
self.inConversation = false }
self.localVideo.view.$container.hide().css({
top: '72px',
left: '30px'
})
self.localVideo.view.audioOn()
self.localVideo.view.videoOn()
},
createCompass: function(name, id, image, color) {
var str = '<img width="28" height="28" src="' + image + '" /><p>' + name + '</p>'
str += '<div id="compassArrow' + id + '" class="compassArrow"></div>'
$('#compass' + id).remove()
$('<div/>', {
id: 'compass' + id,
class: 'collabCompass'
}).html(str).appendTo('#wrapper')
$('#compass' + id + ' img').css({
'border': '2px solid ' + color
})
$('#compass' + id + ' p').css({
'background-color': color
})
},
positionPeerIcons: function() {
var self = toExport
for (var key in self.mappersOnMap) {
self.positionPeerIcon(key)
}
},
positionPeerIcon: function(id) {
var self = toExport
var mapper = self.mappersOnMap[id]
var origPixels = Util.coordsToPixels(map.Visualize.mGraph, mapper.coords)
var pixels = self.limitPixelsToScreen(origPixels)
$('#compass' + id).css({
left: pixels.x + 'px',
top: pixels.y + 'px'
})
/* showing the arrow if the collaborator is off of the viewport screen */
if (origPixels.x !== pixels.x || origPixels.y !== pixels.y) {
var dy = origPixels.y - pixels.y // opposite
var dx = origPixels.x - pixels.x // adjacent
var angle = Math.atan2(dy, dx)
$('#compassArrow' + id).show().css({
transform: 'rotate(' + angle + 'rad)',
'-webkit-transform': 'rotate(' + angle + 'rad)'
}) })
},
callEnded: function() {
var self = toExport
if (dx > 0) { map.ChatView.conversationEnded()
$('#compass' + id).addClass('labelLeft') self.room.leaveVideoOnly()
self.inConversation = false
self.localVideo.view.$container.hide().css({
top: '72px',
left: '30px'
})
self.localVideo.view.audioOn()
self.localVideo.view.videoOn()
},
createCompass: function(name, id, image, color) {
var str = '<img width="28" height="28" src="' + image + '" /><p>' + name + '</p>'
str += '<div id="compassArrow' + id + '" class="compassArrow"></div>'
$('#compass' + id).remove()
$('<div/>', {
id: 'compass' + id,
class: 'collabCompass'
}).html(str).appendTo('#wrapper')
$('#compass' + id + ' img').css({
'border': '2px solid ' + color
})
$('#compass' + id + ' p').css({
'background-color': color
})
},
positionPeerIcons: function() {
var self = toExport
for (var key in self.mappersOnMap) {
self.positionPeerIcon(key)
} }
} else { },
$('#compassArrow' + id).hide() positionPeerIcon: function(id) {
$('#compass' + id).removeClass('labelLeft') var self = toExport
var mapper = self.mappersOnMap[id]
var origPixels = Util.coordsToPixels(map.Visualize.mGraph, mapper.coords)
var pixels = self.limitPixelsToScreen(origPixels)
$('#compass' + id).css({
left: pixels.x + 'px',
top: pixels.y + 'px'
})
/* showing the arrow if the collaborator is off of the viewport screen */
if (origPixels.x !== pixels.x || origPixels.y !== pixels.y) {
var dy = origPixels.y - pixels.y // opposite
var dx = origPixels.x - pixels.x // adjacent
var angle = Math.atan2(dy, dx)
$('#compassArrow' + id).show().css({
transform: 'rotate(' + angle + 'rad)',
'-webkit-transform': 'rotate(' + angle + 'rad)'
})
if (dx > 0) {
$('#compass' + id).addClass('labelLeft')
}
} else {
$('#compassArrow' + id).hide()
$('#compass' + id).removeClass('labelLeft')
}
},
limitPixelsToScreen: function(pixels) {
var self = toExport
var boundary = self.chatOpen ? '#wrapper' : document
var xLimit, yLimit
var xMax = $(boundary).width()
var yMax = $(boundary).height()
var compassDiameter = 56
var compassArrowSize = 24
xLimit = Math.max(0 + compassArrowSize, pixels.x)
xLimit = Math.min(xLimit, xMax - compassDiameter)
yLimit = Math.max(0 + compassArrowSize, pixels.y)
yLimit = Math.min(yLimit, yMax - compassDiameter)
return {x: xLimit, y: yLimit}
} }
},
limitPixelsToScreen: function(pixels) {
var self = toExport
var boundary = self.chatOpen ? '#wrapper' : document
var xLimit, yLimit
var xMax = $(boundary).width()
var yMax = $(boundary).height()
var compassDiameter = 56
var compassArrowSize = 24
xLimit = Math.max(0 + compassArrowSize, pixels.x)
xLimit = Math.min(xLimit, xMax - compassDiameter)
yLimit = Math.max(0 + compassArrowSize, pixels.y)
yLimit = Math.min(yLimit, yMax - compassDiameter)
return {x: xLimit, y: yLimit}
} }
return toExport
} }
const sendables = [ Realtime.init = function(serverData) {
['joinMap', joinMap], var self = Realtime
['leaveMap', leaveMap], self.socket = new SocketIoConnection({
['checkForCall', checkForCall], url: serverData['REALTIME_SERVER'],
['acceptCall', acceptCall], socketio: {
['denyCall', denyCall], // don't poll forever if in development
['denyInvite', denyInvite], reconnectionAttempts: serverData.RAILS_ENV === 'development' ? 5 : Infinity
['inviteToJoin', inviteToJoin], }
['inviteACall', inviteACall], })
['joinCall', joinCall], self['junto_spinner_darkgrey.gif'] = serverData['junto_spinner_darkgrey.gif']
['leaveCall', leaveCall], self.socket.on('connect', function() {
['sendMapperInfo', sendMapperInfo], console.log('connected')
['sendCoords', sendCoords], self.socket.on(JUNTO_UPDATED, (state) => {
['dragTopic', dragTopic] ReactApp.juntoState = state
] ReactApp.render()
sendables.forEach(sendable => { })
toExport[sendable[0]] = sendable[1](toExport, map) self.disconnected = false
}) ReactApp.openMap && ReactApp.openMap.Realtime.onSocketConnect()
})
const subscribeToEvents = (toExport, socket) => { self.socket.on('disconnect', function() {
socket.on(JUNTO_UPDATED, juntoUpdated(toExport, map)) self.disconnected = true
socket.on(INVITED_TO_CALL, invitedToCall(toExport, map)) })
socket.on(INVITED_TO_JOIN, invitedToJoin(toExport, map))
socket.on(CALL_ACCEPTED, callAccepted(toExport, map))
socket.on(CALL_DENIED, callDenied(toExport, map))
socket.on(INVITE_DENIED, inviteDenied(toExport, map))
socket.on(CALL_IN_PROGRESS, callInProgress(toExport, map))
socket.on(CALL_STARTED, callStarted(toExport, map))
socket.on(MAPPER_LIST_UPDATED, mapperListUpdated(toExport, map))
socket.on(MAPPER_JOINED_CALL, mapperJoinedCall(toExport, map))
socket.on(MAPPER_LEFT_CALL, mapperLeftCall(toExport, map))
socket.on(PEER_COORDS_UPDATED, peerCoordsUpdated(toExport, map))
socket.on(NEW_MAPPER, newMapper(toExport, map))
socket.on(LOST_MAPPER, lostMapper(toExport, map))
socket.on(TOPIC_DRAGGED, topicDragged(toExport, map))
}
return toExport
} }

View file

@ -4,16 +4,9 @@
everthing in this file happens as a result of websocket events everthing in this file happens as a result of websocket events
*/ */
import { JUNTO_UPDATED } from './events' import GlobalUI from '../../GlobalUI'
import GlobalUI, { ReactApp } from '../../GlobalUI'
import Util from '../../Util' import Util from '../../Util'
export const juntoUpdated = (self, map) => state => {
ReactApp.juntoState = state
$(document).trigger(JUNTO_UPDATED)
}
/* All the following events are received through the nodejs realtime server /* All the following events are received through the nodejs realtime server
and are done this way because they are transient data, not persisted to the server */ and are done this way because they are transient data, not persisted to the server */
export const topicDragged = (self, map) => positions => { export const topicDragged = (self, map) => positions => {

View file

@ -18,8 +18,8 @@ import {
DRAG_TOPIC DRAG_TOPIC
} from './events' } from './events'
export const joinMap = (self, map) => () => { export const joinMap = (socket, self, map) => () => {
self.socket.emit(JOIN_MAP, { socket.emit(JOIN_MAP, {
userid: map.Active.Mapper.id, userid: map.Active.Mapper.id,
username: map.Active.Mapper.get('name'), username: map.Active.Mapper.get('name'),
avatar: map.Active.Mapper.get('image'), avatar: map.Active.Mapper.get('image'),
@ -28,15 +28,15 @@ export const joinMap = (self, map) => () => {
}) })
} }
export const leaveMap = (self, map) => () => { export const leaveMap = (socket, self, map) => () => {
self.socket.emit(LEAVE_MAP) socket.emit(LEAVE_MAP)
} }
export const checkForCall = (self, map) => () => { export const checkForCall = (socket, self, map) => () => {
self.socket.emit(CHECK_FOR_CALL, { room: self.room.room, mapid: map.Active.Map.id }) socket.emit(CHECK_FOR_CALL, { room: self.room.room, mapid: map.Active.Map.id })
} }
export const sendMapperInfo = (self, map) => userid => { export const sendMapperInfo = (socket, self, map) => userid => {
// send this new mapper back your details, and the awareness that you've loaded the map // send this new mapper back your details, and the awareness that you've loaded the map
var update = { var update = {
userToNotify: userid, userToNotify: userid,
@ -46,10 +46,10 @@ export const sendMapperInfo = (self, map) => userid => {
userinconversation: self.inConversation, userinconversation: self.inConversation,
mapid: map.Active.Map.id mapid: map.Active.Map.id
} }
self.socket.emit(SEND_MAPPER_INFO, update) socket.emit(SEND_MAPPER_INFO, update)
} }
export const joinCall = (self, map) => () => { export const joinCall = (socket, self, map) => () => {
self.webrtc.off('readyToCall') self.webrtc.off('readyToCall')
self.webrtc.once('readyToCall', function() { self.webrtc.once('readyToCall', function() {
self.videoInitialized = true self.videoInitialized = true
@ -64,7 +64,7 @@ export const joinCall = (self, map) => () => {
map.ChatView.conversationInProgress(true) map.ChatView.conversationInProgress(true)
}) })
self.inConversation = true self.inConversation = true
self.socket.emit(JOIN_CALL, { socket.emit(JOIN_CALL, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
id: map.Active.Mapper.id id: map.Active.Mapper.id
}) })
@ -73,8 +73,8 @@ export const joinCall = (self, map) => () => {
map.ChatView.mapperJoinedCall(map.Active.Mapper.id) map.ChatView.mapperJoinedCall(map.Active.Mapper.id)
} }
export const leaveCall = (self, map) => () => { export const leaveCall = (socket, self, map) => () => {
self.socket.emit(LEAVE_CALL, { socket.emit(LEAVE_CALL, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
id: map.Active.Mapper.id id: map.Active.Mapper.id
}) })
@ -92,9 +92,9 @@ export const leaveCall = (self, map) => () => {
} }
} }
export const acceptCall = (self, map) => userid => { export const acceptCall = (socket, self, map) => userid => {
map.ChatView.sound.stop(self.soundId) map.ChatView.sound.stop(self.soundId)
self.socket.emit(ACCEPT_CALL, { socket.emit(ACCEPT_CALL, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
invited: map.Active.Mapper.id, invited: map.Active.Mapper.id,
inviter: userid inviter: userid
@ -104,9 +104,9 @@ export const acceptCall = (self, map) => userid => {
GlobalUI.clearNotify() GlobalUI.clearNotify()
} }
export const denyCall = (self, map) => userid => { export const denyCall = (socket, self, map) => userid => {
map.ChatView.sound.stop(self.soundId) map.ChatView.sound.stop(self.soundId)
self.socket.emit(DENY_CALL, { socket.emit(DENY_CALL, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
invited: map.Active.Mapper.id, invited: map.Active.Mapper.id,
inviter: userid inviter: userid
@ -114,9 +114,9 @@ export const denyCall = (self, map) => userid => {
GlobalUI.clearNotify() GlobalUI.clearNotify()
} }
export const denyInvite = (self, map) => userid => { export const denyInvite = (socket, self, map) => userid => {
map.ChatView.sound.stop(self.soundId) map.ChatView.sound.stop(self.soundId)
self.socket.emit(DENY_INVITE, { socket.emit(DENY_INVITE, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
invited: map.Active.Mapper.id, invited: map.Active.Mapper.id,
inviter: userid inviter: userid
@ -124,8 +124,8 @@ export const denyInvite = (self, map) => userid => {
GlobalUI.clearNotify() GlobalUI.clearNotify()
} }
export const inviteACall = (self, map) => userid => { export const inviteACall = (socket, self, map) => userid => {
self.socket.emit(INVITE_A_CALL, { socket.emit(INVITE_A_CALL, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
inviter: map.Active.Mapper.id, inviter: map.Active.Mapper.id,
invited: userid invited: userid
@ -134,8 +134,8 @@ export const inviteACall = (self, map) => userid => {
GlobalUI.clearNotify() GlobalUI.clearNotify()
} }
export const inviteToJoin = (self, map) => userid => { export const inviteToJoin = (socket, self, map) => userid => {
self.socket.emit(INVITE_TO_JOIN, { socket.emit(INVITE_TO_JOIN, {
mapid: map.Active.Map.id, mapid: map.Active.Map.id,
inviter: map.Active.Mapper.id, inviter: map.Active.Mapper.id,
invited: userid invited: userid
@ -143,22 +143,22 @@ export const inviteToJoin = (self, map) => userid => {
map.ChatView.invitationPending(userid) map.ChatView.invitationPending(userid)
} }
export const sendCoords = (self, map) => coords => { export const sendCoords = (socket, self, map) => coords => {
var map = map.Active.Map var m = map.Active.Map
var mapper = map.Active.Mapper var mapper = map.Active.Mapper
if (map && map.authorizeToEdit(mapper)) { if (m && m.authorizeToEdit(mapper)) {
var update = { var update = {
usercoords: coords, usercoords: coords,
userid: map.Active.Mapper.id, userid: map.Active.Mapper.id,
mapid: map.Active.Map.id mapid: m.id
} }
self.socket.emit(SEND_COORDS, update) socket.emit(SEND_COORDS, update)
} }
} }
export const dragTopic = (self, map) => positions => { export const dragTopic = (socket, self, map) => positions => {
if (map.Active.Map) { if (map.Active.Map) {
positions.mapid = map.Active.Map.id positions.mapid = map.Active.Map.id
self.socket.emit(DRAG_TOPIC, positions) socket.emit(DRAG_TOPIC, positions)
} }
} }

View file

@ -7,7 +7,6 @@ import VideoView from './VideoView'
const Room = function(opts = {}) { const Room = function(opts = {}) {
this.isActiveRoom = false this.isActiveRoom = false
this.socket = opts.socket
this.webrtc = opts.webrtc this.webrtc = opts.webrtc
this.room = opts.room this.room = opts.room
this.config = opts.config this.config = opts.config

View file

@ -2,13 +2,8 @@
import VideoView from './VideoView' import VideoView from './VideoView'
import Room from './Room' import Room from './Room'
import { JUNTO_UPDATED } from '../Realtime/events'
const Views = { const Views = {
init: (serverData) => {
$(document).on(JUNTO_UPDATED, () => ExploreMaps.render())
//map.ChatView.init([serverData['sounds/MM_sounds.mp3'], serverData['sounds/MM_sounds.ogg']])
},
VideoView, VideoView,
Room Room
} }

View file

@ -91,8 +91,8 @@ const mapControl = {
newMap.Active.Mapper = ReactApp.currentUser newMap.Active.Mapper = ReactApp.currentUser
newMap.DataModel.Mappers = new MapperCollection(data.mappers) newMap.DataModel.Mappers = new MapperCollection(data.mappers)
newMap.DataModel.Collaborators = new MapperCollection(data.collaborators) newMap.DataModel.Collaborators = new MapperCollection(data.collaborators)
newMap.DataModel.Topics = new TopicCollection(data.topics) //newMap.DataModel.Topics = new TopicCollection(data.topics)
newMap.DataModel.Synapses = new SynapseCollection(data.synapses) //newMap.DataModel.Synapses = new SynapseCollection(data.synapses)
newMap.DataModel.Mappings = new MappingCollection(data.mappings) newMap.DataModel.Mappings = new MappingCollection(data.mappings)
newMap.DataModel.Messages = data.messages newMap.DataModel.Messages = data.messages
newMap.DataModel.Stars = data.stars newMap.DataModel.Stars = data.stars
@ -127,15 +127,15 @@ const mapControl = {
end: function(map) { end: function(map) {
$('.main').removeClass('compressed') $('.main').removeClass('compressed')
$('.rightclickmenu').remove() $('.rightclickmenu').remove()
map.AutoLayout.resetSpiral() //map.AutoLayout.resetSpiral()
map.TopicCard.hideCard() //map.TopicCard.hideCard()
map.map.SynapseCard.hideCard() map.SynapseCard.hideCard()
map.Create.newTopic.hide(true) // true means force (and override pinned) map.Create.newTopic.hide(true) // true means force (and override pinned)
map.Create.newSynapse.hide() map.Create.newSynapse.hide()
map.InfoBox.close() map.InfoBox.close()
//map.Map.requests = []
//map.Map.hasLearnedTopicCreation = true
map.Realtime.endActiveMap() map.Realtime.endActiveMap()
map.Map.requests = []
map.Map.hasLearnedTopicCreation = true
} }
} }
export { mapControl } export { mapControl }
@ -442,6 +442,9 @@ const Map = (map) => {
Map.events = { Map.events = {
editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper' editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper'
} }
Map.init = (serverData) => {
ChatView.init([serverData['sounds/MM_sounds.mp3'], serverData['sounds/MM_sounds.ogg']])
}
export { CheatSheet } export { CheatSheet }
export default Map export default Map

View file

@ -58,7 +58,6 @@ Metamaps.Synapse = Synapse
Metamaps.SynapseCard = SynapseCard Metamaps.SynapseCard = SynapseCard
Metamaps.Topic = Topic Metamaps.Topic = Topic
Metamaps.Util = Util Metamaps.Util = Util
Metamaps.Views = Views
Metamaps.Visualize = Visualize Metamaps.Visualize = Visualize
Metamaps.GlobalUI = GlobalUI Metamaps.GlobalUI = GlobalUI
@ -76,7 +75,6 @@ document.addEventListener('DOMContentLoaded', function() {
Metamaps[prop].hasOwnProperty('init') && Metamaps[prop].hasOwnProperty('init') &&
typeof (Metamaps[prop].init) === 'function' typeof (Metamaps[prop].init) === 'function'
) { ) {
console.log(prop)
Metamaps[prop].init(Metamaps.ServerData) Metamaps[prop].init(Metamaps.ServerData)
} }
} }

View file

@ -59,7 +59,7 @@ class MapChat extends Component {
scroll = () => { scroll = () => {
// hack: figure out how to do this right // hack: figure out how to do this right
this.messagesDiv.scrollTop = this.messagesDiv.scrollHeight + 100 if (this.messagesDiv) this.messagesDiv.scrollTop = this.messagesDiv.scrollHeight + 100
} }
toggleDrawer = () => { toggleDrawer = () => {

View file

@ -7,7 +7,7 @@ const {
LEAVE_CALL, LEAVE_CALL,
JOIN_MAP, JOIN_MAP,
LEAVE_MAP LEAVE_MAP
} = require('../frontend/src/Metamaps/Realtime/events') } = require('../frontend/src/Metamaps/Map/Realtime/events')
module.exports = function(io, store) { module.exports = function(io, store) {
store.subscribe(() => { store.subscribe(() => {

View file

@ -17,7 +17,7 @@ const {
INVITE_A_CALL, INVITE_A_CALL,
JOIN_CALL, JOIN_CALL,
LEAVE_CALL LEAVE_CALL
} = require('../frontend/src/Metamaps/Realtime/events') } = require('../frontend/src/Metamaps/Map/Realtime/events')
const { mapRoom, userMapRoom } = require('./rooms') const { mapRoom, userMapRoom } = require('./rooms')

View file

@ -10,7 +10,7 @@ const {
SEND_COORDS, SEND_COORDS,
SEND_MAPPER_INFO, SEND_MAPPER_INFO,
DRAG_TOPIC DRAG_TOPIC
} = require('../frontend/src/Metamaps/Realtime/events') } = require('../frontend/src/Metamaps/Map/Realtime/events')
const { mapRoom, userMapRoom } = require('./rooms') const { mapRoom, userMapRoom } = require('./rooms')

View file

@ -4,7 +4,7 @@ const {
LEAVE_MAP, LEAVE_MAP,
JOIN_CALL, JOIN_CALL,
LEAVE_CALL LEAVE_CALL
} = require('../frontend/src/Metamaps/Realtime/events') } = require('../frontend/src/Metamaps/Map/Realtime/events')
const NOT_IN_CONVERSATION = 0 const NOT_IN_CONVERSATION = 0
const IN_CONVERSATION = 1 const IN_CONVERSATION = 1