diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 784395de..b25950b0 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -25,6 +25,7 @@ //= require ./src/views/room //= require ./src/JIT //= require ./src/Metamaps +//= require ./src/Metamaps.Map //= require ./src/Metamaps.Account //= require ./src/Metamaps.Mapper //= require ./src/Metamaps.Admin diff --git a/app/assets/javascripts/src/Metamaps.Map.js.erb b/app/assets/javascripts/src/Metamaps.Map.js.erb new file mode 100644 index 00000000..0207d081 --- /dev/null +++ b/app/assets/javascripts/src/Metamaps.Map.js.erb @@ -0,0 +1,667 @@ +/* global Metamaps, $ */ + +/* + * Metamaps.Map.js.erb + * + * Dependencies: + * Metamaps.Create + * Metamaps.Filter + * Metamaps.JIT + * Metamaps.Loading + * Metamaps.Maps + * Metamaps.Realtime + * Metamaps.Router + * Metamaps.Selected + * Metamaps.SynapseCard + * Metamaps.TopicCard + * Metamaps.Visualize + * - Metamaps.Active + * - Metamaps.Backbone + * - Metamaps.GlobalUI + * - Metamaps.Mappers + * - Metamaps.Mappings + * - Metamaps.Messages + * - Metamaps.Synapses + * - Metamaps.Topics + * + * Major sub-modules: + * - Metamaps.Map.CheatSheet + * - Metamaps.Map.InfoBox + */ + +Metamaps.Map = { + events: { + editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper' + }, + nextX: 0, + nextY: 0, + sideLength: 1, + turnCount: 0, + nextXshift: 1, + nextYshift: 0, + timeToTurn: 0, + init: function () { + var self = Metamaps.Map + + // prevent right clicks on the main canvas, so as to not get in the way of our right clicks + $('#center-container').bind('contextmenu', function (e) { + return false + }) + + $('.sidebarFork').click(function () { + self.fork() + }) + + Metamaps.GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html() + + self.InfoBox.init() + self.CheatSheet.init() + + $(document).on(Metamaps.Map.events.editedByActiveMapper, self.editedByActiveMapper) + }, + launch: function (id) { + var bb = Metamaps.Backbone + var start = function (data) { + Metamaps.Active.Map = new bb.Map(data.map) + Metamaps.Mappers = new bb.MapperCollection(data.mappers) + Metamaps.Topics = new bb.TopicCollection(data.topics) + Metamaps.Synapses = new bb.SynapseCollection(data.synapses) + Metamaps.Mappings = new bb.MappingCollection(data.mappings) + Metamaps.Messages = data.messages + Metamaps.Backbone.attachCollectionEvents() + + var map = Metamaps.Active.Map + var mapper = Metamaps.Active.Mapper + + // add class to .wrapper for specifying whether you can edit the map + if (map.authorizeToEdit(mapper)) { + $('.wrapper').addClass('canEditMap') + } + + // add class to .wrapper for specifying if the map can + // be collaborated on + if (map.get('permission') === 'commons') { + $('.wrapper').addClass('commonsMap') + } + + // set filter mapper H3 text + $('#filter_by_mapper h3').html('MAPPERS') + + // build and render the visualization + Metamaps.Visualize.type = 'ForceDirected' + Metamaps.JIT.prepareVizData() + + // update filters + Metamaps.Filter.reset() + + // reset selected arrays + Metamaps.Selected.reset() + + // set the proper mapinfobox content + Metamaps.Map.InfoBox.load() + + // these three update the actual filter box with the right list items + Metamaps.Filter.checkMetacodes() + Metamaps.Filter.checkSynapses() + Metamaps.Filter.checkMappers() + + Metamaps.Realtime.startActiveMap() + Metamaps.Loading.hide() + } + + $.ajax({ + url: '/maps/' + id + '/contains.json', + success: start + }) + }, + end: function () { + if (Metamaps.Active.Map) { + $('.wrapper').removeClass('canEditMap commonsMap') + Metamaps.Map.resetSpiral() + + $('.rightclickmenu').remove() + Metamaps.TopicCard.hideCard() + Metamaps.SynapseCard.hideCard() + Metamaps.Create.newTopic.hide() + Metamaps.Create.newSynapse.hide() + Metamaps.Filter.close() + Metamaps.Map.InfoBox.close() + Metamaps.Realtime.endActiveMap() + } + }, + fork: function () { + Metamaps.GlobalUI.openLightbox('forkmap') + + var nodes_data = '', + synapses_data = '' + var nodes_array = [] + var synapses_array = [] + // collect the unfiltered topics + Metamaps.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 + nodes_array.push(id) + var x, y + if (n.pos.x && n.pos.y) { + x = n.pos.x + y = n.pos.y + } else { + var x = Math.cos(n.pos.theta) * n.pos.rho + var y = Math.sin(n.pos.theta) * n.pos.rho + } + nodes_data += id + '/' + x + '/' + y + ',' + } + }) + // collect the unfiltered synapses + Metamaps.Synapses.each(function (synapse) { + var desc = synapse.get('desc') + + var descNotFiltered = Metamaps.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 = nodes_array.indexOf(synapse.get('node1_id')) > -1 + topicsNotFiltered = topicsNotFiltered && nodes_array.indexOf(synapse.get('node2_id')) > -1 + if (descNotFiltered && topicsNotFiltered) { + synapses_array.push(synapse.id) + } + }) + + synapses_data = synapses_array.join() + nodes_data = nodes_data.slice(0, -1) + + Metamaps.GlobalUI.CreateMap.topicsToMap = nodes_data + Metamaps.GlobalUI.CreateMap.synapsesToMap = synapses_data + }, + leavePrivateMap: function () { + var map = Metamaps.Active.Map + Metamaps.Maps.Active.remove(map) + Metamaps.Maps.Featured.remove(map) + Metamaps.Router.home() + Metamaps.GlobalUI.notifyUser('Sorry! That map has been changed to Private.') + }, + commonsToPublic: function () { + Metamaps.Realtime.turnOff(true); // true is for 'silence' + Metamaps.GlobalUI.notifyUser('Map was changed to Public. Editing is disabled.') + Metamaps.Active.Map.trigger('changeByOther') + }, + publicToCommons: function () { + var confirmString = 'This map permission has been changed to Commons! ' + confirmString += 'Do you want to reload and enable realtime collaboration?' + var c = confirm(confirmString) + if (c) { + Metamaps.Router.maps(Metamaps.Active.Map.id) + } + }, + editedByActiveMapper: function () { + if (Metamaps.Active.Mapper) { + Metamaps.Mappers.add(Metamaps.Active.Mapper) + } + }, + getNextCoord: function () { + var self = Metamaps.Map + var nextX = self.nextX + var nextY = self.nextY + + var DISTANCE_BETWEEN = 120 + + 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 = 0 + + // going right? turn down + if (self.nextXshift == 1 && self.nextYshift == 0) { + self.nextXshift = 0 + self.nextYshift = 1 + } + // going down? turn left + else if (self.nextXshift == 0 && self.nextYshift == 1) { + self.nextXshift = -1 + self.nextYshift = 0 + } + // going left? turn up + else if (self.nextXshift == -1 && self.nextYshift == 0) { + self.nextXshift = 0 + self.nextYshift = -1 + } + // going up? turn right + else if (self.nextXshift == 0 && self.nextYshift == -1) { + self.nextXshift = 1 + self.nextYshift = 0 + } + } + + return { + x: nextX, + y: nextY + } + }, + resetSpiral: function () { + Metamaps.Map.nextX = 0 + Metamaps.Map.nextY = 0 + Metamaps.Map.nextXshift = 1 + Metamaps.Map.nextYshift = 0 + Metamaps.Map.sideLength = 1 + Metamaps.Map.timeToTurn = 0 + Metamaps.Map.turnCount = 0 + }, + exportImage: function () { + 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 + return this.size = { + width: canvas.width, + height: canvas.height + } + } + canvas.scale = function (x, y) { + var px = this.scaleOffsetX * x, + py = this.scaleOffsetY * y + var dx = this.translateOffsetX * (x - 1) / px, + 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) { + var sx = this.scaleOffsetX, + 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 = Metamaps.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 + Metamaps.JIT.zoomExtents(null, canvas, true) + + var c = canvas.canvas, + ctx = canvas.getCtx(), + scale = canvas.scaleOffsetX + + // draw a grey background + ctx.fillStyle = '#d8d9da' + var xPoint = (-(c.width / scale) / 2) - (canvas.translateOffsetX / scale), + 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 + }) + + var imageData = { + encoded_image: canvas.canvas.toDataURL() + } + + var map = Metamaps.Active.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([separator = '-']) + var downloadMessage = '' + downloadMessage += 'Captured map screenshot! ' + downloadMessage += "DOWNLOAD" + Metamaps.GlobalUI.notifyUser(downloadMessage) + + $.ajax({ + type: 'POST', + dataType: 'json', + url: '/maps/' + Metamaps.Active.Map.id + '/upload_screenshot', + data: imageData, + success: function (data) { + console.log('successfully uploaded map screenshot') + }, + error: function () { + console.log('failed to save map screenshot') + } + }) + } +} + +/* + * + * CHEATSHEET + * + */ +Metamaps.Map.CheatSheet = { + init: function () { + // tab the cheatsheet + $('#cheatSheet').tabs() + $('#quickReference').tabs().addClass('ui-tabs-vertical ui-helper-clearfix') + $('#quickReference .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left') + + // id = the id of a vimeo video + var switchVideo = function (element, id) { + $('.tutorialItem').removeClass('active') + $(element).addClass('active') + $('#tutorialVideo').attr('src', '//player.vimeo.com/video/' + id) + } + + $('#gettingStarted').click(function () { + // switchVideo(this,'88334167') + }) + $('#upYourSkillz').click(function () { + // switchVideo(this,'100118167') + }) + $('#advancedMapping').click(function () { + // switchVideo(this,'88334167') + }) + } +}; // end Metamaps.Map.CheatSheet + +/* + * + * INFOBOX + * + */ +Metamaps.Map.InfoBox = { + isOpen: false, + changing: false, + selectingPermission: false, + changePermissionText: "
As the creator, you can change the permission of this map, but the permissions of the topics and synapses on it must be changed independently.
", + nameHTML: '{{name}}', + descHTML: '{{desc}}', + init: function () { + var self = Metamaps.Map.InfoBox + + $('.mapInfoIcon').click(self.toggleBox) + $('.mapInfoBox').click(function (event) { + event.stopPropagation() + }) + $('body').click(self.close) + + self.attachEventListeners() + + self.generateBoxHTML = Hogan.compile($('#mapInfoBoxTemplate').html()) + }, + toggleBox: function (event) { + var self = Metamaps.Map.InfoBox + + if (self.isOpen) self.close() + else self.open() + + event.stopPropagation() + }, + open: function () { + var self = Metamaps.Map.InfoBox + $('.mapInfoIcon div').addClass('hide') + if (!self.isOpen && !self.changing) { + self.changing = true + $('.mapInfoBox').fadeIn(200, function () { + self.changing = false + self.isOpen = true + }) + } + }, + close: function () { + var self = Metamaps.Map.InfoBox + + $('.mapInfoIcon div').removeClass('hide') + if (!self.changing) { + self.changing = true + $('.mapInfoBox').fadeOut(200, function () { + self.changing = false + self.isOpen = false + self.hidePermissionSelect() + $('.mapContributors .tip').hide() + }) + } + }, + load: function () { + var self = Metamaps.Map.InfoBox + + var map = Metamaps.Active.Map + + var obj = map.pick('permission', 'contributor_count', 'topic_count', 'synapse_count') + + var isCreator = map.authorizePermissionChange(Metamaps.Active.Mapper) + var canEdit = map.authorizeToEdit(Metamaps.Active.Mapper) + var shareable = map.get('permission') !== 'private' + + obj['name'] = canEdit ? Hogan.compile(self.nameHTML).render({id: map.id, name: map.get('name')}) : map.get('name') + obj['desc'] = canEdit ? Hogan.compile(self.descHTML).render({id: map.id, desc: map.get('desc')}) : map.get('desc') + obj['map_creator_tip'] = isCreator ? self.changePermissionText : '' + obj['contributors_class'] = Metamaps.Mappers.length > 1 ? 'multiple' : '' + obj['contributors_class'] += Metamaps.Mappers.length === 2 ? ' mTwo' : '' + obj['contributor_image'] = Metamaps.Mappers.length > 0 ? Metamaps.Mappers.models[0].get('image') : "<%= asset_path('user.png') %>" + obj['contributor_list'] = self.createContributorList() + obj['user_name'] = isCreator ? 'You' : map.get('user_name') + obj['created_at'] = map.get('created_at_clean') + obj['updated_at'] = map.get('updated_at_clean') + + var classes = isCreator ? 'yourMap' : '' + classes += canEdit ? ' canEdit' : '' + classes += shareable ? ' shareable' : '' + $('.mapInfoBox').removeClass('shareable yourMap canEdit') + .addClass(classes) + .html(self.generateBoxHTML.render(obj)) + + self.attachEventListeners() + }, + attachEventListeners: function () { + var self = Metamaps.Map.InfoBox + + $('.mapInfoBox.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') + bipName.unbind('best_in_place:activate').bind('best_in_place:activate', function () { + var $el = bipName.find('textarea') + var el = $el[0] + + $el.attr('maxlength', '140') + + $('.mapInfoName').append('
') + + var callback = function (data) { + $('.nameCounter.forMap').html(data.all + '/140') + } + Countable.live(el, callback) + }) + bipName.unbind('best_in_place:deactivate').bind('best_in_place:deactivate', function () { + $('.nameCounter.forMap').remove() + }) + + $('.mapInfoName .best_in_place_name').unbind('ajax:success').bind('ajax:success', function () { + var name = $(this).html() + Metamaps.Active.Map.set('name', name) + Metamaps.Active.Map.trigger('saved') + }) + + $('.mapInfoDesc .best_in_place_desc').unbind('ajax:success').bind('ajax:success', function () { + var desc = $(this).html() + Metamaps.Active.Map.set('desc', desc) + Metamaps.Active.Map.trigger('saved') + }) + + $('.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) + + $('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap) + + $('.mapContributors span, #mapContribs').unbind().click(function (event) { + $('.mapContributors .tip').toggle() + event.stopPropagation() + }) + $('.mapContributors .tip').unbind().click(function (event) { + event.stopPropagation() + }) + $('.mapContributors .tip li a').click(Metamaps.Router.intercept) + + $('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function () { + $('.mapContributors .tip').hide() + }) + }, + updateNameDescPerm: function (name, desc, perm) { + $('.mapInfoName .best_in_place_name').html(name) + $('.mapInfoDesc .best_in_place_desc').html(desc) + $('.mapInfoBox .mapPermission').removeClass('commons public private').addClass(perm) + }, + createContributorList: function () { + var self = Metamaps.Map.InfoBox + + var string = '' + string += '' + return string + }, + updateNumbers: function () { + var self = Metamaps.Map.InfoBox + var mapper = Metamaps.Active.Mapper + + var contributors_class = '' + if (Metamaps.Mappers.length === 2) contributors_class = 'multiple mTwo' + else if (Metamaps.Mappers.length > 2) contributors_class = 'multiple' + + var contributors_image = "<%= asset_path('user.png') %>" + if (Metamaps.Mappers.length > 0) { + // get the first contributor and use their image + contributors_image = Metamaps.Mappers.models[0].get('image') + } + $('.mapContributors img').attr('src', contributors_image).removeClass('multiple mTwo').addClass(contributors_class) + $('.mapContributors span').text(Metamaps.Mappers.length) + $('.mapContributors .tip').html(self.createContributorList()) + $('.mapTopics').text(Metamaps.Topics.length) + $('.mapSynapses').text(Metamaps.Synapses.length) + + $('.mapEditedAt').html('Last edited: ' + Metamaps.Util.nowDateFormatted()) + }, + onPermissionClick: function (event) { + var self = Metamaps.Map.InfoBox + + if (!self.selectingPermission) { + self.selectingPermission = true + $(this).addClass('minimize') // this line flips the drop down arrow to a pull up arrow + if ($(this).hasClass('commons')) { + $(this).append('') + } else if ($(this).hasClass('public')) { + $(this).append('') + } else if ($(this).hasClass('private')) { + $(this).append('') + } + $('.mapPermission .permissionSelect li').click(self.selectPermission) + event.stopPropagation() + } + }, + hidePermissionSelect: function () { + var self = Metamaps.Map.InfoBox + + 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 = Metamaps.Map.InfoBox + + self.selectingPermission = false + var permission = $(this).attr('class') + var permBefore = Metamaps.Active.Map.get('permission') + Metamaps.Active.Map.save({ + permission: permission + }) + Metamaps.Active.Map.updateMapWrapper() + if (permBefore !== 'commons' && permission === 'commons') { + Metamaps.Realtime.setupSocket() + Metamaps.Realtime.turnOn() + } + else if (permBefore === 'commons' && permission === 'public') { + Metamaps.Realtime.turnOff(true); // true is to 'silence' + // the notification that would otherwise be sent + } + shareable = permission === 'private' ? '' : 'shareable' + $('.mapPermission').removeClass('commons public private minimize').addClass(permission) + $('.mapPermission .permissionSelect').remove() + $('.mapInfoBox').removeClass('shareable').addClass(shareable) + event.stopPropagation() + }, + deleteActiveMap: function () { + var confirmString = 'Are you sure you want to delete this map? ' + confirmString += 'This action is irreversible. It will not delete the topics and synapses on the map.' + + var doIt = confirm(confirmString) + var map = Metamaps.Active.Map + var mapper = Metamaps.Active.Mapper + var authorized = map.authorizePermissionChange(mapper) + + if (doIt && authorized) { + Metamaps.Map.InfoBox.close() + Metamaps.Maps.Active.remove(map) + Metamaps.Maps.Featured.remove(map) + Metamaps.Maps.Mine.remove(map) + map.destroy() + Metamaps.Router.home() + Metamaps.GlobalUI.notifyUser('Map eliminated!') + } + else if (!authorized) { + alert("Hey now. We can't just go around willy nilly deleting other people's maps now can we? Run off and find something constructive to do, eh?") + } + } +}; // end Metamaps.Map.InfoBox diff --git a/app/assets/javascripts/src/Metamaps.js.erb b/app/assets/javascripts/src/Metamaps.js.erb index dbcb5b8a..c2585d76 100644 --- a/app/assets/javascripts/src/Metamaps.js.erb +++ b/app/assets/javascripts/src/Metamaps.js.erb @@ -4729,652 +4729,3 @@ Metamaps.Synapse = { self.renderSynapse(mapping, synapse, node1, node2, true); } }; // end Metamaps.Synapse - - -/* - * - * MAP - * - */ -Metamaps.Map = { - events: { - editedByActiveMapper: "Metamaps:Map:events:editedByActiveMapper" - }, - nextX: 0, - nextY: 0, - sideLength: 1, - turnCount: 0, - nextXshift: 1, - nextYshift: 0, - timeToTurn: 0, - init: function () { - var self = Metamaps.Map; - - // prevent right clicks on the main canvas, so as to not get in the way of our right clicks - $('#center-container').bind('contextmenu', function (e) { - return false; - }); - - $('.sidebarFork').click(function () { - self.fork(); - }); - - Metamaps.GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html(); - - self.InfoBox.init(); - self.CheatSheet.init(); - - $(document).on(Metamaps.Map.events.editedByActiveMapper, self.editedByActiveMapper); - }, - launch: function (id) { - var bb = Metamaps.Backbone; - var start = function (data) { - Metamaps.Active.Map = new bb.Map(data.map); - Metamaps.Mappers = new bb.MapperCollection(data.mappers); - Metamaps.Topics = new bb.TopicCollection(data.topics); - Metamaps.Synapses = new bb.SynapseCollection(data.synapses); - Metamaps.Mappings = new bb.MappingCollection(data.mappings); - Metamaps.Messages = data.messages; - Metamaps.Backbone.attachCollectionEvents(); - - var map = Metamaps.Active.Map; - var mapper = Metamaps.Active.Mapper; - - // add class to .wrapper for specifying whether you can edit the map - if (map.authorizeToEdit(mapper)) { - $('.wrapper').addClass('canEditMap'); - } - - // add class to .wrapper for specifying if the map can - // be collaborated on - if (map.get('permission') === 'commons') { - $('.wrapper').addClass('commonsMap'); - } - - // set filter mapper H3 text - $('#filter_by_mapper h3').html('MAPPERS'); - - // build and render the visualization - Metamaps.Visualize.type = "ForceDirected"; - Metamaps.JIT.prepareVizData(); - - // update filters - Metamaps.Filter.reset(); - - // reset selected arrays - Metamaps.Selected.reset(); - - // set the proper mapinfobox content - Metamaps.Map.InfoBox.load(); - - // these three update the actual filter box with the right list items - Metamaps.Filter.checkMetacodes(); - Metamaps.Filter.checkSynapses(); - Metamaps.Filter.checkMappers(); - - Metamaps.Realtime.startActiveMap(); - Metamaps.Loading.hide(); - } - - $.ajax({ - url: "/maps/" + id + "/contains.json", - success: start - }); - }, - end: function () { - if (Metamaps.Active.Map) { - - $('.wrapper').removeClass('canEditMap commonsMap'); - Metamaps.Map.resetSpiral(); - - $('.rightclickmenu').remove(); - Metamaps.TopicCard.hideCard(); - Metamaps.SynapseCard.hideCard(); - Metamaps.Create.newTopic.hide(); - Metamaps.Create.newSynapse.hide(); - Metamaps.Filter.close(); - Metamaps.Map.InfoBox.close(); - Metamaps.Realtime.endActiveMap(); - } - }, - fork: function () { - Metamaps.GlobalUI.openLightbox('forkmap'); - - var nodes_data = "", - synapses_data = ""; - var nodes_array = []; - var synapses_array = []; - // collect the unfiltered topics - Metamaps.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; - nodes_array.push(id); - var x, y; - if (n.pos.x && n.pos.y) { - x = n.pos.x; - y = n.pos.y; - } else { - var x = Math.cos(n.pos.theta) * n.pos.rho; - var y = Math.sin(n.pos.theta) * n.pos.rho; - } - nodes_data += id + '/' + x + '/' + y + ','; - } - }); - // collect the unfiltered synapses - Metamaps.Synapses.each(function(synapse){ - var desc = synapse.get("desc"); - - var descNotFiltered = Metamaps.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 = nodes_array.indexOf(synapse.get('node1_id')) > -1; - topicsNotFiltered = topicsNotFiltered && nodes_array.indexOf(synapse.get('node2_id')) > -1; - if (descNotFiltered && topicsNotFiltered) { - synapses_array.push(synapse.id); - } - }); - - synapses_data = synapses_array.join(); - nodes_data = nodes_data.slice(0, -1); - - Metamaps.GlobalUI.CreateMap.topicsToMap = nodes_data; - Metamaps.GlobalUI.CreateMap.synapsesToMap = synapses_data; - - }, - leavePrivateMap: function(){ - var map = Metamaps.Active.Map; - Metamaps.Maps.Active.remove(map); - Metamaps.Maps.Featured.remove(map); - Metamaps.Router.home(); - Metamaps.GlobalUI.notifyUser('Sorry! That map has been changed to Private.'); - }, - commonsToPublic: function(){ - Metamaps.Realtime.turnOff(true); // true is for 'silence' - Metamaps.GlobalUI.notifyUser('Map was changed to Public. Editing is disabled.'); - Metamaps.Active.Map.trigger('changeByOther'); - }, - publicToCommons: function(){ - var confirmString = "This map permission has been changed to Commons! "; - confirmString += "Do you want to reload and enable realtime collaboration?"; - var c = confirm(confirmString); - if (c) { - Metamaps.Router.maps(Metamaps.Active.Map.id); - } - }, - editedByActiveMapper: function () { - if (Metamaps.Active.Mapper) { - Metamaps.Mappers.add(Metamaps.Active.Mapper); - } - }, - getNextCoord: function() { - var self = Metamaps.Map; - var nextX = self.nextX; - var nextY = self.nextY; - - var DISTANCE_BETWEEN = 120; - - 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 = 0; - - // going right? turn down - if (self.nextXshift == 1 && self.nextYshift == 0) { - self.nextXshift = 0; - self.nextYshift = 1; - } - // going down? turn left - else if (self.nextXshift == 0 && self.nextYshift == 1) { - self.nextXshift = -1; - self.nextYshift = 0; - } - // going left? turn up - else if (self.nextXshift == -1 && self.nextYshift == 0) { - self.nextXshift = 0; - self.nextYshift = -1; - } - // going up? turn right - else if (self.nextXshift == 0 && self.nextYshift == -1) { - self.nextXshift = 1; - self.nextYshift = 0; - } - } - - return { - x: nextX, - y: nextY - } - }, - resetSpiral: function() { - Metamaps.Map.nextX = 0; - Metamaps.Map.nextY = 0; - Metamaps.Map.nextXshift = 1; - Metamaps.Map.nextYshift = 0; - Metamaps.Map.sideLength = 1; - Metamaps.Map.timeToTurn = 0; - Metamaps.Map.turnCount = 0; - }, - exportImage: function() { - - 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; - return this.size = { - width: canvas.width, - height: canvas.height - }; - }; - canvas.scale = function(x, y) { - var px = this.scaleOffsetX * x, - py = this.scaleOffsetY * y; - var dx = this.translateOffsetX * (x -1) / px, - 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) { - var sx = this.scaleOffsetX, - 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 = Metamaps.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 - Metamaps.JIT.zoomExtents(null, canvas, true); - - var c = canvas.canvas, - ctx = canvas.getCtx(), - scale = canvas.scaleOffsetX; - - // draw a grey background - ctx.fillStyle = '#d8d9da'; - var xPoint = (-(c.width/scale)/2) - (canvas.translateOffsetX/scale), - 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; - }); - - var imageData = { - encoded_image: canvas.canvas.toDataURL() - }; - - var map = Metamaps.Active.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([separator = '-']); - var downloadMessage = ""; - downloadMessage += "Captured map screenshot! "; - downloadMessage += "DOWNLOAD"; - Metamaps.GlobalUI.notifyUser(downloadMessage); - - $.ajax({ - type: "POST", - dataType: 'json', - url: "/maps/" + Metamaps.Active.Map.id + "/upload_screenshot", - data: imageData, - success: function (data) { - console.log('successfully uploaded map screenshot'); - }, - error: function () { - console.log('failed to save map screenshot'); - } - }); - } -}; - - -/* - * - * CHEATSHEET - * - */ -Metamaps.Map.CheatSheet = { - init: function () { - // tab the cheatsheet - $('#cheatSheet').tabs(); - $('#quickReference').tabs().addClass("ui-tabs-vertical ui-helper-clearfix"); - $("#quickReference .ui-tabs-nav li").removeClass("ui-corner-top").addClass("ui-corner-left"); - - // id = the id of a vimeo video - var switchVideo = function (element, id) { - $('.tutorialItem').removeClass("active"); - $(element).addClass("active"); - $('#tutorialVideo').attr('src','//player.vimeo.com/video/'+id); - }; - - $('#gettingStarted').click(function() { - //switchVideo(this,'88334167'); - }); - $('#upYourSkillz').click(function() { - //switchVideo(this,'100118167'); - }); - $('#advancedMapping').click(function() { - //switchVideo(this,'88334167'); - }); - } -}; // end Metamaps.Map.CheatSheet - - -/* - * - * INFOBOX - * - */ -Metamaps.Map.InfoBox = { - isOpen: false, - changing: false, - selectingPermission: false, - changePermissionText: "
As the creator, you can change the permission of this map, but the permissions of the topics and synapses on it must be changed independently.
", - nameHTML: '{{name}}', - descHTML: '{{desc}}', - init: function () { - var self = Metamaps.Map.InfoBox; - - $('.mapInfoIcon').click(self.toggleBox); - $('.mapInfoBox').click(function(event){ - event.stopPropagation(); - }); - $('body').click(self.close); - - self.attachEventListeners(); - - self.generateBoxHTML = Hogan.compile($('#mapInfoBoxTemplate').html()); - }, - toggleBox: function (event) { - var self = Metamaps.Map.InfoBox; - - if (self.isOpen) self.close(); - else self.open(); - - event.stopPropagation(); - }, - open: function () { - var self = Metamaps.Map.InfoBox; - $('.mapInfoIcon div').addClass('hide'); - if (!self.isOpen && !self.changing) { - self.changing = true; - $('.mapInfoBox').fadeIn(200, function () { - self.changing = false; - self.isOpen = true; - }); - } - }, - close: function () { - var self = Metamaps.Map.InfoBox; - - $('.mapInfoIcon div').removeClass('hide'); - if (!self.changing) { - self.changing = true; - $('.mapInfoBox').fadeOut(200, function () { - self.changing = false; - self.isOpen = false; - self.hidePermissionSelect(); - $('.mapContributors .tip').hide(); - }); - } - }, - load: function () { - var self = Metamaps.Map.InfoBox; - - var map = Metamaps.Active.Map; - - var obj = map.pick("permission","contributor_count","topic_count","synapse_count"); - - var isCreator = map.authorizePermissionChange(Metamaps.Active.Mapper); - var canEdit = map.authorizeToEdit(Metamaps.Active.Mapper); - var shareable = map.get('permission') !== 'private'; - - obj["name"] = canEdit ? Hogan.compile(self.nameHTML).render({id: map.id, name: map.get("name")}) : map.get("name"); - obj["desc"] = canEdit ? Hogan.compile(self.descHTML).render({id: map.id, desc: map.get("desc")}) : map.get("desc"); - obj["map_creator_tip"] = isCreator ? self.changePermissionText : ""; - obj["contributors_class"] = Metamaps.Mappers.length > 1 ? "multiple" : ""; - obj["contributors_class"] += Metamaps.Mappers.length === 2 ? " mTwo" : ""; - obj["contributor_image"] = Metamaps.Mappers.length > 0 ? Metamaps.Mappers.models[0].get("image") : "<%= asset_path('user.png') %>"; - obj["contributor_list"] = self.createContributorList(); - obj["user_name"] = isCreator ? "You" : map.get("user_name"); - obj["created_at"] = map.get("created_at_clean"); - obj["updated_at"] = map.get("updated_at_clean"); - - var classes = isCreator ? "yourMap" : ""; - classes += canEdit ? " canEdit" : ""; - classes += shareable ? " shareable" : ""; - $(".mapInfoBox").removeClass("shareable yourMap canEdit") - .addClass(classes) - .html(self.generateBoxHTML.render(obj)); - - self.attachEventListeners(); - }, - attachEventListeners: function () { - var self = Metamaps.Map.InfoBox; - - $('.mapInfoBox.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'); - bipName.unbind("best_in_place:activate").bind("best_in_place:activate", function () { - var $el = bipName.find('textarea'); - var el = $el[0]; - - $el.attr('maxlength', '140'); - - $('.mapInfoName').append('
'); - - var callback = function (data) { - $('.nameCounter.forMap').html(data.all + '/140'); - }; - Countable.live(el, callback); - }); - bipName.unbind("best_in_place:deactivate").bind("best_in_place:deactivate", function () { - $('.nameCounter.forMap').remove(); - }); - - $('.mapInfoName .best_in_place_name').unbind("ajax:success").bind("ajax:success", function () { - var name = $(this).html(); - Metamaps.Active.Map.set('name', name); - Metamaps.Active.Map.trigger('saved'); - }); - - $('.mapInfoDesc .best_in_place_desc').unbind("ajax:success").bind("ajax:success", function () { - var desc = $(this).html(); - Metamaps.Active.Map.set('desc', desc); - Metamaps.Active.Map.trigger('saved'); - }); - - $('.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); - - $('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap); - - $('.mapContributors span, #mapContribs').unbind().click(function(event){ - $('.mapContributors .tip').toggle(); - event.stopPropagation(); - }); - $('.mapContributors .tip').unbind().click(function(event){ - event.stopPropagation(); - }); - $('.mapContributors .tip li a').click(Metamaps.Router.intercept); - - $('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function(){ - $('.mapContributors .tip').hide(); - }); - }, - updateNameDescPerm: function(name, desc, perm) { - $('.mapInfoName .best_in_place_name').html(name); - $('.mapInfoDesc .best_in_place_desc').html(desc); - $('.mapInfoBox .mapPermission').removeClass('commons public private').addClass(perm); - }, - createContributorList: function () { - var self = Metamaps.Map.InfoBox; - - var string = ""; - string += ""; - return string; - }, - updateNumbers: function () { - var self = Metamaps.Map.InfoBox; - var mapper = Metamaps.Active.Mapper; - - var contributors_class = ""; - if (Metamaps.Mappers.length === 2) contributors_class = "multiple mTwo"; - else if (Metamaps.Mappers.length > 2) contributors_class = "multiple"; - - var contributors_image = "<%= asset_path('user.png') %>"; - if (Metamaps.Mappers.length > 0) { - // get the first contributor and use their image - contributors_image = Metamaps.Mappers.models[0].get("image"); - } - $('.mapContributors img').attr('src', contributors_image).removeClass('multiple mTwo').addClass(contributors_class); - $('.mapContributors span').text(Metamaps.Mappers.length) - $('.mapContributors .tip').html(self.createContributorList()); - $('.mapTopics').text(Metamaps.Topics.length); - $('.mapSynapses').text(Metamaps.Synapses.length); - - $('.mapEditedAt').html('Last edited: ' + Metamaps.Util.nowDateFormatted()); - }, - onPermissionClick: function (event) { - var self = Metamaps.Map.InfoBox; - - if (!self.selectingPermission) { - self.selectingPermission = true; - $(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow - if ($(this).hasClass('commons')) { - $(this).append(''); - } else if ($(this).hasClass('public')) { - $(this).append(''); - } else if ($(this).hasClass('private')) { - $(this).append(''); - } - $('.mapPermission .permissionSelect li').click(self.selectPermission); - event.stopPropagation(); - } - }, - hidePermissionSelect: function () { - var self = Metamaps.Map.InfoBox; - - 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 = Metamaps.Map.InfoBox; - - self.selectingPermission = false; - var permission = $(this).attr('class'); - var permBefore = Metamaps.Active.Map.get('permission'); - Metamaps.Active.Map.save({ - permission: permission - }); - Metamaps.Active.Map.updateMapWrapper(); - if (permBefore !== 'commons' && permission === 'commons') { - Metamaps.Realtime.setupSocket(); - Metamaps.Realtime.turnOn(); - } - else if (permBefore === 'commons' && permission === 'public') { - Metamaps.Realtime.turnOff(true); // true is to 'silence' - // the notification that would otherwise be sent - } - shareable = permission === 'private' ? '' : 'shareable'; - $('.mapPermission').removeClass('commons public private minimize').addClass(permission); - $('.mapPermission .permissionSelect').remove(); - $('.mapInfoBox').removeClass('shareable').addClass(shareable); - event.stopPropagation(); - }, - deleteActiveMap: function () { - var confirmString = 'Are you sure you want to delete this map? '; - confirmString += 'This action is irreversible. It will not delete the topics and synapses on the map.'; - - var doIt = confirm(confirmString); - var map = Metamaps.Active.Map; - var mapper = Metamaps.Active.Mapper; - var authorized = map.authorizePermissionChange(mapper); - - if (doIt && authorized) { - Metamaps.Map.InfoBox.close(); - Metamaps.Maps.Active.remove(map); - Metamaps.Maps.Featured.remove(map); - Metamaps.Maps.Mine.remove(map); - map.destroy(); - Metamaps.Router.home(); - Metamaps.GlobalUI.notifyUser('Map eliminated!'); - } - else if (!authorized) { - alert('Hey now. We can\'t just go around willy nilly deleting other people\'s maps now can we? Run off and find something constructive to do, eh?'); - } - } -}; // end Metamaps.Map.InfoBox