trying to scope all the modules per map or topic

This commit is contained in:
Connor Turland 2017-03-22 19:20:10 -04:00
parent 663706b1f7
commit f07b97d573
29 changed files with 1366 additions and 1311 deletions

View file

@ -22,11 +22,16 @@
<div class="clearfloat"></div>
<script>
Metamaps.ServerData = Metamaps.ServerData || {}
Metamaps.ServerData.selectedMetacodes = []
Metamaps.ServerData.newSelectedMetacodes = []
Metamaps.ServerData.selectedMetacodeNames = []
Metamaps.ServerData.newSelectedMetacodeNames = []
<% @metacodes.each do |metacode| %>
Metamaps.Create.selectedMetacodes.push("<%= metacode.id %>");
Metamaps.Create.newSelectedMetacodes.push("<%= metacode.id %>");
Metamaps.Create.selectedMetacodeNames.push("<%= metacode.name %>");
Metamaps.Create.newSelectedMetacodeNames.push("<%= metacode.name %>");
Metamaps.ServerData.selectedMetacodes.push("<%= metacode.id %>");
Metamaps.ServerData.newSelectedMetacodes.push("<%= metacode.id %>");
Metamaps.ServerData.selectedMetacodeNames.push("<%= metacode.name %>");
Metamaps.ServerData.newSelectedMetacodeNames.push("<%= metacode.name %>");
<% end %>
</script>
<% end %>

View file

@ -116,6 +116,7 @@
<div class="clearfloat"></div>
<script>
Metamaps.Create.selectedMetacodeSet = "metacodeset-<%= selectedSet %>"
Metamaps.Create.selectedMetacodeSetIndex = <%= index %>
Metamaps.ServerData = Metamaps.ServerData || {}
Metamaps.ServerData.selectedMetacodeSet = "metacodeset-<%= selectedSet %>"
Metamaps.ServerData.selectedMetacodeSetIndex = <%= index %>
</script>

View file

@ -1,7 +1,9 @@
const Active = {
Map: null,
Mapper: null,
Topic: null
const Active = (map = null, mapper = null, topic = null) => {
return {
Map: map,
Mapper: mapper,
Topic: topic
}
}
export default Active

View file

@ -1,77 +1,79 @@
const AutoLayout = {
nextX: 0,
nextY: 0,
sideLength: 1,
turnCount: 0,
nextXshift: 1,
nextYshift: 0,
timeToTurn: 0,
const AutoLayout = () => {
return {
nextX: 0,
nextY: 0,
sideLength: 1,
turnCount: 0,
nextXshift: 1,
nextYshift: 0,
timeToTurn: 0,
getNextCoord: function(opts = {}) {
var self = AutoLayout
var nextX = self.nextX
var nextY = self.nextY
getNextCoord: function(opts = {}) {
var self = AutoLayout
var nextX = self.nextX
var nextY = self.nextY
var DISTANCE_BETWEEN = 120
var DISTANCE_BETWEEN = 120
self.nextX = self.nextX + DISTANCE_BETWEEN * self.nextXshift
self.nextY = self.nextY + DISTANCE_BETWEEN * self.nextYshift
self.nextX = self.nextX + DISTANCE_BETWEEN * self.nextXshift
self.nextY = self.nextY + DISTANCE_BETWEEN * self.nextYshift
self.timeToTurn += 1
// if true, it's time to turn
if (self.timeToTurn === self.sideLength) {
self.turnCount += 1
// if true, it's time to increase side length
if (self.turnCount % 2 === 0) {
self.sideLength += 1
self.timeToTurn += 1
// if true, it's time to turn
if (self.timeToTurn === self.sideLength) {
self.turnCount += 1
// if true, it's time to increase side length
if (self.turnCount % 2 === 0) {
self.sideLength += 1
}
self.timeToTurn = 0
// going right? turn down
if (self.nextXshift === 1 && self.nextYshift === 0) {
self.nextXshift = 0
self.nextYshift = 1
} else if (self.nextXshift === 0 && self.nextYshift === 1) {
// going down? turn left
self.nextXshift = -1
self.nextYshift = 0
} else if (self.nextXshift === -1 && self.nextYshift === 0) {
// going left? turn up
self.nextXshift = 0
self.nextYshift = -1
} else if (self.nextXshift === 0 && self.nextYshift === -1) {
// going up? turn right
self.nextXshift = 1
self.nextYshift = 0
}
}
if (opts.mappings && self.coordsTaken(nextX, nextY, opts.mappings)) {
// check if the coordinate is already taken on the current map
return self.getNextCoord(opts)
} else {
return {
x: nextX,
y: nextY
}
}
},
coordsTaken: function(x, y, mappings) {
if (mappings.findWhere({ xloc: x, yloc: y })) {
return true
} else {
return false
}
},
resetSpiral: function() {
var self = AutoLayout
self.nextX = 0
self.nextY = 0
self.nextXshift = 1
self.nextYshift = 0
self.sideLength = 1
self.timeToTurn = 0
// going right? turn down
if (self.nextXshift === 1 && self.nextYshift === 0) {
self.nextXshift = 0
self.nextYshift = 1
} else if (self.nextXshift === 0 && self.nextYshift === 1) {
// going down? turn left
self.nextXshift = -1
self.nextYshift = 0
} else if (self.nextXshift === -1 && self.nextYshift === 0) {
// going left? turn up
self.nextXshift = 0
self.nextYshift = -1
} else if (self.nextXshift === 0 && self.nextYshift === -1) {
// going up? turn right
self.nextXshift = 1
self.nextYshift = 0
}
self.turnCount = 0
}
if (opts.mappings && self.coordsTaken(nextX, nextY, opts.mappings)) {
// check if the coordinate is already taken on the current map
return self.getNextCoord(opts)
} else {
return {
x: nextX,
y: nextY
}
}
},
coordsTaken: function(x, y, mappings) {
if (mappings.findWhere({ xloc: x, yloc: y })) {
return true
} else {
return false
}
},
resetSpiral: function() {
var self = AutoLayout
self.nextX = 0
self.nextY = 0
self.nextXshift = 1
self.nextYshift = 0
self.sideLength = 1
self.timeToTurn = 0
self.turnCount = 0
}
}

View file

@ -2,24 +2,13 @@
import { indexOf } from 'lodash'
import Active from './Active'
import Control from './Control'
import DataModel from './DataModel'
import Map from './Map'
import Mapper from './Mapper'
import Synapse from './Synapse'
import Topic from './Topic'
import { ChatView } from './Views'
import Visualize from './Visualize'
const Cable = {
init: () => {
let self = Cable
self.cable = ActionCable.createConsumer()
},
const Cable = ({Active, Control, DataModel, Map, Synapse, Topic, ChatView, Visualize}) => {
const toExport = {
subscribeToMap: id => {
let self = Cable
self.sub = self.cable.subscriptions.create({
let self = toExport
self.sub = Cable.cable.subscriptions.create({
channel: 'MapChannel',
id: id
}, {
@ -27,7 +16,7 @@ const Cable = {
})
},
unsubscribeFromMap: () => {
let self = Cable
let self = toExport
self.sub.unsubscribe()
delete self.sub
},
@ -230,5 +219,10 @@ const Cable = {
})
}
}
return toExport
}
Cable.init = () => {
Cable.cable = ActionCable.createConsumer()
}
export default Cable

View file

@ -1,452 +1,448 @@
import _ from 'lodash'
import outdent from 'outdent'
import Active from './Active'
import DataModel from './DataModel'
import Filter from './Filter'
import GlobalUI from './GlobalUI'
import Mouse from './Mouse'
import Selected from './Selected'
import Settings from './Settings'
import Visualize from './Visualize'
const Control = {
selectNode: function(node, e) {
var filtered = node.getData('alpha') === 0
const Control = ({Active, DataModel, Filter, Mouse, Selected, Visualize}) => {
return {
selectNode: function(node, e) {
var filtered = node.getData('alpha') === 0
if (filtered || Selected.Nodes.indexOf(node) !== -1) return
node.selected = true
node.setData('dim', 30, 'current')
Selected.Nodes.push(node)
},
selectNeighbors: function() {
if (Selected.Nodes.length > 0) {
//For each selected node, select all connected node and the synapses too
Selected.Nodes.forEach((item) => {
if (Visualize.mGraph.graph.getNode(item.id).adjacencies) {
for (const adjID in Visualize.mGraph.graph.getNode(item.id).adjacencies) {
Control.selectNode(Visualize.mGraph.graph.getNode(adjID))
Control.selectEdge(Visualize.mGraph.graph.getNode(item.id).adjacencies[adjID])
if (filtered || Selected.Nodes.indexOf(node) !== -1) return
node.selected = true
node.setData('dim', 30, 'current')
Selected.Nodes.push(node)
},
selectNeighbors: function() {
if (Selected.Nodes.length > 0) {
//For each selected node, select all connected node and the synapses too
Selected.Nodes.forEach((item) => {
if (Visualize.mGraph.graph.getNode(item.id).adjacencies) {
for (const adjID in Visualize.mGraph.graph.getNode(item.id).adjacencies) {
Control.selectNode(Visualize.mGraph.graph.getNode(adjID))
Control.selectEdge(Visualize.mGraph.graph.getNode(item.id).adjacencies[adjID])
}
}
}
})
})
Visualize.mGraph.plot()
}
},
deselectAllNodes: function() {
var l = Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
var node = Selected.Nodes[i]
Control.deselectNode(node)
}
Visualize.mGraph.plot()
},
deselectNode: function(node) {
delete node.selected
node.setData('dim', 25, 'current')
// remove the node
Selected.Nodes.splice(
Selected.Nodes.indexOf(node), 1)
},
deleteSelected: function() {
if (!Active.Map) return
var n = Selected.Nodes.length
var e = Selected.Edges.length
var ntext = n === 1 ? '1 topic' : n + ' topics'
var etext = e === 1 ? '1 synapse' : e + ' synapses'
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var r = window.confirm(outdent`
You have ${ntext} and ${etext} selected. Are you sure you want
to permanently delete them all? This will remove them from all
maps they appear on.`)
if (r) {
Control.deleteSelectedEdges()
Control.deleteSelectedNodes()
}
if (DataModel.Topics.length === 0) {
Map.setHasLearnedTopicCreation(false)
}
},
deleteSelectedNodes: function() { // refers to deleting topics permanently
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var l = Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
var node = Selected.Nodes[i]
Control.deleteNode(node.id)
}
},
deleteNode: function(nodeid) { // refers to deleting topics permanently
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var node = Visualize.mGraph.graph.getNode(nodeid)
var topic = node.getData('topic')
var permToDelete = Active.Mapper.id === topic.get('user_id') || Active.Mapper.get('admin')
if (permToDelete) {
var mapping = node.getData('mapping')
topic.destroy()
DataModel.Mappings.remove(mapping)
Control.hideNode(nodeid)
} else {
GlobalUI.notifyUser('Only topics you created can be deleted')
}
},
removeSelectedNodes: function() { // refers to removing topics permanently from a map
if (Active.Topic) {
// hideNode will handle synapses as well
var nodeids = _.map(Selected.Nodes, function(node) {
return node.id
})
_.each(nodeids, function(nodeid) {
if (Active.Topic.id !== nodeid) {
DataModel.Topics.remove(nodeid)
Control.hideNode(nodeid)
}
})
return
}
if (!Active.Map) return
const l = Selected.Nodes.length
const authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
for (let i = l - 1; i >= 0; i -= 1) {
const node = Selected.Nodes[i]
Control.removeNode(node.id)
}
},
removeNode: function(nodeid) { // refers to removing topics permanently from a map
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
var node = Visualize.mGraph.graph.getNode(nodeid)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
var topic = node.getData('topic')
var mapping = node.getData('mapping')
mapping.destroy()
DataModel.Topics.remove(topic)
Control.hideNode(nodeid)
},
hideSelectedNodes: function() {
const l = Selected.Nodes.length
for (let i = l - 1; i >= 0; i -= 1) {
const node = Selected.Nodes[i]
Control.hideNode(node.id)
}
},
hideNode: function(nodeid) {
var node = Visualize.mGraph.graph.getNode(nodeid)
var graph = Visualize.mGraph
Control.deselectNode(node)
node.setData('alpha', 0, 'end')
node.eachAdjacency(function(adj) {
adj.setData('alpha', 0, 'end')
})
Visualize.mGraph.fx.animate({
modes: ['node-property:alpha',
'edge-property:alpha'
],
duration: 500
})
setTimeout(function() {
if (nodeid === Visualize.mGraph.root) { // && Visualize.type === "RGraph"
var newroot = _.find(graph.graph.nodes, function(n) { return n.id !== nodeid })
graph.root = newroot ? newroot.id : null
Visualize.mGraph.plot()
}
Visualize.mGraph.graph.removeNode(nodeid)
}, 500)
Filter.checkMetacodes()
Filter.checkMappers()
},
selectEdge: function(edge) {
var filtered = edge.getData('alpha') === 0 // don't select if the edge is filtered
},
deselectAllNodes: function() {
var l = Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
var node = Selected.Nodes[i]
Control.deselectNode(node)
}
Visualize.mGraph.plot()
},
deselectNode: function(node) {
delete node.selected
node.setData('dim', 25, 'current')
if (filtered || Selected.Edges.indexOf(edge) !== -1) return
// remove the node
Selected.Nodes.splice(
Selected.Nodes.indexOf(node), 1)
},
deleteSelected: function() {
if (!Active.Map) return
var width = Mouse.edgeHoveringOver === edge ? 4 : 2
edge.setDataset('current', {
showDesc: true,
lineWidth: width,
color: Settings.colors.synapses.selected
})
Visualize.mGraph.plot()
var n = Selected.Nodes.length
var e = Selected.Edges.length
var ntext = n === 1 ? '1 topic' : n + ' topics'
var etext = e === 1 ? '1 synapse' : e + ' synapses'
Selected.Edges.push(edge)
},
deselectAllEdges: function() {
var l = Selected.Edges.length
for (var i = l - 1; i >= 0; i -= 1) {
var edge = Selected.Edges[i]
Control.deselectEdge(edge)
}
Visualize.mGraph.plot()
},
deselectEdge: function(edge) {
edge.setData('showDesc', false, 'current')
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
edge.setDataset('current', {
lineWidth: 2,
color: Settings.colors.synapses.normal
})
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
if (Mouse.edgeHoveringOver === edge) {
var r = window.confirm(outdent`
You have ${ntext} and ${etext} selected. Are you sure you want
to permanently delete them all? This will remove them from all
maps they appear on.`)
if (r) {
Control.deleteSelectedEdges()
Control.deleteSelectedNodes()
}
if (DataModel.Topics.length === 0) {
Map.setHasLearnedTopicCreation(false)
}
},
deleteSelectedNodes: function() { // refers to deleting topics permanently
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var l = Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
var node = Selected.Nodes[i]
Control.deleteNode(node.id)
}
},
deleteNode: function(nodeid) { // refers to deleting topics permanently
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var node = Visualize.mGraph.graph.getNode(nodeid)
var topic = node.getData('topic')
var permToDelete = Active.Mapper.id === topic.get('user_id') || Active.Mapper.get('admin')
if (permToDelete) {
var mapping = node.getData('mapping')
topic.destroy()
DataModel.Mappings.remove(mapping)
Control.hideNode(nodeid)
} else {
GlobalUI.notifyUser('Only topics you created can be deleted')
}
},
removeSelectedNodes: function() { // refers to removing topics permanently from a map
if (Active.Topic) {
// hideNode will handle synapses as well
var nodeids = _.map(Selected.Nodes, function(node) {
return node.id
})
_.each(nodeids, function(nodeid) {
if (Active.Topic.id !== nodeid) {
DataModel.Topics.remove(nodeid)
Control.hideNode(nodeid)
}
})
return
}
if (!Active.Map) return
const l = Selected.Nodes.length
const authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
for (let i = l - 1; i >= 0; i -= 1) {
const node = Selected.Nodes[i]
Control.removeNode(node.id)
}
},
removeNode: function(nodeid) { // refers to removing topics permanently from a map
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
var node = Visualize.mGraph.graph.getNode(nodeid)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
var topic = node.getData('topic')
var mapping = node.getData('mapping')
mapping.destroy()
DataModel.Topics.remove(topic)
Control.hideNode(nodeid)
},
hideSelectedNodes: function() {
const l = Selected.Nodes.length
for (let i = l - 1; i >= 0; i -= 1) {
const node = Selected.Nodes[i]
Control.hideNode(node.id)
}
},
hideNode: function(nodeid) {
var node = Visualize.mGraph.graph.getNode(nodeid)
var graph = Visualize.mGraph
Control.deselectNode(node)
node.setData('alpha', 0, 'end')
node.eachAdjacency(function(adj) {
adj.setData('alpha', 0, 'end')
})
Visualize.mGraph.fx.animate({
modes: ['node-property:alpha',
'edge-property:alpha'
],
duration: 500
})
setTimeout(function() {
if (nodeid === Visualize.mGraph.root) { // && Visualize.type === "RGraph"
var newroot = _.find(graph.graph.nodes, function(n) { return n.id !== nodeid })
graph.root = newroot ? newroot.id : null
}
Visualize.mGraph.graph.removeNode(nodeid)
}, 500)
Filter.checkMetacodes()
Filter.checkMappers()
},
selectEdge: function(edge) {
var filtered = edge.getData('alpha') === 0 // don't select if the edge is filtered
if (filtered || Selected.Edges.indexOf(edge) !== -1) return
var width = Mouse.edgeHoveringOver === edge ? 4 : 2
edge.setDataset('current', {
showDesc: true,
lineWidth: 4
lineWidth: width,
color: Settings.colors.synapses.selected
})
}
Visualize.mGraph.plot()
Visualize.mGraph.plot()
Selected.Edges.push(edge)
},
deselectAllEdges: function() {
var l = Selected.Edges.length
for (var i = l - 1; i >= 0; i -= 1) {
var edge = Selected.Edges[i]
Control.deselectEdge(edge)
}
Visualize.mGraph.plot()
},
deselectEdge: function(edge) {
edge.setData('showDesc', false, 'current')
// remove the edge
Selected.Edges.splice(
Selected.Edges.indexOf(edge), 1)
},
deleteSelectedEdges: function() { // refers to deleting topics permanently
if (!Active.Map) return
edge.setDataset('current', {
lineWidth: 2,
color: Settings.colors.synapses.normal
})
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (Mouse.edgeHoveringOver === edge) {
edge.setDataset('current', {
showDesc: true,
lineWidth: 4
})
}
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
Visualize.mGraph.plot()
const l = Selected.Edges.length
for (let i = l - 1; i >= 0; i -= 1) {
const edge = Selected.Edges[i]
Control.deleteEdge(edge)
}
},
deleteEdge: function(edge) {
if (!Active.Map) return
// remove the edge
Selected.Edges.splice(
Selected.Edges.indexOf(edge), 1)
},
deleteSelectedEdges: function() { // refers to deleting topics permanently
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
const l = Selected.Edges.length
for (let i = l - 1; i >= 0; i -= 1) {
const edge = Selected.Edges[i]
Control.deleteEdge(edge)
}
},
deleteEdge: function(edge) {
if (!Active.Map) return
var synapse = edge.getData('synapses')[index]
var mapping = edge.getData('mappings')[index]
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
var permToDelete = Active.Mapper.id === synapse.get('user_id') || Active.Mapper.get('admin')
if (permToDelete) {
if (edge.getData('synapses').length - 1 === 0) {
if (!authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
var synapse = edge.getData('synapses')[index]
var mapping = edge.getData('mappings')[index]
var permToDelete = Active.Mapper.id === synapse.get('user_id') || Active.Mapper.get('admin')
if (permToDelete) {
if (edge.getData('synapses').length - 1 === 0) {
Control.hideEdge(edge)
}
synapse.destroy()
// the server will destroy the mapping, we just need to remove it here
DataModel.Mappings.remove(mapping)
edge.getData('mappings').splice(index, 1)
edge.getData('synapses').splice(index, 1)
if (edge.getData('displayIndex')) {
delete edge.data.$displayIndex
}
} else {
GlobalUI.notifyUser('Only synapses you created can be deleted')
}
},
removeSelectedEdges: function() {
// Topic view is handled by removeSelectedNodes
if (!Active.Map) return
const l = Selected.Edges.length
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
for (let i = l - 1; i >= 0; i -= 1) {
const edge = Selected.Edges[i]
Control.removeEdge(edge)
}
Selected.Edges = [ ]
},
removeEdge: function(edge) {
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
if (edge.getData('mappings').length - 1 === 0) {
Control.hideEdge(edge)
}
synapse.destroy()
// the server will destroy the mapping, we just need to remove it here
DataModel.Mappings.remove(mapping)
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
var synapse = edge.getData('synapses')[index]
var mapping = edge.getData('mappings')[index]
mapping.destroy()
DataModel.Synapses.remove(synapse)
edge.getData('mappings').splice(index, 1)
edge.getData('synapses').splice(index, 1)
if (edge.getData('displayIndex')) {
delete edge.data.$displayIndex
}
} else {
GlobalUI.notifyUser('Only synapses you created can be deleted')
}
},
removeSelectedEdges: function() {
// Topic view is handled by removeSelectedNodes
if (!Active.Map) return
const l = Selected.Edges.length
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
for (let i = l - 1; i >= 0; i -= 1) {
const edge = Selected.Edges[i]
Control.removeEdge(edge)
}
Selected.Edges = [ ]
},
removeEdge: function(edge) {
if (!Active.Map) return
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
if (!authorized) {
GlobalUI.notifyUser('Cannot edit this map.')
return
}
if (Active.Mapper.get('follow_map_on_contributed')) {
Active.Mapper.followMap(Active.Map.id)
}
if (edge.getData('mappings').length - 1 === 0) {
Control.hideEdge(edge)
}
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
var synapse = edge.getData('synapses')[index]
var mapping = edge.getData('mappings')[index]
mapping.destroy()
DataModel.Synapses.remove(synapse)
edge.getData('mappings').splice(index, 1)
edge.getData('synapses').splice(index, 1)
if (edge.getData('displayIndex')) {
delete edge.data.$displayIndex
}
},
hideSelectedEdges: function() {
const l = Selected.Edges.length
for (let i = l - 1; i >= 0; i -= 1) {
const edge = Selected.Edges[i]
Control.hideEdge(edge)
}
Selected.Edges = [ ]
},
hideEdge: function(edge) {
var from = edge.nodeFrom.id
var to = edge.nodeTo.id
edge.setData('alpha', 0, 'end')
Control.deselectEdge(edge)
Visualize.mGraph.fx.animate({
modes: ['edge-property:alpha'],
duration: 500
})
setTimeout(function() {
Visualize.mGraph.graph.removeAdjacence(from, to)
}, 500)
Filter.checkSynapses()
Filter.checkMappers()
},
updateSelectedPermissions: function(permission) {
var edge, synapse, node, topic
GlobalUI.notifyUser('Working...')
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0
var sCount = 0
// change the permission of the selected synapses, if logged in user is the original creator
const edgesLength = Selected.Edges.length
for (let i = edgesLength - 1; i >= 0; i -= 1) {
edge = Selected.Edges[i]
synapse = edge.getData('synapses')[0]
if (synapse.authorizePermissionChange(Active.Mapper)) {
synapse.save({
permission: permission
})
sCount++
},
hideSelectedEdges: function() {
const l = Selected.Edges.length
for (let i = l - 1; i >= 0; i -= 1) {
const edge = Selected.Edges[i]
Control.hideEdge(edge)
}
}
Selected.Edges = [ ]
},
hideEdge: function(edge) {
var from = edge.nodeFrom.id
var to = edge.nodeTo.id
edge.setData('alpha', 0, 'end')
Control.deselectEdge(edge)
Visualize.mGraph.fx.animate({
modes: ['edge-property:alpha'],
duration: 500
})
setTimeout(function() {
Visualize.mGraph.graph.removeAdjacence(from, to)
}, 500)
Filter.checkSynapses()
Filter.checkMappers()
},
updateSelectedPermissions: function(permission) {
var edge, synapse, node, topic
// change the permission of the selected topics, if logged in user is the original creator
const nodesLength = Selected.Nodes.length
for (let i = nodesLength - 1; i >= 0; i -= 1) {
node = Selected.Nodes[i]
topic = node.getData('topic')
GlobalUI.notifyUser('Working...')
if (topic.authorizePermissionChange(Active.Mapper)) {
topic.save({
permission: permission
})
nCount++
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0
var sCount = 0
// change the permission of the selected synapses, if logged in user is the original creator
const edgesLength = Selected.Edges.length
for (let i = edgesLength - 1; i >= 0; i -= 1) {
edge = Selected.Edges[i]
synapse = edge.getData('synapses')[0]
if (synapse.authorizePermissionChange(Active.Mapper)) {
synapse.save({
permission: permission
})
sCount++
}
}
}
var nString = nCount === 1 ? (nCount.toString() + ' topic and ') : (nCount.toString() + ' topics and ')
var sString = sCount === 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses')
// change the permission of the selected topics, if logged in user is the original creator
const nodesLength = Selected.Nodes.length
for (let i = nodesLength - 1; i >= 0; i -= 1) {
node = Selected.Nodes[i]
topic = node.getData('topic')
var message = nString + sString + ' you created updated to ' + permission
GlobalUI.notifyUser(message)
},
updateSelectedMetacodes: function(metacodeId) {
var node, topic
GlobalUI.notifyUser('Working...')
var metacode = DataModel.Metacodes.get(metacodeId)
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0
// change the permission of the selected topics, if logged in user is the original creator
var l = Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
node = Selected.Nodes[i]
topic = node.getData('topic')
if (topic.authorizeToEdit(Active.Mapper)) {
topic.save({
'metacode_id': metacodeId
})
nCount++
if (topic.authorizePermissionChange(Active.Mapper)) {
topic.save({
permission: permission
})
nCount++
}
}
var nString = nCount === 1 ? (nCount.toString() + ' topic and ') : (nCount.toString() + ' topics and ')
var sString = sCount === 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses')
var message = nString + sString + ' you created updated to ' + permission
GlobalUI.notifyUser(message)
},
updateSelectedMetacodes: function(metacodeId) {
var node, topic
GlobalUI.notifyUser('Working...')
var metacode = DataModel.Metacodes.get(metacodeId)
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0
// change the permission of the selected topics, if logged in user is the original creator
var l = Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
node = Selected.Nodes[i]
topic = node.getData('topic')
if (topic.authorizeToEdit(Active.Mapper)) {
topic.save({
'metacode_id': metacodeId
})
nCount++
}
}
var nString = nCount === 1 ? (nCount.toString() + ' topic') : (nCount.toString() + ' topics')
var message = nString + ' you can edit updated to ' + metacode.get('name')
GlobalUI.notifyUser(message)
Visualize.mGraph.plot()
}
var nString = nCount === 1 ? (nCount.toString() + ' topic') : (nCount.toString() + ' topics')
var message = nString + ' you can edit updated to ' + metacode.get('name')
GlobalUI.notifyUser(message)
Visualize.mGraph.plot()
}
}

View file

@ -1,15 +1,9 @@
/* global $, Hogan, Bloodhound */
import DataModel from './DataModel'
import Map from './Map'
import Mouse from './Mouse'
import Selected from './Selected'
import Synapse from './Synapse'
import Topic from './Topic'
import Visualize from './Visualize'
import GlobalUI from './GlobalUI'
const Create = {
const toExport = ({DataModel, Map, Mouse, Selected, Synapse, Topic, Visualize}) => {
const toExport = {
isSwitchingSet: false, // indicates whether the metacode set switch lightbox is open
selectedMetacodeSet: null,
selectedMetacodeSetIndex: null,
@ -17,52 +11,54 @@ const Create = {
newSelectedMetacodeNames: [],
selectedMetacodes: [],
newSelectedMetacodes: [],
init: function() {
var self = Create
self.newTopic.init()
self.newSynapse.init()
init: function(serverData) {
toExport.newTopic.init()
toExport.newSynapse.init()
toExport.selectedMetacodeSet = serverData.selectedMetacodeSet
toExport.selectedMetacodeSetIndex = serverData.selectedMetacodeSetIndex
toExport.selectedMetacodes = serverData.selectedMetacodes
toExport.newSelectedMetacodes = serverData.newSelectedMetacodes
toExport.selectedMetacodeNames = serverData.newSelectedMetacodeNames
toExport.newSelectedMetacodeNames = serverData.newSelectedMetacodeNames
// // SWITCHING METACODE SETS
$('#metacodeSwitchTabs').tabs({
active: self.selectedMetacodeSetIndex
active: toExport.selectedMetacodeSetIndex
}).addClass('ui-tabs-vertical ui-helper-clearfix')
$('#metacodeSwitchTabs .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left')
$('.customMetacodeList li').click(self.toggleMetacodeSelected) // within the custom metacode set tab
$('.selectAll').click(self.metacodeSelectorSelectAll)
$('.selectNone').click(self.metacodeSelectorSelectNone)
$('.customMetacodeList li').click(toExport.toggleMetacodeSelected) // within the custom metacode set tab
$('.selectAll').click(toExport.metacodeSelectorSelectAll)
$('.selectNone').click(toExport.metacodeSelectorSelectNone)
},
toggleMetacodeSelected: function() {
var self = Create
if ($(this).attr('class') !== 'toggledOff') {
$(this).addClass('toggledOff')
var valueToRemove = $(this).attr('id')
var nameToRemove = $(this).attr('data-name')
self.newSelectedMetacodes.splice(self.newSelectedMetacodes.indexOf(valueToRemove), 1)
self.newSelectedMetacodeNames.splice(self.newSelectedMetacodeNames.indexOf(nameToRemove), 1)
toExport.newSelectedMetacodes.splice(self.newSelectedMetacodes.indexOf(valueToRemove), 1)
toExport.newSelectedMetacodeNames.splice(self.newSelectedMetacodeNames.indexOf(nameToRemove), 1)
} else if ($(this).attr('class') === 'toggledOff') {
$(this).removeClass('toggledOff')
self.newSelectedMetacodes.push($(this).attr('id'))
self.newSelectedMetacodeNames.push($(this).attr('data-name'))
toExport.newSelectedMetacodes.push($(this).attr('id'))
toExport.newSelectedMetacodeNames.push($(this).attr('data-name'))
}
self.updateSelectAllColors()
toExport.updateSelectAllColors()
},
updateSelectAllColors: function() {
$('.selectAll, .selectNone').removeClass('selected')
if (Create.metacodeSelectorAreAllSelected()) {
if (toExport.metacodeSelectorAreAllSelected()) {
$('.selectAll').addClass('selected')
} else if (Create.metacodeSelectorAreNoneSelected()) {
} else if (toExport.metacodeSelectorAreNoneSelected()) {
$('.selectNone').addClass('selected')
}
},
metacodeSelectorSelectAll: function() {
$('.customMetacodeList li.toggledOff').each(Create.toggleMetacodeSelected)
Create.updateSelectAllColors()
$('.customMetacodeList li.toggledOff').each(toExport.toggleMetacodeSelected)
toExport.updateSelectAllColors()
},
metacodeSelectorSelectNone: function() {
$('.customMetacodeList li').not('.toggledOff').each(Create.toggleMetacodeSelected)
Create.updateSelectAllColors()
$('.customMetacodeList li').not('.toggledOff').each(toExport.toggleMetacodeSelected)
toExport.updateSelectAllColors()
},
metacodeSelectorAreAllSelected: function() {
return $('.customMetacodeList li').toArray()
@ -75,41 +71,41 @@ const Create = {
.reduce((curr, prev) => curr && prev)
},
metacodeSelectorToggleSelectAll: function() {
// should be called when Create.isSwitchingSet is true and .customMetacodeList is visible
if (!Create.isSwitchingSet) return
// should be called when toExport.isSwitchingSet is true and .customMetacodeList is visible
if (!toExport.isSwitchingSet) return
if (!$('.customMetacodeList').is(':visible')) return
// If all are selected, then select none. Otherwise, select all.
if (Create.metacodeSelectorAreAllSelected()) {
Create.metacodeSelectorSelectNone()
if (toExport.metacodeSelectorAreAllSelected()) {
toExport.metacodeSelectorSelectNone()
} else {
// if some, but not all, are selected, it still runs this function
Create.metacodeSelectorSelectAll()
toExport.metacodeSelectorSelectAll()
}
},
updateMetacodeSet: function(set, index, custom) {
if (custom && Create.newSelectedMetacodes.length === 0) {
if (custom && toExport.newSelectedMetacodes.length === 0) {
window.alert('Please select at least one metacode to use!')
return false
}
var codesToSwitchToIds
var metacodeModels = new DataModel.MetacodeCollection()
Create.selectedMetacodeSetIndex = index
Create.selectedMetacodeSet = 'metacodeset-' + set
toExport.selectedMetacodeSetIndex = index
toExport.selectedMetacodeSet = 'metacodeset-' + set
if (!custom) {
codesToSwitchToIds = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',')
$('.customMetacodeList li').addClass('toggledOff')
Create.selectedMetacodes = []
Create.selectedMetacodeNames = []
Create.newSelectedMetacodes = []
Create.newSelectedMetacodeNames = []
toExport.selectedMetacodes = []
toExport.selectedMetacodeNames = []
toExport.newSelectedMetacodes = []
toExport.newSelectedMetacodeNames = []
} else if (custom) {
// uses .slice to avoid setting the two arrays to the same actual array
Create.selectedMetacodes = Create.newSelectedMetacodes.slice(0)
Create.selectedMetacodeNames = Create.newSelectedMetacodeNames.slice(0)
codesToSwitchToIds = Create.selectedMetacodes.slice(0)
toExport.selectedMetacodes = Create.newSelectedMetacodes.slice(0)
toExport.selectedMetacodeNames = Create.newSelectedMetacodeNames.slice(0)
codesToSwitchToIds = toExport.selectedMetacodes.slice(0)
}
// sort by name
@ -141,7 +137,7 @@ const Create = {
var mdata = {
'metacodes': {
'value': custom ? Create.selectedMetacodes.toString() : Create.selectedMetacodeSet
'value': custom ? toExport.selectedMetacodes.toString() : Create.selectedMetacodeSet
}
}
$.ajax({
@ -158,26 +154,25 @@ const Create = {
})
},
cancelMetacodeSetSwitch: function() {
var self = Create
self.isSwitchingSet = false
toExport.isSwitchingSet = false
if (self.selectedMetacodeSet !== 'metacodeset-custom') {
if (toExport.selectedMetacodeSet !== 'metacodeset-custom') {
$('.customMetacodeList li').addClass('toggledOff')
self.selectedMetacodes = []
self.selectedMetacodeNames = []
self.newSelectedMetacodes = []
self.newSelectedMetacodeNames = []
toExport.selectedMetacodes = []
toExport.selectedMetacodeNames = []
toExport.newSelectedMetacodes = []
toExport.newSelectedMetacodeNames = []
} else { // custom set is selected
// reset it to the current actual selection
$('.customMetacodeList li').addClass('toggledOff')
for (var i = 0; i < self.selectedMetacodes.length; i++) {
$('#' + self.selectedMetacodes[i]).removeClass('toggledOff')
for (var i = 0; i < toExport.selectedMetacodes.length; i++) {
$('#' + toExport.selectedMetacodes[i]).removeClass('toggledOff')
}
// uses .slice to avoid setting the two arrays to the same actual array
self.newSelectedMetacodeNames = self.selectedMetacodeNames.slice(0)
self.newSelectedMetacodes = self.selectedMetacodes.slice(0)
toExport.newSelectedMetacodeNames = self.selectedMetacodeNames.slice(0)
toExport.newSelectedMetacodes = self.selectedMetacodes.slice(0)
}
$('#metacodeSwitchTabs').tabs('option', 'active', self.selectedMetacodeSetIndex)
$('#metacodeSwitchTabs').tabs('option', 'active', toExport.selectedMetacodeSetIndex)
$('#topic_name').focus()
},
newTopic: {
@ -186,19 +181,19 @@ const Create = {
const ESC = 27
if (e.keyCode === ESC) {
Create.newTopic.hide()
toExport.newTopic.hide()
} // if
Create.newTopic.name = $(this).val()
toExport.newTopic.name = $(this).val()
})
$('.pinCarousel').click(function() {
if (Create.newTopic.pinned) {
if (toExport.newTopic.pinned) {
$('.pinCarousel').removeClass('isPinned')
Create.newTopic.pinned = false
toExport.newTopic.pinned = false
} else {
$('.pinCarousel').addClass('isPinned')
Create.newTopic.pinned = true
toExport.newTopic.pinned = true
}
})
@ -232,7 +227,7 @@ const Create = {
// tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete
$('#topic_name').bind('typeahead:select', function(event, datum, dataset) {
Create.newTopic.beingCreated = false
toExport.newTopic.beingCreated = false
if (datum.rtype === 'topic') {
Topic.getTopicFromAutocomplete(datum.id)
} else if (datum.rtype === 'map') {
@ -259,7 +254,7 @@ const Create = {
},
name: null,
newId: 1,
beingCreated: false,
beingtoExportd: false,
metacode: null,
x: null,
y: null,
@ -269,22 +264,22 @@ const Create = {
$('#new_topic').fadeIn('fast', function() {
$('#topic_name').focus()
})
Create.newTopic.beingCreated = true
Create.newTopic.name = ''
Map.setHasLearnedTopicCreation(true)
toExport.newTopic.beingCreated = true
toExport.newTopic.name = ''
//Map.setHasLearnedTopicCreation(true)
},
hide: function(force) {
if (force || !Create.newTopic.pinned) {
if (force || !toExport.newTopic.pinned) {
$('#new_topic').fadeOut('fast')
}
if (force) {
$('.pinCarousel').removeClass('isPinned')
Create.newTopic.pinned = false
toExport.newTopic.pinned = false
}
if (DataModel.Topics.length === 0) {
Map.setHasLearnedTopicCreation(false)
}
Create.newTopic.beingCreated = false
toExport.newTopic.beingCreated = false
},
reset: function() {
$('#topic_name').typeahead('val', '')
@ -306,9 +301,8 @@ const Create = {
remote: {
url: '/search/synapses?topic1id=%TOPIC1&topic2id=%TOPIC2',
prepare: function(query, settings) {
var self = Create.newSynapse
if (Selected.Nodes.length < 2 && self.topic1id && self.topic2id) {
settings.url = settings.url.replace('%TOPIC1', self.topic1id).replace('%TOPIC2', self.topic2id)
if (Selected.Nodes.length < 2 && toExport.newSynapse.topic1id && self.newSynapse.topic2id) {
settings.url = settings.url.replace('%TOPIC1', toExport.newSynapse.topic1id).replace('%TOPIC2', toExport.newSynapse.topic2id)
return settings
} else {
return null
@ -351,21 +345,21 @@ const Create = {
const ESC = 27
if (e.keyCode === ESC) {
Create.newSynapse.hide()
toExport.newSynapse.hide()
} // if
Create.newSynapse.description = $(this).val()
toExport.newSynapse.description = $(this).val()
})
$('#synapse_desc').focusout(function() {
if (Create.newSynapse.beingCreated) {
if (toExport.newSynapse.beingCreated) {
Synapse.createSynapseLocally()
}
})
$('#synapse_desc').keydown(function(e) {
const TAB = 9
if (Create.newSynapse.beingCreated && e.keyCode === TAB) {
if (toExport.newSynapse.beingCreated && e.keyCode === TAB) {
e.preventDefault()
Synapse.createSynapseLocally()
}
@ -375,12 +369,12 @@ const Create = {
if (datum.id) { // if they clicked on an existing synapse get it
Synapse.getSynapseFromAutocomplete(datum.id)
} else {
Create.newSynapse.description = datum.value
toExport.newSynapse.description = datum.value
Synapse.createSynapseLocally()
}
})
},
beingCreated: false,
beingtoExportd: false,
description: null,
topic1id: null,
topic2id: null,
@ -389,19 +383,21 @@ const Create = {
$('#new_synapse').fadeIn(100, function() {
$('#synapse_desc').focus()
})
Create.newSynapse.beingCreated = true
toExport.newSynapse.beingCreated = true
},
hide: function() {
$('#new_synapse').fadeOut('fast')
$('#synapse_desc').typeahead('val', '')
Create.newSynapse.beingCreated = false
Create.newTopic.addSynapse = false
Create.newSynapse.topic1id = 0
Create.newSynapse.topic2id = 0
toExport.newSynapse.beingCreated = false
toExport.newTopic.addSynapse = false
toExport.newSynapse.topic1id = 0
toExport.newSynapse.topic2id = 0
Mouse.synapseStartCoordinates = []
if (Visualize.mGraph) Visualize.mGraph.plot()
}
}
}
return toExport
}
export default Create
export default toExport

View file

@ -1,7 +1,3 @@
import Active from '../Active'
import Filter from '../Filter'
import { InfoBox } from '../Map'
import Map from './Map'
import MapCollection from './MapCollection'
import Message from './Message'
@ -17,57 +13,20 @@ import SynapseCollection from './SynapseCollection'
import Mapping from './Mapping'
import MappingCollection from './MappingCollection'
const DataModel = {
Map: Map,
MapCollection: MapCollection,
Message: Message,
MessageCollection: MessageCollection,
Mapper: Mapper,
MapperCollection: MapperCollection,
Metacode: Metacode,
MetacodeCollection: MetacodeCollection,
Topic: Topic,
TopicCollection: TopicCollection,
Synapse: Synapse,
SynapseCollection: SynapseCollection,
Mapping: Mapping,
MappingCollection: MappingCollection,
const DataModel = ({Filter, InfoBox}) => {
const toExport = {
Collaborators: new MapperCollection(),
Creators: new MapperCollection(),
Mappers: new MapperCollection(),
Mappings: new MappingCollection(),
Maps: {
Mine: [],
Shared: [],
Starred: [],
Mapper: {
models: [],
mapperId: null
},
Featured: [],
Active: []
},
Messages: [],
Metacodes: new MetacodeCollection(),
Stars: [],
Synapses: new SynapseCollection(),
Topics: new TopicCollection(),
init: function(serverData) {
var self = DataModel
// workaround circular import problem
if (!self.MapCollection.model) self.MapCollection.model = Map
self.synapseIconUrl = serverData['synapse16.png']
if (serverData.ActiveMap) Active.Map = new Map(serverData.ActiveMap)
if (serverData.ActiveMapper) Active.Mapper = new Mapper(serverData.ActiveMapper)
if (serverData.ActiveTopic) Active.Topic = new Topic(serverData.ActiveTopic)
setMap: function(serverData) {
var self = toExport
if (serverData.Collaborators) self.Collaborators = new MapperCollection(serverData.Collaborators)
if (serverData.Creators) self.Creators = new MapperCollection(serverData.Creators)
if (serverData.Mappers) self.Mappers = new MapperCollection(serverData.Mappers)
if (serverData.Mappings) self.Mappings = new MappingCollection(serverData.Mappings)
if (serverData.Messages) self.Messages = serverData.Messages
@ -75,42 +34,28 @@ const DataModel = {
if (serverData.Stars) self.Stars = serverData.Stars
if (serverData.Synapses) self.Synapses = new SynapseCollection(serverData.Synapses)
if (serverData.Topics) self.Topics = new TopicCollection(serverData.Topics)
// initialize global backbone models and collections
var myCollection = serverData.Mine ? serverData.Mine : []
var sharedCollection = serverData.Shared ? serverData.Shared : []
var starredCollection = serverData.Starred ? serverData.Starred : []
var mapperCollection = serverData.Mapper ? serverData.Mapper : []
var mapperOptionsObj = { id: 'mapper', sortBy: 'updated_at' }
if (serverData.Mapper && serverData.Mapper.mapperId) {
mapperCollection = serverData.Mapper.models
mapperOptionsObj.mapperId = serverData.Mapper.mapperId
}
var featuredCollection = serverData.Featured ? serverData.Featured : []
var activeCollection = serverData.Active ? serverData.Active : []
self.Maps.Mine = new MapCollection(myCollection, { id: 'mine', sortBy: 'updated_at' })
self.Maps.Shared = new MapCollection(sharedCollection, { id: 'shared', sortBy: 'updated_at' })
self.Maps.Starred = new MapCollection(starredCollection, { id: 'starred', sortBy: 'updated_at' })
// 'Mapper' refers to another mapper
self.Maps.Mapper = new MapCollection(mapperCollection, mapperOptionsObj)
self.Maps.Featured = new MapCollection(featuredCollection, { id: 'featured', sortBy: 'updated_at' })
self.Maps.Active = new MapCollection(activeCollection, { id: 'active', sortBy: 'updated_at' })
self.attachCollectionEvents()
},
setTopic: function(serverData) {
var self = toExport
if (serverData.Creators) self.Creators = new MapperCollection(serverData.Creators)
if (serverData.Metacodes) self.Metacodes = new MetacodeCollection(serverData.Metacodes)
if (serverData.Synapses) self.Synapses = new SynapseCollection(serverData.Synapses)
if (serverData.Topics) self.Topics = new TopicCollection(serverData.Topics)
self.attachCollectionEvents()
},
attachCollectionEvents: function() {
DataModel.Topics.on('add remove', function(topic) {
toExport.Topics.on('add remove', function(topic) {
InfoBox.updateNumbers()
Filter.checkMetacodes()
Filter.checkMappers()
})
DataModel.Synapses.on('add remove', function(synapse) {
toExport.Synapses.on('add remove', function(synapse) {
InfoBox.updateNumbers()
Filter.checkSynapses()
Filter.checkMappers()
})
DataModel.Mappings.on('add remove', function(mapping) {
toExport.Mappings.on('add remove', function(mapping) {
InfoBox.updateNumbers()
Filter.checkSynapses()
Filter.checkMetacodes()
@ -118,7 +63,43 @@ const DataModel = {
})
}
}
return toExport
}
DataModel.Maps = {
Mine: [],
Shared: [],
Starred: [],
Mapper: {
models: [],
mapperId: null
},
Featured: [],
Active: []
}
DataModel.init = function(serverData) {
var self = DataModel
self.synapseIconUrl = serverData['synapse16.png']
// initialize global backbone models and collections
var myCollection = serverData.Mine ? serverData.Mine : []
var sharedCollection = serverData.Shared ? serverData.Shared : []
var starredCollection = serverData.Starred ? serverData.Starred : []
var mapperCollection = serverData.Mapper ? serverData.Mapper : []
var mapperOptionsObj = { id: 'mapper', sortBy: 'updated_at' }
if (serverData.Mapper && serverData.Mapper.mapperId) {
mapperCollection = serverData.Mapper.models
mapperOptionsObj.mapperId = serverData.Mapper.mapperId
}
var featuredCollection = serverData.Featured ? serverData.Featured : []
var activeCollection = serverData.Active ? serverData.Active : []
self.Maps.Mine = new MapCollection(myCollection, { id: 'mine', sortBy: 'updated_at' })
self.Maps.Shared = new MapCollection(sharedCollection, { id: 'shared', sortBy: 'updated_at' })
self.Maps.Starred = new MapCollection(starredCollection, { id: 'starred', sortBy: 'updated_at' })
// 'Mapper' refers to another mapper
self.Maps.Mapper = new MapCollection(mapperCollection, mapperOptionsObj)
self.Maps.Featured = new MapCollection(featuredCollection, { id: 'featured', sortBy: 'updated_at' })
self.Maps.Active = new MapCollection(activeCollection, { id: 'active', sortBy: 'updated_at' })
}
// Note: Topics, Metacodes, Synapses, Mappers, Mappings, Collaborators, Creators are not exported
// You can access them by importing DataModel

View file

@ -2,14 +2,11 @@
import _ from 'lodash'
import Active from './Active'
import Control from './Control'
import DataModel from './DataModel'
import GlobalUI, { ReactApp } from './GlobalUI'
import Settings from './Settings'
import Visualize from './Visualize'
const Filter = {
const Filter = ({Active, Control, DataModel, Visualize}) => {
const toExport = {
dataForPresentation: {
metacodes: {},
mappers: {},
@ -26,7 +23,7 @@ const Filter = {
synapses: []
},
reset: function() {
var self = Filter
var self = toExport
self.filters.metacodes = []
self.filters.mappers = []
self.filters.synapses = []
@ -41,7 +38,7 @@ const Filter = {
// an abstraction function for checkMetacodes, checkMappers, checkSynapses to reduce
// code redundancy
updateFilters: function(collection, propertyToCheck, correlatedModel, filtersToUse, listToModify) {
var self = Filter
var self = toExport
var newList = []
var removed = []
var added = []
@ -97,11 +94,11 @@ const Filter = {
ReactApp.render()
},
checkMetacodes: function() {
var self = Filter
var self = toExport
self.updateFilters('Topics', 'metacode_id', 'Metacodes', 'metacodes', 'metacode')
},
checkMappers: function() {
var self = Filter
var self = toExport
if (Active.Map) {
self.updateFilters('Mappings', 'user_id', 'Mappers', 'mappers', 'mapper')
} else {
@ -110,23 +107,23 @@ const Filter = {
}
},
checkSynapses: function() {
var self = Filter
var self = toExport
self.updateFilters('Synapses', 'desc', 'Synapses', 'synapses', 'synapse')
},
filterAllMetacodes: function(toVisible) {
var self = Filter
var self = toExport
self.visible.metacodes = toVisible ? self.filters.metacodes.slice() : []
ReactApp.render()
self.passFilters()
},
filterAllMappers: function(toVisible) {
var self = Filter
var self = toExport
self.visible.mappers = toVisible ? self.filters.mappers.slice() : []
ReactApp.render()
self.passFilters()
},
filterAllSynapses: function(toVisible) {
var self = Filter
var self = toExport
self.visible.synapses = toVisible ? self.filters.synapses.slice() : []
ReactApp.render()
self.passFilters()
@ -135,7 +132,7 @@ const Filter = {
// to reduce code redundancy
// gets called in the context of a list item in a filter box
toggleLi: function(whichToFilter, id) {
var self = Filter
var self = toExport
if (self.visible[whichToFilter].indexOf(id) === -1) {
self.visible[whichToFilter].push(id)
} else {
@ -146,19 +143,19 @@ const Filter = {
self.passFilters()
},
toggleMetacode: function(id) {
var self = Filter
var self = toExport
self.toggleLi('metacodes', id)
},
toggleMapper: function(id) {
var self = Filter
var self = toExport
self.toggleLi('mappers', id)
},
toggleSynapse: function(id) {
var self = Filter
var self = toExport
self.toggleLi('synapses', id)
},
passFilters: function() {
var self = Filter
var self = toExport
var visible = self.visible
var passesMetacode, passesMapper, passesSynapse
@ -276,5 +273,7 @@ const Filter = {
})
}
}
return toExport
}
export default Filter

View file

@ -7,13 +7,12 @@ import { merge } from 'lodash'
import { notifyUser } from './index.js'
import ImportDialog from './ImportDialog'
import Active from '../Active'
import DataModel from '../DataModel'
import Mapper from '../DataModel/Mapper'
import { ExploreMaps, ChatView, TopicCard } from '../Views'
import Filter from '../Filter'
import JIT from '../JIT'
import Realtime from '../Realtime'
import Map, { InfoBox } from '../Map'
import Map, { mapControl } from '../Map'
import Topic from '../Topic'
import Visualize from '../Visualize'
import makeRoutes from '../../components/makeRoutes'
@ -27,8 +26,11 @@ const MAX_COLUMNS = 4
const ReactApp = {
serverData: {},
currentUser: null,
mapId: null,
openMap: null,
topicId: null,
openTopic: null,
unreadNotificationsCount: 0,
mapsWidth: 0,
toast: '',
@ -36,9 +38,11 @@ const ReactApp = {
mobileTitle: '',
mobileTitleWidth: 0,
metacodeSets: [],
juntoState: { connectedPeople: {}, liveMaps: {} },
init: function(serverData, openLightbox) {
const self = ReactApp
self.serverData = serverData
self.currentUser = new Mapper(serverData.ActiveMapper)
self.unreadNotificationsCount = serverData.unreadNotificationsCount
self.mobileTitle = serverData.mobileTitle
self.openLightbox = openLightbox
@ -52,12 +56,13 @@ const ReactApp = {
const pathname = this.state.location.pathname
switch (pathname.split('/')[1]) {
case '':
if (Active.Mapper && Active.Mapper.id) {
if (self.currentUser && self.currentUser.id) {
$('#yield').hide()
ExploreMaps.updateFromPath(pathname)
self.mapId = null
Active.Map = null
Active.Topic = null
self.topicId = null
self.openMap = null
self.openTopic = null
}
break
case 'explore':
@ -65,19 +70,19 @@ const ReactApp = {
ExploreMaps.updateFromPath(pathname)
self.mapId = null
self.topicId = null
Active.Map = null
Active.Topic = null
self.openMap = null
self.openTopic = null
break
case 'topics':
$('#yield').hide()
Active.Map = null
self.openMap = null
self.mapId = null
self.topicId = pathname.split('/')[2]
break
case 'maps':
if (!pathname.includes('request_access')) {
$('#yield').hide()
Active.Topic = null
self.openTopic = null
self.topicId = null
self.mapId = pathname.split('/')[2]
}
@ -99,14 +104,18 @@ const ReactApp = {
const self = ReactApp
return merge({
unreadNotificationsCount: self.unreadNotificationsCount,
currentUser: Active.Mapper,
currentUser: self.currentUser,
toast: self.toast,
mobile: self.mobile,
mobileTitle: self.mobileTitle,
mobileTitleWidth: self.mobileTitleWidth,
mobileTitleClick: (e) => Active.Map && InfoBox.toggleBox(e),
mobileTitleClick: (e) => self.openMap && self.openMap.InfoBox.toggleBox(e),
openInviteLightbox: () => self.openLightbox('invite'),
serverData: self.serverData
serverData: self.serverData,
endActiveMap: mapControl.end,
launchNewMap: mapControl.launch,
mapId: self.mapId,
topicId: self.topicId
},
self.getMapProps(),
self.getTopicProps(),
@ -118,27 +127,27 @@ const ReactApp = {
},
getMapProps: function() {
const self = ReactApp
if (!self.openMap) return {}
return {
mapId: self.mapId,
map: Active.Map,
hasLearnedTopicCreation: Map.hasLearnedTopicCreation,
userRequested: Map.userRequested,
requestAnswered: Map.requestAnswered,
requestApproved: Map.requestApproved,
onRequestAccess: Map.requestAccess,
mapIsStarred: Map.mapIsStarred,
endActiveMap: Map.end,
launchNewMap: Map.launch,
toggleMapInfoBox: InfoBox.toggleBox,
infoBoxHtml: InfoBox.html,
map: self.openMap.Active.Map,
hasLearnedTopicCreation: self.openMap.Map.hasLearnedTopicCreation,
userRequested: self.openMap.Map.userRequested,
requestAnswered: self.openMap.Map.requestAnswered,
requestApproved: self.openMap.Map.requestApproved,
onRequestAccess: self.openMap.Map.requestAccess,
mapIsStarred: self.openMap.Map.mapIsStarred,
toggleMapInfoBox: self.openMap.InfoBox.toggleBox,
infoBoxHtml: self.openMap.InfoBox.html,
openImportLightbox: () => ImportDialog.show(),
forkMap: Map.fork,
onMapStar: Map.star,
onMapUnstar: Map.unstar
forkMap: self.openMap.Map.fork,
onMapStar: self.openMap.Map.star,
onMapUnstar: self.openMap.Map.unstar
}
},
getCommonProps: function() {
const self = ReactApp
if (!(self.openMap || self.openTopic)) return {}
const { JIT, Visualize } = self.openMap || self.openTopic
return {
openHelpLightbox: () => self.openLightbox('cheatsheet'),
onZoomExtents: event => JIT.zoomExtents(event, Visualize.mGraph.canvas),
@ -148,20 +157,22 @@ const ReactApp = {
},
getTopicCardProps: function() {
const self = ReactApp
if (!(self.openMap || self.openTopic)) return {}
const { TopicCard } = self.openMap || self.openTopic
return {
openTopic: TopicCard.openTopic,
metacodeSets: self.metacodeSets,
updateTopic: (topic, obj) => topic.save(obj),
onTopicFollow: Topic.onTopicFollow
onTopicFollow: Topic.onTopicFollow // todo
}
},
getTopicProps: function() {
const self = ReactApp
if (!self.openTopic) return {}
return {
topicId: self.topicId,
topic: Active.Topic,
endActiveTopic: Topic.end,
launchNewTopic: Topic.launch
topic: self.openTopic.Active.Topic,
endActiveTopic: Topic.end, // todo
launchNewTopic: Topic.launch // todo
}
},
getMapsProps: function() {
@ -169,7 +180,7 @@ const ReactApp = {
return {
section: ExploreMaps.collection && ExploreMaps.collection.id,
maps: ExploreMaps.collection,
juntoState: Realtime.juntoState,
juntoState: self.juntoState,
moreToLoad: ExploreMaps.collection && ExploreMaps.collection.page !== 'loadedAll',
user: ExploreMaps.collection && ExploreMaps.collection.id === 'mapper' ? ExploreMaps.mapper : null,
loadMore: ExploreMaps.loadMore,
@ -182,6 +193,11 @@ const ReactApp = {
},
getChatProps: function() {
const self = ReactApp
if (!self.openMap) return {
participants: [],
messages: []
}
const { ChatView, Realtime } = self.openMap
return {
unreadMessages: ChatView.unreadMessages,
conversationLive: ChatView.conversationLive,
@ -204,6 +220,8 @@ const ReactApp = {
},
getFilterProps: function() {
const self = ReactApp
if (!self.openMap) return {}
const { Filter } = self.openMap
return {
filterData: Filter.dataForPresentation,
allForFiltering: Filter.filters,
@ -219,7 +237,7 @@ const ReactApp = {
resize: function() {
const self = ReactApp
const maps = ExploreMaps.collection
const currentUser = Active.Mapper
const currentUser = self.currentUser
const user = maps && maps.id === 'mapper' ? ExploreMaps.mapper : null
const numCards = (maps ? maps.length : 0) + (user || currentUser ? 1 : 0)
const mapSpaces = Math.floor(document.body.clientWidth / MAP_WIDTH)

View file

@ -3,15 +3,10 @@
import parse from 'csv-parse'
import _ from 'lodash'
import Active from './Active'
import AutoLayout from './AutoLayout'
import DataModel from './DataModel'
import GlobalUI from './GlobalUI'
import Map from './Map'
import Synapse from './Synapse'
import Topic from './Topic'
const Import = {
const Import = ({Active, AutoLayout, DataModel, Map, Synapse, Topic}) => {
const toExport = {
// note that user is not imported
topicWhitelist: [
'id', 'name', 'metacode', 'x', 'y', 'description', 'link', 'permission'
@ -22,12 +17,12 @@ const Import = {
cidMappings: {}, // to be filled by importId => cid mappings
handleTSV: function(text) {
const results = Import.parseTabbedString(text)
Import.handle(results)
const results = toExport.parseTabbedString(text)
toExport.handle(results)
},
handleCSV: function(text, parserOpts = {}) {
const self = Import
const self = toExport
const topicsRegex = /("?Topics"?[, \t"]*)([\s\S]*)/mi
const synapsesRegex = /("?Synapses"?[, \t"]*)([\s\S]*)/mi
@ -68,11 +63,11 @@ const Import = {
handleJSON: function(text) {
const results = JSON.parse(text)
Import.handle(results)
toExport.handle(results)
},
handle: function(results) {
var self = Import
var self = toExport
var topics = results.topics.map(topic => self.normalizeKeys(topic))
var synapses = results.synapses.map(synapse => self.normalizeKeys(synapse))
@ -87,7 +82,7 @@ const Import = {
},
parseTabbedString: function(text) {
var self = Import
var self = toExport
// determine line ending and split lines
var delim = '\n'
@ -213,7 +208,7 @@ const Import = {
},
importTopics: function(parsedTopics) {
var self = Import
var self = toExport
parsedTopics.forEach(topic => {
let coords = { x: topic.x, y: topic.y }
@ -240,7 +235,7 @@ const Import = {
},
importSynapses: function(parsedSynapses) {
var self = Import
var self = toExport
parsedSynapses.forEach(function(synapse) {
// only createSynapseWithParameters once both topics are persisted
@ -279,7 +274,7 @@ const Import = {
createTopicWithParameters: function(name, metacodeName, permission, desc,
link, xloc, yloc, importId, opts = {}) {
var self = Import
var self = toExport
$(document).trigger(Map.events.editedByActiveMapper)
var metacode = DataModel.Metacodes.where({name: metacodeName})[0] || null
if (metacode === null) {
@ -359,7 +354,7 @@ const Import = {
const permission = opts.permission || null // use default
const desc = opts.desc || url
Import.createTopicWithParameters(
toExport.createTopicWithParameters(
name,
metacode,
permission,
@ -423,5 +418,7 @@ const Import = {
})
}
}
return toExport
}
export default Import

View file

@ -35,17 +35,6 @@ return {
animationDone: 'Metamaps:JIT:events:animationDone'
},
vizData: [], // contains the visualization-compatible graph
/**
* This method will bind the event handlers it is interested and initialize the class.
*/
init: function(serverData) {
const self = JIT
self.topicDescImage = new Image()
self.topicDescImage.src = serverData['topic_description_signifier.png']
self.topicLinkImage = new Image()
self.topicLinkImage.src = serverData['topic_link_signifier.png']
},
/**
* convert our topic JSON into something JIT can use
*/
@ -1968,5 +1957,12 @@ return {
}
}
}
JIT.init = function(serverData) {
JIT.topicDescImage = new Image()
JIT.topicDescImage.src = serverData['topic_description_signifier.png']
JIT.topicLinkImage = new Image()
JIT.topicLinkImage.src = serverData['topic_link_signifier.png']
}
export default JIT

View file

@ -5,9 +5,9 @@ import { Search } from './GlobalUI'
const Listeners = ({ Active, Create, Control, DataModel, JIT, Realtime, Selected, Topic, Visualize }) => {
return {
init: function() {
activate: function() {
var self = this
$(document).on('keydown', function(e) {
$(document).on('keydown.map', function(e) {
if (!(Active.Map || Active.Topic)) return
const onCanvas = e.target.tagName === 'BODY'
@ -131,7 +131,7 @@ return {
break
}
})
$(window).resize(function() {
$(window).on('resize.map', function() {
if (Visualize && Visualize.mGraph) {
Util.resizeCanvas(Visualize.mGraph.canvas)
}

View file

@ -3,12 +3,11 @@
import outdent from 'outdent'
import { browserHistory } from 'react-router'
import Active from '../Active'
import DataModel from '../DataModel'
import GlobalUI, { ReactApp } from '../GlobalUI'
import Util from '../Util'
const InfoBox = {
const InfoBox = ({Active, DataModel}) => {
const toExport = {
isOpen: 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>",
@ -36,32 +35,32 @@ const InfoBox = {
userImageUrl: '',
html: '',
init: function(serverData, updateThumbnail) {
var self = InfoBox
var self = toExport
self.updateThumbnail = updateThumbnail
$('.mapInfoBox').click(function(event) {
$('.maptoExport').click(function(event) {
event.stopPropagation()
})
$('body').click(self.close)
self.attachEventListeners()
self.generateBoxHTML = Hogan.compile($('#mapInfoBoxTemplate').html())
self.generateBoxHTML = Hogan.compile($('#maptoExportTemplate').html())
self.userImageUrl = serverData['user.png']
var querystring = window.location.search.replace(/^\?/, '')
if (querystring === 'new') {
self.open()
$('.mapInfoBox').addClass('mapRequestTitle')
$('.maptoExport').addClass('mapRequestTitle')
$('#mapInfoName').trigger('click')
$('#mapInfoName textarea').focus()
$('#mapInfoName textarea').select()
}
},
toggleBox: function(event) {
var self = InfoBox
var self = toExport
if (self.isOpen) self.close()
else self.open()
@ -69,23 +68,23 @@ const InfoBox = {
event.stopPropagation()
},
open: function() {
var self = InfoBox
var self = toExport
$('.mapInfoIcon div').addClass('hide')
$('.mapInfoBox').fadeIn(200, function() {
$('.maptoExport').fadeIn(200, function() {
self.isOpen = true
})
},
close: function() {
var self = InfoBox
var self = toExport
$('.mapInfoIcon div').removeClass('hide')
$('.mapInfoBox').fadeOut(200, function() {
$('.maptoExport').fadeOut(200, function() {
self.isOpen = false
self.hidePermissionSelect()
$('.mapContributors .tip').hide()
})
},
load: function() {
var self = InfoBox
var self = toExport
var map = Active.Map
@ -115,12 +114,12 @@ const InfoBox = {
self.attachEventListeners()
},
attachEventListeners: function() {
var self = InfoBox
var self = toExport
$('.mapInfoBox.canEdit .best_in_place').best_in_place()
$('.maptoExport.canEdit .best_in_place').best_in_place()
// because anyone who can edit the map can change the map title
var bipName = $('.mapInfoBox .best_in_place_name')
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]
@ -144,7 +143,7 @@ const InfoBox = {
Active.Map.trigger('saved')
// mobile menu
$('#header_content').html(name)
$('.mapInfoBox').removeClass('mapRequestTitle')
$('.maptoExport').removeClass('mapRequestTitle')
document.title = `${name} | Metamaps`
window.history.replaceState('', `${name} | Metamaps`, window.location.pathname)
})
@ -164,8 +163,8 @@ const InfoBox = {
$('.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 .mapInfoBox
$('.mapInfoBox.yourMap').unbind('.yourMap').bind('click.yourMap', self.hidePermissionSelect)
// 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)
@ -178,14 +177,14 @@ const InfoBox = {
event.stopPropagation()
})
$('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function() {
$('.maptoExport').unbind('.hideTip').bind('click.hideTip', function() {
$('.mapContributors .tip').hide()
})
self.addTypeahead()
},
addTypeahead: function() {
var self = InfoBox
var self = toExport
if (!Active.Map) return
@ -232,14 +231,14 @@ const InfoBox = {
}
},
removeCollaborator: function(collaboratorId) {
var self = InfoBox
var self = toExport
DataModel.Collaborators.remove(DataModel.Collaborators.get(collaboratorId))
var mapperIds = DataModel.Collaborators.models.map(function(mapper) { return mapper.id })
$.post('/maps/' + Active.Map.id + '/access', { access: mapperIds })
self.updateNumbers()
},
addCollaborator: function(newCollaboratorId) {
var self = InfoBox
var self = toExport
if (DataModel.Collaborators.get(newCollaboratorId)) {
GlobalUI.notifyUser('That user already has access')
@ -258,16 +257,16 @@ const InfoBox = {
$.getJSON('/users/' + newCollaboratorId + '.json', callback)
},
handleResultClick: function(event, item) {
var self = InfoBox
var self = toExport
self.addCollaborator(item.id)
$('.collaboratorSearchField').typeahead('val', '')
},
updateNameDescPerm: function(name, desc, perm) {
$('.mapInfoBox').removeClass('mapRequestTitle')
$('.maptoExport').removeClass('mapRequestTitle')
$('.mapInfoName .best_in_place_name').html(name)
$('.mapInfoDesc .best_in_place_desc').html(desc)
$('.mapInfoBox .mapPermission').removeClass('commons public private').addClass(perm)
$('.maptoExport .mapPermission').removeClass('commons public private').addClass(perm)
},
createContributorList: function() {
var relevantPeople = Active.Map.get('permission') === 'commons' ? DataModel.Mappers : DataModel.Collaborators
@ -294,7 +293,7 @@ const InfoBox = {
updateNumbers: function() {
if (!Active.Map) return
const self = InfoBox
const self = toExport
var relevantPeople = Active.Map.get('permission') === 'commons' ? DataModel.Mappers : DataModel.Collaborators
@ -323,7 +322,7 @@ const InfoBox = {
$('.mapEditedAt').html('<span>Last edited: </span>' + Util.nowDateFormatted())
},
onPermissionClick: function(event) {
var self = InfoBox
var self = toExport
if (!self.selectingPermission) {
self.selectingPermission = true
@ -340,14 +339,14 @@ const InfoBox = {
}
},
hidePermissionSelect: function() {
var self = InfoBox
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 = InfoBox
var self = toExport
self.selectingPermission = false
var permission = $(this).attr('class')
@ -358,7 +357,7 @@ const InfoBox = {
const shareable = permission === 'private' ? '' : 'shareable'
$('.mapPermission').removeClass('commons public private minimize').addClass(permission)
$('.mapPermission .permissionSelect').remove()
$('.mapInfoBox').removeClass('shareable').addClass(shareable)
$('.maptoExport').removeClass('shareable').addClass(shareable)
event.stopPropagation()
},
deleteActiveMap: function() {
@ -371,7 +370,7 @@ const InfoBox = {
var authorized = map.authorizePermissionChange(mapper)
if (doIt && authorized) {
InfoBox.close()
toExport.close()
DataModel.Maps.Active.remove(map)
DataModel.Maps.Featured.remove(map)
DataModel.Maps.Mine.remove(map)
@ -384,5 +383,7 @@ const InfoBox = {
}
}
}
return toExport
}
export default InfoBox

View file

@ -6,414 +6,442 @@ import { browserHistory } from 'react-router'
import Active from '../Active'
import AutoLayout from '../AutoLayout'
import Cable from '../Cable'
import Control from '../Control'
import Create from '../Create'
import DataModel from '../DataModel'
import DataModelMap from '../DataModel/Map'
import MapperCollection from '../DataModel/MapperCollection'
import TopicCollection from '../DataModel/TopicCollection'
import SynapseCollection from '../DataModel/SynapseCollection'
import MappingCollection from '../DataModel/MappingCollection'
import Filter from '../Filter'
import GlobalUI, { ReactApp } from '../GlobalUI'
import Import from '../Import'
import InfoBox from './InfoBox'
import JIT from '../JIT'
import Listeners from '../Listeners'
import Loading from '../Loading'
import Mouse from '../Mouse'
import Organize from '../Organize'
import PasteInput from '../PasteInput'
import Realtime from '../Realtime'
import Selected from '../Selected'
import Synapse from '../Synapse'
import SynapseCard from '../SynapseCard'
import Topic from '../Topic'
import TopicCard from '../Views/TopicCard'
import ChatView from '../Views/ChatView'
import Visualize from '../Visualize'
import CheatSheet from './CheatSheet'
import InfoBox from './InfoBox'
const Map = {
events: {
editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper'
},
mapIsStarred: false,
requests: [],
userRequested: false,
requestAnswered: false,
requestApproved: false,
hasLearnedTopicCreation: true,
init: function(serverData) {
var self = Map
self.mapIsStarred = serverData.mapIsStarred
self.requests = serverData.requests
self.setAccessRequest()
$('#wrapper').mousedown(function(e) {
if (e.button === 1) return false
})
GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
InfoBox.init(serverData, function updateThumbnail() {
self.uploadMapScreenshot()
})
CheatSheet.init(serverData)
$(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper)
},
setHasLearnedTopicCreation: function(value) {
const self = Map
self.hasLearnedTopicCreation = value
ReactApp.render()
},
requestAccess: function() {
const self = Map
self.requests.push({
user_id: Active.Mapper.id,
answered: false,
approved: false
})
self.setAccessRequest()
const mapId = Active.Map.id
$.post({
url: `/maps/${mapId}/access_request`
})
GlobalUI.notifyUser('Map creator will be notified of your request')
},
setAccessRequest: function() {
const self = Map
if (Active.Mapper) {
const request = _find(self.requests, r => r.user_id === Active.Mapper.id)
if (!request) {
self.userRequested = false
self.requestAnswered = false
self.requestApproved = false
const mapControl = {
launch: function(id, serverData) {
var dataIsReadySetupMap = function(data) {
const newMap = {
Active: null,
AutoLayout: null,
Cable: null,
ChatView: null,
Control: null,
Create: null,
DataModel: null,
Filter: null,
Import: null,
JIT: null,
Listeners: null,
Mouse: null,
Organize: null,
PasteInput: null,
Realtime: null,
Selected: null,
Synapse: null,
SynapseCard: null,
Topic: null,
TopicCard: null,
Visualize: null
}
else if (request && !request.answered) {
self.userRequested = true
self.requestAnswered = false
self.requestApproved = false
}
else if (request && request.answered && !request.approved) {
self.userRequested = true
self.requestAnswered = true
self.requestApproved = false
}
}
ReactApp.render()
},
launch: function(id) {
const self = Map
const newMap = {
Active: null,
AutoLayout: null,
Cable: null,
Control: null,
Create: null,
DataModel: null,
Filter: null,
Import: null,
JIT: null,
Listeners: null,
Loading: null,
Map: null,
Mouse: null,
Organize: null,
PasteInput: null,
Realtime: null,
Selected: null,
Settings: null,
Synapse: null,
SynapseCard: null,
Topic: null,
Views: null,
Visualize: null
}
newMap.JIT = JIT(newMap)
newMap.Listeners = Listeners(newMap)
console.log(newMap)
var dataIsReadySetupMap = function() {
Map.setAccessRequest()
Visualize.type = 'ForceDirected'
newMap.Active = Active()
newMap.AutoLayout = AutoLayout(newMap)
newMap.Cable = Cable(newMap)
newMap.ChatView = ChatView(newMap)
newMap.Control = Control(newMap)
newMap.Create = Create(newMap)
newMap.DataModel = DataModel(newMap)
newMap.Filter = Filter(newMap)
newMap.Import = Import(newMap)
newMap.InfoBox = InfoBox(newMap)
newMap.JIT = JIT(newMap)
newMap.Listeners = Listeners(newMap)
newMap.Map = Map(newMap)
newMap.Mouse = Mouse(newMap)
newMap.Organize = Organize(newMap)
newMap.PasteInput = PasteInput(newMap)
newMap.Realtime = Realtime(newMap)
newMap.Selected = Selected(newMap)
newMap.Synapse = Synapse(newMap)
newMap.SynapseCard = SynapseCard(newMap)
newMap.Topic = Topic(newMap)
newMap.TopicCard = TopicCard(newMap)
newMap.Visualize = Visualize(newMap)
console.log(newMap)
newMap.Active.Map = new DataModelMap(data.map)
newMap.DataModel.Mappers = new MapperCollection(data.mappers)
newMap.DataModel.Collaborators = new MapperCollection(data.collaborators)
newMap.DataModel.Topics = new TopicCollection(data.topics)
newMap.DataModel.Synapses = new SynapseCollection(data.synapses)
newMap.DataModel.Mappings = new MappingCollection(data.mappings)
newMap.DataModel.Messages = data.messages
newMap.DataModel.Stars = data.stars
newMap.DataModel.attachCollectionEvents()
newMap.Map.requests = data.requests
newMap.Map.setAccessRequest()
newMap.Visualize.type = 'ForceDirected'
newMap.JIT.prepareVizData()
Selected.reset()
InfoBox.load()
Filter.reset()
Filter.checkMetacodes()
Filter.checkSynapses()
Filter.checkMappers()
Realtime.startActiveMap()
newMap.InfoBox.load()
newMap.Filter.checkMetacodes()
newMap.Filter.checkSynapses()
newMap.Filter.checkMappers()
newMap.Realtime.startActiveMap()
Loading.hide()
document.title = Active.Map.get('name') + ' | Metamaps'
ReactApp.mobileTitle = Active.Map.get('name')
document.title = newMap.Active.Map.get('name') + ' | Metamaps'
ReactApp.openMap = newMap
ReactApp.mobileTitle = newMap.Active.Map.get('name')
ReactApp.render()
}
function isLoaded() {
if (InfoBox.generateBoxHTML) dataIsReadySetupMap()
else setTimeout(() => isLoaded(), 50)
}
if (Active.Map && Active.Map.id === id) {
isLoaded()
if (false) {
// do something with serverData here
dataIsReadySetupMap()
}
else {
Loading.show()
$.ajax({
url: '/maps/' + id + '/contains.json',
success: function(data) {
Active.Map = new DataModelMap(data.map)
DataModel.Mappers = new DataModel.MapperCollection(data.mappers)
DataModel.Collaborators = new DataModel.MapperCollection(data.collaborators)
DataModel.Topics = new DataModel.TopicCollection(data.topics)
DataModel.Synapses = new DataModel.SynapseCollection(data.synapses)
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
DataModel.Messages = data.messages
DataModel.Stars = data.stars
DataModel.attachCollectionEvents()
self.requests = data.requests
isLoaded()
}
success: dataIsReadySetupMap
})
}
},
end: function() {
if (Active.Map) {
$('.main').removeClass('compressed')
AutoLayout.resetSpiral()
$('.rightclickmenu').remove()
TopicCard.hideCard()
SynapseCard.hideCard()
Create.newTopic.hide(true) // true means force (and override pinned)
Create.newSynapse.hide()
InfoBox.close()
Realtime.endActiveMap()
self.requests = []
self.hasLearnedTopicCreation = true
}
},
star: function() {
var self = Map
if (!Active.Map) return
$.post('/maps/' + Active.Map.id + '/star')
DataModel.Stars.push({ user_id: Active.Mapper.id, map_id: Active.Map.id })
DataModel.Maps.Starred.add(Active.Map)
GlobalUI.notifyUser('Map is now starred')
self.mapIsStarred = true
ReactApp.render()
},
unstar: function() {
var self = Map
if (!Active.Map) return
$.post('/maps/' + Active.Map.id + '/unstar')
DataModel.Stars = DataModel.Stars.filter(function(s) { return s.user_id !== Active.Mapper.id })
DataModel.Maps.Starred.remove(Active.Map)
self.mapIsStarred = false
ReactApp.render()
},
fork: function() {
GlobalUI.openLightbox('forkmap')
let nodesData = ''
let synapsesData = ''
let nodesArray = []
let synapsesArray = []
// collect the unfiltered topics
Visualize.mGraph.graph.eachNode(function(n) {
// if the opacity is less than 1 then it's filtered
if (n.getData('alpha') === 1) {
var id = n.getData('topic').id
nodesArray.push(id)
let x, y
if (n.pos.x && n.pos.y) {
x = n.pos.x
y = n.pos.y
} else {
x = Math.cos(n.pos.theta) * n.pos.rho
y = Math.sin(n.pos.theta) * n.pos.rho
}
nodesData += id + '/' + x + '/' + y + ','
}
})
// collect the unfiltered synapses
DataModel.Synapses.each(function(synapse) {
var desc = synapse.get('desc')
var descNotFiltered = Filter.visible.synapses.indexOf(desc) > -1
// make sure that both topics are being added, otherwise, it
// doesn't make sense to add the synapse
var topicsNotFiltered = nodesArray.indexOf(synapse.get('topic1_id')) > -1
topicsNotFiltered = topicsNotFiltered && nodesArray.indexOf(synapse.get('topic2_id')) > -1
if (descNotFiltered && topicsNotFiltered) {
synapsesArray.push(synapse.id)
}
})
synapsesData = synapsesArray.join()
nodesData = nodesData.slice(0, -1)
GlobalUI.CreateMap.topicsToMap = nodesData
GlobalUI.CreateMap.synapsesToMap = synapsesData
},
leavePrivateMap: function() {
var map = Active.Map
DataModel.Maps.Active.remove(map)
DataModel.Maps.Featured.remove(map)
browserHistory.push('/')
GlobalUI.notifyUser('Sorry! That map has been changed to Private.')
},
cantEditNow: function() {
Realtime.turnOff(true) // true is for 'silence'
GlobalUI.notifyUser('Map was changed to Public. Editing is disabled.')
Active.Map.trigger('changeByOther')
},
canEditNow: function() {
var confirmString = "You've been granted permission to edit this map. "
confirmString += 'Do you want to reload and enable realtime collaboration?'
var c = window.confirm(confirmString)
if (c) {
window.location.reload()
}
},
editedByActiveMapper: function() {
if (Active.Mapper) {
DataModel.Mappers.add(Active.Mapper)
}
},
offerScreenshotDownload: () => {
const canvas = Map.getMapCanvasForScreenshots()
const filename = Map.getMapScreenshotFilename(Active.Map)
var downloadMessage = outdent`
Captured map screenshot!
<a id="map-screenshot-download-link"
href="${canvas.canvas.toDataURL()}"
download="${filename}"
>
DOWNLOAD
</a>`
GlobalUI.notifyUser(downloadMessage)
},
uploadMapScreenshot: () => {
const canvas = Map.getMapCanvasForScreenshots()
const filename = Map.getMapScreenshotFilename(Active.Map)
canvas.canvas.toBlob(imageBlob => {
const formData = new window.FormData()
formData.append('map[screenshot]', imageBlob, filename)
$.ajax({
type: 'PATCH',
dataType: 'json',
url: `/maps/${Active.Map.id}`,
data: formData,
processData: false,
contentType: false,
success: function(data) {
GlobalUI.notifyUser('Successfully updated map screenshot.')
},
error: function() {
GlobalUI.notifyUser('Failed to update map screenshot.')
}
})
})
},
getMapCanvasForScreenshots: () => {
var canvas = {}
canvas.canvas = document.createElement('canvas')
canvas.canvas.width = 1880 // 960
canvas.canvas.height = 1260 // 630
canvas.scaleOffsetX = 1
canvas.scaleOffsetY = 1
canvas.translateOffsetY = 0
canvas.translateOffsetX = 0
canvas.denySelected = true
canvas.getSize = function() {
if (this.size) return this.size
var canvas = this.canvas
this.size = {
width: canvas.width,
height: canvas.height
}
return this.size
}
canvas.scale = function(x, y) {
const px = this.scaleOffsetX * x
const py = this.scaleOffsetY * y
const dx = this.translateOffsetX * (x - 1) / px
const dy = this.translateOffsetY * (y - 1) / py
this.scaleOffsetX = px
this.scaleOffsetY = py
this.getCtx().scale(x, y)
this.translate(dx, dy)
}
canvas.translate = function(x, y) {
const sx = this.scaleOffsetX
const sy = this.scaleOffsetY
this.translateOffsetX += x * sx
this.translateOffsetY += y * sy
this.getCtx().translate(x, y)
}
canvas.getCtx = function() {
return this.canvas.getContext('2d')
}
// center it
canvas.getCtx().translate(1880 / 2, 1260 / 2)
var mGraph = Visualize.mGraph
var id = mGraph.root
var root = mGraph.graph.getNode(id)
var T = !!root.visited
// pass true to avoid basing it on a selection
JIT.zoomExtents(null, canvas, true)
const c = canvas.canvas
const ctx = canvas.getCtx()
const scale = canvas.scaleOffsetX
// draw a grey background
ctx.fillStyle = '#d8d9da'
const xPoint = (-(c.width / scale) / 2) - (canvas.translateOffsetX / scale)
const yPoint = (-(c.height / scale) / 2) - (canvas.translateOffsetY / scale)
ctx.fillRect(xPoint, yPoint, c.width / scale, c.height / scale)
// draw the graph
mGraph.graph.eachNode(function(node) {
var nodeAlpha = node.getData('alpha')
node.eachAdjacency(function(adj) {
var nodeTo = adj.nodeTo
if (!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {
mGraph.fx.plotLine(adj, canvas)
}
})
if (node.drawn) {
mGraph.fx.plotNode(node, canvas)
}
if (!mGraph.labelsHidden) {
if (node.drawn && nodeAlpha >= 0.95) {
mGraph.labels.plotLabel(canvas, node)
} else {
mGraph.labels.hideLabel(node, false)
}
}
node.visited = !T
})
return canvas
},
getMapScreenshotFilename: map => {
var today = new Date()
var dd = today.getDate()
var mm = today.getMonth() + 1 // January is 0!
var yyyy = today.getFullYear()
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
today = mm + '/' + dd + '/' + yyyy
var mapName = map.get('name').split(' ').join(['-'])
const filename = `metamap-${map.id}-${mapName}-${today}.png`
return filename
end: function(map) {
$('.main').removeClass('compressed')
$('.rightclickmenu').remove()
map.AutoLayout.resetSpiral()
map.TopicCard.hideCard()
map.SynapseCard.hideCard()
map.Create.newTopic.hide(true) // true means force (and override pinned)
map.Create.newSynapse.hide()
map.InfoBox.close()
map.Realtime.endActiveMap()
map.Map.requests = []
map.Map.hasLearnedTopicCreation = true
}
}
export { mapControl }
export { CheatSheet, InfoBox }
const Map = ({Active, DataModel, JIT, Visualize, Realtime}) => {
const toExport = {
mapIsStarred: false,
requests: [],
userRequested: false,
requestAnswered: false,
requestApproved: false,
hasLearnedTopicCreation: true,
init: function(serverData) {
var self = toExport
self.mapIsStarred = serverData.mapIsStarred
self.requests = serverData.requests
self.setAccessRequest()
$('#wrapper').mousedown(function(e) {
if (e.button === 1) return false
})
GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
//InfoBox.init(serverData, function updateThumbnail() {
// self.uploadMapScreenshot()
//})
CheatSheet.init(serverData)
$(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper)
},
setHasLearnedTopicCreation: function(value) {
const self = toExport
self.hasLearnedTopicCreation = value
ReactApp.render()
},
requestAccess: function() {
const self = toExport
self.requests.push({
user_id: Active.Mapper.id,
answered: false,
approved: false
})
self.setAccessRequest()
const mapId = Active.Map.id
$.post({
url: `/maps/${mapId}/access_request`
})
GlobalUI.notifyUser('Map creator will be notified of your request')
},
setAccessRequest: function() {
const self = toExport
if (Active.Mapper) {
const request = _find(self.requests, r => r.user_id === Active.Mapper.id)
if (!request) {
self.userRequested = false
self.requestAnswered = false
self.requestApproved = false
}
else if (request && !request.answered) {
self.userRequested = true
self.requestAnswered = false
self.requestApproved = false
}
else if (request && request.answered && !request.approved) {
self.userRequested = true
self.requestAnswered = true
self.requestApproved = false
}
}
ReactApp.render()
},
star: function() {
var self = toExport
if (!Active.Map) return
$.post('/maps/' + Active.Map.id + '/star')
DataModel.Stars.push({ user_id: Active.Mapper.id, map_id: Active.Map.id })
DataModel.Maps.Starred.add(Active.Map)
GlobalUI.notifyUser('Map is now starred')
self.mapIsStarred = true
ReactApp.render()
},
unstar: function() {
var self = toExport
if (!Active.Map) return
$.post('/maps/' + Active.Map.id + '/unstar')
DataModel.Stars = DataModel.Stars.filter(function(s) { return s.user_id !== Active.Mapper.id })
DataModel.Maps.Starred.remove(Active.Map)
self.mapIsStarred = false
ReactApp.render()
},
fork: function() {
GlobalUI.openLightbox('forkmap')
let nodesData = ''
let synapsesData = ''
let nodesArray = []
let synapsesArray = []
// collect the unfiltered topics
Visualize.mGraph.graph.eachNode(function(n) {
// if the opacity is less than 1 then it's filtered
if (n.getData('alpha') === 1) {
var id = n.getData('topic').id
nodesArray.push(id)
let x, y
if (n.pos.x && n.pos.y) {
x = n.pos.x
y = n.pos.y
} else {
x = Math.cos(n.pos.theta) * n.pos.rho
y = Math.sin(n.pos.theta) * n.pos.rho
}
nodesData += id + '/' + x + '/' + y + ','
}
})
// collect the unfiltered synapses
DataModel.Synapses.each(function(synapse) {
var desc = synapse.get('desc')
var descNotFiltered = Filter.visible.synapses.indexOf(desc) > -1
// make sure that both topics are being added, otherwise, it
// doesn't make sense to add the synapse
var topicsNotFiltered = nodesArray.indexOf(synapse.get('topic1_id')) > -1
topicsNotFiltered = topicsNotFiltered && nodesArray.indexOf(synapse.get('topic2_id')) > -1
if (descNotFiltered && topicsNotFiltered) {
synapsesArray.push(synapse.id)
}
})
synapsesData = synapsesArray.join()
nodesData = nodesData.slice(0, -1)
GlobalUI.CreateMap.topicsToMap = nodesData
GlobalUI.CreateMap.synapsesToMap = synapsesData
},
leavePrivateMap: function() {
var map = Active.Map
DataModel.Maps.Active.remove(map)
DataModel.Maps.Featured.remove(map)
browserHistory.push('/')
GlobalUI.notifyUser('Sorry! That map has been changed to Private.')
},
cantEditNow: function() {
Realtime.turnOff(true) // true is for 'silence'
GlobalUI.notifyUser('Map was changed to Public. Editing is disabled.')
Active.Map.trigger('changeByOther')
},
canEditNow: function() {
var confirmString = "You've been granted permission to edit this map. "
confirmString += 'Do you want to reload and enable realtime collaboration?'
var c = window.confirm(confirmString)
if (c) {
window.location.reload()
}
},
editedByActiveMapper: function() {
if (Active.Mapper) {
DataModel.Mappers.add(Active.Mapper)
}
},
offerScreenshotDownload: () => {
const canvas = toExport.getMapCanvasForScreenshots()
const filename = toExport.getMapScreenshotFilename(Active.Map)
var downloadMessage = outdent`
Captured map screenshot!
<a id="map-screenshot-download-link"
href="${canvas.canvas.toDataURL()}"
download="${filename}"
>
DOWNLOAD
</a>`
GlobalUI.notifyUser(downloadMessage)
},
uploadMapScreenshot: () => {
const canvas = toExport.getMapCanvasForScreenshots()
const filename = toExport.getMapScreenshotFilename(Active.Map)
canvas.canvas.toBlob(imageBlob => {
const formData = new window.FormData()
formData.append('map[screenshot]', imageBlob, filename)
$.ajax({
type: 'PATCH',
dataType: 'json',
url: `/maps/${Active.Map.id}`,
data: formData,
processData: false,
contentType: false,
success: function(data) {
GlobalUI.notifyUser('Successfully updated map screenshot.')
},
error: function() {
GlobalUI.notifyUser('Failed to update map screenshot.')
}
})
})
},
getMapCanvasForScreenshots: () => {
var canvas = {}
canvas.canvas = document.createElement('canvas')
canvas.canvas.width = 1880 // 960
canvas.canvas.height = 1260 // 630
canvas.scaleOffsetX = 1
canvas.scaleOffsetY = 1
canvas.translateOffsetY = 0
canvas.translateOffsetX = 0
canvas.denySelected = true
canvas.getSize = function() {
if (this.size) return this.size
var canvas = this.canvas
this.size = {
width: canvas.width,
height: canvas.height
}
return this.size
}
canvas.scale = function(x, y) {
const px = this.scaleOffsetX * x
const py = this.scaleOffsetY * y
const dx = this.translateOffsetX * (x - 1) / px
const dy = this.translateOffsetY * (y - 1) / py
this.scaleOffsetX = px
this.scaleOffsetY = py
this.getCtx().scale(x, y)
this.translate(dx, dy)
}
canvas.translate = function(x, y) {
const sx = this.scaleOffsetX
const sy = this.scaleOffsetY
this.translateOffsetX += x * sx
this.translateOffsetY += y * sy
this.getCtx().translate(x, y)
}
canvas.getCtx = function() {
return this.canvas.getContext('2d')
}
// center it
canvas.getCtx().translate(1880 / 2, 1260 / 2)
var mGraph = Visualize.mGraph
var id = mGraph.root
var root = mGraph.graph.getNode(id)
var T = !!root.visited
// pass true to avoid basing it on a selection
JIT.zoomExtents(null, canvas, true)
const c = canvas.canvas
const ctx = canvas.getCtx()
const scale = canvas.scaleOffsetX
// draw a grey background
ctx.fillStyle = '#d8d9da'
const xPoint = (-(c.width / scale) / 2) - (canvas.translateOffsetX / scale)
const yPoint = (-(c.height / scale) / 2) - (canvas.translateOffsetY / scale)
ctx.fillRect(xPoint, yPoint, c.width / scale, c.height / scale)
// draw the graph
mGraph.graph.eachNode(function(node) {
var nodeAlpha = node.getData('alpha')
node.eachAdjacency(function(adj) {
var nodeTo = adj.nodeTo
if (!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {
mGraph.fx.plotLine(adj, canvas)
}
})
if (node.drawn) {
mGraph.fx.plotNode(node, canvas)
}
if (!mGraph.labelsHidden) {
if (node.drawn && nodeAlpha >= 0.95) {
mGraph.labels.plotLabel(canvas, node)
} else {
mGraph.labels.hideLabel(node, false)
}
}
node.visited = !T
})
return canvas
},
getMapScreenshotFilename: map => {
var today = new Date()
var dd = today.getDate()
var mm = today.getMonth() + 1 // January is 0!
var yyyy = today.getFullYear()
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
today = mm + '/' + dd + '/' + yyyy
var mapName = map.get('name').split(' ').join(['-'])
const filename = `metamap-${map.id}-${mapName}-${today}.png`
return filename
}
}
return toExport
}
Map.events = {
editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper'
}
export { CheatSheet }
export default Map

View file

@ -1,16 +1,18 @@
const Mouse = {
didPan: false,
didBoxZoom: false,
changeInX: 0,
changeInY: 0,
edgeHoveringOver: false,
boxStartCoordinates: false,
boxEndCoordinates: false,
synapseStartCoordinates: [],
synapseEndCoordinates: null,
lastNodeClick: 0,
lastCanvasClick: 0,
DOUBLE_CLICK_TOLERANCE: 300
const Mouse = () => {
return {
didPan: false,
didBoxZoom: false,
changeInX: 0,
changeInY: 0,
edgeHoveringOver: false,
boxStartCoordinates: false,
boxEndCoordinates: false,
synapseStartCoordinates: [],
synapseEndCoordinates: null,
lastNodeClick: 0,
lastCanvasClick: 0,
DOUBLE_CLICK_TOLERANCE: 300
}
}
export default Mouse

View file

@ -2,10 +2,8 @@ import _ from 'lodash'
import $jit from '../patched/JIT'
import Visualize from './Visualize'
import JIT from './JIT'
const Organize = {
const Organize = ({Visualize, JIT}) => {
const toExport = {
arrange: function(layout, centerNode) {
// first option for layout to implement is 'grid', will do an evenly spaced grid with its center at the 0,0 origin
if (layout === 'grid') {
@ -112,5 +110,7 @@ const Organize = {
}
}
}
return toExport
}
export default Organize

View file

@ -1,16 +1,15 @@
/* global $ */
import Import from './Import'
import Util from './Util'
import Visualize from './Visualize'
const PasteInput = {
const PasteInput = ({Import, Visualize}) => {
const toReturn = {
// thanks to https://github.com/kevva/url-regex
// eslint-disable-next-line no-useless-escape
URL_REGEX: new RegExp('^(?:(?:(?:[a-z]+:)?//)|www\.)(?:\S+(?::\S*)?@)?(?:localhost|(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){3}|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#][^\s"]*)?$'),
init: function() {
var self = PasteInput
var self = toReturn
// intercept dragged files
// see http://stackoverflow.com/questions/6756583
@ -50,7 +49,7 @@ const PasteInput = {
},
handleFile: (file, coords = null) => {
var self = PasteInput
var self = toReturn
var fileReader = new window.FileReader()
fileReader.readAsText(file)
fileReader.onload = function(e) {
@ -64,7 +63,7 @@ const PasteInput = {
},
handle: function(text, coords = {}) {
var self = PasteInput
var self = toReturn
if (text.match(self.URL_REGEX)) {
Import.handleURL(text, coords)
@ -78,5 +77,7 @@ const PasteInput = {
}
}
}
return toReturn
}
export default PasteInput

View file

@ -3,13 +3,8 @@
import SimpleWebRTC from 'simplewebrtc'
import SocketIoConnection from 'simplewebrtc/socketioconnection'
import Active from '../Active'
import Cable from '../Cable'
import DataModel from '../DataModel'
import JIT from '../JIT'
import Util from '../Util'
import Views, { ChatView } from '../Views'
import Visualize from '../Visualize'
import Views from '../Views'
import {
JUNTO_UPDATED,
@ -63,8 +58,8 @@ import {
dragTopic
} from './sendable'
let Realtime = {
juntoState: { connectedPeople: {}, liveMaps: {} },
const Realtime = ({Active, Cable, DataModel, JIT, Visualize}) => {
const toExport = {
videoId: 'video-wrapper',
socket: null,
webrtc: null,
@ -78,7 +73,7 @@ let Realtime = {
localVideo: null,
'junto_spinner_darkgrey.gif': '',
init: function(serverData) {
var self = Realtime
var self = toExport
self.addJuntoListeners()
@ -154,7 +149,7 @@ let Realtime = {
} // if Active.Mapper
},
addJuntoListeners: function() {
var self = Realtime
var self = toExport
$(document).on(ChatView.events.openTray, function() {
$('.main').addClass('compressed')
@ -180,7 +175,7 @@ let Realtime = {
})
},
startActiveMap: function() {
var self = Realtime
var self = toExport
if (Active.Map && Active.Mapper) {
if (Active.Map.authorizeToEdit(Active.Mapper)) {
self.turnOn()
@ -192,7 +187,7 @@ let Realtime = {
}
},
endActiveMap: function() {
var self = Realtime
var self = toExport
$(document).off('.map')
// leave the appropriate rooms to leave
if (self.inConversation) self.leaveCall()
@ -202,7 +197,7 @@ let Realtime = {
Cable.unsubscribeFromMap()
},
turnOn: function(notify) {
var self = Realtime
var self = toExport
$('.collabCompass').show()
self.room.room = 'map-' + Active.Map.id
self.activeMapper = {
@ -219,13 +214,13 @@ let Realtime = {
self.setupLocalEvents()
},
setupChat: function() {
const self = Realtime
const self = toExport
ChatView.setNewMap()
ChatView.addParticipant(self.activeMapper)
ChatView.addMessages(new DataModel.MessageCollection(DataModel.Messages), true)
},
setupLocalEvents: function() {
var self = Realtime
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)
@ -242,7 +237,7 @@ let Realtime = {
})
},
countOthersInConversation: function() {
var self = Realtime
var self = toExport
var count = 0
for (var key in self.mappersOnMap) {
if (self.mappersOnMap[key].inConversation) count++
@ -250,7 +245,7 @@ let Realtime = {
return count
},
handleVideoAdded: function(v, id) {
var self = Realtime
var self = toExport
self.positionVideos()
v.setParent($('#wrapper'))
v.$container.find('.video-cutoff').css({
@ -259,7 +254,7 @@ let Realtime = {
$('#wrapper').append(v.$container)
},
positionVideos: function() {
var self = Realtime
var self = toExport
var videoIds = Object.keys(self.room.videos)
// var numOfVideos = videoIds.length
// var numOfVideosToPosition = _.filter(videoIds, function(id) {
@ -290,7 +285,7 @@ let Realtime = {
}
// do self first
var myVideo = Realtime.localVideo.view
var myVideo = toExport.localVideo.view
if (!myVideo.manuallyPositioned) {
myVideo.$container.css({
top: yFormula() + 'px',
@ -308,7 +303,7 @@ let Realtime = {
})
},
callEnded: function() {
var self = Realtime
var self = toExport
ChatView.conversationEnded()
self.room.leaveVideoOnly()
@ -336,13 +331,13 @@ let Realtime = {
})
},
positionPeerIcons: function() {
var self = Realtime
var self = toExport
for (var key in self.mappersOnMap) {
self.positionPeerIcon(key)
}
},
positionPeerIcon: function(id) {
var self = Realtime
var self = toExport
var mapper = self.mappersOnMap[id]
var origPixels = Util.coordsToPixels(Visualize.mGraph, mapper.coords)
@ -371,7 +366,7 @@ let Realtime = {
}
},
limitPixelsToScreen: function(pixels) {
var self = Realtime
var self = toExport
var boundary = self.chatOpen ? '#wrapper' : document
var xLimit, yLimit
@ -405,25 +400,28 @@ const sendables = [
['dragTopic', dragTopic]
]
sendables.forEach(sendable => {
Realtime[sendable[0]] = sendable[1](Realtime)
toExport[sendable[0]] = sendable[1](toExport)
})
const subscribeToEvents = (Realtime, socket) => {
socket.on(JUNTO_UPDATED, juntoUpdated(Realtime))
socket.on(INVITED_TO_CALL, invitedToCall(Realtime))
socket.on(INVITED_TO_JOIN, invitedToJoin(Realtime))
socket.on(CALL_ACCEPTED, callAccepted(Realtime))
socket.on(CALL_DENIED, callDenied(Realtime))
socket.on(INVITE_DENIED, inviteDenied(Realtime))
socket.on(CALL_IN_PROGRESS, callInProgress(Realtime))
socket.on(CALL_STARTED, callStarted(Realtime))
socket.on(MAPPER_LIST_UPDATED, mapperListUpdated(Realtime))
socket.on(MAPPER_JOINED_CALL, mapperJoinedCall(Realtime))
socket.on(MAPPER_LEFT_CALL, mapperLeftCall(Realtime))
socket.on(PEER_COORDS_UPDATED, peerCoordsUpdated(Realtime))
socket.on(NEW_MAPPER, newMapper(Realtime))
socket.on(LOST_MAPPER, lostMapper(Realtime))
socket.on(TOPIC_DRAGGED, topicDragged(Realtime))
const subscribeToEvents = (toExport, socket) => {
socket.on(JUNTO_UPDATED, juntoUpdated(toExport))
socket.on(INVITED_TO_CALL, invitedToCall(toExport))
socket.on(INVITED_TO_JOIN, invitedToJoin(toExport))
socket.on(CALL_ACCEPTED, callAccepted(toExport))
socket.on(CALL_DENIED, callDenied(toExport))
socket.on(INVITE_DENIED, inviteDenied(toExport))
socket.on(CALL_IN_PROGRESS, callInProgress(toExport))
socket.on(CALL_STARTED, callStarted(toExport))
socket.on(MAPPER_LIST_UPDATED, mapperListUpdated(toExport))
socket.on(MAPPER_JOINED_CALL, mapperJoinedCall(toExport))
socket.on(MAPPER_LEFT_CALL, mapperLeftCall(toExport))
socket.on(PEER_COORDS_UPDATED, peerCoordsUpdated(toExport))
socket.on(NEW_MAPPER, newMapper(toExport))
socket.on(LOST_MAPPER, lostMapper(toExport))
socket.on(TOPIC_DRAGGED, topicDragged(toExport))
}
return toExport
}
export default Realtime

View file

@ -9,12 +9,12 @@ import { JUNTO_UPDATED } from './events'
import Active from '../Active'
import { ChatView } from '../Views'
import DataModel from '../DataModel'
import GlobalUI from '../GlobalUI'
import GlobalUI, { ReactApp } from '../GlobalUI'
import Util from '../Util'
import Visualize from '../Visualize'
export const juntoUpdated = self => state => {
self.juntoState = state
ReactApp.juntoState = state
$(document).trigger(JUNTO_UPDATED)
}

View file

@ -1,11 +1,14 @@
const Selected = {
reset: function() {
var self = Selected
self.Nodes = []
self.Edges = []
},
Nodes: [],
Edges: []
const Selected = () => {
const toExport = {
reset: function() {
var self = toExport
self.Nodes = []
self.Edges = []
},
Nodes: [],
Edges: []
}
return toExport
}
export default Selected

View file

@ -1,17 +1,11 @@
/* global $ */
import Active from './Active'
import Control from './Control'
import Create from './Create'
import DataModel from './DataModel'
import Map from './Map'
import Selected from './Selected'
import Settings from './Settings'
import Visualize from './Visualize'
const noOp = () => {}
const Synapse = {
const Synapse = ({Active, Control, Create, DataModel, Map, Selected, Visualize}) => {
const toExport = {
// this function is to retrieve a synapse JSON object from the database
// @param id = the id of the synapse to retrieve
get: function(id, callback = noOp) {
@ -77,7 +71,7 @@ const Synapse = {
}
},
createSynapseLocally: function() {
var self = Synapse
var self = toExport
let topic1
let topic2
let node1
@ -124,7 +118,7 @@ const Synapse = {
Create.newSynapse.hide()
},
getSynapseFromAutocomplete: function(id) {
var self = Synapse
var self = toExport
self.get(id, synapse => {
const mapping = new DataModel.Mapping({
@ -141,5 +135,7 @@ const Synapse = {
})
}
}
return toExport
}
export default Synapse

View file

@ -1,13 +1,11 @@
/* global $ */
import Active from './Active'
import Control from './Control'
import Mapper from './Mapper'
import Visualize from './Visualize'
const SynapseCard = {
const SynapseCard = ({Active, Control, Visualize}) => {
const toExport = {
openSynapseCard: null,
showCard: function(edge, e) {
var self = SynapseCard
var self = toExport
// reset so we don't interfere with other edges, but first, save its x and y
var myX = $('#edit_synapse').css('left')
@ -53,11 +51,11 @@ const SynapseCard = {
hideCard: function() {
$('#edit_synapse').remove()
SynapseCard.openSynapseCard = null
toExport.openSynapseCard = null
},
populateShowCard: function(edge, synapse) {
var self = SynapseCard
var self = toExport
self.add_synapse_count(edge)
self.add_desc_form(synapse)
@ -156,7 +154,7 @@ const SynapseCard = {
var index = parseInt($(this).attr('data-synapse-index'))
edge.setData('displayIndex', index)
Visualize.mGraph.plot()
SynapseCard.showCard(edge, false)
toExport.showCard(edge, false)
})
}
},
@ -291,5 +289,7 @@ const SynapseCard = {
} // if
} // add_direction_form
}
return toExport
}
export default SynapseCard

View file

@ -2,27 +2,15 @@
import $jit from '../patched/JIT'
import Active from './Active'
import AutoLayout from './AutoLayout'
import Create from './Create'
import DataModel from './DataModel'
import Filter from './Filter'
import GlobalUI, { ReactApp } from './GlobalUI'
import JIT from './JIT'
import Loading from './Loading'
import Map from './Map'
import Selected from './Selected'
import Settings from './Settings'
import SynapseCard from './SynapseCard'
import TopicCard from './Views/TopicCard'
import Util from './Util'
import Visualize from './Visualize'
const noOp = () => {}
const Topic = {
// this function is to retrieve a topic JSON object from the database
// @param id = the id of the topic to retrieve
const Topic = ({Active, AutoLayout, Create, DataModel, Filter, JIT, MAP, Selected, SynapseCard, TopicCard, Visualize}) => {
const toExport = {
get: function(id, callback = noOp) {
// if the desired topic is not yet in the local topic repository, fetch it
if (DataModel.Topics.get(id) === undefined) {
@ -101,7 +89,7 @@ const Topic = {
ReactApp.render()
},
fetchRelatives: function(nodes, metacodeId) {
var self = this
var self = toExport
var node = $.isArray(nodes) ? nodes[0] : nodes
@ -292,7 +280,7 @@ const Topic = {
}
},
createTopicLocally: function() {
var self = Topic
var self = toExport
if (Create.newTopic.name === '') {
GlobalUI.notifyUser('Please enter a topic title...')
@ -330,7 +318,7 @@ const Topic = {
self.renderTopic(mapping, topic, true, true) // this function also includes the creation of the topic in the database
},
getTopicFromAutocomplete: function(id) {
var self = Topic
var self = toExport
Map.setHasLearnedTopicCreation(true)
@ -357,7 +345,7 @@ const Topic = {
})
},
getMapFromAutocomplete: function(data) {
var self = Topic
var self = toExport
$(document).trigger(Map.events.editedByActiveMapper)
@ -387,7 +375,7 @@ const Topic = {
if (Create.newTopic.pinned) Create.newTopic.beingCreated = true
},
getTopicFromSearch: function(event, id) {
var self = Topic
var self = toExport
$(document).trigger(Map.events.editedByActiveMapper)
@ -409,5 +397,7 @@ const Topic = {
return false
}
}
return toExport
}
export default Topic

View file

@ -3,18 +3,17 @@
import Backbone from 'backbone'
import { Howl } from 'howler'
import Active from '../Active'
import DataModel from '../DataModel'
import ReactApp from '../GlobalUI/ReactApp'
const ChatView = {
const ChatView = ({Active, DataModel}) => {
const toExport = {
isOpen: false,
unreadMessages: 0,
messages: new Backbone.Collection(),
conversationLive: false,
isParticipating: false,
init: function(urls) {
const self = ChatView
const self = toExport
self.sound = new Howl({
src: urls,
sprite: {
@ -27,7 +26,7 @@ const ChatView = {
})
},
setNewMap: function() {
const self = ChatView
const self = toExport
self.unreadMessages = 0
self.isOpen = false
self.conversationLive = false
@ -41,74 +40,74 @@ const ChatView = {
},
render: () => {
if (!Active.Map) return
const self = ChatView
const self = toExport
ReactApp.render()
},
onOpen: () => {
const self = ChatView
const self = toExport
self.isOpen = true
self.unreadMessages = 0
self.render()
$(document).trigger(ChatView.events.openTray)
},
onClose: () => {
const self = ChatView
const self = toExport
self.isOpen = false
$(document).trigger(ChatView.events.closeTray)
},
addParticipant: participant => {
ChatView.participants.add(participant)
ChatView.render()
toExport.participants.add(participant)
toExport.render()
},
removeParticipant: participant => {
ChatView.participants.remove(participant)
ChatView.render()
toExport.participants.remove(participant)
toExport.render()
},
leaveConversation: () => {
ChatView.isParticipating = false
ChatView.render()
toExport.isParticipating = false
toExport.render()
},
mapperJoinedCall: id => {
const mapper = ChatView.participants.findWhere({id})
const mapper = toExport.participants.findWhere({id})
mapper && mapper.set('isParticipating', true)
ChatView.render()
toExport.render()
},
mapperLeftCall: id => {
const mapper = ChatView.participants.findWhere({id})
const mapper = toExport.participants.findWhere({id})
mapper && mapper.set('isParticipating', false)
ChatView.render()
toExport.render()
},
invitationPending: id => {
const mapper = ChatView.participants.findWhere({id})
const mapper = toExport.participants.findWhere({id})
mapper && mapper.set('isPending', true)
ChatView.render()
toExport.render()
},
invitationAnswered: id => {
const mapper = ChatView.participants.findWhere({id})
const mapper = toExport.participants.findWhere({id})
mapper && mapper.set('isPending', false)
ChatView.render()
toExport.render()
},
conversationInProgress: participating => {
ChatView.conversationLive = true
ChatView.isParticipating = participating
ChatView.render()
toExport.conversationLive = true
toExport.isParticipating = participating
toExport.render()
},
conversationEnded: () => {
ChatView.conversationLive = false
ChatView.isParticipating = false
ChatView.participants.forEach(p => p.set({isParticipating: false, isPending: false}))
ChatView.render()
toExport.conversationLive = false
toExport.isParticipating = false
toExport.participants.forEach(p => p.set({isParticipating: false, isPending: false}))
toExport.render()
},
videoToggleClick: function() {
ChatView.videosShowing = !ChatView.videosShowing
$(document).trigger(ChatView.videosShowing ? ChatView.events.videosOn : ChatView.events.videosOff)
toExport.videosShowing = !toExport.videosShowing
$(document).trigger(toExport.videosShowing ? ChatView.events.videosOn : ChatView.events.videosOff)
},
cursorToggleClick: function() {
ChatView.cursorsShowing = !ChatView.cursorsShowing
$(document).trigger(ChatView.cursorsShowing ? ChatView.events.cursorsOn : ChatView.events.cursorsOff)
toExport.cursorsShowing = !toExport.cursorsShowing
$(document).trigger(toExport.cursorsShowing ? ChatView.events.cursorsOn : ChatView.events.cursorsOff)
},
soundToggleClick: function() {
ChatView.alertSound = !ChatView.alertSound
toExport.alertSound = !toExport.alertSound
},
inputFocus: () => {
$(document).trigger(ChatView.events.inputFocus)
@ -117,15 +116,15 @@ const ChatView = {
$(document).trigger(ChatView.events.inputBlur)
},
addMessage: (message, isInitial, wasMe) => {
const self = ChatView
const self = toExport
if (!isInitial && !self.isOpen) self.unreadMessages += 1
if (!wasMe && !isInitial && self.alertSound) self.sound.play('receivechat')
self.messages.add(message)
if (!isInitial && self.isOpen) self.render()
},
sendChatMessage: message => {
var self = ChatView
if (ChatView.alertSound) ChatView.sound.play('sendchat')
var self = toExport
if (toExport.alertSound) toExport.sound.play('sendchat')
var m = new DataModel.Message({
message: message.message,
resource_id: Active.Map.id,
@ -141,14 +140,16 @@ const ChatView = {
})
},
handleInputMessage: text => {
ChatView.sendChatMessage({message: text})
toExport.sendChatMessage({message: text})
},
// they should be instantiated as backbone models before they get
// passed to this function
addMessages: (messages, isInitial, wasMe) => {
messages.models.forEach(m => ChatView.addMessage(m, isInitial, wasMe))
messages.models.forEach(m => toExport.addMessage(m, isInitial, wasMe))
}
}
return toExport
}
/**
* @class

View file

@ -1,15 +1,18 @@
import { ReactApp } from '../GlobalUI'
const TopicCard = {
const TopicCard = () => {
const toExport = {
openTopic: null,
showCard: function(node) {
TopicCard.openTopic = node.getData('topic')
toExport.openTopic = node.getData('topic')
ReactApp.render()
},
hideCard: function() {
TopicCard.openTopic = null
toExport.openTopic = null
ReactApp.render()
}
}
return toExport
}
export default TopicCard

View file

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

View file

@ -10,14 +10,15 @@ import JIT from './JIT'
import Loading from './Loading'
import TopicCard from './Views/TopicCard'
const Visualize = {
const Visualize = ({Active, DataModel, JIT, TopicCard}) => {
const toExport = {
mGraph: null, // a reference to the graph object.
cameraPosition: null, // stores the camera position when using a 3D visualization
type: 'ForceDirected', // the type of graph we're building, could be "RGraph", "ForceDirected", or "ForceDirected3D"
loadLater: false, // indicates whether there is JSON that should be loaded right in the offset, or whether to wait till the first topic is created
touchDragNode: null,
init: function(serverData) {
var self = Visualize
var self = toExport
if (serverData.VisualizeType) self.type = serverData.VisualizeType
@ -45,7 +46,7 @@ const Visualize = {
})
},
computePositions: function() {
const self = Visualize
const self = toExport
if (self.type === 'RGraph') {
let i
@ -107,7 +108,7 @@ const Visualize = {
*
*/
render: function() {
const self = Visualize
const self = toExport
if (self.type === 'RGraph') {
// clear the previous canvas from #infovis
@ -199,11 +200,14 @@ const Visualize = {
hold()
},
clearVisualization: function() {
Visualize.mGraph.graph.empty()
Visualize.mGraph.plot()
const self = toExport
self.mGraph.graph.empty()
self.mGraph.plot()
JIT.centerMap(Visualize.mGraph.canvas)
$('#infovis').empty()
}
}
return toExport
}
export default Visualize

View file

@ -1,32 +1,72 @@
import Account from './Account'
import Active from './Active'
import Admin from './Admin'
import AutoLayout from './AutoLayout'
import Cable from './Cable'
import Control from './Control'
import Create from './Create'
import DataModel from './DataModel'
import Debug from './Debug'
import Filter from './Filter'
import GlobalUI, {
ReactApp, Search, CreateMap, ImportDialog
} from './GlobalUI'
import Import from './Import'
import JIT from './JIT'
import Listeners from './Listeners'
import Loading from './Loading'
import Map, { CheatSheet } from './Map'
import Mapper from './Mapper'
import Mouse from './Mouse'
import Organize from './Organize'
import PasteInput from './PasteInput'
import Realtime from './Realtime'
import Selected from './Selected'
import Settings from './Settings'
import Synapse from './Synapse'
import SynapseCard from './SynapseCard'
import Topic from './Topic'
import Util from './Util'
import Views from './Views'
import Visualize from './Visualize'
const Metamaps = window.Metamaps || {}
Metamaps.Account = Account
Metamaps.Active = Active
Metamaps.Admin = Admin
Metamaps.AutoLayout = AutoLayout
Metamaps.Cable = Cable
Metamaps.Control = Control
Metamaps.Create = Create
Metamaps.DataModel = DataModel
Metamaps.Debug = Debug
Metamaps.Filter = Filter
Metamaps.Import = Import
Metamaps.JIT = JIT
Metamaps.Listeners = Listeners
Metamaps.Loading = Loading
Metamaps.Map = Map
Metamaps.Map.CheatSheet = CheatSheet
Metamaps.Maps = {}
Metamaps.Mapper = Mapper
Metamaps.Mouse = Mouse
Metamaps.Organize = Organize
Metamaps.PasteInput = PasteInput
Metamaps.Realtime = Realtime
Metamaps.Selected = Selected
Metamaps.Settings = Settings
Metamaps.Synapse = Synapse
Metamaps.SynapseCard = SynapseCard
Metamaps.Topic = Topic
Metamaps.Util = Util
Metamaps.Views = Views
Metamaps.Visualize = Visualize
Metamaps.GlobalUI = GlobalUI
Metamaps.GlobalUI.ReactApp = ReactApp
Metamaps.GlobalUI.Search = Search
Metamaps.GlobalUI.CreateMap = CreateMap
Metamaps.GlobalUI.ImportDialog = ImportDialog
Metamaps.Import = Import
Metamaps.Loading = Loading
Metamaps.Maps = {}
Metamaps.Mapper = Mapper
Metamaps.Topic = Topic
Metamaps.Util = Util
document.addEventListener('DOMContentLoaded', function() {
// initialize all the modules
@ -37,6 +77,7 @@ document.addEventListener('DOMContentLoaded', function() {
Metamaps[prop].hasOwnProperty('init') &&
typeof (Metamaps[prop].init) === 'function'
) {
console.log(prop)
Metamaps[prop].init(Metamaps.ServerData)
}
}